allegro5-5.2.10.1/000077500000000000000000000000001473414355200134605ustar00rootroot00000000000000allegro5-5.2.10.1/.editorconfig000066400000000000000000000003201473414355200161300ustar00rootroot00000000000000root = true [*] end_of_line = lf insert_final_newline = true charset = utf-8 trim_trailing_whitespace = true indent_style = space indent_size = 3 [CMakeLists.txt] indent_size = 4 [*.cmake] indent_size = 4 allegro5-5.2.10.1/.github/000077500000000000000000000000001473414355200150205ustar00rootroot00000000000000allegro5-5.2.10.1/.github/workflows/000077500000000000000000000000001473414355200170555ustar00rootroot00000000000000allegro5-5.2.10.1/.github/workflows/continuous-integration.yml000066400000000000000000000076461473414355200243440ustar00rootroot00000000000000name: Tests on: [push, pull_request] jobs: windows_test: name: Windows (MSYS2) tests runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v1 with: fetch-depth: 1 - uses: msys2/setup-msys2@v2 - name: Setup shell: msys2 {0} run: | pacman --noconfirm -S mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake make mingw-w64-x86_64-physfs mingw-w64-x86_64-freetype mingw-w64-x86_64-libvorbis mingw-w64-x86_64-flac mingw-w64-x86_64-dumb mingw-w64-x86_64-libtheora mingw-w64-x86_64-libjpeg-turbo mingw-w64-x86_64-opusfile mingw-w64-x86_64-enet mingw-w64-x86_64-libwebp mingw-w64-x86_64-libopenmpt mkdir build - name: Configure shell: msys2 {0} run: | cd build cmake .. -G"MSYS Makefiles" - name: Build shell: msys2 {0} run: | cd build make -j2 osx_test: name: OSX tests runs-on: macos-12 steps: - name: Checkout uses: actions/checkout@v1 with: fetch-depth: 1 - name: Setup run: | brew update && brew install opusfile libvorbis freetype flac physfs dumb theora enet libopenmpt mkdir build - name: Configure run: | cd build cmake .. -DWANT_SHADERS_GL=$WANT_SHADERS_GL -G Xcode - name: Build run: | cd build xcodebuild ubuntu_test: name: Ubuntu tests runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v1 with: fetch-depth: 1 - name: Setup run: | sudo apt-get update sudo apt-get install -y xvfb libvorbis-dev libtheora-dev libwebp-dev libphysfs-dev libopusfile-dev libdumb1-dev libflac-dev libpulse-dev libgtk-3-dev pandoc libcurl4-nss-dev libenet-dev pulseaudio libasound2-dev libopenal-dev libgl1-mesa-dev libglu-dev libopenmpt-dev; mkdir build cd build . ../tests/grab_bitmap_suites.sh - name: Configure run: | cd build cmake .. -DCMAKE_BUILD_TYPE=Debug -DWANT_SHADERS_GL=on -DWANT_CURL_EXAMPLE=on -DWANT_PYTHON_WRAPPER=1 - name: Build run: | cd build make -j2 - name: Run test_driver run: | cd build find ../tests -name '*.ini' | grep -v 'compressed' | xargs xvfb-run tests/test_driver --save_on_failure --xvfb | tee /tmp/test_out || true mkdir -p test_outputs mv *.png test_outputs grep -q 'failed tests: 0' /tmp/test_out - name: Run other tests run: | cd build make run_standalone_tests - name: Upload artifacts if: failure() uses: actions/upload-artifact@v4 with: name: bitmaps path: build/test_outputs - name: Run install_test run: | cd build sudo make install sudo ldconfig gcc ../misc/install_test.c -o install_test $(pkg-config --cflags --libs allegro_image-debug-5 allegro_ttf-debug-5 allegro_acodec-debug-5 allegro_dialog-debug-5 allegro_primitives-debug-5 allegro_video-debug-5) pulseaudio -D xvfb-run ./install_test - name: Test Python wrapper run: | cd build python python/allegro.py allegro5-5.2.10.1/.github/workflows/update-docs.yml000066400000000000000000000026261473414355200220160ustar00rootroot00000000000000name: Update docs on: push: branches: [master] permissions: contents: write jobs: build-and-deploy: concurrency: ci-${{ github.ref }} runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 1 - name: Download pandoc uses: dsaltares/fetch-gh-release-asset@1.1.0 with: repo: jgm/pandoc version: tags/2.19.2 file: pandoc-2.19.2-1-amd64.deb target: pandoc-2.19.2-1-amd64.deb - name: Install and Build run: | sudo apt-get install -y libgl1-mesa-dev libglu-dev libxcursor-dev sudo dpkg -i pandoc-2.19.2-1-amd64.deb mkdir build cd build cmake .. make html - name: Checkout liballeg uses: actions/checkout@v4 with: repository: liballeg/liballeg.github.io ssh-key: ${{ secrets.LIBALLEG_DEPLOY_KEY }} ref: master path: liballeg - name: Deploy run: | cd liballeg git config user.name "allebot" git config user.email "13711631+allebot@users.noreply.github.com" rm -R a5docs/trunk cp -R ../build/docs/html/refman a5docs/trunk git add a5docs/trunk git diff-index --quiet HEAD || git commit -m "Automatic update from allegro5" git push allegro5-5.2.10.1/.gitignore000066400000000000000000000004001473414355200154420ustar00rootroot00000000000000 # ignore the build/ directory build/ build_android_arm/ build_android_arm64-v8a/ build_android_armeabi-v7a/ build_android_mips64/ build_android_mips/ build_android_x86/ build_android_x86_64/ # build dependencies optionally go in deps/, ignore them deps/ allegro5-5.2.10.1/CMakeLists.txt000066400000000000000000001231021473414355200162170ustar00rootroot00000000000000# # # TODO: # # - some documentation targets still missing # - installing documentation # cmake_minimum_required(VERSION 3.0) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) if(POLICY CMP0026) cmake_policy(SET CMP0026 NEW) endif() if(POLICY CMP0072) cmake_policy(SET CMP0072 NEW) endif() if(POLICY CMP0060) cmake_policy(SET CMP0060 NEW) endif() if(POLICY CMP0075) cmake_policy(SET CMP0075 NEW) endif() endif(COMMAND cmake_policy) #-----------------------------------------------------------------------------# # # Version # #-----------------------------------------------------------------------------# set(ALLEGRO_VERSION_REGEX_PATTERN "#define ALLEGRO_VERSION_STR[ ]+\"([0-9]+\\.[0-9]+\\.[0-9]+).*\"") file(STRINGS "${CMAKE_CURRENT_LIST_DIR}/include/allegro5/base.h" ALLEGRO_VERSION_MATCH REGEX ${ALLEGRO_VERSION_REGEX_PATTERN} LIMIT_COUNT 1 ) string(REGEX REPLACE ${ALLEGRO_VERSION_REGEX_PATTERN} "\\1" ALLEGRO_VERSION "${ALLEGRO_VERSION_MATCH}") if("${ALLEGRO_VERSION}" VERSION_GREATER_EQUAL 5.0.0) message(STATUS "[Allegro] Allegro Version: [${ALLEGRO_VERSION}]") else() message(FATAL_ERROR "[Allegro] Invalid Allegro Version: [${ALLEGRO_VERSION}]") endif() #-----------------------------------------------------------------------------# # # Project # #-----------------------------------------------------------------------------# # Allow generating custom project name via command-line arguments (#1174) set(ALLEGRO_PROJECT_NAME "ALLEGRO" CACHE STRING "Project default name") set(ALLEGRO_PROJECT_SUFFIX "" CACHE STRING "Project suffix") project(${ALLEGRO_PROJECT_NAME}${ALLEGRO_PROJECT_SUFFIX} VERSION ${ALLEGRO_VERSION} LANGUAGES C CXX DESCRIPTION "Allegro project" HOMEPAGE_URL "https://github.com/liballeg/allegro5" ) set(ALLEGRO_SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Profile." FORCE) endif() # Restrict configuration types to the selected build type. # Note: This needs to be done before the project command set(CMAKE_CONFIGURATION_TYPES "${CMAKE_BUILD_TYPE}" CACHE INTERNAL "internal") if(ANDROID) option(WANT_ANDROID_LEGACY "Build for Android 4 (1.6)" OFF) set(ANDROID_TARGET "android-12" CACHE STRING "What Android target to compile for.") endif(ANDROID) option(ALLEGRO_SDL "Build using the SDL backend (experimental)" OFF) option(WANT_STATIC_RUNTIME "Whether or not to link the C and C++ runtimes statically (currently only implemented on Windows)" OFF) # Search in the `cmake' directory for additional CMake modules. list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) # Reject in-source builds include(PreventInSourceBuilds) # Search in `deps' directories for dependency files. file(GLOB deps_subdirs "${PROJECT_SOURCE_DIR}/deps" "${PROJECT_SOURCE_DIR}/deps/*" "${PROJECT_BINARY_DIR}/deps" "${PROJECT_BINARY_DIR}/deps/*" ) foreach(subdir ${deps_subdirs}) if(EXISTS "${subdir}/include" OR EXISTS "${subdir}/lib") if(CMAKE_FIND_ROOT_PATH) message(STATUS "Adding ${subdir} to CMAKE_FIND_ROOT_PATH") list(APPEND CMAKE_FIND_ROOT_PATH "${subdir}") else() message(STATUS "Adding ${subdir} to CMAKE_PREFIX_PATH") list(APPEND CMAKE_PREFIX_PATH "${subdir}") endif() endif() endforeach(subdir) # Search for C header files in these directories. include_directories( ${PROJECT_SOURCE_DIR}/include ${PROJECT_BINARY_DIR}/include ) # Put libraries into `lib'. set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) # Lists of all the source files. include(FileList) # Our own CMake macros and functions. include(Common) #-----------------------------------------------------------------------------# # # Build options # #-----------------------------------------------------------------------------# if(NOT IPHONE) option(SHARED "Build shared libraries" on) set(BUILD_SHARED_LIBS ${SHARED}) # actual CMake variable endif(NOT IPHONE) # On some 64-bit platforms, libraries should be installed into `lib64' # instead of `lib'. Set this to 64 to do that. set(LIB_SUFFIX "" CACHE STRING "Suffix for 'lib' directories, e.g. '64'") option(WANT_FRAMEWORKS "Want frameworks on Mac OS X" off) option(WANT_EMBED "Make frameworks embeddable in application bundles (Mac OS X)" on) set(FRAMEWORK_INSTALL_PREFIX "/Library/Frameworks" CACHE STRING "Directory in which to install Mac OS X frameworks") option(PREFER_STATIC_DEPS "Whether to prefer static dependencies." off) # # Platforms and drivers. # option(WANT_X11 "X11 support" on) option(WANT_X11_XF86VIDMODE "X11 XF86VidMode Extension support" on) option(WANT_X11_XINERAMA "X11 Xinerama Extension support" on) option(WANT_X11_XRANDR "X11 XRandR Extension support" on) option(WANT_X11_XSCREENSAVER "X11 XScreenSaver Extension support" on) option(WANT_D3D "Enable Direct3D graphics driver (Windows)" on) option(WANT_D3D9EX "Enable Direct3D 9Ex extensions (Vista)" off) option(WANT_OPENGL "Enable OpenGL graphics driver (Windows, X11, OS X))" on) option(WANT_SHADERS_GL "Build GLSL shader support (OpenGL)" on) option(WANT_SHADERS_D3D "Build HLSL shader support (Direct3D)" on) set(GL_BUILD_TYPE "auto" CACHE STRING "OpenGL profile to build Allegro against") set_property(CACHE GL_BUILD_TYPE PROPERTY STRINGS "auto;gl;gles1;gles2+") set(GL_AUTO_BUILD_TYPE "gl") option(WANT_GLES3 "Use GLES3-only features in a GLES2+ build" off) # # Addons. # option(WANT_FONT "Enable bitmap font add-on" on) option(WANT_AUDIO "Enable allegro_audio engine" on) option(WANT_IMAGE "Enable image load/save addon" on) if (NOT IPHONE) option(WANT_IMAGE_JPG "Enable JPEG support in image addon" on) option(WANT_IMAGE_PNG "Enable PNG support in image addon" on) option(WANT_IMAGE_FREEIMAGE "Enable FreeImage support in image addon" on) endif (NOT IPHONE) option(WANT_IMAGE_WEBP "Enable WebP support in image addon" on) option(WANT_TTF "Enable TTF addon" on) option(WANT_COLOR "Enable color addon" on) option(WANT_MEMFILE "Enable memfile addon" on) option(WANT_PHYSFS "Enable PhysicsFS addon" on) option(WANT_PRIMITIVES "Enable primitives addon" on) option(WANT_NATIVE_DIALOG "Enable native dialog addon" on) option(WANT_VIDEO "Enable video player addon" on) option(WANT_MONOLITH "Include all addons in the main library" off) # # Wrappers. # option(WANT_PYTHON_WRAPPER "Enable generation of the Python wrapper" off) option(WANT_LUAJIT "Enable generation of the Luajit wrapper" off) # # Documentation. # option(WANT_DOCS "Generate documentation" on) option(WANT_DOCS_HTML "Generate HTML documentation" on) option(WANT_DOCS_MAN "Generate man pages" on) option(WANT_DOCS_INFO "Generate Info document" off) option(WANT_DOCS_PDF "Generate PDF document (requires pdflatex)" off) option(WANT_DOCS_PDF_PAPER "Whether PDF output is destined for paper" off) # # For developers. # option(STRICT_WARN "Halt at warnings" off) option(WANT_MUDFLAP "Enable gcc mudflap (requires gcc 4.0+)" off) option(WANT_RELEASE_LOGGING "Enable logging even in release mode" on) if(WANT_RELEASE_LOGGING) set(ALLEGRO_CFG_RELEASE_LOGGING 1) endif() # # Minor options. # if(NOT IPHONE) option(WANT_ALLOW_SSE "Allow compiler to use SSE instructions (x86)" on) endif(NOT IPHONE) option(NO_FPU "No floating point unit" off) option(WANT_DLL_TLS "Force use of DllMain for TLS (Windows)" off) option(WANT_DEMO "Build demo programs" on) option(WANT_EXAMPLES "Build example programs" on) option(WANT_POPUP_EXAMPLES "Use popups instead of printf for fatal errors" on) option(WANT_TESTS "Build test programs" on) option(WANT_WAIT_EVENT_SLEEP "Use sleep instead of threads in al_wait_for_event (only useful for emscripten without web workers)" off) if(WANT_WAIT_EVENT_SLEEP) set(ALLEGRO_WAIT_EVENT_SLEEP 1) endif() #-----------------------------------------------------------------------------# # # Set up compilers # #-----------------------------------------------------------------------------# include(CheckCSourceCompiles) include(CheckCXXSourceCompiles) if(CMAKE_COMPILER_IS_GNUCC) set(COMPILER_GCC 1) set(COMPILER_GCC_OR_CLANG 1) endif() if(CMAKE_C_COMPILER_ID MATCHES "Clang") set(COMPILER_GCC_OR_CLANG 1) endif() if(WIN32) if(WANT_DLL_TLS AND SHARED) set(ALLEGRO_CFG_DLL_TLS 1) endif(WANT_DLL_TLS AND SHARED) endif(WIN32) if(MSVC) set(COMPILER_MSVC 1) set(ALLEGRO_MSVC 1) # Guess VCINSTALLDIR from the value of CMAKE_C_COMPILER if it's not set. # XXX CMAKE_C_COMPILER will often be simply "cl" so this won't work. if("$ENV{VCINSTALLDIR}" STREQUAL "") string(REGEX REPLACE "/bin/[^/]*$" "" VCINSTALLDIR "${CMAKE_C_COMPILER}") message(STATUS "Guessed MSVC directory: ${VCINSTALLDIR}") else("$ENV{VCINSTALLDIR}" STREQUAL "") file(TO_CMAKE_PATH "$ENV{VCINSTALLDIR}" VCINSTALLDIR) message(STATUS "Using VCINSTALLDIR: ${VCINSTALLDIR}") endif("$ENV{VCINSTALLDIR}" STREQUAL "") # Install in VCINSTALLDIR by default if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX ${VCINSTALLDIR} CACHE PATH "Install path prefix, prepended onto install directories." FORCE) endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(EXECUTABLE_TYPE "WIN32") endif(MSVC) if(MINGW) # For alplatf.h set(ALLEGRO_MINGW32 1) # Guess MINGDIR from the value of CMAKE_C_COMPILER if it's not set. if("$ENV{MINGDIR}" STREQUAL "") string(REGEX REPLACE "/bin/[^/]*$" "" MINGDIR "${CMAKE_C_COMPILER}") message(STATUS "Guessed MinGW directory: ${MINGDIR}") else("$ENV{MINGDIR}" STREQUAL "") file(TO_CMAKE_PATH "$ENV{MINGDIR}" MINGDIR) message(STATUS "Using MINGDIR: ${MINGDIR}") endif("$ENV{MINGDIR}" STREQUAL "") # Search in MINGDIR for headers and libraries. if(CMAKE_FIND_ROOT_PATH) list(APPEND CMAKE_FIND_ROOT_PATH "${MINGDIR}") else() list(APPEND CMAKE_PREFIX_PATH "${MINGDIR}") endif() # Install to MINGDIR if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX ${MINGDIR} CACHE PATH "Install path prefix, prepended onto install directories." FORCE) endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) # Check for a common problem (at the time of writing). run_c_compile_test(" #include int main(void) { int x = DM_POSITION; return 0; }" HAVE_DM_POSITION) if(NOT HAVE_DM_POSITION) message(FATAL_ERROR "Missing DM_POSITION. Please update your MinGW " "w32api package, delete CMakeCache.txt and try again.") endif(NOT HAVE_DM_POSITION) endif(MINGW) if(UNIX AND NOT APPLE AND NOT ANDROID) set(ALLEGRO_UNIX 1) endif(UNIX AND NOT APPLE AND NOT ANDROID) if(APPLE AND NOT IPHONE) set(MACOSX 1) endif(APPLE AND NOT IPHONE) if(MACOSX) set(ALLEGRO_MACOSX 1) set(ALLEGRO_CFG_PTHREADS_TLS 1) set(ALLEGRO_UNIX 0) set(WANT_X11 off) # This flag is required on some versions of Mac OS X to avoid linker # problems with global variables which are not explicitly initialised. set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-common") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common") endif(MACOSX) if(IPHONE) set(ALLEGRO_CFG_PTHREADS_TLS 1) set(ALLEGRO_IPHONE 1) set(ALLEGRO_UNIX 0) set(ALLEGRO_LITTLE_ENDIAN 1) set(WANT_X11 off) set(GL_AUTO_BUILD_TYPE "gles2+") set(WANT_GLES3 yes) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") set(CMAKE_EXE_LINKER_FLAGS "-framework CoreGraphics -framework QuartzCore -framework UIKit -framework Foundation -framework CoreFoundation -framework MobileCoreServices") endif(IPHONE) if(BORLAND) set(ALLEGRO_BCC32 1) endif(BORLAND) if(ANDROID) set(ALLEGRO_ANDROID 1) set(ALLEGRO_CFG_PTHREADS_TLS 1) set(WANT_X11 off) set(GL_AUTO_BUILD_TYPE "gles2+") endif(ANDROID) if(ALLEGRO_RASPBERRYPI) set(ALLEGRO_CFG_PTHREADS_TLS 1) set(GL_AUTO_BUILD_TYPE "gles2+") set(ALLEGRO_EXCLUDE_GLX 1) endif(ALLEGRO_RASPBERRYPI) if(EMSCRIPTEN) set(GL_AUTO_BUILD_TYPE "gles2+") set(ALLEGRO_LITTLE_ENDIAN 1) if (NOT ALLEGRO_SDL) message(FATAL_ERROR "Emscripten support currently requires the SDL backend (set ALLEGRO_SDL)") endif(NOT ALLEGRO_SDL) endif() if(ALLEGRO_SDL) set(ALLEGRO_UNIX 0) set(ALLEGRO_MACOSX 0) set(WANT_X11 off) include(FindSDL2) endif(ALLEGRO_SDL) # Tell the compiler it can use SSE instructions on x86 architectures. # If compatibility with Pentium 2's and below is required then the user # should switch WANT_ALLOW_SSE off. # Workaround for a possible bug in CMake. Even if we set this variable in # the toolchain file when cross-compiling, as we should, it is empty. if(NOT CMAKE_SYSTEM_PROCESSOR AND CMAKE_SYSTEM_NAME MATCHES "Windows") set(CMAKE_SYSTEM_PROCESSOR i686) endif() if(CMAKE_SYSTEM_PROCESSOR MATCHES "i.86") set(ARCH_X86 1) endif() # CMake reports "x86" on my Windows Vista machine if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86") set(ARCH_X86 1) endif() if(ARCH_X86 AND WANT_ALLOW_SSE) if(COMPILER_GCC_OR_CLANG) message(STATUS "Allowing GCC/Clang to use SSE instructions") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse") endif(COMPILER_GCC_OR_CLANG) # Flags for other compilers should be added here. if(COMPILER_MSVC) message(STATUS "Allowing MSVC to use SSE instructions") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:SSE") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:SSE") endif(COMPILER_MSVC) endif() #-----------------------------------------------------------------------------# # # Build types # #-----------------------------------------------------------------------------# # Warnings. if(COMPILER_GCC_OR_CLANG) set(WFLAGS "-W -Wall -Wpointer-arith") set(WFLAGS_C_ONLY "-Wmissing-declarations -Wstrict-prototypes") if(ALLEGRO_UNIX) # Unfortunately we can't use this flag when magic main is used, # the mangled_main won't have a forward declaration. set(WFLAGS_C_ONLY "${WFLAGS_C_ONLY} -Wmissing-prototypes") endif(ALLEGRO_UNIX) if(STRICT_WARN) set(WFLAGS "${WFLAGS} -Werror") endif() endif() if(COMPILER_MSVC) set(WFLAGS "/W3 -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE") if(CMAKE_C_COMPILER_ID MATCHES "Clang") # Clang is more strict than MSVC's compiler here. set(WFLAGS "${WFLAGS} -Wno-c++11-narrowing") endif() endif(COMPILER_MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WFLAGS} ${WFLAGS_C_ONLY}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WFLAGS}") if(WANT_MUDFLAP AND COMPILER_GCC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fmudflapth") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmudflapth") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fmudflapth -lmudflapth") endif(WANT_MUDFLAP AND COMPILER_GCC) # Debugging. set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUGMODE=1 -DD3D_DEBUG_INFO") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUGMODE=1 -DD3D_DEBUG_INFO") # Profiling. list(APPEND CMAKE_BUILD_CONFIGURATIONS Profile) if(COMPILER_GCC_OR_CLANG) set(CMAKE_C_FLAGS_PROFILE "-pg" CACHE STRING "profiling flags") set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_C_FLAGS_PROFILE}" CACHE STRING "profiling flags") set(CMAKE_EXE_LINKER_FLAGS_PROFILE "-pg" CACHE STRING "profiling flags") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "-pg" CACHE STRING "profiling flags") mark_as_advanced( CMAKE_C_FLAGS_PROFILE CMAKE_CXX_FLAGS_PROFILE CMAKE_EXE_LINKER_FLAGS_PROFILE CMAKE_SHARED_LINKER_FLAGS_PROFILE ) endif(COMPILER_GCC_OR_CLANG) #-----------------------------------------------------------------------------# # # Begin tests # #-----------------------------------------------------------------------------# include(CheckFunctionExists) include(CheckIncludeFiles) include(CheckLibraryExists) include(CheckSymbolExists) include(CheckTypeSize) include(FindPkgConfig) include(TestBigEndian) if(NOT ALLEGRO_BIG_ENDIAN AND NOT ALLEGRO_LITTLE_ENDIAN) test_big_endian(ALLEGRO_BIG_ENDIAN) if(NOT ALLEGRO_BIG_ENDIAN) set(ALLEGRO_LITTLE_ENDIAN 1) endif(NOT ALLEGRO_BIG_ENDIAN) endif(NOT ALLEGRO_BIG_ENDIAN AND NOT ALLEGRO_LITTLE_ENDIAN) check_include_files(dirent.h ALLEGRO_HAVE_DIRENT_H) check_include_files(inttypes.h ALLEGRO_HAVE_INTTYPES_H) check_include_files(linux/input.h ALLEGRO_HAVE_LINUX_INPUT_H) check_include_files(stdbool.h ALLEGRO_HAVE_STDBOOL_H) check_include_files(stdint.h ALLEGRO_HAVE_STDINT_H) check_include_files(sys/io.h ALLEGRO_HAVE_SYS_IO_H) check_include_files(sys/stat.h ALLEGRO_HAVE_SYS_STAT_H) check_include_files(sys/time.h ALLEGRO_HAVE_SYS_TIME_H) check_include_files(time.h ALLEGRO_HAVE_TIME_H) check_include_files(sys/utsname.h ALLEGRO_HAVE_SYS_UTSNAME_H) check_include_files(sys/types.h ALLEGRO_HAVE_SYS_TYPES_H) check_include_files(soundcard.h ALLEGRO_HAVE_SOUNDCARD_H) check_include_files(sys/soundcard.h ALLEGRO_HAVE_SYS_SOUNDCARD_H) check_include_files(machine/soundcard.h ALLEGRO_HAVE_MACHINE_SOUNDCARD_H) check_include_files(linux/soundcard.h ALLEGRO_HAVE_LINUX_SOUNDCARD_H) check_include_files(libkern/OSAtomic.h ALLEGRO_HAVE_OSATOMIC_H) check_include_files(sys/inotify.h ALLEGRO_HAVE_SYS_INOTIFY_H) check_include_files(sal.h ALLEGRO_HAVE_SAL_H) check_function_exists(getexecname ALLEGRO_HAVE_GETEXECNAME) check_function_exists(mkstemp ALLEGRO_HAVE_MKSTEMP) check_function_exists(mmap ALLEGRO_HAVE_MMAP) check_function_exists(mprotect ALLEGRO_HAVE_MPROTECT) check_function_exists(sched_yield ALLEGRO_HAVE_SCHED_YIELD) check_function_exists(sysconf ALLEGRO_HAVE_SYSCONF) check_function_exists(fseeko ALLEGRO_HAVE_FSEEKO) check_function_exists(ftello ALLEGRO_HAVE_FTELLO) check_function_exists(strerror_r ALLEGRO_HAVE_STRERROR_R) check_function_exists(strerror_s ALLEGRO_HAVE_STRERROR_S) if(WIN32) check_function_exists(_ftelli64 ALLEGRO_HAVE_FTELLI64) check_function_exists(_fseeki64 ALLEGRO_HAVE_FSEEKI64) endif() check_type_size("_Bool" ALLEGRO_HAVE__BOOL) run_c_compile_test(" #include int main(void) { struct prpsinfo psinfo; psinfo.pr_argc = 0; return 0; }" ALLEGRO_HAVE_PROCFS_ARGCV ) run_c_compile_test(" #include #include int main(void) { struct prpsinfo psinfo; ioctl(0, PIOCPSINFO, &psinfo); return 0; }" ALLEGRO_HAVE_SV_PROCFS_H ) run_c_compile_test(" #include int main(void) { va_list a, b; va_copy(a, b); return 0; }" ALLEGRO_HAVE_VA_COPY ) #-----------------------------------------------------------------------------# # # Driver configuration # #-----------------------------------------------------------------------------# # # These are the conventions for this CMakeFile. # # The WANT_* variables indicate whether the user wants to have an optional # feature enabled, i.e. whether they have selected something in the CMake UI. # # The CAN_* variables indicate whether a feature *can* be enabled on this # system/platform. As these variable values are cached, CAN_ variables could # be set even though the user has turned a corresponding WANT_* variable # off---it might have been tested and set in a previous run. # # The SUPPORT_* variables are the conjunction of WANT_FEATURE and CAN_FEATURE, # i.e. the user wants it and the system can support it. # # Those variables are internal to the CMake build. Allegro header files use # preprocessor constants with names like ALLEGRO_WITH_* and ALLEGRO_HAVE_*. # Sometimes we make use of those variables in this CMakeFile as well, but # generally that's just due to sloppiness. # set(SPACER "===========================") set(CONFIGURATION_SUMMARY "Configuration summary\n${SPACER}\n") if(PREFER_STATIC_DEPS) set(CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_STATIC_LIBRARY_SUFFIX}" "${CMAKE_SHARED_LIBRARY_SUFFIX}" "${CMAKE_SHARED_MODULE_SUFFIX}") endif() set(OPENGL_SUMMARY "- OpenGL: NO") if(WANT_OPENGL) find_package(OpenGL) if(GL_BUILD_TYPE MATCHES "auto") set(GL_REAL_BUILD_TYPE ${GL_AUTO_BUILD_TYPE}) else() set(GL_REAL_BUILD_TYPE ${GL_BUILD_TYPE}) endif() if(GL_REAL_BUILD_TYPE MATCHES "gl$") if(OPENGL_FOUND AND OPENGL_GLU_FOUND) set(SUPPORT_OPENGL 1) set(ALLEGRO_CFG_OPENGL 1) set(ALLEGRO_CFG_OPENGL_FIXED_FUNCTION 1) # We assume that the OpenGL library is not very old. set(ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE 1) if(OPENGL_opengl_LIBRARY) # prefer GLVND if available set(OPENGL_LIBRARIES ${OPENGL_opengl_LIBRARY} ${OPENGL_glu_LIBRARY}) endif() include_directories(SYSTEM ${OPENGL_INCLUDE_DIR}) set(OPENGL_SUMMARY "- OpenGL: Desktop") else(OPENGL_FOUND) if(GL_BUILD_TYPE MATCHES "auto") set(GL_REAL_BUILD_TYPE "gles2+") endif() endif() endif() if(GL_REAL_BUILD_TYPE MATCHES "gles2") # on cmake 2.8.1 OpenGL ES is not found in the iphone case # XXX incorporate IPHONE case into FindOpenGLES/2 if(IPHONE) set(OPENGLES2_FOUND 1) set(OPENGLES2_LIBRARIES "-framework OpenGLES") elseif(EMSCRIPTEN) set(OPENGLES2_FOUND 1) else() find_package(OpenGLES2) endif() if(OPENGLES2_FOUND) set(SUPPORT_OPENGL 1) set(SUPPORT_OPENGLES 1) set(SUPPORT_OPENGLES2 1) set(ALLEGRO_CFG_OPENGL 1) set(ALLEGRO_CFG_OPENGLES 1) set(ALLEGRO_CFG_OPENGLES2 1) set(ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE 1) set(OPENGL_LIBRARIES ${OPENGLES2_LIBRARIES}) set(OPENGLES_INCLUDE_DIR ${OPENGLES2_INCLUDE_DIR}) set(OPENGL_SUMMARY "- OpenGL: ES 2.0") if(WANT_GLES3 AND NOT ANDROID) set(SUPPORT_OPENGLES3 1) set(ALLEGRO_CFG_OPENGLES3 1) set(OPENGL_SUMMARY "- OpenGL: ES 3.0") elseif(WANT_GLES3 AND ANDROID) find_package(OpenGLES3) if(OPENGLES3_FOUND) set(SUPPORT_OPENGLES3 1) set(ALLEGRO_CFG_OPENGLES3 1) set(OPENGL_LIBRARIES ${OPENGLES3_LIBRARIES}) list(APPEND OPENGLES_INCLUDE_DIR ${OPENGLES3_INCLUDE_DIR}) set(OPENGL_SUMMARY "- OpenGL: ES 3.0") endif(OPENGLES3_FOUND) endif() if(NOT IPHONE) include_directories(SYSTEM ${OPENGLES_INCLUDE_DIR}) endif() else(OPENGLES2_FOUND) if(GL_BUILD_TYPE MATCHES "auto") set(GL_REAL_BUILD_TYPE "gles1") endif() endif(OPENGLES2_FOUND) endif() if(GL_REAL_BUILD_TYPE MATCHES "gles1") # on cmake 2.8.1 OpenGL ES is not found in the iphone case # XXX incorporate IPHONE case into FindOpenGLES/2 if(IPHONE) set(OPENGLES1_FOUND 1) set(OPENGLES1_LIBRARIES "-framework OpenGLES") else() find_package(OpenGLES1) endif() if(OPENGLES1_FOUND) set(SUPPORT_OPENGL 1) set(SUPPORT_OPENGLES 1) set(SUPPORT_OPENGLES1 1) set(ALLEGRO_CFG_OPENGL 1) set(ALLEGRO_CFG_OPENGLES 1) set(ALLEGRO_CFG_OPENGLES1 1) set(ALLEGRO_CFG_OPENGL_FIXED_FUNCTION 1) set(OPENGL_SUMMARY "- OpenGL: ES 1.1") set(OPENGL_LIBRARIES ${OPENGLES1_LIBRARIES}) if(NOT IPHONE) include_directories(SYSTEM ${OPENGLES1_INCLUDE_DIR}) endif() endif(OPENGLES1_FOUND) endif() endif(WANT_OPENGL) set(CONFIGURATION_SUMMARY "${CONFIGURATION_SUMMARY}${OPENGL_SUMMARY}\n") # # Unix-specific # if(UNIX) # includes MACOSX if(NOT IPHONE AND NOT ANDROID) find_package(Threads) if(NOT CMAKE_USE_PTHREADS_INIT) message(FATAL_ERROR "Unix port requires pthreads support, not detected.") endif(NOT CMAKE_USE_PTHREADS_INIT) endif() endif(UNIX) # # SDL # if(ALLEGRO_SDL AND NOT SUPPORT_OPENGL) message(FATAL_ERROR "SDL support currently requires OpenGL or OpenGL ES support.") endif(ALLEGRO_SDL AND NOT SUPPORT_OPENGL) # # X Window System # if(WANT_X11) find_package(X11) if(X11_FOUND) set(SUPPORT_X11 1) set(ALLEGRO_WITH_XWINDOWS 1) endif(X11_FOUND) endif(WANT_X11) if(ALLEGRO_UNIX AND NOT SUPPORT_X11 AND WANT_X11) # not MACOSX message(FATAL_ERROR "X11 not found. You may need to install X11 development libraries.") endif(ALLEGRO_UNIX AND NOT SUPPORT_X11 AND WANT_X11) if(SUPPORT_X11 AND NOT SUPPORT_OPENGL) message(FATAL_ERROR "X11 support currently requires OpenGL or OpenGL ES support.") endif(SUPPORT_X11 AND NOT SUPPORT_OPENGL) if(SUPPORT_X11) set(CMAKE_REQUIRED_LIBRARIES ${X11_LIBRARIES}) if (OpenGL_GLX_FOUND) set(OPENGL_LIBRARIES "${OPENGL_LIBRARIES}" "${OPENGL_glx_LIBRARY}") endif() if (NOT OPENGL_LIBRARIES MATCHES "(libGL\\.|libGLX\\.)" AND NOT ALLEGRO_EXCLUDE_GLX) message(FATAL_ERROR "X11 support currently requires GLX (set OPENGL_glx_LIBRARY and OpenGL_GLX_FOUND).") endif() check_library_exists(Xcursor XcursorImageCreate "" CAN_XCURSOR) if(CAN_XCURSOR) set(ALLEGRO_XWINDOWS_WITH_XCURSOR 1) find_library(XCURSOR_LIB "Xcursor") list(APPEND X11_LIBRARIES "${XCURSOR_LIB}") else(CAN_XCURSOR) message(FATAL_ERROR "X11 support requires Xcursor library.") endif(CAN_XCURSOR) check_include_file("X11/extensions/XInput2.h" CAN_XINPUT2) run_c_compile_test(" #include int main(void) { (void)XI_TouchBegin; return 0; }" XINPUT2_COMPILES ) if(CAN_XINPUT2 AND XINPUT2_COMPILES) list(APPEND X11_LIBRARIES "Xi") set(ALLEGRO_XWINDOWS_WITH_XINPUT2 1) else() message("XInput2 library version 2.2 or higher not found, disabling touch support.") endif() if(WANT_X11_XF86VIDMODE) check_include_file("X11/extensions/xf86vmode.h" HAVE_XF86VIDMODE_H) check_library_exists(Xxf86vm XF86VidModeQueryExtension "" CAN_XF86VIDMODE) if(CAN_XF86VIDMODE AND HAVE_XF86VIDMODE_H) set(ALLEGRO_XWINDOWS_WITH_XF86VIDMODE 1) list(APPEND X11_LIBRARIES "Xxf86vm") endif() endif(WANT_X11_XF86VIDMODE) if(WANT_X11_XINERAMA) check_include_file("X11/extensions/Xinerama.h" HAVE_XINERAMA_H) check_library_exists(Xinerama XineramaQueryExtension "" CAN_XINERAMA) if(CAN_XINERAMA AND HAVE_XINERAMA_H) set(ALLEGRO_XWINDOWS_WITH_XINERAMA 1) find_library(XINERAMA_LIB "Xinerama") list(APPEND X11_LIBRARIES "${XINERAMA_LIB}") endif() endif(WANT_X11_XINERAMA) if(WANT_X11_XRANDR) check_include_file("X11/extensions/Xrandr.h" HAVE_XRANDR_H) check_library_exists(Xrandr XRRQueryExtension "" CAN_XRANDR) if(CAN_XRANDR AND HAVE_XRANDR_H) set(ALLEGRO_XWINDOWS_WITH_XRANDR 1) find_library(XRANDR_LIB "Xrandr") list(APPEND X11_LIBRARIES "${XRANDR_LIB}") endif() endif(WANT_X11_XRANDR) if(WANT_X11_XSCREENSAVER) check_include_file("X11/extensions/scrnsaver.h" HAVE_XSCREENSAVER_H) check_library_exists(Xss XScreenSaverQueryExtension "" CAN_XSCREENSAVER) if(CAN_XSCREENSAVER AND HAVE_XSCREENSAVER_H) set(ALLEGRO_XWINDOWS_WITH_XSCREENSAVER 1) find_library(XSCREENSAVER_LIB "Xss") list(APPEND X11_LIBRARIES "${XSCREENSAVER_LIB}") endif() endif(WANT_X11_XSCREENSAVER) if(NOT ALLEGRO_RASPBERRYPI) check_library_exists(X11 XOpenIM "" CAN_XIM) if(CAN_XIM) set(ALLEGRO_XWINDOWS_WITH_XIM 1) endif(CAN_XIM) endif(NOT ALLEGRO_RASPBERRYPI) set(CMAKE_REQUIRED_LIBRARIES) endif(SUPPORT_X11) # # Windows # if(WIN32) find_package(DirectX) if(DINPUT_FOUND) # At least some copies of dinput.h redefine some types multiple times. # We must add the directory as a system directory so that the compiler # will suppress such errors. include_directories(${DINPUT_INCLUDE_DIR}) else(DINPUT_FOUND) message(FATAL_ERROR "Windows port requires DirectInput (not found).") endif(DINPUT_FOUND) # Xinput support for xbox compatible controllers. if(XINPUT_FOUND) run_c_compile_test(" #include XINPUT_CAPABILITIES_EX x; int main(void) { return 0; }" HAVE_XINPUT_CAPABILITIES_EX ) if(HAVE_XINPUT_CAPABILITIES_EX) set(ALLEGRO_CFG_HAVE_XINPUT_CAPABILITIES_EX 1) endif() set(SUPPORT_XINPUT 1) set(ALLEGRO_CFG_XINPUT 1) endif(XINPUT_FOUND) if(WANT_D3D) if(D3D9_FOUND) set(SUPPORT_D3D 1) set(ALLEGRO_CFG_D3D 1) endif(D3D9_FOUND) endif(WANT_D3D) if(SUPPORT_D3D) if(D3DX9_FOUND) include_directories(BEFORE ${D3DX9_INCLUDE_DIR}) set(ALLEGRO_CFG_D3DX9 1) else() message("D3DX9 not found. You will not be able to compress or " "decompress textures on the GPU.") endif() endif(SUPPORT_D3D) if(WANT_D3D9EX AND SUPPORT_D3D) set(ALLEGRO_CFG_D3D9EX 1) endif(WANT_D3D9EX AND SUPPORT_D3D) endif(WIN32) #-----------------------------------------------------------------------------# # # Main library # #-----------------------------------------------------------------------------# if(WIN32 AND SHARED) if(NOT SUPPORT_D3D OR NOT SUPPORT_OPENGL) message("WARNING: " "Both D3D and OpenGL should be present for the SHARED build " " to ensure maximum DLL compatibility.") endif(NOT SUPPORT_D3D OR NOT SUPPORT_OPENGL) endif(WIN32 AND SHARED) # List of source files need to compile Allegro in this configuration on # this platform. set(LIBRARY_SOURCES ${ALLEGRO_SRC_FILES} ) # Libraries that we always need to link against on this platform. set(PLATFORM_LIBS) if(ALLEGRO_UNIX) # not MACOSX list(APPEND LIBRARY_SOURCES ${ALLEGRO_SRC_UNIX_FILES}) list(APPEND PLATFORM_LIBS m ${CMAKE_THREAD_LIBS_INIT}) endif(ALLEGRO_UNIX) if(SUPPORT_X11 AND NOT ALLEGRO_RASPBERRYPI) list(APPEND LIBRARY_SOURCES ${ALLEGRO_SRC_X_FILES}) list(APPEND PLATFORM_LIBS ${X11_LIBRARIES}) endif(SUPPORT_X11 AND NOT ALLEGRO_RASPBERRYPI) if(WIN32) list(APPEND LIBRARY_SOURCES ${ALLEGRO_SRC_WIN_FILES}) list(APPEND PLATFORM_LIBS user32 gdi32 comdlg32 ole32 winmm kernel32 psapi shlwapi ) if(SUPPORT_D3D) list(APPEND LIBRARY_SOURCES ${ALLEGRO_SRC_D3D_FILES}) list(APPEND PLATFORM_LIBS ${D3D9_LIBRARIES}) endif(SUPPORT_D3D) list(APPEND PLATFORM_LIBS ${DINPUT_LIBRARIES}) if(MINGW AND NOT SHARED) list(APPEND PLATFORM_LIBS stdc++) endif(MINGW AND NOT SHARED) endif(WIN32) if(ALLEGRO_MACOSX) list(APPEND LIBRARY_SOURCES ${ALLEGRO_SRC_MACOSX_FILES}) find_library(APPKIT_LIBRARY AppKit) find_library(IOKIT_LIBRARY IOKit) find_library(COREVIDEO_LIBRARY CoreVideo) list(APPEND PLATFORM_LIBS ${APPKIT_LIBRARY}) list(APPEND PLATFORM_LIBS ${IOKIT_LIBRARY}) list(APPEND PLATFORM_LIBS ${COREVIDEO_LIBRARY}) endif(ALLEGRO_MACOSX) if(IPHONE) list(APPEND LIBRARY_SOURCES ${ALLEGRO_SRC_IPHONE_FILES}) endif(IPHONE) if(ANDROID) list(APPEND LIBRARY_SOURCES ${ALLEGRO_SRC_ANDROID_FILES}) list(APPEND PLATFORM_LIBS m log) endif(ANDROID) if(ALLEGRO_RASPBERRYPI) list(APPEND LIBRARY_SOURCES ${ALLEGRO_SRC_RASPBERRYPI_FILES}) list(APPEND PLATFORM_LIBS ${X11_LIBRARIES}) endif(ALLEGRO_RASPBERRYPI) if(SUPPORT_OPENGL) list(APPEND LIBRARY_SOURCES ${ALLEGRO_SRC_OPENGL_FILES}) if(WIN32) list(APPEND LIBRARY_SOURCES ${ALLEGRO_SRC_WGL_FILES}) endif(WIN32) list(APPEND PLATFORM_LIBS ${OPENGL_LIBRARIES}) endif(SUPPORT_OPENGL) if(SUPPORT_OPENGL AND WANT_SHADERS_GL AND NOT ALLEGRO_CFG_OPENGLES1) set(ALLEGRO_CFG_SHADER_GLSL 1) endif() if(SUPPORT_D3D AND WANT_SHADERS_D3D AND D3DX9_FOUND) set(ALLEGRO_CFG_SHADER_HLSL 1) endif() # Header files that we need to install. set(ALLEGRO_PUBLIC_HEADERS ${ALLEGRO_INCLUDE_ALLEGRO_FILES} ${ALLEGRO_INCLUDE_ALLEGRO_INLINE_FILES} ${ALLEGRO_INCLUDE_ALLEGRO_INTERNAL_FILES} ${ALLEGRO_INCLUDE_ALLEGRO_PLATFORM_FILES} ) if(WIN32) list(APPEND ALLEGRO_PUBLIC_HEADERS ${ALLEGRO_INCLUDE_ALLEGRO_WINDOWS_FILES} ) endif(WIN32) if(MACOSX) list(APPEND ALLEGRO_PUBLIC_HEADERS ${ALLEGRO_INCLUDE_ALLEGRO_MACOSX_FILES} ) endif(MACOSX) if(IPHONE) list(APPEND ALLEGRO_PUBLIC_HEADERS ${ALLEGRO_INCLUDE_ALLEGRO_IPHONE_FILES} ) endif(IPHONE) if(SUPPORT_X11 AND NOT ALLEGRO_RASPBERRYPI) list(APPEND ALLEGRO_PUBLIC_HEADERS ${ALLEGRO_INCLUDE_ALLEGRO_X_FILES} ) endif(SUPPORT_X11 AND NOT ALLEGRO_RASPBERRYPI) if(ANDROID) list(APPEND ALLEGRO_PUBLIC_HEADERS ${ALLEGRO_INCLUDE_ALLEGRO_ANDROID_FILES}) endif(ANDROID) if(SUPPORT_OPENGL) list(APPEND ALLEGRO_PUBLIC_HEADERS ${ALLEGRO_INCLUDE_ALLEGRO_OPENGL_FILES} ${ALLEGRO_INCLUDE_ALLEGRO_OPENGL_GLEXT_FILES} ) endif(SUPPORT_OPENGL) foreach(genfile ${ALLEGRO_INCLUDE_ALLEGRO_PLATFORM_FILES_GENERATED}) list(APPEND ALLEGRO_PUBLIC_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/${genfile} ) endforeach(genfile) if(ALLEGRO_SDL) list(APPEND LIBRARY_SOURCES ${ALLEGRO_SRC_SDL_FILES}) list(APPEND PLATFORM_LIBS ${SDL2_LIBRARY} m) include_directories(${SDL2_INCLUDE_DIR}) endif(ALLEGRO_SDL) set_our_header_properties(${ALLEGRO_PUBLIC_HEADERS}) unset(ALLEGRO_TARGETS CACHE) if(NOT WANT_MONOLITH) # ALLEGRO_LIB_BUILD is defined for all Allegro sources (core and addon) # ALLEGRO_SRC is defined only while compiling the core sources (its use is # to get the DLL #defines right under Windows for creating DLL export # functions when it is defined or import DLL functions when it is not). add_our_library(allegro Allegro-${ALLEGRO_SOVERSION} "${LIBRARY_SOURCES};${ALLEGRO_PUBLIC_HEADERS}" "${LIBRARY_CFLAGS} -DALLEGRO_SRC" "${PLATFORM_LIBS}" ) endif(NOT WANT_MONOLITH) # Addons and examples should link with this target. set(ALLEGRO_LINK_WITH allegro) install_our_headers(${ALLEGRO_PUBLIC_HEADERS}) #-----------------------------------------------------------------------------# # # Add-ons # #-----------------------------------------------------------------------------# set(MONOLITH_SOURCES ${LIBRARY_SOURCES}) add_subdirectory(addons) if(WANT_MONOLITH) include_directories(${MONOLITH_INCLUDE_DIRECTORIES}) # For OSX, we need to set the header location inside the framework for each # file (relative to the current directory, so for example when the # AllegroImage framework is built we need to set the path for # allegro5/allegro_image.h but when the AllegroMonolith framework is built # we need to set the path for addons/image/allegro5/allegro_image.h - # otherwise the header is silently missing). set_our_header_properties(${MONOLITH_HEADERS}) link_directories(${MONOLITH_LINK_DIRECTORIES}) add_our_library(allegro_monolith AllegroMonolith-${ALLEGRO_SOVERSION} "${MONOLITH_SOURCES};${ALLEGRO_PUBLIC_HEADERS}" "${LIBRARY_CFLAGS} -DALLEGRO_SRC ${MONOLITH_DEFINES}" "${PLATFORM_LIBS};${MONOLITH_LIBRARIES}" ) set(ALLEGRO_MONOLITH_LINK_WITH allegro_monolith) endif(WANT_MONOLITH) #-----------------------------------------------------------------------------# # # Produce configuration file # #-----------------------------------------------------------------------------# if(NO_FPU) set(ALLEGRO_CFG_NO_FPU 1) endif(NO_FPU) # All relevant variables must be set before here. configure_file( include/allegro5/platform/alplatf.h.cmake ${PROJECT_BINARY_DIR}/include/allegro5/platform/alplatf.h ) #-----------------------------------------------------------------------------# # # Android # #-----------------------------------------------------------------------------# if(ANDROID) include(AndroidApp) add_subdirectory(android) endif(ANDROID) #-----------------------------------------------------------------------------# # # Demo # #-----------------------------------------------------------------------------# if(NOT MSVC80 AND WANT_DEMO) # XXX disabled because it breaks MSVC's intellisense for some reason add_subdirectory(demos/cosmic_protector) add_subdirectory(demos/speed) add_subdirectory(demos/skater) add_subdirectory(demos/shooter) endif(NOT MSVC80 AND WANT_DEMO) #-----------------------------------------------------------------------------# # # Examples # #-----------------------------------------------------------------------------# if(WANT_EXAMPLES) add_subdirectory(examples) endif(WANT_EXAMPLES) #-----------------------------------------------------------------------------# # # Tests # #-----------------------------------------------------------------------------# if(WANT_TESTS) add_subdirectory(tests) endif(WANT_TESTS) #-----------------------------------------------------------------------------# # # Example data # #-----------------------------------------------------------------------------# copy_data_dir_to_build(copy_example_data "${CMAKE_CURRENT_SOURCE_DIR}/examples/data" "${CMAKE_CURRENT_BINARY_DIR}/examples/data" ) #-----------------------------------------------------------------------------# # # contrib/Luajit # #-----------------------------------------------------------------------------# if(WANT_LUAJIT) add_subdirectory(contrib/luajit) endif(WANT_LUAJIT) #-----------------------------------------------------------------------------# # # pkg-config files # #-----------------------------------------------------------------------------# set(prefix "${CMAKE_INSTALL_PREFIX}") set(INCLUDE_PREFIX "\${prefix}") # XXX these should be configurable separately set(bindir "\${exec_prefix}/bin") set(includedir "\${prefix}/include") set(libdir "\${exec_prefix}/lib${LIB_SUFFIX}") if(WANT_MONOLITH) set(PKG_CONFIG_FILES allegro_monolith) else() set(PKG_CONFIG_FILES allegro ${ADDON_PKG_CONFIG_FILES}) endif(WANT_MONOLITH) # Install pkg-config files on Unix, and when cross-compiling on Unix. if(UNIX AND NOT WANT_FRAMEWORKS AND NOT IPHONE) set(INSTALL_PKG_CONFIG_FILES true) endif() if(CMAKE_CROSSCOMPILING AND CMAKE_HOST_UNIX) set(INSTALL_PKG_CONFIG_FILES true) endif() if(INSTALL_PKG_CONFIG_FILES) append_lib_type_suffix(lib_type) append_lib_linkage_suffix(lib_linkage) # Our pkg-config files are now named allegro*-5.pc, which will # work across branches. Allegro 5.0.8 and prior used the names # allegro*-5.0.pc so on the 5.0 branch we will continue to install # those files, for backwards compatibility. foreach(versuffix 5) foreach(name ${PKG_CONFIG_FILES}) if (SHARED) set(outname ${name}${lib_type}-${versuffix}.pc) else (SHARED) # For static linking: get extra libraries to link with. get_target_property(link_with ${name} static_link_with) set(outname ${name}${lib_type}-static-${versuffix}.pc) endif (SHARED) configure_file( misc/${name}.pc.in ${LIBRARY_OUTPUT_PATH}/pkgconfig/${outname} @ONLY ) install(FILES ${LIBRARY_OUTPUT_PATH}/pkgconfig/${outname} DESTINATION "lib${LIB_SUFFIX}/pkgconfig" ) endforeach(name) endforeach(versuffix) endif(INSTALL_PKG_CONFIG_FILES) # Generate CMake package-config files include(CMakePackageConfigHelpers) include(GNUInstallDirs) set(PKG_NAME "Allegro") string(TOLOWER ${PKG_NAME} PKG_NAME_LOWER) set(PKG_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PKG_NAME_LOWER}") set(PKG_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") set(PKG_TARGETS_NAME "${PKG_NAME}Targets") set(PKG_CONFIG_FILE "${PKG_GENERATED_DIR}/${PKG_NAME}Config.cmake") set(PKG_VERSION_FILE "${PKG_GENERATED_DIR}/${PKG_NAME}ConfigVersion.cmake") configure_package_config_file( "${CMAKE_CURRENT_LIST_DIR}/cmake/${PKG_NAME}Config.cmake.in" ${PKG_CONFIG_FILE} INSTALL_DESTINATION ${PKG_CONFIG_INSTALL_DIR} NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) write_basic_package_version_file(${PKG_VERSION_FILE} VERSION ${ALLEGRO_VERSION} COMPATIBILITY AnyNewerVersion ) install( TARGETS ${ALLEGRO_TARGETS} EXPORT ${PKG_TARGETS_NAME} ) install( EXPORT ${PKG_TARGETS_NAME} NAMESPACE ${PKG_NAME}:: DESTINATION ${PKG_CONFIG_INSTALL_DIR} ) install( FILES ${PKG_CONFIG_FILE} ${PKG_VERSION_FILE} DESTINATION ${PKG_CONFIG_INSTALL_DIR} ) #-----------------------------------------------------------------------------# # # Documentation # #-----------------------------------------------------------------------------# if(WANT_DOCS) add_subdirectory(docs) endif(WANT_DOCS) #-----------------------------------------------------------------------------# # # Wrappers # #-----------------------------------------------------------------------------# if(WANT_PYTHON_WRAPPER) add_subdirectory(python) endif(WANT_PYTHON_WRAPPER) #-----------------------------------------------------------------------------# # # Configuration summary # #-----------------------------------------------------------------------------# # Output a report string showing what features are supported. message(NOTICE "${SPACER}\n${CONFIGURATION_SUMMARY}${SPACER}\n") #-----------------------------------------------------------------------------# # vim: set sts=4 sw=4 et: allegro5-5.2.10.1/CONTRIBUTORS.txt000066400000000000000000000026301473414355200161570ustar00rootroot00000000000000People who have contributed code to Allegro 5: Aaron Bolyard Aldo Nunez Aldrik Ramaekers Andreas Rönnquist Angelo Mottola Arves100 BQ Ben Davis Beoran Boris Carvajal Bruce Pascoe Bruno Félix Rezende Ribeiro Chris Robinson Christian Mauduit (ufoot) Daniel Johnson David Capello Dennis Busch Dennis Gooden Doug Thompson Douglas Mencken Edgar Reynaldo ElectricSolstice Elias Pschernig Eric Botcazou Erich Erstu Evert Glebbeek Firat Salgur Gabriel Queiroz George Foot Grzegorz Adam Hankiewicz Henrik Stokseth Hyena Isaac Cruz Javier González Garcés Jeff Bernard John-Kim Murphy Jonathan Lilliemarck Jonathan Seeley Jordan Woehr Julian Smythe Marcus Calhoun-Lopez Mark Oates Markus Henschel Martijn van Iersel Matt Smith Matthew Leverton Max Savenkov Michael Bukin Michael Swiger Michał Cichoń Miguel A. Gavidia Milan Mimica Nick Black Nick Trout Peter Hull Peter Wang Polybios Reuben Bell Robert MacGregor Robert Ohannessian Rodolfo Lam Ryan Dickie Ryan Gumbs Ryan Patterson Ryan Roden-Corrent Sebastian Krzyszkowiak SiegeLord Simon Naarmann sleepywind Steven Wallace Sven Sandberg Thomas Fjellstrom Tobias Hansen Tobias Scheuer Todd Cope Tom Bass Trent Gamblin Vitaliy V. Tokarev [bk]door.maus beoran gameovera jmasterx juvinious kazzmir koro pedro-w pkrcel simast sleepywind torhu twobit verderten vkensou Please let us know if we left anyone out. We must also thank everyone who contributed to previous versions of Allegro! allegro5-5.2.10.1/LICENSE.txt000066400000000000000000000103371473414355200153070ustar00rootroot00000000000000Copyright (c) 2004-2015 the Allegro 5 Development Team 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. ------------------------------------------------------------------------------- Allegro includes some files from bstrlib under the following terms. Copyright (c) 2002-2008 Paul Hsieh 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 name of bstrlib 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. ------------------------------------------------------------------------------- Allegro includes the following files originally based on SDL 2.0.0: - src/macosx/osxclipboard.c - src/win/wclipboard.c - src/x/xclipboard.c These files are licensed under the under the following terms: Copyright (C) 1997-2013 Sam Lantinga 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. ------------------------------------------------------------------------------- Some Allegro examples use a font from DejaVu fonts, their license can be found here: ------------------------------------------------------------------------------- The Cosmic Protector demo game graphics were made by Tony Huisman, and are included under a Creative Commons BY Attribution license. The music in Cosmic Protector was purchased from a royalty free website and should not be used outside the game. allegro5-5.2.10.1/README.md000077700000000000000000000000001473414355200164302README.txtustar00rootroot00000000000000allegro5-5.2.10.1/README.txt000066400000000000000000000152331473414355200151620ustar00rootroot00000000000000Welcome to Allegro! =================== Allegro is a cross-platform library mainly aimed at video game and multimedia programming. It handles common, low-level tasks such as creating windows, accepting user input, loading data, drawing images, playing sounds, etc. and generally abstracting away the underlying platform. However, Allegro is not a game engine: you are free to design and structure your program as you like. Allegro 5 has the following additional features: - Supported on Windows, Linux, Mac OSX, iPhone and Android - User-friendly, intuitive C API usable from C++ and many other programming languages - Hardware accelerated bitmap and graphical primitive drawing support (via OpenGL or Direct3D) - Audio recording support - Font loading and drawing - Video playback - Abstractions over shaders and low-level polygon drawing - And more! This readme contains general information which applies to all platforms that Allegro builds on. README_cmake.txt discusses some build options for cmake. README_msvc.txt discusses compilation on Windows with Microsoft Visual C/C++. README_make.txt discusses compilation with GNU make. This applies to Unix-like operating systems such as Linux, MacOS X and MinGW on Windows. README_macosx.txt has a few additional notes for MacOS X. README_iphone.txt discusses iPhone operating systems. Requirements ============ We assume you have C and C++ compilers installed and functioning. We support gcc, clang and MSVC. Allegro also requires CMake 3.0 or later to build. You may download it from Library dependencies ==================== Allegro is divided into a core library and a number of addon libraries. The core library depends on certain libraries to function. If you don't have those, nothing will work. These are required for the core library: - DirectX SDK (Windows only) You can get this for MSVC from the Microsoft web site (large download). Alternatively, smaller downloads for MSVC and MinGW are available here: . Some MinGW distributions come with sufficient DirectX SDK to support compiling Allegro. - X11 development libraries (Linux/Unix only) The libraries will be part of your Linux distribution, but you may have to install them explicitly. - OpenGL development libraries (optional only on Windows) The addons, too, may require additional libraries. Since the addons are strictly optional, they are not required to build Allegro, but a lot of functionality may be disabled if they are not present. Windows users may find some precompiled binaries for the additional libraries from . You need to get the `bin` and `lib` packages. The `bin` packages contain DLLs, and the `lib` packages contain the headers and import libraries. Mac users may find some dependencies in Homebrew, Fink or MacPorts. , and Linux users likely have all the dependencies already, except PhysicsFS and DUMB. If your distribution uses separate development packages, they will need to be installed. The packages are probably named *-dev or *-devel. These are the dependencies required for the addons: - libpng and zlib, for PNG image support (Unix and older MinGW only) Home page: Windows binaries: On Windows/Mac OS X/iPhone/Android, PNG image support is available by using the native facilities on the respective operating systems, so libpng is not required. - libjpeg, for JPEG image support (Unix and older MinGW only) Home page: Windows binaries: On Windows/Mac OS X/iPhone/Android, JPEG image support is available by using the native facilities on the respective operating systems, so libjpeg is not required. - libwebp, for WebP image support Home page: On Android, WebP image support is available by using the native facilities of the operating system, so libwebp is not required. - FreeType, for TrueType font support. Home page: Windows binaries: - Ogg Vorbis, a free lossy audio format. (libogg, libvorbis, libvorbisfile) Home page: - Opus, a free lossy audio codec. (libogg, libopus, libopusfile) Home page: - FLAC, a free lossless audio codec. (libFLAC, libogg) Home page: - DUMB, an IT, XM, S3M and MOD player library. (libdumb) Home page: - OpenAL, a 3D audio API. The audio addon can use OpenAL, although the 3D capabilities aren't used. On Mac OS X, OpenAL is *required* but should come with the OS anyway. On Linux and Windows, OpenAL will only be used if you request it, hence there is no reason to install it specifically. - PhysicsFS, provides access to archives, e.g. .zip files. Home page: On Windows it may be a pain to place all these libraries such that they can be found. Please see the README_cmake.txt section on the "deps subdirectory" when the time comes. API documentation ================= To build the documentation you will need Pandoc. Pandoc's home page is Installing Pandoc from source can be challenging, but you can build Allegro without building the documentation. Online documentation is available on the Allegro web site: Building with CMake =================== Building with CMake is a two step process. During the _configuration_ step, cmake will detect your compiler setup and find the libraries which are installed on your system. At the same time, you may select options to customise your build. If you are unsure of what you are doing, leave all the options at the defaults. You must configure Allegro with a separate build directory. For example, mkdir build cd build cmake .. If you configure Allegro to build in the source directory (i.e. `cmake .`) you will get an error message. Delete `CMakeCache.txt` and the `CMakeFiles` directory and re-configure as described above. Once the configuration step is successful, you will invoke another tool to build Allegro. The tool depends on your compiler, but is usually either `make`, or your IDE. To avoid problems, unpack Allegro into a directory *without spaces or other "weird" characters in the path*. This is a known problem. Now read README_msvc.txt, README_make.txt or README_macosx.txt. allegro5-5.2.10.1/README_android.txt000066400000000000000000000311201473414355200166530ustar00rootroot00000000000000Android ======= This port should support Android 3.1 (Honeycomb, API level 13) and above. Dependencies ============ This port depends on having CMake, the Android SDK, the Android NDK and a Java JDK. We assume you are building on Linux or otherwise a Unix-like system, including MSYS. Install the SDK =============== The most simple way is to install Android Studio which by default will place a copy of the SDK into ~/Android/Sdk. Alternatively you can also download the command-line SDK tools. In that case you will have to accept the licenses, for example like this: ~/Android/Sdk/tools/bin/sdkmanager --licenses Install the NDK =============== The most simple way is again to use Android Studio. Create a new project with C++ support and it will ask you if you want to install the NDK and will then proceed to place it into ~/Android/Sdk/ndk-bundle. Alternatively you can download the NDK and place anywhere you like. Java ==== Android Studio comes with a java runtime environment. To use it for building Android libraries set the evironment variable JAVA_HOME like this: export JAVA_HOME=~/android-studio/jre Build dependencies for Allegro ============================== Now you should build the dependencies for the Allegro addons that you want (you can skip this if just want to try out some simple examples). Most of the libraries use the standard GNU build system, and follow the same pattern. For example, to build libpng: tar zxf libpng-1.6.37.tar.xz cd libpng-1.6.37 # see https://developer.android.com/ndk/guides/other_build_systems export ABI=armeabi-v7a export HOST=arm-linux-androideabi export CHOST=armv7a-linux-androideabi export SDK=21 export HOST_TAG=linux-x86_64 export PREFIX=$HOME/allegro/build/deps export NDK=$HOME/Android/Sdk/ndk-bundle export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/$HOST_TAG export AR=$TOOLCHAIN/bin/$HOST-ar export AS=$TOOLCHAIN/bin/$HOST-as export CC=$TOOLCHAIN/bin/$CHOST$SDK-clang export CXX=$TOOLCHAIN/bin/$CHOST$SDK-clang++ export LD=$TOOLCHAIN/bin/$HOST-ld export RANLIB=$TOOLCHAIN/bin/$HOST-ranlib export STRIP=$TOOLCHAIN/bin/$HOST-strip ./configure --host $HOST --prefix $PREFIX make make install For HOST_TAG you will want: linux-x86_64 if you are using Linux darwin-x86_64 in OSX windows in 32-bit Windows windows-x86_64 in 64-bit Windows For ABI and HOST you will generally use the following (use a separate build folder for each): if ABI == "x86" then HOST = "i686-linux-android" if ABI == "x86_64" then HOST = "x86_64-linux-android" if ABI == "armeabi-v7" then HOST = "arm-linux-androideabi" if ABI == "arm64-v8a" then HOST = "aarch64-linux-android" CHOST is HOST, except if ABI is armeabi-v7 then CHOST = "armv7a-linux-android". The above commands will usually install both static and shared libraries into the `deps` directory where it can be found by CMake, next. If you want only static or shared libraries, you can usually pass `--disable-static` or `--disable-shared` to configure. The static libraries should be easier to use (though I often had problems with unresolved symbols when it came to run the programs, to investigate later). If you wish to use shared libraries, be aware that shared objects must be named like "libFOO.so", despite standard practice. Most libraries you build will have version suffixes by default, e.g. libpng16.so.1.6. Renaming the file after it is produced will not work as the versions are embedded as the soname. For libraries built using libtool, you can avoid the version suffixes as follows: make LDFLAGS=-avoid-version make LDFLAGS=-avoid-version install though you may want to edit the Makefiles instead to avoid overriding important flags in LDFLAGS. You need to ensure that CMake finds the the library file that matches the soname. Either delete the symlinks (e.g. libpng.so -> libpng16.so) or modify the paths in CMake variables manually. Building Allegro ================ The following steps will build Allegro for Android. It uses the cmake toolchain provided by the Android NDK. (Adjust the path if yours is not under ~/Android/Sdk/ndk-bundle.) mkdir build_android_armeabi-v7a cd build_android_armeabi-v7a cmake .. -DCMAKE_TOOLCHAIN_FILE=~/Android/Sdk/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_ABI=armeabi-v7a -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWANT_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX=~/allegro/build/deps You can also use all the normal cmake options supported by Allegro or run cmake (or cmake-gui) to modify them. Finally run: make make install Change ANDROID_ABI to whichever architecture you are building for. The recognized architectures are: -DANDROID_ABI="armeabi" -DANDROID_ABI="armeabi-v7a" -DANDROID_ABI="armeabi-v7a with NEON" -DANDROID_ABI="arm64-v8a" -DANDROID_ABI="x86" -DANDROID_ABI="x86_64" See here for more information: https://developer.android.com/ndk/guides/abis.html This produces the normal Allegro native libraries (liballegro-*.so) as well as allegro-release.aar. You may want to add -DWANT_MONOLITH=ON if you prefer a single Allegro library instead of one for each addon. Running examples ================ You need the adb tool (the Android Debug Bridge) set up, and USB debugging enabled on your device or emulator. This can be quite involved, so please refer to the Android tool documentation. There are makefile targets named "run_FOO", so you can install and run examples easily by typing, e.g. make run_speed Many demos and examples do work, minimally, but most do not support touch input or react to orientation changes, etc. Good examples to try are ex_draw_bitmap and ex_touch_input. If you want to build just the .apk for an example, there are targets for that as well: make ex_draw_bitmap_apk adb -d install -r ./examples/ex_draw_bitmap.project/app/build/outputs/apk/debug/app-debug.apk adb -d shell 'am start -n org.liballeg.ex_draw_bitmap/org.liballeg.app.MainActivity' How startup works on Android ============================ The startup process begins with your application's MainActivity class. In the static initialiser for the Activity, you must manually load the shared libraries that you require, i.e. Allegro and its addons, with dependencies loaded first. For a C++ program, you may need to load the shared library of your chosen STL implementation. After that the onCreate method of the AllegroActivity will be executed, which does some Allegro initialisation. Allegro will then load your application from another shared library. The library name can be specified by overriding the constructor in your Activity class, otherwise the default is "libapp.so". After loading, the `main` function in the library is finally called. Poking around in the android/example directory may help. Using Allegro in your game ========================== If you build with examples or demos, look into your build folder for any of them, for example build/demos/speed It will have a folder called speed.project which is a gradle project ready to compile for Android. You can use it as a template for your own game code. (Either by opening it in Android Studio or by using commandline gradle to compile.) Read the next section if you would like to create an Android project using Allegro from scratch. Using Allegro in a new project ============================== Start Android Studio. Note: Android Studio is not strictly required, you can edit the files mentioned below with any text editor instead of in Android Studio and run ./gradlew instead of rebuilding from within the IDE. Android Studio just is usually more convenient to use when porting a game to Android. On the welcome dialog, select "Start a new Android Studio project". On the "Create Android Project" screen, make sure to check the "Include C++ support" checkbox and click Next. On the "Target Android Devices" screen leave everything at the defaults and click Next. On the "Add an Activity to Mobile" screen pick "Empty Activity". On the "Configure Activity" screen leave the defaults and click Next. On the "Customize C++ Support" screen leave everything at defaults and click Finish. You should be able to click the green arrow at the top and run your application. If not make sure to fix any problems in your Android Studio setup - usually it will prompt you to download any missing components like the NDK or (the special Android) CMake. After that you should be able to run your new Android app, either in an emulator or on a real device. The program we now have already shows how to mix native code and Java code, it just does not use Allegro yet. Find MainActivity.java and adapt it to look like this (do not modify your package line at the top though): import org.liballeg.android.AllegroActivity; public class MainActivity extends AllegroActivity { static { System.loadLibrary("allegro"); System.loadLibrary("allegro_primitives"); System.loadLibrary("allegro_image"); System.loadLibrary("allegro_font"); System.loadLibrary("allegro_ttf"); System.loadLibrary("allegro_audio"); System.loadLibrary("allegro_acodec"); System.loadLibrary("allegro_color"); } public MainActivity() { super("libnative-lib.so"); } } If you used the monolith library, you only need a single System.loadLibrary for that. The "import org.liballeg.android.AllegroActivity" line will be red. Let's fix that. Find the allegro-release.aar from build/lib, where build is the build folder you used when building Allegro. Open your Project-level build.gradle and make your "allprojects" section look like this: allprojects { repositories { google() jcenter() flatDir { dirs 'libs' } } } Then copy allegro-release.aar into the app/libs folder of your Android Studio project. For example I did the following: cp ~/allegro-build/lib/allegro-release.aar ~/AndroidStudioProjects/MyApplication/app/libs/ Now open your app-level build.gradle and add this line inside of the dependencies section: implementation "org.liballeg.android:allegro-release:1.0@aar" On older versions of Android studio use this instead: compile "org.liballeg.android:allegro-release:1.0@aar" Next hit the "Sync Now" link that should have appeared at the top of Android Studio. If you look back at MainActivity.java, nothing should be red any longer. Now run your app again. It will open but crash right away. That is because we are still using the sample C++ code. Let's instead use some Allegro code. Find the native-lib.cpp and replace its code with this: #include int main(int argc, char **argv) { al_init(); auto display = al_create_display(0, 0); auto queue = al_create_event_queue(); auto timer = al_create_timer(1 / 60.0); auto redraw = true; al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (true) { if (redraw) { al_clear_to_color(al_map_rgb_f(1, al_get_time() - (int)(al_get_time()), 0)); al_flip_display(); redraw = false; } ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_TIMER) { redraw = true; } } return 0; } The #include will be red. Oh no. Again, let's fix it. Find CMakeLists.txt under External Build Files and add a line like this: include_directories(${ANDROID_NDK_TOOLCHAIN_ROOT}/user/{ARCH}/include) Where ${ANDROID_NDK_TOOLCHAIN_ROOT}/user/{ARCH} should be the path where the Allegro headers were installed during Allegro's "make install", for example: include_directories($HOME/android-toolchain-arm/user/arm/include) Then add a line like this: target_link_libraries(native-lib ${ANDROID_NDK_TOOLCHAIN_ROOT}/user/{ARCH}/lib/liballegro.so) For example: target_link_libraries(native-lib $HOME/android-toolchain-arm/user/arm/lib/liballegro.so) Finally, create these folders in your project: app/src/main/jniLibs/armeabi-v7a app/src/main/jniLibs/arm64-v8a app/src/main/jniLibs/x86 app/src/main/jniLibs/x86_64 app/src/main/jniLibs/mips app/src/main/jniLibs/mips64 And copy the .so files in the corresponding folder for its architecture. You may have to use "Build->Refresh Linked C++ Projects" for Android Studio to pick up the CMakeLists.txt changes. Run the app again. If it worked, congratulations! You just ran your first Allegro program on Android! (The sample code will just flash your screen yellow and red with no way to quit, so you will have to force quit it.) allegro5-5.2.10.1/README_cmake.txt000066400000000000000000000022641473414355200163220ustar00rootroot00000000000000CMake options ------------- Our build system supports many options. Here are some of them: The option `CMAKE_BUILD_TYPE` selects release, debug or profiling configurations. Valid values are: Release, Debug, RelWithDebInfo, MinSizeRel, Profile. The option `SHARED` controls whether libraries are built as shared libraries or static libraries. Shared libraries are built by default. *Note:* For MinGW with gcc < 4, you cannot build a static library because TLS (thread local storage, using __thread) support was not introduced until version 4. There are many options named WANT_*. Unselecting these will prevent the associated addon or feature from being built. HTML and man page documentation will be built by default, but Info and PDF (through pdfLaTeX) can also be selected from the CMake options. deps subdirectory ----------------- As a convenience, you may create a subdirectory called "deps" in the main Allegro directory, or in the build directory. Inside you can place header and library files for dependencies that Allegro will search for. Allegro will search in these locations: deps/include deps/lib deps//include deps//lib allegro5-5.2.10.1/README_iphone.txt000066400000000000000000000053771473414355200165340ustar00rootroot00000000000000iPhone ====== Can use either OpenGL ES 1 or 2 for graphics, by default OpenGL ES 1 is used. The accelerometer axes are reported as joystick axes. Dependencies ------------ The download section on liballeg.org has some pre-compiled iPhone versions of Freetype (.ttf support), Tremor (.ogg support) and Physfs (.zip) support. Make a directory in the root allegro5 directory called deps. Off of that make an include directory and put your headers there. The structure should look like: allegro5 deps include allegro5 freetype2 physfs.h Building using CMake -------------------- To build for the iOS simulator, run these commands from the build directory: cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-iphone.cmake -G Xcode \ -DIOS_PLATFORM="iphonesimulator" .. xcodebuild This will generate the static libraries inside the lib/RelWithDebInfo directory by default. Note that cmake will occasionally pick up the OSX dependencies, rather than the iPhone dependencies. If that happens, you may want to disable the system you don't want via cmake (e.g. -DWANT_PHYSFS=no). You can also open the XCode project (named ALLEGRO.xcodeproj) and run the examples. To build for the iOS device, the procedure is similar. It is easiest to disable the building of demos, examples and tests as those currently require manual modification of the generated XCode project (to enable code signing). cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-iphone.cmake -G Xcode \ -DIOS_PLATFORM="iphoneos" -DWANT_EXAMPLES=off -DWANT_DEMO=off -DWANT_TESTS=off .. xcodebuild This should generate some ARM libraries in the same location. You might need to manually modify the generated XCode project to enable more architectures. Building using a pre-built XCode project ---------------------------------------- If the above doesn't work for you, you can try the pre-built XCode project. Use the Xcode project in misc/Allegro 5 iOS. By default it will build for the simulator. You will have to change the target to build for an iOS device. The project builds armv7/armv7s/arm64 fat binaries. The project is compiled into a single static library (monolith). You can find the resulting library in ~/Library/Developer/Xcode/DerivedData. The Xcode project currently does not build the audio, acodec or video addons. To build them, add the source files, add addons/audio etc to your header search path and put the dependency includes in deps/include. To install you'll have to copy the library (in DerivedData/*) and the headers manually. The headers you need are the ones you copied to deps, plus the ones in allegro5/include plus /allegro5 for each of the addons. allegro5-5.2.10.1/README_macosx.txt000066400000000000000000000046641473414355200165420ustar00rootroot00000000000000Mac OS X-specific notes ======================= Building Allegro on Mac OS X is the same as on other Unix-like operating systems. See README_make.txt. Building with Xcode ------------------- You may also use Xcode to build Allegro. This works similar to the instructions in README_make.txt, except add the parameter -GXcode when invoking cmake. Instead of creating a makefile this will create an Xcode project which you can double click and open in Xcode and then hit the arrow button to compile. Using the Clang compiler (OS X 10.6+) ------------------------------------- It is possible to build Allegro using the Clang compiler that ships with OS X 10.6 (Snow Leopard). Clang is installed in /Developer/usr/bin. To use it, you have to tell Cmake to use Clang instead of gcc. From the terminal, this is most easily accomplished by the commands export PATH=/Developer/usr/bin:$PATH export CC=clang before you run Cmake. If you use the graphical version of Cmake, you will be given the option of selecting the C compiler to use. Simply select /Developer/usr/bin/clang. The installation otherwise continues as usual. Retina display support (OS X 10.7+) ----------------------------------- Allegro has an option to support high DPI displays by treating them as a regular high-resolution display. To do so, use XCode to set the NSHighResolutionCapable property in the Info.plist of your bundled app to YES. Alternatively, add these two lines to the Info.plist using a text editor: NSHighResolutionCapable If you are making an unbundled app this feature appears to be enabled by default, but it is not recommended to rely on this working: make a bundled app for the most predictable behavior. Allegro uses a pixel-based coordinate system, meaning that high-DPI displays will be larger than is reported by the OS. When changing the display DPI or moving the window between two displays with different DPIs, Allegro displays behave in the following way: - If the ALLEGRO_DISPLAY was created with the ALLEGRO_RESIZABLE flag it will send an ALLEGRO_DISPLAY_RESIZE event. This will have the effect of your app's window remaining visually the same, while the display size in pixels will increase or decrease. This is the recommended situation. - If the ALLEGRO_DISPLAY was not created with the ALLEGRO_RESIZABLE flag, then the display size in pixels will remain the same, but the app's window will appear to grow or shrink. allegro5-5.2.10.1/README_make.txt000066400000000000000000000033611473414355200161560ustar00rootroot00000000000000Building Allegro with make ========================== This document discusses building Allegro using CMake and GNU make from a terminal window. This document applies to Unix-like operating systems such as Linux, and also Mac OS X and MinGW. 1. Unpack Allegro. 2. Create a build directory under the Allegro directory and go there. cd /path/to/allegro mkdir build cd build 3. Run `cmake` with whatever options you want. See README_cmake.txt for details about options you can set. cmake .. Here ".." is the path to the Allegro directory. Alternatively, you can use `ccmake` (Unix) or `cmake-gui` (Windows) to bring up an interactive option selector. e.g. `ccmake ..` or `cmake-gui ..`. You may need to tell CMake which "generator" to use; cmake -h will tell you which generators are available. We recommend using the Makefile generator (default everywhere except Windows). On MinGW you will have a choice between "MinGW Makefiles" or "MSYS Makefiles". If `sh.exe` is on your PATH then you must use "MSYS Makefiles", otherwise use "MinGW Makefiles". More examples: cmake .. -G "MinGW Makefiles" cmake .. -G "MSYS Makefiles" 4. Now, if that step was successful you can run `make` to build Allegro. On MinGW your make might actually be called `mingw32-make`. make Since multicore processors are common now, you might wish to speed that up by passing a "-j" option, where is the number of parallel jobs to spawn. 5. You may optionally install Allegro into your system path with the install target. make install MinGW users might need to set the MINGDIR environment variable first. The DESTDIR variable is supported for staged installs. make install DESTDIR=/tmp/allegro-package allegro5-5.2.10.1/README_msvc.txt000066400000000000000000000071561473414355200162170ustar00rootroot00000000000000Building Allegro with MSVC ========================== There are a lot of variations to the build process, but we will just stick with one to keep things simple. If you know what you are doing, you can do something else. 1. Unpack Allegro into a directory *without spaces or other "weird" characters in the path*. This is a known problem. 2. Create a build directory under the Allegro directory. Optionally, create a deps directory and place the headers and libraries of third party dependencies in there. See README_cmake.txt about this. 3. Start the Microsoft Visual Studio IDE, then bring up a command prompt by clicking "Tools > Visual Studio 20xx Command Prompt". 4. Make sure cmake is in your PATH. Typing "cmake" should display the help message. If it doesn't, you can set the PATH manually by typing "SET PATH=C:\cmake\bin\;%PATH%" or similar. Make sure the MSVC compiler cl.exe and lib.exe also run correctly. 5. Go to the Allegro build directory: cd \allegro\Build 6. Run CMake to configure everything. We will use the CMake GUI. cmake-gui .. 7. Press "Configure". Watch for messages about missing headers and libraries. If anything is missing, you can give CMake a helping hand by setting _INCLUDE_DIR and _LIBRARY options manually, e.g. if ZLIB is not found you would set ZLIB_INCLUDE_DIR and ZLIB_LIBRARY. You may have to switch to "Advanced View" in order to see the variables. Once done, press "Configure" again. 8. Press "Generate". CMake will now generate a project solution. *Note:* As of the time this is written, CMake has a bug that causes the DLLs in MSVC 10 to be named incorrectly. To work around this, generate MSVC 9 projects instead. You may need to uncomment the line "#define ALLEGRO_HAVE_STDINT_H" in alplatf.h. Alternatively, use nmake instead of project files. 9. Open up the project solution with the MSVC IDE and start building. Running the examples ==================== If you build Allegro as a shared library (the default), the example programs will probably not run as-is, because they cannot find the Allegro DLLs. You may: - manually copy the Allegro DLLs into the Build/examples directory where they will be found when the example is run; or - build the INSTALL project, which copies the library files into the MSVC search path (%VCINSTALLDIR%\bin). You may not want to make a mess in there. - The most drastic solution is to copy them into your C:\WINDOWS\SYSTEM32 directory, but most people prefer not to make a mess in that directory. By default, Allegro will load FLAC and Ogg Vorbis DLLs at runtime. If it cannot find them, FLAC and Vorbis file format support will be disabled. Again, the solution is to copy those DLLs where they can be found. Hints on setting up Visual C++ 2005 Express Edition =================================================== After installing Visual C++, you need to install the Platform SDK (or Windows SDK), otherwise CMake will fail at a linking step. You can do a web install to avoid downloading a massive file. For me, installation seemed to take an inordinately long (half an hour or more), but eventually it completed. Don't be too quick to hit Cancel. You also need to install the DirectX SDK. This is a big download, which I don't know how to avoid. Next, you'll need to tell VC++ about the Platform SDK. Start the IDE. Under "Tools > Options > Projects and Solutions > VC++ Directories", add the Platform SDK executable (bin), include and lib directories to the respective lists. The DirectX SDK seems to add itself when it's installed. For debugging, use the DirectX control panel applet to switch to the debugging runtime. It's really useful. allegro5-5.2.10.1/README_packaging.txt000066400000000000000000000005731473414355200171670ustar00rootroot00000000000000Note to packagers (e.g. for Linux distributions) ------------------------------------------------ Allegro 5.x is *not* source compatible with Allegro 4.2.x or 4.4.x. When packaging Allegro 5, please make it possible for users to install Allegro 4.x and 5.x simultaneously. For example, if you already have an 'allegro' package, then you might name the new package 'allegro5'. allegro5-5.2.10.1/README_pkgconfig.txt000066400000000000000000000041751473414355200172140ustar00rootroot00000000000000Using pkg-config with Allegro ============================= On Unix-like operating systems, we use the pkg-config tool to simplify the process of linking with Allegro. To print the list of Allegro libraries installed, you can run: pkg-config --list-all | grep allegro You may need to set the PKG_CONFIG_PATH environment variable appropriately if /usr/local/lib/pkgconfig is not hardcoded for your version of pkg-config or if you installed to a non-standard location. For example: export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig To print the command line options required to link with the core Allegro library and the image addon, you would run: pkg-config --libs allegro-5 allegro_image-5 which outputs something like: -L/usr/lib -lallegro_image -lallegro If you use static libraries, you need to add the --static option: pkg-config --libs --static allegro-static-5 allegro_image-static-5 which will include additional libraries needed for static linking. This can be combined with shell command substitution: gcc mygame.c -o mygame $(pkg-config --libs allegro-5 allegro_image-5) If Allegro is installed to a non-standard location, the compiler will need command line options to find the header files. The pkg-config `--cflags` option provides that information. You can combine it with `--libs` as well: pkg-config --cflags --libs allegro-5 allegro_image-5 Most build systems will allow you to call pkg-config in a similar way to the shell. For example, a very basic Makefile might look like this: ALLEGRO_LIBRARIES := allegro-5 allegro_image-5 ALLEGRO_FLAGS := $(shell pkg-config --cflags --libs $(ALLEGRO_LIBRARIES)) mygame: mygame.c $(CC) -o $@ $^ $(ALLEGRO_FLAGS) Historical note --------------- Prior to Allegro 5.0.9 the .pc files were named allegro-5.0.pc and so on. To ease transitioning to future versions of Allegro the minor version number was dropped, leaving allegro-5.pc and so on. The old names are deprecated but will remain available in 5.0.x releases. Configuration scripts should look for Allegro using the new pkg-config names first, then the old names, for greater compatibility. allegro5-5.2.10.1/README_raspberrypi.txt000066400000000000000000000016701473414355200176040ustar00rootroot00000000000000Building -------- mkdir build cd build cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-raspberrypi.cmake make Virtual machine --------------- Building with a cross compiler is not yet documented. Building directly on a Raspberry Pi or in a Raspberry Pi VM is very similar to building on "regular" Linux. apt-get install the -dev packages you need, run cmake and make sure everything you need is found. For example, you can use an image from: http://www.raspberrypi.org/downloads and a kernel: http://xecdesign.com/downloads/linux-qemu/kernel-qemu With a qemu command line like: qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m 256 -M versatilepb \ -no-reboot -serial stdio -append "root=/dev/sda2 panic=1" \ -hda 2012-12-16-wheezy-raspbian.img \ -redir tcp:2222::22 -net nic -net user You can ssh into the VM with: ssh -p 2222 pi@127.0.0.1 Within the guest you can access the host at 10.0.2.2. allegro5-5.2.10.1/README_releasing.txt000066400000000000000000000056101473414355200172110ustar00rootroot00000000000000How to Make a Release --------------------- This guide explains how to make an Allegro release. This all assumes that we're on Linux. 1. Starting with the master branch, pick a commit which you want to be the base of the release branch. Typically this will be HEAD, but if there are some unbaked commits there, you may want to use an earlier commit. Call this branch with the new release name (e.g. 5.2.2 in this case): git branch 5.2.2 master From now on, aside from changing the version numbers, all commits on this release branch should be cherry-picked from the master branch. For all cherry-picks, prefer using the -x switch, like so: git cherry-pick -x badf00d 2. On the master branch, bump the version to the next release in `include/allegro5/base.h` and then update the dates by using the `misc/fixver.sh` script. Commit this change. 3. Write a changelog file. This is located in docs/src/changes-5.2.txt. Typically you will want to look through the commits made since the last release, e.g. using `git log ..` (e.g. `git log 5.2.1..5.2.2`). Follow the format of the previous changelogs. It's up to you how to determine who are the 'main developers'. For the 5.1.9+ release, I've abitrarily determined it to be developers who've committed 95% of the lines of code (this isn't very important). You probably will want to have other developers check it over in case something is wrong/missing. Commit this change. 4. We are now done with the master branch. You can push these changes to github. Check out the release branch now. 5. Cherry-pick the commit with the changelog onto this branch. 6. Bump the version from "GIT" to "WIP" if it's unstable, or remove "GIT" if it's stable, while preserving the major, minor and patch numbers, but increasing the release number by 1. Also, update the dates at this time. This is all done in `include/allegro5/base.h`. Commit this change. 7. Tag the previous commit with the same version number and the release number (e.g. "5.2.2.0" if you're releasing 5.2.2. An example command would be: git tag -a -m "Tag 5.2.2.0 (WIP)" 5.2.2.0 8. Create the source archives by running `misc/create_release_archives.sh` and passing in the release version. This will create 3 source archives (.tar.gz, .7z and .zip) in the current directory. And example invocation would be: ./misc/create_release_archives.sh 5.2.2.0 9. Upload the source archives to github. Go to the releases tab, and make a new release with the tag you just created. 10. Build the docs, including the pdf. Add these to the website via the liballeg.github.io repository. 11. Make an announcement on the website. This involves making a news item, changing the download area and copy-pasting the change list. 12. Make an announcement on allegro.cc. You're done! allegro5-5.2.10.1/README_sdl.txt000066400000000000000000000055311473414355200160240ustar00rootroot00000000000000SDL === This is an experimental port which uses SDL2 to create the Allegro window and OpenGL context. Dependencies ------------ SDL2 is required. Building -------- Pass -D ALLEGRO_SDL=on to cmake to enable building for SDL2. Limitations ----------- SDL2 requires calling SDL_PumpEvents() from the main thread regularly to generate events. Currently Allegro5 makes those calls from the timer subsystem - so as long as you have any timers running things will work fine. If your Allegro 5 program uses no timers it may get stuck because no SDL2 events can be received. Emscripten ---------- One reason the SDL2 port is useful is that it allows running Allegro on platforms not supported directly by Allegro, such as Emscripten. This is even more experimental but here are some example steps that will compile most of the examples for running in a web browser: 1. Make sure to set up the emscripten environment by running the emsdk_env.sh or equivalent as provided by emscripten. 2. Create a build folder. mkdir build_emscripten cd build_emscripten If you're going to build a demo, you will need to manually create a file: mkdir -p demos/speed/data touch demos/speed/data/nothing.txt 3. Configure CMake, using emcmake. ``` USE_FLAGS=( -s USE_FREETYPE=1 -s USE_VORBIS=1 -s USE_OGG=1 -s USE_LIBJPEG=1 -s USE_SDL=2 -s USE_LIBPNG=1 -s FULL_ES2=1 -s ASYNCIFY -s TOTAL_MEMORY=2147418112 -O3 ) # You may need to set this yourself. EM_CACHE=path-to-emsdk/upstream/emscripten/cache emcmake cmake .. \ -D CMAKE_BUILD_TYPE=Release \ -D ALLEGRO_SDL=ON \ -D SHARED=OFF \ -D WANT_MONOLITH=ON \ -D WANT_ALLOW_SSE=OFF \ -D WANT_DOCS=OFF \ -D WANT_TESTS=OFF \ -D WANT_OPENAL=OFF \ -D ALLEGRO_WAIT_EVENT_SLEEP=ON \ -D SDL2_INCLUDE_DIR=$EM_CACHE/sysroot/include \ -D CMAKE_C_FLAGS="${USE_FLAGS[*]}" \ -D CMAKE_CXX_FLAGS="${USE_FLAGS[*]}" \ -D CMAKE_EXE_LINKER_FLAGS="${USE_FLAGS[*]} --preload-file data" \ -D CMAKE_EXECUTABLE_SUFFIX_CXX=".html" ``` Emscripten will take care of downloading the dependencies mentioned above via its ports system. To compile your own game adjust as necessary. You can use the lib/liballegro_monolith-static.a library. 4. Compile the library and examples. make Since that can take awhile (a lot slower than regular compilation speed), you may want to compile individual examples, e.g. make ex_draw_bitmap Note: If you make any changes to any data/ files, you will need to manually delete the generated .html file in /examples to force emscripten to regenerate the .data file. 5. To run the examples, navigate to the examples folder. At this point it is easiest to start a local webserver, and then navigate to the examples using a web browser. E.g. you could use the Python's web server module which prints out a URL you can open: python3 -m http.server allegro5-5.2.10.1/README_windows.txt000066400000000000000000000025141473414355200167320ustar00rootroot00000000000000Windows-specific notes ====================== DPI Awareness ------------- By default, apps created with Allegro are marked as DPI aware, and are not scaled by the OS. This is mostly transparent on your end, the only complication comes when the DPI changes on the fly (e.g. your app's window gets moved between displays with different DPIs): - If the ALLEGRO_DISPLAY was created with the ALLEGRO_RESIZABLE flag it will send an ALLEGRO_DISPLAY_RESIZE event. This will have the effect of your app's window remaining visually the same, while the display size in pixels will increase or decrease. This is the recommended situation. - If the ALLEGRO_DISPLAY was not created with the ALLEGRO_RESIZABLE flag, then the display size in pixels will remain the same, but the app's window will appear to grow or shrink. If you for some reason want to opt out of DPI-awareness, utilize the application manifests to specify that your app is not DPI-aware. Runtime DLL Loading ------------------- For some of its features, Allegro will look for certain DLLs on the system it runs on, but will not explicitly depend them at build time. These are as follows: - msftedit.dll or riched20.dll or riched32.dll - For the native dialog addon. - d3dx9_${version}.dll - Shader support for the Direct3D backend. - xinput1_${version}.dll - XInput-based joysticks. allegro5-5.2.10.1/SECURITY.md000066400000000000000000000013541473414355200152540ustar00rootroot00000000000000# Security Policy ## Report a security issue The Allegro project team welcomes security reports and is committed to providing prompt attention to security issues. Security issues should be reported privately by sending an email to . ## Version support | Version | Supported | | ------- | ------------------ | | >= 5.2.x| Yes | | < 5.2 | No | ## Security advisories Remediation of security vulnerabilities is prioritized by the project team based on the overall impact. The project team is committed to transparency in the disclosure process. The Allegro team announces security issues Allegro Release notes, as well as the Allegro website on a best-effort basis. allegro5-5.2.10.1/addons/000077500000000000000000000000001473414355200147305ustar00rootroot00000000000000allegro5-5.2.10.1/addons/CMakeLists.txt000066400000000000000000000234001473414355200174670ustar00rootroot00000000000000# FOO_LINK_WITH and SUPPORT_FOO need to be propagated up to the parent scope so # examples know if they can use the FOO addon, and what to link against. # FOO_LINK_WITH should be the name of a single target. The target should # automatically pull in dependencies so they don't need to be listed. include(FindPackageHandleStandardArgs) set(ADDON_PKG_CONFIG_FILES) set(ADDONS_CONFIGURATION_SUMMARY "") function(addons_summary msg yesno) if(${yesno}) set(yesno "yes") else() # No's are more important, so shout them. set(yesno "NO") endif() set(ADDONS_CONFIGURATION_SUMMARY "${ADDONS_CONFIGURATION_SUMMARY}${msg}: ${yesno}\n" PARENT_SCOPE) endfunction() if(WANT_PRIMITIVES) add_subdirectory(primitives) set(SUPPORT_PRIMITIVES 1) set(SUPPORT_PRIMITIVES 1 PARENT_SCOPE) set(PRIMITIVES_LINK_WITH ${PRIMITIVES_LINK_WITH} PARENT_SCOPE) list(APPEND ADDON_PKG_CONFIG_FILES allegro_primitives) endif(WANT_PRIMITIVES) addons_summary("- Primitives addon" SUPPORT_PRIMITIVES) if(WANT_IMAGE) add_subdirectory(image) set(SUPPORT_IMAGE 1) set(SUPPORT_IMAGE 1 PARENT_SCOPE) set(IMAGE_LINK_WITH ${IMAGE_LINK_WITH} PARENT_SCOPE) list(APPEND ADDON_PKG_CONFIG_FILES allegro_image) endif(WANT_IMAGE) addons_summary("- Image addon" SUPPORT_IMAGE) set(ADDONS_CONFIGURATION_SUMMARY "${ADDONS_CONFIGURATION_SUMMARY}${IMAGE_CONFIGURATION_SUMMARY}") if(WANT_FONT AND SUPPORT_IMAGE) add_subdirectory(font) set(SUPPORT_FONT 1) set(SUPPORT_FONT 1 PARENT_SCOPE) set(FONT_LINK_WITH ${FONT_LINK_WITH} PARENT_SCOPE) list(APPEND ADDON_PKG_CONFIG_FILES allegro_font) endif(WANT_FONT AND SUPPORT_IMAGE) addons_summary("- Font addon" SUPPORT_FONT) if(WANT_AUDIO) add_subdirectory(audio) if(SUPPORT_AUDIO) set(SUPPORT_AUDIO 1 PARENT_SCOPE) set(AUDIO_LINK_WITH ${AUDIO_LINK_WITH} PARENT_SCOPE) list(APPEND ADDON_PKG_CONFIG_FILES allegro_audio) endif(SUPPORT_AUDIO) endif(WANT_AUDIO) addons_summary("- Audio addon" SUPPORT_AUDIO) set(ADDONS_CONFIGURATION_SUMMARY "${ADDONS_CONFIGURATION_SUMMARY}${AUDIO_CONFIGURATION_SUMMARY}") if(SUPPORT_AUDIO) add_subdirectory(acodec) if(SUPPORT_ACODEC) set(SUPPORT_ACODEC 1 PARENT_SCOPE) set(ACODEC_LINK_WITH ${ACODEC_LINK_WITH} PARENT_SCOPE) list(APPEND ADDON_PKG_CONFIG_FILES allegro_acodec) endif(SUPPORT_ACODEC) endif(SUPPORT_AUDIO) addons_summary("- Acodec addon" SUPPORT_ACODEC) set(ADDONS_CONFIGURATION_SUMMARY "${ADDONS_CONFIGURATION_SUMMARY}${ACODEC_CONFIGURATION_SUMMARY}") if(SUPPORT_FONT AND WANT_TTF) find_package(Freetype) option(FREETYPE_ZLIB "Enable if FreeType static library needs zlib linked in." off) option(FREETYPE_BZIP2 "Enable if FreeType static library needs bzip2 linked in." off) option(FREETYPE_PNG "Enable if FreeType static library needs png linked in." off) option(FREETYPE_HARFBUZZ "Enable if FreeType static library needs harfbuzz linked in." off) if(FREETYPE_FOUND) set(FREETYPE_TEST_SOURCE " #include #include FT_FREETYPE_H int main(void) { FT_Library ft; FT_Open_Args args; FT_Face face; FT_Int32 ft_load_flags; FT_Error e; int ft_index; FT_Init_FreeType(&ft); FT_Open_Face(ft, &args, 0, &face); return FT_Load_Glyph(face, ft_index, ft_load_flags); }") set(TTF_INCLUDE_DIRECTORIES ${FREETYPE_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${FREETYPE_LIBRARIES}) set(CMAKE_REQUIRED_INCLUDES ${FREETYPE_INCLUDE_DIRS}) run_c_compile_test("${FREETYPE_TEST_SOURCE}" TTF_COMPILES) if(TTF_COMPILES) set(TTF_LIBRARIES ${FREETYPE_LIBRARIES}) else() if(FREETYPE_ZLIB) find_package(ZLIB) endif() if(FREETYPE_BZIP2) find_package(BZip2) endif() if(FREETYPE_PNG) find_package(PNG) endif() if (FREETYPE_HARFBUZZ) find_package(HarfBuzz) endif() # Try compiling with the extra dependencies. set(FREETYPE_STATIC_LIBRARIES ${FREETYPE_LIBRARIES}) if(FREETYPE_ZLIB AND ZLIB_FOUND) list(APPEND FREETYPE_STATIC_LIBRARIES "${ZLIB_LIBRARIES}") endif() if(FREETYPE_BZIP2 AND BZIP2_FOUND) list(APPEND FREETYPE_STATIC_LIBRARIES "${BZIP2_LIBRARIES}") endif() if(FREETYPE_PNG AND PNG_FOUND) list(APPEND FREETYPE_STATIC_LIBRARIES "${PNG_LIBRARIES}") endif() if (FREETYPE_HARFBUZZ AND HARFBUZZ_FOUND) # there's a circular dependency between Harfbuzz and Freetype, so one of them has to be # repeated to ensure proper static linking order list(APPEND FREETYPE_STATIC_LIBRARIES "${HARFBUZZ_LIBRARIES}" "${FREETYPE_LIBRARIES}") endif() set(CMAKE_REQUIRED_LIBRARIES ${FREETYPE_STATIC_LIBRARIES}) set(CMAKE_REQUIRED_INCLUDES ${FREETYPE_INCLUDE_DIRS}) run_c_compile_test("${FREETYPE_TEST_SOURCE}" TTF_COMPILES_WITH_EXTRA_DEPS) if(TTF_COMPILES_WITH_EXTRA_DEPS) set(TTF_COMPILES 1) set(TTF_LIBRARIES ${FREETYPE_STATIC_LIBRARIES}) endif() endif() set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) if(TTF_COMPILES) add_subdirectory(ttf) set(SUPPORT_TTF 1 PARENT_SCOPE) set(TTF_LINK_WITH ${TTF_LINK_WITH} PARENT_SCOPE) list(APPEND ADDON_PKG_CONFIG_FILES allegro_ttf) else() message(WARNING "FreeType doesn't compile. Disabling support.") endif() else(FREETYPE_FOUND) message("WARNING: FreeType not found, disabling support.") endif(FREETYPE_FOUND) endif(SUPPORT_FONT AND WANT_TTF) addons_summary("- TTF addon" SUPPORT_TTF) if(WANT_COLOR) add_subdirectory(color) set(SUPPORT_COLOR 1 PARENT_SCOPE) set(COLOR_LINK_WITH ${COLOR_LINK_WITH} PARENT_SCOPE) list(APPEND ADDON_PKG_CONFIG_FILES allegro_color) endif(WANT_COLOR) addons_summary("- Color addon" SUPPORT_COLOR) if(WANT_MEMFILE) add_subdirectory(memfile) set(SUPPORT_MEMFILE 1 PARENT_SCOPE) set(MEMFILE_LINK_WITH ${MEMFILE_LINK_WITH} PARENT_SCOPE) list(APPEND ADDON_PKG_CONFIG_FILES allegro_memfile) endif(WANT_MEMFILE) addons_summary("- Memfile addon" SUPPORT_MEMFILE) if(WANT_PHYSFS) find_package(PhysFS) # FindPhysFS.cmake in cmake-2.6.2 doesn't call this but it should. find_package_handle_standard_args(PHYSFS DEFAULT_MSG PHYSFS_LIBRARY PHYSFS_INCLUDE_DIR) mark_as_advanced(PHYSFS_INCLUDE_DIR) mark_as_advanced(PHYSFS_LIBRARY) find_package(ZLIB) # Does this copy of PhysicsFS require zlib to be linked separately? # FindPhysFS should really figure this out for us, but it doesn't. if(PHYSFS_FOUND) set(CMAKE_REQUIRED_INCLUDES ${PHYSFS_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${PHYSFS_LIBRARY}) run_c_compile_test(" #include int main(int argc, char **argv) { (void)argc; PHYSFS_init(argv[0]); PHYSFS_deinit(); return 0; }" PHYSFS_IMPLICIT_ZLIB) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) if(PHYSFS_IMPLICIT_ZLIB) set(PHYSFS_LIBRARIES ${PHYSFS_LIBRARY}) set(SUPPORT_PHYSFS 1) elseif(ZLIB_FOUND) set(PHYSFS_LIBRARIES ${PHYSFS_LIBRARY} ${ZLIB_LIBRARY}) set(SUPPORT_PHYSFS 1) else() message("WARNING: PhysicsFS needs zlib, zlib not found, disabling PhysFS support.") endif() endif(PHYSFS_FOUND) if(SUPPORT_PHYSFS) add_subdirectory(physfs) set(SUPPORT_PHYSFS 1 PARENT_SCOPE) set(PHYSFS_LINK_WITH ${PHYSFS_LINK_WITH} PARENT_SCOPE) list(APPEND ADDON_PKG_CONFIG_FILES allegro_physfs) endif(SUPPORT_PHYSFS) endif(WANT_PHYSFS) addons_summary("- PhysFS addon" SUPPORT_PHYSFS) if(WANT_NATIVE_DIALOG) add_subdirectory(native_dialog) if(SUPPORT_NATIVE_DIALOG) set(SUPPORT_NATIVE_DIALOG 1 PARENT_SCOPE) set(NATIVE_DIALOG_LINK_WITH ${NATIVE_DIALOG_LINK_WITH} PARENT_SCOPE) list(APPEND ADDON_PKG_CONFIG_FILES allegro_dialog) endif() endif(WANT_NATIVE_DIALOG) addons_summary("- Native Dialog addon" SUPPORT_NATIVE_DIALOG) if(WANT_VIDEO) add_subdirectory(video) if(SUPPORT_VIDEO) set(SUPPORT_VIDEO 1 PARENT_SCOPE) set(VIDEO_LINK_WITH ${VIDEO_LINK_WITH} PARENT_SCOPE) list(APPEND ADDON_PKG_CONFIG_FILES allegro_video) endif(SUPPORT_VIDEO) endif(WANT_VIDEO) addons_summary("- Video addon" SUPPORT_VIDEO) add_subdirectory(main) # SUPPORT_MAIN and MAIN_LINK_WITH are spelt as such in this scope, # but are prefixed with ALLEGRO in the parent scope. set(SUPPORT_ALLEGRO_MAIN ${SUPPORT_MAIN} PARENT_SCOPE) set(ALLEGRO_MAIN_LINK_WITH ${MAIN_LINK_WITH} PARENT_SCOPE) list(APPEND ADDON_PKG_CONFIG_FILES allegro_main) set(MONOLITH_SOURCES ${MONOLITH_SOURCES} PARENT_SCOPE) set(MONOLITH_INCLUDE_DIRECTORIES ${MONOLITH_INCLUDE_DIRECTORIES} PARENT_SCOPE) set(MONOLITH_LINK_DIRECTORIES ${MONOLITH_LINK_DIRECTORIES} PARENT_SCOPE) set(MONOLITH_LIBRARIES ${MONOLITH_LIBRARIES} PARENT_SCOPE) set(MONOLITH_HEADERS ${MONOLITH_HEADERS} PARENT_SCOPE) set(MONOLITH_DEFINES ${MONOLITH_DEFINES} PARENT_SCOPE) set(ADDON_PKG_CONFIG_FILES ${ADDON_PKG_CONFIG_FILES} PARENT_SCOPE) set(CONFIGURATION_SUMMARY "${CONFIGURATION_SUMMARY}${ADDONS_CONFIGURATION_SUMMARY}" PARENT_SCOPE) #-----------------------------------------------------------------------------# # vi: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/addons/acodec/000077500000000000000000000000001473414355200161465ustar00rootroot00000000000000allegro5-5.2.10.1/addons/acodec/CMakeLists.txt000066400000000000000000000357711473414355200207230ustar00rootroot00000000000000include_directories(../audio) option(WANT_FLAC "Enable FLAC support" on) if(WIN32) option(FLAC_STATIC "Set this if linking with a static FLAC library" off) endif() option(WANT_VORBIS "Enable Ogg Vorbis support using libvorbis" on) option(WANT_TREMOR "Enable Ogg Vorbis support using Tremor" off) option(WANT_OPUS "Enable Opus support using libopus" on) option(WANT_DUMB "Enable mod audio support using DUMB" on) option(WANT_OPENMPT "Enable mod audio support using OpenMPT" on) option(WANT_ACODEC_DYNAMIC_LOAD "Enable DLL loading in acodec (Windows)" off) option(WANT_MP3 "Enable MP3 support" on) #-----------------------------------------------------------------------------# set(ACODEC_INCLUDE_FILES allegro5/allegro_acodec.h ) set_our_header_properties(${ACODEC_INCLUDE_FILES}) set(ACODEC_SOURCES acodec.c wav.c helper.c voc.c # built-in enhanced port of A4 loader ) set(ACODEC_LIBRARIES) # For dynamic loading, we want to make sure that CMake has found an import # library and not a static library. We assume that the name of the DLL to load # is the same as the import library, bar the extension. # # With MSVC, static libraries and import libraries share the same extension. # Luckily the MSVC static libraries for FLAC and Vorbis are named with a # _static suffix. # With MinGW, static libraries end with .a, and import libraries end with # .dll.a so we can tell them apart. (The regex for this is a bodge.) set(WIN32_STATIC_LIB_REGEX "_static[.]|[^l][.]a") function(get_dll_name implib dllname_var) if(MINGW) # Guess the name of dlltool from gcc. string(REGEX REPLACE "gcc.*" dlltool DLLTOOL ${CMAKE_C_COMPILER}) execute_process( COMMAND ${DLLTOOL} -I ${implib} OUTPUT_VARIABLE dllname OUTPUT_STRIP_TRAILING_WHITESPACE ) elseif(MSVC) # Not sure this is the best way. execute_process( COMMAND lib /LIST ${implib} OUTPUT_VARIABLE output ) if(output STREQUAL "") message("WARNING: Failed to execute lib /list") else() string(REGEX MATCH "[^\n]+[.]dll" dllname "${output}") endif() endif() if(NOT dllname) # Guess from the basename. get_filename_component(basename "${implib}" NAME_WE) set(dllname "${basename}.dll") endif() message(STATUS "DLL name for ${implib}: ${dllname}") set(${dllname_var} ${dllname} PARENT_SCOPE) endfunction(get_dll_name) set(ACODEC_CONFIGURATION_SUMMARY "") function(acodec_summary msg yesno) if(${yesno}) set(yesno "yes") else() # No's are more important, so shout them. set(yesno "NO") endif() set(ACODEC_CONFIGURATION_SUMMARY "${ACODEC_CONFIGURATION_SUMMARY}${msg}: ${yesno}\n" PARENT_SCOPE) endfunction() # # FLAC # if(WANT_FLAC) find_package(FLAC) if(FLAC_FOUND) if(FLAC_LIBRARY MATCHES "${WIN32_STATIC_LIB_REGEX}") set(FLAC_STATIC 1) endif() if(FLAC_STATIC) set(FLAC__NO_DLL "-DFLAC__NO_DLL") endif() set(CMAKE_REQUIRED_INCLUDES ${FLAC_INCLUDE_DIR}) if(MSVC) set(CMAKE_REQUIRED_LIBRARIES ${FLAC_LIBRARIES}) else() # FLAC requires libm on Android, doesn't seem to hurt elsewhere either. set(CMAKE_REQUIRED_LIBRARIES ${FLAC_LIBRARIES} m) endif() set(CMAKE_REQUIRED_DEFINITIONS ${FLAC__NO_DLL}) run_c_compile_test(" #include int main(void) { (void)FLAC__stream_decoder_new(); return 0; }" FLAC_COMPILES) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) set(CMAKE_REQUIRED_DEFINITIONS) if(FLAC_COMPILES) set(SUPPORT_FLAC 1) endif(FLAC_COMPILES) endif(FLAC_FOUND) if(NOT SUPPORT_FLAC) message("WARNING: libFLAC not found or compile test failed, disabling support.") endif(NOT SUPPORT_FLAC) endif(WANT_FLAC) if(SUPPORT_FLAC) include_directories(SYSTEM ${FLAC_INCLUDE_DIR}) set(ALLEGRO_CFG_ACODEC_FLAC 1) list(APPEND ACODEC_SOURCES flac.c) list(APPEND ACODEC_INCLUDE_DIRECTORIES ${FLAC_INCLUDE_DIR}) if(WIN32) if(WANT_ACODEC_DYNAMIC_LOAD) if(FLAC_STATIC) message("WARNING: Dynamic loading will be disabled for FLAC as" " static library was found: ${FLAC_LIBRARY}") else() get_dll_name(${FLAC_LIBRARY} ALLEGRO_CFG_ACODEC_FLAC_DLL) endif() endif() endif(WIN32) if(NOT ALLEGRO_CFG_ACODEC_FLAC_DLL) list(APPEND ACODEC_LIBRARIES ${FLAC_LIBRARIES}) endif() endif(SUPPORT_FLAC) acodec_summary(" - FLAC" SUPPORT_FLAC) # # MOD audio # if(WANT_DUMB) find_package(DUMB) if(DUMB_FOUND) set(CMAKE_REQUIRED_INCLUDES ${DUMB_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${DUMB_LIBRARIES}) run_c_compile_test(" #define _FILE_OFFSET_BITS 64 #include #if (DUMB_MAJOR_VERSION) == 1 #error libdumb 1.0 not supported, get >= 2.0 or 0.9.3 #endif int main(void) { dumb_register_stdfiles(); return 0; }" DUMB_COMPILES) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) if(DUMB_COMPILES) set(SUPPORT_DUMB 1) endif(DUMB_COMPILES) endif(DUMB_FOUND) if(NOT SUPPORT_DUMB) message("WARNING: libdumb >= 2.0 or <= 0.9.3 not found or compile " "test failed, disabling support. See " " for 2.0 or " " for 0.9.3.") endif(NOT SUPPORT_DUMB) endif(WANT_DUMB) if(SUPPORT_DUMB) include_directories(SYSTEM ${DUMB_INCLUDE_DIR}) set(ALLEGRO_CFG_ACODEC_DUMB 1) list(APPEND ACODEC_SOURCES dumb.c) list(APPEND ACODEC_INCLUDE_DIRECTORIES ${DUMB_INCLUDE_DIR}) if(WIN32 AND WANT_ACODEC_DYNAMIC_LOAD) if(DUMB_LIBRARY MATCHES "${WIN32_STATIC_LIB_REGEX}") message("WARNING: Dynamic loading will be disabled for DUMB" " as static library was found: ${DUMB_LIBRARY}") else() get_dll_name(${DUMB_LIBRARY} ALLEGRO_CFG_ACODEC_DUMB_DLL) endif() endif() if(NOT ALLEGRO_CFG_ACODEC_DUMB_DLL) list(APPEND ACODEC_LIBRARIES ${DUMB_LIBRARIES}) endif() endif() acodec_summary(" - DUMB" SUPPORT_DUMB) if(WANT_OPENMPT) find_package(OpenMPT) option(OPENMPT_ZLIB "Enable if OpenMPT static library needs zlib linked in." off) option(OPENMPT_VORBIS "Enable if OpenMPT static library needs Ogg/Vorbis linked in." off) if(OPENMPT_FOUND) set(CMAKE_REQUIRED_INCLUDES ${OPENMPT_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${OPENMPT_LIBRARIES}) set(OPENMPT_TEST_SOURCE " #include #include int main(void) { openmpt_module *mod = openmpt_module_create( openmpt_stream_get_file_callbacks(), NULL, NULL, NULL, NULL); openmpt_module_read_interleaved_stereo(mod, 44100, 1, NULL); return 0; }") run_cxx_compile_test( "${OPENMPT_TEST_SOURCE}" OPENMPT_COMPILES) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) if(OPENMPT_COMPILES) set(SUPPORT_OPENMPT 1) set(ALL_OPENMPT_LIBRARIES ${OPENMPT_LIBRARIES}) else() if(OPENMPT_ZLIB) find_package(ZLIB) endif() if(OPENMPT_VORBIS) find_package(Vorbis) endif() # Try compiling with the extra dependencies. set(OPENMPT_STATIC_LIBRARIES ${OPENMPT_LIBRARIES}) if(OPENMPT_ZLIB AND ZLIB_FOUND) list(APPEND OPENMPT_STATIC_LIBRARIES "${ZLIB_LIBRARIES}") endif() if(OPENMPT_VORBIS AND VORBIS_FOUND) list(APPEND OPENMPT_STATIC_LIBRARIES "${VORBIS_LIBRARIES}") endif() set(CMAKE_REQUIRED_LIBRARIES ${OPENMPT_STATIC_LIBRARIES}) set(CMAKE_REQUIRED_INCLUDES ${OPENMPT_INCLUDE_DIR}) run_cxx_compile_test("${OPENMPT_TEST_SOURCE}" OPENMPT_COMPILES_WITH_EXTRA_DEPS) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) if(OPENMPT_COMPILES_WITH_EXTRA_DEPS) set(SUPPORT_OPENMPT 1) set(ALL_OPENMPT_LIBRARIES ${OPENMPT_STATIC_LIBRARIES}) endif() endif() endif() endif() if(SUPPORT_OPENMPT) include_directories(SYSTEM ${OPENMPT_INCLUDE_DIR}) set(ALLEGRO_CFG_ACODEC_OPENMPT 1) list(APPEND ACODEC_SOURCES openmpt.c) list(APPEND ACODEC_INCLUDE_DIRECTORIES ${OPENMPT_INCLUDE_DIR}) list(APPEND ACODEC_LIBRARIES ${ALL_OPENMPT_LIBRARIES}) endif() acodec_summary(" - OpenMPT" SUPPORT_OPENMPT) if(SUPPORT_OPENMPT OR SUPPORT_DUMB) list(APPEND ACODEC_SOURCES modaudio.c) endif(SUPPORT_OPENMPT OR SUPPORT_DUMB) # # Vorbis/Tremor # if(WANT_TREMOR) find_package(Tremor) if(TREMOR_FOUND) set(CMAKE_REQUIRED_INCLUDES ${TREMOR_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${TREMOR_LIBRARIES}) run_c_compile_test(" #include int main(void) { OggVorbis_File f; ov_info(&f, -1); return 0; }" TREMOR_COMPILES) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) if(TREMOR_COMPILES OR IPHONE OR ALLEGRO_RASPBERRYPI) set(SUPPORT_VORBIS 1) endif(TREMOR_COMPILES OR IPHONE OR ALLEGRO_RASPBERRYPI) endif(TREMOR_FOUND) if(NOT SUPPORT_VORBIS) message("WARNING: Tremor not found although WANT_TREMOR was specified.") else(NOT SUPPORT_VORBIS) # mimic regular libogg/libvorbis set(OGG_INCLUDE_DIR ${TREMOR_INCLUDE_DIR}) set(VORBIS_INCLUDE_DIR ${TREMOR_INCLUDE_DIR}) set(VORBIS_LIBRARIES ${TREMOR_LIBRARIES}) set(ALLEGRO_CFG_ACODEC_TREMOR 1) endif(NOT SUPPORT_VORBIS) elseif(WANT_VORBIS) find_package(Vorbis) if(VORBIS_FOUND) set(CMAKE_REQUIRED_INCLUDES ${OGG_INCLUDE_DIR} ${VORBIS_INCLUDE_DIR}) if(MSVC) set(CMAKE_REQUIRED_LIBRARIES "${VORBIS_LIBRARIES}") else() # libm is required when linking statically. set(CMAKE_REQUIRED_LIBRARIES "${VORBIS_LIBRARIES};m") endif() run_c_compile_test(" #include int main(void) { OggVorbis_File f; ov_callbacks callback; vorbis_info *v = 0; (void)v; ov_info(&f, -1); callback = OV_CALLBACKS_NOCLOSE; return 0; }" VORBIS_COMPILES) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) if(VORBIS_COMPILES) set(SUPPORT_VORBIS 1) endif() endif(VORBIS_FOUND) if(NOT SUPPORT_VORBIS) message("WARNING: libvorbis not found or compile test failed, disabling support.") endif(NOT SUPPORT_VORBIS) endif() if(SUPPORT_VORBIS) include_directories(SYSTEM ${OGG_INCLUDE_DIR} ${VORBIS_INCLUDE_DIR}) set(ALLEGRO_CFG_ACODEC_VORBIS 1) list(APPEND ACODEC_SOURCES ogg.c) list(APPEND ACODEC_INCLUDE_DIRECTORIES ${OGG_INCLUDE_DIR} ${VORBIS_INCLUDE_DIR}) if(WIN32 AND WANT_ACODEC_DYNAMIC_LOAD AND NOT WANT_TREMOR) if(VORBISFILE_LIBRARY MATCHES "${WIN32_STATIC_LIB_REGEX}") message("WARNING: Dynamic loading will be disabled for Vorbis" " as static library was found: ${VORBISFILE_LIBRARY}") else() get_dll_name(${VORBISFILE_LIBRARY} ALLEGRO_CFG_ACODEC_VORBISFILE_DLL) endif() endif() if(NOT ALLEGRO_CFG_ACODEC_VORBISFILE_DLL) list(APPEND ACODEC_LIBRARIES ${VORBIS_LIBRARIES}) endif() endif(SUPPORT_VORBIS) acodec_summary(" - Ogg/Vorbis" SUPPORT_VORBIS) # # Opus # if(WANT_OPUS) find_package(Opus) if(OPUS_FOUND) set(CMAKE_REQUIRED_INCLUDES ${OGG_INCLUDE_DIR} ${OPUS_INCLUDE_DIR}) if(MSVC) set(CMAKE_REQUIRED_LIBRARIES "${OPUS_LIBRARIES}") else() # libm is required when linking statically. set(CMAKE_REQUIRED_LIBRARIES "${OPUS_LIBRARIES};m") endif() run_c_compile_test(" #include int main(void) { OggOpusFile *f; OpusHead *v = 0; (void)v; op_free(f); return 0; }" OPUS_COMPILES) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) if(OPUS_COMPILES) set(SUPPORT_OPUS 1) endif() endif(OPUS_FOUND) if(NOT SUPPORT_OPUS) message("WARNING: libopus not found or compile test failed, disabling support.") endif(NOT SUPPORT_OPUS) endif() if(SUPPORT_OPUS) include_directories(SYSTEM ${OGG_INCLUDE_DIR} ${OPUS_INCLUDE_DIR}) set(ALLEGRO_CFG_ACODEC_OPUS 1) list(APPEND ACODEC_SOURCES opus.c) list(APPEND ACODEC_INCLUDE_DIRECTORIES ${OGG_INCLUDE_DIR} ${OPUS_INCLUDE_DIR}) if(WIN32 AND WANT_ACODEC_DYNAMIC_LOAD) if(OPUSFILE_LIBRARY MATCHES "${WIN32_STATIC_LIB_REGEX}") message("WARNING: Dynamic loading will be disabled for Opus" " as static library was found: ${OPUSFILE_LIBRARY}") else() get_dll_name(${OPUSFILE_LIBRARY} ALLEGRO_CFG_ACODEC_OPUSFILE_DLL) endif() endif() if(NOT ALLEGRO_CFG_ACODEC_OPUSFILE_DLL) list(APPEND ACODEC_LIBRARIES ${OPUS_LIBRARIES}) endif() endif(SUPPORT_OPUS) acodec_summary(" - Opus" SUPPORT_OPUS) # # MP3 # if(WANT_MP3) find_package(MiniMP3) if(MINIMP3_FOUND) include_directories(SYSTEM ${MINIMP3_INCLUDE_DIRS}) set(ALLEGRO_CFG_ACODEC_MP3 1) list(APPEND ACODEC_SOURCES mp3.c) endif(MINIMP3_FOUND) if(NOT MINIMP3_FOUND) message("WARNING: minimp3 was not found") endif(NOT MINIMP3_FOUND) endif() acodec_summary(" - MP3" MINIMP3_FOUND) configure_file( allegro5/internal/aintern_acodec_cfg.h.cmake ${PROJECT_BINARY_DIR}/include/allegro5/internal/aintern_acodec_cfg.h ) add_our_addon_library(allegro_acodec AllegroAcodec-${ALLEGRO_SOVERSION} "${ACODEC_SOURCES};${ACODEC_INCLUDE_FILES}" "-DALLEGRO_ACODEC_SRC ${FLAC__NO_DLL}" "${AUDIO_LINK_WITH};${ACODEC_LIBRARIES}" ) if(SUPPORT_OPENMPT AND SHARED AND NOT WANT_MONOLITH) set_target_properties(allegro_acodec PROPERTIES LINKER_LANGUAGE CXX) endif() install_our_headers(${ACODEC_INCLUDE_FILES}) add_addon(acodec) set(ACODEC_CONFIGURATION_SUMMARY "${ACODEC_CONFIGURATION_SUMMARY}" PARENT_SCOPE) #-----------------------------------------------------------------------------# # vim: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/addons/acodec/acodec.c000066400000000000000000000070101473414355200175260ustar00rootroot00000000000000#include "allegro5/allegro_acodec.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern_acodec_cfg.h" #include "acodec.h" /* globals */ static bool acodec_inited = false; /* Function: al_get_allegro_acodec_version */ uint32_t al_get_allegro_acodec_version(void) { return ALLEGRO_VERSION_INT; } /* Function: al_init_acodec_addon */ bool al_init_acodec_addon(void) { bool acodec_prefer_dumb = false; const char* acodec_prefer_dumb_value = al_get_config_value(al_get_system_config(), "compatibility", "acodec_prefer_dumb"); if (acodec_prefer_dumb_value && strcmp(acodec_prefer_dumb_value, "true") == 0) acodec_prefer_dumb = true; bool ret = true; ret &= al_register_sample_loader(".wav", _al_load_wav); ret &= al_register_sample_saver(".wav", _al_save_wav); ret &= al_register_sample_loader_f(".wav", _al_load_wav_f); ret &= al_register_sample_saver_f(".wav", _al_save_wav_f); ret &= al_register_audio_stream_loader(".wav", _al_load_wav_audio_stream); ret &= al_register_audio_stream_loader_f(".wav", _al_load_wav_audio_stream_f); ret &= al_register_sample_identifier(".wav", _al_identify_wav); /* buil-in VOC loader */ ret &= al_register_sample_loader(".voc", _al_load_voc); ret &= al_register_sample_loader_f(".voc", _al_load_voc_f); ret &= al_register_sample_identifier(".voc", _al_identify_voc); #ifdef ALLEGRO_CFG_ACODEC_FLAC ret &= al_register_sample_loader(".flac", _al_load_flac); ret &= al_register_audio_stream_loader(".flac", _al_load_flac_audio_stream); ret &= al_register_sample_loader_f(".flac", _al_load_flac_f); ret &= al_register_audio_stream_loader_f(".flac", _al_load_flac_audio_stream_f); ret &= al_register_sample_identifier(".flac", _al_identify_flac); #endif #ifdef ALLEGRO_CFG_ACODEC_VORBIS ret &= al_register_sample_loader(".ogg", _al_load_ogg_vorbis); ret &= al_register_audio_stream_loader(".ogg", _al_load_ogg_vorbis_audio_stream); ret &= al_register_sample_loader_f(".ogg", _al_load_ogg_vorbis_f); ret &= al_register_audio_stream_loader_f(".ogg", _al_load_ogg_vorbis_audio_stream_f); ret &= al_register_sample_identifier(".ogg", _al_identify_ogg_vorbis); #endif #ifdef ALLEGRO_CFG_ACODEC_OPUS ret &= al_register_sample_loader(".opus", _al_load_ogg_opus); ret &= al_register_audio_stream_loader(".opus", _al_load_ogg_opus_audio_stream); ret &= al_register_sample_loader_f(".opus", _al_load_ogg_opus_f); ret &= al_register_audio_stream_loader_f(".opus", _al_load_ogg_opus_audio_stream_f); ret &= al_register_sample_identifier(".opus", _al_identify_ogg_opus); #endif #ifdef ALLEGRO_CFG_ACODEC_DUMB if (!acodec_prefer_dumb) ret &= _al_register_dumb_loaders(); #endif #ifdef ALLEGRO_CFG_ACODEC_OPENMPT ret &= _al_register_openmpt_loaders(); #endif #ifdef ALLEGRO_CFG_ACODEC_DUMB if (acodec_prefer_dumb) ret &= _al_register_dumb_loaders(); #endif /* MP3 will mis-identify a lot of mod files, so put its identifier last */ #ifdef ALLEGRO_CFG_ACODEC_MP3 ret &= al_register_sample_loader(".mp3", _al_load_mp3); ret &= al_register_audio_stream_loader(".mp3", _al_load_mp3_audio_stream); ret &= al_register_sample_loader_f(".mp3", _al_load_mp3_f); ret &= al_register_audio_stream_loader_f(".mp3", _al_load_mp3_audio_stream_f); ret &= al_register_sample_identifier(".mp3", _al_identify_mp3); #endif acodec_inited = ret; return ret; } /* Function: al_is_acodec_addon_initialized */ bool al_is_acodec_addon_initialized(void) { return acodec_inited; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/acodec/acodec.h000066400000000000000000000065361473414355200175470ustar00rootroot00000000000000#ifndef __al_included_acodec_acodec_h #define __al_included_acodec_acodec_h #include "allegro5/internal/aintern_acodec_cfg.h" ALLEGRO_SAMPLE *_al_load_wav(const char *filename); ALLEGRO_SAMPLE *_al_load_wav_f(ALLEGRO_FILE *fp); ALLEGRO_AUDIO_STREAM *_al_load_wav_audio_stream(const char *filename, size_t buffer_count, unsigned int samples); ALLEGRO_AUDIO_STREAM *_al_load_wav_audio_stream_f(ALLEGRO_FILE* f, size_t buffer_count, unsigned int samples); bool _al_save_wav(const char *filename, ALLEGRO_SAMPLE *spl); bool _al_save_wav_f(ALLEGRO_FILE *pf, ALLEGRO_SAMPLE *spl); bool _al_identify_wav(ALLEGRO_FILE *f); /* * Built-in Port of A4 Creative Voice file (.voc) Loader. * should not implement streams since it's unlikely this container * will ever be used as such. */ ALLEGRO_SAMPLE *_al_load_voc(const char *filename); ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *fp); bool _al_identify_voc(ALLEGRO_FILE *f); #ifdef ALLEGRO_CFG_ACODEC_FLAC ALLEGRO_SAMPLE *_al_load_flac(const char *filename); ALLEGRO_SAMPLE *_al_load_flac_f(ALLEGRO_FILE *f); ALLEGRO_AUDIO_STREAM *_al_load_flac_audio_stream(const char *filename, size_t buffer_count, unsigned int samples); ALLEGRO_AUDIO_STREAM *_al_load_flac_audio_stream_f(ALLEGRO_FILE* f, size_t buffer_count, unsigned int samples); bool _al_identify_flac(ALLEGRO_FILE *f); #endif #ifdef ALLEGRO_CFG_ACODEC_DUMB bool _al_register_dumb_loaders(void); #endif #ifdef ALLEGRO_CFG_ACODEC_OPENMPT bool _al_register_openmpt_loaders(void); #endif #if defined(ALLEGRO_CFG_ACODEC_DUMB) || defined(ALLEGRO_CFG_ACODEC_OPENMPT) bool _al_identify_it(ALLEGRO_FILE *f); bool _al_identify_669(ALLEGRO_FILE *f); bool _al_identify_amf(ALLEGRO_FILE *f); bool _al_identify_asy(ALLEGRO_FILE *f); bool _al_identify_mtm(ALLEGRO_FILE *f); bool _al_identify_okt(ALLEGRO_FILE *f); bool _al_identify_psm(ALLEGRO_FILE *f); bool _al_identify_ptm(ALLEGRO_FILE *f); bool _al_identify_riff(ALLEGRO_FILE *f); bool _al_identify_stm(ALLEGRO_FILE *f); bool _al_identify_mod(ALLEGRO_FILE *f); bool _al_identify_s3m(ALLEGRO_FILE *f); bool _al_identify_xm(ALLEGRO_FILE *f); #endif #ifdef ALLEGRO_CFG_ACODEC_VORBIS ALLEGRO_SAMPLE *_al_load_ogg_vorbis(const char *filename); ALLEGRO_SAMPLE *_al_load_ogg_vorbis_f(ALLEGRO_FILE *file); ALLEGRO_AUDIO_STREAM *_al_load_ogg_vorbis_audio_stream(const char *filename, size_t buffer_count, unsigned int samples); ALLEGRO_AUDIO_STREAM *_al_load_ogg_vorbis_audio_stream_f(ALLEGRO_FILE* file, size_t buffer_count, unsigned int samples); bool _al_identify_ogg_vorbis(ALLEGRO_FILE *f); #endif #ifdef ALLEGRO_CFG_ACODEC_OPUS ALLEGRO_SAMPLE *_al_load_ogg_opus(const char *filename); ALLEGRO_SAMPLE *_al_load_ogg_opus_f(ALLEGRO_FILE *file); ALLEGRO_AUDIO_STREAM *_al_load_ogg_opus_audio_stream(const char *filename, size_t buffer_count, unsigned int samples); ALLEGRO_AUDIO_STREAM *_al_load_ogg_opus_audio_stream_f(ALLEGRO_FILE* file, size_t buffer_count, unsigned int samples); bool _al_identify_ogg_opus(ALLEGRO_FILE *f); #endif #ifdef ALLEGRO_CFG_ACODEC_MP3 ALLEGRO_SAMPLE *_al_load_mp3(const char *filename); ALLEGRO_SAMPLE *_al_load_mp3_f(ALLEGRO_FILE *f); ALLEGRO_AUDIO_STREAM *_al_load_mp3_audio_stream(const char *filename, size_t buffer_count, unsigned int samples); ALLEGRO_AUDIO_STREAM *_al_load_mp3_audio_stream_f(ALLEGRO_FILE* f, size_t buffer_count, unsigned int samples); bool _al_identify_mp3(ALLEGRO_FILE *f); #endif #endif allegro5-5.2.10.1/addons/acodec/allegro5/000077500000000000000000000000001473414355200176605ustar00rootroot00000000000000allegro5-5.2.10.1/addons/acodec/allegro5/allegro_acodec.h000066400000000000000000000020251473414355200227530ustar00rootroot00000000000000#ifndef __al_included_allegro5_allegro_acodec_h #define __al_included_allegro5_allegro_acodec_h #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #ifdef __cplusplus extern "C" { #endif #if (defined ALLEGRO_MINGW32) || (defined ALLEGRO_MSVC) #ifndef ALLEGRO_STATICLINK #ifdef ALLEGRO_ACODEC_SRC #define _ALLEGRO_ACODEC_DLL __declspec(dllexport) #else #define _ALLEGRO_ACODEC_DLL __declspec(dllimport) #endif #else #define _ALLEGRO_ACODEC_DLL #endif #endif #if defined ALLEGRO_MSVC #define ALLEGRO_ACODEC_FUNC(type, name, args) _ALLEGRO_ACODEC_DLL type __cdecl name args #elif defined ALLEGRO_MINGW32 #define ALLEGRO_ACODEC_FUNC(type, name, args) extern type name args #else #define ALLEGRO_ACODEC_FUNC AL_FUNC #endif ALLEGRO_ACODEC_FUNC(bool, al_init_acodec_addon, (void)); ALLEGRO_ACODEC_FUNC(bool, al_is_acodec_addon_initialized, (void)); ALLEGRO_ACODEC_FUNC(uint32_t, al_get_allegro_acodec_version, (void)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/acodec/allegro5/internal/000077500000000000000000000000001473414355200214745ustar00rootroot00000000000000allegro5-5.2.10.1/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake000066400000000000000000000011751473414355200265050ustar00rootroot00000000000000#cmakedefine ALLEGRO_CFG_ACODEC_FLAC #cmakedefine ALLEGRO_CFG_ACODEC_DUMB #cmakedefine ALLEGRO_CFG_ACODEC_OPENMPT #cmakedefine ALLEGRO_CFG_ACODEC_VORBIS #cmakedefine ALLEGRO_CFG_ACODEC_TREMOR #cmakedefine ALLEGRO_CFG_ACODEC_OPUS #cmakedefine ALLEGRO_CFG_ACODEC_MP3 /* Define if the library should be loaded dynamically. */ #cmakedefine ALLEGRO_CFG_ACODEC_FLAC_DLL "@ALLEGRO_CFG_ACODEC_FLAC_DLL@" #cmakedefine ALLEGRO_CFG_ACODEC_DUMB_DLL "@ALLEGRO_CFG_ACODEC_DUMB_DLL@" #cmakedefine ALLEGRO_CFG_ACODEC_VORBISFILE_DLL "@ALLEGRO_CFG_ACODEC_VORBISFILE_DLL@" #cmakedefine ALLEGRO_CFG_ACODEC_OPUSFILE_DLL "@ALLEGRO_CFG_ACODEC_OPUSFILE_DLL@" allegro5-5.2.10.1/addons/acodec/dumb.c000066400000000000000000000522551473414355200172520ustar00rootroot00000000000000/* * Allegro MOD reader * author: Matthew Leverton */ #define _FILE_OFFSET_BITS 64 #include #include "allegro5/allegro.h" #include "allegro5/allegro_acodec.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_system.h" #include "acodec.h" #include "helper.h" #ifndef ALLEGRO_CFG_ACODEC_DUMB #error configuration problem, ALLEGRO_CFG_ACODEC_DUMB not set #endif // We use the deprecated duh_render in DUMB 2. #define DUMB_DECLARE_DEPRECATED #include #include ALLEGRO_DEBUG_CHANNEL("acodec") /* In addition to DUMB 0.9.3 at http://dumb.sourceforge.net/, * we support kode54's fork of DUMB at https://github.com/kode54/dumb. * The newest version before kode54's fork was DUMB 0.9.3, and the first * forked version that A5 supports is already 2.0.0. */ /* forward declarations */ static bool init_libdumb(void); static size_t modaudio_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data, size_t buf_size); static bool modaudio_stream_rewind(ALLEGRO_AUDIO_STREAM *stream); static bool modaudio_stream_seek(ALLEGRO_AUDIO_STREAM *stream, double time); static double modaudio_stream_get_position(ALLEGRO_AUDIO_STREAM *stream); static double modaudio_stream_get_length(ALLEGRO_AUDIO_STREAM *stream); static bool modaudio_stream_set_loop(ALLEGRO_AUDIO_STREAM *stream, double start, double end); static void modaudio_stream_close(ALLEGRO_AUDIO_STREAM *stream); typedef struct MOD_FILE { DUH *duh; DUH_SIGRENDERER *sig; ALLEGRO_FILE *fh; double length; long loop_start, loop_end; } MOD_FILE; static bool libdumb_loaded = false; /* dynamic loading support (Windows only currently) */ #ifdef ALLEGRO_CFG_ACODEC_DUMB_DLL static void *dumb_dll = NULL; #endif /* * dumb_off_t is introduced in DUMB 2.0, it's a signed 64+ bit integer. * dumb_ssize_t is a platform-independent signed size_t. * DUMB 0.9.3 expects long wherever dumb_off_t or dumb_ssize_t appear. * * _al_dumb_size_t takes care of another, less documented, difference * between the versions. */ #if (DUMB_MAJOR_VERSION) < 2 typedef long dumb_off_t; typedef long dumb_ssize_t; typedef long _al_dumb_size_t; #else typedef size_t _al_dumb_size_t; #endif static struct { long (*duh_sigrenderer_get_position)(DUH_SIGRENDERER *); void (*duh_end_sigrenderer)(DUH_SIGRENDERER *); void (*unload_duh)(DUH *); DUH_SIGRENDERER *(*duh_start_sigrenderer)(DUH *, int, int, long); dumb_off_t (*duh_get_length)(DUH *); void (*dumb_exit)(void); DUMB_IT_SIGRENDERER *(*duh_get_it_sigrenderer)(DUH_SIGRENDERER *); void (*dumb_it_set_loop_callback)(DUMB_IT_SIGRENDERER *, int (*)(void *), void *); void (*dumb_it_set_xm_speed_zero_callback)(DUMB_IT_SIGRENDERER *, int (*)(void *), void *); int (*dumb_it_callback_terminate)(void *); #if (DUMB_MAJOR_VERSION) >= 2 /* * DUMB 2.0 deprecates duh_render, and suggests instead duh_render_int * and duh_render_float. But I (Simon N.) don't know how to use those. * I have already written some documentation for DUMB 2.0 that got merged * upstream, but I haven't gotten around to this issue yet. */ long (*duh_render)(DUH_SIGRENDERER *, int, int, float, float, long, void *); /* deprecated */ void (*register_dumbfile_system)(const DUMBFILE_SYSTEM *); DUMBFILE *(*dumbfile_open_ex)(void *, const DUMBFILE_SYSTEM *); DUH *(*dumb_read_any)(DUMBFILE *, int, int); #else long (*duh_render)(DUH_SIGRENDERER *, int, int, float, float, long, void *); void (*register_dumbfile_system)(DUMBFILE_SYSTEM *); DUMBFILE *(*dumbfile_open_ex)(void *, DUMBFILE_SYSTEM *); DUH *(*dumb_read_mod)(DUMBFILE *); DUH *(*dumb_read_it)(DUMBFILE *); DUH *(*dumb_read_xm)(DUMBFILE *); DUH *(*dumb_read_s3m)(DUMBFILE *); #endif } lib; /* Set up DUMB's file system */ static DUMBFILE_SYSTEM dfs, dfs_f; static void *dfs_open(const char *filename) { return al_fopen(filename, "rb"); } static int dfs_skip(void *f, dumb_off_t n) { return al_fseek(f, n, ALLEGRO_SEEK_CUR) ? 0 : -1; } static int dfs_getc(void *f) { return al_fgetc(f); } static dumb_ssize_t dfs_getnc(char *ptr, _al_dumb_size_t n, void *f) { return al_fread(f, ptr, n); } static void dfs_close(void *f) { /* Don't actually close f here. */ (void)f; } #if (DUMB_MAJOR_VERSION) >= 2 static int dfs_seek(void *f, dumb_off_t n) { return al_fseek(f, n, ALLEGRO_SEEK_SET) ? 0 : -1; } static dumb_off_t dfs_get_size(void *f) { return al_fsize(f); } #endif /* Stream Functions */ static int loop_callback(void *data) { bool *internal_loop = (bool *)data; *internal_loop = true; return 0; } static size_t modaudio_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data, size_t buf_size) { MOD_FILE *const df = stream->extra; /* the mod files are stereo and 16-bit */ const int sample_size = 4; size_t written = 0; size_t i; bool internal_loop = false; DUMB_IT_SIGRENDERER *it_sig = lib.duh_get_it_sigrenderer(df->sig); if (it_sig) { lib.dumb_it_set_loop_callback(it_sig, stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONCE ? lib.dumb_it_callback_terminate : loop_callback, &internal_loop); } while (written < buf_size) { long size_to_read = (buf_size - written) / sample_size; long position = lib.duh_sigrenderer_get_position(df->sig); bool manual_loop = false; internal_loop = false; /* If manual looping is not enabled, then we need to implement * short-stopping manually. */ if (stream->spl.loop != _ALLEGRO_PLAYMODE_STREAM_ONCE && df->loop_end != -1 && position + 65536 * size_to_read / 44100 >= df->loop_end) { size_to_read = (df->loop_end - position) * 44100 / 65536; if (size_to_read < 0) size_to_read = 0; manual_loop = true; } written += lib.duh_render(df->sig, 16, 0, 1.0, 65536.0 / 44100.0, size_to_read, &(((char *)data)[written])) * sample_size; /* For internal loops, we don't rewind. */ if (!internal_loop && ((long)written < size_to_read * sample_size || manual_loop)) { break; } } /* Fill the remainder with silence */ for (i = written; i < buf_size; ++i) ((char *)data)[i] = 0; return written; } static void modaudio_stream_close(ALLEGRO_AUDIO_STREAM *stream) { MOD_FILE *const df = stream->extra; _al_acodec_stop_feed_thread(stream); lib.duh_end_sigrenderer(df->sig); lib.unload_duh(df->duh); if (df->fh) al_fclose(df->fh); } static bool modaudio_stream_rewind(ALLEGRO_AUDIO_STREAM *stream) { MOD_FILE *const df = stream->extra; lib.duh_end_sigrenderer(df->sig); df->sig = lib.duh_start_sigrenderer(df->duh, 0, 2, df->loop_start); return true; } static bool modaudio_stream_seek(ALLEGRO_AUDIO_STREAM *stream, double time) { MOD_FILE *const df = stream->extra; if (df->loop_end != -1 && (long)(time * 65336) > df->loop_end) { return false; } lib.duh_end_sigrenderer(df->sig); df->sig = lib.duh_start_sigrenderer(df->duh, 0, 2, time * 65536); return true; } static double modaudio_stream_get_position(ALLEGRO_AUDIO_STREAM *stream) { MOD_FILE *const df = stream->extra; return lib.duh_sigrenderer_get_position(df->sig) / 65536.0; } static double modaudio_stream_get_length(ALLEGRO_AUDIO_STREAM *stream) { MOD_FILE *const df = stream->extra; return df->length; } static bool modaudio_stream_set_loop(ALLEGRO_AUDIO_STREAM *stream, double start, double end) { MOD_FILE *const df = stream->extra; df->loop_start = start * 65536; df->loop_end = end * 65536; return true; } static ALLEGRO_AUDIO_STREAM *modaudio_stream_init(ALLEGRO_FILE* f, size_t buffer_count, unsigned int samples #if (DUMB_MAJOR_VERSION) < 2 /* For DUMB 0.9.3, we must choose a loader function ourselves. */ , DUH *(loader)(DUMBFILE *) #endif ) { ALLEGRO_AUDIO_STREAM *stream; DUMBFILE *df; DUH_SIGRENDERER *sig = NULL; DUH *duh = NULL; DUMB_IT_SIGRENDERER *it_sig = NULL; int64_t start_pos = -1; df = lib.dumbfile_open_ex(f, &dfs_f); if (!df) { ALLEGRO_ERROR("dumbfile_open_ex failed.\n"); return NULL; } start_pos = al_ftell(f); #if (DUMB_MAJOR_VERSION) >= 2 /* * DUMB 2.0 introduces dumb_read_any. It takes two extra int arguments. * * The first int, restrict_, changes how a MOD module is interpreted. * int restrict_ is a two-bit bitfield, and 0 is a good default. * For discussion, see: https://github.com/kode54/dumb/issues/53 * * The second int, subsong, matters only for very few formats. * A5 doesn't allow to choose a subsong from the 5.2 API anyway, thus 0. */ duh = lib.dumb_read_any(df, 0, 0); #else duh = loader(df); #endif if (!duh) { ALLEGRO_ERROR("Failed to create DUH.\n"); goto Error; } sig = lib.duh_start_sigrenderer(duh, 0, 2, 0); if (!sig) { ALLEGRO_ERROR("duh_start_sigrenderer failed.\n"); goto Error; } it_sig = lib.duh_get_it_sigrenderer(sig); if (it_sig) { /* Turn off freezing for XM files. Seems completely pointless. */ lib.dumb_it_set_xm_speed_zero_callback(it_sig, lib.dumb_it_callback_terminate, NULL); } stream = al_create_audio_stream(buffer_count, samples, 44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); if (stream) { MOD_FILE *mf = al_malloc(sizeof(MOD_FILE)); mf->duh = duh; mf->sig = sig; mf->fh = NULL; mf->length = lib.duh_get_length(duh) / 65536.0; if (mf->length < 0) { mf->length = 0; } /* * Set these to -1, so that we can default to the internal loop * points. */ mf->loop_start = -1; mf->loop_end = -1; stream->extra = mf; stream->feeder = modaudio_stream_update; stream->unload_feeder = modaudio_stream_close; stream->rewind_feeder = modaudio_stream_rewind; stream->seek_feeder = modaudio_stream_seek; stream->get_feeder_position = modaudio_stream_get_position; stream->get_feeder_length = modaudio_stream_get_length; stream->set_feeder_loop = modaudio_stream_set_loop; _al_acodec_start_feed_thread(stream); } else { ALLEGRO_ERROR("Failed to create stream.\n"); goto Error; } return stream; Error: if (sig) { lib.duh_end_sigrenderer(sig); } if (duh) { lib.unload_duh(duh); } /* try to return back to where we started to load */ if (start_pos != -1) al_fseek(f, start_pos, ALLEGRO_SEEK_SET); return NULL; } static void shutdown_libdumb(void) { if (libdumb_loaded) { lib.dumb_exit(); libdumb_loaded = false; } #ifdef ALLEGRO_CFG_ACODEC_DUMB_DLL if (dumb_dll) { _al_close_library(dumb_dll); dumb_dll = NULL; } #endif } static bool init_libdumb(void) { if (libdumb_loaded) { return true; } #ifdef ALLEGRO_CFG_ACODEC_DUMB_DLL dumb_dll = _al_open_library(ALLEGRO_CFG_ACODEC_DUMB_DLL); if (!dumb_dll) { ALLEGRO_ERROR("Could not load " ALLEGRO_CFG_ACODEC_DUMB_DLL "\n"); return false; } #define INITSYM(x) \ do \ { \ lib.x = _al_import_symbol(dumb_dll, #x); \ if (lib.x == 0) { \ ALLEGRO_ERROR("undefined symbol in lib structure: " #x "\n"); \ return false; \ } \ } while(0) #else #define INITSYM(x) (lib.x = (x)) #endif _al_add_exit_func(shutdown_libdumb, "shutdown_libdumb"); memset(&lib, 0, sizeof(lib)); INITSYM(duh_render); /* see comment on duh_render deprecation above */ INITSYM(duh_sigrenderer_get_position); INITSYM(duh_end_sigrenderer); INITSYM(unload_duh); INITSYM(duh_start_sigrenderer); INITSYM(dumbfile_open_ex); INITSYM(duh_get_length); INITSYM(dumb_exit); INITSYM(register_dumbfile_system); INITSYM(duh_get_it_sigrenderer); INITSYM(dumb_it_set_loop_callback); INITSYM(dumb_it_set_xm_speed_zero_callback); INITSYM(dumb_it_callback_terminate); dfs.open = dfs_open; dfs.skip = dfs_skip; dfs.getc = dfs_getc; dfs.getnc = dfs_getnc; dfs.close = dfs_close; #if (DUMB_MAJOR_VERSION) >= 2 INITSYM(dumb_read_any); dfs.seek = dfs_seek; dfs.get_size = dfs_get_size; #else INITSYM(dumb_read_it); INITSYM(dumb_read_xm); INITSYM(dumb_read_s3m); INITSYM(dumb_read_mod); #endif /* Set up DUMB's default I/O to go through Allegro... */ lib.register_dumbfile_system(&dfs); /* But we'll actually use them through this version: */ dfs_f = dfs; dfs_f.open = NULL; dfs_f.close = NULL; libdumb_loaded = true; return true; } #if (DUMB_MAJOR_VERSION) >= 2 static ALLEGRO_AUDIO_STREAM *load_dumb_audio_stream_f(ALLEGRO_FILE *f, size_t buffer_count, unsigned int samples) { if (!init_libdumb()) return NULL; return modaudio_stream_init(f, buffer_count, samples); } /* * DUMB 2.0 figures out the file format for us. * Need only one loader from disk file and one loader from DUMBFILE. */ static ALLEGRO_AUDIO_STREAM *load_dumb_audio_stream(const char *filename, size_t buffer_count, unsigned int samples) { ALLEGRO_FILE *f; ALLEGRO_AUDIO_STREAM *stream; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) return NULL; stream = load_dumb_audio_stream_f(f, buffer_count, samples); if (!stream) { al_fclose(f); return NULL; } ((MOD_FILE *)stream->extra)->fh = f; return stream; } #else /* * For DUMB 0.9.3: * * 4 separate loaders for the 4 file formats supported by DUMB 0.9.3, * then 4 loaders that take a DUMBFILE. The loaders from file are * all identical, except for the function called in the middle. */ static ALLEGRO_AUDIO_STREAM *load_mod_audio_stream_f(ALLEGRO_FILE *f, size_t buffer_count, unsigned int samples) { if (!init_libdumb()) return NULL; return modaudio_stream_init(f, buffer_count, samples, lib.dumb_read_mod); } static ALLEGRO_AUDIO_STREAM *load_it_audio_stream_f(ALLEGRO_FILE *f, size_t buffer_count, unsigned int samples) { if (!init_libdumb()) return NULL; return modaudio_stream_init(f, buffer_count, samples, lib.dumb_read_it); } static ALLEGRO_AUDIO_STREAM *load_xm_audio_stream_f(ALLEGRO_FILE *f, size_t buffer_count, unsigned int samples) { if (!init_libdumb()) return NULL; return modaudio_stream_init(f, buffer_count, samples, lib.dumb_read_xm); } static ALLEGRO_AUDIO_STREAM *load_s3m_audio_stream_f(ALLEGRO_FILE *f, size_t buffer_count, unsigned int samples) { if (!init_libdumb()) return NULL; return modaudio_stream_init(f, buffer_count, samples, lib.dumb_read_s3m); } static ALLEGRO_AUDIO_STREAM *load_mod_audio_stream(const char *filename, size_t buffer_count, unsigned int samples) { ALLEGRO_FILE *f; ALLEGRO_AUDIO_STREAM *stream; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } stream = load_mod_audio_stream_f(f, buffer_count, samples); if (!stream) { al_fclose(f); return NULL; } ((MOD_FILE *)stream->extra)->fh = f; return stream; } static ALLEGRO_AUDIO_STREAM *load_it_audio_stream(const char *filename, size_t buffer_count, unsigned int samples) { ALLEGRO_FILE *f; ALLEGRO_AUDIO_STREAM *stream; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } stream = load_it_audio_stream_f(f, buffer_count, samples); if (!stream) { al_fclose(f); return NULL; } ((MOD_FILE *)stream->extra)->fh = f; return stream; } static ALLEGRO_AUDIO_STREAM *load_xm_audio_stream(const char *filename, size_t buffer_count, unsigned int samples) { ALLEGRO_FILE *f; ALLEGRO_AUDIO_STREAM *stream; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } stream = load_xm_audio_stream_f(f, buffer_count, samples); if (!stream) { al_fclose(f); return NULL; } ((MOD_FILE *)stream->extra)->fh = f; return stream; } static ALLEGRO_AUDIO_STREAM *load_s3m_audio_stream(const char *filename, size_t buffer_count, unsigned int samples) { ALLEGRO_FILE *f; ALLEGRO_AUDIO_STREAM *stream; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } stream = load_s3m_audio_stream_f(f, buffer_count, samples); if (!stream) { al_fclose(f); return NULL; } ((MOD_FILE *)stream->extra)->fh = f; return stream; } #endif // DUMB_MAJOR_VERSION bool _al_register_dumb_loaders(void) { bool ret = true; #if (DUMB_MAJOR_VERSION) >= 2 /* * DUMB 2.0 offers a single loader for at least 13 formats, see their * readme. Amiga NoiseTracker isn't listed there, but it's DUMB-supported. * It merely has no common extensions, see: * https://github.com/kode54/dumb/issues/53 */ ret &= al_register_audio_stream_loader(".669", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".669", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".669", _al_identify_669); ret &= al_register_audio_stream_loader(".amf", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".amf", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".amf", _al_identify_amf); ret &= al_register_audio_stream_loader(".asy", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".asy", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".asy", _al_identify_asy); ret &= al_register_audio_stream_loader(".it", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".it", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".it", _al_identify_it); ret &= al_register_audio_stream_loader(".mod", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".mod", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".mod", _al_identify_mod); ret &= al_register_audio_stream_loader(".mtm", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".mtm", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".mtm", _al_identify_mtm); ret &= al_register_audio_stream_loader(".okt", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".okt", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".okt", _al_identify_okt); ret &= al_register_audio_stream_loader(".psm", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".psm", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".psm", _al_identify_psm); ret &= al_register_audio_stream_loader(".ptm", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".ptm", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".ptm", _al_identify_ptm); ret &= al_register_audio_stream_loader(".riff", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".riff", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".riff", _al_identify_riff); ret &= al_register_audio_stream_loader(".s3m", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".s3m", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".s3m", _al_identify_s3m); ret &= al_register_audio_stream_loader(".stm", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".stm", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".stm", _al_identify_stm); ret &= al_register_audio_stream_loader(".xm", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".xm", load_dumb_audio_stream_f); ret &= al_register_sample_identifier(".xm", _al_identify_xm); #else /* * DUMB 0.9.3 supported only these 4 formats and had no *_any loader. * Avoid DUMB 1.0 because of versioning problems: dumb.h from git tag 1.0 * reports 0.9.3 in its version numbers. */ ret &= al_register_audio_stream_loader(".xm", load_xm_audio_stream); ret &= al_register_audio_stream_loader_f(".xm", load_xm_audio_stream_f); ret &= al_register_sample_identifier(".xm", _al_identify_xm); ret &= al_register_audio_stream_loader(".it", load_it_audio_stream); ret &= al_register_audio_stream_loader_f(".it", load_it_audio_stream_f); ret &= al_register_sample_identifier(".it", _al_identify_it); ret &= al_register_audio_stream_loader(".mod", load_mod_audio_stream); ret &= al_register_audio_stream_loader_f(".mod", load_mod_audio_stream_f); ret &= al_register_sample_identifier(".mod", _al_identify_mod); ret &= al_register_audio_stream_loader(".s3m", load_s3m_audio_stream); ret &= al_register_audio_stream_loader_f(".s3m", load_s3m_audio_stream_f); ret &= al_register_sample_identifier(".s3m", _al_identify_s3m); #endif // DUMB_MAJOR_VERSION return ret; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/acodec/flac.c000066400000000000000000000440671473414355200172320ustar00rootroot00000000000000/* * Allegro FLAC reader * author: Ryan Dickie, (c) 2008 * streaming support by Elias Pschernig */ #include "allegro5/allegro.h" #include "allegro5/allegro_acodec.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_system.h" #include "acodec.h" #include "helper.h" #ifndef ALLEGRO_CFG_ACODEC_FLAC #error configuration problem, ALLEGRO_CFG_ACODEC_FLAC not set #endif #include #include ALLEGRO_DEBUG_CHANNEL("acodec") typedef struct FLACFILE { FLAC__StreamDecoder *decoder; double sample_rate; int sample_size; int channels; /* The file buffer. */ uint64_t buffer_pos, buffer_size; char *buffer; /* Number of samples in the complete FLAC. */ uint64_t total_samples; /* Sample position one past last decoded sample. */ uint64_t decoded_samples; /* Sample position one past last streamed sample. */ uint64_t streamed_samples; ALLEGRO_FILE *fh; uint64_t loop_start, loop_end; /* in samples */ } FLACFILE; /* dynamic loading support (Windows only currently) */ #ifdef ALLEGRO_CFG_ACODEC_FLAC_DLL static void *flac_dll = NULL; static bool flac_virgin = true; #endif static struct { FLAC__StreamDecoder *(*FLAC__stream_decoder_new)(void); void (*FLAC__stream_decoder_delete)(FLAC__StreamDecoder *decoder); FLAC__StreamDecoderInitStatus (*FLAC__stream_decoder_init_stream)( FLAC__StreamDecoder *decoder, FLAC__StreamDecoderReadCallback read_callback, FLAC__StreamDecoderSeekCallback seek_callback, FLAC__StreamDecoderTellCallback tell_callback, FLAC__StreamDecoderLengthCallback length_callback, FLAC__StreamDecoderEofCallback eof_callback, FLAC__StreamDecoderWriteCallback write_callback, FLAC__StreamDecoderMetadataCallback metadata_callback, FLAC__StreamDecoderErrorCallback error_callback, void *client_data); FLAC__bool (*FLAC__stream_decoder_process_single)(FLAC__StreamDecoder *decoder); FLAC__bool (*FLAC__stream_decoder_process_until_end_of_metadata)(FLAC__StreamDecoder *decoder); FLAC__bool (*FLAC__stream_decoder_process_until_end_of_stream)(FLAC__StreamDecoder *decoder); FLAC__bool (*FLAC__stream_decoder_seek_absolute)(FLAC__StreamDecoder *decoder, FLAC__uint64 sample); FLAC__bool (*FLAC__stream_decoder_flush)(FLAC__StreamDecoder *decoder); FLAC__bool (*FLAC__stream_decoder_finish)(FLAC__StreamDecoder *decoder); } lib; #ifdef ALLEGRO_CFG_ACODEC_FLAC_DLL static void shutdown_dynlib(void) { if (flac_dll) { _al_close_library(flac_dll); flac_dll = NULL; flac_virgin = true; } } #endif static bool init_dynlib(void) { #ifdef ALLEGRO_CFG_ACODEC_FLAC_DLL if (flac_dll) { return true; } if (!flac_virgin) { return false; } flac_virgin = false; flac_dll = _al_open_library(ALLEGRO_CFG_ACODEC_FLAC_DLL); if (!flac_dll) { ALLEGRO_ERROR("Could not load " ALLEGRO_CFG_ACODEC_FLAC_DLL "\n"); return false; } _al_add_exit_func(shutdown_dynlib, "shutdown_dynlib"); #define INITSYM(x) \ do \ { \ lib.x = _al_import_symbol(flac_dll, #x); \ if (lib.x == 0) { \ ALLEGRO_ERROR("undefined symbol in lib structure: " #x "\n"); \ return false; \ } \ } while(0) #else #define INITSYM(x) (lib.x = (x)) #endif memset(&lib, 0, sizeof(lib)); INITSYM(FLAC__stream_decoder_new); INITSYM(FLAC__stream_decoder_delete); INITSYM(FLAC__stream_decoder_init_stream); INITSYM(FLAC__stream_decoder_process_single); INITSYM(FLAC__stream_decoder_process_until_end_of_metadata); INITSYM(FLAC__stream_decoder_process_until_end_of_stream); INITSYM(FLAC__stream_decoder_seek_absolute); INITSYM(FLAC__stream_decoder_flush); INITSYM(FLAC__stream_decoder_finish); return true; #undef INITSYM } static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *dptr) { FLACFILE *ff = (FLACFILE *)dptr; ALLEGRO_FILE *fh = ff->fh; (void)decoder; if (*bytes > 0) { *bytes = al_fread(fh, buffer, *bytes); if (al_ferror(fh)) return FLAC__STREAM_DECODER_READ_STATUS_ABORT; else if (*bytes == 0) return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; else return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } else return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } static FLAC__StreamDecoderSeekStatus seek_callback( const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *dptr) { FLACFILE *ff = (FLACFILE *)dptr; ALLEGRO_FILE *fh = ff->fh; (void)decoder; if (!al_fseek(fh, absolute_byte_offset, ALLEGRO_SEEK_SET)) return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; else return FLAC__STREAM_DECODER_SEEK_STATUS_OK; } static FLAC__StreamDecoderTellStatus tell_callback( const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *dptr) { FLACFILE *ff = (FLACFILE *)dptr; ALLEGRO_FILE *fh = ff->fh; int64_t pos = 0; (void)decoder; pos = al_ftell(fh); if (pos == -1) return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; *absolute_byte_offset = (FLAC__uint64)pos; return FLAC__STREAM_DECODER_TELL_STATUS_OK; } static FLAC__StreamDecoderLengthStatus length_callback( const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *dptr) { FLACFILE *ff = (FLACFILE *)dptr; ALLEGRO_FILE *fh = ff->fh; (void)decoder; /* XXX check error */ *stream_length = (FLAC__uint64)al_fsize(fh); return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; } static FLAC__bool eof_callback(const FLAC__StreamDecoder *decoder, void *dptr) { FLACFILE *ff = (FLACFILE *)dptr; ALLEGRO_FILE *fh = ff->fh; (void)decoder; if (al_feof(fh)) return true; return false; } static void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) { FLACFILE *out = (FLACFILE *)client_data; (void)decoder; if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { out->total_samples = metadata->data.stream_info.total_samples; out->sample_rate = metadata->data.stream_info.sample_rate; out->channels = metadata->data.stream_info.channels; out->sample_size = metadata->data.stream_info.bits_per_sample / 8; } } static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) { (void)decoder; (void)client_data; #ifdef ALLEGRO_CFG_ACODEC_FLAC_DLL (void)status; ALLEGRO_ERROR("Got FLAC error callback\n"); /* lazy */ #else ALLEGRO_ERROR("Got FLAC error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]); #endif } static FLAC__StreamDecoderWriteStatus write_callback( const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) { FLACFILE *ff = (FLACFILE *) client_data; long len = frame->header.blocksize; long bytes = len * ff->channels * ff->sample_size; FLAC__uint8 *buf8; FLAC__int16 *buf16; float *buf32; int sample_index; int channel_index; int out_index; if (ff->buffer_pos + bytes > ff->buffer_size) { ff->buffer = al_realloc(ff->buffer, ff->buffer_pos + bytes); ff->buffer_size = ff->buffer_pos + bytes; } /* FLAC returns FLAC__int32 and I need to convert it to my own format. */ buf8 = (FLAC__uint8 *) (ff->buffer + ff->buffer_pos); buf16 = (FLAC__int16 *) buf8; buf32 = (float *) buf8; (void)decoder; (void)client_data; /* Flatten the array */ /* TODO: test this array flattening process on 5.1 and higher flac files */ out_index = 0; switch (ff->sample_size) { case 1: for (sample_index = 0; sample_index < len; sample_index++) { for (channel_index = 0; channel_index < ff->channels; channel_index++) { buf8[out_index++] = (FLAC__uint8) buffer[channel_index][sample_index]; } } break; case 2: for (sample_index = 0; sample_index < len; sample_index++) { for (channel_index = 0; channel_index < ff->channels; channel_index++) { buf16[out_index++] = (FLAC__int16) buffer[channel_index][sample_index]; } } break; case 3: for (sample_index = 0; sample_index < len; sample_index++) { for (channel_index = 0; channel_index < ff->channels; channel_index++) { /* Little endian */ /* FIXME: does this work? I only have 16-bit sound card mixer * garbages for other 24-bit codecs too. */ buf8[out_index++] = (FLAC__uint8) (buffer[channel_index][sample_index] & 0xFF); buf8[out_index++] = (FLAC__uint8) ((buffer[channel_index][sample_index] & 0xFF00) >> 8); buf8[out_index++] = (FLAC__uint8) ((buffer[channel_index][sample_index] & 0xFF0000) >> 16); } } break; case 4: for (sample_index = 0; sample_index < len; sample_index++) { for (channel_index = 0; channel_index < ff->channels; channel_index++) { buf32[out_index++] = (float) buffer[channel_index][sample_index]; } } break; default: /* Word_size not supported. */ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } ff->decoded_samples += len; ff->buffer_pos += bytes; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } static void flac_close(FLACFILE *ff) { lib.FLAC__stream_decoder_finish(ff->decoder); lib.FLAC__stream_decoder_delete(ff->decoder); /* Don't close ff->fh here. */ al_free(ff); } /* In seconds. */ static double flac_stream_get_position(ALLEGRO_AUDIO_STREAM *stream) { FLACFILE *ff = (FLACFILE *)stream->extra; return ff->streamed_samples / ff->sample_rate; } /* * Updates 'stream' with the next chunk of data. * Returns the actual number of bytes written. */ static size_t flac_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data, size_t buf_size) { int bytes_per_sample; uint64_t wanted_samples; uint64_t read_samples; size_t written_bytes = 0; size_t read_bytes; FLACFILE *ff = (FLACFILE *)stream->extra; bytes_per_sample = ff->sample_size * ff->channels; wanted_samples = buf_size / bytes_per_sample; if (ff->streamed_samples + wanted_samples > ff->loop_end) { if (ff->loop_end > ff->streamed_samples) wanted_samples = ff->loop_end - ff->streamed_samples; else return 0; } while (wanted_samples > 0) { read_samples = ff->decoded_samples - ff->streamed_samples; /* If the buffer size is small, we shouldn't read a new frame or our * buffer keeps growing - so only refill when needed. */ if (!read_samples) { if (!lib.FLAC__stream_decoder_process_single(ff->decoder)) break; read_samples = ff->decoded_samples - ff->streamed_samples; if (!read_samples) { break; } } if (read_samples > wanted_samples) read_samples = wanted_samples; ff->streamed_samples += read_samples; wanted_samples -= read_samples; read_bytes = read_samples * bytes_per_sample; /* Copy data from the FLAC file buffer to the stream buffer. */ memcpy((uint8_t *)data + written_bytes, ff->buffer, read_bytes); /* Make room in the FLACFILE buffer. */ memmove(ff->buffer, ff->buffer + read_bytes, ff->buffer_pos - read_bytes); ff->buffer_pos -= read_bytes; written_bytes += read_bytes; } return written_bytes; } /* Called from al_destroy_audio_stream. */ static void flac_stream_close(ALLEGRO_AUDIO_STREAM *stream) { FLACFILE *ff = stream->extra; _al_acodec_stop_feed_thread(stream); al_fclose(ff->fh); al_free(ff->buffer); flac_close(ff); } static bool real_seek(ALLEGRO_AUDIO_STREAM *stream, uint64_t sample) { FLACFILE *ff = stream->extra; /* We use ff->streamed_samples as the exact sample position for looping and * returning the position. Therefore we also use it as reference position * when seeking - that is, we call flush below to make the FLAC decoder * discard any additional samples it may have buffered already. * */ lib.FLAC__stream_decoder_flush(ff->decoder); lib.FLAC__stream_decoder_seek_absolute(ff->decoder, sample); ff->buffer_pos = 0; ff->streamed_samples = sample; ff->decoded_samples = sample; return true; } static bool flac_stream_seek(ALLEGRO_AUDIO_STREAM *stream, double time) { FLACFILE *ff = stream->extra; uint64_t sample = time * ff->sample_rate; return real_seek(stream, sample); } static bool flac_stream_rewind(ALLEGRO_AUDIO_STREAM *stream) { FLACFILE *ff = stream->extra; return real_seek(stream, ff->loop_start); } static double flac_stream_get_length(ALLEGRO_AUDIO_STREAM *stream) { FLACFILE *ff = stream->extra; return ff->total_samples / ff->sample_rate; } static bool flac_stream_set_loop(ALLEGRO_AUDIO_STREAM *stream, double start, double end) { FLACFILE *ff = stream->extra; ff->loop_start = start * ff->sample_rate; ff->loop_end = end * ff->sample_rate; return true; } static FLACFILE *flac_open(ALLEGRO_FILE* f) { FLACFILE *ff; FLAC__StreamDecoderInitStatus init_status; if (!init_dynlib()) { return NULL; } ff = al_calloc(1, sizeof *ff); ff->decoder = lib.FLAC__stream_decoder_new(); if (!ff->decoder) { ALLEGRO_ERROR("Error allocating FLAC decoder\n"); goto error; } ff->fh = f; if (!ff->fh) { ALLEGRO_ERROR("Error opening FLAC file\n"); goto error; } init_status = lib.FLAC__stream_decoder_init_stream(ff->decoder, read_callback, seek_callback, tell_callback, length_callback, eof_callback, write_callback, metadata_callback, error_callback, ff); if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { #ifdef ALLEGRO_CFG_ACODEC_FLAC_DLL ALLEGRO_ERROR("Error initializing FLAC decoder\n"); /* lazy */ #else ALLEGRO_ERROR("Error initializing FLAC decoder: %s\n", FLAC__StreamDecoderInitStatusString[init_status]); #endif goto error; } lib.FLAC__stream_decoder_process_until_end_of_metadata(ff->decoder); if (ff->sample_size == 0) { ALLEGRO_ERROR("Error: don't support sub 8-bit sizes\n"); goto error; } ALLEGRO_DEBUG("Loaded FLAC sample with properties:\n"); ALLEGRO_DEBUG(" channels %d\n", ff->channels); ALLEGRO_DEBUG(" sample_size %d\n", ff->sample_size); ALLEGRO_DEBUG(" rate %.f\n", ff->sample_rate); ALLEGRO_DEBUG(" total_samples %ld\n", (long) ff->total_samples); return ff; error: if (ff) { if (ff->decoder) lib.FLAC__stream_decoder_delete(ff->decoder); al_free(ff); } return NULL; } ALLEGRO_SAMPLE *_al_load_flac(const char *filename) { ALLEGRO_FILE *f; ALLEGRO_SAMPLE *spl; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } spl = _al_load_flac_f(f); al_fclose(f); return spl; } ALLEGRO_SAMPLE *_al_load_flac_f(ALLEGRO_FILE *f) { ALLEGRO_SAMPLE *sample; FLACFILE *ff; ff = flac_open(f); if (!ff) { return NULL; } ff->buffer_size = ff->total_samples * ff->channels * ff->sample_size; ff->buffer = al_malloc(ff->buffer_size); lib.FLAC__stream_decoder_process_until_end_of_stream(ff->decoder); sample = al_create_sample(ff->buffer, ff->total_samples, ff->sample_rate, _al_word_size_to_depth_conf(ff->sample_size), _al_count_to_channel_conf(ff->channels), true); if (!sample) { ALLEGRO_ERROR("Failed to create a sample.\n"); al_free(ff->buffer); } flac_close(ff); return sample; } ALLEGRO_AUDIO_STREAM *_al_load_flac_audio_stream(const char *filename, size_t buffer_count, unsigned int samples) { ALLEGRO_FILE *f; ALLEGRO_AUDIO_STREAM *stream; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } stream = _al_load_flac_audio_stream_f(f, buffer_count, samples); if (!stream) { al_fclose(f); } return stream; } ALLEGRO_AUDIO_STREAM *_al_load_flac_audio_stream_f(ALLEGRO_FILE* f, size_t buffer_count, unsigned int samples) { ALLEGRO_AUDIO_STREAM *stream; FLACFILE *ff; ff = flac_open(f); if (!ff) { return NULL; } stream = al_create_audio_stream(buffer_count, samples, ff->sample_rate, _al_word_size_to_depth_conf(ff->sample_size), _al_count_to_channel_conf(ff->channels)); if (stream) { stream->extra = ff; ff->loop_start = 0; ff->loop_end = ff->total_samples; stream->feeder = flac_stream_update; stream->unload_feeder = flac_stream_close; stream->rewind_feeder = flac_stream_rewind; stream->seek_feeder = flac_stream_seek; stream->get_feeder_position = flac_stream_get_position; stream->get_feeder_length = flac_stream_get_length; stream->set_feeder_loop = flac_stream_set_loop; _al_acodec_start_feed_thread(stream); } else { ALLEGRO_ERROR("Failed to create stream.\n"); al_fclose(ff->fh); flac_close(ff); } return stream; } bool _al_identify_flac(ALLEGRO_FILE *f) { uint8_t x[4]; if (al_fread(f, x, 4) < 4) return false; if (memcmp(x, "fLaC", 4) == 0) return true; return false; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/acodec/helper.c000066400000000000000000000027301473414355200175730ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_system.h" #include "helper.h" void _al_acodec_start_feed_thread(ALLEGRO_AUDIO_STREAM *stream) { stream->feed_thread = al_create_thread(_al_kcm_feed_stream, stream); stream->feed_thread_started_cond = al_create_cond(); stream->feed_thread_started_mutex = al_create_mutex(); al_start_thread(stream->feed_thread); /* Need to wait for the thread to start, otherwise the quit event may be * sent before the event source is registered with the queue. * * This also makes the pre-fill system thread safe, as it needs to operate * before the mutexes are set up. */ al_lock_mutex(stream->feed_thread_started_mutex); while (!stream->feed_thread_started) { al_wait_cond(stream->feed_thread_started_cond, stream->feed_thread_started_mutex); } al_unlock_mutex(stream->feed_thread_started_mutex); } void _al_acodec_stop_feed_thread(ALLEGRO_AUDIO_STREAM *stream) { ALLEGRO_EVENT quit_event; quit_event.type = _KCM_STREAM_FEEDER_QUIT_EVENT_TYPE; al_emit_user_event(al_get_audio_stream_event_source(stream), &quit_event, NULL); al_join_thread(stream->feed_thread, NULL); al_destroy_thread(stream->feed_thread); al_destroy_cond(stream->feed_thread_started_cond); al_destroy_mutex(stream->feed_thread_started_mutex); stream->feed_thread = NULL; } allegro5-5.2.10.1/addons/acodec/helper.h000066400000000000000000000003261473414355200175770ustar00rootroot00000000000000#ifndef __al_included_acodec_helper_h #define __al_included_acodec_helper_h void _al_acodec_start_feed_thread(ALLEGRO_AUDIO_STREAM *stream); void _al_acodec_stop_feed_thread(ALLEGRO_AUDIO_STREAM *stream); #endif allegro5-5.2.10.1/addons/acodec/modaudio.c000066400000000000000000000076571473414355200201320ustar00rootroot00000000000000/* * Allegro MOD file common routines * author: Matthew Leverton */ #define _FILE_OFFSET_BITS 64 #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern_audio.h" #include "acodec.h" ALLEGRO_DEBUG_CHANNEL("acodec") bool _al_identify_it(ALLEGRO_FILE *f) { uint8_t x[4]; if (al_fread(f, x, 4) < 4) return false; if (memcmp(x, "IMPM", 4) == 0) return true; return false; } bool _al_identify_669(ALLEGRO_FILE *f) { uint8_t x[2]; if (al_fread(f, x, 2) < 2) return false; if (memcmp(x, "if", 2) == 0 || memcmp(x, "JN", 2) == 0) return true; return false; } bool _al_identify_amf(ALLEGRO_FILE *f) { uint8_t x[3]; if (al_fread(f, x, 3) < 3) return false; if (memcmp(x, "AMF", 3) == 0) return true; return false; } bool _al_identify_asy(ALLEGRO_FILE *f) { uint8_t x[24]; if (al_fread(f, x, 24) < 24) return false; if (memcmp(x, "ASYLUM Music Format V1.0", 24) == 0) return true; return false; } bool _al_identify_mtm(ALLEGRO_FILE *f) { uint8_t x[3]; if (al_fread(f, x, 3) < 3) return false; if (memcmp(x, "MTM", 3) == 0) return true; return false; } bool _al_identify_okt(ALLEGRO_FILE *f) { uint8_t x[8]; if (al_fread(f, x, 8) < 8) return false; if (memcmp(x, "OKTASONG", 8) == 0) return true; return false; } bool _al_identify_psm(ALLEGRO_FILE *f) { uint8_t x[4]; if (al_fread(f, x, 4) < 4) return false; if (memcmp(x, "PSM\x00", 4) == 0 || memcmp(x, "PSM\xFE", 4) == 0) return true; return false; } bool _al_identify_ptm(ALLEGRO_FILE *f) { uint8_t x[4]; if (!al_fseek(f, 0x2C, ALLEGRO_SEEK_CUR)) return false; if (al_fread(f, x, 4) < 4) return false; if (memcmp(x, "DSMF", 4) == 0) return true; return false; } bool _al_identify_riff(ALLEGRO_FILE *f) { const char riff_fmts[][4] = { "AM ", "AMFF", "DSMF" }; uint8_t x[4]; if (al_fread(f, x, 4) < 4) return false; if (memcmp(x, "RIFF", 4) != 0) return false; if (!al_fseek(f, 4, ALLEGRO_SEEK_CUR)) return false; if (al_fread(f, x, 4) < 4) return false; for (size_t i = 0; i < sizeof(riff_fmts) / 4; ++i) { if (memcmp(x, riff_fmts[i], 4) == 0) return true; } return false; } bool _al_identify_stm(ALLEGRO_FILE *f) { const char stm_fmts[][8] = { "!Scream!", "BMOD2STM", "WUZAMOD!" }; uint8_t x[10]; if (!al_fseek(f, 20, ALLEGRO_SEEK_CUR)) return false; if (al_fread(f, x, 10) < 8) return false; if (x[9] != 2) return false; for (size_t i = 0; i < sizeof(stm_fmts) / 8; ++i) { if (memcmp(x, stm_fmts[i], 8) == 0) return true; } return false; } bool _al_identify_mod(ALLEGRO_FILE *f) { const char mod_sigs[][4] = { "M.K.", "M!K!", "M&K!", "N.T.", "NSMS", "FLT4", "M\0\0\0", "8\0\0\0", "FEST", "FLT8", "CD81", "OCTA", "OKTA", "16CN", "32CN" }; uint8_t x[4]; if (!al_fseek(f, 0x438, ALLEGRO_SEEK_CUR)) return false; if (al_fread(f, x, 4) < 4) return false; for (size_t i = 0; i < sizeof(mod_sigs) / 4; ++i) { if (memcmp(x, mod_sigs[i], 4) == 0) return true; } if (memcmp(x + 2, "CH", 2) == 0 && isdigit(x[0]) && isdigit(x[1])) /* ##CH */ return true; if (memcmp(x + 1, "CHN", 3) == 0 && isdigit(x[0])) /* #CHN */ return true; if (memcmp(x, "TDZ", 3) == 0 && isdigit(x[3])) /* TDZ? */ return true; return false; } bool _al_identify_s3m(ALLEGRO_FILE *f) { uint8_t x[4]; if (!al_fseek(f, 0x2C, ALLEGRO_SEEK_CUR)) return false; if (al_fread(f, x, 4) < 4) return false; if (memcmp(x, "SCRM", 4) == 0) return true; return false; } bool _al_identify_xm(ALLEGRO_FILE *f) { uint8_t x[16]; if (al_fread(f, x, 16) < 16) return false; if (memcmp(x, "Extended Module:", 16) == 0) return true; return false; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/acodec/mp3.c000066400000000000000000000362511473414355200170200ustar00rootroot00000000000000/* * Allegro5 MP3 reader. * Requires MiniMP3 from https://github.com/lieff/minimp3 * author: Mark Watkin (pmprog) 2019 */ #include "allegro5/allegro.h" #include "allegro5/allegro_acodec.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_system.h" #include "acodec.h" #include "helper.h" #define MINIMP3_IMPLEMENTATION #include #include ALLEGRO_DEBUG_CHANNEL("acodec") typedef struct MP3FILE { mp3dec_t dec; uint8_t* file_buffer; /* encoded MP3 file */ int64_t file_size; /* in bytes */ int64_t next_frame_offset; /* next frame offset, in bytes */ int file_pos; /* position in samples */ int file_samples; /* in samples */ double loop_start; double loop_end; mp3d_sample_t frame_buffer[MINIMP3_MAX_SAMPLES_PER_FRAME]; /* decoded MP3 frame */ int frame_pos; /* position in the frame buffer, in samples */ int* frame_offsets; /* in bytes */ int num_frames; int frame_samples; /* in samples, same across all frames */ int freq; ALLEGRO_CHANNEL_CONF chan_conf; } MP3FILE; ALLEGRO_SAMPLE *_al_load_mp3(const char *filename) { ALLEGRO_FILE *f; ALLEGRO_SAMPLE *spl; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_WARN("Could not open file '%s'.\n", filename); return NULL; } spl = _al_load_mp3_f(f); al_fclose(f); return spl; } ALLEGRO_SAMPLE *_al_load_mp3_f(ALLEGRO_FILE *f) { mp3dec_t dec; mp3dec_init(&dec); mp3dec_file_info_t info; ALLEGRO_SAMPLE *spl = NULL; /* Read our file size. */ int64_t filesize = al_fsize(f); if (filesize == -1) { ALLEGRO_WARN("Could not determine file size.\n"); return NULL; } /* Allocate buffer and read the entire file. */ uint8_t* mp3data = (uint8_t*)al_malloc(filesize); size_t readbytes = al_fread(f, mp3data, filesize); if (readbytes != (size_t)filesize) { ALLEGRO_WARN("Failed to read file into memory.\n"); al_free(mp3data); return NULL; } /* Decode the file contents, and copy to a new buffer. */ mp3dec_load_buf(&dec, mp3data, filesize, &info, NULL, NULL); al_free(mp3data); if (info.buffer == NULL) { ALLEGRO_WARN("Could not decode MP3.\n"); return NULL; } /* Create sample from info variable. */ spl = al_create_sample(info.buffer, info.samples / info.channels, info.hz, _al_word_size_to_depth_conf(sizeof(mp3d_sample_t)), _al_count_to_channel_conf(info.channels), true); return spl; } ALLEGRO_AUDIO_STREAM *_al_load_mp3_audio_stream(const char *filename, size_t buffer_count, unsigned int samples) { ALLEGRO_FILE *f; ALLEGRO_AUDIO_STREAM *stream; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_WARN("Could not open file '%s'.\n", filename); return NULL; } stream = _al_load_mp3_audio_stream_f(f, buffer_count, samples); /* We load the entire file into memory. */ al_fclose(f); return stream; } static bool mp3_stream_seek(ALLEGRO_AUDIO_STREAM * stream, double time) { MP3FILE *mp3file = (MP3FILE *) stream->extra; int file_pos = time * mp3file->freq; int frame = file_pos / mp3file->frame_samples; /* It is necessary to start decoding a little earlier than where we are * seeking to, because frames will reuse decoder state from previous frames. * minimp3 assures us that 10 frames is sufficient. */ int sync_frame = _ALLEGRO_MAX(0, frame - 10); int frame_pos = file_pos - frame * mp3file->frame_samples; if (frame < 0 || frame > mp3file->num_frames) { ALLEGRO_WARN("Seeking outside the stream bounds: %f\n", time); return false; } int frame_offset = mp3file->frame_offsets[frame]; int sync_frame_offset = mp3file->frame_offsets[sync_frame]; mp3dec_frame_info_t frame_info; do { mp3dec_decode_frame(&mp3file->dec, mp3file->file_buffer + sync_frame_offset, mp3file->file_size - sync_frame_offset, mp3file->frame_buffer, &frame_info); sync_frame_offset += frame_info.frame_bytes; } while (sync_frame_offset <= frame_offset); mp3file->next_frame_offset = frame_offset + frame_info.frame_bytes; mp3file->file_pos = file_pos; mp3file->frame_pos = frame_pos; return true; } static bool mp3_stream_rewind(ALLEGRO_AUDIO_STREAM *stream) { MP3FILE *mp3file = (MP3FILE *) stream->extra; return mp3_stream_seek(stream, mp3file->loop_start); } static double mp3_stream_get_position(ALLEGRO_AUDIO_STREAM *stream) { MP3FILE *mp3file = (MP3FILE *) stream->extra; return (double)mp3file->file_pos / mp3file->freq; } static double mp3_stream_get_length(ALLEGRO_AUDIO_STREAM * stream) { MP3FILE *mp3file = (MP3FILE *) stream->extra; return (double)mp3file->file_samples / mp3file->freq; } static bool mp3_stream_set_loop(ALLEGRO_AUDIO_STREAM * stream, double start, double end) { MP3FILE *mp3file = (MP3FILE *) stream->extra; mp3file->loop_start = start; mp3file->loop_end = end; return true; } /* mp3_stream_update: * Updates 'stream' with the next chunk of data. * Returns the actual number of bytes written. */ static size_t mp3_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data, size_t buf_size) { MP3FILE *mp3file = (MP3FILE *) stream->extra; int sample_size = sizeof(mp3d_sample_t) * al_get_channel_count(mp3file->chan_conf); int samples_needed = buf_size / sample_size;; double ctime = mp3_stream_get_position(stream); double btime = (double)samples_needed / mp3file->freq; if (stream->spl.loop != _ALLEGRO_PLAYMODE_STREAM_ONCE && ctime + btime > mp3file->loop_end) { samples_needed = (mp3file->loop_end - ctime) * mp3file->freq; } if (samples_needed < 0) return 0; mp3dec_t dec; mp3dec_init(&dec); int samples_read = 0; while (samples_read < samples_needed) { int samples_from_this_frame = _ALLEGRO_MIN( mp3file->frame_samples - mp3file->frame_pos, samples_needed - samples_read ); memcpy(data, mp3file->frame_buffer + mp3file->frame_pos * al_get_channel_count(mp3file->chan_conf), samples_from_this_frame * sample_size); mp3file->frame_pos += samples_from_this_frame; mp3file->file_pos += samples_from_this_frame; data = (char*)(data) + samples_from_this_frame * sample_size; samples_read += samples_from_this_frame; if (mp3file->frame_pos >= mp3file->frame_samples) { mp3dec_frame_info_t frame_info; int frame_samples = mp3dec_decode_frame(&mp3file->dec, mp3file->file_buffer + mp3file->next_frame_offset, mp3file->file_size - mp3file->next_frame_offset, mp3file->frame_buffer, &frame_info); if (frame_samples == 0) { mp3_stream_rewind(stream); break; } mp3file->frame_pos = 0; mp3file->next_frame_offset += frame_info.frame_bytes; } } return samples_read * sample_size; } static void mp3_stream_close(ALLEGRO_AUDIO_STREAM *stream) { MP3FILE *mp3file = (MP3FILE *) stream->extra; _al_acodec_stop_feed_thread(stream); al_free(mp3file->frame_offsets); al_free(mp3file->file_buffer); al_free(mp3file); stream->extra = NULL; stream->feed_thread = NULL; } ALLEGRO_AUDIO_STREAM *_al_load_mp3_audio_stream_f(ALLEGRO_FILE* f, size_t buffer_count, unsigned int samples) { MP3FILE* mp3file = al_calloc(sizeof(MP3FILE), 1); mp3dec_init(&mp3file->dec); /* Read our file size. */ mp3file->file_size = al_fsize(f); if (mp3file->file_size == -1) { ALLEGRO_WARN("Could not determine file size.\n"); goto failure; } /* Allocate buffer and read all the file. */ mp3file->file_buffer = (uint8_t*)al_malloc(mp3file->file_size); size_t readbytes = al_fread(f, mp3file->file_buffer, mp3file->file_size); if (readbytes != (size_t)mp3file->file_size) { ALLEGRO_WARN("Failed to read file into memory.\n"); goto failure; } /* Go through all the frames, to build the offset table. */ int frame_offset_capacity = 0; int offset_so_far = 0; while (true) { if (mp3file->num_frames + 1 > frame_offset_capacity) { frame_offset_capacity = mp3file->num_frames * 3 / 2 + 1; mp3file->frame_offsets = al_realloc(mp3file->frame_offsets, sizeof(int) * frame_offset_capacity); } mp3dec_frame_info_t frame_info; int frame_samples = mp3dec_decode_frame(&mp3file->dec, mp3file->file_buffer + offset_so_far, mp3file->file_size - offset_so_far, NULL, &frame_info); if (frame_samples == 0) { if (mp3file->num_frames == 0) { ALLEGRO_WARN("Could not decode the first frame.\n"); goto failure; } else { break; } } /* Grab the file information from the first frame. */ if (offset_so_far == 0) { ALLEGRO_DEBUG("Channels %d, frequency %d\n", frame_info.channels, frame_info.hz); mp3file->chan_conf = _al_count_to_channel_conf(frame_info.channels); mp3file->freq = frame_info.hz; mp3file->frame_samples = frame_samples; } mp3file->frame_offsets[mp3file->num_frames] = offset_so_far; mp3file->num_frames += 1; offset_so_far += frame_info.frame_bytes; mp3file->file_samples += frame_samples; } mp3file->loop_end = (double)mp3file->file_samples * mp3file->freq; ALLEGRO_AUDIO_STREAM *stream = al_create_audio_stream( buffer_count, samples, mp3file->freq, _al_word_size_to_depth_conf(sizeof(mp3d_sample_t)), mp3file->chan_conf); if (!stream) { ALLEGRO_WARN("Failed to create stream.\n"); goto failure; } stream->extra = mp3file; stream->feeder = mp3_stream_update; stream->unload_feeder = mp3_stream_close; stream->rewind_feeder = mp3_stream_rewind; stream->seek_feeder = mp3_stream_seek; stream->get_feeder_position = mp3_stream_get_position; stream->get_feeder_length = mp3_stream_get_length; stream->set_feeder_loop = mp3_stream_set_loop; mp3_stream_rewind(stream); _al_acodec_start_feed_thread(stream); return stream; failure: al_free(mp3file->frame_offsets); al_free(mp3file->file_buffer); al_free(mp3file); return NULL; } /* --- Start of minimp3 code --- */ /* The following code is copied from minimp3 to avoid depending on internals. * `HDR_` and `hdr_` prefixes have been replaced with `IDMP3_` and `idmp3_`. */ #define IDMP3_HDR_SIZE 4 #define IDMP3_IS_FREE_FORMAT(h) ((((h)[2]) & 0xF0) == 0) #define IDMP3_TEST_PADDING(h) (((h)[2]) & 0x2) #define IDMP3_TEST_MPEG1(h) (((h)[1]) & 0x8) #define IDMP3_TEST_NOT_MPEG25(h) (((h)[1]) & 0x10) #define IDMP3_IS_FRAME_576(h) (((h)[1] & 14) == 2) #define IDMP3_IS_LAYER_1(h) (((h)[1] & 6) == 6) #define IDMP3_GET_LAYER(h) ((((h)[1]) >> 1) & 3) #define IDMP3_GET_BITRATE(h) (((h)[2]) >> 4) #define IDMP3_GET_SAMPLE_RATE(h) ((((h)[2]) >> 2) & 3) static int idmp3_frame_samples(const uint8_t* h) { return IDMP3_IS_LAYER_1(h) ? 384 : (1152 >> (int)IDMP3_IS_FRAME_576(h)); } static int idmp3_bitrate_kbps(const uint8_t* h) { static const uint8_t halfrate[2][3][15] = { { { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,16,24,28,32,40,48,56,64,72,80,88,96,112,128 } }, { { 0,16,20,24,28,32,40,48,56,64,80,96,112,128,160 }, { 0,16,24,28,32,40,48,56,64,80,96,112,128,160,192 }, { 0,16,32,48,64,80,96,112,128,144,160,176,192,208,224 } }, }; return 2 * halfrate[!!IDMP3_TEST_MPEG1(h)][IDMP3_GET_LAYER(h) - 1][IDMP3_GET_BITRATE(h)]; } static int idmp3_sample_rate_hz(const uint8_t* h) { static const int g_hz[3] = { 44100, 48000, 32000 }; return g_hz[IDMP3_GET_SAMPLE_RATE(h)] >> (int)!IDMP3_TEST_MPEG1(h) >> (int)!IDMP3_TEST_NOT_MPEG25(h); } static int idmp3_frame_bytes(const uint8_t* h, int free_format_size) { int frame_bytes = idmp3_frame_samples(h) * idmp3_bitrate_kbps(h) * 125 / idmp3_sample_rate_hz(h); if (IDMP3_IS_LAYER_1(h)) frame_bytes &= ~3; /* slot align */ return frame_bytes ? frame_bytes : free_format_size; } static int idmp3_padding(const uint8_t* h) { return IDMP3_TEST_PADDING(h) ? (IDMP3_IS_LAYER_1(h) ? 4 : 1) : 0; } static int idmp3_valid(const uint8_t* h) { return h[0] == 0xff && ((h[1] & 0xF0) == 0xf0 || (h[1] & 0xFE) == 0xe2) && (IDMP3_GET_LAYER(h) != 0) && (IDMP3_GET_BITRATE(h) != 15) && (IDMP3_GET_SAMPLE_RATE(h) != 3); } static int idmp3_compare(const uint8_t* h1, const uint8_t* h2) { return idmp3_valid(h2) && ((h1[1] ^ h2[1]) & 0xFE) == 0 && ((h1[2] ^ h2[2]) & 0x0C) == 0 && !(IDMP3_IS_FREE_FORMAT(h1) ^ IDMP3_IS_FREE_FORMAT(h2)); } /* --- End of minimp3 code --- */ /* Attempts to identify an MP3 file by looking for contiguous MP3 frames. * The tested buffer length should be 8KB for the best accuracy. * Returns true for a match. */ static bool identify_mp3(const uint8_t* buf, size_t len) { const uint8_t* end = buf + len - IDMP3_HDR_SIZE; const uint8_t* quarter = buf + (len / 4) - IDMP3_HDR_SIZE; /* Too short to possibly contain a valid header. */ if (len < IDMP3_HDR_SIZE) return false; /* A file with an ID3v2 tag is assumed to be an MP3 file. */ if (memcmp(buf, "ID3", 3) == 0) return true; /* Only scan the first quarter of the file (2KB out of 8KB) for the initial * frame. This guarantees at least 2 frames in the worst case, but typically * at least 5, can be synced to. */ for (const uint8_t* p = buf; p < quarter; ++p) { if (idmp3_valid(p)) { int frame_bytes = idmp3_frame_bytes(p, 0); int num_frames = 0; const uint8_t* p2 = p; /* free-format -- scan for next frame to discover its length. */ if (frame_bytes == 0) { for (p2 += IDMP3_HDR_SIZE; p2 < end; ++p2) { if (idmp3_compare(p, p2)) { frame_bytes = (int)(p2 - p); ++num_frames; break; } /* Excessive distance between frames */ if ((p2 - p) >= 1152 * 2) goto continue_scan; } /* Reached end of buffer without finding a matching header */ if (p2 == end) goto continue_scan; } p2 += frame_bytes + idmp3_padding(p2); while (p2 < end) { if (idmp3_compare(p, p2)) { /* Bitrate can change per-frame (VBR) */ frame_bytes = idmp3_frame_bytes(p2, frame_bytes); p2 += frame_bytes + idmp3_padding(p2); /* 10 valid frames is enough to identify this as an MP3 file */ if (++num_frames >= 9) return true; } else { goto continue_scan; } } /* Reached the end of the buffer. Everything prior was contiguous * frames, so this is likely an MP3 file. */ return true; } continue_scan: ; } return false; } bool _al_identify_mp3(ALLEGRO_FILE *f) { uint8_t x[8192]; size_t len = al_fread(f, x, sizeof x); return identify_mp3(x, len); } allegro5-5.2.10.1/addons/acodec/ogg.c000066400000000000000000000325741473414355200171010ustar00rootroot00000000000000/* * Allegro5 Ogg Vorbis reader. * Can load samples and do streaming * author: Ryan Dickie (c) 2008 */ #include "allegro5/allegro.h" #include "allegro5/allegro_acodec.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_system.h" #include "acodec.h" #include "helper.h" #ifndef ALLEGRO_CFG_ACODEC_VORBIS #error configuration problem, ALLEGRO_CFG_ACODEC_VORBIS not set #endif ALLEGRO_DEBUG_CHANNEL("acodec") #if defined(ALLEGRO_CFG_ACODEC_TREMOR) #include #define TREMOR 1 #else #include #endif typedef struct AL_OV_DATA AL_OV_DATA; struct AL_OV_DATA { OggVorbis_File *vf; vorbis_info *vi; ALLEGRO_FILE *file; int bitstream; double loop_start; double loop_end; }; /* dynamic loading support (Windows only currently) */ #ifdef ALLEGRO_CFG_ACODEC_VORBISFILE_DLL static void *ov_dll = NULL; static bool ov_virgin = true; #endif static struct { int (*ov_clear)(OggVorbis_File *); ogg_int64_t (*ov_pcm_total)(OggVorbis_File *, int); vorbis_info *(*ov_info)(OggVorbis_File *, int); #ifndef TREMOR int (*ov_open_callbacks)(void *, OggVorbis_File *, const char *, long, ov_callbacks); double (*ov_time_total)(OggVorbis_File *, int); int (*ov_time_seek)(OggVorbis_File *, double); double (*ov_time_tell)(OggVorbis_File *); long (*ov_read)(OggVorbis_File *, char *, int, int, int, int, int *); #else int (*ov_open_callbacks)(void *, OggVorbis_File *, const char *, long, ov_callbacks); ogg_int64_t (*ov_time_total)(OggVorbis_File *, int); int (*ov_time_seek)(OggVorbis_File *, ogg_int64_t); ogg_int64_t (*ov_time_tell)(OggVorbis_File *); long (*ov_read)(OggVorbis_File *, char *, int, int *); #endif } lib; #ifdef ALLEGRO_CFG_ACODEC_VORBISFILE_DLL static void shutdown_dynlib(void) { if (ov_dll) { _al_close_library(ov_dll); ov_dll = NULL; ov_virgin = true; } } #endif static bool init_dynlib(void) { #ifdef ALLEGRO_CFG_ACODEC_VORBISFILE_DLL if (ov_dll) { return true; } if (!ov_virgin) { return false; } ov_virgin = false; ov_dll = _al_open_library(ALLEGRO_CFG_ACODEC_VORBISFILE_DLL); if (!ov_dll) { ALLEGRO_ERROR("Could not load " ALLEGRO_CFG_ACODEC_VORBISFILE_DLL "\n"); return false; } _al_add_exit_func(shutdown_dynlib, "shutdown_dynlib"); #define INITSYM(x) \ do \ { \ lib.x = _al_import_symbol(ov_dll, #x); \ if (lib.x == 0) { \ ALLEGRO_ERROR("undefined symbol in lib structure: " #x "\n"); \ return false; \ } \ } while(0) #else #define INITSYM(x) (lib.x = (x)) #endif memset(&lib, 0, sizeof(lib)); INITSYM(ov_clear); INITSYM(ov_open_callbacks); INITSYM(ov_pcm_total); INITSYM(ov_info); INITSYM(ov_time_total); INITSYM(ov_time_seek); INITSYM(ov_time_tell); INITSYM(ov_read); return true; #undef INITSYM } static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *dptr) { AL_OV_DATA *ov = (AL_OV_DATA *)dptr; size_t ret = 0; ret = al_fread(ov->file, ptr, size*nmemb); return ret; } static int seek_callback(void *dptr, ogg_int64_t offset, int whence) { AL_OV_DATA *ov = (AL_OV_DATA *)dptr; switch(whence) { case SEEK_SET: whence = ALLEGRO_SEEK_SET; break; case SEEK_CUR: whence = ALLEGRO_SEEK_CUR; break; case SEEK_END: whence = ALLEGRO_SEEK_END; break; } if (!al_fseek(ov->file, offset, whence)) { return -1; } return 0; } static long tell_callback(void *dptr) { AL_OV_DATA *ov = (AL_OV_DATA *)dptr; int64_t ret = 0; ret = al_ftell(ov->file); if (ret == -1) return -1; return (long)ret; } static int close_callback(void *dptr) { /* Don't close dptr->file here. */ (void)dptr; return 0; } static ov_callbacks callbacks = { read_callback, seek_callback, close_callback, tell_callback }; ALLEGRO_SAMPLE *_al_load_ogg_vorbis(const char *filename) { ALLEGRO_FILE *f; ALLEGRO_SAMPLE *spl; ASSERT(filename); ALLEGRO_INFO("Loading sample %s.\n", filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } spl = _al_load_ogg_vorbis_f(f); al_fclose(f); return spl; } ALLEGRO_SAMPLE *_al_load_ogg_vorbis_f(ALLEGRO_FILE *file) { /* Note: decoding library returns floats. I always return 16-bit (most * commonly supported). */ #ifdef ALLEGRO_LITTLE_ENDIAN const int endian = 0; /* 0 for Little-Endian, 1 for Big-Endian */ #else const int endian = 1; /* 0 for Little-Endian, 1 for Big-Endian */ #endif int word_size = 2; /* 1 = 8bit, 2 = 16-bit. nothing else */ int signedness = 1; /* 0 for unsigned, 1 for signed */ const int packet_size = 4096; /* suggestion for size to read at a time */ OggVorbis_File vf; vorbis_info* vi; char *buffer; long pos; ALLEGRO_SAMPLE *sample; int channels; long rate; long total_samples; int bitstream; long total_size; AL_OV_DATA ov; long read; if (!init_dynlib()) { return NULL; } ov.file = file; if (lib.ov_open_callbacks(&ov, &vf, NULL, 0, callbacks) < 0) { ALLEGRO_ERROR("Audio file does not appear to be an Ogg bitstream.\n"); return NULL; } vi = lib.ov_info(&vf, -1); channels = vi->channels; rate = vi->rate; total_samples = lib.ov_pcm_total(&vf, -1); bitstream = -1; total_size = total_samples * channels * word_size; ALLEGRO_DEBUG("channels %d\n", channels); ALLEGRO_DEBUG("word_size %d\n", word_size); ALLEGRO_DEBUG("rate %ld\n", rate); ALLEGRO_DEBUG("total_samples %ld\n", total_samples); ALLEGRO_DEBUG("total_size %ld\n", total_size); buffer = al_malloc(total_size); if (!buffer) { ALLEGRO_ERROR("Unable to allocate buffer (%ld).\n", total_size); return NULL; } pos = 0; while (pos < total_size) { const int read_size = _ALLEGRO_MIN(packet_size, total_size - pos); ASSERT(pos + read_size <= total_size); /* XXX error handling */ #ifndef TREMOR read = lib.ov_read(&vf, buffer + pos, read_size, endian, word_size, signedness, &bitstream); #else (void)endian; (void)signedness; read = lib.ov_read(&vf, buffer + pos, read_size, &bitstream); #endif pos += read; if (read == 0) break; } lib.ov_clear(&vf); sample = al_create_sample(buffer, total_samples, rate, _al_word_size_to_depth_conf(word_size), _al_count_to_channel_conf(channels), true); if (!sample) { ALLEGRO_ERROR("Failed to create sample.\n"); al_free(buffer); } return sample; } static bool ogg_stream_seek(ALLEGRO_AUDIO_STREAM *stream, double time) { AL_OV_DATA *extra = (AL_OV_DATA *) stream->extra; if (time >= extra->loop_end) return false; #ifndef TREMOR return (lib.ov_time_seek(extra->vf, time) != -1); #else return lib.ov_time_seek(extra->vf, time*1000) != -1; #endif } static bool ogg_stream_rewind(ALLEGRO_AUDIO_STREAM *stream) { AL_OV_DATA *extra = (AL_OV_DATA *) stream->extra; return ogg_stream_seek(stream, extra->loop_start); } static double ogg_stream_get_position(ALLEGRO_AUDIO_STREAM *stream) { AL_OV_DATA *extra = (AL_OV_DATA *) stream->extra; #ifndef TREMOR return lib.ov_time_tell(extra->vf); #else return lib.ov_time_tell(extra->vf)/1000.0; #endif } static double ogg_stream_get_length(ALLEGRO_AUDIO_STREAM *stream) { AL_OV_DATA *extra = (AL_OV_DATA *) stream->extra; #ifndef TREMOR double ret = lib.ov_time_total(extra->vf, -1); #else double ret = lib.ov_time_total(extra->vf, -1)/1000.0; #endif return ret; } static bool ogg_stream_set_loop(ALLEGRO_AUDIO_STREAM *stream, double start, double end) { AL_OV_DATA *extra = (AL_OV_DATA *) stream->extra; extra->loop_start = start; extra->loop_end = end; return true; } /* To be called when stream is destroyed */ static void ogg_stream_close(ALLEGRO_AUDIO_STREAM *stream) { AL_OV_DATA *extra = (AL_OV_DATA *) stream->extra; _al_acodec_stop_feed_thread(stream); al_fclose(extra->file); lib.ov_clear(extra->vf); al_free(extra->vf); al_free(extra); stream->extra = NULL; } static size_t ogg_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data, size_t buf_size) { AL_OV_DATA *extra = (AL_OV_DATA *) stream->extra; #ifdef ALLEGRO_LITTLE_ENDIAN const int endian = 0; /* 0 for Little-Endian, 1 for Big-Endian */ #else const int endian = 1; /* 0 for Little-Endian, 1 for Big-Endian */ #endif const int word_size = 2; /* 1 = 8bit, 2 = 16-bit. nothing else */ const int signedness = 1; /* 0 for unsigned, 1 for signed */ unsigned long pos = 0; int read_length = buf_size; #ifndef TREMOR double ctime = lib.ov_time_tell(extra->vf); #else double ctime = lib.ov_time_tell(extra->vf)/1000.0; #endif double rate = extra->vi->rate; double btime = ((double)buf_size / ((double)word_size * (double)extra->vi->channels)) / rate; unsigned long read; if (stream->spl.loop != _ALLEGRO_PLAYMODE_STREAM_ONCE && ctime + btime > extra->loop_end) { const int frame_size = word_size * extra->vi->channels; read_length = (extra->loop_end - ctime) * rate * (double)word_size * (double)extra->vi->channels; if (read_length < 0) return 0; if (read_length % frame_size > 0) { read_length += (frame_size - (read_length % frame_size)); } } while (pos < (unsigned long)read_length) { #ifndef TREMOR read = lib.ov_read(extra->vf, (char *)data + pos, read_length - pos, endian, word_size, signedness, &extra->bitstream); #else (void)endian; (void)signedness; read = lib.ov_read(extra->vf, (char *)data + pos, read_length - pos, &extra->bitstream); #endif pos += read; if (read == 0) { /* Return the number of useful bytes written. */ return pos; } } return pos; } ALLEGRO_AUDIO_STREAM *_al_load_ogg_vorbis_audio_stream(const char *filename, size_t buffer_count, unsigned int samples) { ALLEGRO_FILE *f; ALLEGRO_AUDIO_STREAM *stream; ASSERT(filename); ALLEGRO_INFO("Loading stream %s.\n", filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } stream = _al_load_ogg_vorbis_audio_stream_f(f, buffer_count, samples); if (!stream) { al_fclose(f); } return stream; } ALLEGRO_AUDIO_STREAM *_al_load_ogg_vorbis_audio_stream_f(ALLEGRO_FILE *file, size_t buffer_count, unsigned int samples) { const int word_size = 2; /* 1 = 8bit, 2 = 16-bit. nothing else */ OggVorbis_File* vf; vorbis_info* vi; int channels; long rate; long total_samples; long total_size; AL_OV_DATA* extra; ALLEGRO_AUDIO_STREAM* stream; if (!init_dynlib()) { return NULL; } extra = al_malloc(sizeof(AL_OV_DATA)); if (extra == NULL) { ALLEGRO_ERROR("Failed to allocate AL_OV_DATA struct.\n"); return NULL; } extra->file = file; vf = al_malloc(sizeof(OggVorbis_File)); if (lib.ov_open_callbacks(extra, vf, NULL, 0, callbacks) < 0) { ALLEGRO_ERROR("ogg: Input does not appear to be an Ogg bitstream.\n"); return NULL; } extra->vf = vf; vi = lib.ov_info(vf, -1); channels = vi->channels; rate = vi->rate; total_samples = lib.ov_pcm_total(vf, -1); total_size = total_samples * channels * word_size; extra->vi = vi; extra->bitstream = -1; ALLEGRO_DEBUG("channels %d\n", channels); ALLEGRO_DEBUG("word_size %d\n", word_size); ALLEGRO_DEBUG("rate %ld\n", rate); ALLEGRO_DEBUG("total_samples %ld\n", total_samples); ALLEGRO_DEBUG("total_size %ld\n", total_size); stream = al_create_audio_stream(buffer_count, samples, rate, _al_word_size_to_depth_conf(word_size), _al_count_to_channel_conf(channels)); if (!stream) { ALLEGRO_ERROR("Failed to create the stream.\n"); lib.ov_clear(vf); al_free(vf); return NULL; } stream->extra = extra; extra->loop_start = 0.0; extra->loop_end = ogg_stream_get_length(stream); stream->quit_feed_thread = false; stream->feeder = ogg_stream_update; stream->rewind_feeder = ogg_stream_rewind; stream->seek_feeder = ogg_stream_seek; stream->get_feeder_position = ogg_stream_get_position; stream->get_feeder_length = ogg_stream_get_length; stream->set_feeder_loop = ogg_stream_set_loop; stream->unload_feeder = ogg_stream_close; _al_acodec_start_feed_thread(stream); return stream; } bool _al_identify_ogg_vorbis(ALLEGRO_FILE *f) { uint8_t x[8]; if (al_fread(f, x, 4) < 4) return false; if (memcmp(x, "OggS", 4) != 0) return false; if (!al_fseek(f, 23, ALLEGRO_SEEK_CUR)) return false; if (al_fread(f, x, 8) < 8) return false; if (memcmp(x, "\x1E\x01vorbis", 8) == 0) return true; return false; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/acodec/openmpt.c000066400000000000000000000241041473414355200177750ustar00rootroot00000000000000/* * Allegro OpenMPT wrapper * author: Pavel Sountsov */ #define _FILE_OFFSET_BITS 64 #include #include "allegro5/allegro.h" #include "allegro5/allegro_acodec.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_system.h" #include "acodec.h" #include "helper.h" #ifndef ALLEGRO_CFG_ACODEC_OPENMPT #error configuration problem, ALLEGRO_CFG_ACODEC_OPENMPT not set #endif #include #include ALLEGRO_DEBUG_CHANNEL("acodec") typedef struct MOD_FILE { openmpt_module *mod; ALLEGRO_FILE *fh; double length; double loop_start, loop_end; } MOD_FILE; static size_t stream_read_func(void *stream, void *dst, size_t bytes) { return al_fread((ALLEGRO_FILE*)stream, dst, bytes); } static int stream_seek_func(void *stream, int64_t offset, int whence) { int allegro_whence; switch (whence) { case OPENMPT_STREAM_SEEK_SET: allegro_whence = ALLEGRO_SEEK_SET; break; case OPENMPT_STREAM_SEEK_CUR: allegro_whence = ALLEGRO_SEEK_CUR; break; case OPENMPT_STREAM_SEEK_END: allegro_whence = ALLEGRO_SEEK_END; break; default: return -1; } return al_fseek((ALLEGRO_FILE*)stream, offset, allegro_whence) ? 0 : -1; } static int64_t stream_tell_func(void *stream) { return al_ftell((ALLEGRO_FILE*)stream); } static void log_func(const char* message, void *user) { (void)user; ALLEGRO_DEBUG("OpenMPT: %s\n", message); } static int error_func(int error, void *user) { (void)user; const char* error_str = openmpt_error_string(error); if (error_str) { ALLEGRO_ERROR("OpenMPT error: %s\n", error_str); openmpt_free_string(error_str); } else ALLEGRO_ERROR("OpenMPT error: %d\n", error); return OPENMPT_ERROR_FUNC_RESULT_NONE; } // /* Stream Functions */ static size_t openmpt_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data, size_t buf_size) { MOD_FILE *const modf = stream->extra; /* the mod files are stereo and 16-bit */ const int frame_size = 4; size_t written = 0; size_t i; if (stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONCE) { openmpt_module_ctl_set_text(modf->mod, "play.at_end", "stop"); openmpt_module_set_repeat_count(modf->mod, 0); } else { openmpt_module_ctl_set_text(modf->mod, "play.at_end", "continue"); openmpt_module_set_repeat_count(modf->mod, -1); } int count = 0; while (written < buf_size) { long frames_to_read = (buf_size - written * frame_size) / frame_size; double position = openmpt_module_get_position_seconds(modf->mod); bool manual_loop = false; /* If manual looping is not enabled, then we need to implement * short-stopping manually. */ if (stream->spl.loop != _ALLEGRO_PLAYMODE_STREAM_ONCE && modf->loop_end != -1 && position + frames_to_read / 44100 >= modf->loop_end) { frames_to_read = (long)((modf->loop_end - position) * 44100); if (frames_to_read < 0) frames_to_read = 0; manual_loop = true; } written += openmpt_module_read_interleaved_stereo(modf->mod, 44100, frames_to_read, (int16_t*)&(((char *)data)[written])) * frame_size; if (((long)written < frames_to_read * frame_size) || manual_loop) { break; } count += 1; } /* Fill the remainder with silence */ for (i = written; i < buf_size; ++i) ((char *)data)[i] = 0; return written; } static void openmpt_stream_close(ALLEGRO_AUDIO_STREAM *stream) { MOD_FILE *const modf = stream->extra; _al_acodec_stop_feed_thread(stream); openmpt_module_destroy(modf->mod); if (modf->fh) al_fclose(modf->fh); } static bool openmpt_stream_rewind(ALLEGRO_AUDIO_STREAM *stream) { MOD_FILE *const modf = stream->extra; openmpt_module_set_position_seconds(modf->mod, modf->loop_start); return true; } static bool openmpt_stream_seek(ALLEGRO_AUDIO_STREAM *stream, double time) { MOD_FILE *const modf = stream->extra; if (modf->loop_end != -1 && time > modf->loop_end) { return false; } openmpt_module_set_position_seconds(modf->mod, time); return false; } static double openmpt_stream_get_position(ALLEGRO_AUDIO_STREAM *stream) { MOD_FILE *const modf = stream->extra; return openmpt_module_get_position_seconds(modf->mod); } static double openmpt_stream_get_length(ALLEGRO_AUDIO_STREAM *stream) { MOD_FILE *const modf = stream->extra; return modf->length; } static bool openmpt_stream_set_loop(ALLEGRO_AUDIO_STREAM *stream, double start, double end) { MOD_FILE *const modf = stream->extra; modf->loop_start = start; modf->loop_end = end; return true; } static ALLEGRO_AUDIO_STREAM *openmpt_stream_init(ALLEGRO_FILE* f, size_t buffer_count, unsigned int samples ) { int64_t start_pos = al_ftell(f); ALLEGRO_AUDIO_STREAM *stream = NULL; openmpt_stream_callbacks callbacks = { stream_read_func, stream_seek_func, stream_tell_func, }; openmpt_module *mod = openmpt_module_create2( callbacks, f, &log_func, NULL, &error_func, NULL, NULL, NULL, NULL); // HACK: For whatever reason, OpenMPT is slightly quieter than DUMB. // For many modules, this is *very* close to sqrt(2) which is suggestive of // some stereo gain correction, but I could not find the code responsible. // // Also, for some modules it's actually louder by 2x rather than 1.44x, // which is confusing as well. openmpt_module_set_render_param(mod, OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL, 300); if (!mod) return NULL; // TODO: OpenMPT recommends 48000 and float // TODO: OpenMPT supports quad channels too stream = al_create_audio_stream(buffer_count, samples, 44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); if (stream) { MOD_FILE *mf = al_malloc(sizeof(MOD_FILE)); mf->mod = mod; mf->fh = NULL; mf->length = openmpt_module_get_duration_seconds(mod); if (mf->length < 0) { mf->length = 0; } /* * Set these to -1, so that we can default to the internal loop * points. */ mf->loop_start = -1; mf->loop_end = -1; stream->extra = mf; stream->feeder = openmpt_stream_update; stream->unload_feeder = openmpt_stream_close; stream->rewind_feeder = openmpt_stream_rewind; stream->seek_feeder = openmpt_stream_seek; stream->get_feeder_position = openmpt_stream_get_position; stream->get_feeder_length = openmpt_stream_get_length; stream->set_feeder_loop = openmpt_stream_set_loop; _al_acodec_start_feed_thread(stream); } else { ALLEGRO_ERROR("Failed to create stream.\n"); goto Error; } return stream; Error: openmpt_module_destroy(mod); /* try to return back to where we started to load */ if (start_pos != -1) al_fseek(f, start_pos, ALLEGRO_SEEK_SET); return NULL; } static ALLEGRO_AUDIO_STREAM *load_audio_stream_f(ALLEGRO_FILE *f, size_t buffer_count, unsigned int samples) { return openmpt_stream_init(f, buffer_count, samples); } static ALLEGRO_AUDIO_STREAM *load_audio_stream(const char *filename, size_t buffer_count, unsigned int samples) { ALLEGRO_FILE *f; ALLEGRO_AUDIO_STREAM *stream; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } stream = load_audio_stream_f(f, buffer_count, samples); if (!stream) { al_fclose(f); return NULL; } ((MOD_FILE *)stream->extra)->fh = f; return stream; } bool _al_register_openmpt_loaders(void) { bool ret = true; ret &= al_register_audio_stream_loader(".669", load_audio_stream); ret &= al_register_audio_stream_loader_f(".669", load_audio_stream_f); ret &= al_register_sample_identifier(".669", _al_identify_669); ret &= al_register_audio_stream_loader(".amf", load_audio_stream); ret &= al_register_audio_stream_loader_f(".amf", load_audio_stream_f); ret &= al_register_sample_identifier(".amf", _al_identify_amf); ret &= al_register_audio_stream_loader(".it", load_audio_stream); ret &= al_register_audio_stream_loader_f(".it", load_audio_stream_f); ret &= al_register_sample_identifier(".it", _al_identify_it); ret &= al_register_audio_stream_loader(".mod", load_audio_stream); ret &= al_register_audio_stream_loader_f(".mod", load_audio_stream_f); ret &= al_register_sample_identifier(".mod", _al_identify_mod); ret &= al_register_audio_stream_loader(".mtm", load_audio_stream); ret &= al_register_audio_stream_loader_f(".mtm", load_audio_stream_f); ret &= al_register_sample_identifier(".mtm", _al_identify_mtm); ret &= al_register_audio_stream_loader(".okt", load_audio_stream); ret &= al_register_audio_stream_loader_f(".okt", load_audio_stream_f); ret &= al_register_sample_identifier(".okt", _al_identify_okt); ret &= al_register_audio_stream_loader(".psm", load_audio_stream); ret &= al_register_audio_stream_loader_f(".psm", load_audio_stream_f); ret &= al_register_sample_identifier(".psm", _al_identify_psm); ret &= al_register_audio_stream_loader(".ptm", load_audio_stream); ret &= al_register_audio_stream_loader_f(".ptm", load_audio_stream_f); ret &= al_register_sample_identifier(".ptm", _al_identify_ptm); ret &= al_register_audio_stream_loader(".s3m", load_audio_stream); ret &= al_register_audio_stream_loader_f(".s3m", load_audio_stream_f); ret &= al_register_sample_identifier(".s3m", _al_identify_s3m); ret &= al_register_audio_stream_loader(".stm", load_audio_stream); ret &= al_register_audio_stream_loader_f(".stm", load_audio_stream_f); ret &= al_register_sample_identifier(".stm", _al_identify_stm); ret &= al_register_audio_stream_loader(".xm", load_audio_stream); ret &= al_register_audio_stream_loader_f(".xm", load_audio_stream_f); ret &= al_register_sample_identifier(".xm", _al_identify_xm); return ret; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/acodec/opus.c000066400000000000000000000270721473414355200173100ustar00rootroot00000000000000/* * Allegro5 Opus reader. * author: Boris Carvajal (c) 2016 * Based on ogg.c code */ #include "allegro5/allegro.h" #include "allegro5/allegro_acodec.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_system.h" #include "acodec.h" #include "helper.h" #ifndef ALLEGRO_CFG_ACODEC_OPUS #error configuration problem, ALLEGRO_CFG_ACODEC_OPUS not set #endif ALLEGRO_DEBUG_CHANNEL("acodec") #include typedef struct AL_OP_DATA AL_OP_DATA; struct AL_OP_DATA { OggOpusFile *of; ALLEGRO_FILE *file; int channels; int bitstream; double loop_start; double loop_end; }; /* dynamic loading support (Windows only currently) */ #ifdef ALLEGRO_CFG_ACODEC_OPUSFILE_DLL static void *op_dll = NULL; static bool op_virgin = true; #endif static struct { void (*op_free)(OggOpusFile *_of); int (*op_channel_count)(const OggOpusFile *_of,int _li); OggOpusFile *(*op_open_callbacks)(void *_source, const OpusFileCallbacks *_cb, const unsigned char *_initial_data, size_t _initial_bytes, int *_error); ogg_int64_t (*op_pcm_total)(const OggOpusFile *_of, int _li); int (*op_pcm_seek)(OggOpusFile *_of, ogg_int64_t _pcm_offset); ogg_int64_t (*op_pcm_tell)(const OggOpusFile *_of); int (*op_read)(OggOpusFile *_of, opus_int16 *_pcm, int _buf_size, int *_li); } lib; #ifdef ALLEGRO_CFG_ACODEC_OPUSFILE_DLL static void shutdown_dynlib(void) { if (op_dll) { _al_close_library(op_dll); op_dll = NULL; op_virgin = true; } } #endif static bool init_dynlib(void) { #ifdef ALLEGRO_CFG_ACODEC_OPUSFILE_DLL if (op_dll) { return true; } if (!op_virgin) { return false; } op_virgin = false; op_dll = _al_open_library(ALLEGRO_CFG_ACODEC_OPUSFILE_DLL); if (!op_dll) { ALLEGRO_WARN("Could not load " ALLEGRO_CFG_ACODEC_OPUSFILE_DLL "\n"); return false; } _al_add_exit_func(shutdown_dynlib, "shutdown_dynlib"); #define INITSYM(x) \ do \ { \ lib.x = _al_import_symbol(op_dll, #x); \ if (lib.x == 0) { \ ALLEGRO_ERROR("undefined symbol in lib structure: " #x "\n"); \ return false; \ } \ } while(0) #else #define INITSYM(x) (lib.x = (x)) #endif memset(&lib, 0, sizeof(lib)); INITSYM(op_free); INITSYM(op_channel_count); INITSYM(op_open_callbacks); INITSYM(op_pcm_total); INITSYM(op_pcm_seek); INITSYM(op_pcm_tell); INITSYM(op_read); return true; #undef INITSYM } static int read_callback(void *stream, unsigned char *ptr, int nbytes) { AL_OP_DATA *op = (AL_OP_DATA *)stream; size_t ret = 0; ret = al_fread(op->file, ptr, nbytes); return ret; } static int seek_callback(void *stream, opus_int64 offset, int whence) { AL_OP_DATA *op = (AL_OP_DATA *)stream; switch(whence) { case SEEK_SET: whence = ALLEGRO_SEEK_SET; break; case SEEK_CUR: whence = ALLEGRO_SEEK_CUR; break; case SEEK_END: whence = ALLEGRO_SEEK_END; break; } if (!al_fseek(op->file, offset, whence)) { return -1; } return 0; } static opus_int64 tell_callback(void *stream) { AL_OP_DATA *op = (AL_OP_DATA *)stream; int64_t ret = 0; ret = al_ftell(op->file); if (ret == -1) return -1; return ret; } static int close_callback(void *stream) { /* Don't close stream->file here. */ (void)stream; return 0; } static OpusFileCallbacks callbacks = { read_callback, seek_callback, tell_callback, close_callback }; ALLEGRO_SAMPLE *_al_load_ogg_opus(const char *filename) { ALLEGRO_FILE *f; ALLEGRO_SAMPLE *spl; ASSERT(filename); ALLEGRO_INFO("Loading sample %s.\n", filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } spl = _al_load_ogg_opus_f(f); al_fclose(f); return spl; } ALLEGRO_SAMPLE *_al_load_ogg_opus_f(ALLEGRO_FILE *file) { /* Note: decoding library can return 16-bit or floating-point output, * both using native endian ordering. (TODO: Implement float output, * individual links in the stream...) */ int word_size = 2; /* 2 = 16-bit. */ const int packet_size = 5760; /* suggestion for size to read at a time */ OggOpusFile *of; opus_int16 *buffer; ALLEGRO_SAMPLE *sample; int channels; long rate; ogg_int64_t total_samples; int bitstream; ogg_int64_t total_size; AL_OP_DATA op; ogg_int64_t pos; long read; if (!init_dynlib()) { return NULL; } op.file = file; of = lib.op_open_callbacks(&op, &callbacks, NULL, 0, NULL); if (!of) { ALLEGRO_ERROR("Audio file does not appear to be an Ogg bitstream.\n"); return NULL; } bitstream = -1; channels = lib.op_channel_count(of, bitstream); rate = 48000; total_samples = lib.op_pcm_total(of, bitstream); total_size = total_samples * channels * word_size; ALLEGRO_DEBUG("channels %d\n", channels); ALLEGRO_DEBUG("word_size %d\n", word_size); ALLEGRO_DEBUG("rate %ld\n", rate); ALLEGRO_DEBUG("total_samples %ld\n", (long)total_samples); ALLEGRO_DEBUG("total_size %ld\n", (long)total_size); buffer = al_malloc(total_size); if (!buffer) { return NULL; } pos = 0; while (pos < total_samples) { const int read_size = _ALLEGRO_MIN(packet_size, total_samples - pos); ASSERT(pos + read_size <= total_samples); /* XXX error handling */ read = lib.op_read(of, buffer + pos * channels, read_size, NULL); pos += read; if (read == 0) break; } lib.op_free(of); sample = al_create_sample(buffer, total_samples, rate, _al_word_size_to_depth_conf(word_size), _al_count_to_channel_conf(channels), true); if (!sample) { al_free(buffer); } return sample; } static bool ogg_stream_seek(ALLEGRO_AUDIO_STREAM *stream, double time) { AL_OP_DATA *extra = (AL_OP_DATA *) stream->extra; if (time >= extra->loop_end) return false; return !lib.op_pcm_seek(extra->of, time * 48000);; } static bool ogg_stream_rewind(ALLEGRO_AUDIO_STREAM *stream) { AL_OP_DATA *extra = (AL_OP_DATA *) stream->extra; return ogg_stream_seek(stream, extra->loop_start); } static double ogg_stream_get_position(ALLEGRO_AUDIO_STREAM *stream) { AL_OP_DATA *extra = (AL_OP_DATA *) stream->extra; return lib.op_pcm_tell(extra->of)/48000.0; } static double ogg_stream_get_length(ALLEGRO_AUDIO_STREAM *stream) { AL_OP_DATA *extra = (AL_OP_DATA *) stream->extra; return lib.op_pcm_total(extra->of, -1)/48000.0; } static bool ogg_stream_set_loop(ALLEGRO_AUDIO_STREAM *stream, double start, double end) { AL_OP_DATA *extra = (AL_OP_DATA *) stream->extra; extra->loop_start = start; extra->loop_end = end; return true; } /* To be called when stream is destroyed */ static void ogg_stream_close(ALLEGRO_AUDIO_STREAM *stream) { AL_OP_DATA *extra = (AL_OP_DATA *) stream->extra; _al_acodec_stop_feed_thread(stream); al_fclose(extra->file); lib.op_free(extra->of); al_free(extra); stream->extra = NULL; } static size_t ogg_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data, size_t buf_size) { AL_OP_DATA *extra = (AL_OP_DATA *) stream->extra; const int word_size = 2; /* 2 = 16-bit. opus_int16 size, for use in op_read */ unsigned long pos = 0; int read_length = buf_size; int buf_in_word; long rate = 48000; int channels = extra->channels; double ctime = lib.op_pcm_tell(extra->of)/(double)rate; double btime = ((double)buf_size / (word_size * channels)) / rate; long read; if (stream->spl.loop != _ALLEGRO_PLAYMODE_STREAM_ONCE && ctime + btime > extra->loop_end) { read_length = (extra->loop_end - ctime) * rate * word_size * channels; if (read_length < 0) return 0; read_length += read_length % word_size; } buf_in_word= read_length/word_size; while (pos < (unsigned long) read_length) { read = lib.op_read(extra->of, (opus_int16 *)data + pos, buf_in_word - pos, NULL); pos += read * channels; if (read == 0) { /* Return the number of useful bytes written. */ return pos*word_size; } } return pos; } ALLEGRO_AUDIO_STREAM *_al_load_ogg_opus_audio_stream(const char *filename, size_t buffer_count, unsigned int samples) { ALLEGRO_FILE *f; ALLEGRO_AUDIO_STREAM *stream; ASSERT(filename); ALLEGRO_INFO("Loading stream %s.\n", filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } stream = _al_load_ogg_opus_audio_stream_f(f, buffer_count, samples); if (!stream) { al_fclose(f); } return stream; } ALLEGRO_AUDIO_STREAM *_al_load_ogg_opus_audio_stream_f(ALLEGRO_FILE *file, size_t buffer_count, unsigned int samples) { const int word_size = 2; /* 1 = 8bit, 2 = 16-bit. nothing else */ OggOpusFile* of; int channels; long rate; long total_samples; long total_size; int bitstream; AL_OP_DATA* extra; ALLEGRO_AUDIO_STREAM* stream; if (!init_dynlib()) { return NULL; } extra = al_malloc(sizeof(AL_OP_DATA)); if (extra == NULL) { ALLEGRO_ERROR("Failed to allocate AL_OP_DATA struct.\n"); return NULL; } extra->file = file; of = lib.op_open_callbacks(extra, &callbacks, NULL, 0, NULL); if (!of) { ALLEGRO_ERROR("ogg: Input does not appear to be an Ogg bitstream.\n"); return NULL; } extra->of = of; extra->bitstream = -1; bitstream = extra->bitstream; extra->channels = lib.op_channel_count(of, bitstream); channels = extra->channels; rate = 48000; total_samples = lib.op_pcm_total(of, bitstream); total_size = total_samples * channels * word_size; ALLEGRO_DEBUG("channels %d\n", channels); ALLEGRO_DEBUG("word_size %d\n", word_size); ALLEGRO_DEBUG("rate %ld\n", rate); ALLEGRO_DEBUG("total_samples %ld\n", total_samples); ALLEGRO_DEBUG("total_size %ld\n", total_size); stream = al_create_audio_stream(buffer_count, samples, rate, _al_word_size_to_depth_conf(word_size), _al_count_to_channel_conf(channels)); if (!stream) { lib.op_free(of); return NULL; } stream->extra = extra; extra->loop_start = 0.0; extra->loop_end = ogg_stream_get_length(stream); stream->quit_feed_thread = false; stream->feeder = ogg_stream_update; stream->rewind_feeder = ogg_stream_rewind; stream->seek_feeder = ogg_stream_seek; stream->get_feeder_position = ogg_stream_get_position; stream->get_feeder_length = ogg_stream_get_length; stream->set_feeder_loop = ogg_stream_set_loop; stream->unload_feeder = ogg_stream_close; _al_acodec_start_feed_thread(stream); return stream; } bool _al_identify_ogg_opus(ALLEGRO_FILE *f) { uint8_t x[10]; if (al_fread(f, x, 4) < 4) return false; if (memcmp(x, "OggS", 4) != 0) return false; if (!al_fseek(f, 22, ALLEGRO_SEEK_CUR)) return false; if (al_fread(f, x, 10) < 10) return false; if (memcmp(x, "\x01\x13OpusHead", 10) == 0) return true; return false; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/acodec/voc.c000066400000000000000000000320761473414355200171110ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Allegro5 Creative Voice Audio Reader. * * Loosely based on A4 voc loader and tightly based on specs of the soundblaster * hardware programming manual: * * also specs are available at * section 11.5 * * List of VOC audio codecs supported: * supported 0x0000 8-bit unsigned PCM * 0x0001 Creative 8-bit to 4-bit ADPCM *HW implemented on the SB * 0x0002 Creative 8-bit to 3-bit ADPCM *HW implemented on the SB * 0x0003 Creative 8-bit to 2-bit ADPCM *HW implemented on the SB * supported 0x0004 16-bit signed PCM * * these are unsupported and present only in VOC files version 1.20 and above * 0x0006 CCITT a-Law * not really used * 0x0007 CCITT u-Law * not really used * 0x0200 Creative 16-bit to 4-bit ADPCM *HW implemented on the SB * * * author: pkrcel (aka Andrea Provasi) * * Revisions: * 2015-01-03 Source derived from previous sndfile implementation * cleaned up and put decoder into voc.c * 2015-01-08 Clean up ISO C90 related warnings and tried to get * a consistent code style and removed some comments. * 2015-01-15 Corrected style and enriched header. */ #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern_audio.h" #include "acodec.h" #include "helper.h" ALLEGRO_DEBUG_CHANNEL("voc") typedef struct AL_VOC_DATA AL_VOC_DATA; struct AL_VOC_DATA { ALLEGRO_FILE *file; size_t datapos; int samplerate; short bits; /* 8 (unsigned char) or 16 (signed short) */ short channels; /* 1 (mono) or 2 (stereo) */ int sample_size; /* channels * bits/8 */ int samples; /* # of samples. size = samples * sample_size */ }; /* * Fills in a VOC data header with information obtained by opening an * caller-provided ALLEGRO_FILE. * The datapos index will be the first data byte of the first data block which * contains ACTUAL data. */ #define READNBYTES(f, data, n, retv) \ do { \ if (al_fread(f, &data, n) != n) { \ ALLEGRO_WARN("voc_open: Bad Number of bytes read in last operation"); \ return retv; \ } \ } while(0) static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) { AL_VOC_DATA *vocdata; char hdrbuf[0x16]; size_t readcount = 0; uint8_t blocktype = 0; uint8_t x = 0; uint16_t timeconstant = 0; uint16_t format = 0; // can be 16-bit in Blocktype 9 (voc version > 1.20 uint16_t vocversion = 0; uint16_t checkver = 0; // must be 1's complement of vocversion + 0x1234 uint32_t blocklength = 0; //length is stored in 3 bites LE, gd byteorder. ASSERT(fp); /* init VOC data */ vocdata = al_malloc(sizeof(AL_VOC_DATA)); memset(vocdata, 0, sizeof(*vocdata)); memset(hdrbuf, 0, sizeof(hdrbuf)); vocdata->file = fp; /* Begin checking the Header info */ readcount = al_fread(fp, hdrbuf, 0x16); if (readcount != 0x16 /*short header*/ || memcmp(hdrbuf, "Creative Voice File\x1A", 0x14) != 0 /*wrong id */ || memcmp(hdrbuf+0x14, "\x1A\x00", 0x2) != 0) { /*wrong offset */ ALLEGRO_ERROR("voc_open: File does not appear to be a valid VOC file"); return NULL; } READNBYTES(fp, vocversion, 2, NULL); if (vocversion != 0x10A && vocversion != 0x114) { // known ver 1.10 -1.20 ALLEGRO_ERROR("voc_open: File is of unknown version"); return NULL; } /* checksum version check */ READNBYTES(fp, checkver, 2, NULL); if (checkver != ~vocversion + 0x1234) { ALLEGRO_ERROR("voc_open: Bad VOC Version Identification Number"); return NULL; } /* * We're at the first datablock, we shall check type and set all the relevant * info in the vocdata structure, including finally the datapos index to the * first valid data byte. */ READNBYTES(fp, blocktype, 1, NULL); READNBYTES(fp, blocklength, 2, NULL); READNBYTES(fp, x, 1, NULL); blocklength += x<<16; switch (blocktype) { case 1: /* blocktype 1 is the most basic header with 1byte format, time * constant and length equal to (datalength + 2). */ blocklength -= 2; READNBYTES(fp, timeconstant, 1, NULL); READNBYTES(fp, format, 1, NULL); vocdata->bits = 8; /* only possible codec for Blocktype 1 */ vocdata->channels = 1; /* block 1 alone means MONO */ vocdata->samplerate = 1000000 / (256 - timeconstant); vocdata->sample_size = 1; /* or better: 1 * 8 / 8 */ /* * Expected number of samples is at LEAST what is in this block. * IIF lentgh 0xFFF there will be a following blocktype 2. * We will deal with this later in load_voc. */ vocdata->samples = blocklength / vocdata->sample_size; vocdata->datapos = al_ftell(fp); break; case 8: /* Blocktype 8 is enhanced data block (mainly for Stereo samples I * guess) that precedes a Blocktype 1, of which the sound infor have * to be ignored. * We skip to the end of the following Blocktype 1 once we get all the * required header info. */ if (blocklength != 4) { ALLEGRO_ERROR("voc_open: Got opening Blocktype 8 of wrong length"); return NULL; } READNBYTES(fp, timeconstant, 2, NULL); READNBYTES(fp, format, 1, NULL); READNBYTES(fp, vocdata->channels, 1, NULL); vocdata->channels += 1; /* was 0 for mono, 1 for stereo */ vocdata->bits = 8; /* only possible codec for Blocktype 8 */ vocdata->samplerate = 1000000 / (256 - timeconstant); vocdata->samplerate /= vocdata->channels; vocdata->sample_size = vocdata->channels * vocdata->bits / 8; /* * Now following there is a blocktype 1 which tells us the length of * the data block and all other info are discarded. */ READNBYTES(fp, blocktype, 1, NULL); if (blocktype != 1) { ALLEGRO_ERROR("voc_open: Blocktype following type 8 is not 1"); return NULL; } READNBYTES(fp, blocklength, 2, NULL); READNBYTES(fp, x, 1, NULL); blocklength += x<<16; blocklength -= 2; READNBYTES(fp, x, 2, NULL); vocdata->samples = blocklength / vocdata->sample_size; vocdata->datapos = al_ftell(fp); break; case 9: /* * Blocktype 9 is available only for VOC version 1.20 and above. * Deals with 16-bit codecs and stereo and is richier than blocktype 1 * or the BLocktype 8+1 combo * Length is 12 bytes more than actual data. */ blocklength -= 12; READNBYTES(fp, vocdata->samplerate, 4, NULL); // actual samplerate READNBYTES(fp, vocdata->bits, 1, NULL); // actual bits // after compression READNBYTES(fp, vocdata->channels, 1, NULL); // actual channels READNBYTES(fp, format, 2, NULL); if ((vocdata->bits != 8 && vocdata->bits != 16) || (format != 0 && format != 4)) { ALLEGRO_ERROR("voc_open: unsupported CODEC in voc data"); return NULL; } READNBYTES(fp, x, 4, NULL); // just skip 4 reserved bytes vocdata->datapos = al_ftell(fp); break; case 2: // case 3: // these cases are just case 4: // ignored in this span case 5: // and wll not return a case 6: // valid VOC data. case 7: // default: ALLEGRO_ERROR("voc_open: opening Block is of unsupported type"); return NULL; break; } return vocdata; } static void voc_close(AL_VOC_DATA *vocdata) { ASSERT(vocdata); al_free(vocdata); } ALLEGRO_SAMPLE *_al_load_voc(const char *filename) { ALLEGRO_FILE *f; ALLEGRO_SAMPLE *spl; ASSERT(filename); ALLEGRO_INFO("Loading VOC sample %s.\n", filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } spl = _al_load_voc_f(f); al_fclose(f); return spl; } ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) { AL_VOC_DATA *vocdata; ALLEGRO_SAMPLE *sample = NULL; size_t pos = 0; /* where to write in the buffer */ size_t read = 0; /*bytes read during last operation */ char* buffer; size_t buffer_size = 0; size_t bytestoread = 0; bool endofvoc = false; /* * Open file and populate VOC DATA, then create a buffer for the number of * samples of the frst block. * Iterate on the following blocks till EOF or terminator block */ vocdata = voc_open(file); if (!vocdata) return NULL; ALLEGRO_DEBUG("channels %d\n", vocdata->channels); ALLEGRO_DEBUG("word_size %d\n", vocdata->sample_size); ALLEGRO_DEBUG("rate %d\n", vocdata->samplerate); ALLEGRO_DEBUG("first_block_samples %d\n", vocdata->samples); ALLEGRO_DEBUG("first_block_size %d\n", vocdata->samples * vocdata->sample_size); /* * Let's allocate at least the first block's bytes; */ buffer_size = (size_t)vocdata->samples * vocdata->sample_size; buffer = al_malloc(buffer_size); if (!buffer) { return NULL; } /* * We now need to iterate over data blocks till either we hit end of file * or we find a terminator block. */ bytestoread = buffer_size; while(!endofvoc && !al_feof(vocdata->file)) { uint32_t blocktype = 0; uint32_t x = 0, len = 0; read = al_fread(vocdata->file, buffer, bytestoread); pos += read; READNBYTES(vocdata->file, blocktype, 1, NULL); // read next block type if (al_feof(vocdata->file)) break; switch (blocktype) { case 0:{ /* we found a terminator block */ endofvoc = true; break; } case 2:{ /*we found a continuation block: unlikely but handled */ x = 0; bytestoread = 0; READNBYTES(vocdata->file, bytestoread, 2, NULL); READNBYTES(vocdata->file, x, 1, NULL); bytestoread += (size_t)x << 16; /* increase subsequently storage */ buffer_size += bytestoread; buffer = al_realloc(buffer, buffer_size); break; } case 1: // we found a NEW data block starter, I assume this is wrong case 8: // and let the so far read sample data correctly in the case 9:{ // already allocated buffer. endofvoc = true; break; } case 3: /* we found a pause block */ case 4: /* we found a marker block */ case 5: /* we found an ASCII c-string block */ case 6: /* we found a repeat block */ case 7:{ /* we found an end repeat block */ /* all these blocks will be skipped */ unsigned int ii; len = 0; x = 0; READNBYTES(vocdata->file, len, 2, NULL); READNBYTES(vocdata->file, x, 1, NULL); len += x<<16; // this is the length what's left to skip */ for (ii = 0; ii < len ; ++ii) { al_fgetc(vocdata->file); } bytestoread = 0; //should let safely check for the next block */ break; } default: break; } } sample = al_create_sample(buffer, pos, vocdata->samplerate, _al_word_size_to_depth_conf(vocdata->sample_size), _al_count_to_channel_conf(vocdata->channels), true); if (!sample) al_free(buffer); voc_close(vocdata); return sample; } /* * So far a stream implementation is not provided, since it is deemed unlikely * that this format will ever be used as such. */ bool _al_identify_voc(ALLEGRO_FILE *f) { uint8_t x[22]; if (al_fread(f, x, 22) < 22) return false; if (memcmp(x, "Creative Voice File\x1A\x1A\x00", 22) == 0) return true; return false; } allegro5-5.2.10.1/addons/acodec/wav.c000066400000000000000000000336031473414355200171140ustar00rootroot00000000000000/* * Allegro5 WAV reader * author: Matthew Leverton */ #include #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern_audio.h" #include "acodec.h" #include "helper.h" ALLEGRO_DEBUG_CHANNEL("wav") typedef struct WAVFILE { ALLEGRO_FILE *f; size_t dpos; /* the starting position of the data chunk */ int freq; /* e.g., 44100 */ short bits; /* 8 (unsigned char) or 16 (signed short) */ short channels; /* 1 (mono) or 2 (stereo) */ int sample_size; /* channels * bits/8 */ int samples; /* # of samples. size = samples * sample_size */ double loop_start; double loop_end; } WAVFILE; /* wav_open: * Opens f and prepares a WAVFILE struct with the WAV format info. * On a successful return, the ALLEGRO_FILE is at the beginning of the sample data. * returns the WAVFILE on success, or NULL on failure. */ static WAVFILE *wav_open(ALLEGRO_FILE *f) { WAVFILE *wavfile = NULL; char buffer[12]; if (!f) goto wav_open_error; /* prepare default values */ wavfile = al_malloc(sizeof(WAVFILE)); if (!wavfile) { ALLEGRO_ERROR("Failed to allocate WAVFILE.\n"); return NULL; } wavfile->f = f; wavfile->freq = 22050; wavfile->bits = 8; wavfile->channels = 1; /* check the header */ if (al_fread(f, buffer, 12) != 12) { ALLEGRO_ERROR("Unexpected EOF while reading the header.\n"); goto wav_open_error; } if (memcmp(buffer, "RIFF", 4) || memcmp(buffer+8, "WAVE", 4)) { ALLEGRO_ERROR("Bad magic number.\n"); goto wav_open_error; } /* Read as many leading fmt chunks as exist, then read until a data chunk * is found. */ while (true) { int length = 0; short pcm = 0; if (al_fread(f, buffer, 4) != 4) { ALLEGRO_ERROR("Unexpected EOF while reading RIFF type.\n"); goto wav_open_error; } /* check to see if it's a fmt chunk */ if (!memcmp(buffer, "fmt ", 4)) { length = al_fread32le(f); if (length < 16) { ALLEGRO_ERROR("Bad length: %d.\n", length); goto wav_open_error; } /* should be 1 for PCM data */ pcm = al_fread16le(f); if (pcm != 1) { ALLEGRO_ERROR("Bad PCM value: %d.\n", pcm); goto wav_open_error; } /* mono or stereo data */ wavfile->channels = al_fread16le(f); if ((wavfile->channels != 1) && (wavfile->channels != 2)) { ALLEGRO_ERROR("Bad number of channels: %d.\n", wavfile->channels); goto wav_open_error; } /* sample frequency */ wavfile->freq = al_fread32le(f); /* skip six bytes */ al_fseek(f, 6, ALLEGRO_SEEK_CUR); /* 8 or 16 bit data? */ wavfile->bits = al_fread16le(f); if ((wavfile->bits != 8) && (wavfile->bits != 16)) { ALLEGRO_ERROR("Bad number of bits: %d.\n", wavfile->bits); goto wav_open_error; } /* Skip remainder of chunk */ length -= 16; if (length > 0) al_fseek(f, length, ALLEGRO_SEEK_CUR); } else { if (!memcmp(buffer, "data", 4)) { ALLEGRO_ERROR("Bad RIFF type.\n"); break; } ALLEGRO_INFO("Ignoring chunk: %c%c%c%c\n", buffer[0], buffer[1], buffer[2], buffer[3]); length = al_fread32le(f); al_fseek(f, length, ALLEGRO_SEEK_CUR); } } /* find out how many samples exist */ wavfile->samples = al_fread32le(f); if (wavfile->channels == 2) { wavfile->samples = (wavfile->samples + 1) / 2; } if (wavfile->bits == 16) { wavfile->samples /= 2; } wavfile->sample_size = wavfile->channels * wavfile->bits / 8; wavfile->dpos = al_ftell(f); return wavfile; wav_open_error: if (wavfile) al_free(wavfile); return NULL; } /* wav_read: * Reads up to 'samples' number of samples from the wav ALLEGRO_FILE into 'data'. * Returns the actual number of samples written to 'data'. */ static size_t wav_read(WAVFILE *wavfile, void *data, size_t samples) { size_t bytes_read; size_t cur_samples; ASSERT(wavfile); cur_samples = (al_ftell(wavfile->f) - wavfile->dpos) / wavfile->sample_size; if (cur_samples + samples > (size_t)wavfile->samples) samples = wavfile->samples - cur_samples; bytes_read = al_fread(wavfile->f, data, samples * wavfile->sample_size); /* PCM data in RIFF WAV files is little endian. * PCM data in RIFX WAV files is big endian (which we don't support). */ #ifdef ALLEGRO_BIG_ENDIAN if (wavfile->bits == 16) { uint16_t *p = data; const uint16_t *const end = p + (bytes_read >> 1); /* swap high/low bytes */ while (p < end) { *p = ((*p << 8) | (*p >> 8)); p++; } } #endif return bytes_read / wavfile->sample_size; } /* wav_close: * Closes the ALLEGRO_FILE and frees the WAVFILE struct. */ static void wav_close(WAVFILE *wavfile) { ASSERT(wavfile); al_free(wavfile); } static bool wav_stream_seek(ALLEGRO_AUDIO_STREAM * stream, double time) { WAVFILE *wavfile = (WAVFILE *) stream->extra; int align = (wavfile->bits / 8) * wavfile->channels; unsigned long cpos = time * (double)(wavfile->freq * (wavfile->bits / 8) * wavfile->channels); if (time >= wavfile->loop_end) return false; cpos += cpos % align; return al_fseek(wavfile->f, wavfile->dpos + cpos, ALLEGRO_SEEK_SET); } /* wav_stream_rewind: * Rewinds 'stream' to the beginning of the data chunk. * Returns true on success, false on failure. */ static bool wav_stream_rewind(ALLEGRO_AUDIO_STREAM *stream) { WAVFILE *wavfile = (WAVFILE *) stream->extra; return wav_stream_seek(stream, wavfile->loop_start); } static double wav_stream_get_position(ALLEGRO_AUDIO_STREAM * stream) { WAVFILE *wavfile = (WAVFILE *) stream->extra; double samples_per = (double)((wavfile->bits / 8) * wavfile->channels) * (double)(wavfile->freq); return ((double)(al_ftell(wavfile->f) - wavfile->dpos) / samples_per); } static double wav_stream_get_length(ALLEGRO_AUDIO_STREAM * stream) { WAVFILE *wavfile = (WAVFILE *) stream->extra; double total_time = (double)(wavfile->samples) / (double)(wavfile->freq); return total_time; } static bool wav_stream_set_loop(ALLEGRO_AUDIO_STREAM * stream, double start, double end) { WAVFILE *wavfile = (WAVFILE *) stream->extra; wavfile->loop_start = start; wavfile->loop_end = end; return true; } /* wav_stream_update: * Updates 'stream' with the next chunk of data. * Returns the actual number of bytes written. */ static size_t wav_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data, size_t buf_size) { int bytes_per_sample, samples, samples_read; double ctime, btime; WAVFILE *wavfile = (WAVFILE *) stream->extra; bytes_per_sample = (wavfile->bits / 8) * wavfile->channels; ctime = wav_stream_get_position(stream); btime = ((double)buf_size / (double)bytes_per_sample) / (double)(wavfile->freq); if (stream->spl.loop != _ALLEGRO_PLAYMODE_STREAM_ONCE && ctime + btime > wavfile->loop_end) { samples = ((wavfile->loop_end - ctime) * (double)(wavfile->freq)); } else { samples = buf_size / bytes_per_sample; } if (samples < 0) return 0; samples_read = wav_read(wavfile, data, samples); return samples_read * bytes_per_sample; } /* wav_stream_close: * Closes the 'stream'. */ static void wav_stream_close(ALLEGRO_AUDIO_STREAM *stream) { WAVFILE *wavfile = (WAVFILE *) stream->extra; _al_acodec_stop_feed_thread(stream); al_fclose(wavfile->f); wav_close(wavfile); stream->extra = NULL; stream->feed_thread = NULL; } /* _al_load_wav: * Reads a RIFF WAV format sample ALLEGRO_FILE, returning an ALLEGRO_SAMPLE * structure, or NULL on error. */ ALLEGRO_SAMPLE *_al_load_wav(const char *filename) { ALLEGRO_FILE *f; ALLEGRO_SAMPLE *spl; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } spl = _al_load_wav_f(f); al_fclose(f); return spl; } ALLEGRO_SAMPLE *_al_load_wav_f(ALLEGRO_FILE *fp) { WAVFILE *wavfile = wav_open(fp); ALLEGRO_SAMPLE *spl = NULL; if (wavfile) { size_t n = (wavfile->bits / 8) * wavfile->channels * wavfile->samples; char *data = al_malloc(n); if (data) { spl = al_create_sample(data, wavfile->samples, wavfile->freq, _al_word_size_to_depth_conf(wavfile->bits / 8), _al_count_to_channel_conf(wavfile->channels), true); if (spl) { memset(data, 0, n); wav_read(wavfile, data, wavfile->samples); } else { al_free(data); } } wav_close(wavfile); } return spl; } /* _al_load_wav_audio_stream: */ ALLEGRO_AUDIO_STREAM *_al_load_wav_audio_stream(const char *filename, size_t buffer_count, unsigned int samples) { ALLEGRO_FILE *f; ALLEGRO_AUDIO_STREAM *stream; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } stream = _al_load_wav_audio_stream_f(f, buffer_count, samples); if (!stream) { ALLEGRO_ERROR("Failed to load wav stream.\n"); al_fclose(f); } return stream; } /* _al_load_wav_audio_stream_f: */ ALLEGRO_AUDIO_STREAM *_al_load_wav_audio_stream_f(ALLEGRO_FILE* f, size_t buffer_count, unsigned int samples) { WAVFILE* wavfile; ALLEGRO_AUDIO_STREAM* stream; wavfile = wav_open(f); if (wavfile == NULL) { ALLEGRO_ERROR("Failed to load wav file.\n"); return NULL; } stream = al_create_audio_stream(buffer_count, samples, wavfile->freq, _al_word_size_to_depth_conf(wavfile->bits / 8), _al_count_to_channel_conf(wavfile->channels)); if (stream) { stream->extra = wavfile; wavfile->loop_start = 0.0; wavfile->loop_end = wav_stream_get_length(stream); stream->feeder = wav_stream_update; stream->unload_feeder = wav_stream_close; stream->rewind_feeder = wav_stream_rewind; stream->seek_feeder = wav_stream_seek; stream->get_feeder_position = wav_stream_get_position; stream->get_feeder_length = wav_stream_get_length; stream->set_feeder_loop = wav_stream_set_loop; _al_acodec_start_feed_thread(stream); } else { ALLEGRO_ERROR("Failed to load wav stream.\n"); wav_close(wavfile); } return stream; } /* _al_save_wav: * Writes a sample into a wav ALLEGRO_FILE. * Returns true on success, false on error. */ bool _al_save_wav(const char *filename, ALLEGRO_SAMPLE *spl) { ALLEGRO_FILE *pf = al_fopen(filename, "wb"); if (pf) { bool rvsave = _al_save_wav_f(pf, spl); bool rvclose = al_fclose(pf); return rvsave && rvclose; } else { ALLEGRO_ERROR("Unable to open %s for writing.\n", filename); } return false; } /* _al_save_wav_f: * Writes a sample into a wav packfile. * Returns true on success, false on error. */ bool _al_save_wav_f(ALLEGRO_FILE *pf, ALLEGRO_SAMPLE *spl) { size_t channels, bits; size_t data_size; size_t samples; size_t i, n; ASSERT(spl); ASSERT(pf); /* XXX: makes use of ALLEGRO_SAMPLE internals */ channels = (spl->chan_conf >> 4) + (spl->chan_conf & 0xF); bits = (spl->depth == ALLEGRO_AUDIO_DEPTH_INT8 || spl->depth == ALLEGRO_AUDIO_DEPTH_UINT8) ? 8 : 16; if (channels < 1 || channels > 2) { ALLEGRO_ERROR("Can only save samples with 1 or 2 channels as WAV.\n"); return false; } samples = spl->len; data_size = samples * channels * bits / 8; n = samples * channels; al_fputs(pf, "RIFF"); al_fwrite32le(pf, 36 + data_size); al_fputs(pf, "WAVE"); al_fputs(pf, "fmt "); al_fwrite32le(pf, 16); al_fwrite16le(pf, 1); al_fwrite16le(pf, (int16_t)channels); al_fwrite32le(pf, spl->frequency); al_fwrite32le(pf, spl->frequency * channels * bits / 8); al_fwrite16le(pf, (int16_t)(channels * bits / 8)); al_fwrite16le(pf, (int16_t)bits); al_fputs(pf, "data"); al_fwrite32le(pf, data_size); if (spl->depth == ALLEGRO_AUDIO_DEPTH_UINT8) { al_fwrite(pf, spl->buffer.u8, samples * channels); } else if (spl->depth == ALLEGRO_AUDIO_DEPTH_INT16) { al_fwrite(pf, spl->buffer.s16, samples * channels * 2); } else if (spl->depth == ALLEGRO_AUDIO_DEPTH_INT8) { int8_t *data = spl->buffer.s8; for (i = 0; i < samples; ++i) { al_fputc(pf, *data++ + 0x80); } } else if (spl->depth == ALLEGRO_AUDIO_DEPTH_UINT16) { uint16_t *data = spl->buffer.u16; for (i = 0; i < n; ++i) { al_fwrite16le(pf, *data++ - 0x8000); } } else if (spl->depth == ALLEGRO_AUDIO_DEPTH_INT24) { int32_t *data = spl->buffer.s24; for (i = 0; i < n; ++i) { const int v = ((float)(*data++ + 0x800000) / 0x7FFFFF) * 0x7FFF - 0x8000; al_fwrite16le(pf, v); } } else if (spl->depth == ALLEGRO_AUDIO_DEPTH_UINT24) { uint32_t *data = spl->buffer.u24; for (i = 0; i < n; ++i) { const int v = ((float)(*data++) / 0x7FFFFF) * 0x7FFF - 0x8000; al_fwrite16le(pf, v); } } else if (spl->depth == ALLEGRO_AUDIO_DEPTH_FLOAT32) { float *data = spl->buffer.f32; for (i = 0; i < n; ++i) { al_fwrite16le(pf, *data * 0x7FFF); data++; } } else { ALLEGRO_ERROR("Unknown audio depth (%d) when saving wav ALLEGRO_FILE.\n", spl->depth); return false; } return true; } bool _al_identify_wav(ALLEGRO_FILE *f) { uint8_t x[4]; if (al_fread(f, x, 4) < 4) return false; if (memcmp(x, "RIFF", 4) != 0) return false; if (!al_fseek(f, 4, ALLEGRO_SEEK_CUR)) return false; if (al_fread(f, x, 4) < 4) return false; if (memcmp(x, "WAVE", 4) == 0) return true; return false; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/000077500000000000000000000000001473414355200160315ustar00rootroot00000000000000allegro5-5.2.10.1/addons/audio/CMakeLists.txt000066400000000000000000000150451473414355200205760ustar00rootroot00000000000000option(WANT_ALSA "Enable ALSA digital audio driver (Unix)" on) option(WANT_OSS "Enable OSS digital audio driver (Unix)" on) option(WANT_PULSEAUDIO "Enable PulseAudio audio driver (Unix)" on) option(WANT_OPENAL "Enable OpenAL digital audio driver" on) option(WANT_OPENSL "Enable OpenSL digital audio driver (Android)" on) option(WANT_DSOUND "Enable DSound digital audio driver (Windows)" on) option(WANT_AQUEUE "Enable AudioQueue digital audio driver (Mac)" on) set(AUDIO_SOURCES audio.c audio_io.c kcm_dtor.c kcm_instance.c kcm_mixer.c kcm_sample.c kcm_stream.c kcm_voice.c recorder.c ) set(AUDIO_INCLUDE_FILES allegro5/allegro_audio.h) set_our_header_properties(${AUDIO_INCLUDE_FILES}) set(AUDIO_CONFIGURATION_SUMMARY "") function(audio_summary msg yesno) if(${yesno}) set(yesno "yes") else() # No's are more important, so shout them. set(yesno "NO") endif() set(AUDIO_CONFIGURATION_SUMMARY "${AUDIO_CONFIGURATION_SUMMARY}${msg}: ${yesno}\n" PARENT_SCOPE) endfunction() # The platform conditions are not really necessary but prevent confusing the # user, e.g. it's pretty weird to get a warning about missing DSound on Unix. if(WANT_OSS AND ALLEGRO_UNIX) include(AllegroFindOSS) if(OSS_FOUND) set(SUPPORT_OSS 1) endif(OSS_FOUND) endif(WANT_OSS AND ALLEGRO_UNIX) if(SUPPORT_OSS) set(ALLEGRO_CFG_KCM_OSS 1) list(APPEND AUDIO_SOURCES oss.c) set(SUPPORT_AUDIO 1) endif(SUPPORT_OSS) if(ALLEGRO_UNIX) audio_summary(" - OSS" SUPPORT_OSS) endif() if(WANT_PULSEAUDIO AND ALLEGRO_UNIX) pkg_check_modules(PULSEAUDIO libpulse-simple) if(PULSEAUDIO_FOUND) set(CMAKE_REQUIRED_INCLUDES ${PULSEAUDIO_INCLUDE_DIRS}) run_c_compile_test(" #include #include #include #include int main(void) { /* Require pulseaudio 0.9.15 */ pa_context *c; pa_sink_info *si; pa_sink_state_t *ss; return 0; }" PULSEAUDIO_COMPILES) set(CMAKE_REQUIRED_INCLUDES) set(SUPPORT_PULSEAUDIO ${PULSEAUDIO_COMPILES}) if(NOT SUPPORT_PULSEAUDIO) message("WARNING: PulseAudio compile test failed, disabling support") endif() endif(PULSEAUDIO_FOUND) endif(WANT_PULSEAUDIO AND ALLEGRO_UNIX) if(SUPPORT_PULSEAUDIO) set(ALLEGRO_CFG_KCM_PULSEAUDIO 1) list(APPEND AUDIO_SOURCES pulseaudio.c) list(APPEND AUDIO_LIBRARIES ${PULSEAUDIO_LIBRARIES}) list(APPEND AUDIO_INCLUDE_DIRECTORIES ${PULSEAUDIO_INCLUDE_DIRS}) list(APPEND AUDIO_LINK_DIRECTORIES ${PULSEAUDIO_LIBRARY_DIRS}) set(SUPPORT_AUDIO 1) endif(SUPPORT_PULSEAUDIO) if(ALLEGRO_UNIX) audio_summary(" - PulseAudio" SUPPORT_PULSEAUDIO) endif() if(WANT_ALSA AND ALLEGRO_UNIX) pkg_check_modules(ALSA alsa) if(ALSA_FOUND) set(SUPPORT_ALSA 1) endif(ALSA_FOUND) endif(WANT_ALSA AND ALLEGRO_UNIX) if(SUPPORT_ALSA) set(ALLEGRO_CFG_KCM_ALSA 1) list(APPEND AUDIO_SOURCES alsa.c) list(APPEND AUDIO_LIBRARIES ${ALSA_LIBRARIES}) list(APPEND AUDIO_INCLUDE_DIRECTORIES ${ALSA_INCLUDE_DIRS}) set(SUPPORT_AUDIO 1) endif(SUPPORT_ALSA) if(ALLEGRO_UNIX) audio_summary(" - ALSA" SUPPORT_ALSA) endif() if(WANT_DSOUND AND WIN32) find_package(DirectX) if(DSOUND_FOUND) set(SUPPORT_DSOUND 1) endif(DSOUND_FOUND) endif(WANT_DSOUND AND WIN32) if(SUPPORT_DSOUND) set(ALLEGRO_CFG_KCM_DSOUND 1) list(APPEND AUDIO_SOURCES dsound.cpp) list(APPEND AUDIO_LIBRARIES ${DSOUND_LIBRARIES}) list(APPEND AUDIO_INCLUDE_DIRECTORIES ${DSOUND_INCLUDE_DIR}) set(SUPPORT_AUDIO 1) endif(SUPPORT_DSOUND) if(WIN32) audio_summary(" - DirectSound" SUPPORT_DSOUND) endif() if(WANT_AQUEUE AND MACOSX) # Should check the presence just to be sure. find_library(AUDIO_TOOLBOX_LIB NAMES AudioToolbox) if(AUDIO_TOOLBOX_LIB) find_path(AQUEUE_INCLUDE_DIR AudioToolbox/AudioQueue.h) if(AQUEUE_INCLUDE_DIR) set(SUPPORT_AQUEUE 1) endif(AQUEUE_INCLUDE_DIR) endif(AUDIO_TOOLBOX_LIB) if(NOT SUPPORT_AQUEUE) message("WARNING: could not find AudioQueue. (This is normal on OS X 10.4)") endif(NOT SUPPORT_AQUEUE) endif(WANT_AQUEUE AND MACOSX) if(SUPPORT_AQUEUE) set(ALLEGRO_CFG_KCM_AQUEUE 1) list(APPEND AUDIO_SOURCES aqueue.m) list(APPEND AUDIO_LIBRARIES ${AUDIO_TOOLBOX_LIB}) set(SUPPORT_AUDIO 1) endif(SUPPORT_AQUEUE) if(MACOSX) audio_summary(" - AudioQueue" SUPPORT_AQUEUE) endif() if(WANT_OPENAL) find_package(OpenAL) mark_as_advanced(OPENAL_INCLUDE_DIR OPENAL_LIBRARY) if(OPENAL_FOUND) set(SUPPORT_OPENAL 1) endif(OPENAL_FOUND) endif(WANT_OPENAL) if(SUPPORT_OPENAL) set(ALLEGRO_CFG_KCM_OPENAL 1) list(APPEND AUDIO_SOURCES openal.c) list(APPEND AUDIO_LIBRARIES ${OPENAL_LIBRARY}) list(APPEND AUDIO_INCLUDE_DIRECTORIES ${OPENAL_INCLUDE_DIR}) set(SUPPORT_AUDIO 1) endif(SUPPORT_OPENAL) audio_summary(" - OpenAL" SUPPORT_OPENAL) if(WANT_OPENSL) find_package(OpenSL) if(OPENSL_FOUND) set(SUPPORT_OPENSL 1) endif(OPENSL_FOUND) endif(WANT_OPENSL) if(SUPPORT_OPENSL) set(ALLEGRO_CFG_KCM_OPENSL 1) list(APPEND AUDIO_SOURCES opensl.c) list(APPEND AUDIO_LIBRARIES ${OPENSL_LIBRARY}) list(APPEND AUDIO_INCLUDE_DIRECTORIES ${OPENSL_INCLUDE_DIR}) set(SUPPORT_AUDIO 1) endif(SUPPORT_OPENSL) audio_summary(" - OpenSL" SUPPORT_OPENSL) if(ALLEGRO_SDL) set(ALLEGRO_CFG_KCM_SDL 1) list(APPEND AUDIO_SOURCES sdl_audio.c) list(APPEND AUDIO_LIBRARIES ${SDL2_LIBRARIES} ) list(APPEND AUDIO_INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR}) set(SUPPORT_AUDIO 1) endif(ALLEGRO_SDL) configure_file( allegro5/internal/aintern_audio_cfg.h.cmake ${PROJECT_BINARY_DIR}/include/allegro5/internal/aintern_audio_cfg.h ) if(NOT SUPPORT_AUDIO) message("WARNING: allegro_audio wanted but no supported backend found") return() endif(NOT SUPPORT_AUDIO) include_directories(SYSTEM ${AUDIO_INCLUDE_DIRECTORIES}) link_directories(${AUDIO_LINK_DIRECTORIES}) add_our_addon_library(allegro_audio AllegroAudio-${ALLEGRO_SOVERSION} "${AUDIO_SOURCES};${AUDIO_INCLUDE_FILES}" "-DALLEGRO_KCM_AUDIO_SRC" "${ALLEGRO_LINK_WITH};${AUDIO_LIBRARIES}" ) install_our_headers(${AUDIO_INCLUDE_FILES}) add_addon(audio) set(AUDIO_CONFIGURATION_SUMMARY "${AUDIO_CONFIGURATION_SUMMARY}" PARENT_SCOPE) #-----------------------------------------------------------------------------# # vi: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/addons/audio/allegro5/000077500000000000000000000000001473414355200175435ustar00rootroot00000000000000allegro5-5.2.10.1/addons/audio/allegro5/allegro_audio.h000066400000000000000000000504461473414355200225330ustar00rootroot00000000000000/* * Updated for 4.9 api inclusion by Ryan Dickie * Originally done by KC/Milan */ #ifndef __al_included_allegro5_allegro_audio_h #define __al_included_allegro5_allegro_audio_h #ifdef __cplusplus extern "C" { #endif /* Title: Audio types */ #include "allegro5/allegro.h" #if (defined ALLEGRO_MINGW32) || (defined ALLEGRO_MSVC) || (defined ALLEGRO_BCC32) #ifndef ALLEGRO_STATICLINK #ifdef ALLEGRO_KCM_AUDIO_SRC #define _ALLEGRO_KCM_AUDIO_DLL __declspec(dllexport) #else #define _ALLEGRO_KCM_AUDIO_DLL __declspec(dllimport) #endif #else #define _ALLEGRO_KCM_AUDIO_DLL #endif #endif #if defined ALLEGRO_MSVC #define ALLEGRO_KCM_AUDIO_FUNC(type, name, args) _ALLEGRO_KCM_AUDIO_DLL type __cdecl name args #elif defined ALLEGRO_MINGW32 #define ALLEGRO_KCM_AUDIO_FUNC(type, name, args) extern type name args #elif defined ALLEGRO_BCC32 #define ALLEGRO_KCM_AUDIO_FUNC(type, name, args) extern _ALLEGRO_KCM_AUDIO_DLL type name args #else #define ALLEGRO_KCM_AUDIO_FUNC AL_FUNC #endif /* Enum: ALLEGRO_AUDIO_EVENT_TYPE */ enum ALLEGRO_AUDIO_EVENT_TYPE { /* Internal, used to communicate with acodec. */ /* Must be in 512 <= n < 1024 */ _KCM_STREAM_FEEDER_QUIT_EVENT_TYPE = 512, ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT = 513, ALLEGRO_EVENT_AUDIO_STREAM_FINISHED = 514, #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_KCM_AUDIO_SRC) ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT = 515, #endif }; #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_KCM_AUDIO_SRC) /* Type: ALLEGRO_AUDIO_RECORDER_EVENT */ typedef struct ALLEGRO_AUDIO_RECORDER_EVENT ALLEGRO_AUDIO_RECORDER_EVENT; struct ALLEGRO_AUDIO_RECORDER_EVENT { _AL_EVENT_HEADER(struct ALLEGRO_AUDIO_RECORDER) struct ALLEGRO_USER_EVENT_DESCRIPTOR *__internal__descr; void *buffer; unsigned int samples; }; #endif /* Enum: ALLEGRO_AUDIO_DEPTH */ enum ALLEGRO_AUDIO_DEPTH { /* Sample depth and type, and signedness. Mixers only use 32-bit signed * float (-1..+1). The unsigned value is a bit-flag applied to the depth * value. */ ALLEGRO_AUDIO_DEPTH_INT8 = 0x00, ALLEGRO_AUDIO_DEPTH_INT16 = 0x01, ALLEGRO_AUDIO_DEPTH_INT24 = 0x02, ALLEGRO_AUDIO_DEPTH_FLOAT32 = 0x03, ALLEGRO_AUDIO_DEPTH_UNSIGNED = 0x08, /* For convenience */ ALLEGRO_AUDIO_DEPTH_UINT8 = ALLEGRO_AUDIO_DEPTH_INT8 | ALLEGRO_AUDIO_DEPTH_UNSIGNED, ALLEGRO_AUDIO_DEPTH_UINT16 = ALLEGRO_AUDIO_DEPTH_INT16 | ALLEGRO_AUDIO_DEPTH_UNSIGNED, ALLEGRO_AUDIO_DEPTH_UINT24 = ALLEGRO_AUDIO_DEPTH_INT24 | ALLEGRO_AUDIO_DEPTH_UNSIGNED }; /* Enum: ALLEGRO_CHANNEL_CONF */ enum ALLEGRO_CHANNEL_CONF { /* Speaker configuration (mono, stereo, 2.1, 3, etc). With regards to * behavior, most of this code makes no distinction between, say, 4.1 and * 5 speaker setups.. they both have 5 "channels". However, users would * like the distinction, and later when the higher-level stuff is added, * the differences will become more important. (v>>4)+(v&0xF) should yield * the total channel count. */ ALLEGRO_CHANNEL_CONF_1 = 0x10, ALLEGRO_CHANNEL_CONF_2 = 0x20, ALLEGRO_CHANNEL_CONF_3 = 0x30, ALLEGRO_CHANNEL_CONF_4 = 0x40, ALLEGRO_CHANNEL_CONF_5_1 = 0x51, ALLEGRO_CHANNEL_CONF_6_1 = 0x61, ALLEGRO_CHANNEL_CONF_7_1 = 0x71 #define ALLEGRO_MAX_CHANNELS 8 }; /* Enum: ALLEGRO_PLAYMODE */ enum ALLEGRO_PLAYMODE { ALLEGRO_PLAYMODE_ONCE = 0x100, ALLEGRO_PLAYMODE_LOOP = 0x101, ALLEGRO_PLAYMODE_BIDIR = 0x102, _ALLEGRO_PLAYMODE_STREAM_ONCE = 0x103, /* internal */ _ALLEGRO_PLAYMODE_STREAM_ONEDIR = 0x104, /* internal */ ALLEGRO_PLAYMODE_LOOP_ONCE = 0x105, _ALLEGRO_PLAYMODE_STREAM_LOOP_ONCE = 0x106, /* internal */ }; /* Enum: ALLEGRO_MIXER_QUALITY */ enum ALLEGRO_MIXER_QUALITY { ALLEGRO_MIXER_QUALITY_POINT = 0x110, ALLEGRO_MIXER_QUALITY_LINEAR = 0x111, ALLEGRO_MIXER_QUALITY_CUBIC = 0x112 }; /* Enum: ALLEGRO_AUDIO_PAN_NONE */ #define ALLEGRO_AUDIO_PAN_NONE (-1000.0f) /* Type: ALLEGRO_SAMPLE */ typedef struct ALLEGRO_SAMPLE ALLEGRO_SAMPLE; /* Type: ALLEGRO_SAMPLE_ID */ typedef struct ALLEGRO_SAMPLE_ID ALLEGRO_SAMPLE_ID; struct ALLEGRO_SAMPLE_ID { int _index; int _id; }; /* Type: ALLEGRO_SAMPLE_INSTANCE */ typedef struct ALLEGRO_SAMPLE_INSTANCE ALLEGRO_SAMPLE_INSTANCE; /* Type: ALLEGRO_AUDIO_STREAM */ typedef struct ALLEGRO_AUDIO_STREAM ALLEGRO_AUDIO_STREAM; /* Type: ALLEGRO_MIXER */ typedef struct ALLEGRO_MIXER ALLEGRO_MIXER; /* Type: ALLEGRO_VOICE */ typedef struct ALLEGRO_VOICE ALLEGRO_VOICE; /* Type: ALLEGRO_AUDIO_DEVICE */ typedef struct ALLEGRO_AUDIO_DEVICE ALLEGRO_AUDIO_DEVICE; #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_KCM_AUDIO_SRC) /* Type: ALLEGRO_AUDIO_RECORDER */ typedef struct ALLEGRO_AUDIO_RECORDER ALLEGRO_AUDIO_RECORDER; #endif #ifndef __cplusplus typedef enum ALLEGRO_AUDIO_DEPTH ALLEGRO_AUDIO_DEPTH; typedef enum ALLEGRO_CHANNEL_CONF ALLEGRO_CHANNEL_CONF; typedef enum ALLEGRO_PLAYMODE ALLEGRO_PLAYMODE; typedef enum ALLEGRO_MIXER_QUALITY ALLEGRO_MIXER_QUALITY; #endif /* Sample functions */ ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_SAMPLE *, al_create_sample, (void *buf, unsigned int samples, unsigned int freq, ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf, bool free_buf)); ALLEGRO_KCM_AUDIO_FUNC(void, al_destroy_sample, (ALLEGRO_SAMPLE *spl)); /* Sample instance functions */ ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_SAMPLE_INSTANCE*, al_create_sample_instance, ( ALLEGRO_SAMPLE *data)); ALLEGRO_KCM_AUDIO_FUNC(void, al_destroy_sample_instance, ( ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(unsigned int, al_get_sample_frequency, (const ALLEGRO_SAMPLE *spl)); ALLEGRO_KCM_AUDIO_FUNC(unsigned int, al_get_sample_length, (const ALLEGRO_SAMPLE *spl)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_DEPTH, al_get_sample_depth, (const ALLEGRO_SAMPLE *spl)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_CHANNEL_CONF, al_get_sample_channels, (const ALLEGRO_SAMPLE *spl)); ALLEGRO_KCM_AUDIO_FUNC(void *, al_get_sample_data, (const ALLEGRO_SAMPLE *spl)); ALLEGRO_KCM_AUDIO_FUNC(unsigned int, al_get_sample_instance_frequency, (const ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(unsigned int, al_get_sample_instance_length, (const ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(unsigned int, al_get_sample_instance_position, (const ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(float, al_get_sample_instance_speed, (const ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(float, al_get_sample_instance_gain, (const ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(float, al_get_sample_instance_pan, (const ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(float, al_get_sample_instance_time, (const ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_DEPTH, al_get_sample_instance_depth, (const ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_CHANNEL_CONF, al_get_sample_instance_channels, (const ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_PLAYMODE, al_get_sample_instance_playmode, (const ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_get_sample_instance_playing, (const ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_get_sample_instance_attached, (const ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_sample_instance_position, (ALLEGRO_SAMPLE_INSTANCE *spl, unsigned int val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_sample_instance_length, (ALLEGRO_SAMPLE_INSTANCE *spl, unsigned int val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_sample_instance_speed, (ALLEGRO_SAMPLE_INSTANCE *spl, float val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_sample_instance_gain, (ALLEGRO_SAMPLE_INSTANCE *spl, float val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_sample_instance_pan, (ALLEGRO_SAMPLE_INSTANCE *spl, float val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_sample_instance_playmode, (ALLEGRO_SAMPLE_INSTANCE *spl, ALLEGRO_PLAYMODE val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_sample_instance_playing, (ALLEGRO_SAMPLE_INSTANCE *spl, bool val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_detach_sample_instance, (ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_sample, (ALLEGRO_SAMPLE_INSTANCE *spl, ALLEGRO_SAMPLE *data)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_SAMPLE *, al_get_sample, (ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_play_sample_instance, (ALLEGRO_SAMPLE_INSTANCE *spl)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_stop_sample_instance, (ALLEGRO_SAMPLE_INSTANCE *spl)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_KCM_AUDIO_SRC) ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_sample_instance_channel_matrix, (ALLEGRO_SAMPLE_INSTANCE *spl, const float *matrix)); #endif /* Stream functions */ ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_STREAM*, al_create_audio_stream, (size_t buffer_count, unsigned int samples, unsigned int freq, ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf)); ALLEGRO_KCM_AUDIO_FUNC(void, al_destroy_audio_stream, (ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(void, al_drain_audio_stream, (ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(unsigned int, al_get_audio_stream_frequency, (const ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(unsigned int, al_get_audio_stream_length, (const ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(unsigned int, al_get_audio_stream_fragments, (const ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(unsigned int, al_get_available_audio_stream_fragments, (const ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(float, al_get_audio_stream_speed, (const ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(float, al_get_audio_stream_gain, (const ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(float, al_get_audio_stream_pan, (const ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_CHANNEL_CONF, al_get_audio_stream_channels, (const ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_DEPTH, al_get_audio_stream_depth, (const ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_PLAYMODE, al_get_audio_stream_playmode, (const ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_get_audio_stream_playing, (const ALLEGRO_AUDIO_STREAM *spl)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_get_audio_stream_attached, (const ALLEGRO_AUDIO_STREAM *spl)); ALLEGRO_KCM_AUDIO_FUNC(uint64_t, al_get_audio_stream_played_samples, (const ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(void *, al_get_audio_stream_fragment, (const ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_audio_stream_speed, (ALLEGRO_AUDIO_STREAM *stream, float val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_audio_stream_gain, (ALLEGRO_AUDIO_STREAM *stream, float val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_audio_stream_pan, (ALLEGRO_AUDIO_STREAM *stream, float val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_audio_stream_playmode, (ALLEGRO_AUDIO_STREAM *stream, ALLEGRO_PLAYMODE val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_audio_stream_playing, (ALLEGRO_AUDIO_STREAM *stream, bool val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_detach_audio_stream, (ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_audio_stream_fragment, (ALLEGRO_AUDIO_STREAM *stream, void *val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_rewind_audio_stream, (ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_seek_audio_stream_secs, (ALLEGRO_AUDIO_STREAM *stream, double time)); ALLEGRO_KCM_AUDIO_FUNC(double, al_get_audio_stream_position_secs, (ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(double, al_get_audio_stream_length_secs, (ALLEGRO_AUDIO_STREAM *stream)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_audio_stream_loop_secs, (ALLEGRO_AUDIO_STREAM *stream, double start, double end)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_audio_stream_event_source, (ALLEGRO_AUDIO_STREAM *stream)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_KCM_AUDIO_SRC) ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_audio_stream_channel_matrix, (ALLEGRO_AUDIO_STREAM *stream, const float *matrix)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_STREAM *, al_play_audio_stream, (const char *filename)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_STREAM *, al_play_audio_stream_f, (ALLEGRO_FILE *fp, const char *ident)); #endif /* Mixer functions */ ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_MIXER*, al_create_mixer, (unsigned int freq, ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf)); ALLEGRO_KCM_AUDIO_FUNC(void, al_destroy_mixer, (ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_attach_sample_instance_to_mixer, ( ALLEGRO_SAMPLE_INSTANCE *stream, ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_attach_audio_stream_to_mixer, (ALLEGRO_AUDIO_STREAM *stream, ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_attach_mixer_to_mixer, (ALLEGRO_MIXER *stream, ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_mixer_postprocess_callback, ( ALLEGRO_MIXER *mixer, void (*cb)(void *buf, unsigned int samples, void *data), void *data)); ALLEGRO_KCM_AUDIO_FUNC(unsigned int, al_get_mixer_frequency, (const ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_CHANNEL_CONF, al_get_mixer_channels, (const ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_DEPTH, al_get_mixer_depth, (const ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_MIXER_QUALITY, al_get_mixer_quality, (const ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(float, al_get_mixer_gain, (const ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_get_mixer_playing, (const ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_get_mixer_attached, (const ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_mixer_has_attachments, (const ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_mixer_frequency, (ALLEGRO_MIXER *mixer, unsigned int val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_mixer_quality, (ALLEGRO_MIXER *mixer, ALLEGRO_MIXER_QUALITY val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_mixer_gain, (ALLEGRO_MIXER *mixer, float gain)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_mixer_playing, (ALLEGRO_MIXER *mixer, bool val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_detach_mixer, (ALLEGRO_MIXER *mixer)); /* Voice functions */ ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_VOICE*, al_create_voice, (unsigned int freq, ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf)); ALLEGRO_KCM_AUDIO_FUNC(void, al_destroy_voice, (ALLEGRO_VOICE *voice)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_attach_sample_instance_to_voice, ( ALLEGRO_SAMPLE_INSTANCE *stream, ALLEGRO_VOICE *voice)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_attach_audio_stream_to_voice, ( ALLEGRO_AUDIO_STREAM *stream, ALLEGRO_VOICE *voice )); ALLEGRO_KCM_AUDIO_FUNC(bool, al_attach_mixer_to_voice, (ALLEGRO_MIXER *mixer, ALLEGRO_VOICE *voice)); ALLEGRO_KCM_AUDIO_FUNC(void, al_detach_voice, (ALLEGRO_VOICE *voice)); ALLEGRO_KCM_AUDIO_FUNC(unsigned int, al_get_voice_frequency, (const ALLEGRO_VOICE *voice)); ALLEGRO_KCM_AUDIO_FUNC(unsigned int, al_get_voice_position, (const ALLEGRO_VOICE *voice)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_CHANNEL_CONF, al_get_voice_channels, (const ALLEGRO_VOICE *voice)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_DEPTH, al_get_voice_depth, (const ALLEGRO_VOICE *voice)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_get_voice_playing, (const ALLEGRO_VOICE *voice)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_voice_has_attachments, (const ALLEGRO_VOICE* voice)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_voice_position, (ALLEGRO_VOICE *voice, unsigned int val)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_voice_playing, (ALLEGRO_VOICE *voice, bool val)); /* Misc. audio functions */ ALLEGRO_KCM_AUDIO_FUNC(bool, al_install_audio, (void)); ALLEGRO_KCM_AUDIO_FUNC(void, al_uninstall_audio, (void)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_is_audio_installed, (void)); ALLEGRO_KCM_AUDIO_FUNC(uint32_t, al_get_allegro_audio_version, (void)); ALLEGRO_KCM_AUDIO_FUNC(size_t, al_get_channel_count, (ALLEGRO_CHANNEL_CONF conf)); ALLEGRO_KCM_AUDIO_FUNC(size_t, al_get_audio_depth_size, (ALLEGRO_AUDIO_DEPTH conf)); ALLEGRO_KCM_AUDIO_FUNC(void, al_fill_silence, (void *buf, unsigned int samples, ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf)); ALLEGRO_KCM_AUDIO_FUNC(int, al_get_num_audio_output_devices, (void)); ALLEGRO_KCM_AUDIO_FUNC(const ALLEGRO_AUDIO_DEVICE *, al_get_audio_output_device, (int index)); ALLEGRO_KCM_AUDIO_FUNC(const char *, al_get_audio_device_name, (const ALLEGRO_AUDIO_DEVICE * device)); /* Simple audio layer */ ALLEGRO_KCM_AUDIO_FUNC(bool, al_reserve_samples, (int reserve_samples)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_MIXER *, al_get_default_mixer, (void)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_set_default_mixer, (ALLEGRO_MIXER *mixer)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_restore_default_mixer, (void)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_play_sample, (ALLEGRO_SAMPLE *data, float gain, float pan, float speed, ALLEGRO_PLAYMODE loop, ALLEGRO_SAMPLE_ID *ret_id)); ALLEGRO_KCM_AUDIO_FUNC(void, al_stop_sample, (ALLEGRO_SAMPLE_ID *spl_id)); ALLEGRO_KCM_AUDIO_FUNC(void, al_stop_samples, (void)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_VOICE *, al_get_default_voice, (void)); ALLEGRO_KCM_AUDIO_FUNC(void, al_set_default_voice, (ALLEGRO_VOICE *voice)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_KCM_AUDIO_SRC) ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_SAMPLE_INSTANCE*, al_lock_sample_id, (ALLEGRO_SAMPLE_ID *spl_id)); ALLEGRO_KCM_AUDIO_FUNC(void, al_unlock_sample_id, (ALLEGRO_SAMPLE_ID *spl_id)); #endif /* File type handlers */ ALLEGRO_KCM_AUDIO_FUNC(bool, al_register_sample_loader, (const char *ext, ALLEGRO_SAMPLE *(*loader)(const char *filename))); ALLEGRO_KCM_AUDIO_FUNC(bool, al_register_sample_saver, (const char *ext, bool (*saver)(const char *filename, ALLEGRO_SAMPLE *spl))); ALLEGRO_KCM_AUDIO_FUNC(bool, al_register_audio_stream_loader, (const char *ext, ALLEGRO_AUDIO_STREAM *(*stream_loader)(const char *filename, size_t buffer_count, unsigned int samples))); ALLEGRO_KCM_AUDIO_FUNC(bool, al_register_sample_loader_f, (const char *ext, ALLEGRO_SAMPLE *(*loader)(ALLEGRO_FILE *fp))); ALLEGRO_KCM_AUDIO_FUNC(bool, al_register_sample_saver_f, (const char *ext, bool (*saver)(ALLEGRO_FILE *fp, ALLEGRO_SAMPLE *spl))); ALLEGRO_KCM_AUDIO_FUNC(bool, al_register_audio_stream_loader_f, (const char *ext, ALLEGRO_AUDIO_STREAM *(*stream_loader)(ALLEGRO_FILE *fp, size_t buffer_count, unsigned int samples))); ALLEGRO_KCM_AUDIO_FUNC(bool, al_register_sample_identifier, (const char *ext, bool (*identifier)(ALLEGRO_FILE *fp))); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_SAMPLE *, al_load_sample, (const char *filename)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_save_sample, (const char *filename, ALLEGRO_SAMPLE *spl)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_STREAM *, al_load_audio_stream, (const char *filename, size_t buffer_count, unsigned int samples)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_SAMPLE *, al_load_sample_f, (ALLEGRO_FILE* fp, const char *ident)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_save_sample_f, (ALLEGRO_FILE* fp, const char *ident, ALLEGRO_SAMPLE *spl)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_STREAM *, al_load_audio_stream_f, (ALLEGRO_FILE* fp, const char *ident, size_t buffer_count, unsigned int samples)); ALLEGRO_KCM_AUDIO_FUNC(char const *, al_identify_sample_f, (ALLEGRO_FILE *fp)); ALLEGRO_KCM_AUDIO_FUNC(char const *, al_identify_sample, (char const *filename)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_KCM_AUDIO_SRC) /* Recording functions */ ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_RECORDER *, al_create_audio_recorder, (size_t fragment_count, unsigned int samples, unsigned int freq, ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_start_audio_recorder, (ALLEGRO_AUDIO_RECORDER *r)); ALLEGRO_KCM_AUDIO_FUNC(void, al_stop_audio_recorder, (ALLEGRO_AUDIO_RECORDER *r)); ALLEGRO_KCM_AUDIO_FUNC(bool, al_is_audio_recorder_recording, (ALLEGRO_AUDIO_RECORDER *r)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_audio_recorder_event_source, (ALLEGRO_AUDIO_RECORDER *r)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_RECORDER_EVENT *, al_get_audio_recorder_event, (ALLEGRO_EVENT *event)); ALLEGRO_KCM_AUDIO_FUNC(void, al_destroy_audio_recorder, (ALLEGRO_AUDIO_RECORDER *r)); #endif #ifdef __cplusplus } /* End extern "C" */ #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/allegro5/internal/000077500000000000000000000000001473414355200213575ustar00rootroot00000000000000allegro5-5.2.10.1/addons/audio/allegro5/internal/aintern_audio.h000066400000000000000000000335121473414355200243550ustar00rootroot00000000000000/* internal-only header * Updated for 4.9 api inclusion by Ryan Dickie * Originally done by KC/Milan */ #ifndef AINTERN_AUDIO_H #define AINTERN_AUDIO_H #include "allegro5/allegro.h" #include "allegro5/internal/aintern_list.h" #include "allegro5/internal/aintern_vector.h" #include "../allegro_audio.h" struct ALLEGRO_AUDIO_RECORDER { ALLEGRO_EVENT_SOURCE source; ALLEGRO_THREAD *thread; ALLEGRO_MUTEX *mutex; ALLEGRO_COND *cond; /* recording is done in its own thread as implemented by the driver */ ALLEGRO_AUDIO_DEPTH depth; ALLEGRO_CHANNEL_CONF chan_conf; unsigned int frequency; void **fragments; /* the buffers to record into */ unsigned int fragment_count; /* the number of fragments */ unsigned int samples; /* the number of samples returned at every FRAGMENT event */ size_t fragment_size; /* size in bytes of each fragument */ unsigned int sample_size; /* the size in bytes of each sample */ volatile bool is_recording; /* true if the driver should actively be updating the buffer */ void *extra; /* custom data for the driver to use as needed */ }; typedef enum ALLEGRO_AUDIO_DRIVER_ENUM { /* Various driver modes. */ ALLEGRO_AUDIO_DRIVER_AUTODETECT = 0x20000, ALLEGRO_AUDIO_DRIVER_OPENAL = 0x20001, ALLEGRO_AUDIO_DRIVER_ALSA = 0x20002, ALLEGRO_AUDIO_DRIVER_DSOUND = 0x20003, ALLEGRO_AUDIO_DRIVER_OSS = 0x20004, ALLEGRO_AUDIO_DRIVER_AQUEUE = 0x20005, ALLEGRO_AUDIO_DRIVER_PULSEAUDIO = 0x20006, ALLEGRO_AUDIO_DRIVER_OPENSL = 0x20007, ALLEGRO_AUDIO_DRIVER_SDL = 0x20008 } ALLEGRO_AUDIO_DRIVER_ENUM; typedef struct ALLEGRO_AUDIO_DRIVER ALLEGRO_AUDIO_DRIVER; struct ALLEGRO_AUDIO_DRIVER { const char *specifier; int (*open)(void); void (*close)(void); int (*allocate_voice)(ALLEGRO_VOICE*); void (*deallocate_voice)(ALLEGRO_VOICE*); int (*load_voice)(ALLEGRO_VOICE*, const void*); void (*unload_voice)(ALLEGRO_VOICE*); int (*start_voice)(ALLEGRO_VOICE*); int (*stop_voice)(ALLEGRO_VOICE*); bool (*voice_is_playing)(const ALLEGRO_VOICE*); unsigned int (*get_voice_position)(const ALLEGRO_VOICE*); int (*set_voice_position)(ALLEGRO_VOICE*, unsigned int); int (*allocate_recorder)(struct ALLEGRO_AUDIO_RECORDER *); void (*deallocate_recorder)(struct ALLEGRO_AUDIO_RECORDER *); _AL_LIST* (*get_output_devices)(void); }; extern ALLEGRO_AUDIO_DRIVER *_al_kcm_driver; const void *_al_voice_update(ALLEGRO_VOICE *voice, ALLEGRO_MUTEX *mutex, unsigned int *samples); bool _al_kcm_set_voice_playing(ALLEGRO_VOICE *voice, ALLEGRO_MUTEX *mutex, bool val); /* A voice structure that you'd attach a mixer or sample to. Ideally there * would be one ALLEGRO_VOICE per system/hardware voice. */ struct ALLEGRO_VOICE { ALLEGRO_AUDIO_DEPTH depth; ALLEGRO_CHANNEL_CONF chan_conf; unsigned int frequency; size_t buffer_size; size_t num_buffers; /* If non-0, they must be honored by the driver. */ ALLEGRO_SAMPLE_INSTANCE *attached_stream; /* The stream that is attached to the voice, or NULL. * May be an ALLEGRO_SAMPLE_INSTANCE or ALLEGRO_MIXER object. */ bool is_streaming; /* True for voices with an attached mixer. */ ALLEGRO_MUTEX *mutex; ALLEGRO_COND *cond; _AL_LIST_ITEM *dtor_item; ALLEGRO_AUDIO_DRIVER *driver; /* XXX shouldn't there only be one audio driver active * at a time? */ void *extra; /* Extra data for use by the driver. */ }; typedef union { float *f32; uint32_t *u24; int32_t *s24; uint16_t *u16; int16_t *s16; uint8_t *u8; int8_t *s8; void *ptr; } any_buffer_t; struct ALLEGRO_SAMPLE { ALLEGRO_AUDIO_DEPTH depth; ALLEGRO_CHANNEL_CONF chan_conf; unsigned int frequency; int len; any_buffer_t buffer; bool free_buf; /* Whether `buffer' needs to be freed when the sample * is destroyed, or when `buffer' changes. */ _AL_LIST_ITEM *dtor_item; }; /* Read some samples into a mixer buffer. * * source: * The object to read samples from. This may be one of several types. * * *vbuf: (in-out parameter) * Pointer to pointer to destination buffer. * (should confirm what it means to change the pointer on return) * * *samples: (in-out parameter) * On input indicates the maximum number of samples that can fit into *vbuf. * On output indicates the actual number of samples that were read. * * buffer_depth: * The audio depth of the destination buffer. * * dest_maxc: * The number of channels in the destination. */ typedef void (*stream_reader_t)(void *source, void **vbuf, unsigned int *samples, ALLEGRO_AUDIO_DEPTH buffer_depth, size_t dest_maxc); typedef struct { union { ALLEGRO_MIXER *mixer; ALLEGRO_VOICE *voice; void *ptr; } u; bool is_voice; } sample_parent_t; /* The sample struct also serves the base of ALLEGRO_AUDIO_STREAM, ALLEGRO_MIXER. */ struct ALLEGRO_SAMPLE_INSTANCE { /* ALLEGRO_SAMPLE_INSTANCE does not generate any events yet but ALLEGRO_AUDIO_STREAM * does, which can inherit only ALLEGRO_SAMPLE_INSTANCE. */ ALLEGRO_EVENT_SOURCE es; ALLEGRO_SAMPLE spl_data; volatile bool is_playing; /* Is this sample is playing? */ ALLEGRO_PLAYMODE loop; float speed; float gain; float pan; /* When resampling an audio stream there will be fractional sample * positions due to the difference in frequencies. */ int pos; int pos_bresenham_error; int loop_start; int loop_end; int step; int step_denom; /* The numerator and denominator of the step are * stored separately. The actual step is obtained by * dividing step by step_denom */ float *matrix; /* Used to convert from this format to the attached * mixers, if any. Otherwise is NULL. * The gain is premultiplied in. */ bool is_mixer; stream_reader_t spl_read; /* Reads sample data into the provided buffer, using * the specified format, converting as necessary. */ ALLEGRO_MUTEX *mutex; /* Points to the parent object's mutex. It is NULL if * the sample is not directly or indirectly attached * to a voice. */ sample_parent_t parent; /* The object that this sample is attached to, if any. */ _AL_LIST_ITEM *dtor_item; }; void _al_kcm_destroy_sample(ALLEGRO_SAMPLE_INSTANCE *sample, bool unregister); void _al_kcm_stream_set_mutex(ALLEGRO_SAMPLE_INSTANCE *stream, ALLEGRO_MUTEX *mutex); void _al_kcm_detach_from_parent(ALLEGRO_SAMPLE_INSTANCE *spl); typedef size_t (*stream_callback_t)(ALLEGRO_AUDIO_STREAM *, void *, size_t); typedef void (*unload_feeder_t)(ALLEGRO_AUDIO_STREAM *); typedef bool (*rewind_feeder_t)(ALLEGRO_AUDIO_STREAM *); typedef bool (*seek_feeder_t)(ALLEGRO_AUDIO_STREAM *, double); typedef double (*get_feeder_position_t)(ALLEGRO_AUDIO_STREAM *); typedef double (*get_feeder_length_t)(ALLEGRO_AUDIO_STREAM *); typedef bool (*set_feeder_loop_t)(ALLEGRO_AUDIO_STREAM *, double, double); struct ALLEGRO_AUDIO_STREAM { ALLEGRO_SAMPLE_INSTANCE spl; /* ALLEGRO_AUDIO_STREAM is derived from * ALLEGRO_SAMPLE_INSTANCE. */ unsigned int buf_count; /* The stream buffer is divided into a number of * fragments; this is the number of fragments. */ void *main_buffer; /* Pointer to a single buffer big enough to hold all * the fragments. Each fragment has additional samples * at the start for linear/cubic interpolation. */ void **pending_bufs; void **used_bufs; /* Arrays of offsets into the main_buffer. * The arrays are each 'buf_count' long. * * 'pending_bufs' holds pointers to fragments supplied * by the user which are yet to be handed off to the * audio driver. * * 'used_bufs' holds pointers to fragments which * have been sent to the audio driver and so are * ready to receive new data. */ volatile bool is_draining; /* Set to true if sample data is not going to be passed * to the stream any more. The stream must change its * playing state to false after all buffers have been * played. */ uint64_t consumed_fragments; /* Number of complete fragment buffers consumed since * the stream was started. */ ALLEGRO_THREAD *feed_thread; ALLEGRO_MUTEX *feed_thread_started_mutex; ALLEGRO_COND *feed_thread_started_cond; bool feed_thread_started; volatile bool quit_feed_thread; unload_feeder_t unload_feeder; rewind_feeder_t rewind_feeder; seek_feeder_t seek_feeder; get_feeder_position_t get_feeder_position; get_feeder_length_t get_feeder_length; set_feeder_loop_t set_feeder_loop; stream_callback_t feeder; /* If ALLEGRO_AUDIO_STREAM has been created by * al_load_audio_stream(), the stream will be fed * by a thread using the 'feeder' callback. Such * streams don't need to be fed by the user. */ _AL_LIST_ITEM *dtor_item; void *extra; /* Extra data for use by the flac/vorbis addons. */ }; bool _al_kcm_refill_stream(ALLEGRO_AUDIO_STREAM *stream); typedef void (*postprocess_callback_t)(void *buf, unsigned int samples, void *userdata); /* ALLEGRO_MIXER is derived from ALLEGRO_SAMPLE_INSTANCE. Certain internal functions and * pointers may take either object type, and such things are explicitly noted. * This is never exposed to the user, though. The sample object's read method * will be set to a different function that will call the read method of all * attached streams (which may be a sample, or another mixer). */ struct ALLEGRO_MIXER { ALLEGRO_SAMPLE_INSTANCE ss; /* ALLEGRO_MIXER is derived from ALLEGRO_SAMPLE_INSTANCE. */ ALLEGRO_MIXER_QUALITY quality; postprocess_callback_t postprocess_callback; void *pp_callback_userdata; _AL_VECTOR streams; /* Vector of ALLEGRO_SAMPLE_INSTANCE*. Holds the list of * streams being mixed together. */ _AL_LIST_ITEM *dtor_item; }; extern void _al_kcm_mixer_rejig_sample_matrix(ALLEGRO_MIXER *mixer, ALLEGRO_SAMPLE_INSTANCE *spl); extern void _al_kcm_mixer_read(void *source, void **buf, unsigned int *samples, ALLEGRO_AUDIO_DEPTH buffer_depth, size_t dest_maxc); typedef enum { ALLEGRO_NO_ERROR = 0, ALLEGRO_INVALID_PARAM = 1, ALLEGRO_INVALID_OBJECT = 2, ALLEGRO_GENERIC_ERROR = 255 } AL_ERROR_ENUM; extern void _al_set_error(int error, char* string); struct ALLEGRO_AUDIO_DEVICE { char* name; void* identifier; }; /* Supposedly internal */ ALLEGRO_KCM_AUDIO_FUNC(void*, _al_kcm_feed_stream, (ALLEGRO_THREAD *self, void *vstream)); /* Helper to emit an event that the stream has got a buffer ready to be refilled. */ void _al_kcm_emit_stream_events(ALLEGRO_AUDIO_STREAM *stream); void _al_kcm_init_destructors(void); void _al_kcm_shutdown_destructors(void); _AL_LIST_ITEM *_al_kcm_register_destructor(char const *name, void *object, void (*func)(void*)); void _al_kcm_unregister_destructor(_AL_LIST_ITEM *dtor_item); void _al_kcm_foreach_destructor( void (*callback)(void *object, void (*func)(void *), void *udata), void *userdata); ALLEGRO_KCM_AUDIO_FUNC(void, _al_kcm_shutdown_default_mixer, (void)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_CHANNEL_CONF, _al_count_to_channel_conf, (int num_channels)); ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_DEPTH, _al_word_size_to_depth_conf, (int word_size)); ALLEGRO_KCM_AUDIO_FUNC(void, _al_emit_audio_event, (int event_type)); #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/allegro5/internal/aintern_audio_cfg.h.cmake000066400000000000000000000003731473414355200262520ustar00rootroot00000000000000#cmakedefine ALLEGRO_CFG_KCM_ALSA #cmakedefine ALLEGRO_CFG_KCM_OPENAL #cmakedefine ALLEGRO_CFG_KCM_OPENSL #cmakedefine ALLEGRO_CFG_KCM_DSOUND #cmakedefine ALLEGRO_CFG_KCM_OSS #cmakedefine ALLEGRO_CFG_KCM_PULSEAUDIO #cmakedefine ALLEGRO_CFG_KCM_AQUEUE allegro5-5.2.10.1/addons/audio/alsa.c000066400000000000000000000757501473414355200171330ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * ALSA 1.0 sound driver. * * By Thomas Fjellstrom. * * Extensively modified by Elias Pschernig. * * Rewritten for 4.3 sound API by Milan Mimica, with additional * improvements by Chris Robinson. Updated for 4.9 by Ryan Dickie * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_audio.h" #include #include ALLEGRO_DEBUG_CHANNEL("alsa") #define ALSA_CHECK(a) \ do { \ int err = (a); \ if (err < 0) { \ ALLEGRO_ERROR("%s: %s\n", snd_strerror(err), #a); \ goto Error; \ } \ } while(0) static snd_output_t *snd_output = NULL; static char *default_device = "default"; static char *alsa_device = NULL; static _AL_LIST* output_device_list; // TODO: Setting this to 256 causes (extreme, about than 10 seconds) // lag if the alsa device is really pulseaudio. // // pw: But there are calls later which expect this variable to be set an on // my machine (without PulseAudio) the driver doesn't work properly with // anything lower than 32. #define DEFAULT_PERIOD_SIZE 32 #define MIN_PERIOD_SIZE 1 // This value works well on my RPI3 and Linux machine. #define DEFAULT_BUFFER_SIZE 2048 static unsigned int get_period_size(void) { const char *val = al_get_config_value(al_get_system_config(), "alsa", "buffer_size"); if (val && val[0] != '\0') { int n = atoi(val); if (n < MIN_PERIOD_SIZE) n = MIN_PERIOD_SIZE; return n; } return DEFAULT_PERIOD_SIZE; } static snd_pcm_uframes_t get_buffer_size(void) { const char *val = al_get_config_value(al_get_system_config(), "alsa", "buffer_size2"); if (val && val[0] != '\0') { int n = atoi(val); if (n < 1) n = 1; return n; } return DEFAULT_BUFFER_SIZE; } typedef struct ALSA_VOICE { unsigned int frame_size; /* in bytes */ unsigned int len; /* in frames */ snd_pcm_uframes_t frag_len; /* in frames */ bool reversed; /* true if playing reversed ATM. */ volatile bool stop; volatile bool stopped; struct pollfd *ufds; int ufds_count; ALLEGRO_THREAD *poll_thread; snd_pcm_t *pcm_handle; bool mmapped; } ALSA_VOICE; /* initialized output */ static int alsa_open(void) { alsa_device = default_device; const char *config_device; config_device = al_get_config_value(al_get_system_config(), "alsa", "device"); if (config_device && config_device[0] != '\0') alsa_device = strdup(config_device); ALSA_CHECK(snd_output_stdio_attach(&snd_output, stdout, 0)); /* We need to check if alsa is available in this function. */ snd_pcm_t *test_pcm_handle; int alsa_err = snd_pcm_open(&test_pcm_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if (alsa_err < 0) { ALLEGRO_WARN("ALSA is not available on the system.\n"); return 1; } else { snd_pcm_close(test_pcm_handle); } return 0; /* ALSA check is a macro that 'goto' error*/ Error: ALLEGRO_ERROR("Error initializing alsa!\n"); return 1; } /* The close method should close the device, freeing any resources, and allow other processes to use the device */ static void alsa_close(void) { _al_list_destroy(output_device_list); if (alsa_device != default_device) al_free(alsa_device); alsa_device = NULL; snd_output_close(snd_output); snd_config_update_free_global(); } /* Underrun and suspend recovery */ static int xrun_recovery(snd_pcm_t *handle, int err) { if (err == -EPIPE) { /* under-run */ err = snd_pcm_prepare(handle); if (err < 0) { ALLEGRO_ERROR("Can't recover from underrun, prepare failed: %s\n", snd_strerror(err)); } else { ALLEGRO_DEBUG("Recovered from underrun\n"); } return 0; } else if (err == -ESTRPIPE) { /* suspend */ err = snd_pcm_resume(handle); if (err < 0) { ALLEGRO_ERROR("Can't recover from suspend, resume failed: %s\n", snd_strerror(err)); } else { ALLEGRO_DEBUG("Resumed successfully\n"); } return 0; } else { ALLEGRO_ERROR("Unknown error code: %d\n", err); ASSERT(0); } return err; } /* * Updates the supplied non-streaming voice. * buf - Returns a pointer to the buffer containing sample data. * bytes - The requested size of the sample data buffer. Returns the actual * size of returned the buffer. * Updates 'stop', 'pos' and 'reversed' fields of the supplied voice to the * future position. * If the voice is played backwards, 'buf' will point to the end of the buffer * and 'bytes' is the size that can be read towards the beginning. */ static int alsa_update_nonstream_voice(ALLEGRO_VOICE *voice, void **buf, int *bytes) { ALSA_VOICE *alsa_voice = (ALSA_VOICE*)voice->extra; int bpos = voice->attached_stream->pos * alsa_voice->frame_size; int blen = alsa_voice->len * alsa_voice->frame_size; *buf = (char *)voice->attached_stream->spl_data.buffer.ptr + bpos; if (!alsa_voice->reversed) { if (bpos + *bytes > blen) { *bytes = blen - bpos; if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_ONCE) { alsa_voice->stop = true; voice->attached_stream->pos = 0; } if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_LOOP) { voice->attached_stream->pos = 0; } else if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_BIDIR) { alsa_voice->reversed = true; voice->attached_stream->pos = alsa_voice->len; } return 1; } else voice->attached_stream->pos += *bytes / alsa_voice->frame_size; } else { if (bpos - *bytes < 0) { *bytes = bpos; /* loop will be ALLEGRO_PLAYMODE_BIDIR, other playing modes that play backwards are not currently supported by the API */ /*if (voice->attached_stream->loop != ALLEGRO_PLAYMODE_BIDIR) alsa_voice->stop = true;*/ voice->attached_stream->pos = 0; alsa_voice->reversed = false; return 1; } else voice->attached_stream->pos -= *bytes / alsa_voice->frame_size; } return 0; } /* Returns true if the voice is ready for more data. */ static int alsa_voice_is_ready(ALSA_VOICE *alsa_voice) { unsigned short revents; int err; poll(alsa_voice->ufds, alsa_voice->ufds_count, 0); snd_pcm_poll_descriptors_revents(alsa_voice->pcm_handle, alsa_voice->ufds, alsa_voice->ufds_count, &revents); if (revents & POLLERR) { if (snd_pcm_state(alsa_voice->pcm_handle) == SND_PCM_STATE_XRUN || snd_pcm_state(alsa_voice->pcm_handle) == SND_PCM_STATE_SUSPENDED) { if (snd_pcm_state(alsa_voice->pcm_handle) == SND_PCM_STATE_XRUN) err = -EPIPE; else err = -ESTRPIPE; if (xrun_recovery(alsa_voice->pcm_handle, err) < 0) { ALLEGRO_ERROR("Write error: %s\n", snd_strerror(err)); return -POLLERR; } } else { ALLEGRO_ERROR("Wait for poll failed\n"); return -POLLERR; } } if (revents & POLLOUT) return true; return false; } /* Custom routine which runs in another thread and fills the hardware PCM buffer from the voice buffer. */ static void *alsa_update_mmap(ALLEGRO_THREAD *self, void *arg) { ALLEGRO_VOICE *voice = (ALLEGRO_VOICE*)arg; ALSA_VOICE *alsa_voice = (ALSA_VOICE*)voice->extra; snd_pcm_state_t last_state = -1; snd_pcm_state_t state; snd_pcm_uframes_t frames; const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t offset; char *mmap; snd_pcm_sframes_t commitres; int ret; ALLEGRO_INFO("ALSA update_mmap thread started\n"); while (!al_get_thread_should_stop(self)) { if (alsa_voice->stop && !alsa_voice->stopped) { snd_pcm_drop(alsa_voice->pcm_handle); al_lock_mutex(voice->mutex); alsa_voice->stopped = true; al_signal_cond(voice->cond); al_unlock_mutex(voice->mutex); } if (!alsa_voice->stop && alsa_voice->stopped) { alsa_voice->stopped = false; } if (alsa_voice->stopped) { /* Keep waiting while the voice is supposed to be stopped but present. */ al_lock_mutex(voice->mutex); while (alsa_voice->stop && !al_get_thread_should_stop(self)) { al_wait_cond(voice->cond, voice->mutex); } al_unlock_mutex(voice->mutex); continue; } state = snd_pcm_state(alsa_voice->pcm_handle); if (state != last_state) { ALLEGRO_DEBUG("state changed to: %s\n", snd_pcm_state_name(state)); last_state = state; } if (state == SND_PCM_STATE_SETUP) { int rc = snd_pcm_prepare(alsa_voice->pcm_handle); ALLEGRO_DEBUG("snd_pcm_prepare returned: %d\n", rc); continue; } if (state == SND_PCM_STATE_PREPARED) { int rc = snd_pcm_start(alsa_voice->pcm_handle); ALLEGRO_DEBUG("snd_pcm_start returned: %d\n", rc); } ret = alsa_voice_is_ready(alsa_voice); if (ret < 0) break; if (ret == 0) { al_rest(0.005); /* TODO: Why not use an event or condition variable? */ continue; } snd_pcm_avail_update(alsa_voice->pcm_handle); frames = alsa_voice->frag_len; ret = snd_pcm_mmap_begin(alsa_voice->pcm_handle, &areas, &offset, &frames); if (ret < 0) { if ((ret = xrun_recovery(alsa_voice->pcm_handle, ret)) < 0) { ALLEGRO_ERROR("MMAP begin avail error: %s\n", snd_strerror(ret)); } break; } if (frames == 0) { al_rest(0.005); /* TODO: Why not use an event or condition variable? */ goto commit; } /* mmaped driver's memory. Interleaved channels format. */ mmap = (char *) areas[0].addr + areas[0].first / 8 + offset * areas[0].step / 8; /* Read sample data into the buffer. */ if (!voice->is_streaming && !alsa_voice->stopped) { void *buf; bool reverse = alsa_voice->reversed; int bytes = frames * alsa_voice->frame_size; alsa_update_nonstream_voice(voice, &buf, &bytes); frames = bytes / alsa_voice->frame_size; if (!reverse) { memcpy(mmap, buf, bytes); } else { /* Put a reversed copy in the driver's buffer. */ unsigned int i; int fs = alsa_voice->frame_size; for (i = 1; i <= frames; i++) memcpy(mmap + i * fs, (char *) buf - i * fs, fs); } } else if (voice->is_streaming && !alsa_voice->stopped) { /* This should fit. */ unsigned int iframes = frames; const void *data = _al_voice_update(voice, voice->mutex, &iframes); frames = iframes; if (data == NULL) goto silence; memcpy(mmap, data, frames * alsa_voice->frame_size); } else { silence: /* If stopped just fill with silence. */ al_fill_silence(mmap, frames, voice->depth, voice->chan_conf); } commit: commitres = snd_pcm_mmap_commit(alsa_voice->pcm_handle, offset, frames); if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { if ((ret = xrun_recovery(alsa_voice->pcm_handle, commitres >= 0 ? -EPIPE : commitres)) < 0) { ALLEGRO_ERROR("MMAP commit error: %s\n", snd_strerror(ret)); break; } } } ALLEGRO_INFO("ALSA update_mmap thread stopped\n"); return NULL; } static void *alsa_update_rw(ALLEGRO_THREAD *self, void *arg) { ALLEGRO_VOICE *voice = (ALLEGRO_VOICE*)arg; ALSA_VOICE *alsa_voice = (ALSA_VOICE*)voice->extra; snd_pcm_state_t last_state = -1; snd_pcm_state_t state; snd_pcm_uframes_t frames; snd_pcm_sframes_t err; ALLEGRO_INFO("ALSA update_rw thread started\n"); while (!al_get_thread_should_stop(self)) { if (alsa_voice->stop && !alsa_voice->stopped) { snd_pcm_drop(alsa_voice->pcm_handle); al_lock_mutex(voice->mutex); alsa_voice->stopped = true; al_signal_cond(voice->cond); al_unlock_mutex(voice->mutex); } if (!alsa_voice->stop && alsa_voice->stopped) { alsa_voice->stopped = false; } if (alsa_voice->stopped) { /* Keep waiting while the voice is supposed to be stopped but present. */ al_lock_mutex(voice->mutex); while (alsa_voice->stop && !al_get_thread_should_stop(self)) { al_wait_cond(voice->cond, voice->mutex); } al_unlock_mutex(voice->mutex); continue; } state = snd_pcm_state(alsa_voice->pcm_handle); if (state != last_state) { ALLEGRO_DEBUG("state changed to: %s\n", snd_pcm_state_name(state)); last_state = state; } if (state == SND_PCM_STATE_SETUP) { int rc = snd_pcm_prepare(alsa_voice->pcm_handle); ALLEGRO_DEBUG("snd_pcm_prepare returned: %d\n", rc); continue; } if (state == SND_PCM_STATE_PREPARED) { int rc = snd_pcm_start(alsa_voice->pcm_handle); ALLEGRO_DEBUG("snd_pcm_start returned: %d\n", rc); } snd_pcm_wait(alsa_voice->pcm_handle, 10); err = snd_pcm_avail_update(alsa_voice->pcm_handle); if (err < 0) { if (err == -EPIPE) { snd_pcm_prepare(alsa_voice->pcm_handle); } else { ALLEGRO_WARN("Alsa r/w thread exited " "with error code %s.\n", snd_strerror(-err)); break; } } if (err == 0) { continue; } frames = err; if (frames > alsa_voice->frag_len) frames = alsa_voice->frag_len; /* Write sample data into the buffer. */ int bytes = frames * alsa_voice->frame_size; uint8_t data[bytes]; void *buf; if (!voice->is_streaming && !alsa_voice->stopped) { ASSERT(!alsa_voice->reversed); // FIXME alsa_update_nonstream_voice(voice, &buf, &bytes); frames = bytes / alsa_voice->frame_size; } else if (voice->is_streaming && !alsa_voice->stopped) { /* This should fit. */ unsigned int iframes = frames; buf = (void *)_al_voice_update(voice, voice->mutex, &iframes); if (buf == NULL) goto silence; frames = iframes; } else { silence: /* If stopped just fill with silence. */ al_fill_silence(data, frames, voice->depth, voice->chan_conf); buf = data; } err = snd_pcm_writei(alsa_voice->pcm_handle, buf, frames); if (err < 0) { if (err == -EPIPE) { snd_pcm_prepare(alsa_voice->pcm_handle); } } } ALLEGRO_INFO("ALSA update_rw thread stopped\n"); return NULL; } /* The load_voice method loads a sample into the driver's memory. The voice's 'streaming' field will be set to false for these voices, and it's 'buffer_size' field will be the total length in bytes of the sample data. The voice's attached stream's looping mode should be honored, and loading must fail if it cannot be. */ static int alsa_load_voice(ALLEGRO_VOICE *voice, const void *data) { ALSA_VOICE *ex_data = voice->extra; voice->attached_stream->pos = 0; ex_data->len = voice->attached_stream->spl_data.len; return 0; (void)data; } /* The unload_voice method unloads a sample previously loaded with load_voice. This method should not be called on a streaming voice. */ static void alsa_unload_voice(ALLEGRO_VOICE *voice) { (void)voice; } /* The start_voice should, surprise, start the voice. For streaming voices, it should start polling the device and call _al_voice_update for audio data. For non-streaming voices, it should resume playing from the last set position */ static int alsa_start_voice(ALLEGRO_VOICE *voice) { ALSA_VOICE *ex_data = voice->extra; /* We already hold voice->mutex. */ ex_data->stop = false; al_signal_cond(voice->cond); return 0; } /* The stop_voice method should stop playback. For non-streaming voices, it should leave the data loaded, and reset the voice position to 0. */ static int alsa_stop_voice(ALLEGRO_VOICE *voice) { ALSA_VOICE *ex_data = voice->extra; /* We already hold voice->mutex. */ ex_data->stop = true; al_signal_cond(voice->cond); if (!voice->is_streaming) { voice->attached_stream->pos = 0; } while (!ex_data->stopped) { al_wait_cond(voice->cond, voice->mutex); } return 0; } /* The voice_is_playing method should only be called on non-streaming sources, and should return true if the voice is playing */ static bool alsa_voice_is_playing(const ALLEGRO_VOICE *voice) { ALSA_VOICE *ex_data = voice->extra; return !ex_data->stopped; } /* The allocate_voice method should grab a voice from the system, and allocate any data common to streaming and non-streaming sources. */ static int alsa_allocate_voice(ALLEGRO_VOICE *voice) { snd_pcm_format_t format; int chan_count; unsigned int req_freq; ALSA_VOICE *ex_data = al_calloc(1, sizeof(ALSA_VOICE)); if (!ex_data) return 1; chan_count = al_get_channel_count(voice->chan_conf); ex_data->frame_size = chan_count * al_get_audio_depth_size(voice->depth); if (!ex_data->frame_size) goto Error; ex_data->stop = true; ex_data->stopped = true; ex_data->reversed = false; ex_data->frag_len = get_period_size(); if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT8) format = SND_PCM_FORMAT_S8; else if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT8) format = SND_PCM_FORMAT_U8; else if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT16) format = SND_PCM_FORMAT_S16; else if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT16) format = SND_PCM_FORMAT_U16; else if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT24) format = SND_PCM_FORMAT_S24; else if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT24) format = SND_PCM_FORMAT_U24; else if (voice->depth == ALLEGRO_AUDIO_DEPTH_FLOAT32) format = SND_PCM_FORMAT_FLOAT; else goto Error; /* Why is this? And what is this? */ if (voice->chan_conf == ALLEGRO_CHANNEL_CONF_3) goto Error; req_freq = voice->frequency; ALSA_CHECK(snd_pcm_open(&ex_data->pcm_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)); snd_pcm_hw_params_t *hwparams; snd_pcm_hw_params_alloca(&hwparams); ALSA_CHECK(snd_pcm_hw_params_any(ex_data->pcm_handle, hwparams)); if (snd_pcm_hw_params_set_access(ex_data->pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) == 0) { ex_data->mmapped = true; } else { ALSA_CHECK(snd_pcm_hw_params_set_access(ex_data->pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)); ex_data->mmapped = false; } ALSA_CHECK(snd_pcm_hw_params_set_format(ex_data->pcm_handle, hwparams, format)); ALSA_CHECK(snd_pcm_hw_params_set_channels(ex_data->pcm_handle, hwparams, chan_count)); ALSA_CHECK(snd_pcm_hw_params_set_rate_near(ex_data->pcm_handle, hwparams, &req_freq, NULL)); ALSA_CHECK(snd_pcm_hw_params_set_period_size_near(ex_data->pcm_handle, hwparams, &ex_data->frag_len, NULL)); snd_pcm_uframes_t buffer_size = get_buffer_size(); ALSA_CHECK(snd_pcm_hw_params_set_buffer_size_near(ex_data->pcm_handle, hwparams, &buffer_size)); ALSA_CHECK(snd_pcm_hw_params(ex_data->pcm_handle, hwparams)); if (voice->frequency != req_freq) { ALLEGRO_ERROR("Unsupported rate! Requested %u, got %iu.\n", voice->frequency, req_freq); goto Error; } snd_pcm_sw_params_t *swparams; snd_pcm_sw_params_alloca(&swparams); ALSA_CHECK(snd_pcm_sw_params_current(ex_data->pcm_handle, swparams)); ALSA_CHECK(snd_pcm_sw_params_set_start_threshold(ex_data->pcm_handle, swparams, ex_data->frag_len)); ALSA_CHECK(snd_pcm_sw_params_set_avail_min(ex_data->pcm_handle, swparams, ex_data->frag_len)); ALSA_CHECK(snd_pcm_sw_params(ex_data->pcm_handle, swparams)); ex_data->ufds_count = snd_pcm_poll_descriptors_count(ex_data->pcm_handle); ex_data->ufds = al_malloc(sizeof(struct pollfd) * ex_data->ufds_count); ALSA_CHECK(snd_pcm_poll_descriptors(ex_data->pcm_handle, ex_data->ufds, ex_data->ufds_count)); voice->extra = ex_data; if (ex_data->mmapped) { ex_data->poll_thread = al_create_thread(alsa_update_mmap, (void*)voice); } else { ALLEGRO_WARN("Falling back to non-mmapped transfer.\n"); snd_pcm_nonblock(ex_data->pcm_handle, 0); ex_data->poll_thread = al_create_thread(alsa_update_rw, (void*)voice); } al_start_thread(ex_data->poll_thread); return 0; Error: if (ex_data->pcm_handle) snd_pcm_close(ex_data->pcm_handle); al_free(ex_data); voice->extra = NULL; return 1; } /* The deallocate_voice method should free the resources for the given voice, but still retain a hold on the device. The voice should be stopped and unloaded by the time this is called */ static void alsa_deallocate_voice(ALLEGRO_VOICE *voice) { ALSA_VOICE *alsa_voice = (ALSA_VOICE*)voice->extra; al_lock_mutex(voice->mutex); al_set_thread_should_stop(alsa_voice->poll_thread); al_broadcast_cond(voice->cond); al_unlock_mutex(voice->mutex); al_join_thread(alsa_voice->poll_thread, NULL); snd_pcm_drop(alsa_voice->pcm_handle); snd_pcm_close(alsa_voice->pcm_handle); al_destroy_thread(alsa_voice->poll_thread); al_free(alsa_voice->ufds); al_free(voice->extra); voice->extra = NULL; } /* The get_voice_position method should return the current sample position of the voice (sample_pos = byte_pos / (depth/8) / channels). This should never be called on a streaming voice. */ static unsigned int alsa_get_voice_position(const ALLEGRO_VOICE *voice) { return voice->attached_stream->pos; } /* The set_voice_position method should set the voice's playback position, given the value in samples. This should never be called on a streaming voice. */ static int alsa_set_voice_position(ALLEGRO_VOICE *voice, unsigned int val) { voice->attached_stream->pos = val; return 0; } typedef struct ALSA_RECORDER_DATA { snd_pcm_t *capture_handle; snd_pcm_hw_params_t *hw_params; } ALSA_RECORDER_DATA; static void *alsa_update_recorder(ALLEGRO_THREAD *t, void *thread_data) { ALLEGRO_AUDIO_RECORDER *r = thread_data; ALSA_RECORDER_DATA *alsa = r->extra; ALLEGRO_EVENT user_event; uint8_t *null_buffer; unsigned int fragment_i = 0; null_buffer = al_malloc(1024 * r->sample_size); if (!null_buffer) { ALLEGRO_ERROR("Unable to create buffer for draining ALSA.\n"); return NULL; } while (!al_get_thread_should_stop(t)) { al_lock_mutex(r->mutex); if (!r->is_recording) { /* Even if not recording, we still want to read from ALSA. Otherwise it will buffer everything and spit it all out whenever the recording resumes. (XXX: Just copied this from PulseAudio. This current implementation is just a bare minimum effort...) */ al_unlock_mutex(r->mutex); snd_pcm_readi(alsa->capture_handle, null_buffer, 1024); } else { ALLEGRO_AUDIO_RECORDER_EVENT *e; snd_pcm_sframes_t count; al_unlock_mutex(r->mutex); if ((count = snd_pcm_readi(alsa->capture_handle, r->fragments[fragment_i], r->samples)) > 0) { user_event.user.type = ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT; e = al_get_audio_recorder_event(&user_event); e->buffer = r->fragments[fragment_i]; e->samples = count; al_emit_user_event(&r->source, &user_event, NULL); if (++fragment_i == r->fragment_count) { fragment_i = 0; } } } } al_free(null_buffer); return NULL; } static int alsa_allocate_recorder(ALLEGRO_AUDIO_RECORDER *r) { ALSA_RECORDER_DATA *data; unsigned int frequency = r->frequency; snd_pcm_format_t format; const char *device = default_device; const char *config_device; config_device = al_get_config_value(al_get_system_config(), "alsa", "capture_device"); if (config_device && config_device[0] != '\0') device = config_device; data = al_calloc(1, sizeof(*data)); if (!data) { goto Error; } if (r->depth == ALLEGRO_AUDIO_DEPTH_INT8) format = SND_PCM_FORMAT_S8; else if (r->depth == ALLEGRO_AUDIO_DEPTH_UINT8) format = SND_PCM_FORMAT_U8; else if (r->depth == ALLEGRO_AUDIO_DEPTH_INT16) format = SND_PCM_FORMAT_S16; else if (r->depth == ALLEGRO_AUDIO_DEPTH_UINT16) format = SND_PCM_FORMAT_U16; else if (r->depth == ALLEGRO_AUDIO_DEPTH_INT24) format = SND_PCM_FORMAT_S24; else if (r->depth == ALLEGRO_AUDIO_DEPTH_UINT24) format = SND_PCM_FORMAT_U24; else if (r->depth == ALLEGRO_AUDIO_DEPTH_FLOAT32) format = SND_PCM_FORMAT_FLOAT; else goto Error; ALSA_CHECK(snd_pcm_open(&data->capture_handle, device, SND_PCM_STREAM_CAPTURE, 0)); ALSA_CHECK(snd_pcm_hw_params_malloc(&data->hw_params)); ALSA_CHECK(snd_pcm_hw_params_any(data->capture_handle, data->hw_params)); ALSA_CHECK(snd_pcm_hw_params_set_access(data->capture_handle, data->hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)); ALSA_CHECK(snd_pcm_hw_params_set_format(data->capture_handle, data->hw_params, format)); ALSA_CHECK(snd_pcm_hw_params_set_rate_near(data->capture_handle, data->hw_params, &frequency, 0)); if (frequency != r->frequency) { ALLEGRO_ERROR("Unsupported rate! Requested %u, got %iu.\n", r->frequency, frequency); goto Error; } ALSA_CHECK(snd_pcm_hw_params_set_channels(data->capture_handle, data->hw_params, al_get_channel_count(r->chan_conf))); ALSA_CHECK(snd_pcm_hw_params(data->capture_handle, data->hw_params)); ALSA_CHECK(snd_pcm_prepare(data->capture_handle)); r->extra = data; r->thread = al_create_thread(alsa_update_recorder, r); return 0; Error: if (data) { if (data->hw_params) { snd_pcm_hw_params_free(data->hw_params); } if (data->capture_handle) { snd_pcm_close(data->capture_handle); } al_free(data); } return 1; } static void alsa_deallocate_recorder(ALLEGRO_AUDIO_RECORDER *r) { ALSA_RECORDER_DATA *data = r->extra; snd_pcm_hw_params_free(data->hw_params); snd_pcm_close(data->capture_handle); } static void _output_device_list_dtor(void* value, void* userdata) { (void)userdata; ALLEGRO_AUDIO_DEVICE* device = (ALLEGRO_AUDIO_DEVICE*)value; al_free(device->name); al_free(device->identifier); al_free(device); } static _AL_LIST* alsa_get_output_devices(void) { int res; if (!output_device_list) { output_device_list = _al_list_create(); int rcard = -1; while(snd_card_next(&rcard) == 0) { if (rcard < 0) { ALLEGRO_WARN("snd_card_next returned a bad card %d.\n", rcard); /* Something is really messed up, so bail out. */ return output_device_list; } snd_ctl_t *handle; char str[64]; snprintf(str, sizeof str, "hw:%i", rcard); res = snd_ctl_open(&handle, str, 0); if (res < 0) { ALLEGRO_WARN("snd_ctl_open on '%s' failed with code %d.\n", str, res); continue; } snd_ctl_card_info_t *card_info; snd_ctl_card_info_alloca(&card_info); res = snd_ctl_card_info(handle, card_info); if (res < 0) { ALLEGRO_WARN("snd_ctl_card_info on '%s' failed with code %d.\n", str, res); continue; } const char* card_name = snd_ctl_card_info_get_name(card_info); int dev_num = -1; while(1) { if (snd_ctl_pcm_next_device(handle, &dev_num) < 0) { break; } if (dev_num < 0) { ALLEGRO_WARN("Invalid device number for card %d.\n", rcard); break; } void **hints; res = snd_device_name_hint(dev_num, "pcm", &hints); if (res < 0) { ALLEGRO_WARN("snd_device_name_hint for card %d, device %d failed with error code %d\n", rcard, dev_num, res); continue; } char**n = (char**)hints; char* identifier = 0; char* name = 0; while(*n != NULL) { identifier = snd_device_name_get_hint(*n, "NAME"); name = snd_device_name_get_hint(*n, "DESC"); char* ioid = snd_device_name_get_hint(*n, "IOID"); if (ioid == NULL || strcmp(ioid, "Output") == 0) { free(ioid); break; } free(ioid); n++; } if (!identifier || !name) { snd_device_name_free_hint(hints); free(identifier); free(name); ALLEGRO_WARN("Could not find identifier/name for card %d, device %d\n", rcard, dev_num); continue; } char* sep_at = strchr(name, '\n'); char* actual_name = sep_at ? sep_at + 1 : name; /* Two string lengths + space + nul terminator. */ int len = strlen(actual_name) + strlen(card_name) + 1 + 1; int identifier_len = strlen(identifier) + 1; ALLEGRO_AUDIO_DEVICE* device = (ALLEGRO_AUDIO_DEVICE*)al_malloc(sizeof(ALLEGRO_AUDIO_DEVICE)); device->identifier = (char*)al_malloc(identifier_len); device->name = (char*)al_malloc(len); snprintf(device->name, len, "%s %s", card_name, actual_name); strcpy(device->identifier, identifier); snd_device_name_free_hint(hints); free(identifier); free(name); _al_list_push_back_ex(output_device_list, device, _output_device_list_dtor); } snd_ctl_close(handle); } } return output_device_list; } ALLEGRO_AUDIO_DRIVER _al_kcm_alsa_driver = { "ALSA", alsa_open, alsa_close, alsa_allocate_voice, alsa_deallocate_voice, alsa_load_voice, alsa_unload_voice, alsa_start_voice, alsa_stop_voice, alsa_voice_is_playing, alsa_get_voice_position, alsa_set_voice_position, alsa_allocate_recorder, alsa_deallocate_recorder, alsa_get_output_devices }; /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/aqueue.m000066400000000000000000000473771473414355200175160ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Apple Audio Queue driver * * By Trent Gamblin. * * See readme.txt for copyright information. */ #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_audio_cfg.h" #include "allegro5/internal/aintern_vector.h" #import #import #ifdef ALLEGRO_IPHONE #import #endif #import #import #define THREAD_BEGIN NSAutoreleasePool *___p = [[NSAutoreleasePool alloc] init]; #define THREAD_END [___p drain]; // Make configurable #define BUFFER_SIZE 1024*2 // in samples #define NUM_BUFFERS 4 ALLEGRO_DEBUG_CHANNEL("AudioQueue") typedef struct ALLEGRO_AQ_DATA { int bits_per_sample; int channels; bool playing; unsigned int buffer_size; unsigned char *silence; ALLEGRO_VOICE *voice; AudioQueueRef queue; AudioQueueBufferRef buffers[NUM_BUFFERS]; } ALLEGRO_AQ_DATA; static _AL_VECTOR saved_voices = _AL_VECTOR_INITIALIZER(ALLEGRO_VOICE*); static _AL_LIST* output_device_list; /* Audio queue callback */ static void handle_buffer( void *in_data, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { ALLEGRO_AQ_DATA *ex_data = in_data; const void *data; (void)inAQ; // unsused unsigned int samples = (ex_data->buffer_size / ex_data->channels) / (ex_data->bits_per_sample / 8); data = _al_voice_update(ex_data->voice, ex_data->voice->mutex, &samples); if (data == NULL) data = ex_data->silence; unsigned int copy_bytes = samples * ex_data->channels * (ex_data->bits_per_sample / 8); copy_bytes = _ALLEGRO_MIN(copy_bytes, inBuffer->mAudioDataBytesCapacity); memcpy(inBuffer->mAudioData, data, copy_bytes); inBuffer->mAudioDataByteSize = copy_bytes; AudioQueueEnqueueBuffer( ex_data->queue, inBuffer, 0, NULL ); } #ifdef ALLEGRO_IPHONE static int _aqueue_start_voice(ALLEGRO_VOICE *voice); static int _aqueue_stop_voice(ALLEGRO_VOICE* voice); static void interruption_callback(void *inClientData, UInt32 inInterruptionState) { unsigned i; (void)inClientData; for (i = 0; i < _al_vector_size(&saved_voices); i++) { ALLEGRO_VOICE **voice = _al_vector_ref(&saved_voices, i); if (inInterruptionState == kAudioSessionBeginInterruption) { _aqueue_stop_voice(*voice); } else { _aqueue_start_voice(*voice); } } } // This allows plugging/unplugging of hardware/bluetooth/speakers etc while keeping the sound playing static void property_listener(void *inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData) { unsigned i; (void)inClientData; (void)inDataSize; if (inID == kAudioSessionProperty_AudioRouteChange) { for (i = 0; i < _al_vector_size(&saved_voices); i++) { ALLEGRO_VOICE **voice = _al_vector_ref(&saved_voices, i); UInt32 reason = (UInt32)inData; if (reason == kAudioSessionRouteChangeReason_NewDeviceAvailable) { _aqueue_stop_voice(*voice); _aqueue_start_voice(*voice); } } } } #endif static bool _aqueue_device_has_scope(AudioObjectID deviceID, AudioObjectPropertyScope scope) { AudioObjectPropertyAddress propertyAddress = { .mSelector = kAudioDevicePropertyStreamConfiguration, .mScope = scope, .mElement = kAudioObjectPropertyElementWildcard }; UInt32 dataSize = 0; if (AudioObjectGetPropertyDataSize(deviceID, &propertyAddress, 0, NULL, &dataSize) != noErr) { return false; } AudioBufferList *bufferList = al_malloc(dataSize); if(bufferList == NULL) { return false; } if (AudioObjectGetPropertyData(deviceID, &propertyAddress, 0, NULL, &dataSize, bufferList) != noErr) { al_free(bufferList); return false; } BOOL supportsScope = bufferList->mNumberBuffers > 0; al_free(bufferList); return supportsScope; } static _AL_LIST* _aqueue_get_output_devices(void) { return output_device_list; } static void _output_device_list_dtor(void* value, void* userdata) { (void)userdata; ALLEGRO_AUDIO_DEVICE* device = (ALLEGRO_AUDIO_DEVICE*)value; al_free(device->name); al_free(device->identifier); al_free(device); } static void _aqueue_list_audio_output_devices(void) { output_device_list = _al_list_create(); AudioObjectPropertyAddress propertyAddress; AudioObjectID *deviceIDs; UInt32 propertySize; NSInteger numDevices; propertyAddress.mSelector = kAudioHardwarePropertyDevices; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; if (AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize) != noErr) { return; } numDevices = propertySize / sizeof(AudioDeviceID); deviceIDs = (AudioDeviceID *)al_calloc(numDevices, sizeof(AudioDeviceID)); if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, deviceIDs) != noErr) { return; } for (NSInteger idx=0; idx= 120000) deviceAddress.mElement = kAudioObjectPropertyElementMain; #else deviceAddress.mElement = kAudioObjectPropertyElementMaster; #endif if (AudioObjectGetPropertyData(deviceIDs[idx], &deviceAddress, 0, NULL, &propertySize, deviceName) != noErr) { continue; } if (_aqueue_device_has_scope(deviceIDs[idx], kAudioObjectPropertyScopeOutput)) { ALLEGRO_AUDIO_DEVICE* device = (ALLEGRO_AUDIO_DEVICE*)al_malloc(sizeof(ALLEGRO_AUDIO_DEVICE)); device->identifier = (void*)al_malloc(sizeof(AudioDeviceID)); device->name = (char*)al_malloc(sizeof(deviceName)); memcpy(device->identifier, &deviceIDs[idx], sizeof(AudioDeviceID)); memcpy(device->name, deviceName, sizeof(deviceName)); _al_list_push_back_ex(output_device_list, device, _output_device_list_dtor); } } al_free(deviceIDs); } /* The open method starts up the driver and should lock the device, using the previously set paramters, or defaults. It shouldn't need to start sending audio data to the device yet, however. */ static int _aqueue_open(void) { #ifdef ALLEGRO_IPHONE /* These settings allow ipod music playback simultaneously with * our Allegro music/sfx, and also do not stop the streams when * a phone call comes in (it's muted for the duration of the call). */ AudioSessionInitialize(NULL, NULL, interruption_callback, NULL); UInt32 sessionCategory = kAudioSessionCategory_AmbientSound; AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory); UInt32 mix = TRUE; AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(mix), &mix); AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, property_listener, NULL); #endif _aqueue_list_audio_output_devices(); return 0; } /* The close method should close the device, freeing any resources, and allow other processes to use the device */ static void _aqueue_close(void) { _al_list_destroy(output_device_list); _al_vector_free(&saved_voices); } /* The allocate_voice method should grab a voice from the system, and allocate any data common to streaming and non-streaming sources. */ static int _aqueue_allocate_voice(ALLEGRO_VOICE *voice) { ALLEGRO_AQ_DATA *ex_data; int bits_per_sample; int channels; switch (voice->depth) { case ALLEGRO_AUDIO_DEPTH_UINT16: case ALLEGRO_AUDIO_DEPTH_INT16: bits_per_sample = 16; break; default: return 1; } switch (voice->chan_conf) { case ALLEGRO_CHANNEL_CONF_1: channels = 1; break; case ALLEGRO_CHANNEL_CONF_2: channels = 2; break; default: fprintf(stderr, "Unsupported number of channels\n"); return 1; } ex_data = (ALLEGRO_AQ_DATA *)al_calloc(1, sizeof(*ex_data)); if (!ex_data) { fprintf(stderr, "Could not allocate voice data memory\n"); return 1; } ex_data->bits_per_sample = bits_per_sample; ex_data->channels = channels; ex_data->buffer_size = BUFFER_SIZE*channels*(bits_per_sample/8); ex_data->playing = false; voice->extra = ex_data; ex_data->voice = voice; ex_data->silence = al_calloc(1, ex_data->buffer_size); return 0; } /* The deallocate_voice method should free the resources for the given voice, but still retain a hold on the device. The voice should be stopped and unloaded by the time this is called */ static void _aqueue_deallocate_voice(ALLEGRO_VOICE *voice) { ALLEGRO_AQ_DATA *ex_data = voice->extra; al_free(ex_data->silence); al_free(ex_data); voice->extra = NULL; } /* The load_voice method loads a sample into the driver's memory. The voice's 'streaming' field will be set to false for these voices, and it's 'buffer_size' field will be the total length in bytes of the sample data. The voice's attached sample's looping mode should be honored, and loading must fail if it cannot be. */ static int _aqueue_load_voice(ALLEGRO_VOICE *voice, const void *data) { /* FIXME */ (void)voice; (void)data; return 1; } /* The unload_voice method unloads a sample previously loaded with load_voice. This method should not be called on a streaming voice. */ static void _aqueue_unload_voice(ALLEGRO_VOICE *voice) { /* FIXME */ (void)voice; } static void *stream_proc(void *in_data) { THREAD_BEGIN ALLEGRO_VOICE *voice = in_data; ALLEGRO_AQ_DATA *ex_data = voice->extra; AudioStreamBasicDescription desc; desc.mSampleRate = voice->frequency; desc.mFormatID = kAudioFormatLinearPCM; if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT16) desc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; else desc.mFormatFlags = kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsPacked; #ifdef ALLEGRO_BIG_ENDIAN desc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; #endif desc.mBytesPerPacket = ex_data->channels * (ex_data->bits_per_sample/8); desc.mFramesPerPacket = 1; desc.mBytesPerFrame = ex_data->channels * (ex_data->bits_per_sample/8); desc.mChannelsPerFrame = ex_data->channels; desc.mBitsPerChannel = ex_data->bits_per_sample; int ret = AudioQueueNewOutput( &desc, handle_buffer, ex_data, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &ex_data->queue); (void)ret; // FIXME: handle failure? int i; for (i = 0; i < NUM_BUFFERS; ++i) { AudioQueueAllocateBuffer( ex_data->queue, ex_data->buffer_size, &ex_data->buffers[i] ); memcpy(ex_data->buffers[i]->mAudioData, ex_data->silence, ex_data->buffer_size); ex_data->buffers[i]->mAudioDataByteSize = ex_data->buffer_size; ex_data->buffers[i]->mUserData = ex_data; // FIXME: Safe to comment this out? //ex_data->buffers[i]->mPacketDescriptionCount = 0; AudioQueueEnqueueBuffer( ex_data->queue, ex_data->buffers[i], 0, NULL ); } AudioQueueSetParameter( ex_data->queue, kAudioQueueParam_Volume, 1.0f ); ret = AudioQueueStart( ex_data->queue, NULL ); do { THREAD_BEGIN CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.05, false ); THREAD_END } while (ex_data->playing); THREAD_END return NULL; } /* The start_voice should, surprise, start the voice. For streaming voices, it should start polling the device and call _al_voice_update for audio data. For non-streaming voices, it should resume playing from the last set position */ static int _aqueue_start_voice(ALLEGRO_VOICE *voice) { ALLEGRO_AQ_DATA *ex_data = voice->extra; if (voice->is_streaming && !ex_data->playing) { *(ALLEGRO_VOICE**)_al_vector_alloc_back(&saved_voices) = voice; ex_data->playing = true; al_run_detached_thread(stream_proc, voice); return 0; } /* FIXME */ return 1; } /* The stop_voice method should stop playback. For non-streaming voices, it should leave the data loaded, and reset the voice position to 0. */ static int _aqueue_stop_voice(ALLEGRO_VOICE* voice) { ALLEGRO_AQ_DATA *ex_data = voice->extra; if (ex_data->playing) { _al_vector_find_and_delete(&saved_voices, &voice); ex_data->playing = false; AudioQueueDispose( ex_data->queue, false /* Do it asynchronously so the feeder thread can exit. */ ); } return 0; } /* The voice_is_playing method should only be called on non-streaming sources, and should return true if the voice is playing */ static bool _aqueue_voice_is_playing(const ALLEGRO_VOICE *voice) { ALLEGRO_AQ_DATA *ex_data = (ALLEGRO_AQ_DATA *)voice->extra; return ex_data->playing; } /* The get_voice_position method should return the current sample position of the voice (sample_pos = byte_pos / (depth/8) / channels). This should never be called on a streaming voice. */ static unsigned int _aqueue_get_voice_position(const ALLEGRO_VOICE *voice) { /* FIXME */ (void)voice; return 0; } /* The set_voice_position method should set the voice's playback position, given the value in samples. This should never be called on a streaming voice. */ static int _aqueue_set_voice_position(ALLEGRO_VOICE *voice, unsigned int val) { /* FIXME */ (void)voice; (void)val; return 0; } typedef struct RECORDER_DATA { AudioStreamBasicDescription data_format; AudioQueueRef queue; /* AudioQueue buffer information */ AudioQueueBufferRef *buffers; int buffer_count; uint32_t buffer_size; /* User fragment buffer information. * Which buffer are we writing into, and * how much data has already been written? */ unsigned int fragment_i; unsigned int samples_written; } RECORDER_DATA; static void _aqueue_recording_callback(void *user_data, AudioQueueRef aq, AudioQueueBufferRef aq_buffer, const AudioTimeStamp *start_time, UInt32 sample_count, const AudioStreamPacketDescription *descs) { ALLEGRO_AUDIO_RECORDER *recorder = (ALLEGRO_AUDIO_RECORDER *) user_data; RECORDER_DATA *data = (RECORDER_DATA *) recorder->extra; char *input = aq_buffer->mAudioData; (void) aq; (void) start_time; (void) descs; if (sample_count == 0 && data->data_format.mBytesPerPacket != 0) { sample_count = aq_buffer->mAudioDataByteSize / data->data_format.mBytesPerPacket; } al_lock_mutex(recorder->mutex); if (recorder->is_recording) { /* Process the full buffer, putting it into as many user fragments as it needs. * Send an event for every full user fragment. */ while (sample_count > 0) { unsigned int samples_left = recorder->samples - data->samples_written; unsigned int samples_to_write = sample_count < samples_left ? sample_count : samples_left; /* Copy the incoming data into the user's fragment buffer */ memcpy((char*)recorder->fragments[data->fragment_i] + data->samples_written * recorder->sample_size, input, samples_to_write * recorder->sample_size); input += samples_to_write * recorder->sample_size; data->samples_written += samples_to_write; sample_count -= samples_to_write; /* We should have never written more samples than the user asked for */ ALLEGRO_ASSERT(recorder->samples >= data->samples_written); if (data->samples_written == recorder->samples) { ALLEGRO_EVENT user_event; ALLEGRO_AUDIO_RECORDER_EVENT *e; user_event.user.type = ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT; e = al_get_audio_recorder_event(&user_event); e->buffer = recorder->fragments[data->fragment_i]; e->samples = recorder->samples; al_emit_user_event(&recorder->source, &user_event, NULL); if (++data->fragment_i == recorder->fragment_count) { data->fragment_i = 0; } data->samples_written = 0; } } } al_unlock_mutex(recorder->mutex); AudioQueueEnqueueBuffer(data->queue, aq_buffer, 0, NULL); } static int _aqueue_allocate_recorder(ALLEGRO_AUDIO_RECORDER *recorder) { RECORDER_DATA *data; int i; int ret; data = al_calloc(1, sizeof(*data)); if (!data) return 1; data->buffer_count = 3; data->buffers = al_calloc(data->buffer_count, sizeof(AudioQueueBufferRef)); if (!data->buffers) { al_free(data); return 1; } data->data_format.mFormatID = kAudioFormatLinearPCM; data->data_format.mSampleRate = recorder->frequency; data->data_format.mChannelsPerFrame = al_get_channel_count(recorder->chan_conf); data->data_format.mFramesPerPacket = 1; data->data_format.mBitsPerChannel = al_get_audio_depth_size(recorder->depth) * 8; data->data_format.mBytesPerFrame = data->data_format.mBytesPerPacket = data->data_format.mChannelsPerFrame * al_get_audio_depth_size(recorder->depth); data->data_format.mFormatFlags = kLinearPCMFormatFlagIsPacked; #ifdef ALLEGRO_BIG_ENDIAN data->data_format.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; #endif if (recorder->depth == ALLEGRO_AUDIO_DEPTH_FLOAT32) data->data_format.mFormatFlags |= kLinearPCMFormatFlagIsFloat; else if (!(recorder->depth & ALLEGRO_AUDIO_DEPTH_UNSIGNED)) data->data_format.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; data->buffer_size = 2048; // in bytes ret = AudioQueueNewInput( &data->data_format, _aqueue_recording_callback, recorder, NULL, kCFRunLoopCommonModes, 0, &data->queue ); if (ret) { ALLEGRO_ERROR("AudioQueueNewInput failed (%d)\n", ret); al_free(data->buffers); al_free(data); return 1; } /* Create the buffers */ for (i = 0; i < data->buffer_count; ++i) { AudioQueueAllocateBuffer(data->queue, data->buffer_size, &data->buffers[i]); AudioQueueEnqueueBuffer(data->queue, data->buffers[i], 0, NULL); } AudioQueueStart(data->queue, NULL); recorder->extra = data; /* No thread is created. */ return 0; } static void _aqueue_deallocate_recorder(ALLEGRO_AUDIO_RECORDER *recorder) { RECORDER_DATA *data = (RECORDER_DATA *) recorder->extra; AudioQueueStop(data->queue, true); AudioQueueDispose(data->queue, true); al_free(data->buffers); al_free(data); } ALLEGRO_AUDIO_DRIVER _al_kcm_aqueue_driver = { "Apple Audio Queues", _aqueue_open, _aqueue_close, _aqueue_allocate_voice, _aqueue_deallocate_voice, _aqueue_load_voice, _aqueue_unload_voice, _aqueue_start_voice, _aqueue_stop_voice, _aqueue_voice_is_playing, _aqueue_get_voice_position, _aqueue_set_voice_position, _aqueue_allocate_recorder, _aqueue_deallocate_recorder, _aqueue_get_output_devices, }; allegro5-5.2.10.1/addons/audio/audio.c000066400000000000000000000314351473414355200173040ustar00rootroot00000000000000/** * Originally digi.c from allegro wiki * Original authors: KC/Milan * * Converted to allegro5 by Ryan Dickie */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_audio_cfg.h" ALLEGRO_DEBUG_CHANNEL("audio") void _al_set_error(int error, char* string) { ALLEGRO_ERROR("%s (error code: %d)\n", string, error); } ALLEGRO_AUDIO_DRIVER *_al_kcm_driver = NULL; #if defined(ALLEGRO_CFG_KCM_OPENAL) extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_openal_driver; #endif #if defined(ALLEGRO_CFG_KCM_OPENSL) extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_opensl_driver; #endif #if defined(ALLEGRO_CFG_KCM_ALSA) extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_alsa_driver; #endif #if defined(ALLEGRO_CFG_KCM_OSS) extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_oss_driver; #endif #if defined(ALLEGRO_CFG_KCM_DSOUND) extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_dsound_driver; #endif #if defined(ALLEGRO_CFG_KCM_AQUEUE) extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_aqueue_driver; #endif #if defined(ALLEGRO_CFG_KCM_PULSEAUDIO) extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_pulseaudio_driver; #endif #if defined(ALLEGRO_SDL) extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_sdl_driver; #endif /* Channel configuration helpers */ /* Function: al_get_channel_count */ size_t al_get_channel_count(ALLEGRO_CHANNEL_CONF conf) { return (conf>>4)+(conf&0xF); } /* Depth configuration helpers */ /* Function: al_get_audio_depth_size */ size_t al_get_audio_depth_size(ALLEGRO_AUDIO_DEPTH depth) { switch (depth) { case ALLEGRO_AUDIO_DEPTH_INT8: case ALLEGRO_AUDIO_DEPTH_UINT8: return sizeof(int8_t); case ALLEGRO_AUDIO_DEPTH_INT16: case ALLEGRO_AUDIO_DEPTH_UINT16: return sizeof(int16_t); case ALLEGRO_AUDIO_DEPTH_INT24: case ALLEGRO_AUDIO_DEPTH_UINT24: return sizeof(int32_t); case ALLEGRO_AUDIO_DEPTH_FLOAT32: return sizeof(float); default: ASSERT(false); return 0; } } /* FIXME: use the allegro provided helpers */ ALLEGRO_CHANNEL_CONF _al_count_to_channel_conf(int num_channels) { switch (num_channels) { case 1: return ALLEGRO_CHANNEL_CONF_1; case 2: return ALLEGRO_CHANNEL_CONF_2; case 3: return ALLEGRO_CHANNEL_CONF_3; case 4: return ALLEGRO_CHANNEL_CONF_4; case 6: return ALLEGRO_CHANNEL_CONF_5_1; case 7: return ALLEGRO_CHANNEL_CONF_6_1; case 8: return ALLEGRO_CHANNEL_CONF_7_1; default: return 0; } } /* FIXME: assumes 8-bit is unsigned, and all others are signed. */ ALLEGRO_AUDIO_DEPTH _al_word_size_to_depth_conf(int word_size) { switch (word_size) { case 1: return ALLEGRO_AUDIO_DEPTH_UINT8; case 2: return ALLEGRO_AUDIO_DEPTH_INT16; case 3: return ALLEGRO_AUDIO_DEPTH_INT24; case 4: return ALLEGRO_AUDIO_DEPTH_FLOAT32; default: return 0; } } /* Function: al_fill_silence */ void al_fill_silence(void *buf, unsigned int samples, ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf) { size_t bytes = samples * al_get_audio_depth_size(depth) * al_get_channel_count(chan_conf); switch (depth) { case ALLEGRO_AUDIO_DEPTH_INT8: case ALLEGRO_AUDIO_DEPTH_INT16: case ALLEGRO_AUDIO_DEPTH_INT24: case ALLEGRO_AUDIO_DEPTH_FLOAT32: memset(buf, 0, bytes); break; case ALLEGRO_AUDIO_DEPTH_UINT8: memset(buf, 0x80, bytes); break; case ALLEGRO_AUDIO_DEPTH_UINT16: { uint16_t *buffer = buf; size_t n = bytes / sizeof(uint16_t); size_t i; for (i = 0; i < n; i++) buffer[i] = 0x8000; } break; case ALLEGRO_AUDIO_DEPTH_UINT24: { uint32_t *buffer = buf; size_t n = bytes / sizeof(uint32_t); size_t i; for (i = 0; i < n; i++) buffer[i] = 0x800000; } break; default: ASSERT(false); break; } } static ALLEGRO_AUDIO_DRIVER_ENUM get_config_audio_driver(void) { ALLEGRO_CONFIG *config = al_get_system_config(); const char *value; value = al_get_config_value(config, "audio", "driver"); if (!value || value[0] == '\0') return ALLEGRO_AUDIO_DRIVER_AUTODETECT; if (0 == _al_stricmp(value, "ALSA")) return ALLEGRO_AUDIO_DRIVER_ALSA; if (0 == _al_stricmp(value, "OPENAL")) return ALLEGRO_AUDIO_DRIVER_OPENAL; if (0 == _al_stricmp(value, "OPENSL")) return ALLEGRO_AUDIO_DRIVER_OPENSL; if (0 == _al_stricmp(value, "OSS")) return ALLEGRO_AUDIO_DRIVER_OSS; if (0 == _al_stricmp(value, "PULSEAUDIO")) return ALLEGRO_AUDIO_DRIVER_PULSEAUDIO; if (0 == _al_stricmp(value, "DSOUND") || 0 == _al_stricmp(value, "DIRECTSOUND")) return ALLEGRO_AUDIO_DRIVER_DSOUND; return ALLEGRO_AUDIO_DRIVER_AUTODETECT; } /* Function: al_get_num_audio_output_devices */ int al_get_num_audio_output_devices() { if (_al_kcm_driver) { if (_al_kcm_driver->get_output_devices) { _AL_LIST* audio_devices = _al_kcm_driver->get_output_devices(); return _al_list_size(audio_devices); } else { return -1; } } return 0; } /* Function: al_get_audio_output_device */ const ALLEGRO_AUDIO_DEVICE* al_get_audio_output_device(int index) { if (_al_kcm_driver) { if (_al_kcm_driver->get_output_devices) { _AL_LIST* audio_devices = _al_kcm_driver->get_output_devices(); if (index >= 0 && index < (int)_al_list_size(audio_devices)) { return _al_list_item_data(_al_list_at(audio_devices, index)); } } else { return NULL; } } return NULL; } /* Function: al_get_audio_device_name */ const char* al_get_audio_device_name(const ALLEGRO_AUDIO_DEVICE * device) { return device ? device->name : NULL; } static bool do_install_audio(ALLEGRO_AUDIO_DRIVER_ENUM mode) { bool retVal; /* check to see if a driver is already installed and running */ if (_al_kcm_driver) { _al_set_error(ALLEGRO_GENERIC_ERROR, "A driver already running"); return false; } if (mode == ALLEGRO_AUDIO_DRIVER_AUTODETECT) { mode = get_config_audio_driver(); } switch (mode) { case ALLEGRO_AUDIO_DRIVER_AUTODETECT: #if defined(ALLEGRO_SDL) retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_SDL); if (retVal) return retVal; #endif #if defined(ALLEGRO_CFG_KCM_AQUEUE) retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_AQUEUE); if (retVal) return retVal; #endif /* If a PA server is running, we should use it by default as it will * hijack ALSA and OSS and using those then just means extra lag. * * FIXME: Detect if no PA server is running and in that case prefer * ALSA and OSS first. */ #if defined(ALLEGRO_CFG_KCM_PULSEAUDIO) retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_PULSEAUDIO); if (retVal) return retVal; #endif #if defined(ALLEGRO_CFG_KCM_ALSA) retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_ALSA); if (retVal) return retVal; #endif #if defined(ALLEGRO_CFG_KCM_DSOUND) retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_DSOUND); if (retVal) return retVal; #endif #if defined(ALLEGRO_CFG_KCM_OSS) retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_OSS); if (retVal) return retVal; #endif #if defined(ALLEGRO_CFG_KCM_OPENAL) retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_OPENAL); if (retVal) return retVal; #endif #if defined(ALLEGRO_CFG_KCM_OPENSL) retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_OPENSL); if (retVal) return retVal; #endif _al_set_error(ALLEGRO_INVALID_PARAM, "No audio driver can be used."); _al_kcm_driver = NULL; return false; case ALLEGRO_AUDIO_DRIVER_AQUEUE: #if defined(ALLEGRO_CFG_KCM_AQUEUE) if (_al_kcm_aqueue_driver.open() == 0) { ALLEGRO_INFO("Using Apple Audio Queue driver\n"); _al_kcm_driver = &_al_kcm_aqueue_driver; return true; } return false; #else _al_set_error(ALLEGRO_INVALID_PARAM, "Audio Queue driver not available on this platform"); return false; #endif case ALLEGRO_AUDIO_DRIVER_OPENAL: #if defined(ALLEGRO_CFG_KCM_OPENAL) if (_al_kcm_openal_driver.open() == 0) { ALLEGRO_INFO("Using OpenAL driver\n"); _al_kcm_driver = &_al_kcm_openal_driver; return true; } return false; #else _al_set_error(ALLEGRO_INVALID_PARAM, "OpenAL not available on this platform"); return false; #endif case ALLEGRO_AUDIO_DRIVER_OPENSL: #if defined(ALLEGRO_CFG_KCM_OPENSL) if (_al_kcm_opensl_driver.open() == 0) { ALLEGRO_INFO("Using OpenSL driver\n"); _al_kcm_driver = &_al_kcm_opensl_driver; return true; } return false; #else _al_set_error(ALLEGRO_INVALID_PARAM, "OpenSL not available on this platform"); return false; #endif case ALLEGRO_AUDIO_DRIVER_ALSA: #if defined(ALLEGRO_CFG_KCM_ALSA) if (_al_kcm_alsa_driver.open() == 0) { ALLEGRO_INFO("Using ALSA driver\n"); _al_kcm_driver = &_al_kcm_alsa_driver; return true; } return false; #else _al_set_error(ALLEGRO_INVALID_PARAM, "ALSA not available on this platform"); return false; #endif case ALLEGRO_AUDIO_DRIVER_OSS: #if defined(ALLEGRO_CFG_KCM_OSS) if (_al_kcm_oss_driver.open() == 0) { ALLEGRO_INFO("Using OSS driver\n"); _al_kcm_driver = &_al_kcm_oss_driver; return true; } return false; #else _al_set_error(ALLEGRO_INVALID_PARAM, "OSS not available on this platform"); return false; #endif case ALLEGRO_AUDIO_DRIVER_PULSEAUDIO: #if defined(ALLEGRO_CFG_KCM_PULSEAUDIO) if (_al_kcm_pulseaudio_driver.open() == 0) { ALLEGRO_INFO("Using PulseAudio driver\n"); _al_kcm_driver = &_al_kcm_pulseaudio_driver; return true; } return false; #else _al_set_error(ALLEGRO_INVALID_PARAM, "PulseAudio not available on this platform"); return false; #endif case ALLEGRO_AUDIO_DRIVER_DSOUND: #if defined(ALLEGRO_CFG_KCM_DSOUND) if (_al_kcm_dsound_driver.open() == 0) { ALLEGRO_INFO("Using DirectSound driver\n"); _al_kcm_driver = &_al_kcm_dsound_driver; return true; } return false; #else _al_set_error(ALLEGRO_INVALID_PARAM, "DirectSound not available on this platform"); return false; #endif case ALLEGRO_AUDIO_DRIVER_SDL: #if defined(ALLEGRO_SDL) if (_al_kcm_sdl_driver.open() == 0) { ALLEGRO_INFO("Using SDL driver\n"); _al_kcm_driver = &_al_kcm_sdl_driver; return true; } return false; #else _al_set_error(ALLEGRO_INVALID_PARAM, "SDL not available on this platform"); return false; #endif default: _al_set_error(ALLEGRO_INVALID_PARAM, "Invalid audio driver"); return false; } } /* Function: al_install_audio */ bool al_install_audio(void) { bool ret; if (_al_kcm_driver) return true; /* The destructors are initialised even if the audio driver fails to install * because the user may still create samples. */ _al_kcm_init_destructors(); _al_add_exit_func(al_uninstall_audio, "al_uninstall_audio"); ret = do_install_audio(ALLEGRO_AUDIO_DRIVER_AUTODETECT); return ret; } /* Function: al_uninstall_audio */ void al_uninstall_audio(void) { if (_al_kcm_driver) { _al_kcm_shutdown_default_mixer(); _al_kcm_shutdown_destructors(); _al_kcm_driver->close(); _al_kcm_driver = NULL; } else { _al_kcm_shutdown_destructors(); } } /* Function: al_is_audio_installed */ bool al_is_audio_installed(void) { return _al_kcm_driver ? true : false; } /* Function: al_get_allegro_audio_version */ uint32_t al_get_allegro_audio_version(void) { return ALLEGRO_VERSION_INT; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/audio_io.c000066400000000000000000000264461473414355200200010ustar00rootroot00000000000000/* * Allegro audio codec table. */ #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_vector.h" ALLEGRO_DEBUG_CHANNEL("audio") #define MAX_EXTENSION_LENGTH (32) typedef struct ACODEC_TABLE ACODEC_TABLE; struct ACODEC_TABLE { char ext[MAX_EXTENSION_LENGTH]; ALLEGRO_SAMPLE * (*loader)(const char *filename); bool (*saver)(const char *filename, ALLEGRO_SAMPLE *spl); ALLEGRO_AUDIO_STREAM *(*stream_loader)(const char *filename, size_t buffer_count, unsigned int samples); ALLEGRO_SAMPLE * (*fs_loader)(ALLEGRO_FILE *fp); bool (*fs_saver)(ALLEGRO_FILE *fp, ALLEGRO_SAMPLE *spl); ALLEGRO_AUDIO_STREAM *(*fs_stream_loader)(ALLEGRO_FILE *fp, size_t buffer_count, unsigned int samples); bool (*identifier)(ALLEGRO_FILE *fp); }; /* globals */ static bool acodec_inited = false; static _AL_VECTOR acodec_table = _AL_VECTOR_INITIALIZER(ACODEC_TABLE); static ALLEGRO_AUDIO_STREAM *global_stream; static void acodec_shutdown(void) { if (acodec_inited) { _al_vector_free(&acodec_table); acodec_inited = false; } al_destroy_audio_stream(global_stream); } static ACODEC_TABLE *find_acodec_table_entry(const char *ext) { ACODEC_TABLE *ent; unsigned i; for (i = 0; i < _al_vector_size(&acodec_table); i++) { ent = _al_vector_ref(&acodec_table, i); if (0 == _al_stricmp(ent->ext, ext)) { return ent; } } return NULL; } static ACODEC_TABLE *find_acodec_table_entry_for_file(ALLEGRO_FILE *f) { ACODEC_TABLE *ent; unsigned i; for (i = 0; i < _al_vector_size(&acodec_table); i++) { ent = _al_vector_ref(&acodec_table, i); if (ent->identifier) { int64_t pos = al_ftell(f); bool identified = ent->identifier(f); al_fseek(f, pos, ALLEGRO_SEEK_SET); if (identified) return ent; } } return NULL; } static ACODEC_TABLE *add_acodec_table_entry(const char *ext) { ACODEC_TABLE *ent; ASSERT(ext); if (!acodec_inited) { acodec_inited = true; _al_add_exit_func(acodec_shutdown, "acodec_shutdown"); } ent = _al_vector_alloc_back(&acodec_table); strcpy(ent->ext, ext); ent->loader = NULL; ent->saver = NULL; ent->stream_loader = NULL; ent->fs_loader = NULL; ent->fs_saver = NULL; ent->fs_stream_loader = NULL; ent->identifier = NULL; return ent; } /* Function: al_register_sample_loader */ bool al_register_sample_loader(const char *ext, ALLEGRO_SAMPLE *(*loader)(const char *filename)) { ACODEC_TABLE *ent; if (strlen(ext) + 1 >= MAX_EXTENSION_LENGTH) { return false; } ent = find_acodec_table_entry(ext); if (!loader) { if (!ent || !ent->loader) { return false; /* Nothing to remove. */ } } else if (!ent) { ent = add_acodec_table_entry(ext); } ent->loader = loader; return true; } /* Function: al_register_sample_loader_f */ bool al_register_sample_loader_f(const char *ext, ALLEGRO_SAMPLE *(*loader)(ALLEGRO_FILE* fp)) { ACODEC_TABLE *ent; if (strlen(ext) + 1 >= MAX_EXTENSION_LENGTH) { return false; } ent = find_acodec_table_entry(ext); if (!loader) { if (!ent || !ent->fs_loader) { return false; /* Nothing to remove. */ } } else if (!ent) { ent = add_acodec_table_entry(ext); } ent->fs_loader = loader; return true; } /* Function: al_register_sample_saver */ bool al_register_sample_saver(const char *ext, bool (*saver)(const char *filename, ALLEGRO_SAMPLE *spl)) { ACODEC_TABLE *ent; if (strlen(ext) + 1 >= MAX_EXTENSION_LENGTH) { return false; } ent = find_acodec_table_entry(ext); if (!saver) { if (!ent || !ent->saver) { return false; /* Nothing to remove. */ } } else if (!ent) { ent = add_acodec_table_entry(ext); } ent->saver = saver; return true; } /* Function: al_register_sample_saver_f */ bool al_register_sample_saver_f(const char *ext, bool (*saver)(ALLEGRO_FILE* fp, ALLEGRO_SAMPLE *spl)) { ACODEC_TABLE *ent; if (strlen(ext) + 1 >= MAX_EXTENSION_LENGTH) { return false; } ent = find_acodec_table_entry(ext); if (!saver) { if (!ent || !ent->fs_saver) { return false; /* Nothing to remove. */ } } else if (!ent) { ent = add_acodec_table_entry(ext); } ent->fs_saver = saver; return true; } /* Function: al_register_audio_stream_loader */ bool al_register_audio_stream_loader(const char *ext, ALLEGRO_AUDIO_STREAM *(*stream_loader)(const char *filename, size_t buffer_count, unsigned int samples)) { ACODEC_TABLE *ent; if (strlen(ext) + 1 >= MAX_EXTENSION_LENGTH) { return false; } ent = find_acodec_table_entry(ext); if (!stream_loader) { if (!ent || !ent->stream_loader) { return false; /* Nothing to remove. */ } } else if (!ent) { ent = add_acodec_table_entry(ext); } ent->stream_loader = stream_loader; return true; } /* Function: al_register_audio_stream_loader_f */ bool al_register_audio_stream_loader_f(const char *ext, ALLEGRO_AUDIO_STREAM *(*stream_loader)(ALLEGRO_FILE* fp, size_t buffer_count, unsigned int samples)) { ACODEC_TABLE *ent; if (strlen(ext) + 1 >= MAX_EXTENSION_LENGTH) { return false; } ent = find_acodec_table_entry(ext); if (!stream_loader) { if (!ent || !ent->fs_stream_loader) { return false; /* Nothing to remove. */ } } else if (!ent) { ent = add_acodec_table_entry(ext); } ent->fs_stream_loader = stream_loader; return true; } /* Function: al_register_sample_identifier */ bool al_register_sample_identifier(const char *ext, bool (*identifier)(ALLEGRO_FILE* fp)) { ACODEC_TABLE *ent; if (strlen(ext) + 1 >= MAX_EXTENSION_LENGTH) { return false; } ent = find_acodec_table_entry(ext); if (!identifier) { if (!ent || !ent->identifier) { return false; /* Nothing to remove. */ } } else if (!ent) { ent = add_acodec_table_entry(ext); } ent->identifier = identifier; return true; } /* Function: al_load_sample */ ALLEGRO_SAMPLE *al_load_sample(const char *filename) { const char *ext; ACODEC_TABLE *ent; ASSERT(filename); ext = al_identify_sample(filename); if (!ext) { ext = strrchr(filename, '.'); if (ext == NULL) { ALLEGRO_ERROR("Unable to determine extension for %s.\n", filename); return NULL; } } ent = find_acodec_table_entry(ext); if (ent && ent->loader) { return (ent->loader)(filename); } else { ALLEGRO_ERROR("No handler for audio file extension %s - " "therefore not trying to load %s.\n", ext, filename); } return NULL; } /* Function: al_load_sample_f */ ALLEGRO_SAMPLE *al_load_sample_f(ALLEGRO_FILE* fp, const char *ident) { ACODEC_TABLE *ent; ASSERT(fp); ASSERT(ident); ent = find_acodec_table_entry(ident); if (ent && ent->fs_loader) { return (ent->fs_loader)(fp); } else { ALLEGRO_ERROR("No handler for audio file extension %s.\n", ident); } return NULL; } /* Function: al_load_audio_stream */ ALLEGRO_AUDIO_STREAM *al_load_audio_stream(const char *filename, size_t buffer_count, unsigned int samples) { const char *ext; ACODEC_TABLE *ent; ASSERT(filename); ext = al_identify_sample(filename); if (!ext) { ext = strrchr(filename, '.'); if (ext == NULL) { ALLEGRO_ERROR("Unable to determine extension for %s.\n", filename); return NULL; } } ent = find_acodec_table_entry(ext); if (ent && ent->stream_loader) { return (ent->stream_loader)(filename, buffer_count, samples); } else { ALLEGRO_ERROR("No handler for audio file extension %s - " "therefore not trying to load %s.\n", ext, filename); } return NULL; } /* Function: al_load_audio_stream_f */ ALLEGRO_AUDIO_STREAM *al_load_audio_stream_f(ALLEGRO_FILE* fp, const char *ident, size_t buffer_count, unsigned int samples) { ACODEC_TABLE *ent; ASSERT(fp); ASSERT(ident); ent = find_acodec_table_entry(ident); if (ent && ent->fs_stream_loader) { return (ent->fs_stream_loader)(fp, buffer_count, samples); } else { ALLEGRO_ERROR("No handler for audio file extension %s.\n", ident); } return NULL; } /* Function: al_play_audio_stream */ ALLEGRO_AUDIO_STREAM *al_play_audio_stream(const char *filename) { ASSERT(filename); if (!al_get_default_mixer()) { ALLEGRO_ERROR("No default mixer\n!"); return NULL; } al_destroy_audio_stream(global_stream); global_stream = al_load_audio_stream(filename, 4, 2048); if (!global_stream) { ALLEGRO_ERROR("Could not play audio stream: %s.\n", filename); return NULL; } if (!al_attach_audio_stream_to_mixer(global_stream, al_get_default_mixer())) { ALLEGRO_ERROR("Could not attach stream to mixer\n"); return NULL; } return global_stream; } /* Function: al_play_audio_stream_f */ ALLEGRO_AUDIO_STREAM *al_play_audio_stream_f(ALLEGRO_FILE *fp, const char *ident) { ASSERT(fp); ASSERT(ident); if (!al_get_default_mixer()) { ALLEGRO_ERROR("No default mixer\n!"); return NULL; } al_destroy_audio_stream(global_stream); global_stream = al_load_audio_stream_f(fp, ident, 4, 2048); if (!global_stream) { ALLEGRO_ERROR("Could not play audio stream.\n"); return NULL; } if (!al_attach_audio_stream_to_mixer(global_stream, al_get_default_mixer())) { ALLEGRO_ERROR("Could not attach stream to mixer\n"); return NULL; } return global_stream; } /* Function: al_save_sample */ bool al_save_sample(const char *filename, ALLEGRO_SAMPLE *spl) { const char *ext; ACODEC_TABLE *ent; ASSERT(filename); ext = strrchr(filename, '.'); if (ext == NULL) { ALLEGRO_ERROR("Unable to determine extension for %s.\n", filename); return false; } ent = find_acodec_table_entry(ext); if (ent && ent->saver) { return (ent->saver)(filename, spl); } else { ALLEGRO_ERROR("No handler for audio file extension %s - " "therefore not trying to load %s.\n", ext, filename); } return false; } /* Function: al_save_sample_f */ bool al_save_sample_f(ALLEGRO_FILE *fp, const char *ident, ALLEGRO_SAMPLE *spl) { ACODEC_TABLE *ent; ASSERT(fp); ASSERT(ident); ent = find_acodec_table_entry(ident); if (ent && ent->fs_saver) { return (ent->fs_saver)(fp, spl); } else { ALLEGRO_ERROR("No handler for audio file extension %s.\n", ident); } return false; } /* Function: al_identify_sample_f */ char const *al_identify_sample_f(ALLEGRO_FILE *fp) { ACODEC_TABLE *h = find_acodec_table_entry_for_file(fp); if (!h) return NULL; return h->ext; } /* Function: al_identify_sample */ char const *al_identify_sample(char const *filename) { char const *ext; ALLEGRO_FILE *fp = al_fopen(filename, "rb"); if (!fp) return NULL; ext = al_identify_sample_f(fp); al_fclose(fp); return ext; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/dsound.cpp000066400000000000000000000646771473414355200200550ustar00rootroot00000000000000/* * Based on DirectSound driver by KC/Milan */ #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0501 #endif #ifndef WINVER #define WINVER 0x0501 #endif #include #include #include #include /* dsound.h from the official DirectX SDK uses __null to annotate some * function arguments. It is #defined away by a macro in sal.h, but this * breaks GCC headers, as they also use __null (but for a different * purpose). This pre-processor block undefines __null which returns * __null to acting like a GCC keyword. * This does nothing for the unofficial DirectX SDK, which has __null * manually removed. */ #if defined __MINGW32__ && defined __null #undef __null #endif /* I'm not sure what library this is supposed to be in, but I couldn't find it yet */ const IID GUID_NULL = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }; static const IID _al_IID_IDirectSoundBuffer8 = { 0x6825a449, 0x7524, 0x4d82, { 0x92, 0x0f, 0x50, 0xe3, 0x6a, 0xb3, 0xab, 0x1e } }; static const IID _al_IID_IDirectSoundCaptureBuffer8 = { 0x00990df4, 0x0dbb, 0x4872, { 0x83, 0x3e, 0x6d, 0x30, 0x3e, 0x80, 0xae, 0xb6 } }; #include "allegro5/allegro.h" extern "C" { ALLEGRO_DEBUG_CHANNEL("audio-dsound") #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_wunicode.h" /* This is used to stop MinGW from complaining about type-punning */ #define MAKE_UNION(ptr, t) \ union { \ LPVOID *v; \ t p; \ } u; \ u.p = (ptr); /* DirectSound vars */ static IDirectSound8 *device; static IDirectSoundCapture8 *capture_device; static char ds_err_str[100]; static int buffer_size; // in bytes static _AL_LIST* output_device_list; #define MIN_BUFFER_SIZE 1024 #define MIN_FILL 512 #define MAX_FILL 1024 static BOOL CALLBACK _ds_enum_callback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext); static HWND get_window() { const char *val = al_get_config_value(al_get_system_config(), "directsound", "window"); HWND ret; if (val && strncmp(val, "foreground", 10) == 0) { ret = GetForegroundWindow(); ALLEGRO_INFO("Using foreground window: %p\n", ret); } else { ret = GetDesktopWindow(); ALLEGRO_INFO("Using desktop window: %p\n", ret); } return ret; } static void dsound_set_buffer_size(int bits_per_sample) { int buffer_size_in_samples = 8192; // default const char *val = al_get_config_value(al_get_system_config(), "directsound", "buffer_size"); if (val && val[0] != '\0') { int n = atoi(val); if (n < MIN_BUFFER_SIZE) n = MIN_BUFFER_SIZE; buffer_size_in_samples = n; } buffer_size = buffer_size_in_samples * (bits_per_sample/8); } static char *ds_get_error(HRESULT hr) { switch (hr) { case DSERR_ALLOCATED: strcpy(ds_err_str, "DSERR_ALLOCATED"); break; case DSERR_BADFORMAT: strcpy(ds_err_str, "DSERR_BADFORMAT"); break; case DSERR_BUFFERTOOSMALL: strcpy(ds_err_str, "DSERR_BUFFERTOOSMALL"); break; case DSERR_CONTROLUNAVAIL: strcpy(ds_err_str, "DSERR_CONTROLUNAVAIL"); break; case DSERR_DS8_REQUIRED: strcpy(ds_err_str, "DSERR_DS8_REQUIRED"); break; case DSERR_INVALIDCALL: strcpy(ds_err_str, "DSERR_INVALIDCALL"); break; case DSERR_INVALIDPARAM: strcpy(ds_err_str, "DSERR_INVALIDPARAM"); break; case DSERR_NOAGGREGATION: strcpy(ds_err_str, "DSERR_NOAGGREGATION"); break; case DSERR_OUTOFMEMORY: strcpy(ds_err_str, "DSERR_OUTOFMEMORY"); break; case DSERR_UNINITIALIZED: strcpy(ds_err_str, "DSERR_UNINITIALIZED"); break; case DSERR_UNSUPPORTED: strcpy(ds_err_str, "DSERR_UNSUPPORTED"); break; } return ds_err_str; } /* Custom struct to hold voice information DirectSound needs */ /* TODO: review */ struct ALLEGRO_DS_DATA { int bits_per_sample; int channels; DSBUFFERDESC desc; WAVEFORMATEX wave_fmt; LPDIRECTSOUNDBUFFER ds_buffer; LPDIRECTSOUNDBUFFER8 ds8_buffer; int stop_voice; ALLEGRO_THREAD *thread; }; static bool _dsound_voice_is_playing(const ALLEGRO_VOICE *voice); /* Custom routine which runs in another thread to periodically check if DirectSound wants more data for a stream */ static void* _dsound_update(ALLEGRO_THREAD *self, void *arg) { ALLEGRO_VOICE *voice = (ALLEGRO_VOICE *)arg; ALLEGRO_DS_DATA *ex_data = (ALLEGRO_DS_DATA*)voice->extra; const int bytes_per_sample = ex_data->bits_per_sample / 8; DWORD play_cursor = 0; DWORD write_cursor; DWORD saved_play_cursor = 0; unsigned int samples; LPVOID ptr1, ptr2; DWORD block1_bytes, block2_bytes; unsigned char *data; unsigned char *silence; HRESULT hr; (void)self; /* Make a buffer full of silence. */ silence = (unsigned char *)al_malloc(buffer_size); samples = buffer_size / bytes_per_sample / ex_data->channels; al_fill_silence(silence, samples, voice->depth, voice->chan_conf); /* Fill buffer */ hr = ex_data->ds8_buffer->Lock(0, buffer_size, &ptr1, &block1_bytes, &ptr2, &block2_bytes, DSBLOCK_ENTIREBUFFER); if (!FAILED(hr)) { unsigned int sample_bytes; samples = buffer_size / bytes_per_sample / ex_data->channels; data = (unsigned char *) _al_voice_update(voice, voice->mutex, &samples); sample_bytes = samples * bytes_per_sample * ex_data->channels; if (sample_bytes < block1_bytes) block1_bytes = sample_bytes; memcpy(ptr1, data, block1_bytes); sample_bytes -= block1_bytes; if (sample_bytes < block2_bytes) block2_bytes = sample_bytes; memcpy(ptr2, data + block1_bytes, block2_bytes); ex_data->ds8_buffer->Unlock(ptr1, block1_bytes, ptr2, block2_bytes); } else { ALLEGRO_ERROR("Lock failed: %s\n", ds_get_error(hr)); } ex_data->ds8_buffer->Play(0, 0, DSBPLAY_LOOPING); do { if (!_dsound_voice_is_playing(voice)) { ex_data->ds8_buffer->Play(0, 0, DSBPLAY_LOOPING); } ex_data->ds8_buffer->GetCurrentPosition(&play_cursor, &write_cursor); /* We try to fill the gap between the saved_play_cursor and the * play_cursor. */ int d = play_cursor - saved_play_cursor; if (d < 0) d += buffer_size; /* Don't fill small gaps. Let it accumulate to amortise the cost of * mixing the samples and locking/unlocking the buffer. */ if (d < MIN_FILL) { al_rest(0.005); continue; } /* Don't generate too many samples at once. The buffer may underrun * while we wait for _al_voice_update to complete. */ samples = d / bytes_per_sample / ex_data->channels; if (samples > MAX_FILL) { samples = MAX_FILL; } /* Generate the samples. */ data = (unsigned char *) _al_voice_update(voice, voice->mutex, &samples); if (data == NULL) { data = silence; } hr = ex_data->ds8_buffer->Lock(saved_play_cursor, samples * bytes_per_sample * ex_data->channels, &ptr1, &block1_bytes, &ptr2, &block2_bytes, 0); if (!FAILED(hr)) { memcpy(ptr1, data, block1_bytes); memcpy(ptr2, data + block1_bytes, block2_bytes); hr = ex_data->ds8_buffer->Unlock(ptr1, block1_bytes, ptr2, block2_bytes); if (FAILED(hr)) { ALLEGRO_ERROR("Unlock failed: %s\n", ds_get_error(hr)); } } else { ALLEGRO_ERROR("Lock failed: %s\n", ds_get_error(hr)); } saved_play_cursor += block1_bytes + block2_bytes; saved_play_cursor %= buffer_size; } while (!ex_data->stop_voice); ex_data->ds8_buffer->Stop(); al_free(silence); ex_data->stop_voice = 0; al_broadcast_cond(voice->cond); return NULL; } /* The open method starts up the driver and should lock the device, using the previously set parameters, or defaults. It shouldn't need to start sending audio data to the device yet, however. */ static int _dsound_open() { HRESULT hr; ALLEGRO_INFO("Starting DirectSound...\n"); output_device_list = _al_list_create(); DirectSoundEnumerate((LPDSENUMCALLBACK)_ds_enum_callback, NULL); /* FIXME: Use default device until we have device enumeration */ hr = DirectSoundCreate8(NULL, &device, NULL); if (FAILED(hr)) { ALLEGRO_ERROR("DirectSoundCreate8 failed: %s\n", ds_get_error(hr)); return 1; } ALLEGRO_DEBUG("DirectSoundCreate8 succeeded\n"); hr = device->SetCooperativeLevel(get_window(), DSSCL_PRIORITY); if (FAILED(hr)) { ALLEGRO_ERROR("SetCooperativeLevel failed: %s\n", ds_get_error(hr)); return 1; } return 0; } /* The close method should close the device, freeing any resources, and allow other processes to use the device */ static void _dsound_close() { ALLEGRO_DEBUG("Releasing device\n"); _al_list_destroy(output_device_list); device->Release(); ALLEGRO_DEBUG("Released device\n"); ALLEGRO_INFO("DirectSound closed\n"); } /* The allocate_voice method should grab a voice from the system, and allocate any data common to streaming and non-streaming sources. */ static int _dsound_allocate_voice(ALLEGRO_VOICE *voice) { ALLEGRO_DS_DATA *ex_data; int bits_per_sample; int channels; ALLEGRO_DEBUG("Allocating voice\n"); /* openal doesn't support very much! */ switch (voice->depth) { case ALLEGRO_AUDIO_DEPTH_UINT8: /* format supported */ bits_per_sample = 8; break; case ALLEGRO_AUDIO_DEPTH_INT8: ALLEGRO_ERROR("DirectSound requires 8-bit data to be unsigned\n"); return 1; case ALLEGRO_AUDIO_DEPTH_UINT16: ALLEGRO_ERROR("DirectSound requires 16-bit data to be signed\n"); return 1; case ALLEGRO_AUDIO_DEPTH_INT16: /* format supported */ bits_per_sample = 16; break; case ALLEGRO_AUDIO_DEPTH_UINT24: ALLEGRO_ERROR("DirectSound does not support 24-bit data\n"); return 1; case ALLEGRO_AUDIO_DEPTH_INT24: ALLEGRO_ERROR("DirectSound does not support 24-bit data\n"); return 1; case ALLEGRO_AUDIO_DEPTH_FLOAT32: ALLEGRO_ERROR("DirectSound does not support 32-bit floating data\n"); return 1; default: ALLEGRO_ERROR("Cannot allocate unknown voice depth\n"); return 1; } switch (voice->chan_conf) { case ALLEGRO_CHANNEL_CONF_1: channels = 1; break; case ALLEGRO_CHANNEL_CONF_2: channels = 2; break; default: ALLEGRO_ERROR("Unsupported number of channels\n"); return 1; } ex_data = (ALLEGRO_DS_DATA *)al_calloc(1, sizeof(*ex_data)); if (!ex_data) { ALLEGRO_ERROR("Could not allocate voice data memory\n"); return 1; } ex_data->bits_per_sample = bits_per_sample; ex_data->channels = channels; ex_data->stop_voice = 1; dsound_set_buffer_size(bits_per_sample); voice->extra = ex_data; ALLEGRO_DEBUG("Allocated voice\n"); return 0; } /* The deallocate_voice method should free the resources for the given voice, but still retain a hold on the device. The voice should be stopped and unloaded by the time this is called */ static void _dsound_deallocate_voice(ALLEGRO_VOICE *voice) { ALLEGRO_DEBUG("Deallocating voice\n"); al_free(voice->extra); voice->extra = NULL; ALLEGRO_DEBUG("Deallocated voice\n"); } /* The load_voice method loads a sample into the driver's memory. The voice's 'streaming' field will be set to false for these voices, and it's 'buffer_size' field will be the total length in bytes of the sample data. The voice's attached sample's looping mode should be honored, and loading must fail if it cannot be. */ static int _dsound_load_voice(ALLEGRO_VOICE *voice, const void *_data) { ALLEGRO_DS_DATA *ex_data = (ALLEGRO_DS_DATA *)voice->extra; HRESULT hr; LPVOID ptr1, ptr2; DWORD block1_bytes, block2_bytes; MAKE_UNION(&ex_data->ds8_buffer, LPDIRECTSOUNDBUFFER8 *); ALLEGRO_DEBUG("Loading voice\n"); ex_data->wave_fmt.wFormatTag = WAVE_FORMAT_PCM; ex_data->wave_fmt.nChannels = ex_data->channels; ex_data->wave_fmt.nSamplesPerSec = voice->frequency; ex_data->wave_fmt.nBlockAlign = ex_data->channels * (ex_data->bits_per_sample/8); ex_data->wave_fmt.nAvgBytesPerSec = ex_data->wave_fmt.nBlockAlign * voice->frequency; ex_data->wave_fmt.wBitsPerSample = ex_data->bits_per_sample; ex_data->wave_fmt.cbSize = 0; ex_data->desc.dwSize = sizeof(DSBUFFERDESC); ex_data->desc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_GLOBALFOCUS; /* FIXME: software mixing for now */ ex_data->desc.dwBufferBytes = voice->buffer_size; ex_data->desc.dwReserved = 0; ex_data->desc.lpwfxFormat = &ex_data->wave_fmt; ex_data->desc.guid3DAlgorithm = DS3DALG_DEFAULT; hr = device->CreateSoundBuffer(&ex_data->desc, &ex_data->ds_buffer, NULL); if (FAILED(hr)) { ALLEGRO_ERROR("CreateSoundBuffer failed: %s\n", ds_get_error(hr)); return 1; } ex_data->ds_buffer->QueryInterface(_al_IID_IDirectSoundBuffer8, u.v); hr = ex_data->ds8_buffer->Lock(0, voice->buffer_size, &ptr1, &block1_bytes, &ptr2, &block2_bytes, 0); if (FAILED(hr)) { ALLEGRO_ERROR("Locking buffer failed: %s\n", ds_get_error(hr)); return 1; } unsigned char *data = (unsigned char *) _data; memcpy(ptr1, data, block1_bytes); memcpy(ptr2, data + block1_bytes, block2_bytes); ex_data->ds8_buffer->Unlock(ptr1, block1_bytes, ptr2, block2_bytes); return 0; } /* The unload_voice method unloads a sample previously loaded with load_voice. This method should not be called on a streaming voice. */ static void _dsound_unload_voice(ALLEGRO_VOICE *voice) { ALLEGRO_DS_DATA *ex_data = (ALLEGRO_DS_DATA *)voice->extra; ALLEGRO_DEBUG("Unloading voice\n"); ex_data->ds8_buffer->Release(); ALLEGRO_DEBUG("Unloaded voice\n"); } /* The start_voice should, surprise, start the voice. For streaming voices, it should start polling the device and call _al_voice_update for audio data. For non-streaming voices, it should resume playing from the last set position */ static int _dsound_start_voice(ALLEGRO_VOICE *voice) { ALLEGRO_DS_DATA *ex_data = (ALLEGRO_DS_DATA *)voice->extra; HRESULT hr; MAKE_UNION(&ex_data->ds8_buffer, LPDIRECTSOUNDBUFFER8 *); ALLEGRO_DEBUG("Starting voice\n"); if (!voice->is_streaming) { hr = ex_data->ds8_buffer->Play(0, 0, 0); if (FAILED(hr)) { ALLEGRO_ERROR("Streaming voice failed to start: %s\n", ds_get_error(hr)); return 1; } ALLEGRO_INFO("Streaming voice started\n"); return 0; } if (ex_data->stop_voice != 0) { ex_data->wave_fmt.wFormatTag = WAVE_FORMAT_PCM; ex_data->wave_fmt.nChannels = ex_data->channels; ex_data->wave_fmt.nSamplesPerSec = voice->frequency; ex_data->wave_fmt.nBlockAlign = ex_data->channels * (ex_data->bits_per_sample/8); ex_data->wave_fmt.nAvgBytesPerSec = ex_data->wave_fmt.nBlockAlign * voice->frequency; ex_data->wave_fmt.wBitsPerSample = ex_data->bits_per_sample; ex_data->wave_fmt.cbSize = 0; ex_data->desc.dwSize = sizeof(DSBUFFERDESC); ex_data->desc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_GLOBALFOCUS; /* FIXME: software mixing for now */ ex_data->desc.dwBufferBytes = buffer_size; ex_data->desc.dwReserved = 0; ex_data->desc.lpwfxFormat = &ex_data->wave_fmt; ex_data->desc.guid3DAlgorithm = DS3DALG_DEFAULT; ALLEGRO_DEBUG("CreateSoundBuffer\n"); hr = device->CreateSoundBuffer(&ex_data->desc, &ex_data->ds_buffer, NULL); if (FAILED(hr)) { ALLEGRO_ERROR("CreateSoundBuffer failed: %s\n", ds_get_error(hr)); return 1; } ALLEGRO_DEBUG("CreateSoundBuffer succeeded\n"); ex_data->ds_buffer->QueryInterface(_al_IID_IDirectSoundBuffer8, u.v); ex_data->ds8_buffer->SetVolume(DSBVOLUME_MAX); ALLEGRO_DEBUG("Starting _dsound_update thread\n"); ex_data->stop_voice = 0; ex_data->thread = al_create_thread(_dsound_update, (void*) voice); al_start_thread(ex_data->thread); } else { ALLEGRO_WARN("stop_voice == 0\n"); } ALLEGRO_INFO("Voice started\n"); return 0; } /* The stop_voice method should stop playback. For non-streaming voices, it should leave the data loaded, and reset the voice position to 0. */ static int _dsound_stop_voice(ALLEGRO_VOICE* voice) { ALLEGRO_DS_DATA *ex_data = (ALLEGRO_DS_DATA *)voice->extra; ALLEGRO_DEBUG("Stopping voice\n"); if (!ex_data->ds8_buffer) { ALLEGRO_ERROR("Trying to stop empty voice buffer\n"); return 1; } /* if playing a sample */ if (!voice->is_streaming) { ALLEGRO_DEBUG("Stopping non-streaming voice\n"); ex_data->ds8_buffer->Stop(); ex_data->ds8_buffer->SetCurrentPosition(0); ALLEGRO_INFO("Non-streaming voice stopped\n"); return 0; } if (ex_data->stop_voice == 0) { ALLEGRO_DEBUG("Joining thread\n"); ex_data->stop_voice = 1; while (ex_data->stop_voice == 1) { al_wait_cond(voice->cond, voice->mutex); } al_join_thread(ex_data->thread, NULL); ALLEGRO_DEBUG("Joined thread\n"); ALLEGRO_DEBUG("Destroying thread\n"); al_destroy_thread(ex_data->thread); ALLEGRO_DEBUG("Thread destroyed\n"); /* This is required to restart the background thread when the voice * restarts. */ ex_data->stop_voice = 1; } ALLEGRO_DEBUG("Releasing buffer\n"); ex_data->ds8_buffer->Release(); ex_data->ds8_buffer = NULL; ALLEGRO_INFO("Voice stopped\n"); return 0; } /* The voice_is_playing method should only be called on non-streaming sources, and should return true if the voice is playing */ static bool _dsound_voice_is_playing(const ALLEGRO_VOICE *voice) { ALLEGRO_DS_DATA *ex_data = (ALLEGRO_DS_DATA *)voice->extra; DWORD status; if (!ex_data) { ALLEGRO_WARN("ex_data is null\n"); return false; } ex_data->ds8_buffer->GetStatus(&status); return (status & DSBSTATUS_PLAYING); } /* The get_voice_position method should return the current sample position of the voice (sample_pos = byte_pos / (depth/8) / channels). This should never be called on a streaming voice. */ static unsigned int _dsound_get_voice_position(const ALLEGRO_VOICE *voice) { ALLEGRO_DS_DATA *ex_data = (ALLEGRO_DS_DATA *)voice->extra; DWORD play_pos; HRESULT hr; hr = ex_data->ds8_buffer->GetCurrentPosition(&play_pos, NULL); if (FAILED(hr)) { ALLEGRO_ERROR("GetCurrentPosition failed: %s\n", ds_get_error(hr)); return 0; } return play_pos / (ex_data->channels * (ex_data->bits_per_sample/8)); } /* The set_voice_position method should set the voice's playback position, given the value in samples. This should never be called on a streaming voice. */ static int _dsound_set_voice_position(ALLEGRO_VOICE *voice, unsigned int val) { ALLEGRO_DS_DATA *ex_data = (ALLEGRO_DS_DATA *)voice->extra; HRESULT hr; val *= ex_data->channels * (ex_data->bits_per_sample/8); hr = ex_data->ds8_buffer->SetCurrentPosition(val); if (FAILED(hr)) { ALLEGRO_ERROR("SetCurrentPosition failed: %s\n", ds_get_error(hr)); return 1; } return 0; } struct DSOUND_RECORD_DATA { LPDIRECTSOUNDCAPTUREBUFFER buffer; LPDIRECTSOUNDCAPTUREBUFFER8 buffer8; DSCBUFFERDESC desc; WAVEFORMATEX wave_fmt; }; static void *_dsound_update_recorder(ALLEGRO_THREAD *t, void *data) { ALLEGRO_AUDIO_RECORDER *r = (ALLEGRO_AUDIO_RECORDER *) data; DSOUND_RECORD_DATA *extra = (DSOUND_RECORD_DATA *) r->extra; DWORD last_read_pos = 0; ALLEGRO_EVENT user_event; bool is_dsound_recording = false; size_t fragment_i = 0; size_t bytes_written = 0; ALLEGRO_INFO("Starting recorder thread\n"); while (!al_get_thread_should_stop(t)) { al_lock_mutex(r->mutex); while (!r->is_recording) { if (is_dsound_recording) { extra->buffer8->Stop(); is_dsound_recording = false; } al_wait_cond(r->cond, r->mutex); if (al_get_thread_should_stop(t)) goto stop_recording; } if (!is_dsound_recording) { extra->buffer8->Start(DSCBSTART_LOOPING); is_dsound_recording = true; extra->buffer8->GetCurrentPosition(NULL, &last_read_pos); } void *buffer1, *buffer2; DWORD buffer1_size, buffer2_size; DWORD cap_pos, bytes_to_read; extra->buffer8->GetCurrentPosition(NULL, &cap_pos); /* never read past the end of the buffer; that way buffer2 is always NULL */ if (last_read_pos <= cap_pos) bytes_to_read = cap_pos - last_read_pos; else bytes_to_read = extra->desc.dwBufferBytes - last_read_pos; if (bytes_to_read) { uint8_t *buffer; size_t buffer_size; extra->buffer8->Lock(last_read_pos, bytes_to_read, &buffer1, &buffer1_size, &buffer2, &buffer2_size, 0); ALLEGRO_ASSERT(buffer2 == NULL); buffer = (uint8_t *)buffer1; buffer_size = buffer1_size; while (buffer_size > 0) { if (bytes_written + buffer_size <= r->fragment_size) { memcpy((uint8_t*) r->fragments[fragment_i] + bytes_written, buffer, buffer_size); bytes_written += buffer_size; buffer_size = 0; } else { ALLEGRO_AUDIO_RECORDER_EVENT *e; size_t bytes_to_write = r->fragment_size - bytes_written; memcpy((uint8_t*) r->fragments[fragment_i] + bytes_written, buffer, bytes_to_write); buffer_size -= bytes_to_write; buffer += bytes_to_write; user_event.user.type = ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT; e = al_get_audio_recorder_event(&user_event); e->buffer = r->fragments[fragment_i]; e->samples = r->samples; al_emit_user_event(&r->source, &user_event, NULL); /* advance to the next fragment */ if (++fragment_i == r->fragment_count) { fragment_i = 0; } bytes_written = 0; } } extra->buffer8->Unlock(buffer1, buffer1_size, buffer2, buffer2_size); /* advanced the last read position */ last_read_pos += bytes_to_read; if (last_read_pos >= extra->desc.dwBufferBytes) last_read_pos -= extra->desc.dwBufferBytes; } al_unlock_mutex(r->mutex); al_rest(0.10); } stop_recording: if (is_dsound_recording) { extra->buffer8->Stop(); } ALLEGRO_INFO("Leaving recorder thread\n"); return NULL; } static int _dsound_open_recorder(ALLEGRO_AUDIO_RECORDER *r) { HRESULT hr; if (capture_device != NULL) { /* FIXME: It's wrong to assume only a single recording device, but since there is no enumeration of devices, it doesn't matter for now. */ ALLEGRO_ERROR("Already recording.\n"); return 1; } ALLEGRO_INFO("Creating default capture device.\n"); /* FIXME: Use default device until we have device enumeration */ hr = DirectSoundCaptureCreate8(NULL, &capture_device, NULL); if (FAILED(hr)) { ALLEGRO_ERROR("DirectSoundCaptureCreate8 failed: %s\n", ds_get_error(hr)); return 1; } hr = device->SetCooperativeLevel(get_window(), DSSCL_PRIORITY); if (FAILED(hr)) { ALLEGRO_ERROR("SetCooperativeLevel failed: %s\n", ds_get_error(hr)); return 1; } DSOUND_RECORD_DATA *extra = (DSOUND_RECORD_DATA *) al_calloc(1, sizeof(*extra)); DSCCAPS dsccaps; dsccaps.dwSize = sizeof(DSCCAPS); hr = capture_device->GetCaps(&dsccaps); if (FAILED(hr)) { ALLEGRO_ERROR("DirectSoundCaptureCreate8::GetCaps failed: %s\n", ds_get_error(hr)); } else { ALLEGRO_INFO("caps: %lu %lu\n", dsccaps.dwFormats, dsccaps.dwFormats & WAVE_FORMAT_2M16); } memset(&extra->wave_fmt, 0, sizeof(extra->wave_fmt)); extra->wave_fmt.wFormatTag = WAVE_FORMAT_PCM; extra->wave_fmt.nChannels = (WORD)al_get_channel_count(r->chan_conf); extra->wave_fmt.nSamplesPerSec = r->frequency; extra->wave_fmt.wBitsPerSample = (WORD)al_get_audio_depth_size(r->depth) * 8; extra->wave_fmt.nBlockAlign = extra->wave_fmt.nChannels * extra->wave_fmt.wBitsPerSample / 8; extra->wave_fmt.nAvgBytesPerSec = extra->wave_fmt.nSamplesPerSec * extra->wave_fmt.nBlockAlign; memset(&extra->desc, 0, sizeof(extra->desc)); extra->desc.dwSize = sizeof(extra->desc); extra->desc.lpwfxFormat = &extra->wave_fmt; extra->desc.dwBufferBytes = extra->wave_fmt.nAvgBytesPerSec * 5; hr = capture_device->CreateCaptureBuffer(&extra->desc, &extra->buffer, NULL); if (FAILED(hr)) { al_free(extra); ALLEGRO_ERROR("Unable to create Capture Buffer\n"); return 1; } extra->buffer->QueryInterface(_al_IID_IDirectSoundCaptureBuffer8, (void **) &extra->buffer8); r->extra = extra; r->thread = al_create_thread(_dsound_update_recorder, r); return 0; } void _dsound_close_recorder(ALLEGRO_AUDIO_RECORDER *r) { ALLEGRO_ASSERT(capture_device); (void) r; capture_device->Release(); capture_device = NULL; } static void _output_device_list_dtor(void* value, void* userdata) { (void)userdata; ALLEGRO_AUDIO_DEVICE* device = (ALLEGRO_AUDIO_DEVICE*)value; al_free(device->name); al_free(device->identifier); al_free(device); } static BOOL CALLBACK _ds_enum_callback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext) { (void)lpcstrModule; (void)lpContext; if (lpGuid != NULL) { ALLEGRO_AUDIO_DEVICE* device = (ALLEGRO_AUDIO_DEVICE*)al_malloc(sizeof(ALLEGRO_AUDIO_DEVICE)); device->identifier = (void*)al_malloc(sizeof(GUID)); device->name = _twin_tchar_to_utf8(lpcstrDescription); memcpy(device->identifier, lpGuid, sizeof(GUID)); _al_list_push_back_ex(output_device_list, device, _output_device_list_dtor); } return TRUE; } static _AL_LIST* _dsound_get_output_devices(void) { return output_device_list; } ALLEGRO_AUDIO_DRIVER _al_kcm_dsound_driver = { "DirectSound", _dsound_open, _dsound_close, _dsound_allocate_voice, _dsound_deallocate_voice, _dsound_load_voice, _dsound_unload_voice, _dsound_start_voice, _dsound_stop_voice, _dsound_voice_is_playing, _dsound_get_voice_position, _dsound_set_voice_position, _dsound_open_recorder, _dsound_close_recorder, _dsound_get_output_devices, }; } /* End extern "C" */ allegro5-5.2.10.1/addons/audio/kcm_dtor.c000066400000000000000000000037571473414355200200130ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Destructors. * * By Peter Wang. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_thread.h" #include "allegro5/internal/aintern_audio.h" static _AL_DTOR_LIST *kcm_dtors = NULL; /* _al_kcm_init_destructors: * Initialise the destructor list. */ void _al_kcm_init_destructors(void) { if (!kcm_dtors) { kcm_dtors = _al_init_destructors(); } } /* _al_kcm_shutdown_destructors: * Run all destructors and free the destructor list. */ void _al_kcm_shutdown_destructors(void) { if (kcm_dtors) { _al_run_destructors(kcm_dtors); _al_shutdown_destructors(kcm_dtors); kcm_dtors = NULL; } } /* _al_kcm_register_destructor: * Register an object to be destroyed. */ _AL_LIST_ITEM *_al_kcm_register_destructor(char const *name, void *object, void (*func)(void*)) { return _al_register_destructor(kcm_dtors, name, object, func); } /* _al_kcm_unregister_destructor: * Unregister an object to be destroyed. */ void _al_kcm_unregister_destructor(_AL_LIST_ITEM *dtor_item) { _al_unregister_destructor(kcm_dtors, dtor_item); } /* _al_kcm_foreach_destructor: * Call the callback for each registered object. */ void _al_kcm_foreach_destructor( void (*callback)(void *object, void (*func)(void *), void *udata), void *userdata) { _al_foreach_destructor(kcm_dtors, callback, userdata); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/kcm_instance.c000066400000000000000000000356301473414355200206420ustar00rootroot00000000000000/** * Originally digi.c from allegro wiki * Original authors: KC/Milan * * Converted to allegro5 by Ryan Dickie */ /* Title: Sample Instance functions */ #include #include #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_audio_cfg.h" static void maybe_lock_mutex(ALLEGRO_MUTEX *mutex) { if (mutex) { al_lock_mutex(mutex); } } static void maybe_unlock_mutex(ALLEGRO_MUTEX *mutex) { if (mutex) { al_unlock_mutex(mutex); } } /* _al_kcm_stream_set_mutex: * This function sets a sample's mutex pointer to the specified value. It is * ALLEGRO_MIXER aware, and will recursively set any attached streams' mutex * to the same value. */ void _al_kcm_stream_set_mutex(ALLEGRO_SAMPLE_INSTANCE *stream, ALLEGRO_MUTEX *mutex) { ASSERT(stream); if (stream->mutex == mutex) return; stream->mutex = mutex; /* If this is a mixer, we need to make sure all the attached streams also * set the same mutex. */ if (stream->is_mixer) { ALLEGRO_MIXER *mixer = (ALLEGRO_MIXER *)stream; int i; for (i = _al_vector_size(&mixer->streams) - 1; i >= 0; i--) { ALLEGRO_SAMPLE_INSTANCE **slot = _al_vector_ref(&mixer->streams, i); ALLEGRO_SAMPLE_INSTANCE *spl = *slot; _al_kcm_stream_set_mutex(spl, mutex); } } } /* stream_free: * This function is ALLEGRO_MIXER aware and frees the memory associated with * the sample or mixer, and detaches any attached streams or mixers. */ static void stream_free(ALLEGRO_SAMPLE_INSTANCE *spl) { if (spl) { /* Make sure we free the mixer buffer and de-reference the attached * streams if this is a mixer stream. */ if (spl->is_mixer) { ALLEGRO_MIXER *mixer = (ALLEGRO_MIXER *)spl; int i; _al_kcm_stream_set_mutex(&mixer->ss, NULL); for (i = _al_vector_size(&mixer->streams) - 1; i >= 0; i--) { ALLEGRO_SAMPLE_INSTANCE **slot = _al_vector_ref(&mixer->streams, i); ALLEGRO_SAMPLE_INSTANCE *spl = *slot; spl->parent.u.ptr = NULL; spl->spl_read = NULL; al_free(spl->matrix); spl->matrix = NULL; } _al_vector_free(&mixer->streams); if (spl->spl_data.buffer.ptr) { ASSERT(spl->spl_data.free_buf); al_free(spl->spl_data.buffer.ptr); spl->spl_data.buffer.ptr = NULL; } spl->spl_data.free_buf = false; } ASSERT(! spl->spl_data.free_buf); al_free(spl); } } /* _al_kcm_detach_from_parent: * This detaches the sample, stream, or mixer from anything it may be attached * to. */ void _al_kcm_detach_from_parent(ALLEGRO_SAMPLE_INSTANCE *spl) { ALLEGRO_MIXER *mixer; int i; if (!spl || !spl->parent.u.ptr) return; if (spl->parent.is_voice) { al_detach_voice(spl->parent.u.voice); return; } mixer = spl->parent.u.mixer; /* Search through the streams and check for this one */ for (i = _al_vector_size(&mixer->streams) - 1; i >= 0; i--) { ALLEGRO_SAMPLE_INSTANCE **slot = _al_vector_ref(&mixer->streams, i); if (*slot == spl) { maybe_lock_mutex(mixer->ss.mutex); _al_vector_delete_at(&mixer->streams, i); spl->parent.u.mixer = NULL; _al_kcm_stream_set_mutex(spl, NULL); spl->spl_read = NULL; maybe_unlock_mutex(mixer->ss.mutex); break; } } al_free(spl->matrix); spl->matrix = NULL; } /* Function: al_create_sample_instance */ ALLEGRO_SAMPLE_INSTANCE *al_create_sample_instance(ALLEGRO_SAMPLE *sample_data) { ALLEGRO_SAMPLE_INSTANCE *spl; spl = al_calloc(1, sizeof(*spl)); if (!spl) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Out of memory allocating sample object"); return NULL; } if (sample_data) { spl->spl_data = *sample_data; } spl->spl_data.free_buf = false; spl->loop = ALLEGRO_PLAYMODE_ONCE; spl->speed = 1.0f; spl->gain = 1.0f; spl->pan = 0.0f; spl->pos = 0; spl->loop_start = 0; spl->loop_end = sample_data ? sample_data->len : 0; spl->step = 0; spl->matrix = NULL; spl->is_mixer = false; spl->spl_read = NULL; spl->mutex = NULL; spl->parent.u.ptr = NULL; spl->dtor_item = _al_kcm_register_destructor("sample_instance", spl, (void (*)(void *))al_destroy_sample_instance); return spl; } /* This function is ALLEGRO_MIXER aware */ /* Function: al_destroy_sample_instance */ void al_destroy_sample_instance(ALLEGRO_SAMPLE_INSTANCE *spl) { _al_kcm_destroy_sample(spl, true); } /* Internal function: _al_kcm_destroy_sample */ void _al_kcm_destroy_sample(ALLEGRO_SAMPLE_INSTANCE *spl, bool unregister) { if (spl) { if (unregister) { _al_kcm_unregister_destructor(spl->dtor_item); } _al_kcm_detach_from_parent(spl); stream_free(spl); } } /* Function: al_play_sample_instance */ bool al_play_sample_instance(ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return al_set_sample_instance_playing(spl, true); } /* Function: al_stop_sample_instance */ bool al_stop_sample_instance(ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return al_set_sample_instance_playing(spl, false); } /* Function: al_get_sample_instance_frequency */ unsigned int al_get_sample_instance_frequency(const ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return spl->spl_data.frequency; } /* Function: al_get_sample_instance_length */ unsigned int al_get_sample_instance_length(const ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return spl->spl_data.len; } /* Function: al_get_sample_instance_position */ unsigned int al_get_sample_instance_position(const ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); if (spl->parent.u.ptr && spl->parent.is_voice) { ALLEGRO_VOICE *voice = spl->parent.u.voice; return al_get_voice_position(voice); } return spl->pos; } /* Function: al_get_sample_instance_speed */ float al_get_sample_instance_speed(const ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return spl->speed; } /* Function: al_get_sample_instance_gain */ float al_get_sample_instance_gain(const ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return spl->gain; } /* Function: al_get_sample_instance_pan */ float al_get_sample_instance_pan(const ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return spl->pan; } /* Function: al_get_sample_instance_time */ float al_get_sample_instance_time(const ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return (float)(spl->spl_data.len) / (float)spl->spl_data.frequency; } /* Function: al_get_sample_instance_depth */ ALLEGRO_AUDIO_DEPTH al_get_sample_instance_depth(const ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return spl->spl_data.depth; } /* Function: al_get_sample_instance_channels */ ALLEGRO_CHANNEL_CONF al_get_sample_instance_channels( const ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return spl->spl_data.chan_conf; } /* Function: al_get_sample_instance_playmode */ ALLEGRO_PLAYMODE al_get_sample_instance_playmode(const ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return spl->loop; } /* Function: al_get_sample_instance_playing */ bool al_get_sample_instance_playing(const ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); if (spl->parent.u.ptr && spl->parent.is_voice) { ALLEGRO_VOICE *voice = spl->parent.u.voice; return al_get_voice_playing(voice); } return spl->is_playing; } /* Function: al_get_sample_instance_attached */ bool al_get_sample_instance_attached(const ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return (spl->parent.u.ptr != NULL); } /* Function: al_set_sample_instance_position */ bool al_set_sample_instance_position(ALLEGRO_SAMPLE_INSTANCE *spl, unsigned int val) { ASSERT(spl); if (spl->parent.u.ptr && spl->parent.is_voice) { ALLEGRO_VOICE *voice = spl->parent.u.voice; if (!al_set_voice_position(voice, val)) return false; } else { maybe_lock_mutex(spl->mutex); spl->pos = val; maybe_unlock_mutex(spl->mutex); } return true; } /* Function: al_set_sample_instance_length */ bool al_set_sample_instance_length(ALLEGRO_SAMPLE_INSTANCE *spl, unsigned int val) { ASSERT(spl); if (spl->is_playing) { _al_set_error(ALLEGRO_INVALID_OBJECT, "Attempted to change the length of a playing sample"); return false; } spl->spl_data.len = val; spl->loop_end = val; return true; } /* Function: al_set_sample_instance_speed */ bool al_set_sample_instance_speed(ALLEGRO_SAMPLE_INSTANCE *spl, float val) { ASSERT(spl); if (fabsf(val) < (1.0f/64.0f)) { _al_set_error(ALLEGRO_INVALID_PARAM, "Attempted to set zero speed"); return false; } if (spl->parent.u.ptr && spl->parent.is_voice) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Could not set voice playback speed"); return false; } spl->speed = val; if (spl->parent.u.mixer) { ALLEGRO_MIXER *mixer = spl->parent.u.mixer; maybe_lock_mutex(spl->mutex); spl->step = (spl->spl_data.frequency) * spl->speed; spl->step_denom = mixer->ss.spl_data.frequency; /* Don't wanna be trapped with a step value of 0 */ if (spl->step == 0) { if (spl->speed > 0.0f) spl->step = 1; else spl->step = -1; } maybe_unlock_mutex(spl->mutex); } return true; } /* Function: al_set_sample_instance_gain */ bool al_set_sample_instance_gain(ALLEGRO_SAMPLE_INSTANCE *spl, float val) { ASSERT(spl); if (spl->parent.u.ptr && spl->parent.is_voice) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Could not set gain of sample attached to voice"); return false; } if (spl->gain != val) { spl->gain = val; /* If attached to a mixer already, need to recompute the sample * matrix to take into account the gain. */ if (spl->parent.u.mixer) { ALLEGRO_MIXER *mixer = spl->parent.u.mixer; maybe_lock_mutex(spl->mutex); _al_kcm_mixer_rejig_sample_matrix(mixer, spl); maybe_unlock_mutex(spl->mutex); } } return true; } /* Function: al_set_sample_instance_pan */ bool al_set_sample_instance_pan(ALLEGRO_SAMPLE_INSTANCE *spl, float val) { ASSERT(spl); if (spl->parent.u.ptr && spl->parent.is_voice) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Could not set panning of sample attached to voice"); return false; } if (val != ALLEGRO_AUDIO_PAN_NONE && (val < -1.0 || val > 1.0)) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Invalid pan value"); return false; } if (spl->pan != val) { spl->pan = val; /* If attached to a mixer already, need to recompute the sample * matrix to take into account the panning. */ if (spl->parent.u.mixer) { ALLEGRO_MIXER *mixer = spl->parent.u.mixer; maybe_lock_mutex(spl->mutex); _al_kcm_mixer_rejig_sample_matrix(mixer, spl); maybe_unlock_mutex(spl->mutex); } } return true; } /* Function: al_set_sample_instance_playmode */ bool al_set_sample_instance_playmode(ALLEGRO_SAMPLE_INSTANCE *spl, ALLEGRO_PLAYMODE val) { ASSERT(spl); if (val < ALLEGRO_PLAYMODE_ONCE || val > ALLEGRO_PLAYMODE_BIDIR) { _al_set_error(ALLEGRO_INVALID_PARAM, "Invalid loop mode"); return false; } maybe_lock_mutex(spl->mutex); spl->loop = val; if (spl->loop != ALLEGRO_PLAYMODE_ONCE) { if (spl->pos < spl->loop_start) spl->pos = spl->loop_start; else if (spl->pos > spl->loop_end-1) spl->pos = spl->loop_end-1; } maybe_unlock_mutex(spl->mutex); return true; } /* Function: al_set_sample_instance_playing */ bool al_set_sample_instance_playing(ALLEGRO_SAMPLE_INSTANCE *spl, bool val) { ASSERT(spl); if (!spl->parent.u.ptr || !spl->spl_data.buffer.ptr) { spl->is_playing = val; return true; } if (spl->parent.is_voice) { /* parent is voice */ ALLEGRO_VOICE *voice = spl->parent.u.voice; return al_set_voice_playing(voice, val); } /* parent is mixer */ maybe_lock_mutex(spl->mutex); spl->is_playing = val; if (!val) spl->pos = 0; maybe_unlock_mutex(spl->mutex); return true; } /* Function: al_detach_sample_instance */ bool al_detach_sample_instance(ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); _al_kcm_detach_from_parent(spl); ASSERT(spl->spl_read == NULL); return true; } /* Function: al_set_sample */ bool al_set_sample(ALLEGRO_SAMPLE_INSTANCE *spl, ALLEGRO_SAMPLE *data) { sample_parent_t old_parent; bool need_reattach; ASSERT(spl); /* Stop the sample if it is playing. */ if (spl->is_playing) { if (!al_set_sample_instance_playing(spl, false)) { /* Shouldn't happen. */ ASSERT(false); return false; } } if (!data) { if (spl->parent.u.ptr) { _al_kcm_detach_from_parent(spl); } spl->spl_data.buffer.ptr = NULL; return true; } /* Have data. */ need_reattach = false; if (spl->parent.u.ptr != NULL) { if (spl->spl_data.frequency != data->frequency || spl->spl_data.depth != data->depth || spl->spl_data.chan_conf != data->chan_conf) { old_parent = spl->parent; need_reattach = true; _al_kcm_detach_from_parent(spl); } } spl->spl_data = *data; spl->spl_data.free_buf = false; spl->pos = 0; spl->loop_start = 0; spl->loop_end = data->len; /* Should we reset the loop mode? */ if (need_reattach) { if (old_parent.is_voice) { if (!al_attach_sample_instance_to_voice(spl, old_parent.u.voice)) { spl->spl_data.buffer.ptr = NULL; return false; } } else { if (!al_attach_sample_instance_to_mixer(spl, old_parent.u.mixer)) { spl->spl_data.buffer.ptr = NULL; return false; } } } return true; } /* Function: al_get_sample */ ALLEGRO_SAMPLE *al_get_sample(ALLEGRO_SAMPLE_INSTANCE *spl) { ASSERT(spl); return &(spl->spl_data); } /* Function: al_set_sample_instance_channel_matrix */ bool al_set_sample_instance_channel_matrix(ALLEGRO_SAMPLE_INSTANCE *spl, const float *matrix) { ASSERT(spl); ASSERT(matrix); if (spl->parent.u.ptr && spl->parent.is_voice) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Could not set channel matrix of sample attached to voice"); return false; } if (spl->parent.u.mixer) { ALLEGRO_MIXER *mixer = spl->parent.u.mixer; size_t dst_chans = al_get_channel_count(mixer->ss.spl_data.chan_conf); size_t src_chans = al_get_channel_count(spl->spl_data.chan_conf); ASSERT(spl->matrix); maybe_lock_mutex(spl->mutex); memcpy(spl->matrix, matrix, dst_chans * src_chans * sizeof(float)); maybe_unlock_mutex(spl->mutex); } return true; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/kcm_mixer.c000066400000000000000000000762021473414355200201620ustar00rootroot00000000000000/** * Originally digi.c from allegro wiki * Original authors: KC/Milan * * Converted to allegro5 by Ryan Dickie */ /* Title: Mixer functions */ #include #include #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_audio_cfg.h" ALLEGRO_DEBUG_CHANNEL("audio") typedef union { float f32[ALLEGRO_MAX_CHANNELS]; /* max: 7.1 */ int16_t s16[ALLEGRO_MAX_CHANNELS]; void *ptr; } SAMP_BUF; static void maybe_lock_mutex(ALLEGRO_MUTEX *mutex) { if (mutex) { al_lock_mutex(mutex); } } static void maybe_unlock_mutex(ALLEGRO_MUTEX *mutex) { if (mutex) { al_unlock_mutex(mutex); } } /* _al_rechannel_matrix: * This function provides a (temporary!) matrix that can be used to convert * one channel configuration into another. * * Returns a pointer to a statically allocated array. */ static float *_al_rechannel_matrix(ALLEGRO_CHANNEL_CONF orig, ALLEGRO_CHANNEL_CONF target, float gain, float pan) { /* Max 7.1 (8 channels) for input and output */ static float mat[ALLEGRO_MAX_CHANNELS][ALLEGRO_MAX_CHANNELS]; size_t dst_chans = al_get_channel_count(target); size_t src_chans = al_get_channel_count(orig); size_t i, j; /* Start with a simple identity matrix */ memset(mat, 0, sizeof(mat)); for (i = 0; i < src_chans && i < dst_chans; i++) { mat[i][i] = 1.0; } /* Multi-channel -> mono conversion (cuts rear/side channels) */ if (dst_chans == 1 && (orig>>4) > 1) { for (i = 0; i < 2; i++) { mat[0][i] = 1.0 / sqrt(2.0); } /* If the source has a center channel, make sure that's copied 1:1 * (perhaps it should scale the overall output?) */ if ((orig >> 4) & 1) { mat[0][(orig >> 4) - 1] = 1.0; } } /* Center (or mono) -> front l/r conversion */ else if (((orig >> 4) & 1) && !((target >> 4) & 1)) { mat[0][(orig >> 4) - 1] = 1.0 / sqrt(2.0); mat[1][(orig >> 4) - 1] = 1.0 / sqrt(2.0); } /* Copy LFE */ if ((orig >> 4) != (target >> 4) && (orig & 0xF) && (target & 0xF)) { mat[dst_chans-1][src_chans-1] = 1.0; } /* Apply panning, which is supposed to maintain a constant power level. * I took that to mean we want: * sqrt(rgain^2 + lgain^2) = 1.0 */ if (pan != ALLEGRO_AUDIO_PAN_NONE) { float rgain = sqrt(( pan + 1.0f) / 2.0f); float lgain = sqrt((-pan + 1.0f) / 2.0f); /* I dunno what to do about >2 channels, so don't even try for now. */ for (j = 0; j < src_chans; j++) { mat[0][j] *= lgain; mat[1][j] *= rgain; } } /* Apply gain */ if (gain != 1.0f) { for (i = 0; i < dst_chans; i++) { for (j = 0; j < src_chans; j++) { mat[i][j] *= gain; } } } #ifdef DEBUGMODE { char debug[1024]; ALLEGRO_DEBUG("sample matrix:\n"); for (i = 0; i < dst_chans; i++) { strcpy(debug, ""); for (j = 0; j < src_chans; j++) { sprintf(debug + strlen(debug), " %f", mat[i][j]); } ALLEGRO_DEBUG("%s\n", debug); } } #endif return &mat[0][0]; } /* _al_kcm_mixer_rejig_sample_matrix: * Recompute the mixing matrix for a sample attached to a mixer. * The caller must be holding the mixer mutex. */ void _al_kcm_mixer_rejig_sample_matrix(ALLEGRO_MIXER *mixer, ALLEGRO_SAMPLE_INSTANCE *spl) { float *mat; size_t dst_chans; size_t src_chans; size_t i, j; mat = _al_rechannel_matrix(spl->spl_data.chan_conf, mixer->ss.spl_data.chan_conf, spl->gain, spl->pan); dst_chans = al_get_channel_count(mixer->ss.spl_data.chan_conf); src_chans = al_get_channel_count(spl->spl_data.chan_conf); if (!spl->matrix) spl->matrix = al_calloc(1, src_chans * dst_chans * sizeof(float)); for (i = 0; i < dst_chans; i++) { for (j = 0; j < src_chans; j++) { spl->matrix[i*src_chans + j] = mat[i*ALLEGRO_MAX_CHANNELS + j]; } } } /* fix_looped_position: * When a stream loops, this will fix up the position and anything else to * allow it to safely continue playing as expected. Returns false if it * should stop being mixed. */ static bool fix_looped_position(ALLEGRO_SAMPLE_INSTANCE *spl) { bool is_empty; ALLEGRO_AUDIO_STREAM *stream; /* Looping! Should be mostly self-explanatory */ switch (spl->loop) { case ALLEGRO_PLAYMODE_LOOP: if (spl->loop_end - spl->loop_start != 0) { if (spl->step > 0) { while (spl->pos >= spl->loop_end) { spl->pos -= (spl->loop_end - spl->loop_start); } } else if (spl->step < 0) { while (spl->pos < spl->loop_start) { spl->pos += (spl->loop_end - spl->loop_start); } } } return true; case ALLEGRO_PLAYMODE_BIDIR: /* When doing bi-directional looping, you need to do a follow-up * check for the opposite direction if a loop occurred, otherwise * you could end up misplaced on small, high-step loops. */ if (spl->loop_end - spl->loop_start != 0) { if (spl->step >= 0) { check_forward: if (spl->pos >= spl->loop_end) { spl->step = -spl->step; spl->pos = spl->loop_end - (spl->pos - spl->loop_end) - 1; goto check_backward; } } else { check_backward: if (spl->pos < spl->loop_start || spl->pos >= spl->loop_end) { spl->step = -spl->step; spl->pos = spl->loop_start + (spl->loop_start - spl->pos); goto check_forward; } } } return true; case ALLEGRO_PLAYMODE_LOOP_ONCE: if (spl->pos < spl->loop_end && spl->pos >= 0) { return true; } if (spl->step >= 0) spl->pos = 0; else spl->pos = spl->loop_end - 1; spl->is_playing = false; return false; case ALLEGRO_PLAYMODE_ONCE: if (spl->pos < spl->spl_data.len && spl->pos >= 0) { return true; } if (spl->step >= 0) spl->pos = 0; else spl->pos = spl->spl_data.len - 1; spl->is_playing = false; return false; case _ALLEGRO_PLAYMODE_STREAM_ONCE: case _ALLEGRO_PLAYMODE_STREAM_LOOP_ONCE: case _ALLEGRO_PLAYMODE_STREAM_ONEDIR: stream = (ALLEGRO_AUDIO_STREAM *)spl; is_empty = false; while (spl->pos >= spl->spl_data.len && stream->spl.is_playing && !is_empty) { is_empty = !_al_kcm_refill_stream(stream); if (is_empty && stream->is_draining) { stream->spl.is_playing = false; } _al_kcm_emit_stream_events(stream); } return !(is_empty); } ASSERT(false); return false; } #include "kcm_mixer_helpers.inc" static INLINE int32_t clamp(int32_t val, int32_t min, int32_t max) { /* Clamp to min */ val -= min; val &= (~val) >> 31; val += min; /* Clamp to max */ val -= max; val &= val >> 31; val += max; return val; } /* Mix as many sample values as possible from the source sample into a mixer * buffer. Implements stream_reader_t. * * TYPE is the type of the sample values in the mixer buffer, and * NEXT_SAMPLE_VALUE must return a buffer of the same type. * * Note: Uses Bresenham to keep the precise sample position. */ #define BRESENHAM \ do { \ delta = spl->step > 0 ? spl->step : spl->step - spl->step_denom + 1; \ delta /= spl->step_denom; \ delta_error = spl->step - delta * spl->step_denom; \ } while (0) #define MAKE_MIXER(NAME, NEXT_SAMPLE_VALUE, TYPE) \ static void NAME(void *source, void **vbuf, unsigned int *samples, \ ALLEGRO_AUDIO_DEPTH buffer_depth, size_t dest_maxc) \ { \ ALLEGRO_SAMPLE_INSTANCE *spl = (ALLEGRO_SAMPLE_INSTANCE *)source; \ TYPE *buf = *vbuf; \ size_t maxc = al_get_channel_count(spl->spl_data.chan_conf); \ size_t samples_l = *samples; \ size_t c; \ int delta, delta_error; \ SAMP_BUF samp_buf; \ \ BRESENHAM; \ \ if (!spl->is_playing) \ return; \ \ while (samples_l > 0) { \ const TYPE *s; \ int old_step = spl->step; \ \ if (!fix_looped_position(spl)) \ return; \ if (old_step != spl->step) { \ BRESENHAM; \ } \ \ /* It might be worth preparing multiple sample values at once. */ \ s = (TYPE *) NEXT_SAMPLE_VALUE(&samp_buf, spl, maxc); \ \ for (c = 0; c < dest_maxc; c++) { \ ALLEGRO_STATIC_ASSERT(kcm_mixer, ALLEGRO_MAX_CHANNELS == 8); \ switch (maxc) { \ case 8: *buf += s[7] * spl->matrix[c*maxc + 7]; \ /* fall through */ \ case 7: *buf += s[6] * spl->matrix[c*maxc + 6]; \ /* fall through */ \ case 6: *buf += s[5] * spl->matrix[c*maxc + 5]; \ /* fall through */ \ case 5: *buf += s[4] * spl->matrix[c*maxc + 4]; \ /* fall through */ \ case 4: *buf += s[3] * spl->matrix[c*maxc + 3]; \ /* fall through */ \ case 3: *buf += s[2] * spl->matrix[c*maxc + 2]; \ /* fall through */ \ case 2: *buf += s[1] * spl->matrix[c*maxc + 1]; \ /* fall through */ \ case 1: *buf += s[0] * spl->matrix[c*maxc + 0]; \ /* fall through */ \ default: break; \ } \ buf++; \ } \ \ spl->pos += delta; \ spl->pos_bresenham_error += delta_error; \ if (spl->pos_bresenham_error >= spl->step_denom) { \ spl->pos++; \ spl->pos_bresenham_error -= spl->step_denom; \ } \ samples_l--; \ } \ fix_looped_position(spl); \ (void)buffer_depth; \ } MAKE_MIXER(read_to_mixer_point_float_32, point_spl32, float) MAKE_MIXER(read_to_mixer_linear_float_32, linear_spl32, float) MAKE_MIXER(read_to_mixer_cubic_float_32, cubic_spl32, float) MAKE_MIXER(read_to_mixer_point_int16_t_16, point_spl16, int16_t) MAKE_MIXER(read_to_mixer_linear_int16_t_16, linear_spl16, int16_t) #undef MAKE_MIXER /* _al_kcm_mixer_read: * Mixes the streams attached to the mixer and writes additively to the * specified buffer (or if *buf is NULL, indicating a voice, convert it and * set it to the buffer pointer). */ void _al_kcm_mixer_read(void *source, void **buf, unsigned int *samples, ALLEGRO_AUDIO_DEPTH buffer_depth, size_t dest_maxc) { const ALLEGRO_MIXER *mixer; ALLEGRO_MIXER *m = (ALLEGRO_MIXER *)source; int maxc = al_get_channel_count(m->ss.spl_data.chan_conf); int samples_l = *samples; int i; if (!m->ss.is_playing) return; /* Make sure the mixer buffer is big enough. */ if (m->ss.spl_data.len*maxc < samples_l*maxc) { al_free(m->ss.spl_data.buffer.ptr); m->ss.spl_data.buffer.ptr = al_malloc(samples_l*maxc*al_get_audio_depth_size(m->ss.spl_data.depth)); if (!m->ss.spl_data.buffer.ptr) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Out of memory allocating mixer buffer"); m->ss.spl_data.len = 0; return; } m->ss.spl_data.len = samples_l; } mixer = m; /* Clear the buffer to silence. */ memset(mixer->ss.spl_data.buffer.ptr, 0, samples_l * maxc * al_get_audio_depth_size(mixer->ss.spl_data.depth)); /* Mix the streams into the mixer buffer. */ for (i = _al_vector_size(&mixer->streams) - 1; i >= 0; i--) { ALLEGRO_SAMPLE_INSTANCE **slot = _al_vector_ref(&mixer->streams, i); ALLEGRO_SAMPLE_INSTANCE *spl = *slot; ASSERT(spl->spl_read); spl->spl_read(spl, (void **) &mixer->ss.spl_data.buffer.ptr, samples, m->ss.spl_data.depth, maxc); } /* Call the post-processing callback. */ if (mixer->postprocess_callback) { mixer->postprocess_callback(mixer->ss.spl_data.buffer.ptr, *samples, mixer->pp_callback_userdata); } samples_l *= maxc; /* Apply the gain if necessary. */ if (mixer->ss.gain != 1.0f) { float mixer_gain = mixer->ss.gain; unsigned long i = samples_l; switch (m->ss.spl_data.depth) { case ALLEGRO_AUDIO_DEPTH_FLOAT32: { float *p = mixer->ss.spl_data.buffer.f32; while (i-- > 0) { *p++ *= mixer_gain; } break; } case ALLEGRO_AUDIO_DEPTH_INT16: { int16_t *p = mixer->ss.spl_data.buffer.s16; while (i-- > 0) { *p++ *= mixer_gain; } break; } case ALLEGRO_AUDIO_DEPTH_INT8: case ALLEGRO_AUDIO_DEPTH_INT24: case ALLEGRO_AUDIO_DEPTH_UINT8: case ALLEGRO_AUDIO_DEPTH_UINT16: case ALLEGRO_AUDIO_DEPTH_UINT24: /* Unsupported mixer depths. */ ASSERT(false); break; } } /* Feeding to a non-voice. * Currently we only support mixers of the same audio depth doing this. */ if (*buf) { switch (m->ss.spl_data.depth) { case ALLEGRO_AUDIO_DEPTH_FLOAT32: { /* We don't need to clamp in the mixer yet. */ float *lbuf = *buf; float *src = mixer->ss.spl_data.buffer.f32; while (samples_l-- > 0) { *lbuf += *src; lbuf++; src++; } break; case ALLEGRO_AUDIO_DEPTH_INT16: { int16_t *lbuf = *buf; int16_t *src = mixer->ss.spl_data.buffer.s16; while (samples_l-- > 0) { int32_t x = *lbuf + *src; if (x < -32768) x = -32768; else if (x > 32767) x = 32767; *lbuf = (int16_t)x; lbuf++; src++; } break; } case ALLEGRO_AUDIO_DEPTH_INT8: case ALLEGRO_AUDIO_DEPTH_INT24: case ALLEGRO_AUDIO_DEPTH_UINT8: case ALLEGRO_AUDIO_DEPTH_UINT16: case ALLEGRO_AUDIO_DEPTH_UINT24: /* Unsupported mixer depths. */ ASSERT(false); break; } } return; } /* We're feeding to a voice. * Clamp and convert the mixed data for the voice. */ *buf = mixer->ss.spl_data.buffer.ptr; switch (buffer_depth & ~ALLEGRO_AUDIO_DEPTH_UNSIGNED) { case ALLEGRO_AUDIO_DEPTH_FLOAT32: /* Do we need to clamp? */ break; case ALLEGRO_AUDIO_DEPTH_INT24: switch (mixer->ss.spl_data.depth) { case ALLEGRO_AUDIO_DEPTH_FLOAT32: { int32_t off = ((buffer_depth & ALLEGRO_AUDIO_DEPTH_UNSIGNED) ? 0x800000 : 0); int32_t *lbuf = mixer->ss.spl_data.buffer.s24; float *src = mixer->ss.spl_data.buffer.f32; while (samples_l > 0) { *lbuf = clamp(*(src++) * ((float)0x7FFFFF + 0.5f), ~0x7FFFFF, 0x7FFFFF); *lbuf += off; lbuf++; samples_l--; } break; } case ALLEGRO_AUDIO_DEPTH_INT16: /* XXX not yet implemented */ ASSERT(false); break; case ALLEGRO_AUDIO_DEPTH_INT8: case ALLEGRO_AUDIO_DEPTH_INT24: case ALLEGRO_AUDIO_DEPTH_UINT8: case ALLEGRO_AUDIO_DEPTH_UINT16: case ALLEGRO_AUDIO_DEPTH_UINT24: /* Unsupported mixer depths. */ ASSERT(false); break; } break; case ALLEGRO_AUDIO_DEPTH_INT16: switch (mixer->ss.spl_data.depth) { case ALLEGRO_AUDIO_DEPTH_FLOAT32: { int16_t off = ((buffer_depth & ALLEGRO_AUDIO_DEPTH_UNSIGNED) ? 0x8000 : 0); int16_t *lbuf = mixer->ss.spl_data.buffer.s16; float *src = mixer->ss.spl_data.buffer.f32; while (samples_l > 0) { *lbuf = clamp(*(src++) * ((float)0x7FFF + 0.5f), ~0x7FFF, 0x7FFF); *lbuf += off; lbuf++; samples_l--; } break; } case ALLEGRO_AUDIO_DEPTH_INT16: /* Handle signedness differences. */ if (buffer_depth != ALLEGRO_AUDIO_DEPTH_INT16) { int16_t *lbuf = mixer->ss.spl_data.buffer.s16; while (samples_l > 0) { *lbuf++ ^= 0x8000; samples_l--; } } break; case ALLEGRO_AUDIO_DEPTH_INT8: case ALLEGRO_AUDIO_DEPTH_INT24: case ALLEGRO_AUDIO_DEPTH_UINT8: case ALLEGRO_AUDIO_DEPTH_UINT16: case ALLEGRO_AUDIO_DEPTH_UINT24: /* Unsupported mixer depths. */ ASSERT(false); break; } break; /* Ugh, do we really want to support 8-bit output? */ case ALLEGRO_AUDIO_DEPTH_INT8: switch (mixer->ss.spl_data.depth) { case ALLEGRO_AUDIO_DEPTH_FLOAT32: { int8_t off = ((buffer_depth & ALLEGRO_AUDIO_DEPTH_UNSIGNED) ? 0x80 : 0); int8_t *lbuf = mixer->ss.spl_data.buffer.s8; float *src = mixer->ss.spl_data.buffer.f32; while (samples_l > 0) { *lbuf = clamp(*(src++) * ((float)0x7F + 0.5f), ~0x7F, 0x7F); *lbuf += off; lbuf++; samples_l--; } break; } case ALLEGRO_AUDIO_DEPTH_INT16: /* XXX not yet implemented */ ASSERT(false); break; case ALLEGRO_AUDIO_DEPTH_INT8: case ALLEGRO_AUDIO_DEPTH_INT24: case ALLEGRO_AUDIO_DEPTH_UINT8: case ALLEGRO_AUDIO_DEPTH_UINT16: case ALLEGRO_AUDIO_DEPTH_UINT24: /* Unsupported mixer depths. */ ASSERT(false); break; } break; case ALLEGRO_AUDIO_DEPTH_UINT8: case ALLEGRO_AUDIO_DEPTH_UINT16: case ALLEGRO_AUDIO_DEPTH_UINT24: /* Impossible. */ ASSERT(false); break; } (void)dest_maxc; } /* Function: al_create_mixer */ ALLEGRO_MIXER *al_create_mixer(unsigned int freq, ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf) { ALLEGRO_MIXER *mixer; int default_mixer_quality = ALLEGRO_MIXER_QUALITY_LINEAR; const char *p; /* XXX this is in the wrong place */ p = al_get_config_value(al_get_system_config(), "audio", "default_mixer_quality"); if (p && p[0] != '\0') { if (!_al_stricmp(p, "point")) { ALLEGRO_INFO("Point sampling\n"); default_mixer_quality = ALLEGRO_MIXER_QUALITY_POINT; } else if (!_al_stricmp(p, "linear")) { ALLEGRO_INFO("Linear interpolation\n"); default_mixer_quality = ALLEGRO_MIXER_QUALITY_LINEAR; } else if (!_al_stricmp(p, "cubic")) { ALLEGRO_INFO("Cubic interpolation\n"); default_mixer_quality = ALLEGRO_MIXER_QUALITY_CUBIC; } } if (!freq) { _al_set_error(ALLEGRO_INVALID_PARAM, "Attempted to create mixer with no frequency"); return NULL; } if (depth != ALLEGRO_AUDIO_DEPTH_FLOAT32 && depth != ALLEGRO_AUDIO_DEPTH_INT16) { _al_set_error(ALLEGRO_INVALID_PARAM, "Unsupported mixer depth"); return NULL; } mixer = al_calloc(1, sizeof(ALLEGRO_MIXER)); if (!mixer) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Out of memory allocating mixer object"); return NULL; } mixer->ss.is_playing = true; mixer->ss.spl_data.free_buf = true; mixer->ss.loop = ALLEGRO_PLAYMODE_ONCE; /* XXX should we have a specific loop mode? */ mixer->ss.gain = 1.0f; mixer->ss.spl_data.depth = depth; mixer->ss.spl_data.chan_conf = chan_conf; mixer->ss.spl_data.frequency = freq; mixer->ss.is_mixer = true; mixer->ss.spl_read = NULL; mixer->quality = default_mixer_quality; _al_vector_init(&mixer->streams, sizeof(ALLEGRO_SAMPLE_INSTANCE *)); mixer->dtor_item = _al_kcm_register_destructor("mixer", mixer, (void (*)(void *)) al_destroy_mixer); return mixer; } /* Function: al_destroy_mixer */ void al_destroy_mixer(ALLEGRO_MIXER *mixer) { if (mixer) { _al_kcm_unregister_destructor(mixer->dtor_item); _al_kcm_destroy_sample(&mixer->ss, false); } } /* This function is ALLEGRO_MIXER aware */ /* Function: al_attach_sample_instance_to_mixer */ bool al_attach_sample_instance_to_mixer(ALLEGRO_SAMPLE_INSTANCE *spl, ALLEGRO_MIXER *mixer) { ALLEGRO_SAMPLE_INSTANCE **slot; ASSERT(mixer); ASSERT(spl); /* Already referenced, do not attach. */ if (spl->parent.u.ptr) { _al_set_error(ALLEGRO_INVALID_OBJECT, "Attempted to attach a sample that's already attached"); return false; } maybe_lock_mutex(mixer->ss.mutex); _al_kcm_stream_set_mutex(spl, mixer->ss.mutex); slot = _al_vector_alloc_back(&mixer->streams); if (!slot) { if (mixer->ss.mutex) { al_unlock_mutex(mixer->ss.mutex); } _al_set_error(ALLEGRO_GENERIC_ERROR, "Out of memory allocating attachment pointers"); return false; } (*slot) = spl; spl->step = (spl->spl_data.frequency) * spl->speed; spl->step_denom = mixer->ss.spl_data.frequency; /* Don't want to be trapped with a step value of 0. */ if (spl->step == 0) { if (spl->speed > 0.0f) spl->step = 1; else spl->step = -1; } /* Set the proper sample stream reader. */ ASSERT(spl->spl_read == NULL); if (spl->is_mixer) { spl->spl_read = _al_kcm_mixer_read; } else { switch (mixer->ss.spl_data.depth) { case ALLEGRO_AUDIO_DEPTH_FLOAT32: switch (mixer->quality) { case ALLEGRO_MIXER_QUALITY_POINT: spl->spl_read = read_to_mixer_point_float_32; break; case ALLEGRO_MIXER_QUALITY_LINEAR: spl->spl_read = read_to_mixer_linear_float_32; break; case ALLEGRO_MIXER_QUALITY_CUBIC: spl->spl_read = read_to_mixer_cubic_float_32; break; } break; case ALLEGRO_AUDIO_DEPTH_INT16: switch (mixer->quality) { case ALLEGRO_MIXER_QUALITY_POINT: spl->spl_read = read_to_mixer_point_int16_t_16; break; case ALLEGRO_MIXER_QUALITY_CUBIC: ALLEGRO_WARN("Falling back to linear interpolation\n"); /* fallthrough */ case ALLEGRO_MIXER_QUALITY_LINEAR: spl->spl_read = read_to_mixer_linear_int16_t_16; break; } break; case ALLEGRO_AUDIO_DEPTH_INT8: case ALLEGRO_AUDIO_DEPTH_INT24: case ALLEGRO_AUDIO_DEPTH_UINT8: case ALLEGRO_AUDIO_DEPTH_UINT16: case ALLEGRO_AUDIO_DEPTH_UINT24: /* Unsupported mixer depths. */ ASSERT(false); break; } _al_kcm_mixer_rejig_sample_matrix(mixer, spl); } spl->parent.u.mixer = mixer; spl->parent.is_voice = false; maybe_unlock_mutex(mixer->ss.mutex); return true; } /* Function: al_attach_audio_stream_to_mixer */ bool al_attach_audio_stream_to_mixer(ALLEGRO_AUDIO_STREAM *stream, ALLEGRO_MIXER *mixer) { ASSERT(mixer); ASSERT(stream); return al_attach_sample_instance_to_mixer(&stream->spl, mixer); } /* Function: al_attach_mixer_to_mixer */ bool al_attach_mixer_to_mixer(ALLEGRO_MIXER *stream, ALLEGRO_MIXER *mixer) { ASSERT(mixer); ASSERT(stream); ASSERT(mixer != stream); if (mixer->ss.spl_data.frequency != stream->ss.spl_data.frequency) { _al_set_error(ALLEGRO_INVALID_OBJECT, "Attempted to attach a mixer with different frequencies"); return false; } if (mixer->ss.spl_data.depth != stream->ss.spl_data.depth) { _al_set_error(ALLEGRO_INVALID_OBJECT, "Mixers of different audio depths cannot be attached to one another"); return false; } if (mixer->ss.spl_data.chan_conf != stream->ss.spl_data.chan_conf) { _al_set_error(ALLEGRO_INVALID_OBJECT, "Mixers of different channel configurations cannot be attached to one another"); return false; } return al_attach_sample_instance_to_mixer(&stream->ss, mixer); } /* Function: al_set_mixer_postprocess_callback */ bool al_set_mixer_postprocess_callback(ALLEGRO_MIXER *mixer, void (*pp_callback)(void *buf, unsigned int samples, void *data), void *pp_callback_userdata) { ASSERT(mixer); maybe_lock_mutex(mixer->ss.mutex); mixer->postprocess_callback = pp_callback; mixer->pp_callback_userdata = pp_callback_userdata; maybe_unlock_mutex(mixer->ss.mutex); return true; } /* Function: al_get_mixer_frequency */ unsigned int al_get_mixer_frequency(const ALLEGRO_MIXER *mixer) { ASSERT(mixer); return mixer->ss.spl_data.frequency; } /* Function: al_get_mixer_channels */ ALLEGRO_CHANNEL_CONF al_get_mixer_channels(const ALLEGRO_MIXER *mixer) { ASSERT(mixer); return mixer->ss.spl_data.chan_conf; } /* Function: al_get_mixer_depth */ ALLEGRO_AUDIO_DEPTH al_get_mixer_depth(const ALLEGRO_MIXER *mixer) { ASSERT(mixer); return mixer->ss.spl_data.depth; } /* Function: al_get_mixer_quality */ ALLEGRO_MIXER_QUALITY al_get_mixer_quality(const ALLEGRO_MIXER *mixer) { ASSERT(mixer); return mixer->quality; } /* Function: al_get_mixer_gain */ float al_get_mixer_gain(const ALLEGRO_MIXER *mixer) { ASSERT(mixer); return mixer->ss.gain; } /* Function: al_get_mixer_playing */ bool al_get_mixer_playing(const ALLEGRO_MIXER *mixer) { ASSERT(mixer); return mixer->ss.is_playing; } /* Function: al_get_mixer_attached */ bool al_get_mixer_attached(const ALLEGRO_MIXER *mixer) { ASSERT(mixer); return mixer->ss.parent.u.ptr; } /* Function: al_mixer_has_attachments */ bool al_mixer_has_attachments(const ALLEGRO_MIXER* mixer) { ASSERT(mixer); return _al_vector_is_nonempty(&mixer->streams); } /* Function: al_set_mixer_frequency */ bool al_set_mixer_frequency(ALLEGRO_MIXER *mixer, unsigned int val) { ASSERT(mixer); /* You can change the frequency of a mixer as long as it's not attached * to anything. */ if (mixer->ss.parent.u.ptr) { _al_set_error(ALLEGRO_INVALID_OBJECT, "Attempted to change the frequency of an attached mixer"); return false; } mixer->ss.spl_data.frequency = val; return true; } /* Function: al_set_mixer_quality */ bool al_set_mixer_quality(ALLEGRO_MIXER *mixer, ALLEGRO_MIXER_QUALITY new_quality) { bool ret; ASSERT(mixer); maybe_lock_mutex(mixer->ss.mutex); if (mixer->quality == new_quality) { ret = true; } else if (_al_vector_size(&mixer->streams) == 0) { mixer->quality = new_quality; ret = true; } else { _al_set_error(ALLEGRO_INVALID_OBJECT, "Attempted to change the quality of a mixer with attachments"); ret = false; } maybe_unlock_mutex(mixer->ss.mutex); return ret; } /* Function: al_set_mixer_gain */ bool al_set_mixer_gain(ALLEGRO_MIXER *mixer, float new_gain) { int i; ASSERT(mixer); maybe_lock_mutex(mixer->ss.mutex); if (mixer->ss.gain != new_gain) { mixer->ss.gain = new_gain; for (i = _al_vector_size(&mixer->streams) - 1; i >= 0; i--) { ALLEGRO_SAMPLE_INSTANCE **slot = _al_vector_ref(&mixer->streams, i); _al_kcm_mixer_rejig_sample_matrix(mixer, *slot); } } maybe_unlock_mutex(mixer->ss.mutex); return true; } /* Function: al_set_mixer_playing */ bool al_set_mixer_playing(ALLEGRO_MIXER *mixer, bool val) { ASSERT(mixer); mixer->ss.is_playing = val; return true; } /* Function: al_detach_mixer */ bool al_detach_mixer(ALLEGRO_MIXER *mixer) { ASSERT(mixer); _al_kcm_detach_from_parent(&mixer->ss); ASSERT(mixer->ss.spl_read == NULL); return true; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/kcm_sample.c000066400000000000000000000305541473414355200203170ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Sample audio interface. * * By Peter Wang. * * See LICENSE.txt for copyright information. */ /* Title: Sample audio interface */ #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_vector.h" ALLEGRO_DEBUG_CHANNEL("audio") static ALLEGRO_VOICE *allegro_voice = NULL; static ALLEGRO_MIXER *allegro_mixer = NULL; static ALLEGRO_MIXER *default_mixer = NULL; typedef struct AUTO_SAMPLE { ALLEGRO_SAMPLE_INSTANCE *instance; int id; bool locked; } AUTO_SAMPLE; static _AL_VECTOR auto_samples = _AL_VECTOR_INITIALIZER(AUTO_SAMPLE); static bool create_default_mixer(void); static bool do_play_sample(ALLEGRO_SAMPLE_INSTANCE *spl, ALLEGRO_SAMPLE *data, float gain, float pan, float speed, ALLEGRO_PLAYMODE loop); static void free_sample_vector(void); static int string_to_depth(const char *s) { // FIXME: fill in the rest if (!_al_stricmp(s, "int16")) { return ALLEGRO_AUDIO_DEPTH_INT16; } else { return ALLEGRO_AUDIO_DEPTH_FLOAT32; } } /* Creates the default voice and mixer if they haven't been created yet. */ static bool create_default_mixer(void) { int voice_frequency = 44100; int voice_depth = ALLEGRO_AUDIO_DEPTH_INT16; int mixer_frequency = 44100; int mixer_depth = ALLEGRO_AUDIO_DEPTH_FLOAT32; ALLEGRO_CONFIG *config = al_get_system_config(); const char *p; p = al_get_config_value(config, "audio", "primary_voice_frequency"); if (p && p[0] != '\0') { voice_frequency = atoi(p); } p = al_get_config_value(config, "audio", "primary_mixer_frequency"); if (p && p[0] != '\0') { mixer_frequency = atoi(p); } p = al_get_config_value(config, "audio", "primary_voice_depth"); if (p && p[0] != '\0') { voice_depth = string_to_depth(p); } p = al_get_config_value(config, "audio", "primary_mixer_depth"); if (p && p[0] != '\0') { mixer_depth = string_to_depth(p); } if (!allegro_voice) { allegro_voice = al_create_voice(voice_frequency, voice_depth, ALLEGRO_CHANNEL_CONF_2); if (!allegro_voice) { ALLEGRO_ERROR("al_create_voice failed\n"); goto Error; } } if (!allegro_mixer) { allegro_mixer = al_create_mixer(mixer_frequency, mixer_depth, ALLEGRO_CHANNEL_CONF_2); if (!allegro_mixer) { ALLEGRO_ERROR("al_create_voice failed\n"); goto Error; } } /* In case this function is called multiple times. */ al_detach_mixer(allegro_mixer); if (!al_attach_mixer_to_voice(allegro_mixer, allegro_voice)) { ALLEGRO_ERROR("al_attach_mixer_to_voice failed\n"); goto Error; } return true; Error: if (allegro_mixer) { al_destroy_mixer(allegro_mixer); allegro_mixer = NULL; } if (allegro_voice) { al_destroy_voice(allegro_voice); allegro_voice = NULL; } return false; } /* Function: al_create_sample */ ALLEGRO_SAMPLE *al_create_sample(void *buf, unsigned int samples, unsigned int freq, ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf, bool free_buf) { ALLEGRO_SAMPLE *spl; ASSERT(buf); if (!freq) { _al_set_error(ALLEGRO_INVALID_PARAM, "Invalid sample frequency"); return NULL; } spl = al_calloc(1, sizeof(*spl)); if (!spl) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Out of memory allocating sample data object"); return NULL; } spl->depth = depth; spl->chan_conf = chan_conf; spl->frequency = freq; spl->len = samples; spl->buffer.ptr = buf; spl->free_buf = free_buf; spl->dtor_item = _al_kcm_register_destructor("sample", spl, (void (*)(void *)) al_destroy_sample); return spl; } /* Stop any sample instances which are still playing a sample buffer which * is about to be destroyed. */ static void stop_sample_instances_helper(void *object, void (*func)(void *), void *userdata) { ALLEGRO_SAMPLE_INSTANCE *splinst = object; /* This is ugly. */ if (func == (void (*)(void *)) al_destroy_sample_instance && al_get_sample_data(al_get_sample(splinst)) == userdata && al_get_sample_instance_playing(splinst)) { al_stop_sample_instance(splinst); } } /* Function: al_destroy_sample */ void al_destroy_sample(ALLEGRO_SAMPLE *spl) { if (spl) { _al_kcm_foreach_destructor(stop_sample_instances_helper, al_get_sample_data(spl)); _al_kcm_unregister_destructor(spl->dtor_item); if (spl->free_buf && spl->buffer.ptr) { al_free(spl->buffer.ptr); } spl->buffer.ptr = NULL; spl->free_buf = false; al_free(spl); } } /* Function: al_reserve_samples */ bool al_reserve_samples(int reserve_samples) { int i; int current_samples_count = (int) _al_vector_size(&auto_samples); ASSERT(reserve_samples >= 0); /* If no default mixer has been set by the user, then create a voice * and a mixer, and set them to be the default one for use with * al_play_sample(). */ if (default_mixer == NULL) { if (!al_restore_default_mixer()) goto Error; } if (current_samples_count < reserve_samples) { /* We need to reserve more samples than currently are reserved. */ for (i = 0; i < reserve_samples - current_samples_count; i++) { AUTO_SAMPLE *slot = _al_vector_alloc_back(&auto_samples); slot->id = 0; slot->instance = al_create_sample_instance(NULL); slot->locked = false; if (!slot->instance) { ALLEGRO_ERROR("al_create_sample failed\n"); goto Error; } if (!al_attach_sample_instance_to_mixer(slot->instance, default_mixer)) { ALLEGRO_ERROR("al_attach_mixer_to_sample failed\n"); goto Error; } } } else if (current_samples_count > reserve_samples) { /* We need to reserve fewer samples than currently are reserved. */ while (current_samples_count-- > reserve_samples) { AUTO_SAMPLE *slot = _al_vector_ref(&auto_samples, current_samples_count); al_destroy_sample_instance(slot->instance); _al_vector_delete_at(&auto_samples, current_samples_count); } } return true; Error: free_sample_vector(); return false; } /* Function: al_get_default_mixer */ ALLEGRO_MIXER *al_get_default_mixer(void) { return default_mixer; } /* Function: al_set_default_mixer */ bool al_set_default_mixer(ALLEGRO_MIXER *mixer) { ASSERT(mixer != NULL); if (mixer != default_mixer) { int i; default_mixer = mixer; /* Destroy all current sample instances, recreate them, and * attach them to the new mixer */ for (i = 0; i < (int) _al_vector_size(&auto_samples); i++) { AUTO_SAMPLE *slot = _al_vector_ref(&auto_samples, i); slot->id = 0; al_destroy_sample_instance(slot->instance); slot->locked = false; slot->instance = al_create_sample_instance(NULL); if (!slot->instance) { ALLEGRO_ERROR("al_create_sample failed\n"); goto Error; } if (!al_attach_sample_instance_to_mixer(slot->instance, default_mixer)) { ALLEGRO_ERROR("al_attach_mixer_to_sample failed\n"); goto Error; } } } return true; Error: free_sample_vector(); default_mixer = NULL; return false; } /* Function: al_restore_default_mixer */ bool al_restore_default_mixer(void) { if (!create_default_mixer()) return false; if (!al_set_default_mixer(allegro_mixer)) return false; return true; } /* Function: al_get_default_voice */ ALLEGRO_VOICE *al_get_default_voice(void) { return allegro_voice; } /* Function: al_set_default_voice */ void al_set_default_voice(ALLEGRO_VOICE *voice) { if (allegro_voice) { al_destroy_voice(allegro_voice); } allegro_voice = voice; } /* Function: al_play_sample */ bool al_play_sample(ALLEGRO_SAMPLE *spl, float gain, float pan, float speed, ALLEGRO_PLAYMODE loop, ALLEGRO_SAMPLE_ID *ret_id) { static int next_id = 0; unsigned int i; ASSERT(spl); if (ret_id != NULL) { ret_id->_id = -1; ret_id->_index = 0; } for (i = 0; i < _al_vector_size(&auto_samples); i++) { AUTO_SAMPLE *slot = _al_vector_ref(&auto_samples, i); if (!al_get_sample_instance_playing(slot->instance) && !slot->locked) { if (!do_play_sample(slot->instance, spl, gain, pan, speed, loop)) break; if (ret_id != NULL) { ret_id->_index = (int) i; ret_id->_id = slot->id = ++next_id; } return true; } } return false; } static bool do_play_sample(ALLEGRO_SAMPLE_INSTANCE *splinst, ALLEGRO_SAMPLE *spl, float gain, float pan, float speed, ALLEGRO_PLAYMODE loop) { if (!al_set_sample(splinst, spl)) { ALLEGRO_ERROR("al_set_sample failed\n"); return false; } if (!al_set_sample_instance_gain(splinst, gain) || !al_set_sample_instance_pan(splinst, pan) || !al_set_sample_instance_speed(splinst, speed) || !al_set_sample_instance_playmode(splinst, loop)) { return false; } if (!al_play_sample_instance(splinst)) { ALLEGRO_ERROR("al_play_sample_instance failed\n"); return false; } return true; } /* Function: al_stop_sample */ void al_stop_sample(ALLEGRO_SAMPLE_ID *spl_id) { AUTO_SAMPLE *slot; ASSERT(spl_id->_id != -1); ASSERT(spl_id->_index < (int) _al_vector_size(&auto_samples)); slot = _al_vector_ref(&auto_samples, spl_id->_index); if (slot->id == spl_id->_id) { al_stop_sample_instance(slot->instance); } } /* Function: al_lock_sample_id */ ALLEGRO_SAMPLE_INSTANCE* al_lock_sample_id(ALLEGRO_SAMPLE_ID *spl_id) { AUTO_SAMPLE *slot; ASSERT(spl_id->_id != -1); ASSERT(spl_id->_index < (int) _al_vector_size(&auto_samples)); slot = _al_vector_ref(&auto_samples, spl_id->_index); if (slot->id == spl_id->_id) { slot->locked = true; return slot->instance; } return NULL; } /* Function: al_unlock_sample_id */ void al_unlock_sample_id(ALLEGRO_SAMPLE_ID *spl_id) { AUTO_SAMPLE *slot; ASSERT(spl_id->_id != -1); ASSERT(spl_id->_index < (int) _al_vector_size(&auto_samples)); slot = _al_vector_ref(&auto_samples, spl_id->_index); if (slot->id == spl_id->_id) { slot->locked = false; } } /* Function: al_stop_samples */ void al_stop_samples(void) { unsigned int i; for (i = 0; i < _al_vector_size(&auto_samples); i++) { AUTO_SAMPLE *slot = _al_vector_ref(&auto_samples, i); al_stop_sample_instance(slot->instance); } } /* Function: al_get_sample_frequency */ unsigned int al_get_sample_frequency(const ALLEGRO_SAMPLE *spl) { ASSERT(spl); return spl->frequency; } /* Function: al_get_sample_length */ unsigned int al_get_sample_length(const ALLEGRO_SAMPLE *spl) { ASSERT(spl); return spl->len; } /* Function: al_get_sample_depth */ ALLEGRO_AUDIO_DEPTH al_get_sample_depth(const ALLEGRO_SAMPLE *spl) { ASSERT(spl); return spl->depth; } /* Function: al_get_sample_channels */ ALLEGRO_CHANNEL_CONF al_get_sample_channels(const ALLEGRO_SAMPLE *spl) { ASSERT(spl); return spl->chan_conf; } /* Function: al_get_sample_data */ void *al_get_sample_data(const ALLEGRO_SAMPLE *spl) { ASSERT(spl); return spl->buffer.ptr; } /* Destroy all sample instances, and frees the associated vectors. */ static void free_sample_vector(void) { int j; for (j = 0; j < (int) _al_vector_size(&auto_samples); j++) { AUTO_SAMPLE *slot = _al_vector_ref(&auto_samples, j); al_destroy_sample_instance(slot->instance); } _al_vector_free(&auto_samples); } void _al_kcm_shutdown_default_mixer(void) { free_sample_vector(); al_destroy_mixer(allegro_mixer); al_destroy_voice(allegro_voice); allegro_mixer = NULL; allegro_voice = NULL; default_mixer = NULL; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/kcm_stream.c000066400000000000000000000612411473414355200203260ustar00rootroot00000000000000/** * Originally digi.c from allegro wiki * Original authors: KC/Milan * * Converted to allegro5 by Ryan Dickie */ /* Title: Stream functions */ #include #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_audio_cfg.h" ALLEGRO_DEBUG_CHANNEL("audio") /* * The highest quality interpolator is a cubic interpolator requiring * four sample points. In the streaming case we lag the true sample * position by three. */ #define MAX_LAG (3) /* * To avoid deadlocks, unlock the mutex returned by this function, rather than * whatever you passed as the argument. */ static ALLEGRO_MUTEX *maybe_lock_mutex(ALLEGRO_MUTEX *mutex) { if (mutex) { al_lock_mutex(mutex); } return mutex; } static void maybe_unlock_mutex(ALLEGRO_MUTEX *mutex) { if (mutex) { al_unlock_mutex(mutex); } } /* Function: al_create_audio_stream */ ALLEGRO_AUDIO_STREAM *al_create_audio_stream(size_t fragment_count, unsigned int frag_samples, unsigned int freq, ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf) { ALLEGRO_AUDIO_STREAM *stream; unsigned long bytes_per_sample; unsigned long bytes_per_frag_buf; size_t i; if (!fragment_count) { _al_set_error(ALLEGRO_INVALID_PARAM, "Attempted to create stream with no buffers"); return NULL; } if (!frag_samples) { _al_set_error(ALLEGRO_INVALID_PARAM, "Attempted to create stream with no buffer size"); return NULL; } if (!freq) { _al_set_error(ALLEGRO_INVALID_PARAM, "Attempted to create stream with no frequency"); return NULL; } bytes_per_sample = al_get_channel_count(chan_conf) * al_get_audio_depth_size(depth); bytes_per_frag_buf = frag_samples * bytes_per_sample; stream = al_calloc(1, sizeof(*stream)); if (!stream) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Out of memory allocating stream object"); return NULL; } stream->spl.is_playing = true; stream->is_draining = false; stream->spl.loop = _ALLEGRO_PLAYMODE_STREAM_ONCE; stream->spl.spl_data.depth = depth; stream->spl.spl_data.chan_conf = chan_conf; stream->spl.spl_data.frequency = freq; stream->spl.speed = 1.0f; stream->spl.gain = 1.0f; stream->spl.pan = 0.0f; stream->spl.step = 0; stream->spl.pos = frag_samples; stream->spl.spl_data.len = stream->spl.pos; stream->buf_count = fragment_count; stream->used_bufs = al_calloc(1, fragment_count * sizeof(void *) * 2); if (!stream->used_bufs) { al_free(stream->used_bufs); al_free(stream); _al_set_error(ALLEGRO_GENERIC_ERROR, "Out of memory allocating stream buffer pointers"); return NULL; } stream->pending_bufs = stream->used_bufs + fragment_count; /* The main_buffer holds all the buffer fragments in contiguous memory. * To support interpolation across buffer fragments, we allocate extra * MAX_LAG samples at the start of each buffer fragment, to hold the * last few sample values which came before that fragment. */ stream->main_buffer = al_calloc(1, (MAX_LAG * bytes_per_sample + bytes_per_frag_buf) * fragment_count); if (!stream->main_buffer) { al_free(stream->used_bufs); al_free(stream); _al_set_error(ALLEGRO_GENERIC_ERROR, "Out of memory allocating stream buffer"); return NULL; } for (i = 0; i < fragment_count; i++) { char *buffer = (char *)stream->main_buffer + i * (MAX_LAG * bytes_per_sample + bytes_per_frag_buf); al_fill_silence(buffer, MAX_LAG, depth, chan_conf); stream->used_bufs[i] = buffer + MAX_LAG * bytes_per_sample; } al_init_user_event_source(&stream->spl.es); /* This can lead to deadlocks on shutdown, hence we don't do it. */ /* stream->dtor_item = _al_kcm_register_destructor(stream, (void (*)(void *)) al_destroy_audio_stream); */ return stream; } /* Function: al_destroy_audio_stream */ void al_destroy_audio_stream(ALLEGRO_AUDIO_STREAM *stream) { if (stream) { if (stream->feed_thread) { stream->unload_feeder(stream); } /* See commented out call to _al_kcm_register_destructor. */ /* _al_kcm_unregister_destructor(stream->dtor_item); */ _al_kcm_detach_from_parent(&stream->spl); al_destroy_user_event_source(&stream->spl.es); al_free(stream->main_buffer); al_free(stream->used_bufs); al_free(stream); } } /* Function: al_drain_audio_stream */ void al_drain_audio_stream(ALLEGRO_AUDIO_STREAM *stream) { bool playing; if (!al_get_audio_stream_attached(stream)) { al_set_audio_stream_playing(stream, false); return; } stream->is_draining = true; do { al_rest(0.01); playing = al_get_audio_stream_playing(stream); } while (playing); } /* Function: al_get_audio_stream_frequency */ unsigned int al_get_audio_stream_frequency(const ALLEGRO_AUDIO_STREAM *stream) { ASSERT(stream); return stream->spl.spl_data.frequency; } /* Function: al_get_audio_stream_length */ unsigned int al_get_audio_stream_length(const ALLEGRO_AUDIO_STREAM *stream) { ASSERT(stream); return stream->spl.spl_data.len; } /* Function: al_get_audio_stream_fragments */ unsigned int al_get_audio_stream_fragments(const ALLEGRO_AUDIO_STREAM *stream) { ASSERT(stream); return stream->buf_count; } /* Function: al_get_available_audio_stream_fragments */ unsigned int al_get_available_audio_stream_fragments( const ALLEGRO_AUDIO_STREAM *stream) { unsigned int i; ASSERT(stream); for (i = 0; i < stream->buf_count && stream->used_bufs[i]; i++) ; return i; } /* Function: al_get_audio_stream_speed */ float al_get_audio_stream_speed(const ALLEGRO_AUDIO_STREAM *stream) { ASSERT(stream); return stream->spl.speed; } /* Function: al_get_audio_stream_gain */ float al_get_audio_stream_gain(const ALLEGRO_AUDIO_STREAM *stream) { ASSERT(stream); return stream->spl.gain; } /* Function: al_get_audio_stream_pan */ float al_get_audio_stream_pan(const ALLEGRO_AUDIO_STREAM *stream) { ASSERT(stream); return stream->spl.pan; } /* Function: al_get_audio_stream_channels */ ALLEGRO_CHANNEL_CONF al_get_audio_stream_channels( const ALLEGRO_AUDIO_STREAM *stream) { ASSERT(stream); return stream->spl.spl_data.chan_conf; } /* Function: al_get_audio_stream_depth */ ALLEGRO_AUDIO_DEPTH al_get_audio_stream_depth( const ALLEGRO_AUDIO_STREAM *stream) { ASSERT(stream); return stream->spl.spl_data.depth; } /* Function: al_get_audio_stream_playmode */ ALLEGRO_PLAYMODE al_get_audio_stream_playmode( const ALLEGRO_AUDIO_STREAM *stream) { ASSERT(stream); return stream->spl.loop; } /* Function: al_get_audio_stream_playing */ bool al_get_audio_stream_playing(const ALLEGRO_AUDIO_STREAM *stream) { ASSERT(stream); return stream->spl.is_playing; } /* Function: al_get_audio_stream_attached */ bool al_get_audio_stream_attached(const ALLEGRO_AUDIO_STREAM *stream) { ASSERT(stream); return (stream->spl.parent.u.ptr != NULL); } /* Function: al_get_audio_stream_played_samples */ uint64_t al_get_audio_stream_played_samples(const ALLEGRO_AUDIO_STREAM *stream) { uint64_t result; ALLEGRO_MUTEX *stream_mutex; ASSERT(stream); stream_mutex = maybe_lock_mutex(stream->spl.mutex); if (stream->spl.spl_data.buffer.ptr) { result = stream->consumed_fragments * stream->spl.spl_data.len + stream->spl.pos; } else { result = 0; } maybe_unlock_mutex(stream_mutex); return result; } /* Function: al_get_audio_stream_fragment */ void *al_get_audio_stream_fragment(const ALLEGRO_AUDIO_STREAM *stream) { size_t i; void *fragment; ALLEGRO_MUTEX *stream_mutex; ASSERT(stream); stream_mutex = maybe_lock_mutex(stream->spl.mutex); if (!stream->used_bufs[0]) { /* No free fragments are available. */ fragment = NULL; } else { fragment = stream->used_bufs[0]; for (i = 0; i < stream->buf_count-1 && stream->used_bufs[i]; i++) { stream->used_bufs[i] = stream->used_bufs[i+1]; } stream->used_bufs[i] = NULL; } maybe_unlock_mutex(stream_mutex); return fragment; } /* Function: al_set_audio_stream_speed */ bool al_set_audio_stream_speed(ALLEGRO_AUDIO_STREAM *stream, float val) { ASSERT(stream); if (val <= 0.0f) { _al_set_error(ALLEGRO_INVALID_PARAM, "Attempted to set stream speed to a zero or negative value"); return false; } if (stream->spl.parent.u.ptr && stream->spl.parent.is_voice) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Could not set voice playback speed"); return false; } stream->spl.speed = val; if (stream->spl.parent.u.mixer) { ALLEGRO_MIXER *mixer = stream->spl.parent.u.mixer; ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex); stream->spl.step = (stream->spl.spl_data.frequency) * stream->spl.speed; stream->spl.step_denom = mixer->ss.spl_data.frequency; /* Don't wanna be trapped with a step value of 0 */ if (stream->spl.step == 0) { stream->spl.step = 1; } maybe_unlock_mutex(stream_mutex); } return true; } /* Function: al_set_audio_stream_gain */ bool al_set_audio_stream_gain(ALLEGRO_AUDIO_STREAM *stream, float val) { ASSERT(stream); if (stream->spl.parent.u.ptr && stream->spl.parent.is_voice) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Could not set gain of stream attached to voice"); return false; } if (stream->spl.gain != val) { stream->spl.gain = val; /* If attached to a mixer already, need to recompute the sample * matrix to take into account the gain. */ if (stream->spl.parent.u.mixer) { ALLEGRO_MIXER *mixer = stream->spl.parent.u.mixer; ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex); _al_kcm_mixer_rejig_sample_matrix(mixer, &stream->spl); maybe_unlock_mutex(stream_mutex); } } return true; } /* Function: al_set_audio_stream_pan */ bool al_set_audio_stream_pan(ALLEGRO_AUDIO_STREAM *stream, float val) { ASSERT(stream); if (stream->spl.parent.u.ptr && stream->spl.parent.is_voice) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Could not set gain of stream attached to voice"); return false; } if (val != ALLEGRO_AUDIO_PAN_NONE && (val < -1.0 || val > 1.0)) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Invalid pan value"); return false; } if (stream->spl.pan != val) { stream->spl.pan = val; /* If attached to a mixer already, need to recompute the sample * matrix to take into account the panning. */ if (stream->spl.parent.u.mixer) { ALLEGRO_MIXER *mixer = stream->spl.parent.u.mixer; ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex); _al_kcm_mixer_rejig_sample_matrix(mixer, &stream->spl); maybe_unlock_mutex(stream_mutex); } } return true; } /* Function: al_set_audio_stream_playmode */ bool al_set_audio_stream_playmode(ALLEGRO_AUDIO_STREAM *stream, ALLEGRO_PLAYMODE val) { ASSERT(stream); bool ret = false; if (val == ALLEGRO_PLAYMODE_ONCE) { stream->spl.loop = _ALLEGRO_PLAYMODE_STREAM_ONCE; ret = true; } if (val == ALLEGRO_PLAYMODE_LOOP_ONCE) { stream->spl.loop = _ALLEGRO_PLAYMODE_STREAM_LOOP_ONCE; ret = true; } else if (val == ALLEGRO_PLAYMODE_LOOP) { /* Only streams creating by al_load_audio_stream() support * looping. */ if (!stream->feeder) { ret = false; } else { stream->spl.loop = _ALLEGRO_PLAYMODE_STREAM_ONEDIR; ret = true; } } if (ret) { stream->is_draining = false; } // XXX _al_set_error return ret; } static void reset_stopped_stream(ALLEGRO_AUDIO_STREAM *stream) { const int bytes_per_sample = al_get_channel_count(stream->spl.spl_data.chan_conf) * al_get_audio_depth_size(stream->spl.spl_data.depth); const int fragment_buffer_size = bytes_per_sample * (stream->spl.spl_data.len + MAX_LAG); size_t i, n; /* Write silence to the "invisible" part in between fragment buffers to * avoid interpolation artifacts. It's tempting to zero the complete * memory block in one go but some of the buffers might be getting * refilled. So they are currently "owned" by the library user and * should not be overwritten. But zeroing the parts not visible to the * user should be OK. */ for (i = 0; i < stream->buf_count; ++i) { al_fill_silence((char *)stream->main_buffer + i * fragment_buffer_size, MAX_LAG, stream->spl.spl_data.depth, stream->spl.spl_data.chan_conf); } /* Get the current number of entries in the used_buf list. */ for (n = 0; n < stream->buf_count && stream->used_bufs[n]; n++) ; /* Move everything from pending_bufs to used_bufs. */ i = 0; while (i < stream->buf_count && n < stream->buf_count && stream->pending_bufs[i]) { stream->used_bufs[n] = stream->pending_bufs[i]; stream->pending_bufs[i] = NULL; n++; i++; } /* No fragment buffer is currently playing. */ stream->spl.spl_data.buffer.ptr = NULL; stream->spl.pos = stream->spl.spl_data.len; stream->spl.pos_bresenham_error = 0; stream->consumed_fragments = 0; } /* Function: al_set_audio_stream_playing */ bool al_set_audio_stream_playing(ALLEGRO_AUDIO_STREAM *stream, bool val) { bool rc = true; ALLEGRO_MUTEX *stream_mutex; ASSERT(stream); if (stream->spl.parent.u.ptr && stream->spl.parent.is_voice) { ALLEGRO_VOICE *voice = stream->spl.parent.u.voice; if (val != stream->spl.is_playing) { rc = _al_kcm_set_voice_playing(voice, voice->mutex, val); } } stream_mutex = maybe_lock_mutex(stream->spl.mutex); stream->spl.is_playing = rc && val; if (stream->spl.is_playing) { /* We usually emit fragment events when a fragment is used up, but if the * stream has zero pending fragments to begin with then no events would * ever be emitted. */ _al_kcm_emit_stream_events(stream); } else if (!val) { reset_stopped_stream(stream); } maybe_unlock_mutex(stream_mutex); return rc; } /* Function: al_detach_audio_stream */ bool al_detach_audio_stream(ALLEGRO_AUDIO_STREAM *stream) { ASSERT(stream); _al_kcm_detach_from_parent(&stream->spl); ASSERT(stream->spl.spl_read == NULL); return !al_get_audio_stream_attached(stream); } /* Function: al_set_audio_stream_fragment */ bool al_set_audio_stream_fragment(ALLEGRO_AUDIO_STREAM *stream, void *val) { size_t i; bool ret; ALLEGRO_MUTEX *stream_mutex; ASSERT(stream); stream_mutex = maybe_lock_mutex(stream->spl.mutex); for (i = 0; i < stream->buf_count && stream->pending_bufs[i] ; i++) ; if (i < stream->buf_count) { stream->pending_bufs[i] = val; ret = true; } else { _al_set_error(ALLEGRO_INVALID_OBJECT, "Attempted to set a stream buffer with a full pending list"); ret = false; } maybe_unlock_mutex(stream_mutex); return ret; } /* _al_kcm_refill_stream: * Called by the mixer when the current buffer has been used up. It should * point to the next pending buffer and adjust the sample position to reflect * the buffer being updated. It may be necessary to call this function multiple * times if the sample position is so far ahead that multiple buffers need to * be consumed. * Returns true if the next buffer is available and set up. * Otherwise returns false. */ bool _al_kcm_refill_stream(ALLEGRO_AUDIO_STREAM *stream) { ALLEGRO_SAMPLE_INSTANCE *spl = &stream->spl; void *old_buf = spl->spl_data.buffer.ptr; void *new_buf; size_t i; int new_pos = spl->pos - spl->spl_data.len; if (old_buf) { /* Slide the buffers down one position and put the * completed buffer into the used array to be refilled. */ for (i = 0; i < stream->buf_count-1 && stream->pending_bufs[i]; i++) { stream->pending_bufs[i] = stream->pending_bufs[i+1]; } stream->pending_bufs[i] = NULL; for (i = 0; stream->used_bufs[i]; i++) ; stream->used_bufs[i] = old_buf; } new_buf = stream->pending_bufs[0]; stream->spl.spl_data.buffer.ptr = new_buf; if (!new_buf) { ALLEGRO_WARN("Out of buffers\n"); return false; } /* Copy the last MAX_LAG sample values to the front of the new buffer * for interpolation. */ if (old_buf) { const int bytes_per_sample = al_get_channel_count(spl->spl_data.chan_conf) * al_get_audio_depth_size(spl->spl_data.depth); memcpy( (char *) new_buf - bytes_per_sample * MAX_LAG, (char *) old_buf + bytes_per_sample * (spl->pos-MAX_LAG-new_pos), bytes_per_sample * MAX_LAG); stream->consumed_fragments++; } stream->spl.pos = new_pos; return true; } /* _al_kcm_feed_stream: * A routine running in another thread that feeds the stream buffers as * necessary, usually getting data from some file reader backend. */ void *_al_kcm_feed_stream(ALLEGRO_THREAD *self, void *vstream) { ALLEGRO_AUDIO_STREAM *stream = vstream; ALLEGRO_EVENT_QUEUE *queue; bool finished_event_sent = false; bool prefill = true; (void)self; ALLEGRO_DEBUG("Stream feeder thread started.\n"); queue = al_create_event_queue(); al_register_event_source(queue, &stream->spl.es); stream->quit_feed_thread = false; while (!stream->quit_feed_thread) { char *fragment; ALLEGRO_EVENT event; if (!prefill) al_wait_for_event(queue, &event); if ((prefill || event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT) && !stream->is_draining) { unsigned long bytes; unsigned long bytes_written; ALLEGRO_MUTEX *stream_mutex; fragment = al_get_audio_stream_fragment(stream); if (!fragment) { /* This is not an error. */ continue; } bytes = (stream->spl.spl_data.len) * al_get_channel_count(stream->spl.spl_data.chan_conf) * al_get_audio_depth_size(stream->spl.spl_data.depth); stream_mutex = maybe_lock_mutex(stream->spl.mutex); bytes_written = stream->feeder(stream, fragment, bytes); maybe_unlock_mutex(stream_mutex); if (stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONEDIR) { /* Keep rewinding until the fragment is filled. */ while (bytes_written < bytes && stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONEDIR) { size_t bw; al_rewind_audio_stream(stream); stream_mutex = maybe_lock_mutex(stream->spl.mutex); bw = stream->feeder(stream, fragment + bytes_written, bytes - bytes_written); bytes_written += bw; maybe_unlock_mutex(stream_mutex); } } else if (bytes_written < bytes) { /* Fill the rest of the fragment with silence. */ int silence_samples = (bytes - bytes_written) / (al_get_channel_count(stream->spl.spl_data.chan_conf) * al_get_audio_depth_size(stream->spl.spl_data.depth)); al_fill_silence(fragment + bytes_written, silence_samples, stream->spl.spl_data.depth, stream->spl.spl_data.chan_conf); } if (!al_set_audio_stream_fragment(stream, fragment)) { ALLEGRO_ERROR("Error setting stream buffer.\n"); continue; } /* The streaming source doesn't feed any more, so drain the stream. * Don't quit in case the user decides to seek and then restart the * stream. */ if (bytes_written != bytes && (stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONCE || stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_LOOP_ONCE)) { /* Why not al_drain_audio_stream? We don't want to block on draining * because the user might adjust the stream loop points and restart * the stream. */ stream->is_draining = true; if (!finished_event_sent) { ALLEGRO_EVENT fin_event; fin_event.user.type = ALLEGRO_EVENT_AUDIO_STREAM_FINISHED; fin_event.user.timestamp = al_get_time(); al_emit_user_event(&stream->spl.es, &fin_event, NULL); finished_event_sent = true; } } else { finished_event_sent = false; } } else if (event.type == _KCM_STREAM_FEEDER_QUIT_EVENT_TYPE) { ALLEGRO_EVENT fin_event; stream->quit_feed_thread = true; fin_event.user.type = ALLEGRO_EVENT_AUDIO_STREAM_FINISHED; fin_event.user.timestamp = al_get_time(); al_emit_user_event(&stream->spl.es, &fin_event, NULL); } if (prefill) { al_lock_mutex(stream->feed_thread_started_mutex); stream->feed_thread_started = true; al_broadcast_cond(stream->feed_thread_started_cond); al_unlock_mutex(stream->feed_thread_started_mutex); } prefill = false; } al_destroy_event_queue(queue); ALLEGRO_DEBUG("Stream feeder thread finished.\n"); return NULL; } void _al_kcm_emit_stream_events(ALLEGRO_AUDIO_STREAM *stream) { /* Emit one event for each stream fragment available right now. * * There may already be an event corresponding to an available fragment in * some event queue, but there's nothing we can do about that. Streams may * be added and removed from queues, events may be lost by the user, etc. * so it would be dangerous to assume that each fragment event would be * responded to, once and exactly once. * * Having said that, event queues are empty in the steady state so it is * relatively rare that this situation occurs. */ int count = al_get_available_audio_stream_fragments(stream); while (count--) { ALLEGRO_EVENT event; event.user.type = ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT; event.user.timestamp = al_get_time(); al_emit_user_event(&stream->spl.es, &event, NULL); } } /* Function: al_rewind_audio_stream */ bool al_rewind_audio_stream(ALLEGRO_AUDIO_STREAM *stream) { bool ret; if (stream->rewind_feeder) { ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex); ret = stream->rewind_feeder(stream); stream->is_draining = false; maybe_unlock_mutex(stream_mutex); return ret; } return false; } /* Function: al_seek_audio_stream_secs */ bool al_seek_audio_stream_secs(ALLEGRO_AUDIO_STREAM *stream, double time) { bool ret; if (stream->seek_feeder) { ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex); ret = stream->seek_feeder(stream, time); stream->is_draining = false; maybe_unlock_mutex(stream_mutex); return ret; } return false; } /* Function: al_get_audio_stream_position_secs */ double al_get_audio_stream_position_secs(ALLEGRO_AUDIO_STREAM *stream) { double ret; if (stream->get_feeder_position) { ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex); ret = stream->get_feeder_position(stream); maybe_unlock_mutex(stream_mutex); return ret; } return 0.0; } /* Function: al_get_audio_stream_length_secs */ double al_get_audio_stream_length_secs(ALLEGRO_AUDIO_STREAM *stream) { double ret; if (stream->get_feeder_length) { ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex); ret = stream->get_feeder_length(stream); maybe_unlock_mutex(stream_mutex); return ret; } return 0.0; } /* Function: al_set_audio_stream_loop_secs */ bool al_set_audio_stream_loop_secs(ALLEGRO_AUDIO_STREAM *stream, double start, double end) { bool ret; if (start >= end) return false; if (stream->set_feeder_loop) { ALLEGRO_MUTEX *stream_mutex = maybe_lock_mutex(stream->spl.mutex); ret = stream->set_feeder_loop(stream, start, end); stream->is_draining = false; maybe_unlock_mutex(stream_mutex); return ret; } return false; } /* Function: al_get_audio_stream_event_source */ ALLEGRO_EVENT_SOURCE *al_get_audio_stream_event_source( ALLEGRO_AUDIO_STREAM *stream) { return &stream->spl.es; } bool al_set_audio_stream_channel_matrix(ALLEGRO_AUDIO_STREAM *stream, const float *matrix) { ASSERT(stream); if (stream->spl.parent.u.ptr && stream->spl.parent.is_voice) { _al_set_error(ALLEGRO_GENERIC_ERROR, "Could not set channel matrix of stream attached to voice"); return false; } return al_set_sample_instance_channel_matrix(&stream->spl, matrix); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/kcm_voice.c000066400000000000000000000322451473414355200201420ustar00rootroot00000000000000/** * Originally digi.c from allegro wiki * Original authors: KC/Milan * * Converted to allegro5 by Ryan Dickie */ /* Title: Voice functions */ #include #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_audio_cfg.h" ALLEGRO_DEBUG_CHANNEL("audio") /* forward declarations */ static void stream_read(void *source, void **vbuf, unsigned int *samples, ALLEGRO_AUDIO_DEPTH buffer_depth, size_t dest_maxc); /* _al_voice_update: * Reads the attached stream and provides a buffer for the sound card. It is * the driver's responsiblity to call this and to make sure any * driver-specific resources associated with the voice are locked. This should * only be called for streaming sources. * * The return value is a pointer to the next chunk of audio data in the format * the voice was allocated with. It may return NULL, in which case it is the * driver's responsilibty to play silence for the voice. The returned buffer * must *not* be modified. The 'samples' argument is set to the samples count * in the returned audio data and it may be less or equal to the requested * samples count. */ const void *_al_voice_update(ALLEGRO_VOICE *voice, ALLEGRO_MUTEX *mutex, unsigned int *samples) { void *buf = NULL; /* The mutex parameter is intended to make it obvious at the call site * that the voice mutex will be acquired here. */ ASSERT(voice); ASSERT(voice->mutex == mutex); (void)mutex; al_lock_mutex(voice->mutex); if (voice->attached_stream) { ASSERT(voice->attached_stream->spl_read); voice->attached_stream->spl_read(voice->attached_stream, &buf, samples, voice->depth, 0); } al_unlock_mutex(voice->mutex); return buf; } /* Function: al_create_voice */ ALLEGRO_VOICE *al_create_voice(unsigned int freq, ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf) { ALLEGRO_VOICE *voice = NULL; if (!freq) { _al_set_error(ALLEGRO_INVALID_PARAM, "Invalid Voice Frequency"); return NULL; } voice = al_calloc(1, sizeof(*voice)); if (!voice) { return NULL; } voice->depth = depth; voice->chan_conf = chan_conf; voice->frequency = freq; voice->mutex = al_create_mutex(); voice->cond = al_create_cond(); /* XXX why is this needed? there should only be one active driver */ voice->driver = _al_kcm_driver; ASSERT(_al_kcm_driver); if (_al_kcm_driver->allocate_voice(voice) != 0) { al_destroy_mutex(voice->mutex); al_destroy_cond(voice->cond); al_free(voice); return NULL; } voice->dtor_item = _al_kcm_register_destructor("voice", voice, (void (*)(void *)) al_destroy_voice); return voice; } /* Function: al_destroy_voice */ void al_destroy_voice(ALLEGRO_VOICE *voice) { if (voice) { _al_kcm_unregister_destructor(voice->dtor_item); al_detach_voice(voice); ASSERT(al_get_voice_playing(voice) == false); /* We do NOT lock the voice mutex when calling this method. */ voice->driver->deallocate_voice(voice); al_destroy_mutex(voice->mutex); al_destroy_cond(voice->cond); al_free(voice); } } /* Function: al_attach_sample_instance_to_voice */ bool al_attach_sample_instance_to_voice(ALLEGRO_SAMPLE_INSTANCE *spl, ALLEGRO_VOICE *voice) { bool ret; ASSERT(voice); ASSERT(spl); if (voice->attached_stream) { ALLEGRO_WARN( "Attempted to attach to a voice that already has an attachment\n"); _al_set_error(ALLEGRO_INVALID_OBJECT, "Attempted to attach to a voice that already has an attachment"); return false; } if (spl->parent.u.ptr) { ALLEGRO_WARN("Attempted to attach a sample that is already attached\n"); _al_set_error(ALLEGRO_INVALID_OBJECT, "Attempted to attach a sample that is already attached"); return false; } if (voice->chan_conf != spl->spl_data.chan_conf || voice->frequency != spl->spl_data.frequency || voice->depth != spl->spl_data.depth) { ALLEGRO_WARN("Sample settings do not match voice settings\n"); _al_set_error(ALLEGRO_INVALID_OBJECT, "Sample settings do not match voice settings"); return false; } al_lock_mutex(voice->mutex); voice->attached_stream = spl; voice->is_streaming = false; voice->num_buffers = 1; voice->buffer_size = (spl->spl_data.len) * al_get_channel_count(voice->chan_conf) * al_get_audio_depth_size(voice->depth); spl->spl_read = NULL; _al_kcm_stream_set_mutex(spl, voice->mutex); spl->parent.u.voice = voice; spl->parent.is_voice = true; if (voice->driver->load_voice(voice, spl->spl_data.buffer.ptr) != 0 || (spl->is_playing && voice->driver->start_voice(voice) != 0)) { voice->attached_stream = NULL; spl->spl_read = NULL; _al_kcm_stream_set_mutex(spl, NULL); spl->parent.u.voice = NULL; ALLEGRO_ERROR("Unable to load sample into voice\n"); ret = false; } else { ret = true; } al_unlock_mutex(voice->mutex); return ret; } /* stream_read: * This passes the next waiting stream buffer to the voice via vbuf. */ static void stream_read(void *source, void **vbuf, unsigned int *samples, ALLEGRO_AUDIO_DEPTH buffer_depth, size_t dest_maxc) { ALLEGRO_AUDIO_STREAM *stream = (ALLEGRO_AUDIO_STREAM*)source; unsigned int len = stream->spl.spl_data.len; unsigned int pos = stream->spl.pos; if (!stream->spl.is_playing) { *vbuf = NULL; *samples = 0; return; } if (*samples > len) *samples = len; if (pos >= len) { /* XXX: Handle the case where we need to call _al_kcm_refill_stream * multiple times due to ludicrous playback speed. */ _al_kcm_refill_stream(stream); if (!stream->pending_bufs[0]) { if (stream->is_draining) { stream->spl.is_playing = false; } *vbuf = NULL; *samples = 0; return; } *vbuf = stream->pending_bufs[0]; pos = *samples; _al_kcm_emit_stream_events(stream); } else { int bytes = pos * al_get_channel_count(stream->spl.spl_data.chan_conf) * al_get_audio_depth_size(stream->spl.spl_data.depth); *vbuf = ((char *)stream->pending_bufs[0]) + bytes; if (pos + *samples > len) *samples = len - pos; pos += *samples; } stream->spl.pos = pos; (void)dest_maxc; (void)buffer_depth; } /* Function: al_attach_audio_stream_to_voice */ bool al_attach_audio_stream_to_voice(ALLEGRO_AUDIO_STREAM *stream, ALLEGRO_VOICE *voice) { bool ret; ASSERT(voice); ASSERT(stream); if (voice->attached_stream) { _al_set_error(ALLEGRO_INVALID_OBJECT, "Attempted to attach to a voice that already has an attachment"); return false; } if (stream->spl.parent.u.ptr) { _al_set_error(ALLEGRO_INVALID_OBJECT, "Attempted to attach a stream that is already attached"); return false; } if (voice->chan_conf != stream->spl.spl_data.chan_conf || voice->frequency != stream->spl.spl_data.frequency || voice->depth != stream->spl.spl_data.depth) { _al_set_error(ALLEGRO_INVALID_OBJECT, "Stream settings do not match voice settings"); return false; } al_lock_mutex(voice->mutex); voice->attached_stream = &stream->spl; _al_kcm_stream_set_mutex(&stream->spl, voice->mutex); stream->spl.parent.u.voice = voice; stream->spl.parent.is_voice = true; voice->is_streaming = true; voice->num_buffers = stream->buf_count; voice->buffer_size = (stream->spl.spl_data.len) * al_get_channel_count(stream->spl.spl_data.chan_conf) * al_get_audio_depth_size(stream->spl.spl_data.depth); ASSERT(stream->spl.spl_read == NULL); stream->spl.spl_read = stream_read; if (voice->driver->start_voice(voice) != 0) { voice->attached_stream = NULL; _al_kcm_stream_set_mutex(&stream->spl, NULL); stream->spl.parent.u.voice = NULL; stream->spl.spl_read = NULL; _al_set_error(ALLEGRO_GENERIC_ERROR, "Unable to start stream"); ret = false; } else { ret = true; } al_unlock_mutex(voice->mutex); return ret; } /* Function: al_attach_mixer_to_voice */ bool al_attach_mixer_to_voice(ALLEGRO_MIXER *mixer, ALLEGRO_VOICE *voice) { bool ret; ASSERT(voice); ASSERT(mixer); ASSERT(mixer->ss.is_mixer); if (voice->attached_stream) return false; if (mixer->ss.parent.u.ptr) return false; if (voice->chan_conf != mixer->ss.spl_data.chan_conf || voice->frequency != mixer->ss.spl_data.frequency) { return false; } al_lock_mutex(voice->mutex); voice->attached_stream = &mixer->ss; ASSERT(mixer->ss.spl_read == NULL); mixer->ss.spl_read = _al_kcm_mixer_read; _al_kcm_stream_set_mutex(&mixer->ss, voice->mutex); mixer->ss.parent.u.voice = voice; mixer->ss.parent.is_voice = true; voice->is_streaming = true; voice->num_buffers = 0; voice->buffer_size = 0; if (voice->driver->start_voice(voice) != 0) { voice->attached_stream = NULL; _al_kcm_stream_set_mutex(&mixer->ss, NULL); mixer->ss.parent.u.voice = NULL; ret = false; } else { ret = true; } al_unlock_mutex(voice->mutex); return ret; } /* Function: al_detach_voice */ void al_detach_voice(ALLEGRO_VOICE *voice) { ASSERT(voice); if (!voice->attached_stream) { return; } al_lock_mutex(voice->mutex); if (!voice->is_streaming) { ALLEGRO_SAMPLE_INSTANCE *spl = voice->attached_stream; spl->pos = voice->driver->get_voice_position(voice); spl->is_playing = voice->driver->voice_is_playing(voice); voice->driver->stop_voice(voice); voice->driver->unload_voice(voice); } else { voice->driver->stop_voice(voice); } _al_kcm_stream_set_mutex(voice->attached_stream, NULL); voice->attached_stream->parent.u.voice = NULL; voice->attached_stream->spl_read = NULL; voice->attached_stream = NULL; al_unlock_mutex(voice->mutex); } /* Function: al_get_voice_frequency */ unsigned int al_get_voice_frequency(const ALLEGRO_VOICE *voice) { ASSERT(voice); return voice->frequency; } /* Function: al_get_voice_position */ unsigned int al_get_voice_position(const ALLEGRO_VOICE *voice) { ASSERT(voice); if (voice->attached_stream && !voice->is_streaming) { unsigned int ret; al_lock_mutex(voice->mutex); ret = voice->driver->get_voice_position(voice); al_unlock_mutex(voice->mutex); return ret; } else return 0; } /* Function: al_get_voice_channels */ ALLEGRO_CHANNEL_CONF al_get_voice_channels(const ALLEGRO_VOICE *voice) { ASSERT(voice); return voice->chan_conf; } /* Function: al_get_voice_depth */ ALLEGRO_AUDIO_DEPTH al_get_voice_depth(const ALLEGRO_VOICE *voice) { ASSERT(voice); return voice->depth; } /* Function: al_get_voice_playing */ bool al_get_voice_playing(const ALLEGRO_VOICE *voice) { ASSERT(voice); if (voice->attached_stream && !voice->is_streaming) { bool ret; al_lock_mutex(voice->mutex); ret = voice->driver->voice_is_playing(voice); al_unlock_mutex(voice->mutex); return ret; } return voice->attached_stream ? true : false; } /* Function: al_voice_has_attachments */ bool al_voice_has_attachments(const ALLEGRO_VOICE* voice) { ASSERT(voice); return voice->attached_stream; } /* Function: al_set_voice_position */ bool al_set_voice_position(ALLEGRO_VOICE *voice, unsigned int val) { ASSERT(voice); if (voice->attached_stream && !voice->is_streaming) { bool ret; al_lock_mutex(voice->mutex); // XXX change method ret = voice->driver->set_voice_position(voice, val) == 0; al_unlock_mutex(voice->mutex); return ret; } return false; } /* Function: al_set_voice_playing */ bool al_set_voice_playing(ALLEGRO_VOICE *voice, bool val) { ASSERT(voice); if (!voice->attached_stream) { ALLEGRO_DEBUG("Voice has no attachment\n"); return false; } if (voice->is_streaming) { ALLEGRO_WARN("Attempted to change the playing state of a voice " "with a streaming attachment (mixer or audiostreams)\n"); return false; } else { bool playing = al_get_voice_playing(voice); if (playing == val) { if (playing) { ALLEGRO_DEBUG("Voice is already playing\n"); } else { ALLEGRO_DEBUG("Voice is already stopped\n"); } return true; } return _al_kcm_set_voice_playing(voice, voice->mutex, val); } } bool _al_kcm_set_voice_playing(ALLEGRO_VOICE *voice, ALLEGRO_MUTEX *mutex, bool val) { bool ret; /* The mutex parameter is intended to make it obvious at the call site * that the voice mutex will be acquired here. */ ASSERT(voice); ASSERT(voice->mutex == mutex); (void)mutex; al_lock_mutex(voice->mutex); // XXX change methods if (val) ret = voice->driver->start_voice(voice) == 0; else ret = voice->driver->stop_voice(voice) == 0; al_unlock_mutex(voice->mutex); return ret; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/openal.c000066400000000000000000000470741473414355200174670ustar00rootroot00000000000000/* * updated for 4.9 inclusion by Ryan Dickie * Originally done by KC/Milan */ #include #include #include "allegro5/allegro.h" #if defined(ALLEGRO_MACOSX) || defined(ALLEGRO_IPHONE) #include #include #else /* ALLEGRO_MACOSX */ #include #include #endif /* ALLEGRO_MACOSX */ #include "allegro5/internal/aintern_audio.h" ALLEGRO_DEBUG_CHANNEL("openal") /* OpenAL vars */ static ALCdevice *openal_dev; static ALCcontext *openal_context; /* TODO: make these configurable */ static const size_t preferred_frag_size = 1024; static const ALuint preferred_buf_count = 4; static const char *openal_get_err_str(ALenum err) { switch (err) { case AL_NO_ERROR: return "There is no OpenAL error"; case AL_INVALID_NAME: return "A bad name (ID) was passed to OpenAL"; case AL_INVALID_ENUM: return "An invalid enum was passed to OpenAL"; case AL_INVALID_VALUE: return "An Invalid enum was passed to OpenAL"; case AL_INVALID_OPERATION: return "The requestion operation is invalid"; case AL_OUT_OF_MEMORY: return "OpenAL ran out of memory"; default: return "Unknown error"; } } static const char *alc_get_err_str(ALCenum err) { switch (err) { case ALC_NO_ERROR: return "There is no OpenAL error"; case ALC_INVALID_DEVICE: return "A bad device was passed to OpenAL"; case ALC_INVALID_CONTEXT: return "An bad context was passed to OpenAL"; case ALC_INVALID_ENUM: return "An Invalid enum was passed to OpenAL"; case ALC_INVALID_VALUE: return "The requestion operation is invalid"; case ALC_OUT_OF_MEMORY: return "OpenAL ran out of memory"; default: return "Unknown error"; } } /* The open method starts up the driver and should lock the device, using the previously set paramters, or defaults. It shouldn't need to start sending audio data to the device yet, however. */ static int _openal_open(void) { ALenum openal_err; ALCenum alc_err; ALLEGRO_INFO("Starting OpenAL\n"); /* clear the error state */ openal_err = alGetError(); /* pick default device. always a good choice */ openal_dev = alcOpenDevice(NULL); alc_err = ALC_NO_ERROR; if (!openal_dev || (alc_err = alcGetError(openal_dev)) != ALC_NO_ERROR) { ALLEGRO_ERROR("Could not open audio device: %s\n", alc_get_err_str(alc_err)); return 1; } openal_context = alcCreateContext(openal_dev, NULL); alc_err = ALC_NO_ERROR; if (!openal_context || (alc_err = alcGetError(openal_dev)) != ALC_NO_ERROR) { ALLEGRO_ERROR("Could not create current device context: %s\n", alc_get_err_str(alc_err)); return 1; } alcMakeContextCurrent(openal_context); #if !defined ALLEGRO_IPHONE if ((alc_err = alcGetError(openal_dev)) != ALC_NO_ERROR) { ALLEGRO_ERROR("Could not make context current: %s\n", alc_get_err_str(alc_err)); return 1; } alDistanceModel(AL_NONE); if ((openal_err = alGetError()) != AL_NO_ERROR) { ALLEGRO_ERROR("Could not set distance model: %s\n", openal_get_err_str(openal_err)); return 1; } #endif ALLEGRO_DEBUG("Vendor: %s\n", alGetString(AL_VENDOR)); ALLEGRO_DEBUG("Version: %s\n", alGetString(AL_VERSION)); ALLEGRO_DEBUG("Renderer: %s\n", alGetString(AL_RENDERER)); ALLEGRO_DEBUG("Extensions: %s\n", alGetString(AL_EXTENSIONS)); return 0; } /* The close method should close the device, freeing any resources, and allow other processes to use the device */ static void _openal_close(void) { /* clear error states */ alGetError(); alcGetError(openal_dev); /* remove traces from openal */ alcMakeContextCurrent(NULL); alcDestroyContext(openal_context); alcCloseDevice(openal_dev); /* reset the pointers to NULL */ openal_context = NULL; openal_dev = NULL; } /* Custom struct to hold voice information OpenAL needs */ /* TODO: review */ typedef struct ALLEGRO_AL_DATA { ALuint *buffers; size_t num_buffers; ALuint buffer_size; ALuint source; ALuint format; ALLEGRO_THREAD *thread; bool stopped; } ALLEGRO_AL_DATA; /* Custom routine which runs in another thread to periodically check if OpenAL wants more data for a stream */ /* TODO: review */ static void *_openal_update(ALLEGRO_THREAD *self, void *arg) { ALLEGRO_VOICE *voice = (ALLEGRO_VOICE*) arg; ALLEGRO_AL_DATA *ex_data = (ALLEGRO_AL_DATA*)voice->extra; unsigned int i, samples_per_update; unsigned int bytes_per_sample; const void *data; void *silence; /* Streams should not be set to looping */ alSourcei(ex_data->source, AL_LOOPING, AL_FALSE); silence = al_calloc(1, ex_data->buffer_size); if (ex_data->format == AL_FORMAT_STEREO8 || ex_data->format == AL_FORMAT_MONO8) { memset(silence, 0x80, ex_data->buffer_size); } for (i = 0; i < ex_data->num_buffers; i++) { alBufferData(ex_data->buffers[i], ex_data->format, silence, ex_data->buffer_size, voice->frequency); } alSourceQueueBuffers(ex_data->source, ex_data->num_buffers, ex_data->buffers); alSourcePlay(ex_data->source); switch (ex_data->format) { case AL_FORMAT_STEREO16: bytes_per_sample = 4; break; case AL_FORMAT_STEREO8: case AL_FORMAT_MONO16: bytes_per_sample = 2; break; default: bytes_per_sample = 1; break; } samples_per_update = ex_data->buffer_size / bytes_per_sample; data = silence; while (!al_get_thread_should_stop(self)) { ALint status = 0; alGetSourcei(ex_data->source, AL_BUFFERS_PROCESSED, &status); if (status <= 0) { /* FIXME what is this for ? */ al_rest(0.001); continue; } while (--status >= 0) { ALuint buffer; data = _al_voice_update(voice, voice->mutex, &samples_per_update); if (data == NULL) data = silence; alSourceUnqueueBuffers(ex_data->source, 1, &buffer); alBufferData(buffer, ex_data->format, data, samples_per_update * bytes_per_sample, voice->frequency); alSourceQueueBuffers(ex_data->source, 1, &buffer); } alGetSourcei(ex_data->source, AL_SOURCE_STATE, &status); if (status == AL_STOPPED) { alSourcePlay(ex_data->source); } } alSourceStop(ex_data->source); al_free(silence); ex_data->stopped = true; al_broadcast_cond(voice->cond); return NULL; } /* The load_voice method loads a sample into the driver's memory. The voice's 'streaming' field will be set to false for these voices, and it's 'buffer_size' field will be the total length in bytes of the sample data. The voice's attached sample's looping mode should be honored, and loading must fail if it cannot be. */ static int _openal_load_voice(ALLEGRO_VOICE *voice, const void *data) { ALLEGRO_AL_DATA *ex_data = voice->extra; ALenum openal_err; if (voice->attached_stream->loop != ALLEGRO_PLAYMODE_ONCE && voice->attached_stream->loop != ALLEGRO_PLAYMODE_LOOP) { return 1; } ex_data->buffer_size = voice->buffer_size; if (!ex_data->buffer_size) { ALLEGRO_ERROR("Voice buffer and data buffer size mismatch\n"); return 1; } ex_data->num_buffers = 1; alGenSources(1, &ex_data->source); if ((openal_err = alGetError()) != AL_NO_ERROR) { ALLEGRO_ERROR("Could not generate (voice) source: %s\n", openal_get_err_str(openal_err)); return 1; } ex_data->buffers = al_malloc(sizeof(ALuint) * ex_data->num_buffers); if (!ex_data->buffers) { alSourcei(ex_data->source, AL_BUFFER, 0); alDeleteSources(1, &ex_data->source); ALLEGRO_ERROR("Could not allocate voice buffer memory\n"); return 1; } alGenBuffers(ex_data->num_buffers, ex_data->buffers); if ((openal_err = alGetError()) != AL_NO_ERROR) { alSourcei(ex_data->source, AL_BUFFER, 0); alDeleteSources(1, &ex_data->source); al_free(ex_data->buffers); ex_data->buffers = NULL; ALLEGRO_ERROR("Could not generate (voice) buffer: %s\n", openal_get_err_str(openal_err)); return 1; } /* copies data into a buffer */ alBufferData(ex_data->buffers[0], ex_data->format, data, ex_data->buffer_size, voice->frequency); /* sets the buffer */ alSourcei(ex_data->source, AL_BUFFER, ex_data->buffers[0]); /* Loop / no loop? */ alSourcei(ex_data->source, AL_LOOPING, (voice->attached_stream->loop != ALLEGRO_PLAYMODE_ONCE)); /* make sure the volume is on */ alSourcef(ex_data->source, AL_GAIN, 1.0f); if ((openal_err = alGetError()) != AL_NO_ERROR) { alSourcei(ex_data->source, AL_BUFFER, 0); alDeleteSources(1, &ex_data->source); alDeleteBuffers(ex_data->num_buffers, ex_data->buffers); al_free(ex_data->buffers); ex_data->buffers = NULL; ALLEGRO_ERROR("Could not attach voice source: %s\n", openal_get_err_str(openal_err)); return 1; } return 0; } /* The unload_voice method unloads a sample previously loaded with load_voice. This method should not be called on a streaming voice. */ static void _openal_unload_voice(ALLEGRO_VOICE *voice) { ALLEGRO_AL_DATA *ex_data = voice->extra; alSourcei(ex_data->source, AL_BUFFER, 0); alDeleteSources(1, &ex_data->source); alDeleteBuffers(ex_data->num_buffers, ex_data->buffers); al_free(ex_data->buffers); ex_data->buffers = NULL; alGetError(); /* required! */ } /* The start_voice should, surprise, start the voice. For streaming voices, it should start polling the device and call _al_voice_update for audio data. For non-streaming voices, it should resume playing from the last set position */ static int _openal_start_voice(ALLEGRO_VOICE *voice) { ALLEGRO_AL_DATA *ex_data = voice->extra; ALenum openal_err; /* playing a sample instead of a stream */ if (!voice->is_streaming) { alSourcePlay(ex_data->source); if ((openal_err = alGetError()) != AL_NO_ERROR) { ALLEGRO_ERROR("Could not start voice: %s\n", openal_get_err_str(openal_err)); return 1; } ALLEGRO_INFO("Starting voice\n"); return 0; } { ex_data->buffer_size = voice->buffer_size; if (!ex_data->buffer_size) { switch (ex_data->format) { case AL_FORMAT_STEREO16: ex_data->buffer_size = preferred_frag_size * 4; break; case AL_FORMAT_STEREO8: case AL_FORMAT_MONO16: ex_data->buffer_size = preferred_frag_size * 2; break; default: ex_data->buffer_size = preferred_frag_size; break; } } ex_data->num_buffers = voice->num_buffers; if (!ex_data->num_buffers) ex_data->num_buffers = preferred_buf_count; alGenSources(1, &ex_data->source); if (alGetError() != AL_NO_ERROR) return 1; ex_data->buffers = al_malloc(sizeof(ALuint) * ex_data->num_buffers); if (!ex_data->buffers) { alSourcei(ex_data->source, AL_BUFFER, 0); alDeleteSources(1, &ex_data->source); return 1; } alGenBuffers(ex_data->num_buffers, ex_data->buffers); if (alGetError() != AL_NO_ERROR) { alSourcei(ex_data->source, AL_BUFFER, 0); alDeleteSources(1, &ex_data->source); al_free(ex_data->buffers); ex_data->buffers = NULL; return 1; } alSourcef(ex_data->source, AL_GAIN, 1.0f); if (alGetError() != AL_NO_ERROR) { alSourcei(ex_data->source, AL_BUFFER, 0); alDeleteSources(1, &ex_data->source); alDeleteBuffers(ex_data->num_buffers, ex_data->buffers); al_free(ex_data->buffers); ex_data->buffers = NULL; return 1; } ex_data->stopped = false; ex_data->thread = al_create_thread(_openal_update, (void *)voice); al_start_thread(ex_data->thread); } ALLEGRO_INFO("Starting voice\n"); return 0; } /* The stop_voice method should stop playback. For non-streaming voices, it should leave the data loaded, and reset the voice position to 0. */ static int _openal_stop_voice(ALLEGRO_VOICE* voice) { ALLEGRO_AL_DATA *ex_data = voice->extra; ALenum openal_err; if (!ex_data->buffers) { ALLEGRO_WARN("Trying to stop empty voice buffer\n"); return 1; } /* if playing a sample */ if (!voice->is_streaming) { alSourceStop(ex_data->source); if ((openal_err = alGetError()) != AL_NO_ERROR) { ALLEGRO_ERROR("Could not stop voice: %s\n", openal_get_err_str(openal_err)); return 1; } return 0; } if (ex_data->thread) { al_set_thread_should_stop(ex_data->thread); while (!ex_data->stopped) { al_wait_cond(voice->cond, voice->mutex); } al_join_thread(ex_data->thread, NULL); ex_data->thread = NULL; ex_data->stopped = false; } alSourcei(ex_data->source, AL_BUFFER, 0); alDeleteSources(1, &ex_data->source); alDeleteBuffers(ex_data->num_buffers, ex_data->buffers); al_free(ex_data->buffers); ex_data->buffers = NULL; alGetError(); /* required! */ return 0; } /* The voice_is_playing method should only be called on non-streaming sources, and should return true if the voice is playing */ static bool _openal_voice_is_playing(const ALLEGRO_VOICE *voice) { ALLEGRO_AL_DATA *ex_data = voice->extra; ALint status; if (!ex_data) return false; alGetSourcei(ex_data->source, AL_SOURCE_STATE, &status); return (status == AL_PLAYING); } /* The allocate_voice method should grab a voice from the system, and allocate any data common to streaming and non-streaming sources. */ static int _openal_allocate_voice(ALLEGRO_VOICE *voice) { ALLEGRO_AL_DATA *ex_data; /* OpenAL doesn't support very much! */ switch (voice->depth) { case ALLEGRO_AUDIO_DEPTH_UINT8: /* format supported */ break; case ALLEGRO_AUDIO_DEPTH_INT8: ALLEGRO_WARN("OpenAL requires 8-bit data to be unsigned\n"); return 1; case ALLEGRO_AUDIO_DEPTH_UINT16: ALLEGRO_WARN("OpenAL requires 16-bit data to be signed\n"); return 1; case ALLEGRO_AUDIO_DEPTH_INT16: /* format supported */ break; case ALLEGRO_AUDIO_DEPTH_UINT24: ALLEGRO_WARN("OpenAL does not support 24-bit data\n"); return 1; case ALLEGRO_AUDIO_DEPTH_INT24: ALLEGRO_WARN("OpenAL does not support 24-bit data\n"); return 1; case ALLEGRO_AUDIO_DEPTH_FLOAT32: ALLEGRO_WARN("OpenAL does not support 32-bit floating data\n"); return 1; default: ALLEGRO_WARN("Cannot allocate unknown voice depth\n"); return 1; } ex_data = al_calloc(1, sizeof(*ex_data)); if (!ex_data) { ALLEGRO_ERROR("Could not allocate voice data memory\n"); return 1; } switch (voice->chan_conf) { case ALLEGRO_CHANNEL_CONF_1: /* format supported */ if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT8) ex_data->format = AL_FORMAT_MONO8; else ex_data->format = AL_FORMAT_MONO16; break; case ALLEGRO_CHANNEL_CONF_2: /* format supported */ if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT8) ex_data->format = AL_FORMAT_STEREO8; else ex_data->format = AL_FORMAT_STEREO16; break; case ALLEGRO_CHANNEL_CONF_3: ALLEGRO_ERROR("OpenAL does not support voice with 3 channel configuration\n"); al_free(ex_data); return 1; case ALLEGRO_CHANNEL_CONF_4: ex_data->format = alGetEnumValue("AL_FORMAT_QUAD16"); if (ex_data->format) { ALLEGRO_ERROR("OpenAL cannot allocate voice with 4.0 channel configuration\n"); al_free(ex_data); return 1; } if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT16) { ALLEGRO_ERROR("OpenAL requires 16-bit signed data for 4 channel configuration\n"); al_free(ex_data); return 1; } /* else it is supported */ break; case ALLEGRO_CHANNEL_CONF_5_1: ex_data->format = alGetEnumValue("AL_FORMAT_51CHN_16"); if (!ex_data->format) { ALLEGRO_ERROR("Cannot allocate voice with 5.1 channel configuration\n"); al_free(ex_data); return 1; } if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT16) { ALLEGRO_ERROR("5.1 channel requires 16-bit signed data\n"); al_free(ex_data); return 1; } /* else it is supported */ break; case ALLEGRO_CHANNEL_CONF_6_1: ex_data->format = alGetEnumValue("AL_FORMAT_61CHN_16"); if (!ex_data->format) { ALLEGRO_ERROR("Cannot allocate voice with 6.1 channel configuration\n"); al_free(ex_data); return 1; } if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT16) { ALLEGRO_ERROR("6.1 channel requires 16-bit signed data\n"); al_free(ex_data); return 1; } /* else it is supported */ break; case ALLEGRO_CHANNEL_CONF_7_1: ex_data->format = alGetEnumValue("AL_FORMAT_71CHN_16"); if (!ex_data->format) { ALLEGRO_ERROR("Cannot allocate voice with 7.1 channel configuration\n"); al_free(ex_data); return 1; } if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT16) { ALLEGRO_ERROR("7.1 channel requires 16-bit signed data\n"); al_free(ex_data); return 1; } /* else it is supported */ break; default: ALLEGRO_ERROR("Cannot allocate voice with unknown channel configuration\n"); al_free(ex_data); return 1; } voice->extra = ex_data; ex_data->thread = NULL; ex_data->stopped = false; return 0; } /* The deallocate_voice method should free the resources for the given voice, but still retain a hold on the device. The voice should be stopped and unloaded by the time this is called */ static void _openal_deallocate_voice(ALLEGRO_VOICE *voice) { ALLEGRO_AL_DATA *ex_data = voice->extra; ASSERT(ex_data->thread == NULL); (void)ex_data; al_free(voice->extra); voice->extra = NULL; } /* The get_voice_position method should return the current sample position of the voice (sample_pos = byte_pos / (depth/8) / channels). This should never be called on a streaming voice. */ static unsigned int _openal_get_voice_position(const ALLEGRO_VOICE *voice) { ALLEGRO_AL_DATA *ex_data = voice->extra; ALint pos; alGetSourcei(ex_data->source, AL_SAMPLE_OFFSET, &pos); if (alGetError() != AL_NO_ERROR) return 0; return pos; } /* The set_voice_position method should set the voice's playback position, given the value in samples. This should never be called on a streaming voice. */ static int _openal_set_voice_position(ALLEGRO_VOICE *voice, unsigned int val) { ALLEGRO_AL_DATA *ex_data = voice->extra; alSourcei(ex_data->source, AL_SAMPLE_OFFSET, val); if (alGetError() != AL_NO_ERROR) return 1; return 0; } ALLEGRO_AUDIO_DRIVER _al_kcm_openal_driver = { "OpenAL", _openal_open, _openal_close, _openal_allocate_voice, _openal_deallocate_voice, _openal_load_voice, _openal_unload_voice, _openal_start_voice, _openal_stop_voice, _openal_voice_is_playing, _openal_get_voice_position, _openal_set_voice_position, NULL, NULL, NULL }; /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/opensl.c000066400000000000000000000547731473414355200175150ustar00rootroot00000000000000/* OpenSL: The Standard for Embedded Audio Acceleration * http://www.khronos.org/opensles/ * http://www.khronos.org/registry/sles/specs/OpenSL_ES_Specification_1.1.pdf */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_audio.h" #include /* TODO: * If an android application goes into the suspend state then the opensl resources * might become 'unrealized' or 'suspended' so care needs to be taken * to realize them again once the application is resumed. */ /* Not sure if this one is needed, yet */ // #include /* Feel free to change MAX_FRAMES and MAX_BUFFERS if it affects * choppiness for your device. */ /* Number of samples to read in one call to al_voice_update */ static const int MAX_FRAMES = 2048; /* Number of opensl buffers to use */ #define MAX_BUFFERS 2 ALLEGRO_DEBUG_CHANNEL("opensl") static SLObjectItf engine; static const char * opensl_get_error_string(SLresult result) { switch (result){ case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; case SL_RESULT_PARAMETER_INVALID: return "Invalid parameter"; case SL_RESULT_MEMORY_FAILURE: return "Memory failure"; case SL_RESULT_RESOURCE_ERROR: return "Resource error"; case SL_RESULT_RESOURCE_LOST: return "Resource lost"; case SL_RESULT_IO_ERROR: return "IO error"; case SL_RESULT_BUFFER_INSUFFICIENT: return "Insufficient buffer"; case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted"; case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported"; case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found"; case SL_RESULT_PERMISSION_DENIED: return "Permission denied"; case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported"; case SL_RESULT_INTERNAL_ERROR: return "Internal error"; case SL_RESULT_UNKNOWN_ERROR: return "Unknown error"; case SL_RESULT_OPERATION_ABORTED: return "Operation aborted"; case SL_RESULT_CONTROL_LOST: return "Control lost"; } return "Unknown OpenSL error"; } /* Only the original 'engine' object should be passed here */ static SLEngineItf getEngine(SLObjectItf engine){ SLresult result; SLEngineItf interface; result = (*engine)->GetInterface(engine, SL_IID_ENGINE, &interface); if (result == SL_RESULT_SUCCESS){ return interface; } else { ALLEGRO_ERROR("Could not get opensl engine: %s\n", opensl_get_error_string(result)); return NULL; } } /* Create an output mixer */ static SLObjectItf createOutputMixer(SLEngineItf engine){ SLresult result; SLObjectItf output; SLboolean required[1]; SLInterfaceID ids[1]; /* Not all android devices support a mixer that you can control * the volume on, so just ignore it for now. */ required[0] = SL_BOOLEAN_TRUE; ids[0] = SL_IID_VOLUME; result = (*engine)->CreateOutputMix(engine, &output, 0, ids, required); if (result != SL_RESULT_SUCCESS){ ALLEGRO_ERROR("Could not create output mix: %s\n", opensl_get_error_string(result)); return NULL; } result = (*output)->Realize(output, SL_BOOLEAN_FALSE); if (result != SL_RESULT_SUCCESS){ ALLEGRO_ERROR("Could not realize the output mix: %s\n", opensl_get_error_string(result)); (*output)->Destroy(output); return NULL; } return output; } static int _opensl_open(void) { SLresult result; SLuint32 state; SLEngineOption options[] = { { SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE }, /* { SL_ENGINEOPTION_MAJORVERSION, (SLuint32) 1 }, { SL_ENGINEOPTION_MINORVERSION, (SLuint32) 1 }, */ }; result = slCreateEngine(&engine, 1, options, 0, NULL, NULL); if (result != SL_RESULT_SUCCESS){ ALLEGRO_ERROR("Could not open audio device: %s\n", opensl_get_error_string(result)); return 1; } /* Transition the engine to the realized state in synchronous mode */ result = (*engine)->GetState(engine, &state); if (result == SL_RESULT_SUCCESS){ switch (state){ case SL_OBJECT_STATE_UNREALIZED: { result = (*engine)->Realize(engine, SL_BOOLEAN_FALSE); break; } case SL_OBJECT_STATE_REALIZED: { /* This is good */ break; } case SL_OBJECT_STATE_SUSPENDED: { result = (*engine)->Resume(engine, SL_BOOLEAN_FALSE); break; } } } else { return 1; } // output = createOutputMixer(getEngine(engine)); return 0; } static void _opensl_close(void) { /* if (output != NULL){ (*output)->Destroy(output); output = NULL; } */ if (engine != NULL){ (*engine)->Destroy(engine); engine = NULL; } } typedef struct OpenSLData{ /* Output mixer */ SLObjectItf output; /* Audio player */ SLObjectItf player; volatile enum { PLAYING, STOPPING, STOPPED } status; /* load_voice stuff that isn't used, but might be someday */ /* const void * data; int position; int length; */ /* Size of a single sample: depth * channels */ int frame_size; ALLEGRO_THREAD * poll_thread; /* local buffers to keep opensl fed since it doesn't copy * data by default. */ char * buffers[MAX_BUFFERS]; } OpenSLData; static SLDataFormat_PCM setupFormat(ALLEGRO_VOICE * voice){ SLDataFormat_PCM format; format.formatType = SL_DATAFORMAT_PCM; format.numChannels = al_get_channel_count(voice->chan_conf); /* TODO: review the channelMasks */ switch (voice->chan_conf){ case ALLEGRO_CHANNEL_CONF_1: { /* Not sure if center is right.. */ format.channelMask = SL_SPEAKER_FRONT_CENTER; break; } case ALLEGRO_CHANNEL_CONF_2: { format.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; break; } case ALLEGRO_CHANNEL_CONF_3: { format.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER; break; } case ALLEGRO_CHANNEL_CONF_4: { format.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_RIGHT; break; } case ALLEGRO_CHANNEL_CONF_5_1: { format.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY; break; } case ALLEGRO_CHANNEL_CONF_6_1: { format.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT; break; } case ALLEGRO_CHANNEL_CONF_7_1: { format.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT | SL_SPEAKER_TOP_CENTER; break; } default: { ALLEGRO_ERROR("Cannot allocate voice with unknown channel configuration\n"); } } switch (voice->frequency){ case 8000: format.samplesPerSec = SL_SAMPLINGRATE_8; break; case 11025: format.samplesPerSec = SL_SAMPLINGRATE_11_025; break; case 12000: format.samplesPerSec = SL_SAMPLINGRATE_12; break; case 16000: format.samplesPerSec = SL_SAMPLINGRATE_16; break; case 22050: format.samplesPerSec = SL_SAMPLINGRATE_22_05; break; case 24000: format.samplesPerSec = SL_SAMPLINGRATE_24; break; case 32000: format.samplesPerSec = SL_SAMPLINGRATE_32; break; case 44100: format.samplesPerSec = SL_SAMPLINGRATE_44_1; break; case 48000: format.samplesPerSec = SL_SAMPLINGRATE_48; break; case 64000: format.samplesPerSec = SL_SAMPLINGRATE_64; break; case 88200: format.samplesPerSec = SL_SAMPLINGRATE_88_2; break; case 96000: format.samplesPerSec = SL_SAMPLINGRATE_96; break; case 192000: format.samplesPerSec = SL_SAMPLINGRATE_192; break; default: { ALLEGRO_ERROR("Unsupported frequency %d. Using 44100 instead.\n", voice->frequency); format.samplesPerSec = SL_SAMPLINGRATE_44_1; voice->frequency = 44100; } } switch (voice->depth) { case ALLEGRO_AUDIO_DEPTH_UINT8: case ALLEGRO_AUDIO_DEPTH_INT8: { format.bitsPerSample = 8; format.containerSize = 8; break; } case ALLEGRO_AUDIO_DEPTH_UINT16: case ALLEGRO_AUDIO_DEPTH_INT16: { format.bitsPerSample = 16; format.containerSize = 16; break; } case ALLEGRO_AUDIO_DEPTH_UINT24: case ALLEGRO_AUDIO_DEPTH_INT24: { format.bitsPerSample = 24; format.containerSize = 32; break; } case ALLEGRO_AUDIO_DEPTH_FLOAT32: { format.bitsPerSample = 32; format.containerSize = 32; break; } default: { ALLEGRO_WARN("Cannot allocate unknown voice depth\n"); } } #ifdef ALLEGRO_BIG_ENDIAN format.endianness = SL_BYTEORDER_BIGENDIAN; #else format.endianness = SL_BYTEORDER_LITTLEENDIAN; #endif /* Then OpenSL spec says these values are needed for SLDataFormat_PCM_EX * but not all implementations define that struct. If they do then * the following code can be used. */ /* switch (voice->depth){ case ALLEGRO_AUDIO_DEPTH_UINT8: case ALLEGRO_AUDIO_DEPTH_UINT16: case ALLEGRO_AUDIO_DEPTH_UINT24: { format.representation = SL_PCM_REPRESENTATION_UNSIGNED_INT; } case ALLEGRO_AUDIO_DEPTH_INT8: case ALLEGRO_AUDIO_DEPTH_INT16: case ALLEGRO_AUDIO_DEPTH_INT24: { format.representation = SL_PCM_REPRESENTATION_SIGNED_INT; break; } case ALLEGRO_AUDIO_DEPTH_FLOAT32: { format.representation = SL_PCM_REPRESENTATION_FLOAT; break; } } */ return format; } static SLObjectItf createAudioPlayer(SLEngineItf engine, SLDataSource * source, SLDataSink * sink){ SLresult result; SLObjectItf player; SLboolean required[1]; SLInterfaceID ids[1]; required[0] = SL_BOOLEAN_TRUE; ids[0] = SL_IID_BUFFERQUEUE; result = (*engine)->CreateAudioPlayer(engine, &player, source, sink, 1, ids, required); if (result != SL_RESULT_SUCCESS){ ALLEGRO_ERROR("Could not create audio player: %s\n", opensl_get_error_string(result)); return NULL; } result = (*player)->Realize(player, SL_BOOLEAN_FALSE); if (result != SL_RESULT_SUCCESS){ ALLEGRO_ERROR("Could not realize audio player: %s\n", opensl_get_error_string(result)); return NULL; } return player; } static SLObjectItf makeStreamingPlayer(ALLEGRO_VOICE * voice, SLObjectItf mixer){ SLDataFormat_PCM format = setupFormat(voice); SLDataLocator_BufferQueue bufferQueue; SLDataSource audioSource; SLDataSink audioSink; SLDataLocator_OutputMix output; bufferQueue.locatorType = SL_DATALOCATOR_BUFFERQUEUE; bufferQueue.numBuffers = MAX_BUFFERS; audioSource.pFormat = (void*) &format; audioSource.pLocator = (void*) &bufferQueue; output.locatorType = SL_DATALOCATOR_OUTPUTMIX; output.outputMix = mixer; audioSink.pLocator = (void*) &output; audioSink.pFormat = NULL; return createAudioPlayer(getEngine(engine), &audioSource, &audioSink); /* SLresult result; SLVolumeItf volume; result = (*extra->output)->GetInterface(extra->output, SL_IID_VOLUME, &volume); if (result != SL_RESULT_SUCCESS){ ALLEGRO_ERROR("Could not get volume interface: %s\n", opensl_get_error_string(result)); return 1; } */ } /* Number of active buffers in the queue. Will not be more than MAX_BUFFERS */ static int bufferCount(SLObjectItf player){ SLBufferQueueItf queue; SLBufferQueueState state; (*player)->GetInterface(player, SL_IID_BUFFERQUEUE, &queue); (*queue)->GetState(queue, &state); return state.count; } /* Attach some data to the OpenSL player. The data is not copied */ static void enqueue(SLObjectItf player, const void * data, int bytes){ SLresult result; SLBufferQueueItf queue; SLPlayItf play; result = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE, &queue); if (result != SL_RESULT_SUCCESS){ ALLEGRO_ERROR("Could not get bufferqueue interface: %s\n", opensl_get_error_string(result)); return; } // ALLEGRO_DEBUG("Play voice data %p\n", data); result = (*queue)->Enqueue(queue, data, bytes); if (result != SL_RESULT_SUCCESS){ ALLEGRO_ERROR("Could not enqueue data: %s\n", opensl_get_error_string(result)); return; } // result = (*volume)->SetVolumeLevel(volume, -300); result = (*player)->GetInterface(player, SL_IID_PLAY, &play); /* In case the player is not playing, make it play */ result = (*play)->SetPlayState(play, SL_PLAYSTATE_PLAYING); if (result != SL_RESULT_SUCCESS){ ALLEGRO_ERROR("Could not set play state on OpenSL stream\n"); } /* SLBufferQueueState state; result = (*queue)->GetState(queue, &state); if (result == SL_RESULT_SUCCESS){ ALLEGRO_DEBUG("Buffer queue state count %d index %d\n", state.count, state.playIndex); } */ } static void * opensl_update(ALLEGRO_THREAD * self, void * data){ ALLEGRO_VOICE *voice = data; OpenSLData * opensl = voice->extra; int bufferIndex = 0; while (!al_get_thread_should_stop(self)) { if (opensl->status == PLAYING) { // unsigned int frames = 4096; unsigned int frames = MAX_FRAMES; if (voice->is_streaming) { // streaming audio if (bufferCount(opensl->player) < MAX_BUFFERS){ const void * data = _al_voice_update(voice, voice->mutex, &frames); if (data){ /* Copy the data to a local buffer because a call to enqueue * will use the memory in place and al_voice_update will * re-use the same buffer for each call so we don't want * to corrupt memory when the next call to al_voice_update * is made. */ char * buffer = opensl->buffers[bufferIndex]; memcpy(buffer, data, frames * opensl->frame_size); enqueue(opensl->player, buffer, frames * opensl->frame_size); bufferIndex = (bufferIndex + 1) % MAX_BUFFERS; } } else { al_rest(0.001); } } else { ALLEGRO_ERROR("Unimplemented direct audio\n"); /* // direct buffer audio al_lock_mutex(pv->buffer_mutex); const char *data = pv->buffer; unsigned int len = frames * pv->frame_size; pv->buffer += frames * pv->frame_size; if (pv->buffer > pv->buffer_end) { len = pv->buffer_end - data; pv->buffer = voice->attached_stream->spl_data.buffer.ptr; voice->attached_stream->pos = 0; if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_ONCE) { pv->status = PV_STOPPING; } } else { voice->attached_stream->pos += frames; } al_unlock_mutex(pv->buffer_mutex); pa_simple_write(pv->s, data, len, NULL); */ } } else if (opensl->status == STOPPING){ if (bufferCount(opensl->player) == 0){ /* When the buffer count is 0 the opensl buffer queue should * transition to the SL_PLAYSTATE_STOPPED state automatically. */ opensl->status = STOPPED; } } else if (opensl->status == STOPPED){ al_rest(0.001); } } return NULL; } static int _opensl_allocate_voice(ALLEGRO_VOICE *voice) { OpenSLData * data; int i; data = al_calloc(1, sizeof(*data)); voice->extra = data; data->output = createOutputMixer(getEngine(engine)); if (data->output == NULL){ al_free(data); return 1; } data->player = NULL; /* data->data = NULL; data->position = 0; data->length = voice->buffer_size; */ data->frame_size = al_get_channel_count(voice->chan_conf) * al_get_audio_depth_size(voice->depth); data->status = STOPPED; data->poll_thread = NULL; for (i = 0; i < MAX_BUFFERS; i++){ data->buffers[i] = al_malloc(data->frame_size * MAX_FRAMES); } data->player = makeStreamingPlayer(voice, data->output); if (data->player == NULL){ return 1; } data->poll_thread = al_create_thread(opensl_update, (void*)voice); al_start_thread(data->poll_thread); return 0; } static void _opensl_deallocate_voice(ALLEGRO_VOICE *voice) { OpenSLData * data = (OpenSLData*) voice->extra; int i; if (data->poll_thread != NULL){ al_set_thread_should_stop(data->poll_thread); al_join_thread(data->poll_thread, NULL); al_destroy_thread(data->poll_thread); data->poll_thread = NULL; } if (data->player != NULL){ (*data->player)->Destroy(data->player); data->player = NULL; } if (data->output != NULL){ (*data->output)->Destroy(data->output); data->output = NULL; } for (i = 0; i < MAX_BUFFERS; i++){ al_free(data->buffers[i]); } al_free(voice->extra); voice->extra = NULL; } /* load_voice is only called by attach_sample_instance_to_voice which * isn't really used, so we leave it unimplemented for now. */ static int _opensl_load_voice(ALLEGRO_VOICE *voice, const void *data) { (void) voice; (void) data; /* OpenSLData * extra = (OpenSLData*) voice->extra; ALLEGRO_DEBUG("Load voice data %p\n", data); extra->data = data; extra->position = 0; */ return 1; } static void _opensl_unload_voice(ALLEGRO_VOICE *voice) { (void) voice; /* OpenSLData * extra = (OpenSLData*) voice->extra; extra->data = NULL; extra->position = 0; */ } /* static void updateQueue(SLBufferQueueItf queue, void * context){ OpenSLData * data = (OpenSLData*) context; if (data->position < data->length){ int bytes = data->frame_size * 1024; if (data->position + bytes > data->length){ bytes = ((data->length - data->position) / data->frame_size) * data->frame_size; } SLresult result; ALLEGRO_DEBUG("Enqueue %d bytes\n", bytes); result = (*queue)->Enqueue(queue, (char*) data->data + data->position, bytes); data->position += bytes; } } */ static int _opensl_start_voice(ALLEGRO_VOICE *voice) { OpenSLData * extra = (OpenSLData*) voice->extra; extra->status = PLAYING; /* result = (*extra->player)->GetInterface(extra->player, SL_IID_BUFFERQUEUE, &queue); if (result != SL_RESULT_SUCCESS){ ALLEGRO_ERROR("Could not get bufferqueue interface: %s\n", opensl_get_error_string(result)); return 1; } ALLEGRO_DEBUG("Start playing voice data %p\n", extra->data); result = (*queue)->Enqueue(queue, (char*) extra->data + extra->position, extra->frame_size * 32); if (result != SL_RESULT_SUCCESS){ ALLEGRO_ERROR("Could not enqueue data: %s\n", opensl_get_error_string(result)); } extra->position += extra->frame_size * 32; result = (*queue)->RegisterCallback(queue, updateQueue, extra); if (result != SL_RESULT_SUCCESS){ ALLEGRO_ERROR("Could not register callback: %s\n", opensl_get_error_string(result)); } // result = (*volume)->SetVolumeLevel(volume, -300); result = (*extra->player)->GetInterface(extra->player, SL_IID_PLAY, &play); result = (*play)->SetPlayState(play, SL_PLAYSTATE_PLAYING); if (result == SL_RESULT_SUCCESS){ ALLEGRO_DEBUG("Started new OpenSL stream\n"); } result = (*queue)->GetState(queue, &state); if (result == SL_RESULT_SUCCESS){ ALLEGRO_DEBUG("Buffer queue state count %d index %d\n", state.count, state.playIndex); } */ return 0; } static int _opensl_stop_voice(ALLEGRO_VOICE* voice) { OpenSLData * data = (OpenSLData*) voice->extra; if (data->status == PLAYING){ data->status = STOPPING; } while (data->status != STOPPED){ al_rest(0.001); } return 0; } static bool _opensl_voice_is_playing(const ALLEGRO_VOICE *voice) { OpenSLData * extra = (OpenSLData*) voice->extra; return extra->status == PLAYING; } static unsigned int _opensl_get_voice_position(const ALLEGRO_VOICE *voice) { /* TODO */ (void) voice; ALLEGRO_ERROR("Unimplemented: _opensl_get_voice_position\n"); return 0; } static int _opensl_set_voice_position(ALLEGRO_VOICE *voice, unsigned int val) { /* TODO */ (void) voice; (void) val; ALLEGRO_ERROR("Unimplemented: _opensl_set_voice_position\n"); return 1; } ALLEGRO_AUDIO_DRIVER _al_kcm_opensl_driver = { "OpenSL", _opensl_open, _opensl_close, _opensl_allocate_voice, _opensl_deallocate_voice, _opensl_load_voice, _opensl_unload_voice, _opensl_start_voice, _opensl_stop_voice, _opensl_voice_is_playing, _opensl_get_voice_position, _opensl_set_voice_position, NULL, NULL, NULL }; allegro5-5.2.10.1/addons/audio/oss.c000066400000000000000000000377261473414355200170200ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Open Sound System sound driver. * * By Milan Mimica. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_audio.h" #include #include #include #include #include #include ALLEGRO_DEBUG_CHANNEL("oss") #if defined ALLEGRO_HAVE_SOUNDCARD_H #include #elif defined ALLEGRO_HAVE_SYS_SOUNDCARD_H #include #elif defined ALLEGRO_HAVE_LINUX_SOUNDCARD_H #include #elif defined ALLEGRO_HAVE_MACHINE_SOUNDCARD_H #include #endif #if OSS_VERSION >= 0x040000 #define OSS_VER_4 #else #define OSS_VER_3 #endif #ifndef AFMT_S16_NE #ifdef ALLEGRO_BIG_ENDIAN #define AFMT_S16_NE AFMT_S16_BE #else #define AFMT_S16_NE AFMT_S16_LE #endif #endif #ifndef AFMT_U16_NE #ifdef ALLEGRO_BIG_ENDIAN #define AFMT_U16_NE AFMT_U16_BE #else #define AFMT_U16_NE AFMT_U16_LE #endif #endif /* Audio device used by OSS3. * Make this configurable. */ static const char* oss_audio_device_ver3 = "/dev/dsp"; /* Audio device is dynamically retrived in OSS4. */ static char oss_audio_device[512]; /* timing policy (between 0 and 10), used by OSS4 * Make this configurable? */ #ifdef OSS_VER_4 static const int oss_timing_policy = 5; #endif /* Fragment size, used by OSS3 * Make this configurable? */ static int oss_fragsize = (8 << 16) | (10); /* Auxiliary buffer used to store silence. */ #define SIL_BUF_SIZE 1024 static bool using_ver_4; typedef struct OSS_VOICE { int fd; int volume; /* Copied from the parent ALLEGRO_VOICE. Used for convenince. */ unsigned int len; /* in frames */ unsigned int frame_size; /* in bytes */ volatile bool stopped; volatile bool stop; ALLEGRO_THREAD *poll_thread; } OSS_VOICE; #ifdef OSS_VER_4 static int oss_open_ver4() { int mixer_fd, i; oss_sysinfo sysinfo; if ((mixer_fd = open("/dev/mixer", O_RDWR, 0)) == -1) { switch (errno) { case ENXIO: case ENODEV: ALLEGRO_ERROR("Open Sound System is not running in your system.\n"); break; case ENOENT: ALLEGRO_ERROR("No /dev/mixer device available in your system.\n"); ALLEGRO_ERROR("Perhaps Open Sound System is not installed or " "running.\n"); break; default: ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); } return 1; } if (ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) == -1) { if (errno == ENXIO) { ALLEGRO_ERROR("OSS has not detected any supported sound hardware in " "your system.\n"); } else if (errno == EINVAL) { ALLEGRO_INFO("The version of OSS installed on the system is not " "compatible with OSS4.\n"); } else ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); close(mixer_fd); return 1; } /* Some OSS implementations (ALSA emulation) don't fail on SNDCTL_SYSINFO even * though they don't support OSS4. They *seem* to set numcards to 0. */ if (sysinfo.numcards < 1) { ALLEGRO_WARN("The version of OSS installed on the system is not " "compatible with OSS4.\n"); return 1; } ALLEGRO_INFO("OSS Version: %s\n", sysinfo.version); ALLEGRO_INFO("Found %i sound cards.\n", sysinfo.numcards); for (i = 0; i < sysinfo.numcards; i++) { oss_audioinfo audioinfo; memset(&audioinfo, 0, sizeof(oss_audioinfo)); audioinfo.dev = i; ALLEGRO_INFO("Trying sound card no. %i ...\n", audioinfo.dev); ioctl(mixer_fd, SNDCTL_AUDIOINFO, &audioinfo); if (audioinfo.enabled) { if (strlen(audioinfo.devnode)) { strncpy(oss_audio_device, audioinfo.devnode, 511); } else if (audioinfo.legacy_device != -1) { sprintf(oss_audio_device, "/dev/dsp%i", audioinfo.legacy_device); } else { ALLEGRO_ERROR("Cannot find device name.\n"); } ALLEGRO_INFO("Using device: %s\n", oss_audio_device); break; } else { ALLEGRO_INFO("Device disabled.\n"); } } if (i == sysinfo.numcards) { ALLEGRO_ERROR("Couldn't find a suitable device.\n"); close(mixer_fd); return 1; } close(mixer_fd); using_ver_4 = true; return 0; } #endif static int oss_open_ver3(void) { const char *config_device; config_device = al_get_config_value(al_get_system_config(), "oss", "device"); if (config_device && config_device[0] != '\0') oss_audio_device_ver3 = config_device; int fd = open(oss_audio_device_ver3, O_WRONLY); if (fd == -1) { switch (errno) { case ENXIO: case ENODEV: ALLEGRO_ERROR("Open Sound System is not running in your " "system.\n"); break; case ENOENT: ALLEGRO_ERROR("No '%s' device available in your system.\n", oss_audio_device_ver3); ALLEGRO_ERROR("Perhaps Open Sound System is not installed " "or running.\n"); break; default: ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); } return 1; } close(fd); strncpy(oss_audio_device, oss_audio_device_ver3, 511); ALLEGRO_INFO("Using device: %s\n", oss_audio_device); using_ver_4 = false; return 0; } static int oss_open(void) { bool force_oss3 = false; const char *force_oss3_cfg; force_oss3_cfg = al_get_config_value(al_get_system_config(), "oss", "force_ver3"); if (force_oss3_cfg && force_oss3_cfg[0] != '\0') force_oss3 = strcmp(force_oss3_cfg, "yes") ? false : true; if (force_oss3) { ALLEGRO_WARN("Skipping OSS4 probe.\n"); } #ifdef OSS_VER_4 bool inited = false; if (!force_oss3) { if (oss_open_ver4()) ALLEGRO_WARN("OSS ver. 4 init failed, trying ver. 3...\n"); else inited = true; } if (!inited && oss_open_ver3()) { ALLEGRO_ERROR("Failed to init OSS.\n"); return 1; } #else ALLEGRO_INFO("OSS4 support not compiled in. Skipping OSS4 probe.\n"); if (oss_open_ver3()) { ALLEGRO_ERROR("Failed to init OSS.\n"); return 1; } #endif return 0; } static void oss_close(void) { } static void oss_deallocate_voice(ALLEGRO_VOICE *voice) { OSS_VOICE *oss_voice = voice->extra; /* We do NOT hold the voice mutex here, so this does NOT result in a * deadlock when oss_update calls _al_voice_update (which tries to * acquire the voice->mutex). */ al_join_thread(oss_voice->poll_thread, NULL); al_destroy_thread(oss_voice->poll_thread); close(oss_voice->fd); al_free(voice->extra); voice->extra = NULL; } static int oss_start_voice(ALLEGRO_VOICE *voice) { OSS_VOICE *ex_data = voice->extra; ex_data->stop = false; return 0; } static int oss_stop_voice(ALLEGRO_VOICE *voice) { OSS_VOICE *ex_data = voice->extra; ex_data->stop = true; if (!voice->is_streaming) { voice->attached_stream->pos = 0; } while (!ex_data->stopped) al_rest(0.001); return 0; } static int oss_load_voice(ALLEGRO_VOICE *voice, const void *data) { OSS_VOICE *ex_data = voice->extra; /* * One way to support backward playing would be to do like alsa driver does: * mmap(2) the FD and write reversed samples into that. To much trouble for * an optional feature IMO. -- milan */ if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_BIDIR) { ALLEGRO_INFO("Backwards playing not supported by the driver.\n"); return -1; } voice->attached_stream->pos = 0; ex_data->len = voice->attached_stream->spl_data.len; return 0; (void)data; } static void oss_unload_voice(ALLEGRO_VOICE *voice) { (void)voice; } static bool oss_voice_is_playing(const ALLEGRO_VOICE *voice) { OSS_VOICE *ex_data = voice->extra; return !ex_data->stopped; } static unsigned int oss_get_voice_position(const ALLEGRO_VOICE *voice) { return voice->attached_stream->pos; } static int oss_set_voice_position(ALLEGRO_VOICE *voice, unsigned int val) { voice->attached_stream->pos = val; return 0; } /* * Updates the supplied non-streaming voice. * buf - Returns a pointer to the buffer containing sample data. * bytes - The requested size of the sample data buffer. Returns the actual * size of returned the buffer. * Updates 'stop', 'pos' and 'reversed' fields of the supplied voice to the * future position. */ static int oss_update_nonstream_voice(ALLEGRO_VOICE *voice, void **buf, int *bytes) { OSS_VOICE *oss_voice = voice->extra; int bpos = voice->attached_stream->pos * oss_voice->frame_size; int blen = oss_voice->len * oss_voice->frame_size; *buf = (char *)voice->attached_stream->spl_data.buffer.ptr + bpos; if (bpos + *bytes > blen) { *bytes = blen - bpos; if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_ONCE) { oss_voice->stop = true; voice->attached_stream->pos = 0; } if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_LOOP) { voice->attached_stream->pos = 0; } /*else if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_BIDIR) { oss_voice->reversed = true; voice->attached_stream->pos = oss_voice->len; }*/ return 1; } else voice->attached_stream->pos += *bytes / oss_voice->frame_size; return 0; } static void oss_update_silence(ALLEGRO_VOICE *voice, OSS_VOICE *oss_voice) { char sil_buf[SIL_BUF_SIZE]; unsigned int silent_samples; silent_samples = SIL_BUF_SIZE / (al_get_audio_depth_size(voice->depth) * al_get_channel_count(voice->chan_conf)); al_fill_silence(sil_buf, silent_samples, voice->depth, voice->chan_conf); if (write(oss_voice->fd, sil_buf, SIL_BUF_SIZE) == -1) { ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); } } static void* oss_update(ALLEGRO_THREAD *self, void *arg) { ALLEGRO_VOICE *voice = arg; OSS_VOICE *oss_voice = voice->extra; (void)self; while (!al_get_thread_should_stop(self)) { /* For possible eventual non-blocking mode: audio_buf_info bi; if (ioctl(oss_voice->fd, SNDCTL_DSP_GETOSPACE, &bi) == -1) { ALLEGRO_ERROR("Error SNDCTL_DSP_GETOSPACE, errno=%i (%s)\n", errno, strerror(errno)); return NULL; } len = bi.bytes; */ /* How many bytes are we supposed to try to write at once? */ unsigned int frames = 1024; if (oss_voice->stop && !oss_voice->stopped) { oss_voice->stopped = true; } if (!oss_voice->stop && oss_voice->stopped) { oss_voice->stopped = false; } if (!voice->is_streaming && !oss_voice->stopped) { void *buf; int bytes = frames * oss_voice->frame_size; oss_update_nonstream_voice(voice, &buf, &bytes); frames = bytes / oss_voice->frame_size; if (write(oss_voice->fd, buf, bytes) == -1) { ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); if (errno != EINTR) return NULL; } } else if (voice->is_streaming && !oss_voice->stopped) { const void *data = _al_voice_update(voice, voice->mutex, &frames); if (data == NULL) { oss_update_silence(voice, oss_voice); continue; } if (write(oss_voice->fd, data, frames * oss_voice->frame_size) == -1) { ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); if (errno != EINTR) return NULL; } } else { /* If stopped just fill with silence. */ oss_update_silence(voice, oss_voice); } } return NULL; } static int oss_allocate_voice(ALLEGRO_VOICE *voice) { int format; int chan_count; OSS_VOICE *ex_data = al_calloc(1, sizeof(OSS_VOICE)); if (!ex_data) return 1; ex_data->fd = open(oss_audio_device, O_WRONLY/*, O_NONBLOCK*/); if (ex_data->fd == -1) { ALLEGRO_ERROR("Failed to open audio device '%s'.\n", oss_audio_device); ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); al_free(ex_data); return 1; } chan_count = al_get_channel_count(voice->chan_conf); ex_data->frame_size = chan_count * al_get_audio_depth_size(voice->depth); if (!ex_data->frame_size) goto Error; ex_data->stop = true; ex_data->stopped = true; if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT8) format = AFMT_S8; else if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT8) format = AFMT_U8; else if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT16) format = AFMT_S16_NE; else if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT16) format = AFMT_U16_NE; #ifdef OSS_VER_4 else if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT24) format = AFMT_S24_NE; else if (voice->depth == ALLEGRO_AUDIO_DEPTH_FLOAT32) format = AFMT_FLOAT; #endif else { ALLEGRO_ERROR("Unsupported OSS sound format.\n"); goto Error; } int tmp_format = format; int tmp_chan_count = chan_count; unsigned int tmp_freq = voice->frequency; int tmp_oss_fragsize = oss_fragsize; if (using_ver_4) { #ifdef OSS_VER_4 int tmp_oss_timing_policy = oss_timing_policy; if (ioctl(ex_data->fd, SNDCTL_DSP_POLICY, &tmp_oss_timing_policy) == -1) { ALLEGRO_ERROR("Failed to set_timig policity to '%i'.\n", tmp_oss_timing_policy); ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); goto Error; } ALLEGRO_INFO("Accepted timing policy value: %i\n", tmp_oss_timing_policy); #endif } else { if (ioctl(ex_data->fd, SNDCTL_DSP_SETFRAGMENT, &tmp_oss_fragsize) == -1) { ALLEGRO_ERROR("Failed to set fragment size.\n"); ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); goto Error; } } if (ioctl(ex_data->fd, SNDCTL_DSP_SETFMT, &tmp_format) == -1) { ALLEGRO_ERROR("Failed to set sample format.\n"); ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); goto Error; } if (tmp_format != format) { ALLEGRO_ERROR("Sample format not supported by the driver.\n"); goto Error; } if (ioctl(ex_data->fd, SNDCTL_DSP_CHANNELS, &tmp_chan_count)) { ALLEGRO_ERROR("Failed to set channel count.\n"); ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); goto Error; } if (tmp_chan_count != chan_count) { ALLEGRO_ERROR("Requested sample channe count %i, got %i.\n", tmp_chan_count, chan_count); } if (ioctl(ex_data->fd, SNDCTL_DSP_SPEED, &tmp_freq) == -1) { ALLEGRO_ERROR("Failed to set sample rate.\n"); ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno)); goto Error; } if (voice->frequency != tmp_freq) { ALLEGRO_ERROR("Requested sample rate %u, got %iu.\n", voice->frequency, tmp_freq); } voice->extra = ex_data; ex_data->poll_thread = al_create_thread(oss_update, (void*)voice); al_start_thread(ex_data->poll_thread); return 0; Error: close(ex_data->fd); al_free(ex_data); return 1; } ALLEGRO_AUDIO_DRIVER _al_kcm_oss_driver = { "OSS", oss_open, oss_close, oss_allocate_voice, oss_deallocate_voice, oss_load_voice, oss_unload_voice, oss_start_voice, oss_stop_voice, oss_voice_is_playing, oss_get_voice_position, oss_set_voice_position, NULL, NULL, NULL }; /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/pulseaudio.c000066400000000000000000000375311473414355200203600ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * PulseAudio sound driver. * * By Matthew Leverton. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_audio.h" #include #include #include #include #include ALLEGRO_DEBUG_CHANNEL("PulseAudio") enum PULSEAUDIO_VOICE_STATUS { PV_IDLE, PV_PLAYING, PV_STOPPING, PV_JOIN }; typedef struct PULSEAUDIO_VOICE { pa_simple *s; unsigned int buffer_size_in_frames; unsigned int frame_size_in_bytes; ALLEGRO_THREAD *poll_thread; /* status_cond and status are protected by voice->mutex. * Using another mutex introduces a deadlock if waiting for a change in * status (while holding voice->mutex, acquired by a higher layer) * and the background thread tries to acquire voice->mutex as well. */ ALLEGRO_COND *status_cond; enum PULSEAUDIO_VOICE_STATUS status; // direct buffer (non-streaming): ALLEGRO_MUTEX *buffer_mutex; char *buffer; char *buffer_end; } PULSEAUDIO_VOICE; static _AL_LIST* output_device_list; #define DEFAULT_BUFFER_SIZE 1024 #define MIN_BUFFER_SIZE 128 static unsigned int get_buffer_size(const ALLEGRO_CONFIG *config) { if (config) { const char *val = al_get_config_value(config, "pulseaudio", "buffer_size"); if (val && val[0] != '\0') { int n = atoi(val); if (n < MIN_BUFFER_SIZE) n = MIN_BUFFER_SIZE; return n; } } return DEFAULT_BUFFER_SIZE; } static void _output_device_list_dtor(void* value, void* userdata) { (void)userdata; ALLEGRO_AUDIO_DEVICE* device = (ALLEGRO_AUDIO_DEVICE*)value; al_free(device->name); al_free(device->identifier); al_free(device); } static void sink_info_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata) { (void)c; (void)eol; if (!output_device_list) { output_device_list = _al_list_create(); } pa_sink_state_t *ret = userdata; if (!i) return; *ret = i->state; int iden_len = strlen(i->name) + 1; int name_len = strlen(i->description) + 1; ALLEGRO_AUDIO_DEVICE* device = (ALLEGRO_AUDIO_DEVICE*)al_malloc(sizeof(ALLEGRO_AUDIO_DEVICE)); device->identifier = (void*)al_malloc(iden_len); device->name = (char*)al_malloc(name_len); strcpy(device->name, i->description); strcpy(device->identifier, i->name); _al_list_push_back_ex(output_device_list, device, _output_device_list_dtor); } static int pulseaudio_open(void) { /* Use PA_CONTEXT_NOAUTOSPAWN to see if a PA server is running. * If not, fail - we're better off using ALSA/OSS. * * Also check for suspended PA - again better using ALSA/OSS in * that case (pa_simple_write just blocks until PA is unsuspended * otherwise). * * TODO: Maybe we should have a force flag to the audio driver * open method, which in the case of PA would spawn a server if * none is running (and also unsuspend?). */ pa_mainloop *mainloop = pa_mainloop_new(); pa_context *c = pa_context_new(pa_mainloop_get_api(mainloop), al_get_app_name()); if (!c) { pa_mainloop_free(mainloop); return 1; } pa_context_connect(c, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL); while (1) { /* Don't block or it will hang if there is no server to connect to. */ const int blocking = 0; if (pa_mainloop_iterate(mainloop, blocking, NULL) < 0) { ALLEGRO_ERROR("pa_mainloop_iterate failed\n"); pa_context_disconnect(c); pa_context_unref(c); pa_mainloop_free(mainloop); return 1; } pa_context_state_t s = pa_context_get_state(c); if (s == PA_CONTEXT_READY) { ALLEGRO_DEBUG("PA_CONTEXT_READY\n"); break; } if (s == PA_CONTEXT_FAILED) { ALLEGRO_ERROR("PA_CONTEXT_FAILED\n"); pa_context_disconnect(c); pa_context_unref(c); pa_mainloop_free(mainloop); return 1; } } pa_sink_state_t state = 0; pa_operation *op = pa_context_get_sink_info_list(c, sink_info_cb, &state); while (pa_operation_get_state(op) == PA_OPERATION_RUNNING) { pa_mainloop_iterate(mainloop, 1, NULL); } /*if (state == PA_SINK_SUSPENDED) { pa_context_disconnect(c); pa_context_unref(c); pa_mainloop_free(mainloop); return 1; }*/ pa_operation_unref(op); pa_context_disconnect(c); pa_context_unref(c); pa_mainloop_free(mainloop); return 0; } static void pulseaudio_close(void) { _al_list_destroy(output_device_list); } static void *pulseaudio_update(ALLEGRO_THREAD *self, void *data) { ALLEGRO_VOICE *voice = data; PULSEAUDIO_VOICE *pv = voice->extra; (void)self; void* silence = al_malloc(pv->buffer_size_in_frames * pv->frame_size_in_bytes); al_fill_silence(silence, pv->buffer_size_in_frames, voice->depth, voice->chan_conf); for (;;) { enum PULSEAUDIO_VOICE_STATUS status; al_lock_mutex(voice->mutex); while ((status = pv->status) == PV_IDLE) { al_wait_cond(pv->status_cond, voice->mutex); } al_unlock_mutex(voice->mutex); if (status == PV_JOIN) { break; } if (status == PV_PLAYING) { unsigned int frames = pv->buffer_size_in_frames; if (voice->is_streaming) { // streaming audio const void *data = _al_voice_update(voice, voice->mutex, &frames); if (!data) { data = silence; frames = pv->buffer_size_in_frames; } pa_simple_write(pv->s, data, frames * pv->frame_size_in_bytes, NULL); } else { // direct buffer audio al_lock_mutex(pv->buffer_mutex); const char *data = pv->buffer; unsigned int len = frames * pv->frame_size_in_bytes; pv->buffer += frames * pv->frame_size_in_bytes; if (pv->buffer > pv->buffer_end) { len = pv->buffer_end - data; pv->buffer = voice->attached_stream->spl_data.buffer.ptr; voice->attached_stream->pos = 0; if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_ONCE) { al_lock_mutex(voice->mutex); pv->status = PV_STOPPING; al_broadcast_cond(pv->status_cond); al_unlock_mutex(voice->mutex); } } else { voice->attached_stream->pos += frames; } al_unlock_mutex(pv->buffer_mutex); pa_simple_write(pv->s, data, len, NULL); } } else if (status == PV_STOPPING) { pa_simple_drain(pv->s, NULL); al_lock_mutex(voice->mutex); pv->status = PV_IDLE; al_broadcast_cond(pv->status_cond); al_unlock_mutex(voice->mutex); } } al_free(silence); return NULL; } static int pulseaudio_allocate_voice(ALLEGRO_VOICE *voice) { PULSEAUDIO_VOICE *pv = al_malloc(sizeof(PULSEAUDIO_VOICE)); pa_sample_spec ss; pa_buffer_attr ba; ss.channels = al_get_channel_count(voice->chan_conf); ss.rate = voice->frequency; if (voice->depth == ALLEGRO_AUDIO_DEPTH_UINT8) ss.format = PA_SAMPLE_U8; else if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT16) ss.format = PA_SAMPLE_S16NE; #if PA_API_VERSION > 11 else if (voice->depth == ALLEGRO_AUDIO_DEPTH_INT24) ss.format = PA_SAMPLE_S24NE; #endif else if (voice->depth == ALLEGRO_AUDIO_DEPTH_FLOAT32) ss.format = PA_SAMPLE_FLOAT32NE; else { ALLEGRO_ERROR("Unsupported PulseAudio sound format.\n"); al_free(pv); return 1; } // These settings match what pulseaudio does by default, but with a slightly lower latency. // The latency can also be controlled via PULSE_LATENCY_MSEC environment variable. ba.maxlength = -1; ba.tlength = pa_usec_to_bytes(50 * 1000, &ss); // 50 ms of latency by default. ba.prebuf = -1; ba.minreq = -1; ba.fragsize = -1; pv->s = pa_simple_new( NULL, // Use the default server. al_get_app_name(), PA_STREAM_PLAYBACK, NULL, // Use the default device. "Allegro Voice", &ss, NULL, // Use default channel map &ba, NULL // Ignore error code. ); if (!pv->s) { al_free(pv); return 1; } voice->extra = pv; pv->buffer_size_in_frames = get_buffer_size(al_get_system_config()); pv->frame_size_in_bytes = ss.channels * al_get_audio_depth_size(voice->depth); pv->status = PV_IDLE; //pv->status_mutex = al_create_mutex(); pv->status_cond = al_create_cond(); pv->buffer_mutex = al_create_mutex(); pv->poll_thread = al_create_thread(pulseaudio_update, (void*)voice); al_start_thread(pv->poll_thread); return 0; } static void pulseaudio_deallocate_voice(ALLEGRO_VOICE *voice) { PULSEAUDIO_VOICE *pv = voice->extra; al_lock_mutex(voice->mutex); pv->status = PV_JOIN; al_broadcast_cond(pv->status_cond); al_unlock_mutex(voice->mutex); /* We do NOT hold the voice mutex here, so this does NOT result in a * deadlock when the thread calls _al_voice_update. */ al_join_thread(pv->poll_thread, NULL); al_destroy_thread(pv->poll_thread); al_destroy_cond(pv->status_cond); al_destroy_mutex(pv->buffer_mutex); pa_simple_free(pv->s); al_free(pv); } static int pulseaudio_load_voice(ALLEGRO_VOICE *voice, const void *data) { PULSEAUDIO_VOICE *pv = voice->extra; (void)data; if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_BIDIR) { ALLEGRO_INFO("Backwards playing not supported by the driver.\n"); return 1; } voice->attached_stream->pos = 0; pv->buffer = voice->attached_stream->spl_data.buffer.ptr; pv->buffer_end = pv->buffer + (voice->attached_stream->spl_data.len) * pv->frame_size_in_bytes; return 0; } static void pulseaudio_unload_voice(ALLEGRO_VOICE *voice) { (void) voice; } static int pulseaudio_start_voice(ALLEGRO_VOICE *voice) { PULSEAUDIO_VOICE *pv = voice->extra; int ret; /* We hold the voice->mutex already. */ if (pv->status == PV_IDLE) { pv->status = PV_PLAYING; al_broadcast_cond(pv->status_cond); ret = 0; } else { ret = 1; } return ret; } static int pulseaudio_stop_voice(ALLEGRO_VOICE *voice) { PULSEAUDIO_VOICE *pv = voice->extra; /* We hold the voice->mutex already. */ if (pv->status == PV_PLAYING) { pv->status = PV_STOPPING; al_broadcast_cond(pv->status_cond); } while (pv->status != PV_IDLE) { al_wait_cond(pv->status_cond, voice->mutex); } return 0; } static bool pulseaudio_voice_is_playing(const ALLEGRO_VOICE *voice) { PULSEAUDIO_VOICE *pv = voice->extra; return (pv->status == PV_PLAYING); } static unsigned int pulseaudio_get_voice_position(const ALLEGRO_VOICE *voice) { return voice->attached_stream->pos; } static int pulseaudio_set_voice_position(ALLEGRO_VOICE *voice, unsigned int pos) { PULSEAUDIO_VOICE *pv = voice->extra; pa_simple_drain(pv->s, NULL); al_lock_mutex(pv->buffer_mutex); voice->attached_stream->pos = pos; pv->buffer = (char *)voice->attached_stream->spl_data.buffer.ptr + pos * pv->frame_size_in_bytes; al_unlock_mutex(pv->buffer_mutex); return 0; } /* Recording */ typedef struct PULSEAUDIO_RECORDER { pa_simple *s; pa_sample_spec ss; pa_buffer_attr ba; } PULSEAUDIO_RECORDER; static void *pulse_audio_update_recorder(ALLEGRO_THREAD *t, void *data) { ALLEGRO_AUDIO_RECORDER *r = (ALLEGRO_AUDIO_RECORDER *) data; PULSEAUDIO_RECORDER *pa = (PULSEAUDIO_RECORDER *) r->extra; ALLEGRO_EVENT user_event; uint8_t *null_buffer; unsigned int fragment_i = 0; null_buffer = al_malloc(1024); if (!null_buffer) { ALLEGRO_ERROR("Unable to create buffer for draining PulseAudio.\n"); return NULL; } while (!al_get_thread_should_stop(t)) { al_lock_mutex(r->mutex); if (!r->is_recording) { /* Even if not recording, we still want to read from the PA server. Otherwise it will buffer everything and spit it all out whenever the recording resumes. */ al_unlock_mutex(r->mutex); pa_simple_read(pa->s, null_buffer, 1024, NULL); } else { ALLEGRO_AUDIO_RECORDER_EVENT *e; al_unlock_mutex(r->mutex); if (pa_simple_read(pa->s, r->fragments[fragment_i], r->fragment_size, NULL) >= 0) { user_event.user.type = ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT; e = al_get_audio_recorder_event(&user_event); e->buffer = r->fragments[fragment_i]; e->samples = r->samples; al_emit_user_event(&r->source, &user_event, NULL); if (++fragment_i == r->fragment_count) { fragment_i = 0; } } } } al_free(null_buffer); return NULL; }; static int pulseaudio_allocate_recorder(ALLEGRO_AUDIO_RECORDER *r) { PULSEAUDIO_RECORDER *pa; pa = al_calloc(1, sizeof(*pa)); if (!pa) { ALLEGRO_ERROR("Unable to allocate memory for PULSEAUDIO_RECORDER.\n"); return 1; } pa->ss.channels = al_get_channel_count(r->chan_conf); pa->ss.rate = r->frequency; if (r->depth == ALLEGRO_AUDIO_DEPTH_UINT8) pa->ss.format = PA_SAMPLE_U8; else if (r->depth == ALLEGRO_AUDIO_DEPTH_INT16) pa->ss.format = PA_SAMPLE_S16NE; #if PA_API_VERSION > 11 else if (r->depth == ALLEGRO_AUDIO_DEPTH_INT24) pa->ss.format = PA_SAMPLE_S24NE; #endif else if (r->depth == ALLEGRO_AUDIO_DEPTH_FLOAT32) pa->ss.format = PA_SAMPLE_FLOAT32NE; else { ALLEGRO_ERROR("Unsupported PulseAudio sound format (depth).\n"); al_free(pa); return 1; } /* maximum length of the PulseAudio buffer. -1 => let the server decide. */ pa->ba.maxlength = -1; /* fragment size (bytes) controls how much data is returned back per read. The documentation recommends -1 for default behavior, but that sets a latency of around 2 seconds. Lower value decreases latency but increases overhead. The following attempts to set it (the base latency) to 1/8 of a second. */ pa->ba.fragsize = (r->sample_size * r->frequency) / 8; pa->s = pa_simple_new(NULL, al_get_app_name(), PA_STREAM_RECORD, NULL, "Allegro Audio Recorder", &pa->ss, NULL, &pa->ba, NULL); if (!pa->s) { ALLEGRO_ERROR("pa_simple_new() failed.\n"); al_free(pa); return 1; } r->thread = al_create_thread(pulse_audio_update_recorder, r); r->extra = pa; return 0; }; static void pulseaudio_deallocate_recorder(ALLEGRO_AUDIO_RECORDER *r) { PULSEAUDIO_RECORDER *pa = (PULSEAUDIO_RECORDER *) r->extra; pa_simple_free(pa->s); al_free(r->extra); } static _AL_LIST* pulseaudio_get_output_devices(void) { return output_device_list; } ALLEGRO_AUDIO_DRIVER _al_kcm_pulseaudio_driver = { "PulseAudio", pulseaudio_open, pulseaudio_close, pulseaudio_allocate_voice, pulseaudio_deallocate_voice, pulseaudio_load_voice, pulseaudio_unload_voice, pulseaudio_start_voice, pulseaudio_stop_voice, pulseaudio_voice_is_playing, pulseaudio_get_voice_position, pulseaudio_set_voice_position, pulseaudio_allocate_recorder, pulseaudio_deallocate_recorder, pulseaudio_get_output_devices }; /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/audio/recorder.c000066400000000000000000000101631473414355200200030ustar00rootroot00000000000000/* * Allegro audio recording */ #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/internal/aintern_audio_cfg.h" #include "allegro5/internal/aintern.h" ALLEGRO_DEBUG_CHANNEL("audio") ALLEGRO_STATIC_ASSERT(recorder, sizeof(ALLEGRO_AUDIO_RECORDER_EVENT) <= sizeof(ALLEGRO_EVENT)); /* Function: al_create_audio_recorder */ ALLEGRO_AUDIO_RECORDER *al_create_audio_recorder(size_t fragment_count, unsigned int samples, unsigned int frequency, ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf) { size_t i; ALLEGRO_AUDIO_RECORDER *r; ASSERT(_al_kcm_driver); if (!_al_kcm_driver->allocate_recorder) { ALLEGRO_ERROR("Audio driver does not support recording.\n"); return false; } r = al_calloc(1, sizeof(*r)); if (!r) { ALLEGRO_ERROR("Unable to allocate memory for ALLEGRO_AUDIO_RECORDER\n"); return false; } r->fragment_count = fragment_count; r->samples = samples; r->frequency = frequency, r->depth = depth; r->chan_conf = chan_conf; r->sample_size = al_get_channel_count(chan_conf) * al_get_audio_depth_size(depth); r->fragments = al_malloc(r->fragment_count * sizeof(uint8_t *)); if (!r->fragments) { al_free(r); ALLEGRO_ERROR("Unable to allocate memory for ALLEGRO_AUDIO_RECORDER fragments\n"); return false; } r->fragment_size = r->samples * r->sample_size; for (i = 0; i < fragment_count; ++i) { r->fragments[i] = al_malloc(r->fragment_size); if (!r->fragments[i]) { size_t j; for (j = 0; j < i; ++j) { al_free(r->fragments[j]); } al_free(r->fragments); ALLEGRO_ERROR("Unable to allocate memory for ALLEGRO_AUDIO_RECORDER fragments\n"); return false; } } if (_al_kcm_driver->allocate_recorder(r)) { ALLEGRO_ERROR("Failed to allocate recorder from driver\n"); return false; } r->is_recording = false; r->mutex = al_create_mutex(); r->cond = al_create_cond(); al_init_user_event_source(&r->source); if (r->thread) { /* the driver should have created a thread */ al_start_thread(r->thread); } return r; }; /* Function: al_start_audio_recorder */ bool al_start_audio_recorder(ALLEGRO_AUDIO_RECORDER *r) { ALLEGRO_ASSERT(r); al_lock_mutex(r->mutex); r->is_recording = true; al_signal_cond(r->cond); al_unlock_mutex(r->mutex); return true; } /* Function: al_stop_audio_recorder */ void al_stop_audio_recorder(ALLEGRO_AUDIO_RECORDER *r) { al_lock_mutex(r->mutex); if (r->is_recording) { r->is_recording = false; al_signal_cond(r->cond); } al_unlock_mutex(r->mutex); } /* Function: al_is_audio_recorder_recording */ bool al_is_audio_recorder_recording(ALLEGRO_AUDIO_RECORDER *r) { bool is_recording; al_lock_mutex(r->mutex); is_recording = r->is_recording; al_unlock_mutex(r->mutex); return is_recording; } /* Function: al_get_audio_recorder_event */ ALLEGRO_AUDIO_RECORDER_EVENT *al_get_audio_recorder_event(ALLEGRO_EVENT *event) { ASSERT(event->any.type == ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT); return (ALLEGRO_AUDIO_RECORDER_EVENT *) event; } /* Function: al_get_audio_recorder_event_source */ ALLEGRO_EVENT_SOURCE *al_get_audio_recorder_event_source(ALLEGRO_AUDIO_RECORDER *r) { return &r->source; } /* Function: al_destroy_audio_recorder */ void al_destroy_audio_recorder(ALLEGRO_AUDIO_RECORDER *r) { size_t i; if (!r) return; if (r->thread) { al_set_thread_should_stop(r->thread); al_lock_mutex(r->mutex); r->is_recording = false; al_signal_cond(r->cond); al_unlock_mutex(r->mutex); al_join_thread(r->thread, NULL); al_destroy_thread(r->thread); } if (_al_kcm_driver->deallocate_recorder) { _al_kcm_driver->deallocate_recorder(r); } al_destroy_user_event_source(&r->source); al_destroy_mutex(r->mutex); al_destroy_cond(r->cond); for (i = 0; i < r->fragment_count; ++i) { al_free(r->fragments[i]); } al_free(r->fragments); al_free(r); } allegro5-5.2.10.1/addons/audio/sdl_audio.c000066400000000000000000000151041473414355200201410ustar00rootroot00000000000000#define ALLEGRO_INTERNAL_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/internal/aintern_audio.h" #include "allegro5/platform/allegro_internal_sdl.h" ALLEGRO_DEBUG_CHANNEL("SDL") typedef struct SDL_VOICE { SDL_AudioDeviceID device; SDL_AudioSpec spec; ALLEGRO_VOICE *voice; bool is_playing; } SDL_VOICE; typedef struct SDL_RECORDER { SDL_AudioDeviceID device; SDL_AudioSpec spec; unsigned int fragment; } SDL_RECORDER; static _AL_LIST* output_device_list; static void audio_callback(void *userdata, Uint8 *stream, int len) { // TODO: Allegro has those mysterious "non-streaming" samples, but I // can't figure out what their purpose is and how would I play them... SDL_VOICE *sv = userdata; ALLEGRO_SAMPLE_INSTANCE *instance = sv->voice->attached_stream; ALLEGRO_SAMPLE *sample = &instance->spl_data; unsigned int frames = sv->spec.samples; const void *data = _al_voice_update(sv->voice, sv->voice->mutex, &frames); if (data) { // FIXME: What is frames for? memcpy(stream, sample->buffer.ptr, len); } } static int sdl_open(void) { return 0; } static void sdl_close(void) { } static SDL_AudioFormat allegro_format_to_sdl(ALLEGRO_AUDIO_DEPTH d) { if (d == ALLEGRO_AUDIO_DEPTH_INT8) return AUDIO_S8; if (d == ALLEGRO_AUDIO_DEPTH_UINT8) return AUDIO_U8; if (d == ALLEGRO_AUDIO_DEPTH_INT16) return AUDIO_S16; if (d == ALLEGRO_AUDIO_DEPTH_UINT16) return AUDIO_U16; return AUDIO_F32; } static ALLEGRO_AUDIO_DEPTH sdl_format_to_allegro(SDL_AudioFormat d) { if (d == AUDIO_S8) return ALLEGRO_AUDIO_DEPTH_INT8; if (d == AUDIO_U8) return ALLEGRO_AUDIO_DEPTH_UINT8; if (d == AUDIO_S16) return ALLEGRO_AUDIO_DEPTH_INT16; if (d == AUDIO_U16) return ALLEGRO_AUDIO_DEPTH_UINT16; return ALLEGRO_AUDIO_DEPTH_FLOAT32; } static int sdl_allocate_voice(ALLEGRO_VOICE *voice) { SDL_VOICE *sv = al_malloc(sizeof *sv); SDL_AudioSpec want; memset(&want, 0, sizeof want); want.freq = voice->frequency; want.format = allegro_format_to_sdl(voice->depth); want.channels = al_get_channel_count(voice->chan_conf); // TODO: Should make this configurable somehow want.samples = 4096; want.callback = audio_callback; want.userdata = sv; sv->device = SDL_OpenAudioDevice(NULL, 0, &want, &sv->spec, SDL_AUDIO_ALLOW_FORMAT_CHANGE); voice->extra = sv; sv->voice = voice; // we allow format change above so need to update here voice->depth = sdl_format_to_allegro(sv->spec.format); return 0; } static void sdl_deallocate_voice(ALLEGRO_VOICE *voice) { SDL_VOICE *sv = voice->extra; _al_list_destroy(output_device_list); SDL_CloseAudioDevice(sv->device); al_free(sv); } static int sdl_load_voice(ALLEGRO_VOICE *voice, const void *data) { (void)data; voice->attached_stream->pos = 0; return 0; } static void sdl_unload_voice(ALLEGRO_VOICE *voice) { (void) voice; } static int sdl_start_voice(ALLEGRO_VOICE *voice) { SDL_VOICE *sv = voice->extra; sv->is_playing = true; SDL_PauseAudioDevice(sv->device, 0); return 0; } static int sdl_stop_voice(ALLEGRO_VOICE *voice) { SDL_VOICE *sv = voice->extra; sv->is_playing = false; SDL_PauseAudioDevice(sv->device, 1); return 0; } static bool sdl_voice_is_playing(const ALLEGRO_VOICE *voice) { SDL_VOICE *sv = voice->extra; return sv->is_playing; } static unsigned int sdl_get_voice_position(const ALLEGRO_VOICE *voice) { return voice->attached_stream->pos; } static int sdl_set_voice_position(ALLEGRO_VOICE *voice, unsigned int pos) { voice->attached_stream->pos = pos; return 0; } static void recorder_callback(void *userdata, Uint8 *stream, int len) { ALLEGRO_AUDIO_RECORDER *r = (ALLEGRO_AUDIO_RECORDER *) userdata; SDL_RECORDER *sdl = (SDL_RECORDER *) r->extra; al_lock_mutex(r->mutex); if (!r->is_recording) { al_unlock_mutex(r->mutex); return; } while (len > 0) { int count = SDL_min(len, r->samples * r->sample_size); memcpy(r->fragments[sdl->fragment], stream, count); ALLEGRO_EVENT user_event; ALLEGRO_AUDIO_RECORDER_EVENT *e; user_event.user.type = ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT; e = al_get_audio_recorder_event(&user_event); e->buffer = r->fragments[sdl->fragment]; e->samples = count / r->sample_size; al_emit_user_event(&r->source, &user_event, NULL); sdl->fragment++; if (sdl->fragment == r->fragment_count) { sdl->fragment = 0; } len -= count; } al_unlock_mutex(r->mutex); } static int sdl_allocate_recorder(ALLEGRO_AUDIO_RECORDER *r) { SDL_RECORDER *sdl; sdl = al_calloc(1, sizeof(*sdl)); if (!sdl) { ALLEGRO_ERROR("Unable to allocate memory for SDL_RECORDER.\n"); return 1; } SDL_AudioSpec want; memset(&want, 0, sizeof want); want.freq = r->frequency; want.format = allegro_format_to_sdl(r->depth); want.channels = al_get_channel_count(r->chan_conf); want.samples = r->samples; want.callback = recorder_callback; want.userdata = r; sdl->device = SDL_OpenAudioDevice(NULL, 1, &want, &sdl->spec, 0); sdl->fragment = 0; r->extra = sdl; SDL_PauseAudioDevice(sdl->device, 0); return 0; } static void sdl_deallocate_recorder(ALLEGRO_AUDIO_RECORDER *r) { SDL_RECORDER *sdl = (SDL_RECORDER *) r->extra; SDL_CloseAudioDevice(sdl->device); al_free(r->extra); } static void _output_device_list_dtor(void* value, void* userdata) { (void)userdata; ALLEGRO_AUDIO_DEVICE* device = (ALLEGRO_AUDIO_DEVICE*)value; al_free(device->name); al_free(device); } static _AL_LIST* sdl_get_output_devices(void) { if (!output_device_list) { output_device_list = _al_list_create(); int i, count = SDL_GetNumAudioDevices(0); for (i = 0; i < count; ++i) { int len = strlen(SDL_GetAudioDeviceName(i, 0)) + 1; ALLEGRO_AUDIO_DEVICE* device = (ALLEGRO_AUDIO_DEVICE*)al_malloc(sizeof(ALLEGRO_AUDIO_DEVICE)); device->name = (char*)al_malloc(len); device->identifier = device->name; // Name returned by SDL2 is used to identify devices. strcpy(device->name, SDL_GetAudioDeviceName(i, 0)); _al_list_push_back_ex(output_device_list, device, _output_device_list_dtor); } } return output_device_list; } ALLEGRO_AUDIO_DRIVER _al_kcm_sdl_driver = { "SDL", sdl_open, sdl_close, sdl_allocate_voice, sdl_deallocate_voice, sdl_load_voice, sdl_unload_voice, sdl_start_voice, sdl_stop_voice, sdl_voice_is_playing, sdl_get_voice_position, sdl_set_voice_position, sdl_allocate_recorder, sdl_deallocate_recorder, sdl_get_output_devices, }; allegro5-5.2.10.1/addons/color/000077500000000000000000000000001473414355200160465ustar00rootroot00000000000000allegro5-5.2.10.1/addons/color/CMakeLists.txt000066400000000000000000000007541473414355200206140ustar00rootroot00000000000000set(COLOR_SOURCES color.c) set(COLOR_INCLUDE_FILES allegro5/allegro_color.h ) set_our_header_properties(${COLOR_INCLUDE_FILES}) add_our_addon_library(allegro_color AllegroColor-${ALLEGRO_SOVERSION} "${COLOR_SOURCES};${COLOR_INCLUDE_FILES}" "-DALLEGRO_COLOR_SRC" "${ALLEGRO_LINK_WITH}" ) install_our_headers(${COLOR_INCLUDE_FILES}) add_addon(color) #-----------------------------------------------------------------------------# # vi: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/addons/color/allegro5/000077500000000000000000000000001473414355200175605ustar00rootroot00000000000000allegro5-5.2.10.1/addons/color/allegro5/allegro_color.h000066400000000000000000000116461473414355200225640ustar00rootroot00000000000000#ifndef __al_included_allegro5_allegro_color_h #define __al_included_allegro5_allegro_color_h #include "allegro5/allegro.h" #if (defined ALLEGRO_MINGW32) || (defined ALLEGRO_MSVC) || (defined ALLEGRO_BCC32) #ifndef ALLEGRO_STATICLINK #ifdef ALLEGRO_COLOR_SRC #define _ALLEGRO_COLOR_DLL __declspec(dllexport) #else #define _ALLEGRO_COLOR_DLL __declspec(dllimport) #endif #else #define _ALLEGRO_COLOR_DLL #endif #endif #if defined ALLEGRO_MSVC #define ALLEGRO_COLOR_FUNC(type, name, args) _ALLEGRO_COLOR_DLL type __cdecl name args #elif defined ALLEGRO_MINGW32 #define ALLEGRO_COLOR_FUNC(type, name, args) extern type name args #elif defined ALLEGRO_BCC32 #define ALLEGRO_COLOR_FUNC(type, name, args) extern _ALLEGRO_COLOR_DLL type name args #else #define ALLEGRO_COLOR_FUNC AL_FUNC #endif #ifdef __cplusplus extern "C" { #endif ALLEGRO_COLOR_FUNC(uint32_t, al_get_allegro_color_version, (void)); ALLEGRO_COLOR_FUNC(void, al_color_hsv_to_rgb, (float hue, float saturation, float value, float *red, float *green, float *blue)); ALLEGRO_COLOR_FUNC(void, al_color_rgb_to_hsl, (float red, float green, float blue, float *hue, float *saturation, float *lightness)); ALLEGRO_COLOR_FUNC(void, al_color_rgb_to_hsv, (float red, float green, float blue, float *hue, float *saturation, float *value)); ALLEGRO_COLOR_FUNC(void, al_color_hsl_to_rgb, (float hue, float saturation, float lightness, float *red, float *green, float *blue)); ALLEGRO_COLOR_FUNC(bool, al_color_name_to_rgb, (char const *name, float *r, float *g, float *b)); ALLEGRO_COLOR_FUNC(const char*, al_color_rgb_to_name, (float r, float g, float b)); ALLEGRO_COLOR_FUNC(void, al_color_cmyk_to_rgb, (float cyan, float magenta, float yellow, float key, float *red, float *green, float *blue)); ALLEGRO_COLOR_FUNC(void, al_color_rgb_to_cmyk, (float red, float green, float blue, float *cyan, float *magenta, float *yellow, float *key)); ALLEGRO_COLOR_FUNC(void, al_color_yuv_to_rgb, (float y, float u, float v, float *red, float *green, float *blue)); ALLEGRO_COLOR_FUNC(void, al_color_rgb_to_yuv, (float red, float green, float blue, float *y, float *u, float *v)); ALLEGRO_COLOR_FUNC(void, al_color_rgb_to_html, (float red, float green, float blue, char *string)); ALLEGRO_COLOR_FUNC(bool, al_color_html_to_rgb, (char const *string, float *red, float *green, float *blue)); ALLEGRO_COLOR_FUNC(ALLEGRO_COLOR, al_color_yuv, (float y, float u, float v)); ALLEGRO_COLOR_FUNC(ALLEGRO_COLOR, al_color_cmyk, (float c, float m, float y, float k)); ALLEGRO_COLOR_FUNC(ALLEGRO_COLOR, al_color_hsl, (float h, float s, float l)); ALLEGRO_COLOR_FUNC(ALLEGRO_COLOR, al_color_hsv, (float h, float s, float v)); ALLEGRO_COLOR_FUNC(ALLEGRO_COLOR, al_color_name, (char const *name)); ALLEGRO_COLOR_FUNC(ALLEGRO_COLOR, al_color_html, (char const *string)); ALLEGRO_COLOR_FUNC(void, al_color_xyz_to_rgb, (float x, float y, float z, float *red, float *green, float *blue)); ALLEGRO_COLOR_FUNC(void, al_color_rgb_to_xyz, (float red, float green, float blue, float *x, float *y, float *z)); ALLEGRO_COLOR_FUNC(ALLEGRO_COLOR, al_color_xyz, (float x, float y, float z)); ALLEGRO_COLOR_FUNC(void, al_color_lab_to_rgb, (float l, float a, float b, float *red, float *green, float *blue)); ALLEGRO_COLOR_FUNC(void, al_color_rgb_to_lab, (float red, float green, float blue, float *l, float *a, float *b)); ALLEGRO_COLOR_FUNC(ALLEGRO_COLOR, al_color_lab, (float l, float a, float b)); ALLEGRO_COLOR_FUNC(void, al_color_xyy_to_rgb, (float x, float y, float y2, float *red, float *green, float *blue)); ALLEGRO_COLOR_FUNC(void, al_color_rgb_to_xyy, (float red, float green, float blue, float *x, float *y, float *y2)); ALLEGRO_COLOR_FUNC(ALLEGRO_COLOR, al_color_xyy, (float x, float y, float y2)); ALLEGRO_COLOR_FUNC(double, al_color_distance_ciede2000, (ALLEGRO_COLOR c1, ALLEGRO_COLOR c2)); ALLEGRO_COLOR_FUNC(void, al_color_lch_to_rgb, (float l, float c, float h, float *red, float *green, float *blue)); ALLEGRO_COLOR_FUNC(void, al_color_rgb_to_lch, (float red, float green, float blue, float *l, float *c, float *h)); ALLEGRO_COLOR_FUNC(ALLEGRO_COLOR, al_color_lch, (float l, float c, float h)); ALLEGRO_COLOR_FUNC(bool, al_is_color_valid, (ALLEGRO_COLOR color)); ALLEGRO_COLOR_FUNC(void, al_color_oklab_to_rgb, (float l, float a, float b, float *red, float *green, float *blue)); ALLEGRO_COLOR_FUNC(void, al_color_rgb_to_oklab, (float red, float green, float blue, float *l, float *a, float *b)); ALLEGRO_COLOR_FUNC(ALLEGRO_COLOR, al_color_oklab, (float l, float a, float b)); ALLEGRO_COLOR_FUNC(void, al_color_linear_to_rgb, (float x, float y, float z, float *red, float *green, float *blue)); ALLEGRO_COLOR_FUNC(void, al_color_rgb_to_linear, (float red, float green, float blue, float *x, float *y, float *z)); ALLEGRO_COLOR_FUNC(ALLEGRO_COLOR, al_color_linear, (float r, float g, float b)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/color/color.c000066400000000000000000000565011473414355200173370ustar00rootroot00000000000000/* Addon which allows converting between different color * representations. Included are: * - HSV (like A4) * - names (mostly X11 color names, except where CSS redefines them) * - HSL (the "better" HSV) * - CMYK (a bit like the opposite of RGB) * - YUV (the Y channel is quite useful for creating grayscale pictures) */ #include "allegro5/allegro.h" #include "allegro5/allegro_color.h" #include "allegro5/internal/aintern.h" #include #include typedef struct { char const *name; int r, g, b; } ColorName; /* Taken from http://www.w3.org/TR/2010/PR-css3-color-20101028/#svg-color * This must be sorted correctly for binary search. */ static ColorName _al_color_names[] = { {"aliceblue", 0xf0, 0xf8, 0xff}, {"antiquewhite", 0xfa, 0xeb, 0xd7}, {"aqua", 0x00, 0xff, 0xff}, {"aquamarine", 0x7f, 0xff, 0xd4}, {"azure", 0xf0, 0xff, 0xff}, {"beige", 0xf5, 0xf5, 0xdc}, {"bisque", 0xff, 0xe4, 0xc4}, {"black", 0x00, 0x00, 0x00}, {"blanchedalmond", 0xff, 0xeb, 0xcd}, {"blue", 0x00, 0x00, 0xff}, {"blueviolet", 0x8a, 0x2b, 0xe2}, {"brown", 0xa5, 0x2a, 0x2a}, {"burlywood", 0xde, 0xb8, 0x87}, {"cadetblue", 0x5f, 0x9e, 0xa0}, {"chartreuse", 0x7f, 0xff, 0x00}, {"chocolate", 0xd2, 0x69, 0x1e}, {"coral", 0xff, 0x7f, 0x50}, {"cornflowerblue", 0x64, 0x95, 0xed}, {"cornsilk", 0xff, 0xf8, 0xdc}, {"crimson", 0xdc, 0x14, 0x3c}, {"cyan", 0x00, 0xff, 0xff}, {"darkblue", 0x00, 0x00, 0x8b}, {"darkcyan", 0x00, 0x8b, 0x8b}, {"darkgoldenrod", 0xb8, 0x86, 0x0b}, {"darkgray", 0xa9, 0xa9, 0xa9}, {"darkgreen", 0x00, 0x64, 0x00}, {"darkgrey", 0xa9, 0xa9, 0xa9}, {"darkkhaki", 0xbd, 0xb7, 0x6b}, {"darkmagenta", 0x8b, 0x00, 0x8b}, {"darkolivegreen", 0x55, 0x6b, 0x2f}, {"darkorange", 0xff, 0x8c, 0x00}, {"darkorchid", 0x99, 0x32, 0xcc}, {"darkred", 0x8b, 0x00, 0x00}, {"darksalmon", 0xe9, 0x96, 0x7a}, {"darkseagreen", 0x8f, 0xbc, 0x8f}, {"darkslateblue", 0x48, 0x3d, 0x8b}, {"darkslategray", 0x2f, 0x4f, 0x4f}, {"darkslategrey", 0x2f, 0x4f, 0x4f}, {"darkturquoise", 0x00, 0xce, 0xd1}, {"darkviolet", 0x94, 0x00, 0xd3}, {"deeppink", 0xff, 0x14, 0x93}, {"deepskyblue", 0x00, 0xbf, 0xff}, {"dimgray", 0x69, 0x69, 0x69}, {"dimgrey", 0x69, 0x69, 0x69}, {"dodgerblue", 0x1e, 0x90, 0xff}, {"firebrick", 0xb2, 0x22, 0x22}, {"floralwhite", 0xff, 0xfa, 0xf0}, {"forestgreen", 0x22, 0x8b, 0x22}, {"fuchsia", 0xff, 0x00, 0xff}, {"gainsboro", 0xdc, 0xdc, 0xdc}, {"ghostwhite", 0xf8, 0xf8, 0xff}, {"gold", 0xff, 0xd7, 0x00}, {"goldenrod", 0xda, 0xa5, 0x20}, {"gray", 0x80, 0x80, 0x80}, {"green", 0x00, 0x80, 0x00}, {"greenyellow", 0xad, 0xff, 0x2f}, {"grey", 0x80, 0x80, 0x80}, {"honeydew", 0xf0, 0xff, 0xf0}, {"hotpink", 0xff, 0x69, 0xb4}, {"indianred", 0xcd, 0x5c, 0x5c}, {"indigo", 0x4b, 0x00, 0x82}, {"ivory", 0xff, 0xff, 0xf0}, {"khaki", 0xf0, 0xe6, 0x8c}, {"lavender", 0xe6, 0xe6, 0xfa}, {"lavenderblush", 0xff, 0xf0, 0xf5}, {"lawngreen", 0x7c, 0xfc, 0x00}, {"lemonchiffon", 0xff, 0xfa, 0xcd}, {"lightblue", 0xad, 0xd8, 0xe6}, {"lightcoral", 0xf0, 0x80, 0x80}, {"lightcyan", 0xe0, 0xff, 0xff}, {"lightgoldenrodyellow", 0xfa, 0xfa, 0xd2}, {"lightgray", 0xd3, 0xd3, 0xd3}, {"lightgreen", 0x90, 0xee, 0x90}, {"lightgrey", 0xd3, 0xd3, 0xd3}, {"lightpink", 0xff, 0xb6, 0xc1}, {"lightsalmon", 0xff, 0xa0, 0x7a}, {"lightseagreen", 0x20, 0xb2, 0xaa}, {"lightskyblue", 0x87, 0xce, 0xfa}, {"lightslategray", 0x77, 0x88, 0x99}, {"lightslategrey", 0x77, 0x88, 0x99}, {"lightsteelblue", 0xb0, 0xc4, 0xde}, {"lightyellow", 0xff, 0xff, 0xe0}, {"lime", 0x00, 0xff, 0x00}, {"limegreen", 0x32, 0xcd, 0x32}, {"linen", 0xfa, 0xf0, 0xe6}, {"magenta", 0xff, 0x00, 0xff}, {"maroon", 0x80, 0x00, 0x00}, {"mediumaquamarine", 0x66, 0xcd, 0xaa}, {"mediumblue", 0x00, 0x00, 0xcd}, {"mediumorchid", 0xba, 0x55, 0xd3}, {"mediumpurple", 0x93, 0x70, 0xdb}, {"mediumseagreen", 0x3c, 0xb3, 0x71}, {"mediumslateblue", 0x7b, 0x68, 0xee}, {"mediumspringgreen", 0x00, 0xfa, 0x9a}, {"mediumturquoise", 0x48, 0xd1, 0xcc}, {"mediumvioletred", 0xc7, 0x15, 0x85}, {"midnightblue", 0x19, 0x19, 0x70}, {"mintcream", 0xf5, 0xff, 0xfa}, {"mistyrose", 0xff, 0xe4, 0xe1}, {"moccasin", 0xff, 0xe4, 0xb5}, {"navajowhite", 0xff, 0xde, 0xad}, {"navy", 0x00, 0x00, 0x80}, {"oldlace", 0xfd, 0xf5, 0xe6}, {"olive", 0x80, 0x80, 0x00}, {"olivedrab", 0x6b, 0x8e, 0x23}, {"orange", 0xff, 0xa5, 0x00}, {"orangered", 0xff, 0x45, 0x00}, {"orchid", 0xda, 0x70, 0xd6}, {"palegoldenrod", 0xee, 0xe8, 0xaa}, {"palegreen", 0x98, 0xfb, 0x98}, {"paleturquoise", 0xaf, 0xee, 0xee}, {"palevioletred", 0xdb, 0x70, 0x93}, {"papayawhip", 0xff, 0xef, 0xd5}, {"peachpuff", 0xff, 0xda, 0xb9}, {"peru", 0xcd, 0x85, 0x3f}, {"pink", 0xff, 0xc0, 0xcb}, {"plum", 0xdd, 0xa0, 0xdd}, {"powderblue", 0xb0, 0xe0, 0xe6}, {"purple", 0x80, 0x00, 0x80}, {"rebeccapurple", 0x66, 0x33, 0x99}, {"red", 0xff, 0x00, 0x00}, {"rosybrown", 0xbc, 0x8f, 0x8f}, {"royalblue", 0x41, 0x69, 0xe1}, {"saddlebrown", 0x8b, 0x45, 0x13}, {"salmon", 0xfa, 0x80, 0x72}, {"sandybrown", 0xf4, 0xa4, 0x60}, {"seagreen", 0x2e, 0x8b, 0x57}, {"seashell", 0xff, 0xf5, 0xee}, {"sienna", 0xa0, 0x52, 0x2d}, {"silver", 0xc0, 0xc0, 0xc0}, {"skyblue", 0x87, 0xce, 0xeb}, {"slateblue", 0x6a, 0x5a, 0xcd}, {"slategray", 0x70, 0x80, 0x90}, {"slategrey", 0x70, 0x80, 0x90}, {"snow", 0xff, 0xfa, 0xfa}, {"springgreen", 0x00, 0xff, 0x7f}, {"steelblue", 0x46, 0x82, 0xb4}, {"tan", 0xd2, 0xb4, 0x8c}, {"teal", 0x00, 0x80, 0x80}, {"thistle", 0xd8, 0xbf, 0xd8}, {"tomato", 0xff, 0x63, 0x47}, {"turquoise", 0x40, 0xe0, 0xd0}, {"violet", 0xee, 0x82, 0xee}, {"wheat", 0xf5, 0xde, 0xb3}, {"white", 0xff, 0xff, 0xff}, {"whitesmoke", 0xf5, 0xf5, 0xf5}, {"yellow", 0xff, 0xff, 0x00}, {"yellowgreen", 0x9a, 0xcd, 0x32}, }; #define NUM_COLORS (sizeof(_al_color_names) / sizeof(ColorName)) static double const Xn = 0.95047; static double const Yn = 1.00000; static double const Zn = 1.08883; static double const delta = 6.0 / 29; static double const delta2 = 6.0 / 29 * 6.0 / 29; static double const delta3 = 6.0 / 29 * 6.0 / 29 * 6.0 / 29; static double const tf7 = 1.0 / 4 / 4 / 4 / 4 / 4 / 4 / 4; static void assert_sorted_names(void) { /* In debug mode, check once that the array is sorted. */ #ifdef DEBUGMODE static bool done = false; unsigned i; if (!done) { for (i = 1; i < NUM_COLORS; i++) { ASSERT(strcmp(_al_color_names[i-1].name, _al_color_names[i].name) < 0); } done = true; } #endif } static int compare(const void *va, const void *vb) { char const *ca = va; ColorName const *cb = vb; return strcmp(ca, cb->name); } /* Function: al_color_name_to_rgb */ bool al_color_name_to_rgb(char const *name, float *r, float *g, float *b) { void *result; assert_sorted_names(); result = bsearch(name, _al_color_names, NUM_COLORS, sizeof(ColorName), compare); if (result) { ColorName *c = result; *r = c->r / 255.0; *g = c->g / 255.0; *b = c->b / 255.0; return true; } return false; } /* Function: al_color_rgb_to_name */ char const *al_color_rgb_to_name(float r, float g, float b) { int i; int ir = r * 255; int ig = g * 255; int ib = b * 255; int n = NUM_COLORS; int min = n, mind = 0; /* Could optimize this, right now it does linear search. */ for (i = 0; i < n; i++) { int dr = _al_color_names[i].r - ir; int dg = _al_color_names[i].g - ig; int db = _al_color_names[i].b - ib; int d = dr * dr + dg * dg + db * db; if (min == n || d < mind) { min = i; mind = d; } } return _al_color_names[min].name; } /* Function: al_color_name */ ALLEGRO_COLOR al_color_name(char const *name) { float r, g, b; if (al_color_name_to_rgb(name, &r, &g, &b)) return al_map_rgb_f(r, g, b); else return al_map_rgb_f(0, 0, 0); } /* Function: al_color_hsv_to_rgb */ void al_color_hsv_to_rgb(float hue, float saturation, float value, float *red, float *green, float *blue) { int d; float e, a, b, c; hue = fmodf(hue, 360); if (hue < 0) hue += 360; d = hue / 60; e = hue / 60 - d; a = value * (1 - saturation); b = value * (1 - e * saturation); c = value * (1 - (1 - e) * saturation); switch (d) { default: case 0: *red = value, *green = c, *blue = a; return; case 1: *red = b, *green = value, *blue = a; return; case 2: *red = a, *green = value, *blue = c; return; case 3: *red = a, *green = b, *blue = value; return; case 4: *red = c, *green = a, *blue = value; return; case 5: *red = value, *green = a, *blue = b; return; } } /* Function: al_color_rgb_to_hsv */ void al_color_rgb_to_hsv(float red, float green, float blue, float *hue, float *saturation, float *value) { float a, b, c, d; if (red > green) { if (red > blue) { if (green > blue) a = red, b = green - blue, c = blue, d = 0; else a = red, b = green - blue, c = green, d = 0; } else { a = blue, b = red - green, c = green, d = 4; } } else { if (red > blue) a = green, b = blue - red, c = blue, d = 2; else if (green > blue) a = green, b = blue - red, c = red, d = 2; else a = blue, b = red - green, c = red, d = 4; } if (a == c) { *hue = 0; } else { *hue = 60 * (d + b / (a - c)); if (*hue < 0) *hue += 360; if (*hue > 360) *hue -= 360; } if (a == 0) *saturation = 0; else *saturation = (a - c) / a; *value = a; } /* Function: al_color_hsv */ ALLEGRO_COLOR al_color_hsv(float h, float s, float v) { float r, g, b; al_color_hsv_to_rgb(h, s, v, &r, &g, &b); return al_map_rgb_f(r, g, b); } static float hsl_to_rgb_helper(float x, float a, float b) { if (x < 0) x += 1; if (x > 1) x -= 1; if (x * 6 < 1) return b + (a - b) * 6 * x; if (x * 6 < 3) return a; if (x * 6 < 4) return b + (a - b) * (4.0 - 6.0 * x); return b; } /* Function: al_color_hsl_to_rgb */ void al_color_hsl_to_rgb(float hue, float saturation, float lightness, float *red, float *green, float *blue) { float a, b, h; hue = fmodf(hue, 360); if (hue < 0) hue += 360; h = hue / 360; if (lightness < 0.5) a = lightness + lightness * saturation; else a = lightness + saturation - lightness * saturation; b = lightness * 2 - a; *red = hsl_to_rgb_helper(h + 1.0 / 3.0, a, b); *green = hsl_to_rgb_helper(h, a, b); *blue = hsl_to_rgb_helper(h - 1.0 / 3.0, a, b); } /* Function: al_color_rgb_to_hsl */ void al_color_rgb_to_hsl(float red, float green, float blue, float *hue, float *saturation, float *lightness) { float a, b, c, d; if (red > green) { if (red > blue) { if (green > blue) a = red, b = green - blue, c = blue, d = 0; else a = red, b = green - blue, c = green, d = 0; } else { a = blue, b = red - green, c = green, d = 4; } } else { if (red > blue) a = green, b = blue - red, c = blue, d = 2; else if (green > blue) a = green, b = blue - red, c = red, d = 2; else a = blue, b = red - green, c = red, d = 4; } if (a == c) { *hue = 0; } else { *hue = 60 * (d + b / (a - c)); if (*hue < 0) *hue += 360; } if (a == c) *saturation = 0; else if (a + c < 1) *saturation = (a - c) / (a + c); else *saturation = (a - c) / (2 - a - c); *lightness = (a + c) / 2; } /* Function: al_color_hsl */ ALLEGRO_COLOR al_color_hsl(float h, float s, float l) { float r, g, b; al_color_hsl_to_rgb(h, s, l, &r, &g, &b); return al_map_rgb_f(r, g, b); } /* Function: al_color_cmyk_to_rgb */ void al_color_cmyk_to_rgb(float cyan, float magenta, float yellow, float key, float *red, float *green, float *blue) { float max = 1 - key; *red = max - cyan * max; *green = max - magenta * max; *blue = max - yellow * max; } /* Function: al_color_rgb_to_cmyk */ void al_color_rgb_to_cmyk(float red, float green, float blue, float *cyan, float *magenta, float *yellow, float *key) { float max = red; if (green > max) max = green; if (blue > max) max = blue; *key = 1 - max; if (max > 0) { *cyan = (max - red) / max; *magenta = (max - green) / max; *yellow = (max - blue) / max; } else { *cyan = *magenta = *yellow = 0; } } /* Function: al_color_cmyk */ ALLEGRO_COLOR al_color_cmyk(float c, float m, float y, float k) { float r, g, b; al_color_cmyk_to_rgb(c, m, y, k, &r, &g, &b); return al_map_rgb_f(r, g, b); } /* Function: al_color_yuv_to_rgb */ void al_color_yuv_to_rgb(float y, float u, float v, float *red, float *green, float *blue) { /* Translate range 0..1 to actual range. */ u = 0.436 * (u * 2 - 1); v = 0.615 * (v * 2 - 1); *red = _ALLEGRO_CLAMP(0, 1, y + v * 1.13983); *green = _ALLEGRO_CLAMP(0, 1, y + u * -0.39465 + v * -0.58060); *blue = _ALLEGRO_CLAMP(0, 1, y + u * 2.03211); } /* Function: al_color_rgb_to_yuv */ void al_color_rgb_to_yuv(float red, float green, float blue, float *y, float *u, float *v) { *y = red * 0.299 + green * 0.587 + blue * 0.114; *u = red * -0.14713 + green * -0.28886 + blue * 0.436; *v = red * 0.615 + green * -0.51499 + blue * -0.10001; /* Normalize chroma components into 0..1 range. */ *u = (*u / 0.436 + 1) * 0.5; *v = (*v / 0.615 + 1) * 0.5; } /* Function: al_color_yuv */ ALLEGRO_COLOR al_color_yuv(float y, float u, float v) { float r, g, b; al_color_yuv_to_rgb(y, u, v, &r, &g, &b); return al_map_rgb_f(r, g, b); } /* Function: al_color_rgb_to_html */ void al_color_rgb_to_html(float red, float green, float blue, char *string) { sprintf(string, "#%02x%02x%02x", (int)(red * 255), (int)(green * 255), (int)(blue * 255)); } /* Function: al_color_html_to_rgb */ bool al_color_html_to_rgb(char const *string, float *red, float *green, float *blue) { char const *ptr = string; int ir, ig, ib; ASSERT(ptr); ASSERT(red); ASSERT(green); ASSERT(blue); *red = *green = *blue = 0.0f; if (*ptr == '#') ptr++; if (strlen(ptr) != 6) return false; if (sscanf(ptr, "%02x%02x%02x", &ir, &ig, &ib) != 3) return false; *red = ir / 255.0; *green = ig / 255.0; *blue = ib / 255.0; return true; } /* Function: al_color_html */ ALLEGRO_COLOR al_color_html(char const *string) { float r, g, b; if (al_color_html_to_rgb(string, &r, &g, &b)) return al_map_rgb_f(r, g, b); else return al_map_rgba(0, 0, 0, 0); } /* Function: al_get_allegro_color_version */ uint32_t al_get_allegro_color_version(void) { return ALLEGRO_VERSION_INT; } /* Converts from an sRGB color component to the linear value. */ static double srgba_gamma_to_linear(double x) { double const a = 0.055; if (x < 0.04045) return x / 12.92; return pow((x + a) / (1 + a), 2.4); } /* Converts a linear color component back into sRGB. */ static double srgba_linear_to_gamma(double x) { double const a = 0.055; if (x < 0.0031308) return x * 12.92; return pow(x, 1 / 2.4) * (1 + a) - a; } /* Function: al_color_linear_to_rgb */ void al_color_linear_to_rgb(float r, float g, float b, float *red, float *green, float *blue) { *red = srgba_linear_to_gamma(r); *green = srgba_linear_to_gamma(g); *blue = srgba_linear_to_gamma(b); } /* Function: al_color_rgb_to_linear */ void al_color_rgb_to_linear(float red, float green, float blue, float *r, float *g, float *b) { *r = srgba_gamma_to_linear(red); *g = srgba_gamma_to_linear(green); *b = srgba_gamma_to_linear(blue); } /* Function: al_color_linear */ ALLEGRO_COLOR al_color_linear(float r, float g, float b) { float r2, g2, b2; al_color_linear_to_rgb(r, g, b, &r2, &g2, &b2); return al_map_rgb_f(r2, g2, b2); } /* Function: al_color_xyz_to_rgb */ void al_color_xyz_to_rgb(float x, float y, float z, float *red, float *green, float *blue) { double r = 3.2406 * x + (-1.5372 * y) + (-0.4986 * z); double g = -0.9689 * x + 1.8758 * y + 0.0415 * z; double b = 0.0557 * x + (-0.2040 * y) + 1.0570 * z; *red = srgba_linear_to_gamma(r); *green = srgba_linear_to_gamma(g); *blue = srgba_linear_to_gamma(b); } /* Function: al_color_rgb_to_xyz */ void al_color_rgb_to_xyz(float red, float green, float blue, float *x, float *y, float *z) { double r = srgba_gamma_to_linear(red); double g = srgba_gamma_to_linear(green); double b = srgba_gamma_to_linear(blue); *x = r * 0.4124 + g * 0.3576 + b * 0.1805; *y = r * 0.2126 + g * 0.7152 + b * 0.0722; *z = r * 0.0193 + g * 0.1192 + b * 0.9505; } /* Function: al_color_xyz */ ALLEGRO_COLOR al_color_xyz(float x, float y, float z) { float r, g, b; al_color_xyz_to_rgb(x, y, z, &r, &g, &b); return al_map_rgb_f(r, g, b); } static double cielab_f(double x) { if (x > delta3) return pow(x, 1.0 / 3); return 4.0 / 29 + x / delta2 / 3; } static double cielab_f_inv(double x) { if (x > delta) return pow(x, 3); return (x - 4.0 / 29) * 3 * delta2; } /* Function: al_color_lab_to_rgb */ void al_color_lab_to_rgb(float l, float a, float b, float *red, float *green, float *blue) { float x = Xn * cielab_f_inv((l + 0.16) / 1.16 + a / 5.00); float y = Yn * cielab_f_inv((l + 0.16) / 1.16); float z = Zn * cielab_f_inv((l + 0.16) / 1.16 - b / 2.00); al_color_xyz_to_rgb(x, y, z, red, green, blue); } /* Function: al_color_rgb_to_lab */ void al_color_rgb_to_lab(float red, float green, float blue, float *l, float *a, float *b) { float x, y, z; al_color_rgb_to_xyz(red, green, blue, &x, &y, &z); x /= Xn; y /= Yn; z /= Zn; *l = 1.16 * cielab_f(y) - 0.16; *a = 5.00 * (cielab_f(x) - cielab_f(y)); *b = 2.00 * (cielab_f(y) - cielab_f(z)); } /* Function: al_color_lab */ ALLEGRO_COLOR al_color_lab(float l, float a, float b) { float r2, g2, b2; al_color_lab_to_rgb(l, a, b, &r2, &g2, &b2); return al_map_rgb_f(r2, g2, b2); } /* Function: al_color_lch_to_rgb */ void al_color_lch_to_rgb(float l, float c, float h, float *red, float *green, float *blue) { double a = c * cos(h); double b = c * sin(h); al_color_lab_to_rgb(l, a, b, red, green, blue); } /* Function: al_color_rgb_to_lch */ void al_color_rgb_to_lch(float red, float green, float blue, float *l, float *c, float *h) { float a, b; al_color_rgb_to_lab(red, green, blue, l, &a, &b); *c = sqrt(a * a + b * b); *h = fmod(ALLEGRO_PI * 2 + atan2(b, a), ALLEGRO_PI * 2); } /* Function: al_color_lch */ ALLEGRO_COLOR al_color_lch(float l, float c, float h) { float r, g, b; al_color_lch_to_rgb(l, c, h, &r, &g, &b); return al_map_rgb_f(r, g, b); } /* Function: al_color_xyy_to_rgb */ void al_color_xyy_to_rgb(float x, float y, float y2, float *red, float *green, float *blue) { double x2 = x * y / y2; double z2 = (1 - y2 - x) * y / y2; al_color_xyz_to_rgb(x2, y2, z2, red, green, blue); } /* Function: al_color_rgb_to_xyy */ void al_color_rgb_to_xyy(float red, float green, float blue, float *x, float *y, float *y2) { float x2, z2; al_color_rgb_to_xyz(red, green, blue, &x2, y2, &z2); *x = x2 / (x2 + *y2 + z2); *y = *y2 / (x2 + *y2 + z2); } /* Function: al_color_xyy */ ALLEGRO_COLOR al_color_xyy(float x, float y, float y2) { float r, g, b; al_color_xyy_to_rgb(x, y, y2, &r, &g, &b); return al_map_rgb_f(r, g, b); } /* Function: al_color_distance_ciede2000 */ double al_color_distance_ciede2000(ALLEGRO_COLOR color1, ALLEGRO_COLOR color2) { /* For implementation details refer to e.g. * http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf */ float l1, a1, b1, l2, a2, b2; al_color_rgb_to_lab(color1.r, color1.g, color1.b, &l1, &a1, &b1); al_color_rgb_to_lab(color2.r, color2.g, color2.b, &l2, &a2, &b2); double pi = ALLEGRO_PI; double dl = l1 - l2; double ml = (l1 + l2) / 2; double c1 = sqrt(a1 * a1 + b1 * b1); double c2 = sqrt(a2 * a2 + b2 * b2); double mc = (c1 + c2) / 2; double fac = sqrt(pow(mc, 7) / (pow(mc, 7) + tf7)); double g = 0.5 * (1 - fac); a1 *= 1 + g; a2 *= 1 + g; c1 = sqrt(a1 * a1 + b1 * b1); c2 = sqrt(a2 * a2 + b2 * b2); double dc = c2 - c1; mc = (c1 + c2) / 2; fac = sqrt(pow(mc, 7) / (pow(mc, 7) + tf7)); double h1 = fmod(2 * pi + atan2(b1, a1), 2 * pi); double h2 = fmod(2 * pi + atan2(b2, a2), 2 * pi); double dh = 0; double mh = h1 + h2; if (c1 * c2 != 0) { dh = h2 - h1; if (dh > pi) dh -= 2 * pi; if (dh < -pi) dh += 2 * pi; if (fabs(h1 - h2) <= pi) mh = (h1 + h2) / 2; else if (h1 + h2 < 2 * pi) mh = (h1 + h2 + 2 * pi) / 2; else mh = (h1 + h2 - 2 * pi) / 2; } dh = 2 * sqrt(c1 * c2) * sin(dh / 2); double t = 1 - 0.17 * cos(mh - pi / 6) + 0.24 * cos(2 * mh) + 0.32 * cos(3 * mh + pi / 30) - 0.2 * cos(4 * mh - pi * 7 / 20); double mls = pow(ml - 0.5, 2); double sl = 1 + 1.5 * mls / sqrt(0.002 + mls); double sc = 1 + 4.5 * mc; double sh = 1 + 1.5 * mc * t; double rt = -2 * fac * sin(pi / 3 * exp(-pow(mh / pi * 36 / 5 - 11, 2))); return sqrt(pow(dl / sl, 2) + pow(dc / sc, 2) + pow(dh / sh, 2) + rt * dc / sc * dh / sh); } /* Function al_color_is_valid */ bool al_is_color_valid(ALLEGRO_COLOR color) { return color.r >= 0 && color.g >= 0 && color.b >= 0 && color.r <= 1 && color.g <= 1 && color.b <= 1; } /* Function: al_color_oklab_to_rgb * Note: Oklab code from https://bottosson.github.io/posts/oklab/ */ void al_color_oklab_to_rgb(float ol, float oa, float ob, float *red, float *green, float *blue) { float l_ = ol + 0.3963377774f * oa + 0.2158037573f * ob; float m_ = ol - 0.1055613458f * oa - 0.0638541728f * ob; float s_ = ol - 0.0894841775f * oa - 1.2914855480f * ob; float l = l_*l_*l_; float m = m_*m_*m_; float s = s_*s_*s_; float r = +4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s; float g = -1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s; float b = -0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s; *red = srgba_linear_to_gamma(r); *green = srgba_linear_to_gamma(g); *blue = srgba_linear_to_gamma(b); } /* Function: al_color_rgb_to_oklab * Note: Oklab code from https://bottosson.github.io/posts/oklab/ */ void al_color_rgb_to_oklab(float red, float green, float blue, float *ol, float *oa, float *ob) { double r = srgba_gamma_to_linear(red); double g = srgba_gamma_to_linear(green); double b = srgba_gamma_to_linear(blue); float l = 0.4122214708f * r + 0.5363325363f * g + 0.0514459929f * b; float m = 0.2119034982f * r + 0.6806995451f * g + 0.1073969566f * b; float s = 0.0883024619f * r + 0.2817188376f * g + 0.6299787005f * b; float l_ = cbrtf(l); float m_ = cbrtf(m); float s_ = cbrtf(s); *ol = 0.2104542553f*l_ + 0.7936177850f*m_ - 0.0040720468f*s_; *oa = 1.9779984951f*l_ - 2.4285922050f*m_ + 0.4505937099f*s_; *ob = 0.0259040371f*l_ + 0.7827717662f*m_ - 0.8086757660f*s_; } /* Function: al_color_oklab */ ALLEGRO_COLOR al_color_oklab(float l, float a, float b) { float r2, g2, b2; al_color_oklab_to_rgb(l, a, b, &r2, &g2, &b2); return al_map_rgb_f(r2, g2, b2); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/font/000077500000000000000000000000001473414355200156765ustar00rootroot00000000000000allegro5-5.2.10.1/addons/font/CMakeLists.txt000066400000000000000000000010021473414355200204270ustar00rootroot00000000000000set(FONT_SOURCES font.c fontbmp.c stdfont.c text.c bmfont.c xml.c) set(FONT_INCLUDE_FILES allegro5/allegro_font.h) set_our_header_properties(${FONT_INCLUDE_FILES}) add_our_addon_library(allegro_font AllegroFont-${ALLEGRO_SOVERSION} "${FONT_SOURCES};${FONT_INCLUDE_FILES}" "-DALLEGRO_FONT_SRC" "${ALLEGRO_LINK_WITH}" ) install_our_headers(${FONT_INCLUDE_FILES}) add_addon(font) #-----------------------------------------------------------------------------# # vim: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/addons/font/allegro5/000077500000000000000000000000001473414355200174105ustar00rootroot00000000000000allegro5-5.2.10.1/addons/font/allegro5/allegro_font.h000066400000000000000000000155431473414355200222440ustar00rootroot00000000000000#ifndef __al_included_allegro5_allegro_font_h #define __al_included_allegro5_allegro_font_h #include "allegro5/allegro.h" #if (defined ALLEGRO_MINGW32) || (defined ALLEGRO_MSVC) || (defined ALLEGRO_BCC32) #ifndef ALLEGRO_STATICLINK #ifdef ALLEGRO_FONT_SRC #define _ALLEGRO_FONT_DLL __declspec(dllexport) #else #define _ALLEGRO_FONT_DLL __declspec(dllimport) #endif #else #define _ALLEGRO_FONT_DLL #endif #endif #if defined ALLEGRO_MSVC #define ALLEGRO_FONT_FUNC(type, name, args) _ALLEGRO_FONT_DLL type __cdecl name args #define ALLEGRO_FONT_METHOD(type, name, args) type (__cdecl *name) args #define ALLEGRO_FONT_FUNCPTR(type, name, args) extern _ALLEGRO_FONT_DLL type (__cdecl *name) args #define ALLEGRO_FONT_PRINTFUNC(type, name, args, a, b) ALLEGRO_FONT_FUNC(type, name, args) #elif defined ALLEGRO_MINGW32 #define ALLEGRO_FONT_FUNC(type, name, args) extern type name args #define ALLEGRO_FONT_METHOD(type, name, args) type (*name) args #define ALLEGRO_FONT_FUNCPTR(type, name, args) extern _ALLEGRO_FONT_DLL type (*name) args #define ALLEGRO_FONT_PRINTFUNC(type, name, args, a, b) ALLEGRO_FONT_FUNC(type, name, args) __attribute__ ((format (printf, a, b))) #elif defined ALLEGRO_BCC32 #define ALLEGRO_FONT_FUNC(type, name, args) extern _ALLEGRO_FONT_DLL type name args #define ALLEGRO_FONT_METHOD(type, name, args) type (*name) args #define ALLEGRO_FONT_FUNCPTR(type, name, args) extern _ALLEGRO_FONT_DLL type (*name) args #define ALLEGRO_FONT_PRINTFUNC(type, name, args, a, b) ALLEGRO_FONT_FUNC(type, name, args) #else #define ALLEGRO_FONT_FUNC AL_FUNC #define ALLEGRO_FONT_METHOD AL_METHOD #define ALLEGRO_FONT_FUNCPTR AL_FUNCPTR #define ALLEGRO_FONT_PRINTFUNC AL_PRINTFUNC #endif #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_FONT */ typedef struct ALLEGRO_FONT ALLEGRO_FONT; #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_FONT_SRC) /* Type: ALLEGRO_GLYPH */ typedef struct ALLEGRO_GLYPH ALLEGRO_GLYPH; struct ALLEGRO_GLYPH { ALLEGRO_BITMAP *bitmap; int x; int y; int w; int h; int kerning; int offset_x; int offset_y; int advance; }; #endif enum { ALLEGRO_NO_KERNING = -1, ALLEGRO_ALIGN_LEFT = 0, ALLEGRO_ALIGN_CENTRE = 1, ALLEGRO_ALIGN_CENTER = 1, ALLEGRO_ALIGN_RIGHT = 2, ALLEGRO_ALIGN_INTEGER = 4, }; ALLEGRO_FONT_FUNC(bool, al_register_font_loader, (const char *ext, ALLEGRO_FONT *(*load)(const char *filename, int size, int flags))); ALLEGRO_FONT_FUNC(ALLEGRO_FONT *, al_load_bitmap_font, (const char *filename)); ALLEGRO_FONT_FUNC(ALLEGRO_FONT *, al_load_bitmap_font_flags, (const char *filename, int flags)); ALLEGRO_FONT_FUNC(ALLEGRO_FONT *, al_load_font, (const char *filename, int size, int flags)); ALLEGRO_FONT_FUNC(ALLEGRO_FONT *, al_grab_font_from_bitmap, (ALLEGRO_BITMAP *bmp, int n, const int ranges[])); ALLEGRO_FONT_FUNC(ALLEGRO_FONT *, al_create_builtin_font, (void)); ALLEGRO_FONT_FUNC(void, al_draw_ustr, (const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int flags, ALLEGRO_USTR const *ustr)); ALLEGRO_FONT_FUNC(void, al_draw_text, (const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int flags, char const *text)); ALLEGRO_FONT_FUNC(void, al_draw_justified_text, (const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x1, float x2, float y, float diff, int flags, char const *text)); ALLEGRO_FONT_FUNC(void, al_draw_justified_ustr, (const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x1, float x2, float y, float diff, int flags, ALLEGRO_USTR const *text)); ALLEGRO_FONT_PRINTFUNC(void, al_draw_textf, (const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int flags, char const *format, ...), 6, 7); ALLEGRO_FONT_PRINTFUNC(void, al_draw_justified_textf, (const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x1, float x2, float y, float diff, int flags, char const *format, ...), 8, 9); ALLEGRO_FONT_FUNC(int, al_get_text_width, (const ALLEGRO_FONT *f, const char *str)); ALLEGRO_FONT_FUNC(int, al_get_ustr_width, (const ALLEGRO_FONT *f, const ALLEGRO_USTR *ustr)); ALLEGRO_FONT_FUNC(int, al_get_font_line_height, (const ALLEGRO_FONT *f)); ALLEGRO_FONT_FUNC(int, al_get_font_ascent, (const ALLEGRO_FONT *f)); ALLEGRO_FONT_FUNC(int, al_get_font_descent, (const ALLEGRO_FONT *f)); ALLEGRO_FONT_FUNC(void, al_destroy_font, (ALLEGRO_FONT *f)); ALLEGRO_FONT_FUNC(void, al_get_ustr_dimensions, (const ALLEGRO_FONT *f, ALLEGRO_USTR const *text, int *bbx, int *bby, int *bbw, int *bbh)); ALLEGRO_FONT_FUNC(void, al_get_text_dimensions, (const ALLEGRO_FONT *f, char const *text, int *bbx, int *bby, int *bbw, int *bbh)); ALLEGRO_FONT_FUNC(bool, al_init_font_addon, (void)); ALLEGRO_FONT_FUNC(bool, al_is_font_addon_initialized, (void)); ALLEGRO_FONT_FUNC(void, al_shutdown_font_addon, (void)); ALLEGRO_FONT_FUNC(uint32_t, al_get_allegro_font_version, (void)); ALLEGRO_FONT_FUNC(int, al_get_font_ranges, (ALLEGRO_FONT *font, int ranges_count, int *ranges)); ALLEGRO_FONT_FUNC(void, al_draw_glyph, (const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int codepoint)); ALLEGRO_FONT_FUNC(int, al_get_glyph_width, (const ALLEGRO_FONT *f, int codepoint)); ALLEGRO_FONT_FUNC(bool, al_get_glyph_dimensions, (const ALLEGRO_FONT *f, int codepoint, int *bbx, int *bby, int *bbw, int *bbh)); ALLEGRO_FONT_FUNC(int, al_get_glyph_advance, (const ALLEGRO_FONT *f, int codepoint1, int codepoint2)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_FONT_SRC) ALLEGRO_FONT_FUNC(bool, al_get_glyph, (const ALLEGRO_FONT *f, int prev_codepoint, int codepoint, ALLEGRO_GLYPH *glyph)); #endif ALLEGRO_FONT_FUNC(void, al_draw_multiline_text, (const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, float max_width, float line_height, int flags, const char *text)); ALLEGRO_FONT_PRINTFUNC(void, al_draw_multiline_textf, (const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, float max_width, float line_height, int flags, const char *format, ...), 8, 9); ALLEGRO_FONT_FUNC(void, al_draw_multiline_ustr, (const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, float max_width, float line_height, int flags, const ALLEGRO_USTR *text)); ALLEGRO_FONT_FUNC(void, al_do_multiline_text, (const ALLEGRO_FONT *font, float max_width, const char *text, bool (*cb)(int line_num, const char *line, int size, void *extra), void *extra)); ALLEGRO_FONT_FUNC(void, al_do_multiline_ustr, (const ALLEGRO_FONT *font, float max_width, const ALLEGRO_USTR *ustr, bool (*cb)(int line_num, const ALLEGRO_USTR *line, void *extra), void *extra)); ALLEGRO_FONT_FUNC(void, al_set_fallback_font, (ALLEGRO_FONT *font, ALLEGRO_FONT *fallback)); ALLEGRO_FONT_FUNC(ALLEGRO_FONT *, al_get_fallback_font, ( ALLEGRO_FONT *font)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/font/allegro5/internal/000077500000000000000000000000001473414355200212245ustar00rootroot00000000000000allegro5-5.2.10.1/addons/font/allegro5/internal/aintern_font.h000066400000000000000000000032571473414355200240720ustar00rootroot00000000000000#ifndef __al_included_allegro_aintern_font_h #define __al_included_allegro_aintern_font_h #include "allegro5/internal/aintern_list.h" typedef struct ALLEGRO_FONT_VTABLE ALLEGRO_FONT_VTABLE; struct ALLEGRO_FONT { void *data; int height; ALLEGRO_FONT *fallback; ALLEGRO_FONT_VTABLE *vtable; _AL_LIST_ITEM *dtor_item; }; /* text- and font-related stuff */ struct ALLEGRO_FONT_VTABLE { ALLEGRO_FONT_METHOD(int, font_height, (const ALLEGRO_FONT *f)); ALLEGRO_FONT_METHOD(int, font_ascent, (const ALLEGRO_FONT *f)); ALLEGRO_FONT_METHOD(int, font_descent, (const ALLEGRO_FONT *f)); ALLEGRO_FONT_METHOD(int, char_length, (const ALLEGRO_FONT *f, int ch)); ALLEGRO_FONT_METHOD(int, text_length, (const ALLEGRO_FONT *f, const ALLEGRO_USTR *text)); ALLEGRO_FONT_METHOD(int, render_char, (const ALLEGRO_FONT *f, ALLEGRO_COLOR color, int ch, float x, float y)); ALLEGRO_FONT_METHOD(int, render, (const ALLEGRO_FONT *f, ALLEGRO_COLOR color, const ALLEGRO_USTR *text, float x, float y)); ALLEGRO_FONT_METHOD(void, destroy, (ALLEGRO_FONT *f)); ALLEGRO_FONT_METHOD(void, get_text_dimensions, (const ALLEGRO_FONT *f, const ALLEGRO_USTR *text, int *bbx, int *bby, int *bbw, int *bbh)); ALLEGRO_FONT_METHOD(int, get_font_ranges, (ALLEGRO_FONT *font, int ranges_count, int *ranges)); ALLEGRO_FONT_METHOD(bool, get_glyph_dimensions, (const ALLEGRO_FONT *f, int codepoint, int *bbx, int *bby, int *bbw, int *bbh)); ALLEGRO_FONT_METHOD(int, get_glyph_advance, (const ALLEGRO_FONT *font, int codepoint1, int codepoint2)); ALLEGRO_FONT_METHOD(bool, get_glyph, (const ALLEGRO_FONT *f, int prev_codepoint, int codepoint, ALLEGRO_GLYPH *glyph)); }; #endif allegro5-5.2.10.1/addons/font/bmfont.c000066400000000000000000000347201473414355200173350ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include #include "allegro5/internal/aintern_font.h" #include "font.h" #include "xml.h" ALLEGRO_DEBUG_CHANNEL("font") typedef struct { int first; int second; int amount; } BMFONT_KERNING; typedef struct { int page; int x, y; int width, height; int xoffset, yoffset; int xadvance; int chnl; int kerning_pairs; BMFONT_KERNING *kerning; } BMFONT_CHAR; typedef struct BMFONT_RANGE BMFONT_RANGE; struct BMFONT_RANGE { int first; int count; BMFONT_CHAR **characters; BMFONT_RANGE *next; }; typedef struct { int pages_count; ALLEGRO_BITMAP **pages; BMFONT_RANGE *range_first; int base; int line_height; int flags; int kerning_pairs; BMFONT_KERNING *kerning; } BMFONT_DATA; typedef struct { ALLEGRO_FONT *font; ALLEGRO_USTR *tag; ALLEGRO_USTR *attribute; BMFONT_CHAR *c; ALLEGRO_PATH *path; } BMFONT_PARSER; static void reallocate(BMFONT_RANGE *range) { range->characters = al_realloc(range->characters, range->count * sizeof *range->characters); } static void prepend_char(BMFONT_PARSER *parser, BMFONT_RANGE *range) { range->first--; range->count++; reallocate(range); memmove(range->characters + 1, range->characters, (range->count - 1) * sizeof *range->characters); range->characters[0] = parser->c; } static void append_char(BMFONT_PARSER *parser, BMFONT_RANGE *range) { range->count++; reallocate(range); range->characters[range->count - 1] = parser->c; } static void combine_ranges(BMFONT_DATA *data, BMFONT_RANGE *range, BMFONT_RANGE *range2) { (void)data; range->count += range2->count; reallocate(range); memmove(range->characters + range->count - range2->count, range2->characters, range2->count * sizeof *range->characters); range->next = range2->next; al_free(range2->characters); al_free(range2); } static void insert_new_range(BMFONT_PARSER *parser, BMFONT_RANGE *prev, int codepoint) { BMFONT_RANGE *range = al_calloc(1, sizeof *range); range->first = codepoint; range->count = 1; reallocate(range); range->characters[0] = parser->c; if (prev) { range->next = prev->next; prev->next = range; } else { ALLEGRO_FONT *font = parser->font; BMFONT_DATA *data = font->data; range->next = data->range_first; data->range_first = range; } } /* Adding a new codepoint creates either a new range consisting of that * single codepoint, appends the codepoint to the end of a range, * prepends it to the beginning of a range, or merges two ranges. */ static void add_codepoint(BMFONT_PARSER *parser, int codepoint) { ALLEGRO_FONT *font = parser->font; BMFONT_DATA *data = font->data; BMFONT_RANGE *prev = NULL; BMFONT_RANGE *range = data->range_first; while (range) { if (codepoint == range->first - 1) { prepend_char(parser, range); return; } if (codepoint < range->first) { insert_new_range(parser, prev, codepoint); return; } if (codepoint == range->first + range->count) { append_char(parser, range); BMFONT_RANGE *range2 = range->next; if (range2 != NULL && codepoint == range2->first - 1) { combine_ranges(data, range, range2); } return; } prev = range; range = range->next; } insert_new_range(parser, prev, codepoint); } static BMFONT_CHAR *find_codepoint(BMFONT_DATA *data, int codepoint) { BMFONT_RANGE *range = data->range_first; while (range) { if (codepoint >= range->first && codepoint < range->first + range->count) { return range->characters[codepoint - range->first]; } range = range->next; } return NULL; } static void add_page(BMFONT_PARSER *parser, char const *filename) { ALLEGRO_FONT *font = parser->font; BMFONT_DATA *data = font->data; data->pages_count++; data->pages = al_realloc(data->pages, data->pages_count * sizeof *data->pages); al_set_path_filename(parser->path, filename); ALLEGRO_BITMAP *page = al_load_bitmap_flags( al_path_cstr(parser->path, '/'), data->flags); data->pages[data->pages_count - 1] = page; } static bool tag_is(BMFONT_PARSER *parser, char const *str) { return strcmp(al_cstr(parser->tag), str) == 0; } static bool attribute_is(BMFONT_PARSER *parser, char const *str) { return strcmp(al_cstr(parser->attribute), str) == 0; } static int get_int(char const *value) { return strtol(value, NULL, 10); } static int xml_callback(XmlState state, char const *value, void *u) { BMFONT_PARSER *parser = u; ALLEGRO_FONT *font = parser->font; BMFONT_DATA *data = font->data; if (state == ElementName) { al_ustr_assign_cstr(parser->tag, value); if (tag_is(parser, "char")) { parser->c = al_calloc(1, sizeof *parser->c); } else if (tag_is(parser, "kerning")) { data->kerning_pairs++; data->kerning = al_realloc(data->kerning, data->kerning_pairs * sizeof *data->kerning); } } if (state == AttributeName) { al_ustr_assign_cstr(parser->attribute, value); } if (state == AttributeValue) { if (tag_is(parser, "char")) { if (attribute_is(parser, "x")) parser->c->x = get_int(value); else if (attribute_is(parser, "y")) parser->c->y = get_int(value); else if (attribute_is(parser, "xoffset")) parser->c->xoffset = get_int(value); else if (attribute_is(parser, "yoffset")) parser->c->yoffset = get_int(value); else if (attribute_is(parser, "width")) parser->c->width = get_int(value); else if (attribute_is(parser, "height")) parser->c->height = get_int(value); else if (attribute_is(parser, "page")) parser->c->page = get_int(value); else if (attribute_is(parser, "xadvance")) parser->c->xadvance = get_int(value); else if (attribute_is(parser, "chnl")) parser->c->chnl = get_int(value); else if (attribute_is(parser, "id")) { add_codepoint(parser, get_int(value)); } } else if (tag_is(parser, "page")) { if (attribute_is(parser, "file")) { add_page(parser, value); } } else if (tag_is(parser, "common")) { if (attribute_is(parser, "lineHeight")) data->line_height = get_int(value); else if (attribute_is(parser, "base")) data->base = get_int(value); } else if (tag_is(parser, "kerning")) { BMFONT_KERNING *k = data->kerning + data->kerning_pairs - 1; if (attribute_is(parser, "first")) k->first = get_int(value); else if (attribute_is(parser, "second")) k->second = get_int(value); else if (attribute_is(parser, "amount")) k->amount = get_int(value); } } return 0; } static int font_height(const ALLEGRO_FONT *f) { BMFONT_DATA *data = f->data; return data->line_height; } static int font_ascent(const ALLEGRO_FONT *f) { BMFONT_DATA *data = f->data; return data->base; } static int font_descent(const ALLEGRO_FONT *f) { BMFONT_DATA *data = f->data; return data->line_height - data->base; } static int get_kerning(BMFONT_CHAR *prev, int c) { if (!prev) return 0; int i; for (i = 0; i < prev->kerning_pairs; i++) { if (prev->kerning[i].second == c) { int a = prev->kerning[i].amount; return a; } } return 0; } static int each_character(const ALLEGRO_FONT *f, ALLEGRO_COLOR color, const ALLEGRO_USTR *text, float x, float y, ALLEGRO_GLYPH *glyph, int (*cb)(const ALLEGRO_FONT *f, ALLEGRO_COLOR color, int ch, float x, float y, ALLEGRO_GLYPH *glyph)) { BMFONT_DATA *data = f->data; int pos = 0; int advance = 0; int prev = 0; while (true) { int c = al_ustr_get_next(text, &pos); if (c < 0) break; if (prev) { BMFONT_CHAR *pc = find_codepoint(data, prev); advance += get_kerning(pc, c); } advance += cb(f, color, c, x + advance, y, glyph); prev = c; } return advance; } static int measure_char(const ALLEGRO_FONT *f, ALLEGRO_COLOR color, int ch, float x, float y, ALLEGRO_GLYPH *glyph) { (void)color; (void)y; BMFONT_DATA *data = f->data; BMFONT_CHAR *c = find_codepoint(data, ch); int advance = 0; int xo = 0, yo = 0, w = 0, h = 0; if (c) { advance = c->xadvance; xo = c->xoffset; yo = c->yoffset; w = c->width; h = c->height; } else { if (!f->fallback) return 0; advance = al_get_glyph_width(f->fallback, ch); al_get_glyph_dimensions(f->fallback, ch, &xo, &yo, &w, &h); } if (glyph) { if (glyph->x == INT_MAX) glyph->x = xo; if (yo < glyph->y) glyph->y = yo; if (yo + h > glyph->h) glyph->h = yo + h; if (x + xo + w > glyph->w) glyph->w = x + xo + w; } return advance; } static bool get_glyph_dimensions(const ALLEGRO_FONT *f, int codepoint, int *bbx, int *bby, int *bbw, int *bbh) { BMFONT_DATA *data = f->data; BMFONT_CHAR *c = find_codepoint(data, codepoint); if (!c) { if (!f->fallback) return false; return al_get_glyph_dimensions(f->fallback, codepoint, bbx, bby, bbw, bbh); } *bbx = c->xoffset; *bby = c->yoffset; *bbw = c->width; *bbh = c->height; return true; } static int get_glyph_advance(const ALLEGRO_FONT *f, int codepoint1, int codepoint2) { BMFONT_DATA *data = f->data; BMFONT_CHAR *c = find_codepoint(data, codepoint1); int kerning = 0; if (codepoint1 == ALLEGRO_NO_KERNING) { return 0; } if (!c) { if (!f->fallback) return 0; return al_get_glyph_advance(f->fallback, codepoint1, codepoint2); } if (codepoint2 != ALLEGRO_NO_KERNING) kerning = get_kerning(c, codepoint2); return c->xadvance + kerning; } static bool get_glyph(const ALLEGRO_FONT *f, int prev_codepoint, int codepoint, ALLEGRO_GLYPH *glyph) { BMFONT_DATA *data = f->data; BMFONT_CHAR *prev = find_codepoint(data, prev_codepoint); BMFONT_CHAR *c = find_codepoint(data, codepoint); if (c) { glyph->bitmap = data->pages[c->page]; glyph->x = c->x; glyph->y = c->y; glyph->w = c->width; glyph->h = c->height; glyph->kerning = get_kerning(prev, codepoint); glyph->offset_x = c->xoffset; glyph->offset_y = c->yoffset; glyph->advance = c->xadvance + glyph->kerning; return true; } if (f->fallback) { return al_get_glyph(f->fallback, prev_codepoint, codepoint, glyph); } return false; } static int char_length(const ALLEGRO_FONT *f, int ch) { ALLEGRO_COLOR color = {0, 0, 0, 0}; return measure_char(f, color, ch, 0, 0, NULL); } static int text_length(const ALLEGRO_FONT *f, const ALLEGRO_USTR *text) { ALLEGRO_COLOR color = {0, 0, 0, 0}; return each_character(f, color, text, 0, 0, NULL, measure_char); } static int render_char(const ALLEGRO_FONT *f, ALLEGRO_COLOR color, int ch, float x, float y) { BMFONT_DATA *data = f->data; BMFONT_CHAR *c = find_codepoint(data, ch); if (!c) { if (f->fallback) return f->fallback->vtable->render_char( f->fallback, color, ch, x, y); return 0; } ALLEGRO_BITMAP *page = data->pages[c->page]; al_draw_tinted_bitmap_region(page, color, c->x, c->y, c->width, c->height, x + c->xoffset, y + c->yoffset, 0); return c->xadvance; } static int render_char_cb(const ALLEGRO_FONT *f, ALLEGRO_COLOR color, int ch, float x, float y, ALLEGRO_GLYPH *glyph) { (void)glyph; return render_char(f, color, ch, x, y); } static int render(const ALLEGRO_FONT *f, ALLEGRO_COLOR color, const ALLEGRO_USTR *text, float x, float y) { return each_character(f, color, text, x, y, NULL, render_char_cb); } static void destroy_range(BMFONT_RANGE *range) { int i; for (i = 0; i < range->count; i++) { BMFONT_CHAR *c = range->characters[i]; al_free(c->kerning); al_free(c); } al_free(range); } static void destroy(ALLEGRO_FONT *f) { BMFONT_DATA *data = f->data; BMFONT_RANGE *range = data->range_first; while (range) { BMFONT_RANGE *next = range->next; destroy_range(range); range = next; } int i; for (i = 0; i < data->pages_count; i++) { al_destroy_bitmap(data->pages[i]); } al_free(data->pages); al_free(data->kerning); al_free(f); } static void get_text_dimensions(const ALLEGRO_FONT *f, const ALLEGRO_USTR *text, int *bbx, int *bby, int *bbw, int *bbh) { ALLEGRO_COLOR color = {0, 0, 0, 0}; ALLEGRO_GLYPH glyph; glyph.x = INT_MAX; glyph.y = INT_MAX; glyph.w = INT_MIN; glyph.h = INT_MIN; each_character(f, color, text, 0, 0, &glyph, measure_char); *bbx = glyph.x; *bby = glyph.y; *bbw = glyph.w - glyph.x; *bbh = glyph.h - glyph.y; } static int get_font_ranges(ALLEGRO_FONT *f, int ranges_count, int *ranges) { BMFONT_DATA *data = f->data; BMFONT_RANGE *range = data->range_first; int i = 0; while (range) { if (i < ranges_count) { ranges[i * 2 + 0] = range->first; ranges[i * 2 + 1] = range->first + range->count - 1; } range = range->next; i++; } return i; } static ALLEGRO_FONT_VTABLE _al_font_vtable_xml = { font_height, font_ascent, font_descent, char_length, text_length, render_char, render, destroy, get_text_dimensions, get_font_ranges, get_glyph_dimensions, get_glyph_advance, get_glyph }; ALLEGRO_FONT *_al_load_bmfont_xml(const char *filename, int size, int font_flags) { (void)size; ALLEGRO_FILE *f = al_fopen(filename, "r"); if (!f) { ALLEGRO_DEBUG("Could not open %s.\n", filename); return NULL; } BMFONT_DATA *data = al_calloc(1, sizeof *data); BMFONT_PARSER _parser; BMFONT_PARSER *parser = &_parser; parser->tag = al_ustr_new(""); parser->attribute = al_ustr_new(""); parser->path = al_create_path(filename); data->flags = font_flags; ALLEGRO_FONT *font = al_calloc(1, sizeof *font); font->vtable = &_al_font_vtable_xml; font->data = data; parser->font = font; _al_xml_parse(f, xml_callback, parser); int i; for (i = 0; i < data->kerning_pairs; i++) { BMFONT_KERNING *k = data->kerning + i; BMFONT_CHAR *c = find_codepoint(data, k->first); c->kerning_pairs++; c->kerning = al_realloc(c->kerning, c->kerning_pairs * sizeof *c->kerning); c->kerning[c->kerning_pairs - 1] = *k; } al_ustr_free(parser->tag); al_ustr_free(parser->attribute); al_destroy_path(parser->path); return font; } allegro5-5.2.10.1/addons/font/font.c000066400000000000000000000267721473414355200170260ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * * See readme.txt for copyright information. */ #define ALLEGRO_INTERNAL_UNSTABLE #include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_font.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_vector.h" #include "font.h" #include ALLEGRO_DEBUG_CHANNEL("font") typedef struct { ALLEGRO_USTR *extension; ALLEGRO_FONT *(*load_font)(char const *filename, int size, int flags); } FONT_HANDLER; /* globals */ static bool font_inited = false; static _AL_VECTOR font_handlers = _AL_VECTOR_INITIALIZER(FONT_HANDLER); /* al_font_404_character: * This is what we render missing glyphs as. */ static int al_font_404_character = '^'; /* font_height: * (mono and color vtable entry) * Returns the height, in pixels of the font. */ static int font_height(const ALLEGRO_FONT *f) { ASSERT(f); return f->height; } static int font_ascent(const ALLEGRO_FONT *f) { return font_height(f); } static int font_descent(const ALLEGRO_FONT *f) { (void)f; return 0; } /* length: * (mono and color vtable entry) * Returns the length, in pixels, of a string as rendered in a font. */ static int length(const ALLEGRO_FONT* f, const ALLEGRO_USTR *text) { int ch = 0, w = 0; int pos = 0; ASSERT(f); while ((ch = al_ustr_get_next(text, &pos)) >= 0) { w += f->vtable->char_length(f, ch); } return w; } static void color_get_text_dimensions(ALLEGRO_FONT const *f, const ALLEGRO_USTR *text, int *bbx, int *bby, int *bbw, int *bbh) { /* Dummy implementation - for A4-style bitmap fonts the bounding * box of text is its width and line-height. */ int h = al_get_font_line_height(f); if (bbx) *bbx = 0; if (bby) *bby = 0; if (bbw) *bbw = length(f, text); if (bbh) *bbh = h; } static ALLEGRO_FONT_COLOR_DATA *_al_font_find_page( ALLEGRO_FONT_COLOR_DATA *cf, int ch) { while (cf) { if (ch >= cf->begin && ch < cf->end) return cf; cf = cf->next; } return NULL; } /* _color_find_glyph: * Helper for color vtable entries, below. */ static ALLEGRO_BITMAP* _al_font_color_find_glyph(const ALLEGRO_FONT* f, int ch) { ALLEGRO_FONT_COLOR_DATA* cf = (ALLEGRO_FONT_COLOR_DATA*)(f->data); cf = _al_font_find_page(cf, ch); if (cf) { return cf->bitmaps[ch - cf->begin]; } /* if we don't find the character, then search for the missing glyph, but don't get stuck in a loop. */ if (ch != al_font_404_character && !f->fallback) return _al_font_color_find_glyph(f, al_font_404_character); return 0; } /* color_char_length: * (color vtable entry) * Returns the length of a character, in pixels, as it would be rendered * in this font. */ static int color_char_length(const ALLEGRO_FONT* f, int ch) { ALLEGRO_BITMAP* g = _al_font_color_find_glyph(f, ch); if (g) return al_get_bitmap_width(g); if (f->fallback) return al_get_glyph_width(f->fallback, ch); return 0; } /* color_render_char: * (color vtable entry) * Renders a color character onto a bitmap, at the specified location, * using the specified color. * Returns the character width, in pixels. */ static int color_render_char(const ALLEGRO_FONT* f, ALLEGRO_COLOR color, int ch, float x, float y) { int w = 0; int h = f->vtable->font_height(f); ALLEGRO_BITMAP *g; g = _al_font_color_find_glyph(f, ch); if (g) { al_draw_tinted_bitmap(g, color, x, y + ((float)h - al_get_bitmap_height(g))/2.0f, 0); w = al_get_bitmap_width(g); } else if (f->fallback) { al_draw_glyph(f->fallback, color, x, y, ch); w = al_get_glyph_width(f->fallback, ch); } return w; } /* color_render: * (color vtable entry) * Renders a color font onto a bitmap, at the specified location, using * the specified color. */ static int color_render(const ALLEGRO_FONT* f, ALLEGRO_COLOR color, const ALLEGRO_USTR *text, float x, float y) { int pos = 0; int advance = 0; int32_t ch; bool held = al_is_bitmap_drawing_held(); al_hold_bitmap_drawing(true); while ((ch = al_ustr_get_next(text, &pos)) >= 0) { advance += f->vtable->render_char(f, color, ch, x + advance, y); } al_hold_bitmap_drawing(held); return advance; } static bool color_get_glyph(const ALLEGRO_FONT *f, int prev_codepoint, int codepoint, ALLEGRO_GLYPH *glyph) { ALLEGRO_BITMAP *g = _al_font_color_find_glyph(f, codepoint); if (g) { glyph->bitmap = g; glyph->x = 0; glyph->y = 0; glyph->w = al_get_bitmap_width(g); glyph->h = al_get_bitmap_height(g); glyph->kerning = 0; glyph->offset_x = 0; glyph->offset_y = 0; glyph->advance = glyph->w; return true; } if (f->fallback) { return f->fallback->vtable->get_glyph(f->fallback, prev_codepoint, codepoint, glyph); } return false; } /* color_destroy: * (color vtable entry) * Destroys a color font. */ static void color_destroy(ALLEGRO_FONT* f) { ALLEGRO_FONT_COLOR_DATA* cf; ALLEGRO_BITMAP *glyphs = NULL; if (!f) return; cf = (ALLEGRO_FONT_COLOR_DATA*)(f->data); if (cf) glyphs = cf->glyphs; while (cf) { ALLEGRO_FONT_COLOR_DATA* next = cf->next; int i = 0; for (i = cf->begin; i < cf->end; i++) al_destroy_bitmap(cf->bitmaps[i - cf->begin]); /* Each range might point to the same bitmap. */ if (cf->glyphs != glyphs) { al_destroy_bitmap(cf->glyphs); cf->glyphs = NULL; } if (!next && cf->glyphs) al_destroy_bitmap(cf->glyphs); al_free(cf->bitmaps); al_free(cf); cf = next; } al_free(f); } static int color_get_font_ranges(ALLEGRO_FONT *font, int ranges_count, int *ranges) { ALLEGRO_FONT_COLOR_DATA *cf = font->data; int i = 0; while (cf) { if (i < ranges_count) { ranges[i * 2 + 0] = cf->begin; ranges[i * 2 + 1] = cf->end - 1; } i++; cf = cf->next; } return i; } static bool color_get_glyph_dimensions(ALLEGRO_FONT const *f, int codepoint, int *bbx, int *bby, int *bbw, int *bbh) { ALLEGRO_BITMAP *glyph = _al_font_color_find_glyph(f, codepoint); if(!glyph) { if (f->fallback) { return al_get_glyph_dimensions(f->fallback, codepoint, bbx, bby, bbw, bbh); } return false; } if (bbx) *bbx = 0; if (bby) *bby = 0; if (bbw) *bbw = glyph ? al_get_bitmap_width(glyph) : 0; if (bbh) *bbh = al_get_font_line_height(f); return true; } static int color_get_glyph_advance(ALLEGRO_FONT const *f, int codepoint1, int codepoint2) { (void) codepoint2; /* Handle special case to simplify use in a loop. */ if (codepoint1 == ALLEGRO_NO_KERNING) { return 0; } /* For other cases, bitmap fonts don't use any kerning, so just use the * width of codepoint1. */ return color_char_length(f, codepoint1); } /******** * vtable declarations ********/ ALLEGRO_FONT_VTABLE _al_font_vtable_color = { font_height, font_ascent, font_descent, color_char_length, length, color_render_char, color_render, color_destroy, color_get_text_dimensions, color_get_font_ranges, color_get_glyph_dimensions, color_get_glyph_advance, color_get_glyph }; static void font_shutdown(void) { if (!font_inited) return; while (!_al_vector_is_empty(&font_handlers)) { FONT_HANDLER *h = _al_vector_ref_back(&font_handlers); al_ustr_free(h->extension); _al_vector_delete_at(&font_handlers, _al_vector_size(&font_handlers)-1); } _al_vector_free(&font_handlers); font_inited = false; } /* Function: al_init_font_addon */ bool al_init_font_addon(void) { if (font_inited) { ALLEGRO_WARN("Font addon already initialised.\n"); return true; } al_register_font_loader(".bmp", _al_load_bitmap_font); al_register_font_loader(".jpg", _al_load_bitmap_font); al_register_font_loader(".pcx", _al_load_bitmap_font); al_register_font_loader(".png", _al_load_bitmap_font); al_register_font_loader(".tga", _al_load_bitmap_font); al_register_font_loader(".xml", _al_load_bmfont_xml); al_register_font_loader(".fnt", _al_load_bmfont_xml); _al_add_exit_func(font_shutdown, "font_shutdown"); font_inited = true; return font_inited; } /* Function: al_is_font_addon_initialized */ bool al_is_font_addon_initialized(void) { return font_inited; } /* Function: al_shutdown_font_addon */ void al_shutdown_font_addon(void) { font_shutdown(); } static FONT_HANDLER *find_extension(char const *extension) { int i; /* Go backwards so a handler registered later for the same extension * has precedence. */ for (i = _al_vector_size(&font_handlers) - 1; i >= 0 ; i--) { FONT_HANDLER *handler = _al_vector_ref(&font_handlers, i); if (0 == _al_stricmp(al_cstr(handler->extension), extension)) return handler; } return NULL; } /* Function: al_register_font_loader */ bool al_register_font_loader(char const *extension, ALLEGRO_FONT *(*load_font)(char const *filename, int size, int flags)) { FONT_HANDLER *handler = find_extension(extension); if (!handler) { if (!load_font) return false; /* Nothing to remove. */ handler = _al_vector_alloc_back(&font_handlers); handler->extension = al_ustr_new(extension); } else { if (!load_font) { al_ustr_free(handler->extension); return _al_vector_find_and_delete(&font_handlers, handler); } } handler->load_font = load_font; return true; } /* Function: al_load_font */ ALLEGRO_FONT *al_load_font(char const *filename, int size, int flags) { int i; const char *ext; FONT_HANDLER *handler; ASSERT(filename); if (!font_inited) { ALLEGRO_ERROR("Font addon not initialised.\n"); return NULL; } ext = strrchr(filename, '.'); if (!ext) { ALLEGRO_ERROR("Unable to determine filetype: '%s'\n", filename); return NULL; } handler = find_extension(ext); if (handler) return handler->load_font(filename, size, flags); /* No handler for the extension was registered - try to load with * all registered font_handlers and see if one works. So if the user * does: * * al_init_font_addon() * al_init_ttf_addon() * * This will first try to load an unknown (let's say Type1) font file * with Freetype (and load it successfully in this case), then try * to load it as a bitmap font. */ for (i = _al_vector_size(&font_handlers) - 1; i >= 0 ; i--) { FONT_HANDLER *handler = _al_vector_ref(&font_handlers, i); ALLEGRO_FONT *try = handler->load_font(filename, size, flags); if (try) return try; } return NULL; } /* Function: al_get_allegro_font_version */ uint32_t al_get_allegro_font_version(void) { return ALLEGRO_VERSION_INT; } /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/addons/font/font.h000066400000000000000000000012701473414355200170150ustar00rootroot00000000000000#ifndef __al_included_allegro5_font_h #define __al_included_allegro5_font_h #include "allegro5/internal/aintern_font.h" extern ALLEGRO_FONT_VTABLE _al_font_vtable_color; typedef struct ALLEGRO_FONT_COLOR_DATA { int begin, end; /* first char and one-past-the-end char */ ALLEGRO_BITMAP *glyphs; /* our glyphs */ ALLEGRO_BITMAP **bitmaps; /* sub bitmaps pointing to our glyphs */ struct ALLEGRO_FONT_COLOR_DATA *next; /* linked list structure */ } ALLEGRO_FONT_COLOR_DATA; ALLEGRO_FONT *_al_load_bitmap_font(const char *filename, int size, int flags); ALLEGRO_FONT *_al_load_bmfont_xml(const char *filename, int size, int flags); #endif allegro5-5.2.10.1/addons/font/fontbmp.c000066400000000000000000000167441473414355200175230ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Read font from a bitmap. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_system.h" #include "font.h" ALLEGRO_DEBUG_CHANNEL("font") static void font_find_character(uint32_t *data, int pitch, int bmp_w, int bmp_h, int *x, int *y, int *w, int *h) { /* The pixel at position 0/0 is used as background color. */ uint32_t c = data[0]; pitch >>= 2; /* look for top left corner of character */ while (1) { /* Reached border? */ if (*x >= bmp_w - 1) { *x = 0; (*y)++; if (*y >= bmp_h - 1) { *w = 0; *h = 0; return; } } if ( data[*x + *y * pitch] == c && data[(*x + 1) + *y * pitch] == c && data[*x + (*y + 1) * pitch] == c && data[(*x + 1) + (*y + 1) * pitch] != c) { break; } (*x)++; } /* look for right edge of character */ *w = 1; while ((*x + *w + 1 < bmp_w) && data[(*x + *w + 1) + (*y + 1) * pitch] != c) { (*w)++; } /* look for bottom edge of character */ *h = 1; while ((*y + *h + 1 < bmp_h) && data[*x + 1 + (*y + *h + 1) * pitch] != c) { (*h)++; } } /* import_bitmap_font_color: * Helper for import_bitmap_font, below. */ static int import_bitmap_font_color(uint32_t *data, int pitch, int bmp_w, int bmp_h, ALLEGRO_BITMAP **bits, ALLEGRO_BITMAP *glyphs, int num, int *import_x, int *import_y) { int w, h, i; for (i = 0; i < num; i++) { font_find_character(data, pitch, bmp_w, bmp_h, import_x, import_y, &w, &h); if (w <= 0 || h <= 0) { ALLEGRO_ERROR("Unable to find character %d\n", i); return -1; } else { bits[i] = al_create_sub_bitmap(glyphs, *import_x + 1, *import_y + 1, w, h); *import_x += w; } } return 0; } /* bitmap_font_count: * Helper for `import_bitmap_font', below. */ static int bitmap_font_count(ALLEGRO_BITMAP* bmp) { int x = 0, y = 0, w = 0, h = 0; int num = 0; ALLEGRO_LOCKED_REGION *lock; lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_RGBA_8888, ALLEGRO_LOCK_READONLY); while (1) { font_find_character(lock->data, lock->pitch, al_get_bitmap_width(bmp), al_get_bitmap_height(bmp), &x, &y, &w, &h); if (w <= 0 || h <= 0) break; num++; x += w; } al_unlock_bitmap(bmp); return num; } ALLEGRO_FONT *_al_load_bitmap_font(const char *fname, int size, int font_flags) { ALLEGRO_BITMAP *import_bmp; ALLEGRO_FONT *f; ALLEGRO_STATE backup; int range[2]; int bmp_flags; ASSERT(fname); (void)size; bmp_flags = 0; if (font_flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA) { bmp_flags |= ALLEGRO_NO_PREMULTIPLIED_ALPHA; } al_store_state(&backup, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA); import_bmp = al_load_bitmap_flags(fname, bmp_flags); al_restore_state(&backup); if (!import_bmp) { ALLEGRO_ERROR("Couldn't load bitmap from '%s'\n", fname); return NULL; } /* We assume a single unicode range, starting at the space * character. */ range[0] = 32; range[1] = 32 + bitmap_font_count(import_bmp) - 1; f = al_grab_font_from_bitmap(import_bmp, 1, range); al_destroy_bitmap(import_bmp); return f; } /* Function: al_load_bitmap_font */ ALLEGRO_FONT *al_load_bitmap_font(const char *fname) { int flags = 0; /* For backwards compatibility with the 5.0 branch. */ if (al_get_new_bitmap_flags() & ALLEGRO_NO_PREMULTIPLIED_ALPHA) { flags |= ALLEGRO_NO_PREMULTIPLIED_ALPHA; } return _al_load_bitmap_font(fname, 0, flags); } /* Function: al_load_bitmap_font_flags */ ALLEGRO_FONT *al_load_bitmap_font_flags(const char *fname, int flags) { return _al_load_bitmap_font(fname, 0, flags); } /* Function: al_grab_font_from_bitmap */ ALLEGRO_FONT *al_grab_font_from_bitmap(ALLEGRO_BITMAP *bmp, int ranges_n, const int ranges[]) { ALLEGRO_FONT *f; ALLEGRO_FONT_COLOR_DATA *cf, *prev = NULL; ALLEGRO_STATE backup; int i; ALLEGRO_COLOR mask = al_get_pixel(bmp, 0, 0); ALLEGRO_BITMAP *glyphs = NULL, *unmasked = NULL; int import_x = 0, import_y = 0; ALLEGRO_LOCKED_REGION *lock = NULL; int w, h; ASSERT(bmp); w = al_get_bitmap_width(bmp); h = al_get_bitmap_height(bmp); f = al_calloc(1, sizeof *f); f->vtable = &_al_font_vtable_color; al_store_state(&backup, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA); unmasked = al_clone_bitmap(bmp); /* At least with OpenGL, texture pixels at the very border of * the glyph are sometimes partly sampled from the yellow mask * pixels. To work around this, we replace the mask with full * transparency. * And we best do it on a memory copy to avoid loading back a texture. */ al_convert_mask_to_alpha(unmasked, mask); al_restore_state(&backup); al_store_state(&backup, ALLEGRO_STATE_BITMAP | ALLEGRO_STATE_BLENDER); // Use the users preferred format, so don't set this below! //al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA); for (i = 0; i < ranges_n; i++) { int first = ranges[i * 2]; int last = ranges[i * 2 + 1]; int n = 1 + last - first; cf = al_calloc(1, sizeof(ALLEGRO_FONT_COLOR_DATA)); if (prev) prev->next = cf; else f->data = cf; cf->bitmaps = al_malloc(sizeof(ALLEGRO_BITMAP*) * n); cf->bitmaps[0] = NULL; if (!glyphs) { glyphs = al_clone_bitmap(unmasked); if (!glyphs) { ALLEGRO_ERROR("Unable clone bitmap.\n"); goto cleanup_and_fail_on_error; } lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_RGBA_8888, ALLEGRO_LOCK_READONLY); } cf->glyphs = glyphs; if (import_bitmap_font_color(lock->data, lock->pitch, w, h, cf->bitmaps, cf->glyphs, n, &import_x, &import_y)) { goto cleanup_and_fail_on_error; } else { cf->begin = first; cf->end = last + 1; prev = cf; } } al_restore_state(&backup); cf = f->data; if (cf && cf->bitmaps[0]) f->height = al_get_bitmap_height(cf->bitmaps[0]); if (lock) al_unlock_bitmap(bmp); if (unmasked) al_destroy_bitmap(unmasked); f->dtor_item = _al_register_destructor(_al_dtor_list, "font", f, (void (*)(void *))al_destroy_font); return f; cleanup_and_fail_on_error: if (lock) al_unlock_bitmap(bmp); al_restore_state(&backup); al_destroy_font(f); if (unmasked) al_destroy_bitmap(unmasked); return NULL; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/font/stdfont.c000066400000000000000000000570771473414355200175430ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * A builtin bitmap font using no external data. * * By Dennis Busch. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" ALLEGRO_DEBUG_CHANNEL("font") /* Adapted from Allegro4 "font.c" (removed unnecessary height and width * information and packed them all into a single continuous array). * Contains the following ranges * * ASCII (0x0020 to 0x007F) * Latin-1 (0x00A1 to 0x00FF) * Extended-A (0x0100 to 0x017F) * Euro (0x20AC) */ static const unsigned char builtin_rom_font_8x8[] = { /* standard ASCII characters (0x20 to 0x7F) */ /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x21 */ 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00, /* 0x22 */ 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x23 */ 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, /* 0x24 */ 0x18, 0x7E, 0xC0, 0x7C, 0x06, 0xFC, 0x18, 0x00, /* 0x25 */ 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, /* 0x26 */ 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, /* 0x27 */ 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28 */ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, /* 0x29 */ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, /* 0x2A */ 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, /* 0x2B */ 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, /* 0x2C */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, /* 0x2D */ 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, /* 0x2E */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, /* 0x2F */ 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, /* 0x30 */ 0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xC6, 0x7C, 0x00, /* 0x31 */ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, /* 0x32 */ 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00, /* 0x33 */ 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00, /* 0x34 */ 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, /* 0x35 */ 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00, /* 0x36 */ 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00, /* 0x37 */ 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, /* 0x38 */ 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00, /* 0x39 */ 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00, /* 0x3A */ 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, /* 0x3B */ 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, /* 0x3C */ 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, /* 0x3D */ 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, /* 0x3E */ 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, /* 0x3F */ 0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, /* 0x40 */ 0x7C, 0xC6, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, /* 0x41 */ 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00, /* 0x42 */ 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, /* 0x43 */ 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, /* 0x44 */ 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, /* 0x45 */ 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, /* 0x46 */ 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, /* 0x47 */ 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3A, 0x00, /* 0x48 */ 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, /* 0x49 */ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x4A */ 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, /* 0x4B */ 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, /* 0x4C */ 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, /* 0x4D */ 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, /* 0x4E */ 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, /* 0x4F */ 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, /* 0x50 */ 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, /* 0x51 */ 0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0x7C, 0x0E, 0x00, /* 0x52 */ 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00, /* 0x53 */ 0x7C, 0xC6, 0xE0, 0x78, 0x0E, 0xC6, 0x7C, 0x00, /* 0x54 */ 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x55 */ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00, /* 0x56 */ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, /* 0x57 */ 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00, /* 0x58 */ 0xC6, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0xC6, 0x00, /* 0x59 */ 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00, /* 0x5A */ 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, /* 0x5B */ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, /* 0x5C */ 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, /* 0x5D */ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, /* 0x5E */ 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0x5F */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, /* 0x60 */ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x61 */ 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, /* 0x62 */ 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00, /* 0x63 */ 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, /* 0x64 */ 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00, /* 0x65 */ 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, /* 0x66 */ 0x38, 0x6C, 0x64, 0xF0, 0x60, 0x60, 0xF0, 0x00, /* 0x67 */ 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, /* 0x68 */ 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, /* 0x69 */ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x6A */ 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, /* 0x6B */ 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, /* 0x6C */ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x6D */ 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xD6, 0x00, /* 0x6E */ 0x00, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, /* 0x6F */ 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, /* 0x70 */ 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, /* 0x71 */ 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, /* 0x72 */ 0x00, 0x00, 0xDC, 0x76, 0x62, 0x60, 0xF0, 0x00, /* 0x73 */ 0x00, 0x00, 0x7C, 0xC0, 0x70, 0x1C, 0xF8, 0x00, /* 0x74 */ 0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00, /* 0x75 */ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, /* 0x76 */ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, /* 0x77 */ 0x00, 0x00, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00, /* 0x78 */ 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, /* 0x79 */ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, /* 0x7A */ 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, /* 0x7B */ 0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00, /* 0x7C */ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, /* 0x7D */ 0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00, /* 0x7E */ 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7F */ 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00, /* ANSI Latin-1 characters (0xA1 to 0xFF) */ /* 0xA1 */ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, /* 0xA2 */ 0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18, /* 0xA3 */ 0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00, /* 0xA4 */ 0x00, 0xC6, 0x7C, 0xC6, 0xC6, 0x7C, 0xC6, 0x00, /* 0xA5 */ 0xCC, 0xCC, 0x78, 0xFC, 0x30, 0xFC, 0x30, 0x30, /* 0xA6 */ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, /* 0xA7 */ 0x3E, 0x61, 0x3C, 0x66, 0x66, 0x3C, 0x86, 0x7C, /* 0xA8 */ 0x00, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA9 */ 0x7E, 0x81, 0x9D, 0xA1, 0xA1, 0x9D, 0x81, 0x7E, /* 0xAA */ 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00, /* 0xAB */ 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00, /* 0xAC */ 0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00, /* 0xAD */ 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, /* 0xAE */ 0x7E, 0x81, 0xB9, 0xA5, 0xB9, 0xA5, 0x81, 0x7E, /* 0xAF */ 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0 */ 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, /* 0xB1 */ 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00, /* 0xB2 */ 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00, /* 0xB3 */ 0x78, 0x0C, 0x38, 0x0C, 0x78, 0x00, 0x00, 0x00, /* 0xB4 */ 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB5 */ 0x00, 0x00, 0x33, 0x33, 0x66, 0x7E, 0xC0, 0x80, /* 0xB6 */ 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, /* 0xB7 */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* 0xB8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0x38, /* 0xB9 */ 0x18, 0x38, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, /* 0xBA */ 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00, /* 0xBB */ 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00, /* 0xBC */ 0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6F, 0xCF, 0x03, /* 0xBD */ 0xC3, 0xC6, 0xCC, 0xDE, 0x33, 0x66, 0xCC, 0x0F, /* 0xBE */ 0xE1, 0x32, 0xE4, 0x3A, 0xF6, 0x2A, 0x5F, 0x86, /* 0xBF */ 0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00, /* 0xC0 */ 0x18, 0x0C, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x00, /* 0xC1 */ 0x30, 0x60, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x00, /* 0xC2 */ 0x7C, 0x82, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x00, /* 0xC3 */ 0x76, 0xDC, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x00, /* 0xC4 */ 0xC6, 0x00, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x00, /* 0xC5 */ 0x10, 0x28, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x00, /* 0xC6 */ 0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00, /* 0xC7 */ 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78, /* 0xC8 */ 0x30, 0x18, 0xFE, 0xC0, 0xFC, 0xC0, 0xFE, 0x00, /* 0xC9 */ 0x0C, 0x18, 0xFE, 0xC0, 0xFC, 0xC0, 0xFE, 0x00, /* 0xCA */ 0x7C, 0x82, 0xFE, 0xC0, 0xFC, 0xC0, 0xFE, 0x00, /* 0xCB */ 0xC6, 0x00, 0xFE, 0xC0, 0xFC, 0xC0, 0xFE, 0x00, /* 0xCC */ 0x30, 0x18, 0x3C, 0x18, 0x18, 0x18, 0x3C, 0x00, /* 0xCD */ 0x0C, 0x18, 0x3C, 0x18, 0x18, 0x18, 0x3C, 0x00, /* 0xCE */ 0x3C, 0x42, 0x3C, 0x18, 0x18, 0x18, 0x3C, 0x00, /* 0xCF */ 0x66, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x3C, 0x00, /* 0xD0 */ 0xF8, 0x6C, 0x66, 0xF6, 0x66, 0x6C, 0xF8, 0x00, /* 0xD1 */ 0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00, /* 0xD2 */ 0x30, 0x18, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0xD3 */ 0x18, 0x30, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0xD4 */ 0x7C, 0x82, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0xD5 */ 0x76, 0xDC, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0xD6 */ 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0xD7 */ 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, 0x00, /* 0xD8 */ 0x3A, 0x6C, 0xCE, 0xD6, 0xE6, 0x6C, 0xB8, 0x00, /* 0xD9 */ 0x60, 0x30, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0xDA */ 0x18, 0x30, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0xDB */ 0x7C, 0x82, 0x00, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0xDC */ 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0xDD */ 0x0C, 0x18, 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x00, /* 0xDE */ 0xE0, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0xF0, /* 0xDF */ 0x78, 0xCC, 0xCC, 0xD8, 0xCC, 0xC6, 0xCC, 0x00, /* 0xE0 */ 0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, /* 0xE1 */ 0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, /* 0xE2 */ 0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00, /* 0xE3 */ 0x76, 0xDC, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, /* 0xE4 */ 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, /* 0xE5 */ 0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, /* 0xE6 */ 0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00, /* 0xE7 */ 0x00, 0x00, 0x78, 0xC0, 0xC0, 0x78, 0x0C, 0x38, /* 0xE8 */ 0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, /* 0xE9 */ 0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, /* 0xEA */ 0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, /* 0xEB */ 0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, /* 0xEC */ 0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0xED */ 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0xEE */ 0x7C, 0xC6, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, /* 0xEF */ 0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0xF0 */ 0x08, 0x3C, 0x08, 0x7C, 0xCC, 0xCC, 0x78, 0x00, /* 0xF1 */ 0x00, 0xF8, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0x00, /* 0xF2 */ 0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, /* 0xF3 */ 0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, /* 0xF4 */ 0x78, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, /* 0xF5 */ 0x76, 0xDC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, /* 0xF6 */ 0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, /* 0xF7 */ 0x30, 0x30, 0x00, 0xFC, 0x00, 0x30, 0x30, 0x00, /* 0xF8 */ 0x00, 0x02, 0x7C, 0xCE, 0xD6, 0xE6, 0x7C, 0x80, /* 0xF9 */ 0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, /* 0xFA */ 0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, /* 0xFB */ 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, /* 0xFC */ 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, /* 0xFD */ 0x18, 0x30, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, /* 0xFE */ 0xF0, 0x60, 0x7C, 0x66, 0x7C, 0x60, 0xF0, 0x00, /* 0xFF */ 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, /* Extended-A characters (0x100 to 0x17F) */ /* 0x100 */ 0xFE, 0x00, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x00, /* 0x101 */ 0xFC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, /* 0x102 */ 0x82, 0x7C, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x00, /* 0x103 */ 0xC3, 0x7E, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, /* 0x104 */ 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x1C, 0x30, 0x1E, /* 0x105 */ 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x30, 0x1C, /* 0x106 */ 0x0C, 0x18, 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x00, /* 0x107 */ 0x1C, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, /* 0x108 */ 0x7C, 0x82, 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x00, /* 0x109 */ 0x7E, 0xC3, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, /* 0x10A */ 0x10, 0x00, 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x00, /* 0x10B */ 0x10, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, /* 0x10C */ 0x6C, 0x38, 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x00, /* 0x10D */ 0x6C, 0x38, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, /* 0x10E */ 0x6C, 0x38, 0xF8, 0x66, 0x66, 0x66, 0xF8, 0x00, /* 0x10F */ 0xBC, 0x4C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00, /* 0x110 */ 0xF8, 0x6C, 0x66, 0xF6, 0x66, 0x6C, 0xF8, 0x00, /* 0x111 */ 0x08, 0x3C, 0x08, 0x7C, 0xCC, 0xCC, 0x78, 0x00, /* 0x112 */ 0xFE, 0x00, 0xFE, 0xC0, 0xFC, 0xC0, 0xFE, 0x00, /* 0x113 */ 0xFC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, /* 0x114 */ 0x6C, 0x38, 0xFE, 0xC0, 0xFC, 0xC0, 0xFE, 0x00, /* 0x115 */ 0x6C, 0x38, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, /* 0x116 */ 0x10, 0x00, 0xFE, 0xC0, 0xFC, 0xC0, 0xFE, 0x00, /* 0x117 */ 0x10, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, /* 0x118 */ 0xFE, 0xC0, 0xFC, 0xC0, 0xFE, 0x18, 0x30, 0x1C, /* 0x119 */ 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x38, 0x0C, /* 0x11A */ 0x6C, 0x38, 0xFE, 0xC0, 0xFC, 0xC0, 0xFE, 0x00, /* 0x11B */ 0x6C, 0x38, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, /* 0x11C */ 0x7C, 0x82, 0x7C, 0xC6, 0xC0, 0xCE, 0x7E, 0x00, /* 0x11D */ 0x7E, 0xC3, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, /* 0x11E */ 0x82, 0x7C, 0x7C, 0xC6, 0xC0, 0xCE, 0x7E, 0x00, /* 0x11F */ 0xC3, 0x7E, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, /* 0x120 */ 0x10, 0x00, 0x7C, 0xC6, 0xC0, 0xCE, 0x7E, 0x00, /* 0x121 */ 0x10, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, /* 0x122 */ 0x7C, 0xC6, 0xC0, 0xCE, 0x7E, 0x18, 0x0C, 0x78, /* 0x123 */ 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, 0x0C, 0x38, /* 0x124 */ 0x78, 0x84, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00, /* 0x125 */ 0xEE, 0x7B, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, /* 0x126 */ 0xCC, 0xFE, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, /* 0x127 */ 0xE0, 0xFE, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, /* 0x128 */ 0x76, 0xDC, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x129 */ 0x76, 0xDC, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x12A */ 0x78, 0x00, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x12B */ 0x78, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x12C */ 0x84, 0x78, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x12D */ 0xC6, 0x7C, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x12E */ 0x78, 0x30, 0x30, 0x30, 0x78, 0x18, 0x30, 0x1E, /* 0x12F */ 0x30, 0x00, 0x70, 0x30, 0x30, 0x78, 0x30, 0x1C, /* 0x130 */ 0x10, 0x00, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x131 */ 0x00, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x132 */ 0xEE, 0x42, 0x42, 0x42, 0x52, 0x52, 0xEC, 0x00, /* 0x133 */ 0x42, 0x00, 0xC6, 0x42, 0x42, 0x42, 0xE2, 0x0C, /* 0x134 */ 0x7C, 0x82, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, /* 0x135 */ 0x7C, 0xC6, 0x1C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, /* 0x136 */ 0xE6, 0x6C, 0x78, 0x6C, 0xE6, 0x30, 0x18, 0xF0, /* 0x137 */ 0xE0, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x30, 0xE0, /* 0x138 */ 0x00, 0x00, 0xE6, 0x6C, 0x78, 0x6C, 0xE6, 0x00, /* 0x139 */ 0xF3, 0x66, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, /* 0x13A */ 0x73, 0x36, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x13B */ 0xF0, 0x60, 0x62, 0x66, 0xFE, 0x18, 0x0C, 0x78, /* 0x13C */ 0x70, 0x30, 0x30, 0x30, 0x30, 0x78, 0x0C, 0x38, /* 0x13D */ 0xF5, 0x66, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, /* 0x13E */ 0x75, 0x36, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x13F */ 0xF0, 0x60, 0x64, 0x60, 0x62, 0x66, 0xFE, 0x00, /* 0x140 */ 0x70, 0x30, 0x30, 0x32, 0x30, 0x30, 0x78, 0x00, /* 0x141 */ 0xF0, 0x60, 0x70, 0x60, 0xE2, 0x66, 0xFE, 0x00, /* 0x142 */ 0x70, 0x30, 0x38, 0x30, 0x70, 0x30, 0x78, 0x00, /* 0x143 */ 0x0C, 0x18, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00, /* 0x144 */ 0x1C, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, /* 0x145 */ 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x30, 0x18, 0xF0, /* 0x146 */ 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0x30, 0xE0, /* 0x147 */ 0x6C, 0x38, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00, /* 0x148 */ 0x6C, 0x38, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, /* 0x149 */ 0xC0, 0x80, 0x5C, 0x66, 0x66, 0x66, 0x66, 0x00, /* 0x14A */ 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x0C, 0x38, /* 0x14B */ 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0x0C, 0x38, /* 0x14C */ 0xFE, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0x14D */ 0x00, 0xFC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, /* 0x14E */ 0x6C, 0x38, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0x14F */ 0x6C, 0x38, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, /* 0x150 */ 0x36, 0x6C, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0x151 */ 0x36, 0x6C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, /* 0x152 */ 0x7E, 0xDA, 0x88, 0x8C, 0x88, 0xDA, 0x7E, 0x00, /* 0x153 */ 0x00, 0x00, 0x6C, 0x92, 0x9E, 0x90, 0x6C, 0x00, /* 0x154 */ 0x0C, 0x18, 0xFC, 0x66, 0x7C, 0x6C, 0xE6, 0x00, /* 0x155 */ 0x0C, 0x18, 0xDC, 0x76, 0x62, 0x60, 0xF0, 0x00, /* 0x156 */ 0xFC, 0x66, 0x7C, 0x6C, 0xE6, 0x30, 0x18, 0xF0, /* 0x157 */ 0x00, 0xDC, 0x76, 0x62, 0x60, 0xF0, 0x30, 0xE0, /* 0x158 */ 0x6C, 0x38, 0xFC, 0x66, 0x7C, 0x6C, 0xE6, 0x00, /* 0x159 */ 0x6C, 0x38, 0xDC, 0x76, 0x62, 0x60, 0xF0, 0x00, /* 0x15A */ 0x0C, 0x18, 0x7C, 0xE0, 0x78, 0x0E, 0x7C, 0x00, /* 0x15B */ 0x0C, 0x18, 0x7C, 0xC0, 0x70, 0x1C, 0xF8, 0x00, /* 0x15C */ 0x7C, 0x82, 0x7C, 0xE0, 0x78, 0x0E, 0x7C, 0x00, /* 0x15D */ 0x7C, 0xC6, 0x7C, 0xC0, 0x70, 0x1C, 0xF8, 0x00, /* 0x15E */ 0x7C, 0xE0, 0x78, 0x0E, 0x7C, 0x18, 0x0C, 0x78, /* 0x15F */ 0x00, 0x7C, 0xC0, 0x70, 0x1C, 0xF8, 0x0C, 0x38, /* 0x160 */ 0x6C, 0x38, 0x7C, 0xE0, 0x78, 0x0E, 0x7C, 0x00, /* 0x161 */ 0x6C, 0x38, 0x7C, 0xC0, 0x70, 0x1C, 0xF8, 0x00, /* 0x162 */ 0xFC, 0x30, 0x30, 0x30, 0x78, 0x18, 0x0C, 0x38, /* 0x163 */ 0x10, 0x30, 0xFC, 0x30, 0x34, 0x18, 0x0C, 0x38, /* 0x164 */ 0x6C, 0x38, 0xFC, 0x30, 0x30, 0x30, 0x78, 0x00, /* 0x165 */ 0x12, 0x3A, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00, /* 0x166 */ 0xFC, 0xB4, 0x30, 0x30, 0xFC, 0x30, 0x78, 0x00, /* 0x167 */ 0x10, 0x30, 0xFC, 0x30, 0xFC, 0x34, 0x18, 0x00, /* 0x168 */ 0x76, 0xDC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0x169 */ 0x76, 0xDC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, /* 0x16A */ 0xFE, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0x16B */ 0x00, 0xFE, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, /* 0x16C */ 0x6C, 0x38, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0x16D */ 0x6C, 0x38, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, /* 0x16E */ 0x38, 0x6C, 0xFE, 0xD6, 0xC6, 0xC6, 0x7C, 0x00, /* 0x16F */ 0x38, 0x6C, 0x38, 0xDC, 0xCC, 0xCC, 0x7E, 0x00, /* 0x170 */ 0x36, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, /* 0x171 */ 0x36, 0x6C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, /* 0x172 */ 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x30, 0x60, 0x3C, /* 0x173 */ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x18, 0x0E, /* 0x174 */ 0x7C, 0x82, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00, /* 0x175 */ 0x7C, 0xC6, 0x00, 0xC6, 0xD6, 0xFE, 0x6C, 0x00, /* 0x176 */ 0x7C, 0x82, 0xCC, 0xCC, 0x78, 0x30, 0x78, 0x00, /* 0x177 */ 0x7C, 0xC6, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, /* 0x178 */ 0xCC, 0x00, 0xCC, 0xCC, 0x78, 0x30, 0x78, 0x00, /* 0x179 */ 0x0C, 0x18, 0xFE, 0x8C, 0x18, 0x32, 0xFE, 0x00, /* 0x17A */ 0x0C, 0x18, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, /* 0x17B */ 0x10, 0x00, 0xFE, 0x8C, 0x18, 0x32, 0xFE, 0x00, /* 0x17C */ 0x10, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, /* 0x17D */ 0x6C, 0x38, 0xFE, 0x8C, 0x18, 0x32, 0xFE, 0x00, /* 0x17E */ 0x6C, 0x38, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, /* 0x17F */ 0x38, 0x6C, 0x64, 0xE0, 0x60, 0x60, 0xE0, 0x00, /* euro character (0x20AC) */ /* 0x20AC*/ 0x3C, 0x62, 0xF8, 0x60, 0xF8, 0x62, 0x3C, 0x00 }; /* range definitions for the above binary data */ static const int builtin_rom_font_8x8_ranges[] = { 0x00000020, 0x0000007F, 0x000000A1, 0x000000FF, 0x00000100, 0x0000017F, 0x000020AC, 0x000020AC }; static const int builtin_rom_font_8x8_ranges_count = (sizeof(builtin_rom_font_8x8_ranges) / sizeof(int)) / 2; static void put_pixel_abgr8888_le(ALLEGRO_LOCKED_REGION *region, int x, int y, uint32_t pixel) { uint32_t *target = (uint32_t *) ((uint8_t *)region->data + y * region->pitch + x * region->pixel_size); *target = pixel; } /* decodes the binary data and creates a bitmap containing the glyps from it */ static ALLEGRO_BITMAP *create_builtin_font_sheet(void) { const int glyph_count = sizeof(builtin_rom_font_8x8) / 8; const int glyphs_per_row = 32; const int alloc_rows = (glyph_count + glyphs_per_row - 1) / glyphs_per_row; ALLEGRO_STATE state; ALLEGRO_BITMAP *bmp; ALLEGRO_LOCKED_REGION *lr; int i, j, k; al_store_state(&state, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS | ALLEGRO_STATE_TARGET_BITMAP); /* putting pixels is much faster on a memory bitmap */ al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA); /* create bitmap onto which to render the glyphs */ bmp = al_create_bitmap(glyphs_per_row * 8 + glyphs_per_row + 1, alloc_rows * 8 + alloc_rows + 1); if (bmp) { al_set_target_bitmap(bmp); al_clear_to_color(al_map_rgba(255, 255, 0, 255)); lr = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_READWRITE); /* decode and render glyph pixels */ for (i = 0; i < glyph_count; i++) { /* for each of the 8 lines per character */ for (j = 0; j < 8; j++) { /* decode and draw each of the 8 pixels of the current line */ for (k = 0; k < 8; k++) { bool set = (builtin_rom_font_8x8[i * 8 + j] >> (7 - k)) & 0x01; put_pixel_abgr8888_le(lr, (i % glyphs_per_row) * 9 + 1 + k, (i / glyphs_per_row) * 9 + 1 + j, set ? 0xFFFFFFFF : 0x00000000); } } } al_unlock_bitmap(bmp); } else { ALLEGRO_ERROR("Unable to create bitmap.\n"); } al_restore_state(&state); return bmp; } /* Function: al_create_builtin_font */ ALLEGRO_FONT *al_create_builtin_font(void) { ALLEGRO_BITMAP *bmp; ALLEGRO_FONT *font; bmp = create_builtin_font_sheet(); if (!bmp) return NULL; font = al_grab_font_from_bitmap(bmp, builtin_rom_font_8x8_ranges_count, builtin_rom_font_8x8_ranges); al_destroy_bitmap(bmp); return font; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/font/text.c000066400000000000000000000425321473414355200170340ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Text drawing routines. * * By Shawn Hargreaves. * * textout_justify() by Seymour Shlien. * * Laurence Withers added the textout_ex() function family. * * See readme.txt for copyright information. */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_font.h" #include "allegro5/internal/aintern_system.h" /* If you call this, you're probably making a mistake. */ /* #define strlen(s) __are_you_sure__ */ /* Removed the above define since some compilers seem to use some * preprocessor magic when calling strcmp() that inserts a call to strlen. * There might be a better way to do this. */ /* Text usually looks best when aligned to pixels - * but if x is 0.5 it may very well end up at an integer * position if the current transformation scales by 2 or * translated x by 0.5. So we simply apply the transformation, * round to nearest integer, and backtransform that. */ static void align_to_integer_pixel_inner( ALLEGRO_TRANSFORM const *fwd, ALLEGRO_TRANSFORM const *inv, float *x, float *y) { al_transform_coordinates(fwd, x, y); *x = floorf(*x + 0.5f); *y = floorf(*y + 0.5f); al_transform_coordinates(inv, x, y); } static void align_to_integer_pixel(float *x, float *y) { ALLEGRO_TRANSFORM const *fwd; ALLEGRO_TRANSFORM inv; fwd = al_get_current_transform(); al_copy_transform(&inv, fwd); al_invert_transform(&inv); align_to_integer_pixel_inner(fwd, &inv, x, y); } /* Function: al_draw_ustr */ void al_draw_ustr(const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int flags, const ALLEGRO_USTR *ustr) { ASSERT(font); ASSERT(ustr); if (flags & ALLEGRO_ALIGN_CENTRE) { /* Use integer division to avoid introducing a fractional * component to an integer x value. */ x -= font->vtable->text_length(font, ustr) / 2; } else if (flags & ALLEGRO_ALIGN_RIGHT) { x -= font->vtable->text_length(font, ustr); } if (flags & ALLEGRO_ALIGN_INTEGER) align_to_integer_pixel(&x, &y); font->vtable->render(font, color, ustr, x, y); } /* Function: al_draw_text */ void al_draw_text(const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int flags, char const *text) { ALLEGRO_USTR_INFO info; ASSERT(text); al_draw_ustr(font, color, x, y, flags, al_ref_cstr(&info, text)); } /* Function: al_draw_justified_ustr */ void al_draw_justified_ustr(const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x1, float x2, float y, float diff, int flags, const ALLEGRO_USTR *ustr) { const char *whitespace = " \t\n\r"; ALLEGRO_USTR_INFO word_info; const ALLEGRO_USTR *word; int pos1, pos2; int minlen; int num_words; int space; float fleft, finc; int advance; ALLEGRO_TRANSFORM const *fwd = NULL; ALLEGRO_TRANSFORM inv; ASSERT(font); /* count words and measure min length (without spaces) */ num_words = 0; minlen = 0; pos1 = 0; for (;;) { pos1 = al_ustr_find_cset_cstr(ustr, pos1, whitespace); if (pos1 == -1) break; pos2 = al_ustr_find_set_cstr(ustr, pos1, whitespace); if (pos2 == -1) pos2 = al_ustr_size(ustr); word = al_ref_ustr(&word_info, ustr, pos1, pos2); minlen += font->vtable->text_length(font, word); num_words++; pos1 = pos2; } /* amount of room for space between words */ space = x2 - x1 - minlen; if ((space <= 0) || (space > diff) || (num_words < 2)) { /* can't justify */ if (flags & ALLEGRO_ALIGN_INTEGER) align_to_integer_pixel(&x1, &y); font->vtable->render(font, color, ustr, x1, y); return; } /* distribute space left evenly between words */ fleft = (float)x1; finc = (float)space / (float)(num_words-1); pos1 = 0; if (flags & ALLEGRO_ALIGN_INTEGER) { fwd = al_get_current_transform(); al_copy_transform(&inv, fwd); al_invert_transform(&inv); } for (;;) { pos1 = al_ustr_find_cset_cstr(ustr, pos1, whitespace); if (pos1 == -1) break; pos2 = al_ustr_find_set_cstr(ustr, pos1, whitespace); if (pos2 == -1) pos2 = al_ustr_size(ustr); word = al_ref_ustr(&word_info, ustr, pos1, pos2); if (flags & ALLEGRO_ALIGN_INTEGER) { float drawx = fleft; float drawy = y; align_to_integer_pixel_inner(fwd, &inv, &drawx, &drawy); advance = font->vtable->render(font, color, word, drawx, drawy); } else { advance = font->vtable->render(font, color, word, fleft, y); } fleft += advance + finc; pos1 = pos2; } } /* Function: al_draw_justified_text */ void al_draw_justified_text(const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x1, float x2, float y, float diff, int flags, const char *text) { ALLEGRO_USTR_INFO info; ASSERT(text); al_draw_justified_ustr(font, color, x1, x2, y, diff, flags, al_ref_cstr(&info, text)); } /* Function: al_draw_textf */ void al_draw_textf(const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int flags, const char *format, ...) { ALLEGRO_USTR *buf; va_list ap; const char *s; ASSERT(font); ASSERT(format); /* Fast path for common case. */ if (0 == strcmp(format, "%s")) { va_start(ap, format); s = va_arg(ap, const char *); al_draw_text(font, color, x, y, flags, s); va_end(ap); return; } va_start(ap, format); buf = al_ustr_new(""); al_ustr_vappendf(buf, format, ap); va_end(ap); al_draw_ustr(font, color, x, y, flags, buf); al_ustr_free(buf); } /* Function: al_draw_justified_textf */ void al_draw_justified_textf(const ALLEGRO_FONT *f, ALLEGRO_COLOR color, float x1, float x2, float y, float diff, int flags, const char *format, ...) { ALLEGRO_USTR *buf; va_list ap; ASSERT(f); ASSERT(format); va_start(ap, format); buf = al_ustr_new(""); al_ustr_vappendf(buf, format, ap); va_end(ap); al_draw_justified_ustr(f, color, x1, x2, y, diff, flags, buf); al_ustr_free(buf); } /* Function: al_get_ustr_width */ int al_get_ustr_width(const ALLEGRO_FONT *f, ALLEGRO_USTR const *ustr) { ASSERT(f); ASSERT(ustr); return f->vtable->text_length(f, ustr); } /* Function: al_get_text_width */ int al_get_text_width(const ALLEGRO_FONT *f, const char *str) { ALLEGRO_USTR_INFO str_info; const ALLEGRO_USTR *ustr; ASSERT(f); ASSERT(str); ustr = al_ref_cstr(&str_info, str); return f->vtable->text_length(f, ustr); } /* Function: al_get_font_line_height */ int al_get_font_line_height(const ALLEGRO_FONT *f) { ASSERT(f); return f->vtable->font_height(f); } /* Function: al_get_font_ascent */ int al_get_font_ascent(const ALLEGRO_FONT *f) { ASSERT(f); return f->vtable->font_ascent(f); } /* Function: al_get_font_descent */ int al_get_font_descent(const ALLEGRO_FONT *f) { ASSERT(f); return f->vtable->font_descent(f); } /* Function: al_get_ustr_dimensions */ void al_get_ustr_dimensions(const ALLEGRO_FONT *f, ALLEGRO_USTR const *ustr, int *bbx, int *bby, int *bbw, int *bbh) { ASSERT(f); ASSERT(ustr); f->vtable->get_text_dimensions(f, ustr, bbx, bby, bbw, bbh); } /* Function: al_get_text_dimensions */ void al_get_text_dimensions(const ALLEGRO_FONT *f, char const *text, int *bbx, int *bby, int *bbw, int *bbh) { ALLEGRO_USTR_INFO info; ASSERT(f); ASSERT(text); f->vtable->get_text_dimensions(f, al_ref_cstr(&info, text), bbx, bby, bbw, bbh); } /* Function: al_destroy_font */ void al_destroy_font(ALLEGRO_FONT *f) { if (!f) return; _al_unregister_destructor(_al_dtor_list, f->dtor_item); f->vtable->destroy(f); } /* Function: al_get_font_ranges */ int al_get_font_ranges(ALLEGRO_FONT *f, int ranges_count, int *ranges) { return f->vtable->get_font_ranges(f, ranges_count, ranges); } /* Function: al_draw_glyph */ void al_draw_glyph(const ALLEGRO_FONT *f, ALLEGRO_COLOR color, float x, float y, int codepoint) { f->vtable->render_char(f, color, codepoint, x, y); }; /* Function: al_get_glyph_width */ int al_get_glyph_width(const ALLEGRO_FONT *f, int codepoint) { return f->vtable->char_length(f, codepoint); } /* Function: al_get_glyph_dimensions */ bool al_get_glyph_dimensions(const ALLEGRO_FONT *f, int codepoint, int *bbx, int *bby, int *bbw, int *bbh) { return f->vtable->get_glyph_dimensions(f, codepoint, bbx, bby, bbw, bbh); } /* Function: al_get_glyph_advance */ int al_get_glyph_advance(const ALLEGRO_FONT *f, int codepoint1, int codepoint2) { return f->vtable->get_glyph_advance(f, codepoint1, codepoint2); } /* Function: al_get_glyph */ bool al_get_glyph(const ALLEGRO_FONT *f, int prev_codepoint, int codepoint, ALLEGRO_GLYPH *glyph) { return f->vtable->get_glyph(f, prev_codepoint, codepoint, glyph); }; /* This helper function helps splitting an ustr in several delimited parts. * It returns an ustr that refers to the next part of the string that * is delimited by the delimiters in delimiter. * Returns NULL at the end of the string. * Pos is updated to byte index of character after the delimiter or * to the end of the string. */ static const ALLEGRO_USTR *ustr_split_next(const ALLEGRO_USTR *ustr, ALLEGRO_USTR_INFO *info, int *pos, const char *delimiter) { const ALLEGRO_USTR *result; int end, size; size = al_ustr_size(ustr); if (*pos >= size) { return NULL; } end = al_ustr_find_set_cstr(ustr, *pos, delimiter); if (end == -1) end = size; result = al_ref_ustr(info, ustr, *pos, end); /* Set pos to character AFTER delimiter */ al_ustr_next(ustr, &end); (*pos) = end; return result; } /* This returns the next "soft" line of text from ustr * that will fit in max_with using the font font, starting at pos *pos. * These are "soft" lines because they are broken up if needed at a space * or tab character. * This function updates pos if needed, and returns the next "soft" line, * or NULL if no more soft lines. * The soft line will not include the trailing space where the * line was split, but pos will be set to point to after that trailing * space so iteration can continue easily. */ static const ALLEGRO_USTR *get_next_soft_line(const ALLEGRO_USTR *ustr, ALLEGRO_USTR_INFO *info, int *pos, const ALLEGRO_FONT *font, float max_width) { const ALLEGRO_USTR *result = NULL; const char *whitespace = " \t"; int old_end = 0; int end = 0; int size = al_ustr_size(ustr); bool first_word = true; if (*pos >= size) { return NULL; } end = *pos; old_end = end; do { /* On to the next word. */ end = al_ustr_find_set_cstr(ustr, end, whitespace); if (end < 0) end = size; /* Reference to the line that is being built. */ result = al_ref_ustr(info, ustr, *pos, end); /* Check if the line is too long. If it is, return a soft line. */ if (al_get_ustr_width(font, result) > max_width) { /* Corner case: a single word may not even fit the line. * In that case, return the word/line anyway as the "soft line", * the user can set a clip rectangle to cut it. */ if (first_word) { /* Set pos to character AFTER end to allow easy iteration. */ al_ustr_next(ustr, &end); *pos = end; return result; } else { /* Not first word, return old end position without the new word */ result = al_ref_ustr(info, ustr, *pos, old_end); /* Set pos to character AFTER end to allow easy iteration. */ al_ustr_next(ustr, &old_end); *pos = old_end; return result; } } first_word = false; old_end = end; /* Skip the character at end which normally is whitespace. */ al_ustr_next(ustr, &end); } while (end < size); /* If we get here the whole ustr will fit.*/ result = al_ref_ustr(info, ustr, *pos, size); *pos = size; return result; } /* Function: al_do_multiline_ustr */ void al_do_multiline_ustr(const ALLEGRO_FONT *font, float max_width, const ALLEGRO_USTR *ustr, bool (*cb)(int line_num, const ALLEGRO_USTR * line, void *extra), void *extra) { const char *linebreak = "\n"; const ALLEGRO_USTR *hard_line, *soft_line; ALLEGRO_USTR_INFO hard_line_info, soft_line_info; int hard_line_pos = 0, soft_line_pos = 0; int line_num = 0; bool proceed; /* For every "hard" line separated by a newline character... */ hard_line = ustr_split_next(ustr, &hard_line_info, &hard_line_pos, linebreak); while (hard_line) { /* For every "soft" line in the "hard" line... */ soft_line_pos = 0; soft_line = get_next_soft_line(hard_line, &soft_line_info, &soft_line_pos, font, max_width); /* No soft line here because it's an empty hard line. */ if (!soft_line) { /* Call the callback with empty string to indicate an empty line. */ proceed = cb(line_num, al_ustr_empty_string(), extra); if (!proceed) return; line_num ++; } while(soft_line) { /* Call the callback on the next soft line. */ proceed = cb(line_num, soft_line, extra); if (!proceed) return; line_num++; soft_line = get_next_soft_line(hard_line, &soft_line_info, &soft_line_pos, font, max_width); } hard_line = ustr_split_next(ustr, &hard_line_info, &hard_line_pos, linebreak); } } /* Helper struct for al_do_multiline_text. */ typedef struct DO_MULTILINE_TEXT_EXTRA { bool (*callback)(int line_num, const char *line, int size, void *extra); void *extra; } DO_MULTILINE_TEXT_EXTRA; /* The functions do_multiline_text_cb is the helper callback * that "adapts" al_do_multiline_ustr to al_do_multiline_text. */ static bool do_multiline_text_cb(int line_num, const ALLEGRO_USTR *line, void *extra) { DO_MULTILINE_TEXT_EXTRA *s = extra; return s->callback(line_num, al_cstr(line), al_ustr_size(line), s->extra); } /* Function: al_do_multiline_text */ void al_do_multiline_text(const ALLEGRO_FONT *font, float max_width, const char *text, bool (*cb)(int line_num, const char *line, int size, void *extra), void *extra) { ALLEGRO_USTR_INFO info; DO_MULTILINE_TEXT_EXTRA extra2; ASSERT(font); ASSERT(text); extra2.callback = cb; extra2.extra = extra; al_do_multiline_ustr(font, max_width, al_ref_cstr(&info, text), do_multiline_text_cb, &extra2); } /* Helper struct for al_draw_multiline_ustr. */ typedef struct DRAW_MULTILINE_USTR_EXTRA { const ALLEGRO_FONT *font; ALLEGRO_COLOR color; float x; float y; float line_height; int flags; } DRAW_MULTILINE_USTR_EXTRA; /* The function draw_multiline_ustr_cb is the helper callback * that implements the actual drawing for al_draw_multiline_ustr. */ static bool draw_multiline_ustr_cb(int line_num, const ALLEGRO_USTR *line, void *extra) { DRAW_MULTILINE_USTR_EXTRA *s = extra; float y; y = s->y + (s->line_height * line_num); al_draw_ustr(s->font, s->color, s->x, y, s->flags, line); return true; } /* Function: al_draw_multiline_ustr */ void al_draw_multiline_ustr(const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, float max_width, float line_height, int flags, const ALLEGRO_USTR *ustr) { DRAW_MULTILINE_USTR_EXTRA extra; ASSERT(font); ASSERT(ustr); extra.font = font; extra.color = color; extra.x = x; extra.y = y; if (line_height < 1) { extra.line_height = al_get_font_line_height(font); } else { extra.line_height = line_height; } extra.flags = flags; al_do_multiline_ustr(font, max_width, ustr, draw_multiline_ustr_cb, &extra); } /* Function: al_draw_multiline_text */ void al_draw_multiline_text(const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, float max_width, float line_height, int flags, const char *text) { ALLEGRO_USTR_INFO info; ASSERT(font); ASSERT(text); al_draw_multiline_ustr(font, color, x, y, max_width, line_height, flags, al_ref_cstr(&info, text)); } /* Function: al_draw_multiline_textf */ void al_draw_multiline_textf(const ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, float max_width, float line_height, int flags, const char *format, ...) { ALLEGRO_USTR *buf; va_list ap; ASSERT(font); ASSERT(format); va_start(ap, format); buf = al_ustr_new(""); al_ustr_vappendf(buf, format, ap); va_end(ap); al_draw_multiline_ustr(font, color, x, y, max_width, line_height, flags, buf); al_ustr_free(buf); } /* Function: al_set_fallback_font */ void al_set_fallback_font(ALLEGRO_FONT *font, ALLEGRO_FONT *fallback) { font->fallback = fallback; } /* Function: al_get_fallback_font */ ALLEGRO_FONT *al_get_fallback_font(ALLEGRO_FONT *font) { return font->fallback; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/font/xml.c000066400000000000000000000055701473414355200166510ustar00rootroot00000000000000#include "allegro5/allegro.h" #include #include "xml.h" typedef struct { XmlState state; bool closing; ALLEGRO_USTR *value; int (*callback)(XmlState state, char const *value, void *u); void *u; } XmlParser; static void scalar(XmlParser *x) { x->callback(x->state, al_cstr(x->value), x->u); al_ustr_assign_cstr(x->value, ""); } static void opt_scalar(XmlParser *x) { if (al_ustr_size(x->value)) { scalar(x); } } static void discard_scalar(XmlParser *x) { al_ustr_assign_cstr(x->value, ""); } static void close_tag(XmlParser *x) { x->state = Outside; x->closing = false; } static void add_char(XmlParser *x, char c) { char s[] = {c, 0}; al_ustr_append_cstr(x->value, s); } static void create_tag(XmlParser *x) { scalar(x); } static void open_tag(XmlParser *x) { x->state = Outside; } void _al_xml_parse(ALLEGRO_FILE *f, int (*callback)(XmlState state, char const *value, void *u), void *u) { XmlParser x_; XmlParser *x = &x_; x->value = al_ustr_new(""); x->state = Outside; x->closing = false; x->callback = callback; x->u = u; while (true) { int c = al_fgetc(f); if (c < 0) { break; } if (x->state == Outside) { if (c == '<') { opt_scalar(x); x->state = ElementName; continue; } } else if (x->state == ElementName) { if (c == '/') { x->closing = true; continue; } else if (c == '>') { if (x->closing) { discard_scalar(x); close_tag(x); } else { create_tag(x); open_tag(x); } continue; } else if (isspace(c)) { create_tag(x); x->state = AttributeName; continue; } } else if (x->state == AttributeName) { if (isspace(c)) { continue; } else if (c == '/') { x->closing = true; continue; } else if (c == '?') { x->closing = true; continue; } else if (c == '>') { if (x->closing) { close_tag(x); } else { open_tag(x); } continue; } else if (c == '=') { scalar(x); x->state = AttributeStart; continue; } } else if (x->state == AttributeStart) { if (c == '"') { x->state = AttributeValue; } continue; } else if (x->state == AttributeValue) { if (c == '"') { scalar(x); x->state = AttributeName; continue; } } add_char(x, c); } al_fclose(f); al_ustr_free(x->value); } allegro5-5.2.10.1/addons/font/xml.h000066400000000000000000000003521473414355200166470ustar00rootroot00000000000000typedef enum { Outside, ElementName, AttributeName, AttributeStart, AttributeValue } XmlState; void _al_xml_parse(ALLEGRO_FILE *f, int (*callback)(XmlState state, char const *value, void *u), void *u); allegro5-5.2.10.1/addons/image/000077500000000000000000000000001473414355200160125ustar00rootroot00000000000000allegro5-5.2.10.1/addons/image/CMakeLists.txt000066400000000000000000000166321473414355200205620ustar00rootroot00000000000000option(WANT_NATIVE_IMAGE_LOADER "Enable the native platform image loader (if available)" on) set(IMAGE_SOURCES bmp.c iio.c pcx.c tga.c dds.c identify.c) set(IMAGE_INCLUDE_FILES allegro5/allegro_image.h) set_our_header_properties(${IMAGE_INCLUDE_FILES}) # Accumulate these. set(IMAGE_LIBRARIES) set(IMAGE_DEFINES) set(IMAGE_CONFIGURATION_SUMMARY "") function(image_summary msg yesno) if(${yesno}) set(yesno "yes") else() # No's are more important, so shout them. set(yesno "NO") endif() set(IMAGE_CONFIGURATION_SUMMARY "${IMAGE_CONFIGURATION_SUMMARY}${msg}: ${yesno}\n" PARENT_SCOPE) endfunction() # ALLEGRO_CFG_IIO_HAVE_* are the available libraries. # ALLEGRO_CFG_IIO_SUPPORT_* are the supported formats. # First look for native libraries and mark any supported image # type as found, so that the associated third party libraries # don't need to be used. if(WANT_NATIVE_IMAGE_LOADER) set(ALLEGRO_CFG_WANT_NATIVE_IMAGE_LOADER 1) if(WIN32) find_package(GDIPLUS) if(GDIPLUS_FOUND) set(CMAKE_REQUIRED_DEFINITIONS -DGDIPLUS_LOWERCASE=${GDIPLUS_LOWERCASE}) set(CMAKE_REQUIRED_INCLUDES ${GDIPLUS_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${GDIPLUS_LIBRARY}) run_cxx_compile_test(" #include #include #if GDIPLUS_LOWERCASE #include #else #include #endif using namespace Gdiplus; int main(void) { int pf = PixelFormat32bppARGB; return 0; } " SUPPORT_GDIPLUS) endif(GDIPLUS_FOUND) if(SUPPORT_GDIPLUS) set(ALLEGRO_CFG_IIO_HAVE_GDIPLUS 1) set(ALLEGRO_CFG_IIO_HAVE_GDIPLUS_LOWERCASE_H ${GDIPLUS_LOWERCASE}) set(ALLEGRO_CFG_IIO_SUPPORT_PNG 1) set(ALLEGRO_CFG_IIO_SUPPORT_JPG 1) list(APPEND IMAGE_SOURCES gdiplus.cpp) list(APPEND IMAGE_LIBRARIES ${GDIPLUS_LIBRARIES}) if(MINGW) list(APPEND IMAGE_LIBRARIES uuid) endif(MINGW) list(APPEND IMAGE_DEFINES ${GDIPLUS_DEFINITIONS}) list(APPEND IMAGE_INCLUDE_DIRECTORIES ${GDIPLUS_INCLUDE_DIR}) include_directories(SYSTEM ${GDIPLUS_INCLUDE_DIR}) else(SUPPORT_GDIPLUS) message("WARNING: cannot use GDI+. Will try other libraries.") endif(SUPPORT_GDIPLUS) endif(WIN32) if (ALLEGRO_MACOSX) set(ALLEGRO_CFG_IIO_SUPPORT_PNG 1) set(ALLEGRO_CFG_IIO_SUPPORT_JPG 1) list(APPEND IMAGE_SOURCES macosx.m) endif(ALLEGRO_MACOSX) if(ANDROID) set(ALLEGRO_CFG_IIO_HAVE_ANDROID 1) set(ALLEGRO_CFG_IIO_SUPPORT_JPG 1) set(ALLEGRO_CFG_IIO_SUPPORT_PNG 1) set(ALLEGRO_CFG_IIO_SUPPORT_WEBP 1) list(APPEND IMAGE_SOURCES android.c) endif(ANDROID) if(IPHONE) list(APPEND IMAGE_SOURCES iphone.m) endif(IPHONE) endif(WANT_NATIVE_IMAGE_LOADER) if(WIN32) image_summary(" - GDI+" SUPPORT_GDIPLUS) elseif(MACOSX OR ANDROID OR IPHONE) image_summary(" - Native image loader" WANT_NATIVE_IMAGE_LOADER) endif() # Now look for third party libraries to handle the unsupported formats if(WANT_IMAGE_FREEIMAGE) find_package(FreeImage) if(FREEIMAGE_FOUND) # HAVE_FREEIMAGE means libfreeimage is available (and should be used) set(ALLEGRO_CFG_IIO_HAVE_FREEIMAGE 1) set(ALLEGRO_CFG_IIO_SUPPORT_FREEIMAGE 1) list(APPEND IMAGE_SOURCES freeimage.c) list(APPEND IMAGE_LIBRARIES ${FREEIMAGE_LIBRARIES}) list(APPEND IMAGE_DEFINES ${FREEIMAGE_DEFINITIONS}) list(APPEND IMAGE_INCLUDE_DIRECTORIES ${FREEIMAGE_INCLUDE_PATH}) include_directories(SYSTEM ${FREEIMAGE_INCLUDE_PATH}) else(FREEIMAGE_FOUND) message("WARNING: FreeImage not found, disabling support") endif(FREEIMAGE_FOUND) endif(WANT_IMAGE_FREEIMAGE) image_summary(" - FreeImage" ALLEGRO_CFG_IIO_SUPPORT_FREEIMAGE) if(WANT_IMAGE_PNG AND NOT ALLEGRO_CFG_IIO_SUPPORT_PNG) find_package(PNG) if(PNG_FOUND) # HAVE_PNG means libpng is available (and should be used) set(ALLEGRO_CFG_IIO_HAVE_PNG 1) set(ALLEGRO_CFG_IIO_SUPPORT_PNG 1) list(APPEND IMAGE_SOURCES png.c) list(APPEND IMAGE_LIBRARIES ${PNG_LIBRARIES}) list(APPEND IMAGE_DEFINES ${PNG_DEFINITIONS}) list(APPEND IMAGE_INCLUDE_DIRECTORIES ${PNG_INCLUDE_DIR}) include_directories(SYSTEM ${PNG_INCLUDE_DIR}) else(PNG_FOUND) message("WARNING: libpng not found, disabling support") endif(PNG_FOUND) endif(WANT_IMAGE_PNG AND NOT ALLEGRO_CFG_IIO_SUPPORT_PNG) image_summary(" - libpng" PNG_FOUND) if(WANT_IMAGE_JPG AND NOT ALLEGRO_CFG_IIO_SUPPORT_JPG) find_package(JPEG) if(JPEG_FOUND AND MINGW) set(CMAKE_REQUIRED_INCLUDES ${JPEG_INCLUDE_DIR}) run_c_compile_test(" #include #include #include #include int main(void) { return 0; }" JPEG_COMPILES) set(CMAKE_REQUIRED_INCLUDES) set(SUPPORT_JPEG ${JPEG_COMPILES}) else() set(SUPPORT_JPEG ${JPEG_FOUND}) endif() if(SUPPORT_JPEG) # HAVE_JPG means libjpeg is available (and should be used) set(ALLEGRO_CFG_IIO_HAVE_JPG 1) set(ALLEGRO_CFG_IIO_SUPPORT_JPG 1) list(APPEND IMAGE_SOURCES jpg.c) list(APPEND IMAGE_LIBRARIES ${JPEG_LIBRARIES}) list(APPEND IMAGE_DEFINES ${JPEG_DEFINITIONS}) list(APPEND IMAGE_INCLUDE_DIRECTORIES ${JPEG_INCLUDE_DIR}) include_directories(SYSTEM ${JPEG_INCLUDE_DIR}) else() if(MINGW AND JPEG_FOUND AND NOT JPEG_COMPILES) message("WARNING: libjpeg found but the headers appear to " "conflict with your MinGW headers, so disabling support. " "Try a later version.") else() message("WARNING: libjpeg not found, disabling support") endif() endif() endif(WANT_IMAGE_JPG AND NOT ALLEGRO_CFG_IIO_SUPPORT_JPG) image_summary(" - libjpeg" SUPPORT_JPEG) if(WANT_IMAGE_WEBP AND NOT ALLEGRO_CFG_IIO_SUPPORT_WEBP) find_package(WebP) if(WEBP_FOUND) set(ALLEGRO_CFG_IIO_HAVE_WEBP 1) set(ALLEGRO_CFG_IIO_SUPPORT_WEBP 1) list(APPEND IMAGE_SOURCES webp.c) list(APPEND IMAGE_LIBRARIES ${WEBP_LIBRARIES}) list(APPEND IMAGE_INCLUDE_DIRECTORIES ${WEBP_INCLUDE_DIRS}) include_directories(SYSTEM ${WEBP_INCLUDE_DIRS}) else(WEBP_FOUND) message("WARNING: libwebp not found, disabling support") endif(WEBP_FOUND) endif(WANT_IMAGE_WEBP AND NOT ALLEGRO_CFG_IIO_SUPPORT_WEBP) image_summary(" - libwebp" WEBP_FOUND) configure_file( allegro5/internal/aintern_image_cfg.h.cmake ${PROJECT_BINARY_DIR}/include/allegro5/internal/aintern_image_cfg.h ) add_our_addon_library(allegro_image AllegroImage-${ALLEGRO_SOVERSION} "${IMAGE_SOURCES};${IMAGE_INCLUDE_FILES}" "-DALLEGRO_IIO_SRC" "${ALLEGRO_LINK_WITH};${IMAGE_LIBRARIES}" ) install_our_headers(${IMAGE_INCLUDE_FILES}) add_addon(image) set(IMAGE_CONFIGURATION_SUMMARY "${IMAGE_CONFIGURATION_SUMMARY}" PARENT_SCOPE) #-----------------------------------------------------------------------------# # vi: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/addons/image/allegro5/000077500000000000000000000000001473414355200175245ustar00rootroot00000000000000allegro5-5.2.10.1/addons/image/allegro5/allegro_image.h000066400000000000000000000022241473414355200224640ustar00rootroot00000000000000#ifndef __al_included_allegro5_allegro_image_h #define __al_included_allegro5_allegro_image_h #include "allegro5/base.h" #if (defined ALLEGRO_MINGW32) || (defined ALLEGRO_MSVC) || (defined ALLEGRO_BCC32) #ifndef ALLEGRO_STATICLINK #ifdef ALLEGRO_IIO_SRC #define _ALLEGRO_IIO_DLL __declspec(dllexport) #else #define _ALLEGRO_IIO_DLL __declspec(dllimport) #endif #else #define _ALLEGRO_IIO_DLL #endif #endif #if defined ALLEGRO_MSVC #define ALLEGRO_IIO_FUNC(type, name, args) _ALLEGRO_IIO_DLL type __cdecl name args #elif defined ALLEGRO_MINGW32 #define ALLEGRO_IIO_FUNC(type, name, args) extern type name args #elif defined ALLEGRO_BCC32 #define ALLEGRO_IIO_FUNC(type, name, args) extern _ALLEGRO_IIO_DLL type name args #else #define ALLEGRO_IIO_FUNC AL_FUNC #endif #ifdef __cplusplus extern "C" { #endif ALLEGRO_IIO_FUNC(bool, al_init_image_addon, (void)); ALLEGRO_IIO_FUNC(bool, al_is_image_addon_initialized, (void)); ALLEGRO_IIO_FUNC(void, al_shutdown_image_addon, (void)); ALLEGRO_IIO_FUNC(uint32_t, al_get_allegro_image_version, (void)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/image/allegro5/internal/000077500000000000000000000000001473414355200213405ustar00rootroot00000000000000allegro5-5.2.10.1/addons/image/allegro5/internal/aintern_image.h000066400000000000000000000112341473414355200243140ustar00rootroot00000000000000#ifndef __al_included_allegro_aintern_image_h #define __al_included_allegro_aintern_image_h #include "allegro5/platform/alplatf.h" #include "allegro5/internal/aintern_image_cfg.h" #ifdef __cplusplus extern "C" { #endif #ifdef ALLEGRO_CFG_WANT_NATIVE_IMAGE_LOADER #ifdef ALLEGRO_IPHONE ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_iphone_load_image, (const char *filename, int flags)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_iphone_load_image_f, (ALLEGRO_FILE *f, int flags)); #endif #ifdef ALLEGRO_MACOSX ALLEGRO_IIO_FUNC(bool, _al_osx_register_image_loader, (void)); #endif #endif ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_pcx, (const char *filename, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_pcx, (const char *filename, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_pcx_f, (ALLEGRO_FILE *f, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_pcx_f, (ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(bool, _al_identify_pcx, (ALLEGRO_FILE *f)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_bmp, (const char *filename, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_bmp, (const char *filename, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_bmp_f, (ALLEGRO_FILE *f, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_bmp_f, (ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(bool, _al_identify_bmp, (ALLEGRO_FILE *f)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_tga, (const char *filename, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_tga, (const char *filename, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_tga_f, (ALLEGRO_FILE *f, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_tga_f, (ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(bool, _al_identify_tga, (ALLEGRO_FILE *f)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_dds, (const char *filename, int flags)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_dds_f, (ALLEGRO_FILE *f, int flags)); ALLEGRO_IIO_FUNC(bool, _al_identify_dds, (ALLEGRO_FILE *f)); ALLEGRO_IIO_FUNC(bool, _al_identify_png, (ALLEGRO_FILE *f)); ALLEGRO_IIO_FUNC(bool, _al_identify_jpg, (ALLEGRO_FILE *f)); ALLEGRO_IIO_FUNC(bool, _al_identify_webp, (ALLEGRO_FILE *f)); #ifdef ALLEGRO_CFG_IIO_HAVE_FREEIMAGE ALLEGRO_IIO_FUNC(bool, _al_init_fi, (void)); ALLEGRO_IIO_FUNC(void, _al_shutdown_fi, (void)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_fi_bitmap, (const char *filename, int flags)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_fi_bitmap_f, (ALLEGRO_FILE *f, int flags)); ALLEGRO_IIO_FUNC(bool, _al_identify_fi, (ALLEGRO_FILE *f)); #endif #ifdef ALLEGRO_CFG_IIO_HAVE_GDIPLUS ALLEGRO_IIO_FUNC(bool, _al_init_gdiplus, (void)); ALLEGRO_IIO_FUNC(void, _al_shutdown_gdiplus, (void)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_gdiplus_bitmap, (const char *filename, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_gdiplus_bitmap, (const char *filename, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_gdiplus_bitmap_f, (ALLEGRO_FILE *f, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_gdiplus_png_f, (ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(bool, _al_save_gdiplus_jpg_f, (ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(bool, _al_save_gdiplus_tif_f, (ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(bool, _al_save_gdiplus_gif_f, (ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp)); #endif #ifdef ALLEGRO_CFG_IIO_HAVE_ANDROID ALLEGRO_BITMAP *_al_load_android_bitmap_f(ALLEGRO_FILE *fp, int flags); ALLEGRO_BITMAP *_al_load_android_bitmap(const char *filename, int flags); #endif /* ALLEGRO_CFG_IIO_HAVE_PNG/JPG implies that "native" loaders aren't available. */ #ifdef ALLEGRO_CFG_IIO_HAVE_PNG ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_png, (const char *filename, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_png, (const char *filename, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_png_f, (ALLEGRO_FILE *f, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_png_f, (ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp)); #endif #ifdef ALLEGRO_CFG_IIO_HAVE_JPG ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_jpg, (const char *filename, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_jpg, (const char *filename, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_jpg_f, (ALLEGRO_FILE *f, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_jpg_f, (ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp)); #endif #ifdef ALLEGRO_CFG_IIO_HAVE_WEBP ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_webp, (const char *filename, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_webp, (const char *filename, ALLEGRO_BITMAP *bmp)); ALLEGRO_IIO_FUNC(ALLEGRO_BITMAP *, _al_load_webp_f, (ALLEGRO_FILE *f, int flags)); ALLEGRO_IIO_FUNC(bool, _al_save_webp_f, (ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp)); #endif #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/image/allegro5/internal/aintern_image_cfg.h.cmake000066400000000000000000000010651473414355200262130ustar00rootroot00000000000000#cmakedefine ALLEGRO_CFG_WANT_NATIVE_IMAGE_LOADER /* which libraries are present and needed? */ #cmakedefine ALLEGRO_CFG_IIO_HAVE_FREEIMAGE #cmakedefine ALLEGRO_CFG_IIO_HAVE_GDIPLUS #cmakedefine ALLEGRO_CFG_IIO_HAVE_GDIPLUS_LOWERCASE_H #cmakedefine ALLEGRO_CFG_IIO_HAVE_ANDROID #cmakedefine ALLEGRO_CFG_IIO_HAVE_PNG #cmakedefine ALLEGRO_CFG_IIO_HAVE_JPG #cmakedefine ALLEGRO_CFG_IIO_HAVE_WEBP /* which formats are supported and wanted? */ #cmakedefine ALLEGRO_CFG_IIO_SUPPORT_PNG #cmakedefine ALLEGRO_CFG_IIO_SUPPORT_JPG #cmakedefine ALLEGRO_CFG_IIO_SUPPORT_WEBP allegro5-5.2.10.1/addons/image/android.c000066400000000000000000000006361473414355200176030ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern_android.h" #include "allegro5/internal/aintern_image.h" ALLEGRO_BITMAP *_al_load_android_bitmap_f(ALLEGRO_FILE *fp, int flags) { return _al_android_load_image_f(fp, flags); } ALLEGRO_BITMAP *_al_load_android_bitmap(const char *filename, int flags) { return _al_android_load_image(filename, flags); } allegro5-5.2.10.1/addons/image/bmp.c000066400000000000000000001407671473414355200167530ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * BMP reader. * * By Seymour Shlien. * * OS/2 BMP support and BMP save function by Jonas Petersen. * * See readme.txt for copyright information. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern_convert.h" #include "allegro5/internal/aintern_image.h" #include "iio.h" ALLEGRO_DEBUG_CHANNEL("image") /* Do NOT simplify this to just (x), it doesn't work in MSVC. */ #define INT_TO_BOOL(x) ((x) != 0) #define BIT_RGB 0 #define BIT_RLE8 1 #define BIT_RLE4 2 #define BIT_BITFIELDS 3 #define OS2INFOHEADERSIZE 12 #define WININFOHEADERSIZE 40 #define WININFOHEADERSIZEV2 52 #define WININFOHEADERSIZEV3 56 #define WININFOHEADERSIZEV4 108 #define WININFOHEADERSIZEV5 124 typedef struct BMPFILEHEADER { unsigned short bfType; unsigned long bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned long bfOffBits; } BMPFILEHEADER; /* Used for both OS/2 and Windows BMP. * Contains only the parameters needed to load the image */ typedef struct BMPINFOHEADER { unsigned long biWidth; signed long biHeight; unsigned short biBitCount; unsigned long biCompression; unsigned long biClrUsed; uint32_t biRedMask; uint32_t biGreenMask; uint32_t biBlueMask; bool biHaveAlphaMask; uint32_t biAlphaMask; } BMPINFOHEADER; typedef struct WINBMPINFOHEADER { /* size: 40 */ unsigned long biWidth; signed long biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned long biCompression; unsigned long biSizeImage; unsigned long biXPelsPerMeter; unsigned long biYPelsPerMeter; unsigned long biClrUsed; unsigned long biClrImportant; } WINBMPINFOHEADER; typedef struct OS2BMPINFOHEADER { /* size: 12 */ unsigned short biWidth; unsigned short biHeight; unsigned short biPlanes; unsigned short biBitCount; } OS2BMPINFOHEADER; typedef void(*bmp_line_fn)(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul); /* read_bmfileheader: * Reads a BMP file header and check that it has the BMP magic number. */ static int read_bmfileheader(ALLEGRO_FILE *f, BMPFILEHEADER *fileheader) { fileheader->bfType = (uint16_t)al_fread16le(f); fileheader->bfSize = (uint32_t)al_fread32le(f); fileheader->bfReserved1 = (uint16_t)al_fread16le(f); fileheader->bfReserved2 = (uint16_t)al_fread16le(f); fileheader->bfOffBits = (uint32_t)al_fread32le(f); if (fileheader->bfType != 0x4D42) { ALLEGRO_WARN("Not BMP format\n"); return -1; } if (al_feof(f) || al_ferror(f)) { ALLEGRO_ERROR("Failed to read file header\n"); return -1; } return 0; } /* read_win_bminfoheader: * Reads information from a BMP file header. */ static int read_win_bminfoheader(ALLEGRO_FILE *f, BMPINFOHEADER *infoheader) { WINBMPINFOHEADER win_infoheader; win_infoheader.biWidth = (uint32_t)al_fread32le(f); win_infoheader.biHeight = al_fread32le(f); win_infoheader.biPlanes = (uint16_t)al_fread16le(f); win_infoheader.biBitCount = (uint16_t)al_fread16le(f); win_infoheader.biCompression = (uint32_t)al_fread32le(f); win_infoheader.biSizeImage = (uint32_t)al_fread32le(f); win_infoheader.biXPelsPerMeter = (uint32_t)al_fread32le(f); win_infoheader.biYPelsPerMeter = (uint32_t)al_fread32le(f); win_infoheader.biClrUsed = (uint32_t)al_fread32le(f); win_infoheader.biClrImportant = (uint32_t)al_fread32le(f); infoheader->biWidth = win_infoheader.biWidth; infoheader->biHeight = win_infoheader.biHeight; infoheader->biBitCount = win_infoheader.biBitCount; infoheader->biCompression = win_infoheader.biCompression; infoheader->biClrUsed = win_infoheader.biClrUsed; if (al_feof(f) || al_ferror(f)) { ALLEGRO_ERROR("Failed to read file header\n"); return -1; } return 0; } /* read_os2_bminfoheader: * Reads information from an OS/2 format BMP file header. */ static int read_os2_bminfoheader(ALLEGRO_FILE *f, BMPINFOHEADER *infoheader) { OS2BMPINFOHEADER os2_infoheader; os2_infoheader.biWidth = (uint16_t)al_fread16le(f); os2_infoheader.biHeight = (uint16_t)al_fread16le(f); os2_infoheader.biPlanes = (uint16_t)al_fread16le(f); os2_infoheader.biBitCount = (uint16_t)al_fread16le(f); infoheader->biWidth = os2_infoheader.biWidth; infoheader->biHeight = os2_infoheader.biHeight; infoheader->biBitCount = os2_infoheader.biBitCount; infoheader->biCompression = BIT_RGB; infoheader->biClrUsed = 0; /* default */ if (al_feof(f) || al_ferror(f)) { ALLEGRO_ERROR("Failed to read file header\n"); return -1; } return 0; } /* decode_bitfield: * Converts a bitfield in to a shift+mask pair */ static void decode_bitfield(uint32_t m, int *shift_out, uint32_t *mask_out) { int shift = 0; if (m == 0) { *shift_out = 0; *mask_out = 0; return; } #ifdef __GNUC__ shift = __builtin_ctz(m); m >>= shift; #else while ((m & 1) == 0) { m >>= 1; ++shift; } #endif *shift_out = shift; *mask_out = m; } /* read_palette: * Loads the color palette for 1,4,8 bit formats. * OS/2 bitmaps take 3 bytes per color. * Windows bitmaps take 4 bytes per color. */ static void read_palette(int ncolors, PalEntry *pal, ALLEGRO_FILE *f, int flags, const BMPINFOHEADER *infoheader, int win_flag) { int i; unsigned char c[3]; uint32_t r, g, b, a; bool premul = !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA); int as; uint32_t am; decode_bitfield(infoheader->biAlphaMask, &as, &am); for (i = 0; i < ncolors; i++) { uint32_t pixel; al_fread(f, c, 3); r = c[2]; g = c[1]; b = c[0]; pixel = (r << 16) | (g << 8) | b; switch (am) { case 0x00: a = 255; break; case 0x01: a = ((pixel >> as) & am) * 255; break; case 0xFF: a = ((pixel >> as) & am); break; default: a = ((pixel >> as) & am) * 255 / am; } if (am && premul) { r = r * a / 255; g = g * a / 255; b = b * a / 255; } pal[i].r = r; pal[i].g = g; pal[i].b = b; pal[i].a = a; if (win_flag) { al_fgetc(f); } } } /* read_16le: * Support function for reading 16-bit little endian values * from a memory buffer. */ static uint16_t read_16le(void *buf) { unsigned char *ucbuf = (unsigned char *)buf; return ucbuf[0] | (ucbuf[1] << 8); } /* read_32le: * Support function for reading 32-bit little endian values * from a memory buffer. */ static uint32_t read_32le(void *buf) { unsigned char *ucbuf = (unsigned char *)buf; return ucbuf[0] | (ucbuf[1] << 8) | (ucbuf[2] << 16) | (ucbuf[3] << 24); } /* read_1bit_line: * Support function for reading the 1 bit bitmap file format. */ static void read_1bit_line(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul) { int i, j; unsigned char *ucbuf = (unsigned char *)buf; size_t bytes_wanted = ((length + 7) / 8 + 3) & ~3; size_t bytes_read = al_fread(f, ucbuf, bytes_wanted); memset(ucbuf + bytes_read, 0, bytes_wanted - bytes_read); (void)premul; (void)data; for (i = (length - 1) / 8; i >= 0; --i) { unsigned char x = ucbuf[i]; for (j = 0; j < 8; ++j) ucbuf[i*8 + 7 - j] = (x & (1 << j)) >> j; } } /* read_2bit_line: * Support function for reading the 2 bit bitmap file format. */ static void read_2bit_line(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul) { int i; unsigned char *ucbuf = (unsigned char *)buf; size_t bytes_wanted = ((length + 3) / 4 + 3) & ~3; size_t bytes_read = al_fread(f, ucbuf, bytes_wanted); memset(ucbuf + bytes_read, 0, bytes_wanted - bytes_read); (void)premul; (void)data; for (i = (length - 1) / 4; i >= 0; --i) { unsigned char x = ucbuf[i]; ucbuf[i*4] = (x & 0xC0) >> 6; ucbuf[i*4+1] = (x & 0x30) >> 4; ucbuf[i*4+2] = (x & 0x0C) >> 2; ucbuf[i*4+3] = (x & 0x03); } } /* read_4bit_line: * Support function for reading the 4 bit bitmap file format. */ static void read_4bit_line(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul) { int i; unsigned char *ucbuf = (unsigned char *)buf; size_t bytes_wanted = ((length + 1) / 2 + 3) & ~3; size_t bytes_read = al_fread(f, ucbuf, bytes_wanted); memset(ucbuf + bytes_read, 0, bytes_wanted - bytes_read); (void)premul; (void)data; for (i = (length - 1) / 2; i >= 0; --i) { unsigned char x = ucbuf[i]; ucbuf[i*2] = (x & 0xF0) >> 4; ucbuf[i*2+1] = (x & 0x0F); } } /* read_8bit_line: * Support function for reading the 8 bit bitmap file format. */ static void read_8bit_line(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul) { size_t bytes_wanted = (length + 3) & ~3; size_t bytes_read = al_fread(f, buf, bytes_wanted); memset(buf + bytes_read, 0, bytes_wanted - bytes_read); (void)premul; (void)data; } /* read_16_rgb_555_line: * Support function for reading the 16 bit / RGB555 bitmap file format. */ static void read_16_rgb_555_line(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul) { int i; uint32_t *data32 = (uint32_t *)data; size_t bytes_wanted = (length + (length & 1)) * 2; size_t bytes_read = al_fread(f, buf, bytes_wanted); memset(buf + bytes_read, 0, bytes_wanted - bytes_read); (void)premul; for (i = 0; i < length; ++i) { uint16_t pixel = read_16le(buf + i*2); data32[i] = ALLEGRO_CONVERT_RGB_555_TO_ABGR_8888_LE(pixel); } } /* read_16_argb_1555_line: * Support function for reading the 16 bit / ARGB1555 bitmap file format. */ static void read_16_argb_1555_line(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul) { int i; uint32_t *data32 = (uint32_t *)data; size_t bytes_wanted = (length + (length & 1)) * 2; size_t bytes_read = al_fread(f, buf, bytes_wanted); memset(buf + bytes_read, 0, bytes_wanted - bytes_read); for (i = 0; i < length; ++i) { uint16_t pixel = read_16le(buf + i*2); data32[i] = ALLEGRO_CONVERT_ARGB_1555_TO_ABGR_8888_LE(pixel); if (premul && (pixel & 0x8000)) data32[i] = 0; } } /* read_16_rgb_565_line: * Support function for reading the 16 bit / RGB565 bitmap file format. */ static void read_16_rgb_565_line(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul) { int i; uint32_t *data32 = (uint32_t *)data; size_t bytes_wanted = (length + (length & 1)) * 2; size_t bytes_read = al_fread(f, buf, bytes_wanted); memset(buf + bytes_read, 0, bytes_wanted - bytes_read); (void)premul; for (i = 0; i < length; i++) { uint16_t pixel = read_16le(buf + i*2); data32[i] = ALLEGRO_CONVERT_RGB_565_TO_ABGR_8888_LE(pixel); } } /* read_24_rgb_888_line: * Support function for reading the 24 bit / RGB888 bitmap file format. */ static void read_24_rgb_888_line(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul) { int bi, i; unsigned char *ucbuf = (unsigned char *)buf; uint32_t *data32 = (uint32_t *)data; size_t bytes_wanted = length * 3 + (length & 3); size_t bytes_read = al_fread(f, buf, bytes_wanted); memset(buf + bytes_read, 0, bytes_wanted - bytes_read); (void)premul; for (i = 0, bi = 0; i < (length & ~3); i += 4, bi += 3) { uint32_t a = read_32le(buf + bi*4); // BGRB [LE:BRGB] uint32_t b = read_32le(buf + bi*4 + 4); // GRBG [LE:GBRG] uint32_t c = read_32le(buf + bi*4 + 8); // RBGR [LE:RGBR] uint32_t w = a; uint32_t x = (a >> 24) | (b << 8); uint32_t y = (b >> 16) | (c << 16); uint32_t z = (c >> 8); data32[i] = ALLEGRO_CONVERT_RGB_888_TO_ABGR_8888_LE(w); data32[i+1] = ALLEGRO_CONVERT_RGB_888_TO_ABGR_8888_LE(x); data32[i+2] = ALLEGRO_CONVERT_RGB_888_TO_ABGR_8888_LE(y); data32[i+3] = ALLEGRO_CONVERT_RGB_888_TO_ABGR_8888_LE(z); } bi *= 4; for (; i < length; i++, bi += 3) { uint32_t pixel = ucbuf[bi] | (ucbuf[bi+1] << 8) | (ucbuf[bi+2] << 16); data32[i] = ALLEGRO_CONVERT_RGB_888_TO_ABGR_8888_LE(pixel); } } /* read_32_xrgb_8888_line: * Support function for reading the 32 bit / XRGB8888 bitmap file format. */ static void read_32_xrgb_8888_line(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul) { int i; uint32_t *data32 = (uint32_t *)data; size_t bytes_wanted = length * 4; size_t bytes_read = al_fread(f, buf, bytes_wanted); memset(buf + bytes_read, 0, bytes_wanted - bytes_read); (void)premul; for (i = 0; i < length; i++) { uint32_t pixel = read_32le(buf + i*4); data32[i] = ALLEGRO_CONVERT_XRGB_8888_TO_ABGR_8888_LE(pixel); } } /* read_32_rgbx_8888_line: * Support function for reading the 32 bit / RGBX8888 bitmap file format. */ static void read_32_rgbx_8888_line(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul) { int i; uint32_t *data32 = (uint32_t *)data; size_t bytes_wanted = length * 4; size_t bytes_read = al_fread(f, buf, bytes_wanted); memset(buf + bytes_read, 0, bytes_wanted - bytes_read); (void)premul; for (i = 0; i < length; i++) { uint32_t pixel = read_32le(buf + i*4); data32[i] = ALLEGRO_CONVERT_RGBX_8888_TO_ABGR_8888_LE(pixel); } } /* read_32_argb_8888_line: * Support function for reading the 32 bit / ARGB8888 bitmap file format. */ static void read_32_argb_8888_line(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul) { int i; uint32_t *data32 = (uint32_t *)data; size_t bytes_wanted = length * 4; size_t bytes_read = al_fread(f, buf, bytes_wanted); memset(buf + bytes_read, 0, bytes_wanted - bytes_read); for (i = 0; i < length; i++) { uint32_t pixel = read_32le(buf + i*4); uint32_t a = (pixel & 0xFF000000U) >> 24; data32[i] = ALLEGRO_CONVERT_ARGB_8888_TO_ABGR_8888_LE(pixel); if (premul && a != 255) { data[i*4+1] = data[i*4+1] * a / 255; data[i*4+2] = data[i*4+2] * a / 255; data[i*4+3] = data[i*4+3] * a / 255; } } } /* read_32_rgba_8888_line: * Support function for reading the 32 bit / RGBA8888 bitmap file format. */ static void read_32_rgba_8888_line(ALLEGRO_FILE *f, char *buf, char *data, int length, bool premul) { int i; uint32_t *data32 = (uint32_t *)data; size_t bytes_wanted = length * 4; size_t bytes_read = al_fread(f, buf, bytes_wanted); memset(buf + bytes_read, 0, bytes_wanted - bytes_read); for (i = 0; i < length; i++) { uint32_t pixel = read_32le(buf + i*4); uint32_t a = (pixel & 0x000000FFU); data32[i] = ALLEGRO_CONVERT_RGBA_8888_TO_ABGR_8888_LE(pixel); if (premul && a != 255) { data[i*4] = data[i*4] * a / 255; data[i*4+1] = data[i*4+1] * a / 255; data[i*4+2] = data[i*4+2] * a / 255; } } } /* read_RGB_image: * For reading the standard BMP image format */ static bool read_RGB_image(ALLEGRO_FILE *f, int flags, const BMPINFOHEADER *infoheader, ALLEGRO_LOCKED_REGION *lr, bmp_line_fn fn) { int i, line, height, width, dir; size_t linesize; char *linebuf; bool premul = !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA); height = infoheader->biHeight; width = infoheader->biWidth; // Includes enough space to read the padding for a line linesize = (infoheader->biWidth + 3) & ~3; if (infoheader->biBitCount < 8) linesize *= (8 / infoheader->biBitCount); else linesize *= (infoheader->biBitCount / 8); linebuf = al_malloc(linesize); if (!linebuf) { ALLEGRO_WARN("Failed to allocate pixel row buffer\n"); return false; } line = height < 0 ? 0 : height - 1; dir = height < 0 ? 1 : -1; height = abs(height); for (i = 0; i < height; i++, line += dir) { char *data = (char *)lr->data + lr->pitch * line; fn(f, linebuf, data, width, premul); } al_free(linebuf); return true; } /* read_RGB_image_indices: * For reading the palette indices from BMP image format */ static bool read_RGB_image_indices(ALLEGRO_FILE *f, int flags, const BMPINFOHEADER *infoheader, ALLEGRO_LOCKED_REGION *lr, bmp_line_fn fn) { int i, line, height, width, dir; size_t linesize; char *linebuf; (void)flags; height = infoheader->biHeight; width = infoheader->biWidth; // Includes enough space to read the padding for a line linesize = (width + 3) & ~3; // Indices are always 8-bit, so no need to adjust linesize linebuf = al_malloc(linesize); if (!linebuf) { ALLEGRO_WARN("Failed to allocate pixel row buffer\n"); return false; } if (height < 0) { dir = 1; line = 0; height = -height; } else { dir = -1; line = height - 1; } for (i = 0; i < height; i++, line += dir) { char *data = (char *)lr->data + lr->pitch * line; fn(f, linebuf, data, width, false); memcpy(data, linebuf, width); } al_free(linebuf); return true; } /* read_RGB_paletted_image: * For reading the standard palette mapped BMP image format */ static bool read_RGB_paletted_image(ALLEGRO_FILE *f, int flags, const BMPINFOHEADER *infoheader, PalEntry* pal, ALLEGRO_LOCKED_REGION *lr, bmp_line_fn fn) { int i, j, line, height, width, dir; size_t linesize; char *linebuf; (void)flags; height = infoheader->biHeight; width = infoheader->biWidth; // Includes enough space to read the padding for a line linesize = (width + 3) & ~3; if (infoheader->biBitCount < 8) linesize *= (8 / infoheader->biBitCount); else linesize *= (infoheader->biBitCount / 8); linebuf = al_malloc(linesize); if (!linebuf) { ALLEGRO_WARN("Failed to allocate pixel row buffer\n"); return false; } line = height < 0 ? 0 : height - 1; dir = height < 0 ? 1 : -1; height = abs(height); for (i = 0; i < height; i++, line += dir) { char *data = (char *)lr->data + lr->pitch * line; fn(f, linebuf, data, width, false); for (j = 0; j < width; ++j) { unsigned char idx = linebuf[j]; data[j*4] = pal[idx].r; data[j*4+1] = pal[idx].g; data[j*4+2] = pal[idx].b; data[j*4+3] = pal[idx].a; } } al_free(linebuf); return true; } /* generate_scale_table: * Helper function to generate color tables for bitfield format bitmaps. */ static void generate_scale_table(int* table, int entries) { int i; for (i = 0; i < entries; ++i) table[i] = i * 255 / (entries - 1); } /* read_bitfields_image: * For reading the generic bitfield compressed BMP image format */ static bool read_bitfields_image(ALLEGRO_FILE *f, int flags, const BMPINFOHEADER *infoheader, ALLEGRO_LOCKED_REGION *lr) { int i, k, line, height, width, dir; size_t linesize, bytes_read; unsigned char *linebuf; int bytes_per_pixel = infoheader->biBitCount / 8; bool premul = !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA); int rs, gs, bs, as; uint32_t rm, gm, bm, am; // Temporary colour conversion tables for 1..10 bit channels // Worst case: ~7KB is temporarily allocated int *tempconvert[10]; int *rtable = NULL; int *gtable = NULL; int *btable = NULL; int *atable = NULL; height = infoheader->biHeight; width = infoheader->biWidth; // Includes enough space to read the padding for a line linesize = width * bytes_per_pixel + ((width * bytes_per_pixel) & 3); // Overallocate by bytes_per_pixel so a 32-bit read can overlap the end linebuf = al_malloc((width + 1) * bytes_per_pixel); if (!linebuf) { ALLEGRO_WARN("Failed to allocate pixel row buffer\n"); return false; } decode_bitfield(infoheader->biRedMask, &rs, &rm); decode_bitfield(infoheader->biGreenMask, &gs, &gm); decode_bitfield(infoheader->biBlueMask, &bs, &bm); decode_bitfield(infoheader->biAlphaMask, &as, &am); for (i = 0; i < (int)(sizeof(tempconvert) / sizeof(int *)); ++i) { uint32_t mask = ~(0xFFFFFFFFU << (i+1)) & 0xFFFFFFFFU; switch (i) { case 0: tempconvert[i] = _al_rgb_scale_1; break; case 3: tempconvert[i] = _al_rgb_scale_4; break; case 4: tempconvert[i] = _al_rgb_scale_5; break; case 5: tempconvert[i] = _al_rgb_scale_6; break; default: if (rm == mask || gm == mask || bm == mask || am == mask) { int entries = (1 << (i+1)); // Skip generating tables for tiny images if (width * height > entries * 2) { tempconvert[i] = al_malloc(sizeof(int) * entries); generate_scale_table(tempconvert[i], entries); } else { tempconvert[i] = NULL; } } else { tempconvert[i] = NULL; } } if (rm == mask) rtable = tempconvert[i]; if (gm == mask) gtable = tempconvert[i]; if (bm == mask) btable = tempconvert[i]; if (am == mask) atable = tempconvert[i]; } line = height < 0 ? 0 : height - 1; dir = height < 0 ? 1 : -1; height = abs(height); for (i = 0; i < height; i++, line += dir) { unsigned char *data = (unsigned char *)lr->data + lr->pitch * line; bytes_read = al_fread(f, linebuf, linesize); memset(linebuf + bytes_read, 0, linesize - bytes_read); for (k = 0; k < width; k++) { uint32_t pixel = read_32le(linebuf + k*bytes_per_pixel); uint32_t r, g, b, a = 255; r = ((pixel >> rs) & rm); g = ((pixel >> gs) & gm); b = ((pixel >> bs) & bm); if (rtable) r = rtable[r]; else if (rm > 0) r = r * 255 / rm; if (gtable) g = gtable[g]; else if (gm > 0) g = g * 255 / gm; if (btable) b = btable[b]; else if (bm > 0) b = b * 255 / bm; if (am) { a = ((pixel >> as) & am); if (atable) a = atable[a]; else a = a * 255 / am; if (premul) { r = r * a / 255; g = g * a / 255; b = b * a / 255; } } data[0] = r; data[1] = g; data[2] = b; data[3] = a; data += 4; } } al_free(linebuf); for (i = 0; i < (int)(sizeof(tempconvert) / sizeof(int *)); ++i) { if (i != 0 && i != 3 && i != 4 && i != 5) al_free(tempconvert[i]); } return true; } /* read_RGB_image_32bit_alpha_hack: * For reading the non-compressed BMP image format (32-bit). * These are treatly specially because some programs put alpha information in * the fourth byte of each pixel, which is normally just padding (and zero). * We use a heuristic: if every pixel has zero in that fourth byte then assume * the whole image is opaque (a=255). Otherwise treat the fourth byte as an * alpha channel. * * Note that V3 headers include an alpha bit mask, which can properly indicate * the presence or absence of an alpha channel. * This hack is not required then. */ static bool read_RGB_image_32bit_alpha_hack(ALLEGRO_FILE *f, int flags, const BMPINFOHEADER *infoheader, ALLEGRO_LOCKED_REGION *lr) { int i, j, line, startline, height, width, dir; int have_alpha = 0; size_t linesize; char *linebuf; const bool premul = !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA); height = infoheader->biHeight; width = infoheader->biWidth; // Includes enough space to read the padding for a line linesize = (infoheader->biWidth + 3) & ~3; if (infoheader->biBitCount < 8) linesize *= (8 / infoheader->biBitCount); else linesize *= (infoheader->biBitCount / 8); linebuf = al_malloc(linesize); if (!linebuf) { ALLEGRO_WARN("Failed to allocate pixel row buffer\n"); return false; } line = startline = height < 0 ? 0 : height - 1; dir = height < 0 ? 1 : -1; height = abs(height); for (i = 0; i < height; i++, line += dir) { unsigned char *data = (unsigned char *)lr->data + lr->pitch * line; /* Don't premultiply alpha here or the image will come out all black */ read_32_argb_8888_line(f, linebuf, (char *)data, width, false); /* Check the alpha values of every pixel in the row */ for (j = 0; j < width; j++) { have_alpha |= ((data[j*4+3] & 0xFF) != 0); } } /* Fixup pass - make imague opaque or premultiply alpha */ if (!have_alpha) { line = startline; for (i = 0; i < height; i++, line += dir) { unsigned char *data = (unsigned char *)lr->data + lr->pitch * line; for (j = 0; j < width; j++) { data[j*4+3] = 255; } } } else if (premul) { line = startline; for (i = 0; i < height; i++, line += dir) { unsigned char *data = (unsigned char *)lr->data + lr->pitch * line; for (j = 0; j < width; j++) { data[j*4] = data[j*4] * data[j*4+3] / 255; data[j*4+1] = data[j*4+1] * data[j*4+3] / 255; data[j*4+2] = data[j*4+2] * data[j*4+3] / 255; } } } al_free(linebuf); return true; } /* read_RLE8_compressed_image: * For reading the 8 bit RLE compressed BMP image format. */ static bool read_RLE8_compressed_image(ALLEGRO_FILE *f, unsigned char *buf, const BMPINFOHEADER *infoheader) { int count; unsigned char val; int j, pos, line, width, height, dir; int eolflag, eopicflag; eopicflag = 0; width = (int)infoheader->biWidth; height = abs((int)infoheader->biHeight); line = (infoheader->biHeight < 0) ? 0 : height - 1; dir = (infoheader->biHeight < 0) ? 1 : -1; while (eopicflag == 0) { pos = 0; /* x position in bitmap */ eolflag = 0; /* end of line flag */ while ((eolflag == 0) && (eopicflag == 0)) { count = al_fgetc(f); if (count == EOF) { return false; } val = al_fgetc(f); if (count > 0) { /* repeat pixel count times */ if (count > width - pos) { count = width - pos; } for (j = 0; j < count; j++) { buf[line * width + pos] = val; pos++; } } else { switch (val) { case 0: /* end of line flag */ eolflag = 1; break; case 1: /* end of picture flag */ eopicflag = 1; break; case 2: /* displace picture */ count = al_fgetc(f); if (count == EOF) { return false; } pos += count; count = al_fgetc(f); if (count == EOF) { return false; } line += dir * count; if (line < 0) line = 0; if (line >= height) line = height - 1; break; default: /* read in absolute mode */ count = val; if (count > width - pos) { count = width - pos; } for (j = 0; j < count; j++) { val = al_fgetc(f); buf[line * width + pos] = val; pos++; } if (j % 2 == 1) val = al_fgetc(f); /* align on word boundary */ break; } } if (pos > width + 1) eolflag = 1; } line += dir; if (line < 0 || line >= height) eopicflag = 1; } return true; } /* read_RLE4_compressed_image: * For reading the 4 bit RLE compressed BMP image format. */ static bool read_RLE4_compressed_image(ALLEGRO_FILE *f, unsigned char *buf, const BMPINFOHEADER *infoheader) { unsigned char b[8]; int count; unsigned short val; int j, k, pos, line, width, height, dir; int eolflag, eopicflag; eopicflag = 0; /* end of picture flag */ width = (int)infoheader->biWidth; height = abs((int)infoheader->biHeight); line = (infoheader->biHeight < 0) ? 0 : height - 1; dir = (infoheader->biHeight < 0) ? 1 : -1; while (eopicflag == 0) { pos = 0; eolflag = 0; /* end of line flag */ while ((eolflag == 0) && (eopicflag == 0)) { count = al_fgetc(f); if (count == EOF) return false; val = al_fgetc(f); if (count > 0) { /* repeat pixels count times */ if (count > width - pos) { count = width - pos; } b[1] = val & 15; b[0] = (val >> 4) & 15; for (j = 0; j < count; j++) { buf[line * width + pos] = b[j % 2]; pos++; } } else { switch (val) { case 0: /* end of line */ eolflag = 1; break; case 1: /* end of picture */ eopicflag = 1; break; case 2: /* displace image */ count = al_fgetc(f); if (count == EOF) return false; pos += count; count = al_fgetc(f); if (count == EOF) return false; line += dir * count; if (line < 0) line = 0; if (line >= height) line = height - 1; break; default: /* read in absolute mode */ count = val; if (count > width - pos) { count = width - pos; } for (j = 0; j < count; j++) { if ((j % 4) == 0) { val = (uint16_t)al_fread16le(f); for (k = 0; k < 2; k++) { b[2 * k + 1] = val & 15; val = val >> 4; b[2 * k] = val & 15; val = val >> 4; } } buf[line * width + pos] = b[j % 4]; pos++; } break; } } if (pos > width + 1) eolflag = 1; } line += dir; if (line < 0 || line >= height) eopicflag = 1; } return true; } /* Like load_bmp, but starts loading from the current place in the ALLEGRO_FILE * specified. If successful the offset into the file will be left just after * the image data. If unsuccessful the offset into the file is unspecified, * i.e. you must either reset the offset to some known place or close the * packfile. The packfile is not closed by this function. */ ALLEGRO_BITMAP *_al_load_bmp_f(ALLEGRO_FILE *f, int flags) { BMPFILEHEADER fileheader; BMPINFOHEADER infoheader; ALLEGRO_BITMAP *bmp; PalEntry pal[256]; int64_t file_start; int64_t header_start; unsigned long biSize; unsigned char *buf = NULL; ALLEGRO_LOCKED_REGION *lr; bool keep_index = INT_TO_BOOL(flags & ALLEGRO_KEEP_INDEX); bool loaded_ok; ASSERT(f); file_start = al_ftell(f); if (read_bmfileheader(f, &fileheader) != 0) { return NULL; } header_start = al_ftell(f); biSize = (uint32_t)al_fread32le(f); if (al_feof(f) || al_ferror(f)) { ALLEGRO_ERROR("EOF or file error while reading bitmap header.\n"); return NULL; } switch (biSize) { case WININFOHEADERSIZE: case WININFOHEADERSIZEV2: case WININFOHEADERSIZEV3: case WININFOHEADERSIZEV4: case WININFOHEADERSIZEV5: if (read_win_bminfoheader(f, &infoheader) != 0) { return NULL; } break; case OS2INFOHEADERSIZE: if (read_os2_bminfoheader(f, &infoheader) != 0) { return NULL; } ASSERT(infoheader.biCompression == BIT_RGB); break; default: ALLEGRO_WARN("Unsupported header size: %ld\n", biSize); return NULL; } /* End of header for OS/2 and BITMAPV2INFOHEADER (V1). */ if (biSize == OS2INFOHEADERSIZE || biSize == WININFOHEADERSIZE) { ASSERT(al_ftell(f) == header_start + (int64_t) biSize); } if ((int)infoheader.biWidth < 0) { ALLEGRO_WARN("negative width: %ld\n", infoheader.biWidth); return NULL; } if (infoheader.biCompression != BIT_RGB && infoheader.biCompression != BIT_RLE8 && infoheader.biCompression != BIT_RLE4 && infoheader.biCompression != BIT_BITFIELDS) { ALLEGRO_ERROR("Unsupported compression: 0x%x\n", (int) infoheader.biCompression); return NULL; } if (infoheader.biBitCount != 1 && infoheader.biBitCount != 2 && infoheader.biBitCount != 4 && infoheader.biBitCount != 8 && infoheader.biBitCount != 16 && infoheader.biBitCount != 24 && infoheader.biBitCount != 32) { ALLEGRO_WARN("unsupported bit depth: %d\n", infoheader.biBitCount); return NULL; } if (infoheader.biCompression == BIT_RLE4 && infoheader.biBitCount != 4) { ALLEGRO_WARN("unsupported bit depth for RLE4 compression: %d\n", infoheader.biBitCount); return NULL; } if (infoheader.biCompression == BIT_RLE8 && infoheader.biBitCount != 8) { ALLEGRO_WARN("unsupported bit depth for RLE8 compression: %d\n", infoheader.biBitCount); return NULL; } if (infoheader.biCompression == BIT_BITFIELDS && infoheader.biBitCount != 16 && infoheader.biBitCount != 24 && infoheader.biBitCount != 32) { ALLEGRO_WARN("unsupported bit depth for bitfields compression: %d\n", infoheader.biBitCount); return NULL; } /* In BITMAPINFOHEADER (V1) the RGB bit masks are not part of the header. * In BITMAPV2INFOHEADER they form part of the header, but only valid when * for BITFIELDS images. */ if (infoheader.biCompression == BIT_BITFIELDS || biSize >= WININFOHEADERSIZEV2) { infoheader.biRedMask = (uint32_t)al_fread32le(f); infoheader.biGreenMask = (uint32_t)al_fread32le(f); infoheader.biBlueMask = (uint32_t)al_fread32le(f); } /* BITMAPV3INFOHEADER and above include an Alpha bit mask. */ if (biSize < WININFOHEADERSIZEV3) { infoheader.biHaveAlphaMask = false; infoheader.biAlphaMask = 0x0; } else { uint32_t pixel_mask = 0xFFFFFFFFU; infoheader.biHaveAlphaMask = true; infoheader.biAlphaMask = (uint32_t)al_fread32le(f); if (infoheader.biBitCount < 32) pixel_mask = ~(pixel_mask << infoheader.biBitCount) & 0xFFFFFFFFU; if ((infoheader.biAlphaMask & pixel_mask) == 0) { infoheader.biAlphaMask = 0; ALLEGRO_WARN("Ignoring invalid alpha mask\n"); } } /* Seek past the end of the header to reach the palette / image data */ if (biSize > WININFOHEADERSIZEV3) { if (!al_fseek(f, file_start + 14 + biSize, ALLEGRO_SEEK_SET)) { ALLEGRO_ERROR("Seek error\n"); return NULL; } } if (infoheader.biBitCount <= 8) { int i; for (i = 0; i < 256; ++i) { pal[i].r = 0; pal[i].g = 0; pal[i].b = 0; pal[i].a = 255; } } /* Read the palette, if any. Higher bit depth images _may_ have an optional * palette but we don't use it. */ if (infoheader.biCompression != BIT_BITFIELDS && infoheader.biBitCount <= 8) { int win_flag = (biSize != OS2INFOHEADERSIZE); int ncolors = infoheader.biClrUsed; int extracolors = 0; int bytes_per_color = win_flag ? 4 : 3; if (infoheader.biClrUsed >= INT_MAX) { ALLEGRO_ERROR("Illegal palette size: %lu\n", infoheader.biClrUsed); return NULL; } if (win_flag) { if (ncolors == 0) { ncolors = (1 << infoheader.biBitCount); } } else { /* detect palette size for OS2v1 format BMP files */ if (ncolors == 0) { ncolors = (fileheader.bfOffBits - 14 - OS2INFOHEADERSIZE) / 3; } if (ncolors == 0) { ALLEGRO_WARN("No palette in OS2v1 BMP file!\n"); } } if (ncolors > 256) { ALLEGRO_WARN("Too many colors: %d\n", ncolors); ncolors = 256; extracolors = ncolors - 256; } read_palette(ncolors, pal, f, flags, &infoheader, win_flag); if (al_feof(f) || al_ferror(f)) { ALLEGRO_ERROR("EOF or I/O error\n"); return NULL; } if (!al_fseek(f, extracolors * bytes_per_color, ALLEGRO_SEEK_SET)) { ALLEGRO_ERROR("Seek error\n"); return NULL; } } else if (infoheader.biClrUsed && infoheader.biBitCount > 8) { int win_flag = (biSize != OS2INFOHEADERSIZE); int bytes_per_color = win_flag ? 4 : 3; if (!al_fseek(f, infoheader.biClrUsed * bytes_per_color, ALLEGRO_SEEK_CUR)) { ALLEGRO_ERROR("Seek error\n"); return NULL; } } /* Skip to the pixel data only if it's outside of the image metadata */ if (file_start + (int64_t)fileheader.bfOffBits > al_ftell(f)) { if (!al_fseek(f, file_start + fileheader.bfOffBits, ALLEGRO_SEEK_SET)) { ALLEGRO_ERROR("Seek error\n"); return NULL; } } bmp = al_create_bitmap(infoheader.biWidth, abs((int)infoheader.biHeight)); if (!bmp) { ALLEGRO_ERROR("Failed to create bitmap\n"); return NULL; } if (infoheader.biWidth == 0 || infoheader.biHeight == 0) { ALLEGRO_WARN("Creating zero-sized bitmap\n"); return bmp; } if (infoheader.biBitCount <= 8 && keep_index) { lr = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8, ALLEGRO_LOCK_WRITEONLY); } else { lr = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_WRITEONLY); } if (!lr) { ALLEGRO_ERROR("Failed to lock region\n"); al_destroy_bitmap(bmp); return NULL; } if (infoheader.biCompression == BIT_RLE8 || infoheader.biCompression == BIT_RLE4) { /* Questionable but most loaders handle this, so we should. */ if (infoheader.biHeight < 0) { ALLEGRO_WARN("compressed bitmap with negative height\n"); } /* RLE decoding may skip pixels so clear the buffer first. */ buf = al_calloc(infoheader.biWidth, abs((int)infoheader.biHeight)); } loaded_ok = true; switch (infoheader.biCompression) { case BIT_RGB: if (infoheader.biBitCount == 32 && !infoheader.biHaveAlphaMask) { if (!read_RGB_image_32bit_alpha_hack(f, flags, &infoheader, lr)) return NULL; } else { bmp_line_fn fn = NULL; switch (infoheader.biBitCount) { case 1: fn = read_1bit_line; break; case 2: fn = read_2bit_line; break; case 4: fn = read_4bit_line; break; case 8: fn = read_8bit_line; break; case 16: fn = read_16_rgb_555_line; break; case 24: fn = read_24_rgb_888_line; break; case 32: fn = read_32_xrgb_8888_line; break; default: ALLEGRO_ERROR("No decoding function for bit depth %d\n", infoheader.biBitCount); return NULL; } if (infoheader.biBitCount == 16 && infoheader.biAlphaMask == 0x00008000U) fn = read_16_argb_1555_line; else if (infoheader.biBitCount == 32 && infoheader.biAlphaMask == 0xFF000000U) fn = read_32_argb_8888_line; if (keep_index) { if (!read_RGB_image_indices(f, flags, &infoheader, lr, fn)) return NULL; } else if (infoheader.biBitCount <= 8) { if (!read_RGB_paletted_image(f, flags, &infoheader, pal, lr, fn)) return NULL; } else { if (!read_RGB_image(f, flags, &infoheader, lr, fn)) return NULL; } } break; case BIT_RLE8: loaded_ok = read_RLE8_compressed_image(f, buf, &infoheader); if (!loaded_ok) ALLEGRO_ERROR("Error reading RLE8 data\n"); break; case BIT_RLE4: loaded_ok = read_RLE4_compressed_image(f, buf, &infoheader); if (!loaded_ok) ALLEGRO_ERROR("Error reading RLE4 data\n"); break; case BIT_BITFIELDS: if (infoheader.biBitCount == 16) { if (infoheader.biRedMask == 0x00007C00U && infoheader.biGreenMask == 0x000003E0U && infoheader.biBlueMask == 0x0000001FU && infoheader.biAlphaMask == 0x00000000U) { loaded_ok = read_RGB_image(f, flags, &infoheader, lr, read_16_rgb_555_line); } else if (infoheader.biRedMask == 0x00007C00U && infoheader.biGreenMask == 0x000003E0U && infoheader.biBlueMask == 0x0000001FU && infoheader.biAlphaMask == 0x00008000U) { loaded_ok = read_RGB_image(f, flags, &infoheader, lr, read_16_argb_1555_line); } else if (infoheader.biRedMask == 0x0000F800U && infoheader.biGreenMask == 0x000007E0U && infoheader.biBlueMask == 0x0000001FU && infoheader.biAlphaMask == 0x00000000U) { loaded_ok = read_RGB_image(f, flags, &infoheader, lr, read_16_rgb_565_line); } else { loaded_ok = read_bitfields_image(f, flags, &infoheader, lr); } } else if (infoheader.biBitCount == 24) { if (infoheader.biRedMask == 0x00FF0000U && infoheader.biGreenMask == 0x0000FF00U && infoheader.biBlueMask == 0x000000FFU && infoheader.biAlphaMask == 0x00000000U) { loaded_ok = read_RGB_image(f, flags, &infoheader, lr, read_24_rgb_888_line); } else { loaded_ok = read_bitfields_image(f, flags, &infoheader, lr); } } else if (infoheader.biBitCount == 32) { if (infoheader.biRedMask == 0x00FF0000U && infoheader.biGreenMask == 0x0000FF00U && infoheader.biBlueMask == 0x000000FFU && infoheader.biAlphaMask == 0x00000000U) { loaded_ok = read_RGB_image(f, flags, &infoheader, lr, read_32_xrgb_8888_line); } else if (infoheader.biRedMask == 0x00FF0000U && infoheader.biGreenMask == 0x0000FF00U && infoheader.biBlueMask == 0x000000FFU && infoheader.biAlphaMask == 0xFF000000U) { loaded_ok = read_RGB_image(f, flags, &infoheader, lr, read_32_argb_8888_line); } else if (infoheader.biRedMask == 0xFF000000U && infoheader.biGreenMask == 0x00FF0000U && infoheader.biBlueMask == 0x0000FF00U && infoheader.biAlphaMask == 0x00000000U) { loaded_ok = read_RGB_image(f, flags, &infoheader, lr, read_32_rgbx_8888_line); } else if (infoheader.biRedMask == 0xFF000000U && infoheader.biGreenMask == 0x00FF0000U && infoheader.biBlueMask == 0x0000FF00U && infoheader.biAlphaMask == 0x000000FFU) { loaded_ok = read_RGB_image(f, flags, &infoheader, lr, read_32_rgba_8888_line); } else { loaded_ok = read_bitfields_image(f, flags, &infoheader, lr); } } break; default: ALLEGRO_WARN("Unknown compression: %ld\n", infoheader.biCompression); loaded_ok = false; break; } if (infoheader.biCompression == BIT_RLE8 || infoheader.biCompression == BIT_RLE4) { int x, y; unsigned char *data; for (y = 0; y < abs((int)infoheader.biHeight); y++) { data = (unsigned char *)lr->data + lr->pitch * y; for (x = 0; x < (int)infoheader.biWidth; x++) { if (keep_index) { data[0] = buf[y * infoheader.biWidth + x]; data++; } else { data[0] = pal[buf[y * infoheader.biWidth + x]].r; data[1] = pal[buf[y * infoheader.biWidth + x]].g; data[2] = pal[buf[y * infoheader.biWidth + x]].b; data[3] = 255; data += 4; } } } al_free(buf); } if (bmp) { al_unlock_bitmap(bmp); } /* If something went wrong internally */ if (!loaded_ok) { al_destroy_bitmap(bmp); bmp = NULL; } return bmp; } /* Like save_bmp but writes into the ALLEGRO_FILE given instead of a new file. * The packfile is not closed after writing is completed. On success the * offset into the file is left after the TGA file just written. On failure * the offset is left at the end of whatever incomplete data was written. */ bool _al_save_bmp_f(ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp) { int bfSize; int biSizeImage; int bpp; int filler; int i, j; int w, h; ALLEGRO_LOCKED_REGION *lr; ASSERT(f); ASSERT(bmp); w = al_get_bitmap_width(bmp); h = al_get_bitmap_height(bmp); bpp = 24; filler = 3 - ((w * (bpp / 8) - 1) & 3); biSizeImage = (w * 3 + filler) * h; bfSize = 14 + WININFOHEADERSIZE + biSizeImage; al_set_errno(0); /* file_header */ al_fwrite16le(f, 0x4D42); /* bfType ("BM") */ al_fwrite32le(f, bfSize); /* bfSize */ al_fwrite16le(f, 0); /* bfReserved1 */ al_fwrite16le(f, 0); /* bfReserved2 */ al_fwrite32le(f, 14 + WININFOHEADERSIZE); /* bfOffBits */ /* info_header */ al_fwrite32le(f, WININFOHEADERSIZE); /* biSize */ al_fwrite32le(f, w); /* biWidth */ al_fwrite32le(f, h); /* biHeight */ al_fwrite16le(f, 1); /* biPlanes */ al_fwrite16le(f, bpp); /* biBitCount */ al_fwrite32le(f, BIT_RGB); /* biCompression */ al_fwrite32le(f, biSizeImage); /* biSizeImage */ al_fwrite32le(f, 0xB12); /* biXPelsPerMeter (0xB12 = 72 dpi) */ al_fwrite32le(f, 0xB12); /* biYPelsPerMeter */ al_fwrite32le(f, 0); /* biClrUsed */ al_fwrite32le(f, 0); /* biClrImportant */ /* Don't really need the alpha channel, just the _LE. * Note that there exist 32-bit BMPs now so we could try to save those. */ lr = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_READONLY); /* image data */ for (i = h - 1; i >= 0; i--) { unsigned char *data = (unsigned char *)lr->data + i * lr->pitch; for (j = 0; j < w; j++) { unsigned char r = data[0]; unsigned char g = data[1]; unsigned char b = data[2]; data += 4; al_fputc(f, b); al_fputc(f, g); al_fputc(f, r); } for (j = 0; j < filler; j++) al_fputc(f, 0); } al_unlock_bitmap(bmp); return al_get_errno() ? false : true; } ALLEGRO_BITMAP *_al_load_bmp(const char *filename, int flags) { ALLEGRO_FILE *f; ALLEGRO_BITMAP *bmp; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } bmp = _al_load_bmp_f(f, flags); al_fclose(f); return bmp; } bool _al_save_bmp(const char *filename, ALLEGRO_BITMAP *bmp) { ALLEGRO_FILE *f; bool retsave; bool retclose; ASSERT(filename); f = al_fopen(filename, "wb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for writing.\n", filename); return false; } retsave = _al_save_bmp_f(f, bmp); retclose = al_fclose(f); return retsave && retclose; } bool _al_identify_bmp(ALLEGRO_FILE *f) { uint16_t x; uint16_t y; y = al_fread16le(f); if (y != 0x4D42) return false; if (!al_fseek(f, 14 - 2, ALLEGRO_SEEK_CUR)) return false; x = al_fread16le(f); switch (x) { case WININFOHEADERSIZE: case WININFOHEADERSIZEV2: case WININFOHEADERSIZEV3: case WININFOHEADERSIZEV4: case WININFOHEADERSIZEV5: case OS2INFOHEADERSIZE: return true; } return false; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/image/dds.c000066400000000000000000000120451473414355200167320ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * A simple DDS reader. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern_image.h" #include "iio.h" ALLEGRO_DEBUG_CHANNEL("image") typedef int DWORD; typedef struct { DWORD dwSize; DWORD dwFlags; DWORD dwFourCC; DWORD dwRGBBitCount; DWORD dwRBitMask; DWORD dwGBitMask; DWORD dwBBitMask; DWORD dwABitMask; } DDS_PIXELFORMAT; typedef struct { DWORD dwSize; DWORD dwFlags; DWORD dwHeight; DWORD dwWidth; DWORD dwPitchOrLinearSize; DWORD dwDepth; DWORD dwMipMapCount; DWORD dwReserved1[11]; DDS_PIXELFORMAT ddspf; DWORD dwCaps; DWORD dwCaps2; DWORD dwCaps3; DWORD dwCaps4; DWORD dwReserved2; } DDS_HEADER; #define DDS_HEADER_SIZE 124 #define DDS_PIXELFORMAT_SIZE 32 #define FOURCC(c0, c1, c2, c3) ((int)(c0) | ((int)(c1) << 8) | ((int)(c2) << 16) | ((int)(c3) << 24)) #define DDPF_FOURCC 0x4 ALLEGRO_BITMAP *_al_load_dds_f(ALLEGRO_FILE *f, int flags) { ALLEGRO_BITMAP *bmp; DDS_HEADER header; DWORD magic; size_t num_read; int w, h, fourcc, format, block_width, block_height, block_size; ALLEGRO_STATE state; ALLEGRO_LOCKED_REGION *lr = NULL; int ii; char* bitmap_data; (void)flags; magic = al_fread32le(f); if (magic != 0x20534444) { ALLEGRO_ERROR("Invalid DDS magic number.\n"); return NULL; } num_read = al_fread(f, &header, sizeof(DDS_HEADER)); if (num_read != DDS_HEADER_SIZE) { ALLEGRO_ERROR("Wrong DDS header size. Got %d, expected %d.\n", (int)num_read, DDS_HEADER_SIZE); return NULL; } if (!(header.ddspf.dwFlags & DDPF_FOURCC)) { ALLEGRO_ERROR("Only compressed DDS formats supported.\n"); return NULL; } w = header.dwWidth; h = header.dwHeight; fourcc = header.ddspf.dwFourCC; switch (fourcc) { case FOURCC('D', 'X', 'T', '1'): format = ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1; break; case FOURCC('D', 'X', 'T', '3'): format = ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3; break; case FOURCC('D', 'X', 'T', '5'): format = ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5; break; default: ALLEGRO_ERROR("Invalid pixel format.\n"); return NULL; } block_width = al_get_pixel_block_width(format); block_height = al_get_pixel_block_height(format); block_size = al_get_pixel_block_size(format); al_store_state(&state, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS); al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP); al_set_new_bitmap_format(format); bmp = al_create_bitmap(w, h); if (!bmp) { ALLEGRO_ERROR("Failed to create bitmap.\n"); goto FAIL; } if (al_get_bitmap_format(bmp) != format) { ALLEGRO_ERROR("Created a bad bitmap.\n"); goto FAIL; } lr = al_lock_bitmap_blocked(bmp, ALLEGRO_LOCK_WRITEONLY); if (!lr) { switch (format) { case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1: case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3: case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5: ALLEGRO_ERROR("Could not lock the bitmap (probably the support for locking this format has not been enabled).\n"); break; default: ALLEGRO_ERROR("Could not lock the bitmap.\n"); } return NULL; } bitmap_data = lr->data; for (ii = 0; ii < (h + block_height - 1) / block_height; ii++) { size_t pitch = (size_t)((w + block_width - 1) / block_width * block_size); num_read = al_fread(f, bitmap_data, pitch); if (num_read != pitch) { ALLEGRO_ERROR("DDS file too short.\n"); goto FAIL; } bitmap_data += lr->pitch; } al_unlock_bitmap(bmp); goto RESET; FAIL: if (lr) al_unlock_bitmap(bmp); al_destroy_bitmap(bmp); bmp = NULL; RESET: al_restore_state(&state); return bmp; } ALLEGRO_BITMAP *_al_load_dds(const char *filename, int flags) { ALLEGRO_FILE *f; ALLEGRO_BITMAP *bmp; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable open %s for reading.\n", filename); return NULL; } bmp = _al_load_dds_f(f, flags); al_fclose(f); return bmp; } bool _al_identify_dds(ALLEGRO_FILE *f) { uint8_t x[4]; uint32_t y; al_fread(f, x, 4); if (memcmp(x, "DDS ", 4) != 0) return false; y = al_fread32le(f); if (y != 124) return false; return true; } allegro5-5.2.10.1/addons/image/freeimage.c000066400000000000000000000122221473414355200201010ustar00rootroot00000000000000/* Allegro wrapper routines for FreeImage * by Karthik Kumar Viswanathan . */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_image.h" #include "iio.h" ALLEGRO_DEBUG_CHANNEL("image") static bool freeimage_initialized = false; static void _fiio_al_error_handler(FREE_IMAGE_FORMAT fif, const char *message) { ALLEGRO_ERROR("FreeImage %s : %s\n", (fif == FIF_UNKNOWN)? "UNKNOWN" : FreeImage_GetFormatFromFIF(fif), message); } bool _al_init_fi(void) { if (freeimage_initialized) return true; FreeImage_Initialise(FALSE); _al_add_exit_func(_al_shutdown_fi, "_al_shutdown_fi"); FreeImage_SetOutputMessage(_fiio_al_error_handler); freeimage_initialized = true; return true; } void _al_shutdown_fi(void) { if (!freeimage_initialized) return; FreeImage_DeInitialise(); freeimage_initialized = false; } static ALLEGRO_BITMAP *_al_fi_to_al_bitmap(FIBITMAP *fib) { int width = 0, height = 0; ALLEGRO_BITMAP *bitmap = NULL; width = FreeImage_GetWidth(fib); height = FreeImage_GetHeight(fib); bitmap = al_create_bitmap(width, height); if (bitmap) { ALLEGRO_LOCKED_REGION *a_lock = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_WRITEONLY); if (a_lock) { unsigned char *out = (unsigned char *)a_lock->data; int out_inc = a_lock->pitch - (width*4); for (int j=height - 1; j > -1; --j) { for (int i=0; i < width; ++i) { RGBQUAD color = { 0.0, 0.0, 0.0, 0.0 } ; if (FreeImage_GetPixelColor(fib, i, j, &color) == FALSE) { ALLEGRO_ERROR("Unable to get pixel data at %d,%d\n", i , j); } *out++ = (unsigned char) color.rgbBlue; *out++ = (unsigned char) color.rgbGreen; *out++ = (unsigned char) color.rgbRed; *out++ = (unsigned char) color.rgbReserved; } out += out_inc; } al_unlock_bitmap(bitmap); } } return bitmap; } ALLEGRO_BITMAP *_al_load_fi_bitmap(const char *filename, int flags) { FIBITMAP *fib = NULL; ALLEGRO_BITMAP *bitmap = NULL; FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; ASSERT(filename); ASSERT(freeimage_initialized == true); fif = FreeImage_GetFIFFromFilename(filename); if (fif == FIF_UNKNOWN) fif = FreeImage_GetFileType(filename, 0); if (fif == FIF_UNKNOWN) { ALLEGRO_WARN("Could not determine the file type for '%s'\n", filename); return NULL; } { FIBITMAP *fibRaw = FreeImage_Load(fif, filename, flags); if (!fibRaw) return NULL; fib = FreeImage_ConvertTo32Bits(fibRaw); FreeImage_Unload(fibRaw); if (!fib) return NULL; } bitmap = _al_fi_to_al_bitmap(fib); FreeImage_Unload(fib); return bitmap; } /* FreeImage requires stdcall on win32 for these. DLL_CALLCONV is provided by FreeImage.h */ static unsigned int DLL_CALLCONV _fiio_al_read(void *buffer, unsigned size, unsigned count, fi_handle handle) { return (unsigned int) al_fread((ALLEGRO_FILE *)handle, buffer, (count * size)); } static unsigned int DLL_CALLCONV _fiio_al_write(void *buffer, unsigned size, unsigned count, fi_handle handle) { return (unsigned int) al_fwrite((ALLEGRO_FILE *)handle, buffer, (count * size)); } static int DLL_CALLCONV _fiio_al_fseek(fi_handle handle, long offset, int origin) { return al_fseek((ALLEGRO_FILE *)handle, offset, origin); } static long DLL_CALLCONV _fiio_al_ftell(fi_handle handle) { return (long) al_ftell((ALLEGRO_FILE *)handle); } ALLEGRO_BITMAP *_al_load_fi_bitmap_f(ALLEGRO_FILE *f, int flags) { FreeImageIO fio; ALLEGRO_BITMAP *bitmap = NULL; FIBITMAP *fib = NULL; FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; if (flags != 0) { ALLEGRO_WARN("Ignoring bitmap loading flags.\n"); } ASSERT(f); ASSERT(freeimage_initialized == true); fio.read_proc = _fiio_al_read; fio.write_proc = _fiio_al_write; fio.seek_proc = _fiio_al_fseek; fio.tell_proc = _fiio_al_ftell; fif = FreeImage_GetFileTypeFromHandle(&fio, (fi_handle)f, 0); if (fif == FIF_UNKNOWN) { ALLEGRO_WARN("Could not determine the file type for Allegro file.\n"); return NULL; } { FIBITMAP *fibRaw = FreeImage_LoadFromHandle(fif, &fio, (fi_handle)f, 0); if (!fibRaw) return NULL; fib = FreeImage_ConvertTo32Bits(fibRaw); FreeImage_Unload(fibRaw); if (!fib) return NULL; } bitmap = _al_fi_to_al_bitmap(fib); FreeImage_Unload(fib); return bitmap; } bool _al_identify_fi(ALLEGRO_FILE *f) { FreeImageIO fio; FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; ASSERT(f); ASSERT(freeimage_initialized == true); fio.read_proc = _fiio_al_read; fio.write_proc = _fiio_al_write; fio.seek_proc = _fiio_al_fseek; fio.tell_proc = _fiio_al_ftell; fif = FreeImage_GetFileTypeFromHandle(&fio, (fi_handle)f, 0); if (fif == FIF_UNKNOWN) { ALLEGRO_WARN("Could not determine the file type for Allegro file.\n"); return false; } return true; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/image/gdiplus.cpp000066400000000000000000000316621473414355200201750ustar00rootroot00000000000000#include #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_convert.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_image.h" #include "iio.h" #ifdef ALLEGRO_CFG_IIO_HAVE_GDIPLUS_LOWERCASE_H #include #else #include #endif ALLEGRO_DEBUG_CHANNEL("image") /* Needed with the MinGW w32api-3.15 headers. */ using namespace Gdiplus; #if !defined(_MSC_VER) && !defined(__uuidof) #define __uuidof(x) (IID_ ## x) #endif static bool gdiplus_inited = false; static ULONG_PTR gdiplusToken = 0; /* Source: * http://msdn.microsoft.com/en-us/library/ms533843%28VS.85%29.aspx */ static int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) { UINT num = 0; // number of image encoders UINT size = 0; // size of the image encoder array in bytes Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL; Gdiplus::GetImageEncodersSize(&num, &size); if (size == 0) { return -1; } pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(al_malloc(size)); if (pImageCodecInfo == NULL) { return -1; } GetImageEncoders(num, size, pImageCodecInfo); for (UINT j = 0; j < num; ++j) { if(wcscmp(pImageCodecInfo[j].MimeType, format) == 0) { *pClsid = pImageCodecInfo[j].Clsid; al_free(pImageCodecInfo); return j; } } al_free(pImageCodecInfo); return -1; } /* A wrapper around an already opened ALLEGRO_FILE* pointer */ class AllegroWindowsStream : public IStream { long refCount; ALLEGRO_FILE *fp; public: /* Create a stream from an open file handle */ AllegroWindowsStream(ALLEGRO_FILE *fp) : refCount(1), fp(fp) { this->fp = fp; } virtual ~AllegroWindowsStream() { } /* IUnknown */ virtual ULONG STDMETHODCALLTYPE AddRef(void) { return (ULONG) InterlockedIncrement(&refCount); } virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) { if (iid == __uuidof(IUnknown) || iid == __uuidof(ISequentialStream) || iid == __uuidof(IStream)) { *ppvObject = static_cast(this); AddRef(); return S_OK; } else { return E_NOINTERFACE; } } virtual ULONG STDMETHODCALLTYPE Release(void) { ULONG ret = InterlockedDecrement(&refCount); if (ret == 0) { delete this; return 0; } return ret; } /* ISequentialStream */ virtual HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb, ULONG *pcbRead) { size_t read = al_fread(fp, pv, cb); if (pcbRead) { *pcbRead = read; } return read == cb ? S_OK : S_FALSE; } virtual HRESULT STDMETHODCALLTYPE Write(const void *pv, ULONG cb, ULONG *pcbWritten) { size_t written = al_fwrite(fp, pv, cb); if (pcbWritten) { *pcbWritten = written; } return written == cb ? S_OK : STG_E_CANTSAVE; } /* IStream */ virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { ALLEGRO_SEEK o; if (dwOrigin == STREAM_SEEK_SET) { o = ALLEGRO_SEEK_SET; } else if (dwOrigin == STREAM_SEEK_CUR) { o = ALLEGRO_SEEK_CUR; } else { o = ALLEGRO_SEEK_END; } bool ret = al_fseek(fp, dlibMove.QuadPart, o); if (plibNewPosition) { int64_t pos = al_ftell(fp); if (pos == -1) { return STG_E_INVALIDFUNCTION; } plibNewPosition->QuadPart = pos; } return ret ? S_OK : STG_E_INVALIDFUNCTION; } /* The GDI+ image I/O methods need to know the file size */ virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG *pstatstg, DWORD grfStatFlag) { (void) grfStatFlag; memset(pstatstg, 0, sizeof(*pstatstg)); pstatstg->type = STGTY_STREAM; pstatstg->cbSize.QuadPart = al_fsize(fp); return S_OK; } /* The following IStream methods aren't needed */ virtual HRESULT STDMETHODCALLTYPE Clone(IStream **ppstm) { (void) ppstm; return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags) { (void) grfCommitFlags; return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE CopyTo (IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) { (void) pstm; (void) cb; (void) pcbRead; (void) pcbWritten; return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { (void) libOffset; (void) cb; (void) dwLockType; return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE Revert() { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize) { (void) libNewSize; return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { (void) libOffset; (void) cb; (void) dwLockType; return E_NOTIMPL; } }; static void load_indexed_data(Gdiplus::Bitmap *gdi_bmp, ALLEGRO_BITMAP *a_bmp, uint32_t w, uint32_t h) { Gdiplus::BitmapData *gdi_lock = new Gdiplus::BitmapData(); Gdiplus::Rect rect(0, 0, w, h); if (!gdi_bmp->LockBits(&rect, Gdiplus::ImageLockModeRead, PixelFormat8bppIndexed, gdi_lock)) { ALLEGRO_LOCKED_REGION *a_lock = al_lock_bitmap(a_bmp, ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8, ALLEGRO_LOCK_WRITEONLY); if (a_lock) { unsigned char *in = (unsigned char *)gdi_lock->Scan0; unsigned char *out = (unsigned char *)a_lock->data; if (gdi_lock->Stride == a_lock->pitch) { memcpy(out, in, h * gdi_lock->Stride); } else { uint32_t rows = h; while (rows--) { memcpy(out, in, w); in += gdi_lock->Stride; out += a_lock->pitch; } } al_unlock_bitmap(a_bmp); } gdi_bmp->UnlockBits(gdi_lock); } delete gdi_lock; } static void load_non_indexed_data(Gdiplus::Bitmap *gdi_bmp, ALLEGRO_BITMAP *a_bmp, uint32_t w, uint32_t h, bool premul) { Gdiplus::BitmapData *gdi_lock = new Gdiplus::BitmapData(); Gdiplus::Rect rect(0, 0, w, h); if (!gdi_bmp->LockBits(&rect, Gdiplus::ImageLockModeRead, PixelFormat32bppARGB, gdi_lock)) { ALLEGRO_LOCKED_REGION *a_lock = al_lock_bitmap(a_bmp, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_WRITEONLY); if (a_lock) { unsigned char *in = (unsigned char *)gdi_lock->Scan0; unsigned char *out = (unsigned char *)a_lock->data; if (premul) { int in_inc = gdi_lock->Stride - (w*4); int out_inc = a_lock->pitch - (w*4); for (unsigned int y = 0; y < h; y++) { for (unsigned int x = 0; x < w; x++) { unsigned char r, g, b, a; b = *in++; g = *in++; r = *in++; a = *in++; b = b * a / 255; g = g * a / 255; r = r * a / 255; *out++ = b; *out++ = g; *out++ = r; *out++ = a; } in += in_inc; out += out_inc; } } else { if (gdi_lock->Stride == a_lock->pitch) { memcpy(out, in, h * gdi_lock->Stride); } else { uint32_t rows = h; while (rows--) { memcpy(out, in, w * 4); in += gdi_lock->Stride; out += a_lock->pitch; } } } al_unlock_bitmap(a_bmp); } gdi_bmp->UnlockBits(gdi_lock); } delete gdi_lock; } ALLEGRO_BITMAP *_al_load_gdiplus_bitmap_f(ALLEGRO_FILE *fp, int flags) { AllegroWindowsStream *s = new AllegroWindowsStream(fp); if (!s) { ALLEGRO_ERROR("Unable to create AllegroWindowsStream.\n"); return NULL; } ALLEGRO_BITMAP *a_bmp = NULL; Gdiplus::Bitmap *gdi_bmp = Gdiplus::Bitmap::FromStream(s, false); if (gdi_bmp) { const uint32_t w = gdi_bmp->GetWidth(); const uint32_t h = gdi_bmp->GetHeight(); const PixelFormat pf = gdi_bmp->GetPixelFormat(); bool premul = !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA); bool keep_index = (flags & ALLEGRO_KEEP_INDEX); a_bmp = al_create_bitmap(w, h); if (a_bmp) { if (pf == PixelFormat8bppIndexed && keep_index) { load_indexed_data(gdi_bmp, a_bmp, w, h); } else { load_non_indexed_data(gdi_bmp, a_bmp, w, h, premul); } } delete gdi_bmp; } s->Release(); return a_bmp; } ALLEGRO_BITMAP *_al_load_gdiplus_bitmap(const char *filename, int flags) { ALLEGRO_BITMAP *bmp = NULL; ALLEGRO_FILE *fp; fp = al_fopen(filename, "rb"); if (fp) { bmp = _al_load_gdiplus_bitmap_f(fp, flags); al_fclose(fp); } return bmp; } bool _al_save_gdiplus_bitmap_f(ALLEGRO_FILE *fp, const char *ident, ALLEGRO_BITMAP *a_bmp) { CLSID encoder; int encoder_status = -1; if (!_al_stricmp(ident, ".bmp")) { encoder_status = GetEncoderClsid(L"image/bmp", &encoder); } else if (!_al_stricmp(ident, ".jpg") || !_al_stricmp(ident, ".jpeg")) { encoder_status = GetEncoderClsid(L"image/jpeg", &encoder); } else if (!_al_stricmp(ident, ".gif")) { encoder_status = GetEncoderClsid(L"image/gif", &encoder); } else if (!_al_stricmp(ident, ".tif") || !_al_stricmp(ident, ".tiff")) { encoder_status = GetEncoderClsid(L"image/tiff", &encoder); } else if (!_al_stricmp(ident, ".png")) { encoder_status = GetEncoderClsid(L"image/png", &encoder); } if (encoder_status == -1) { ALLEGRO_ERROR("Invalid encoder status.\n"); return false; } AllegroWindowsStream *s = new AllegroWindowsStream(fp); if (!s) { ALLEGRO_ERROR("Couldn't create AllegroWindowsStream.\n"); return false; } const int w = al_get_bitmap_width(a_bmp), h = al_get_bitmap_height(a_bmp); bool ret = false; Gdiplus::Bitmap *gdi_bmp = new Gdiplus::Bitmap(w, h, PixelFormat32bppARGB); if (gdi_bmp) { Gdiplus::Rect rect(0, 0, w, h); Gdiplus::BitmapData *gdi_lock = new Gdiplus::BitmapData(); if (!gdi_bmp->LockBits(&rect, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, gdi_lock)) { ALLEGRO_LOCKED_REGION *a_lock = al_lock_bitmap( a_bmp, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_READONLY); if (a_lock) { unsigned char *in = (unsigned char *)a_lock->data; unsigned char *out = (unsigned char *)gdi_lock->Scan0; if (gdi_lock->Stride == a_lock->pitch) { memcpy(out, in, h * gdi_lock->Stride); } else { uint32_t rows = h; while (rows--) { memcpy(out, in, w * 4); in += a_lock->pitch; out += gdi_lock->Stride; } } al_unlock_bitmap(a_bmp); } gdi_bmp->UnlockBits(gdi_lock); } ret = (gdi_bmp->Save(s, &encoder, NULL) == 0); delete gdi_lock; delete gdi_bmp; } s->Release(); return ret; } bool _al_save_gdiplus_bitmap(const char *filename, ALLEGRO_BITMAP *bmp) { ALLEGRO_FILE *fp; bool ret = false; fp = al_fopen(filename, "wb"); if (fp) { ALLEGRO_PATH *path = al_create_path(filename); if (path) { ret = _al_save_gdiplus_bitmap_f(fp, al_get_path_extension(path), bmp); al_destroy_path(path); } al_fclose(fp); } return ret; } bool _al_save_gdiplus_png_f(ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp) { return _al_save_gdiplus_bitmap_f(f, ".png", bmp); } bool _al_save_gdiplus_jpg_f(ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp) { return _al_save_gdiplus_bitmap_f(f, ".jpg", bmp); } bool _al_save_gdiplus_tif_f(ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp) { return _al_save_gdiplus_bitmap_f(f, ".tif", bmp); } bool _al_save_gdiplus_gif_f(ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp) { return _al_save_gdiplus_bitmap_f(f, ".gif", bmp); } bool _al_init_gdiplus() { if (!gdiplus_inited) { Gdiplus::GdiplusStartupInput gdiplusStartupInput; if (Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL) == Gdiplus::Ok) { gdiplus_inited = TRUE; _al_add_exit_func(_al_shutdown_gdiplus, "_al_shutdown_gdiplus"); } } return gdiplus_inited; } void _al_shutdown_gdiplus() { if (gdiplus_inited) { Gdiplus::GdiplusShutdown(gdiplusToken); gdiplus_inited = false; } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/image/identify.c000066400000000000000000000014611473414355200177730ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern_image.h" bool _al_identify_png(ALLEGRO_FILE *f) { uint8_t x[8]; al_fread(f, x, 8); if (memcmp(x, "\x89PNG\r\n\x1a\n", 8) != 0) return false; return true; } bool _al_identify_jpg(ALLEGRO_FILE *f) { uint8_t x[4]; uint16_t y; y = al_fread16be(f); if (y != 0xffd8) return false; al_fseek(f, 6 - 2, ALLEGRO_SEEK_CUR); al_fread(f, x, 4); if (memcmp(x, "JFIF", 4) != 0) return false; return true; } bool _al_identify_webp(ALLEGRO_FILE *f) { uint8_t x[4]; al_fread(f, x, 4); if (memcmp(x, "RIFF", 4) != 0) return false; al_fseek(f, 4, ALLEGRO_SEEK_CUR); al_fread(f, x, 4); if (memcmp(x, "WEBP", 4) != 0) return false; return true; } allegro5-5.2.10.1/addons/image/iio.c000066400000000000000000000150201473414355200167340ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_image.h" #include "allegro5/internal/aintern_image_cfg.h" /* globals */ static bool iio_inited = false; /* Function: al_init_image_addon */ bool al_init_image_addon(void) { int success; if (iio_inited) return true; success = 0; success |= al_register_bitmap_loader(".pcx", _al_load_pcx); success |= al_register_bitmap_saver(".pcx", _al_save_pcx); success |= al_register_bitmap_loader_f(".pcx", _al_load_pcx_f); success |= al_register_bitmap_saver_f(".pcx", _al_save_pcx_f); success |= al_register_bitmap_identifier(".pcx", _al_identify_pcx); success |= al_register_bitmap_loader(".bmp", _al_load_bmp); success |= al_register_bitmap_saver(".bmp", _al_save_bmp); success |= al_register_bitmap_loader_f(".bmp", _al_load_bmp_f); success |= al_register_bitmap_saver_f(".bmp", _al_save_bmp_f); success |= al_register_bitmap_identifier(".bmp", _al_identify_bmp); success |= al_register_bitmap_loader(".tga", _al_load_tga); success |= al_register_bitmap_saver(".tga", _al_save_tga); success |= al_register_bitmap_loader_f(".tga", _al_load_tga_f); success |= al_register_bitmap_saver_f(".tga", _al_save_tga_f); success |= al_register_bitmap_identifier(".tga", _al_identify_tga); success |= al_register_bitmap_loader(".dds", _al_load_dds); success |= al_register_bitmap_loader_f(".dds", _al_load_dds_f); success |= al_register_bitmap_identifier(".dds", _al_identify_dds); /* Even if we don't have libpng or libjpeg we most likely have a * native reader for those instead so always identify them. */ success |= al_register_bitmap_identifier(".png", _al_identify_png); success |= al_register_bitmap_identifier(".jpg", _al_identify_jpg); /* ALLEGRO_CFG_IIO_HAVE_* is sufficient to know that the library should be used. i.e., ALLEGRO_CFG_IIO_HAVE_GDIPLUS and ALLEGRO_CFG_IIO_HAVE_PNG will never both be set. */ #ifdef ALLEGRO_CFG_IIO_HAVE_GDIPLUS { char const *extensions[] = {".tif", ".tiff", ".jpg", ".jpeg", ".gif", ".png", NULL}; int i; if (_al_init_gdiplus()) { for (i = 0; extensions[i]; i++) { success |= al_register_bitmap_loader(extensions[i], _al_load_gdiplus_bitmap); success |= al_register_bitmap_loader_f(extensions[i], _al_load_gdiplus_bitmap_f); success |= al_register_bitmap_saver(extensions[i], _al_save_gdiplus_bitmap); } success |= al_register_bitmap_saver_f(".tif", _al_save_gdiplus_tif_f); success |= al_register_bitmap_saver_f(".tiff", _al_save_gdiplus_tif_f); success |= al_register_bitmap_saver_f(".gif", _al_save_gdiplus_gif_f); success |= al_register_bitmap_saver_f(".png", _al_save_gdiplus_png_f); success |= al_register_bitmap_saver_f(".jpg", _al_save_gdiplus_jpg_f); success |= al_register_bitmap_saver_f(".jpeg", _al_save_gdiplus_jpg_f); } } #endif #ifdef ALLEGRO_CFG_IIO_HAVE_PNG success |= al_register_bitmap_loader(".png", _al_load_png); success |= al_register_bitmap_saver(".png", _al_save_png); success |= al_register_bitmap_loader_f(".png", _al_load_png_f); success |= al_register_bitmap_saver_f(".png", _al_save_png_f); #endif #ifdef ALLEGRO_CFG_IIO_HAVE_JPG success |= al_register_bitmap_loader(".jpg", _al_load_jpg); success |= al_register_bitmap_saver(".jpg", _al_save_jpg); success |= al_register_bitmap_loader_f(".jpg", _al_load_jpg_f); success |= al_register_bitmap_saver_f(".jpg", _al_save_jpg_f); success |= al_register_bitmap_loader(".jpeg", _al_load_jpg); success |= al_register_bitmap_saver(".jpeg", _al_save_jpg); success |= al_register_bitmap_loader_f(".jpeg", _al_load_jpg_f); success |= al_register_bitmap_saver_f(".jpeg", _al_save_jpg_f); #endif #ifdef ALLEGRO_CFG_IIO_HAVE_WEBP success |= al_register_bitmap_loader(".webp", _al_load_webp); success |= al_register_bitmap_saver(".webp", _al_save_webp); success |= al_register_bitmap_loader_f(".webp", _al_load_webp_f); success |= al_register_bitmap_saver_f(".webp", _al_save_webp_f); success |= al_register_bitmap_identifier(".webp", _al_identify_webp); #endif #ifdef ALLEGRO_CFG_IIO_HAVE_FREEIMAGE { char const *extensions[] = {".ico", ".jng", ".koala", ".lbm", ".iff", ".mng", ".pbm", ".pcd", ".pgm", ".ppm", ".ras", ".wbmp", ".psd", ".cut", ".xpm", ".hdr", ".fax", ".sgi", ".exr", ".raw", ".j2k", ".jp2", ".jpf", ".jpm", ".jpx", ".mj2", ".pfm", ".pict", ".jxr", ".jbg", NULL}; int i; if (_al_init_fi()) { for (i = 0; extensions[i]; i++) { success |= al_register_bitmap_loader(extensions[i], _al_load_fi_bitmap); success |= al_register_bitmap_loader_f(extensions[i], _al_load_fi_bitmap_f); success |= al_register_bitmap_identifier(extensions[i], _al_identify_fi); } } } #endif #ifdef ALLEGRO_CFG_IIO_HAVE_ANDROID { char const *extensions[] = {".webp", ".jpg", ".jpeg", ".ico", ".gif", ".wbmp", ".png", NULL}; int i; for (i = 0; extensions[i]; i++) { success |= al_register_bitmap_loader(extensions[i], _al_load_android_bitmap); success |= al_register_bitmap_loader_f(extensions[i], _al_load_android_bitmap_f); //success |= al_register_bitmap_saver(extensions[i], _al_save_android_bitmap); } success |= al_register_bitmap_identifier(".webp", _al_identify_webp); } #endif #ifdef ALLEGRO_CFG_WANT_NATIVE_IMAGE_LOADER #ifdef ALLEGRO_IPHONE { char const *extensions[] = {".tif", ".tiff", ".jpg", ".jpeg", ".gif", ".png", ".BMPf", ".ico", ".cur", ".xbm", NULL}; int i; for (i = 0; extensions[i]; i++) { success |= al_register_bitmap_loader(extensions[i], _al_iphone_load_image); success |= al_register_bitmap_loader_f(extensions[i], _al_iphone_load_image_f); } } #endif #ifdef ALLEGRO_MACOSX success |= _al_osx_register_image_loader(); #endif #endif if (success) iio_inited = true; _al_add_exit_func(al_shutdown_image_addon, "al_shutdown_image_addon"); return success; } /* Function: al_is_image_addon_initialized */ bool al_is_image_addon_initialized(void) { return iio_inited; } /* Function: al_shutdown_image_addon */ void al_shutdown_image_addon(void) { iio_inited = false; } /* Function: al_get_allegro_image_version */ uint32_t al_get_allegro_image_version(void) { return ALLEGRO_VERSION_INT; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/image/iio.h000066400000000000000000000003041473414355200167400ustar00rootroot00000000000000#ifndef __al_included_allegro5_iio_h #define __al_included_allegro5_iio_h #include "allegro5/internal/aintern_image_cfg.h" typedef struct PalEntry { int r, g, b, a; } PalEntry; #endif allegro5-5.2.10.1/addons/image/iphone.m000066400000000000000000000074321473414355200174600ustar00rootroot00000000000000#import #import #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern_image.h" #include "iio.h" ALLEGRO_DEBUG_CHANNEL("image") static ALLEGRO_BITMAP *really_load_image(char *buffer, int size, int flags) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; ALLEGRO_BITMAP *bmp = NULL; void *pixels = NULL; /* Note: buffer is now owned (and later freed) by the data object. */ NSData *nsdata = [NSData dataWithBytesNoCopy:buffer length:size]; UIImage *uiimage = [UIImage imageWithData:nsdata]; int w = uiimage.size.width; int h = uiimage.size.height; bool premul = !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA); /* Now we need to draw the image into a memory buffer. */ pixels = al_malloc(w * h * 4); CGFloat whitePoint[3] = { 1, 1, 1 }; CGFloat blackPoint[3] = { 0, 0, 0 }; CGFloat gamma[3] = { 2.2, 2.2, 2.2 }; CGFloat matrix[9] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; /* This sets up a color space that results in identical values * as the image data itself, which is the same as the standalone * libpng loader */ CGColorSpaceRef cs = CGColorSpaceCreateCalibratedRGB( whitePoint, blackPoint, gamma, matrix ); CGContextRef context = CGBitmapContextCreate(pixels, w, h, 8, w * 4, cs, kCGImageAlphaPremultipliedLast); CGContextSetBlendMode(context, kCGBlendModeCopy); CGContextDrawImage(context, CGRectMake(0.0, 0.0, (CGFloat)w, (CGFloat)h), uiimage.CGImage); CGContextRelease(context); CGColorSpaceRelease(cs); /* Then create a bitmap out of the memory buffer. */ bmp = al_create_bitmap(w, h); if (!bmp) goto done; ALLEGRO_LOCKED_REGION *lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888, ALLEGRO_LOCK_WRITEONLY); if (!premul) { for (int i = 0; i < h; i++) { unsigned char *src_ptr = (unsigned char *)pixels + w * 4 * i; unsigned char *dest_ptr = (unsigned char *)lock->data + lock->pitch * i; for (int x = 0; x < w; x++) { unsigned char r, g, b, a; r = *src_ptr++; g = *src_ptr++; b = *src_ptr++; a = *src_ptr++; // NOTE: avoid divide by zero by adding a fraction float alpha_mul = 255.0f / (a+0.001f); r *= alpha_mul; g *= alpha_mul; b *= alpha_mul; *dest_ptr++ = r; *dest_ptr++ = g; *dest_ptr++ = b; *dest_ptr++ = a; } } } else { for (int i = 0; i < h; i++) { memcpy(lock->data + lock->pitch * i, pixels + w * 4 * i, w * 4); } } al_unlock_bitmap(bmp); done: al_free(pixels); [pool release]; return bmp; } ALLEGRO_BITMAP *_al_iphone_load_image_f(ALLEGRO_FILE *f, int flags) { ALLEGRO_BITMAP *bmp; ALLEGRO_ASSERT(f); int64_t size = al_fsize(f); if (size <= 0) { // TODO: Read from stream until we have the whole image ALLEGRO_ERROR("Unable to determine file size.\n"); return NULL; } /* Note: This *MUST* be the Apple malloc and not any wrapper, as the * buffer will be owned and freed by the NSData object not us. */ void *buffer = al_malloc(size); al_fread(f, buffer, size); /* Really load the image now. */ bmp = really_load_image(buffer, size, flags); return bmp; } ALLEGRO_BITMAP *_al_iphone_load_image(const char *filename, int flags) { ALLEGRO_FILE *fp; ALLEGRO_BITMAP *bmp; ALLEGRO_ASSERT(filename); fp = al_fopen(filename, "rb"); if (!fp) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } bmp = _al_iphone_load_image_f(fp, flags); al_fclose(fp); return bmp; } allegro5-5.2.10.1/addons/image/jpg.c000066400000000000000000000237471473414355200167530ustar00rootroot00000000000000/* libjpeg wrapper for Allegro 5 iio addon. * by Elias Pschernig */ #include #include #include #ifdef ALLEGRO_HAVE_STDINT_H #include #endif #define BUFFER_SIZE 4096 #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern_image.h" #include "iio.h" #include #include ALLEGRO_DEBUG_CHANNEL("image") struct my_src_mgr { struct jpeg_source_mgr pub; JOCTET *buffer; ALLEGRO_FILE *fp; }; struct my_dest_mgr { struct jpeg_destination_mgr pub; JOCTET *buffer; ALLEGRO_FILE *fp; }; struct my_err_mgr { struct jpeg_error_mgr pub; jmp_buf jmpenv; }; static void init_source(j_decompress_ptr cinfo) { (void)cinfo; } static void init_destination(j_compress_ptr cinfo) { struct my_dest_mgr *dest = (void *)cinfo->dest; dest->pub.next_output_byte = dest->buffer; dest->pub.free_in_buffer = BUFFER_SIZE; } static boolean fill_input_buffer(j_decompress_ptr cinfo) { struct my_src_mgr *src = (void *)cinfo->src; src->pub.next_input_byte = src->buffer; src->pub.bytes_in_buffer = al_fread(src->fp, src->buffer, BUFFER_SIZE); return 1; } static boolean empty_output_buffer(j_compress_ptr cinfo) { struct my_dest_mgr *dest = (void *)cinfo->dest; al_fwrite(dest->fp, dest->buffer, BUFFER_SIZE); dest->pub.next_output_byte = dest->buffer; dest->pub.free_in_buffer = BUFFER_SIZE; return 1; } static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { struct my_src_mgr *src = (void *)cinfo->src; if (num_bytes <= (long)src->pub.bytes_in_buffer) { src->pub.next_input_byte += num_bytes; src->pub.bytes_in_buffer -= num_bytes; } else { long skip = num_bytes - src->pub.bytes_in_buffer; al_fseek(src->fp, skip, ALLEGRO_SEEK_CUR); src->pub.bytes_in_buffer = 0; } } static void term_source(j_decompress_ptr cinfo) { (void)cinfo; } static void term_destination(j_compress_ptr cinfo) { struct my_dest_mgr *dest = (void *)cinfo->dest; al_fwrite(dest->fp, dest->buffer, BUFFER_SIZE - dest->pub.free_in_buffer); } static void jpeg_packfile_src(j_decompress_ptr cinfo, ALLEGRO_FILE *fp, JOCTET *buffer) { struct my_src_mgr *src; if (!cinfo->src) cinfo->src = (*cinfo->mem->alloc_small) ((void *)cinfo, JPOOL_PERMANENT, sizeof *src); src = (void *)cinfo->src; src->pub.init_source = init_source; src->pub.fill_input_buffer = fill_input_buffer; src->pub.skip_input_data = skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; src->pub.term_source = term_source; src->pub.bytes_in_buffer = 0; src->buffer = buffer; src->fp = fp; } static void jpeg_packfile_dest(j_compress_ptr cinfo, ALLEGRO_FILE *fp, JOCTET *buffer) { struct my_dest_mgr *dest; if (!cinfo->dest) cinfo->dest = (*cinfo->mem->alloc_small) ((void *)cinfo, JPOOL_PERMANENT, sizeof *dest); dest = (void *)cinfo->dest; dest->pub.init_destination = init_destination; dest->pub.empty_output_buffer = empty_output_buffer; dest->pub.term_destination = term_destination; dest->pub.free_in_buffer = 0; dest->buffer = buffer; dest->fp = fp; } static void my_error_exit(j_common_ptr cinfo) { char buffer[JMSG_LENGTH_MAX]; struct my_err_mgr *jerr = (void *)cinfo->err; jerr->pub.format_message(cinfo, buffer); ALLEGRO_ERROR("jpeg error: %s\n", buffer); longjmp(jerr->jmpenv, 1); } /* We keep data for load_jpg_entry_helper in a structure allocated in the * caller's stack frame to avoid problems with automatic variables being * undefined after a longjmp. */ struct load_jpg_entry_helper_data { bool error; ALLEGRO_BITMAP *bmp; JOCTET *buffer; unsigned char *row; }; static void load_jpg_entry_helper(ALLEGRO_FILE *fp, struct load_jpg_entry_helper_data *data, int flags) { struct jpeg_decompress_struct cinfo; struct my_err_mgr jerr; ALLEGRO_LOCKED_REGION *lock; int w, h, s; /* ALLEGRO_NO_PREMULTIPLIED_ALPHA does not apply. * ALLEGRO_KEEP_INDEX does not apply. */ (void)flags; data->error = false; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.jmpenv) != 0) { /* Longjmp'd. */ data->error = true; goto longjmp_error; } data->buffer = al_malloc(BUFFER_SIZE); if (!data->buffer) { data->error = true; goto error; } jpeg_create_decompress(&cinfo); jpeg_packfile_src(&cinfo, fp, data->buffer); jpeg_read_header(&cinfo, true); jpeg_start_decompress(&cinfo); w = cinfo.output_width; h = cinfo.output_height; s = cinfo.output_components; /* Only one and three components make sense in a JPG file. */ if (s != 1 && s != 3) { data->error = true; ALLEGRO_ERROR("%d components makes no sense\n", s); goto error; } data->bmp = al_create_bitmap(w, h); if (!data->bmp) { data->error = true; ALLEGRO_ERROR("%dx%d bitmap creation failed\n", w, h); goto error; } /* Allegro's pixel format is endian independent, so that in * ALLEGRO_PIXEL_FORMAT_RGB_888 the lower 8 bits always hold the Blue * component. On a little endian system this is in byte 0. On a big * endian system this is in byte 2. * * libjpeg expects byte 0 to hold the Red component, byte 1 to hold the * Green component, byte 2 to hold the Blue component. Hence on little * endian systems we need the opposite format, ALLEGRO_PIXEL_FORMAT_BGR_888. */ #ifdef ALLEGRO_BIG_ENDIAN lock = al_lock_bitmap(data->bmp, ALLEGRO_PIXEL_FORMAT_RGB_888, ALLEGRO_LOCK_WRITEONLY); #else lock = al_lock_bitmap(data->bmp, ALLEGRO_PIXEL_FORMAT_BGR_888, ALLEGRO_LOCK_WRITEONLY); #endif if (s == 3) { /* Colour. */ int y; for (y = cinfo.output_scanline; y < h; y = cinfo.output_scanline) { unsigned char *out[1]; out[0] = ((unsigned char *)lock->data) + y * lock->pitch; jpeg_read_scanlines(&cinfo, (void *)out, 1); } } else if (s == 1) { /* Greyscale. */ unsigned char *in; unsigned char *out; int x, y; data->row = al_malloc(w); for (y = cinfo.output_scanline; y < h; y = cinfo.output_scanline) { jpeg_read_scanlines(&cinfo, (void *)&data->row, 1); in = data->row; out = ((unsigned char *)lock->data) + y * lock->pitch; for (x = 0; x < w; x++) { *out++ = *in; *out++ = *in; *out++ = *in; in++; } } } error: jpeg_finish_decompress(&cinfo); longjmp_error: jpeg_destroy_decompress(&cinfo); if (data->bmp) { if (al_is_bitmap_locked(data->bmp)) { al_unlock_bitmap(data->bmp); } if (data->error) { al_destroy_bitmap(data->bmp); data->bmp = NULL; } } al_free(data->buffer); al_free(data->row); } ALLEGRO_BITMAP *_al_load_jpg_f(ALLEGRO_FILE *fp, int flags) { struct load_jpg_entry_helper_data data; memset(&data, 0, sizeof(data)); load_jpg_entry_helper(fp, &data, flags); return data.bmp; } /* See comment about load_jpg_entry_helper_data. */ struct save_jpg_entry_helper_data { bool error; JOCTET *buffer; }; static void save_jpg_entry_helper(ALLEGRO_FILE *fp, ALLEGRO_BITMAP *bmp, struct save_jpg_entry_helper_data *data) { struct jpeg_compress_struct cinfo; struct my_err_mgr jerr; ALLEGRO_LOCKED_REGION *lock; data->error = false; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.jmpenv)) { /* Longjmp'd. */ data->error = true; goto longjmp_error; } data->buffer = al_malloc(BUFFER_SIZE); if (!data->buffer) { data->error = true; goto error; } jpeg_create_compress(&cinfo); jpeg_packfile_dest(&cinfo, fp, data->buffer); cinfo.image_width = al_get_bitmap_width(bmp); cinfo.image_height = al_get_bitmap_height(bmp); cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); const char* level = al_get_config_value(al_get_system_config(), "image", "jpeg_quality_level"); jpeg_set_quality(&cinfo, level ? strtol(level, NULL, 10) : 75, true); jpeg_start_compress(&cinfo, 1); /* See comment in load_jpg_entry_helper. */ #ifdef ALLEGRO_BIG_ENDIAN lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_RGB_888, ALLEGRO_LOCK_READONLY); #else lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_BGR_888, ALLEGRO_LOCK_READONLY); #endif while (cinfo.next_scanline < cinfo.image_height) { unsigned char *row[1]; row[0] = ((unsigned char *)lock->data) + (signed)cinfo.next_scanline * lock->pitch; jpeg_write_scanlines(&cinfo, (void *)row, 1); } error: jpeg_finish_compress(&cinfo); longjmp_error: jpeg_destroy_compress(&cinfo); if (al_is_bitmap_locked(bmp)) { al_unlock_bitmap(bmp); } al_free(data->buffer); } bool _al_save_jpg_f(ALLEGRO_FILE *fp, ALLEGRO_BITMAP *bmp) { struct save_jpg_entry_helper_data data; memset(&data, 0, sizeof(data)); save_jpg_entry_helper(fp, bmp, &data); return !data.error; } ALLEGRO_BITMAP *_al_load_jpg(char const *filename, int flags) { ALLEGRO_FILE *fp; ALLEGRO_BITMAP *bmp; ALLEGRO_ASSERT(filename); fp = al_fopen(filename, "rb"); if (!fp) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } bmp = _al_load_jpg_f(fp, flags); al_fclose(fp); return bmp; } bool _al_save_jpg(char const *filename, ALLEGRO_BITMAP *bmp) { ALLEGRO_FILE *fp; bool retsave; bool retclose; ALLEGRO_ASSERT(filename); ALLEGRO_ASSERT(bmp); fp = al_fopen(filename, "wb"); if (!fp) { ALLEGRO_ERROR("Unable to open file %s for writing\n", filename); return false; } retsave = _al_save_jpg_f(fp, bmp); retclose = al_fclose(fp); return retsave && retclose; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/image/macosx.m000066400000000000000000000215161473414355200174670ustar00rootroot00000000000000#import #import #import #include "allegro5/allegro.h" #include "allegro5/fshook.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_image.h" #include "iio.h" #if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 typedef float CGFloat; #endif ALLEGRO_DEBUG_CHANNEL("OSXIIO") // Just to make sure it's never al_malloc. #define apple_malloc malloc static ALLEGRO_BITMAP *really_load_image(char *buffer, int size, int flags) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; ALLEGRO_BITMAP *bmp = NULL; void *pixels = NULL; /* Note: buffer is now owned (and later freed) by the data object. */ NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:buffer length:size]; NSImage *image = [[NSImage alloc] initWithData:nsdata]; [nsdata release]; bool premul = !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA); if (!image) goto done; /* Get the image representations */ NSArray *reps = [image representations]; NSImageRep *image_rep = [reps objectAtIndex: 0]; if (!image_rep) { [image release]; goto done; } /* Get the actual size in pixels from the representation */ unsigned char *data[5]; // TODO: We should check it really is a bitmap representation. NSBitmapImageRep *bitmap_rep = (NSBitmapImageRep *)image_rep; [bitmap_rep getBitmapDataPlanes:data]; pixels = data[0]; int w = [image_rep pixelsWide]; int h = [image_rep pixelsHigh]; int bits = [bitmap_rep bitsPerPixel]; int samples = bits / 8; ALLEGRO_DEBUG("Read image of size %dx%dx%d\n", w, h, bits); /* Then create a bitmap out of the memory buffer. */ bmp = al_create_bitmap(w, h); if (bmp) { ALLEGRO_LOCKED_REGION *lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_WRITEONLY); int i, j; { for (i = 0; i < h; i++) { uint8_t *data_row = (uint8_t *) lock->data + lock->pitch * i; uint8_t *source_row = (uint8_t *) pixels + w * samples * i; if (samples == 4) { if (premul) { for (j = 0; j < w; j++) { int r, g, b, a; r = source_row[j * 4 + 0]; g = source_row[j * 4 + 1]; b = source_row[j * 4 + 2]; a = source_row[j * 4 + 3]; data_row[j * 4 + 0] = r * a / 255; data_row[j * 4 + 1] = g * a / 255; data_row[j * 4 + 2] = b * a / 255; data_row[j * 4 + 3] = a; } } else memcpy(data_row, source_row, w * 4); } else if (samples == 3) { for (j = 0; j < w; j++) { data_row[j * 4 + 0] = source_row[j * 3 + 0]; data_row[j * 4 + 1] = source_row[j * 3 + 1]; data_row[j * 4 + 2] = source_row[j * 3 + 2]; data_row[j * 4 + 3] = 255; } } else if (samples == 2) { for (j = 0; j < w; j++) { int a = data_row[j * 4 + 3] = source_row[j * 2 + 1]; if (!premul) a = 255; data_row[j * 4 + 0] = source_row[j * 2 + 0] * a / 255; data_row[j * 4 + 1] = source_row[j * 2 + 0] * a / 255; data_row[j * 4 + 2] = source_row[j * 2 + 0] * a / 255; } } else if (samples == 1) { for (j = 0; j < w; j++) { data_row[j * 4 + 0] = source_row[j]; data_row[j * 4 + 1] = source_row[j]; data_row[j * 4 + 2] = source_row[j]; data_row[j * 4 + 3] = 255; } } } } al_unlock_bitmap(bmp); } [image release]; done: [pool drain]; return bmp; } static ALLEGRO_BITMAP *_al_osx_load_image_f(ALLEGRO_FILE *f, int flags) { ALLEGRO_BITMAP *bmp; ASSERT(f); int64_t size = al_fsize(f); if (size <= 0) { // TODO: Read from stream until we have the whole image ALLEGRO_ERROR("Couldn't determine file size.\n"); return NULL; } /* Note: This *MUST* be the Apple malloc and not any wrapper, as the * buffer will be owned and freed by the NSData object not us. */ void *buffer = apple_malloc(size); al_fread(f, buffer, size); /* Really load the image now. */ bmp = really_load_image(buffer, size, flags); return bmp; } static ALLEGRO_BITMAP *_al_osx_load_image(const char *filename, int flags) { ALLEGRO_FILE *fp; ALLEGRO_BITMAP *bmp; ASSERT(filename); ALLEGRO_DEBUG("Using native loader to read %s\n", filename); fp = al_fopen(filename, "rb"); if (!fp) { ALLEGRO_ERROR("Unable open %s for reading.\n", filename); return NULL; } bmp = _al_osx_load_image_f(fp, flags); al_fclose(fp); return bmp; } extern NSImage* NSImageFromAllegroBitmap(ALLEGRO_BITMAP* bmp); bool _al_osx_save_image_f(ALLEGRO_FILE *f, const char *ident, ALLEGRO_BITMAP *bmp) { NSBitmapImageFileType type; if (!strcmp(ident, ".bmp")) { type = NSBMPFileType; } else if (!strcmp(ident, ".jpg") || !strcmp(ident, ".jpeg")) { type = NSJPEGFileType; } else if (!strcmp(ident, ".gif")) { type = NSGIFFileType; } else if (!strcmp(ident, ".tif") || !strcmp(ident, ".tiff")) { type = NSTIFFFileType; } else if (!strcmp(ident, ".png")) { type = NSPNGFileType; } else { ALLEGRO_ERROR("Unsupported image format: %s.\n", ident); return false; } NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; NSImage *image = NSImageFromAllegroBitmap(bmp); NSArray *reps = [image representations]; NSData *nsdata = [NSBitmapImageRep representationOfImageRepsInArray: reps usingType: type properties: [NSDictionary dictionary]]; size_t size = (size_t)[nsdata length]; bool ret = al_fwrite(f, [nsdata bytes], size) == size; [image release]; [pool drain]; return ret; } bool _al_osx_save_image(const char *filename, ALLEGRO_BITMAP *bmp) { ALLEGRO_FILE *fp; bool retsave = false; bool retclose = false; fp = al_fopen(filename, "wb"); if (fp) { ALLEGRO_PATH *path = al_create_path(filename); if (path) { retsave = _al_osx_save_image_f(fp, al_get_path_extension(path), bmp); al_destroy_path(path); } retclose = al_fclose(fp); } else { ALLEGRO_ERROR("Unable open %s for writing.\n", filename); } return retsave && retclose; } bool _al_osx_save_png_f(ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp) { return _al_osx_save_image_f(f, ".png", bmp); } bool _al_osx_save_jpg_f(ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp) { return _al_osx_save_image_f(f, ".jpg", bmp); } bool _al_osx_save_tif_f(ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp) { return _al_osx_save_image_f(f, ".tif", bmp); } bool _al_osx_save_gif_f(ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp) { return _al_osx_save_image_f(f, ".gif", bmp); } bool _al_osx_register_image_loader(void) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; bool success = false; int num_types; int i; /* Get a list of all supported image types */ NSArray *file_types = [NSImage imageFileTypes]; num_types = [file_types count]; for (i = 0; i < num_types; i++) { NSString *str = @"."; NSString *type_str = [str stringByAppendingString: [file_types objectAtIndex: i]]; const char *s = [type_str UTF8String]; /* Skip image types Allegro supports built-in */ if (!_al_stricmp(s, ".tga") || !_al_stricmp(s, ".bmp") || !_al_stricmp(s, ".pcx")) { continue; } /* Unload previous loader, if any */ al_register_bitmap_loader(s, NULL); al_register_bitmap_loader_f(s, NULL); ALLEGRO_DEBUG("Registering native loader for bitmap type %s\n", s); success |= al_register_bitmap_loader(s, _al_osx_load_image); success |= al_register_bitmap_loader_f(s, _al_osx_load_image_f); } char const *extensions[] = { ".tif", ".tiff", ".gif", ".png", ".jpg", ".jpeg", NULL }; for (i = 0; extensions[i]; i++) { ALLEGRO_DEBUG("Registering native saver for bitmap type %s\n", extensions[i]); success |= al_register_bitmap_saver(extensions[i], _al_osx_save_image); } success |= al_register_bitmap_saver_f(".tif", _al_osx_save_tif_f); success |= al_register_bitmap_saver_f(".tiff", _al_osx_save_tif_f); success |= al_register_bitmap_saver_f(".gif", _al_osx_save_gif_f); success |= al_register_bitmap_saver_f(".png", _al_osx_save_png_f); success |= al_register_bitmap_saver_f(".jpg", _al_osx_save_jpg_f); success |= al_register_bitmap_saver_f(".jpeg", _al_osx_save_jpg_f); [pool drain]; return success; } allegro5-5.2.10.1/addons/image/pcx.c000066400000000000000000000200141473414355200167450ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern_image.h" #include "iio.h" ALLEGRO_DEBUG_CHANNEL("image") /* Do NOT simplify this to just (x), it doesn't work in MSVC. */ #define INT_TO_BOOL(x) ((x) != 0) ALLEGRO_BITMAP *_al_load_pcx_f(ALLEGRO_FILE *f, int flags) { ALLEGRO_BITMAP *b; int c; int width, height; int bpp, bytes_per_line; int x, xx, y; char ch; ALLEGRO_LOCKED_REGION *lr; unsigned char *buf; PalEntry pal[256]; bool keep_index; ASSERT(f); al_fgetc(f); /* skip manufacturer ID */ al_fgetc(f); /* skip version flag */ al_fgetc(f); /* skip encoding flag */ char color_plane = al_fgetc(f); if (color_plane != 8) { /* we like 8 bit color planes */ ALLEGRO_ERROR("Invalid color plane %d.\n", color_plane); return NULL; } width = -(al_fread16le(f)); /* xmin */ height = -(al_fread16le(f)); /* ymin */ width += al_fread16le(f) + 1; /* xmax */ height += al_fread16le(f) + 1; /* ymax */ al_fread32le(f); /* skip DPI values */ for (c = 0; c < 16 * 3; c++) { /* skip the 16 color palette */ al_fgetc(f); } al_fgetc(f); bpp = al_fgetc(f) * 8; /* how many color planes? */ if ((bpp != 8) && (bpp != 24)) { ALLEGRO_ERROR("Invalid bpp %d.\n", color_plane); return NULL; } bytes_per_line = al_fread16le(f); /* It can only be this because we only support 8 bit planes */ if (bytes_per_line != width) { ALLEGRO_ERROR("Invalid bytes per line %d\n", bytes_per_line); return NULL; } for (c = 0; c < 60; c++) /* skip some more junk */ al_fgetc(f); if (al_feof(f) || al_ferror(f)) { ALLEGRO_ERROR("Unexpected EOF/error.\n"); return NULL; } b = al_create_bitmap(width, height); if (!b) { ALLEGRO_ERROR("Failed to create bitmap.\n"); return NULL; } keep_index = INT_TO_BOOL(flags & ALLEGRO_KEEP_INDEX); al_set_errno(0); if (bpp == 8) { /* The palette comes after the image data. We need to to keep the * whole image in a temporary buffer before mapping the final colours. */ buf = (unsigned char *)al_malloc(bytes_per_line * height); } else { /* We can read one line at a time. */ buf = (unsigned char *)al_malloc(bytes_per_line * 3); } if (bpp == 8 && keep_index) { lr = al_lock_bitmap(b, ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8, ALLEGRO_LOCK_WRITEONLY); } else { lr = al_lock_bitmap(b, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_WRITEONLY); } if (!lr) { ALLEGRO_ERROR("Failed to lock bitmap.\n"); al_free(buf); return NULL; } xx = 0; /* index into buf, only for bpp = 8 */ for (y = 0; y < height; y++) { /* read RLE encoded PCX data */ x = 0; while (x < bytes_per_line * bpp / 8) { ch = al_fgetc(f); if ((ch & 0xC0) == 0xC0) { /* a run */ c = (ch & 0x3F); ch = al_fgetc(f); } else { c = 1; /* single pixel */ } if (bpp == 8) { while (c--) { if (x < width) /* ignore padding */ buf[xx++] = ch; x++; } } else { while (c--) { if (x < width * 3) /* ignore padding */ buf[x] = ch; x++; } } } if (bpp == 24) { char *dest = (char*)lr->data + y*lr->pitch; for (x = 0; x < width; x++) { dest[x*4 ] = buf[x]; dest[x*4 + 1] = buf[x + width]; dest[x*4 + 2] = buf[x + width * 2]; dest[x*4 + 3] = 255; } } } if (bpp == 8) { /* look for a 256 color palette */ while ((c = al_fgetc(f)) != EOF) { if (c == 12) { for (c = 0; c < 256; c++) { pal[c].r = al_fgetc(f); pal[c].g = al_fgetc(f); pal[c].b = al_fgetc(f); } break; } } for (y = 0; y < height; y++) { char *dest = (char*)lr->data + y*lr->pitch; for (x = 0; x < width; x++) { int index = buf[y * width + x]; if (keep_index) { dest[x] = index; } else { dest[x*4 ] = pal[index].r; dest[x*4 + 1] = pal[index].g; dest[x*4 + 2] = pal[index].b; dest[x*4 + 3] = 255; } } } } al_unlock_bitmap(b); al_free(buf); if (al_get_errno()) { ALLEGRO_ERROR("Error detected: %d.\n", al_get_errno()); al_destroy_bitmap(b); return NULL; } return b; } bool _al_save_pcx_f(ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp) { int c; int x, y; int i; int w, h; unsigned char *buf; ASSERT(f); ASSERT(bmp); al_set_errno(0); w = al_get_bitmap_width(bmp); h = al_get_bitmap_height(bmp); al_fputc(f, 10); /* manufacturer */ al_fputc(f, 5); /* version */ al_fputc(f, 1); /* run length encoding */ al_fputc(f, 8); /* 8 bits per pixel */ al_fwrite16le(f, 0); /* xmin */ al_fwrite16le(f, 0); /* ymin */ al_fwrite16le(f, w - 1); /* xmax */ al_fwrite16le(f, h - 1); /* ymax */ al_fwrite16le(f, 320); /* HDpi */ al_fwrite16le(f, 200); /* VDpi */ for (c = 0; c < 16 * 3; c++) { al_fputc(f, 0); } al_fputc(f, 0); /* reserved */ al_fputc(f, 3); /* color planes */ al_fwrite16le(f, w); /* number of bytes per scanline */ al_fwrite16le(f, 1); /* color palette */ al_fwrite16le(f, w); /* hscreen size */ al_fwrite16le(f, h); /* vscreen size */ for (c = 0; c < 54; c++) /* filler */ al_fputc(f, 0); buf = al_malloc(w * 3); al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); for (y = 0; y < h; y++) { /* for each scanline... */ for (x = 0; x < w; x++) { ALLEGRO_COLOR c = al_get_pixel(bmp, x, y); unsigned char r, g, b; al_unmap_rgb(c, &r, &g, &b); buf[x] = r; buf[x + w] = g; buf[x + w * 2] = b; } for (i = 0; i < 3; i++) { int color; int count; x = 0; for (;;) { count = 0; color = buf[x + w * i]; do { count++; x++; } while ((count < 63) && (x < w) && (color == buf[x + w * i])); al_fputc(f, count | 0xC0); al_fputc(f, color); if (x >= w) break; } } } al_free(buf); al_unlock_bitmap(bmp); if (al_get_errno()) { ALLEGRO_ERROR("Error detected: %d.\n", al_get_errno()); return false; } else return true; } ALLEGRO_BITMAP *_al_load_pcx(const char *filename, int flags) { ALLEGRO_FILE *f; ALLEGRO_BITMAP *bmp; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } bmp = _al_load_pcx_f(f, flags); al_fclose(f); return bmp; } bool _al_save_pcx(const char *filename, ALLEGRO_BITMAP *bmp) { ALLEGRO_FILE *f; bool retsave; bool retclose; ASSERT(filename); f = al_fopen(filename, "wb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for writing.\n", filename); return false; } retsave = _al_save_pcx_f(f, bmp); retclose = al_fclose(f); return retsave && retclose; } bool _al_identify_pcx(ALLEGRO_FILE *f) { uint8_t x[4]; al_fread(f, x, 4); if (x[0] != 0x0a) // PCX must start with 0x0a return false; if (x[1] == 1 || x[1] > 5) // version must be 0, 2, 3, 4, 5 return false; if (x[2] > 1) // compression must be 0 or 1 return false; if (x[3] != 8) // only 8-bit PCX files supported by Allegro! return false; return true; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/image/png.c000066400000000000000000000416761473414355200167600ustar00rootroot00000000000000/* loadpng, Allegro wrapper routines for libpng * by Peter Wang (tjaden@users.sf.net). */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern_image.h" #include "iio.h" ALLEGRO_DEBUG_CHANNEL("image") /* get_gamma: * Get screen gamma value one of three ways. */ static double get_gamma(void) { double gamma = -1.0; const char* config = al_get_config_value(al_get_system_config(), "image", "png_screen_gamma"); if (config) { gamma = strtod(config, NULL); } if (gamma == -1.0) { /* Use the environment variable if available. * 2.2 is a good guess for PC monitors. * 1.1 is good for my laptop. */ const char *gamma_str = getenv("SCREEN_GAMMA"); return (gamma_str) ? strtod(gamma_str, NULL) : 2.2; } return gamma; } static void user_error_fn(png_structp png_ptr, png_const_charp message) { jmp_buf *jmpbuf = (jmp_buf *)png_get_error_ptr(png_ptr); ALLEGRO_DEBUG("PNG error: %s\n", message); longjmp(*jmpbuf, 1); } /***************************************************************************** * Loading routines ****************************************************************************/ /* read_data: * Custom read function to use Allegro packfile routines, * rather than C streams (so we can read from datafiles!) */ static void read_data(png_structp png_ptr, png_bytep data, size_t length) { ALLEGRO_FILE *f = (ALLEGRO_FILE *)png_get_io_ptr(png_ptr); if ((png_uint_32) al_fread(f, data, length) != length) png_error(png_ptr, "read error (loadpng calling al_fs_entry_read)"); } /* check_if_png: * Check if input file is really PNG format. */ #define PNG_BYTES_TO_CHECK 4 static int check_if_png(ALLEGRO_FILE *fp) { unsigned char buf[PNG_BYTES_TO_CHECK]; ALLEGRO_ASSERT(fp); if (al_fread(fp, buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) return 0; return (png_sig_cmp(buf, (png_size_t) 0, PNG_BYTES_TO_CHECK) == 0); } /* really_load_png: * Worker routine, used by load_png and load_memory_png. */ static ALLEGRO_BITMAP *really_load_png(png_structp png_ptr, png_infop info_ptr, int flags) { ALLEGRO_BITMAP *bmp; png_uint_32 width, height, rowbytes, real_rowbytes; int bit_depth, color_type, interlace_type; double image_gamma, screen_gamma; int intent; int bpp; int number_passes, pass; int num_trans = 0; PalEntry pal[256]; png_bytep trans; ALLEGRO_LOCKED_REGION *lock; unsigned char *buf; unsigned char *dest; bool premul = !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA); bool index_only; ALLEGRO_ASSERT(png_ptr && info_ptr); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8)) png_set_expand(png_ptr); /* Adds a full alpha channel if there is transparency information * in a tRNS chunk. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { if (!(color_type & PNG_COLOR_MASK_PALETTE)) png_set_tRNS_to_alpha(png_ptr); png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); } /* Convert 16-bits per colour component to 8-bits per colour component. */ if (bit_depth == 16) png_set_strip_16(png_ptr); /* Convert grayscale to RGB triplets */ if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_gray_to_rgb(png_ptr); /* Optionally, tell libpng to handle the gamma correction for us. */ screen_gamma = get_gamma(); if (screen_gamma != 0.0) { if (png_get_sRGB(png_ptr, info_ptr, &intent)) png_set_gamma(png_ptr, screen_gamma, 0.45455); else { if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) png_set_gamma(png_ptr, screen_gamma, image_gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45455); } } /* Turn on interlace handling. */ number_passes = png_set_interlace_handling(png_ptr); /* Call to gamma correct and add the background to the palette * and update info structure. */ png_read_update_info(png_ptr, info_ptr); /* Palettes. */ if (color_type & PNG_COLOR_MASK_PALETTE) { int num_palette, i; png_colorp palette; if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) { /* We don't actually dither, we just copy the palette. */ for (i = 0; ((i < num_palette) && (i < 256)); i++) { pal[i].r = palette[i].red; pal[i].g = palette[i].green; pal[i].b = palette[i].blue; } for (; i < 256; i++) pal[i].r = pal[i].g = pal[i].b = 0; } } rowbytes = png_get_rowbytes(png_ptr, info_ptr); /* Allocate the memory to hold the image using the fields of info_ptr. */ bpp = rowbytes * 8 / width; /* Allegro cannot handle less than 8 bpp. */ if (bpp < 8) bpp = 8; if ((bpp == 24) || (bpp == 32)) { #ifdef ALLEGRO_BIG_ENDIAN png_set_bgr(png_ptr); png_set_swap_alpha(png_ptr); #endif } bmp = al_create_bitmap(width, height); if (!bmp) { ALLEGRO_ERROR("al_create_bitmap failed while loading PNG.\n"); return NULL; } // TODO: can this be different from rowbytes? real_rowbytes = ((bpp + 7) / 8) * width; if (interlace_type == PNG_INTERLACE_ADAM7) buf = al_malloc(real_rowbytes * height); else buf = al_malloc(real_rowbytes); if (bpp == 8 && (color_type & PNG_COLOR_MASK_PALETTE) && (flags & ALLEGRO_KEEP_INDEX)) { lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8, ALLEGRO_LOCK_WRITEONLY); index_only = true; } else { lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_WRITEONLY); index_only = false; } /* Read the image, one line at a time (easier to debug!) */ for (pass = 0; pass < number_passes; pass++) { png_uint_32 y; unsigned int i; unsigned char *ptr; dest = lock->data; for (y = 0; y < height; y++) { unsigned char *dest_row_start = dest; /* For interlaced pictures, the row needs to be initialized with * the contents of the previous pass. */ if (interlace_type == PNG_INTERLACE_ADAM7) ptr = buf + y * real_rowbytes; else ptr = buf; png_read_row(png_ptr, NULL, ptr); switch (bpp) { case 8: if (index_only) { for (i = 0; i < width; i++) { *(dest++) = *(ptr++); } } else if (color_type & PNG_COLOR_MASK_PALETTE) { for (i = 0; i < width; i++) { int pix = ptr[0]; ptr++; dest[0] = pal[pix].r; dest[1] = pal[pix].g; dest[2] = pal[pix].b; if (pix < num_trans) { int a = trans[pix]; dest[3] = a; if (premul) { dest[0] = dest[0] * a / 255; dest[1] = dest[1] * a / 255; dest[2] = dest[2] * a / 255; } } else { dest[3] = 255; } dest += 4; } } else { for (i = 0; i < width; i++) { int pix = ptr[0]; ptr++; *(dest++) = pix; *(dest++) = pix; *(dest++) = pix; *(dest++) = 255; } } break; case 24: for (i = 0; i < width; i++) { uint32_t pix = _AL_READ3BYTES(ptr); ptr += 3; *(dest++) = pix & 0xff; *(dest++) = (pix >> 8) & 0xff; *(dest++) = (pix >> 16) & 0xff; *(dest++) = 255; } break; case 32: for (i = 0; i < width; i++) { uint32_t pix = *(uint32_t*)ptr; int r = pix & 0xff; int g = (pix >> 8) & 0xff; int b = (pix >> 16) & 0xff; int a = (pix >> 24) & 0xff; ptr += 4; if (premul) { r = r * a / 255; g = g * a / 255; b = b * a / 255; } *(dest++) = r; *(dest++) = g; *(dest++) = b; *(dest++) = a; } break; default: ALLEGRO_ASSERT(bpp == 8 || bpp == 24 || bpp == 32); break; } dest = dest_row_start + lock->pitch; } } al_unlock_bitmap(bmp); al_free(buf); /* Read rest of file, and get additional chunks in info_ptr. */ png_read_end(png_ptr, info_ptr); return bmp; } /* Load a PNG file from disk, doing colour coversion if required. */ ALLEGRO_BITMAP *_al_load_png_f(ALLEGRO_FILE *fp, int flags) { jmp_buf jmpbuf; ALLEGRO_BITMAP *bmp; png_structp png_ptr; png_infop info_ptr; ALLEGRO_ASSERT(fp); if (!check_if_png(fp)) { ALLEGRO_ERROR("Not a png.\n"); return NULL; } /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (void *)NULL, NULL, NULL); if (!png_ptr) { ALLEGRO_ERROR("png_ptr == NULL\n"); return NULL; } /* Allocate/initialize the memory for image information. */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); ALLEGRO_ERROR("png_create_info_struct failed\n"); return NULL; } /* Set error handling. */ if (setjmp(jmpbuf)) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); /* If we get here, we had a problem reading the file */ ALLEGRO_ERROR("Error reading PNG file\n"); return NULL; } png_set_error_fn(png_ptr, jmpbuf, user_error_fn, NULL); /* Use Allegro packfile routines. */ png_set_read_fn(png_ptr, fp, (png_rw_ptr) read_data); /* We have already read some of the signature. */ png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); /* Really load the image now. */ bmp = really_load_png(png_ptr, info_ptr, flags); /* Clean up after the read, and free any memory allocated. */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); return bmp; } ALLEGRO_BITMAP *_al_load_png(const char *filename, int flags) { ALLEGRO_FILE *fp; ALLEGRO_BITMAP *bmp; ALLEGRO_ASSERT(filename); fp = al_fopen(filename, "rb"); if (!fp) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } bmp = _al_load_png_f(fp, flags); al_fclose(fp); return bmp; } /***************************************************************************** * Saving routines ****************************************************************************/ /* write_data: * Custom write function to use Allegro packfile routines, * rather than C streams. */ static void write_data(png_structp png_ptr, png_bytep data, size_t length) { ALLEGRO_FILE *f = (ALLEGRO_FILE *)png_get_io_ptr(png_ptr); if ((png_uint_32) al_fwrite(f, data, length) != length) png_error(png_ptr, "write error (loadpng calling al_fs_entry_write)"); } /* Don't think Allegro has any problem with buffering * (rather, Allegro provides no way to flush packfiles). */ static void flush_data(png_structp png_ptr) { (void)png_ptr; } /* translate_compression_level: * Translate string with config value into proper zlib's * compression level. Assumes default on NULL. */ static int translate_compression_level(const char* value) { if (!value || strcmp(value, "default") == 0) { return Z_DEFAULT_COMPRESSION; } if (strcmp(value, "best") == 0) { return Z_BEST_COMPRESSION; } if (strcmp(value, "fastest") == 0) { return Z_BEST_SPEED; } if (strcmp(value, "none") == 0) { return Z_NO_COMPRESSION; } return strtol(value, NULL, 10); } /* save_rgba: * Core save routine for 32 bpp images. */ static int save_rgba(png_structp png_ptr, ALLEGRO_BITMAP *bmp) { const int bmp_h = al_get_bitmap_height(bmp); ALLEGRO_LOCKED_REGION *lock; int y; lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_READONLY); if (!lock) return 0; for (y = 0; y < bmp_h; y++) { unsigned char *p = (unsigned char *)lock->data + lock->pitch * y; png_write_row(png_ptr, p); } al_unlock_bitmap(bmp); return 1; } /* Writes a non-interlaced, no-frills PNG, taking the usual save_xyz * parameters. Returns non-zero on error. */ bool _al_save_png_f(ALLEGRO_FILE *fp, ALLEGRO_BITMAP *bmp) { jmp_buf jmpbuf; png_structp png_ptr = NULL; png_infop info_ptr = NULL; int colour_type; /* Create and initialize the png_struct with the * desired error handler functions. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (void *)NULL, NULL, NULL); if (!png_ptr) { ALLEGRO_ERROR("Unable to create PNG write struct.\n"); goto Error; } /* Allocate/initialize the image information data. */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { ALLEGRO_ERROR("Unable to create PNG info struct.\n"); goto Error; } /* Set error handling. */ if (setjmp(jmpbuf)) { ALLEGRO_ERROR("Failed to call setjmp.\n"); goto Error; } png_set_error_fn(png_ptr, jmpbuf, user_error_fn, NULL); /* Use packfile routines. */ png_set_write_fn(png_ptr, fp, (png_rw_ptr) write_data, flush_data); /* Set the image information here. Width and height are up to 2^31, * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. */ colour_type = PNG_COLOR_TYPE_RGB_ALPHA; /* Set compression level. */ int z_level = translate_compression_level( al_get_config_value(al_get_system_config(), "image", "png_compression_level") ); png_set_compression_level(png_ptr, z_level); png_set_IHDR(png_ptr, info_ptr, al_get_bitmap_width(bmp), al_get_bitmap_height(bmp), 8, colour_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Optionally write comments into the image ... Nah. */ /* Write the file header information. */ png_write_info(png_ptr, info_ptr); /* Once we write out the header, the compression type on the text * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again * at the end. */ if (!save_rgba(png_ptr, bmp)) { ALLEGRO_ERROR("save_rgba failed.\n"); goto Error; } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); return true; Error: if (png_ptr) { if (info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr); else png_destroy_write_struct(&png_ptr, NULL); } return false; } bool _al_save_png(const char *filename, ALLEGRO_BITMAP *bmp) { ALLEGRO_FILE *fp; bool retsave; bool retclose; ALLEGRO_ASSERT(filename); ALLEGRO_ASSERT(bmp); fp = al_fopen(filename, "wb"); if (!fp) { ALLEGRO_ERROR("Unable to open file %s for writing\n", filename); return false; } retsave = _al_save_png_f(fp, bmp); retclose = al_fclose(fp); return retsave && retclose; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/image/tga.c000066400000000000000000000454361473414355200167450ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * TGA reader. * * By Tim Gunn. * * RLE support added by Michal Mertl and Salvador Eduardo Tropea. * * Palette reading improved by Peter Wang. * * Big-endian support added by Eric Botcazou. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern_image.h" #include "allegro5/internal/aintern_pixels.h" #include "iio.h" ALLEGRO_DEBUG_CHANNEL("image") /* raw_tga_read8: * Helper for reading 256-color raw data from TGA files. * Returns pointer past the end. */ static INLINE unsigned char *raw_tga_read8(unsigned char *b, int w, ALLEGRO_FILE *f) { return b + al_fread(f, b, w); } /* rle_tga_read8: * Helper for reading 256-color RLE data from TGA files. * Returns pointer past the end or NULL for error. */ static unsigned char *rle_tga_read8(unsigned char *b, int w, ALLEGRO_FILE *f) { int value, count, c = 0; do { count = al_fgetc(f); if (count & 0x80) { /* run-length packet */ count = (count & 0x7F) + 1; c += count; if (c > w) { /* Stepped past the end of the line, error */ return NULL; } value = al_fgetc(f); while (count--) *b++ = value; } else { /* raw packet */ count++; c += count; if (c > w) { /* Stepped past the end of the line, error */ return NULL; } b = raw_tga_read8(b, count, f); } } while (c < w); return b; } /* single_tga_read32: * Helper for reading a single 32-bit data from TGA files. */ static INLINE int32_t single_tga_read32(ALLEGRO_FILE *f) { return al_fread32le(f); } /* raw_tga_read32: * Helper for reading 32-bit raw data from TGA files. * Returns pointer past the end. */ static unsigned int *raw_tga_read32(unsigned int *b, int w, ALLEGRO_FILE *f) { while (w--) *b++ = single_tga_read32(f); return b; } /* rle_tga_read32: * Helper for reading 32-bit RLE data from TGA files. * Returns pointer past the end or NULL for error. */ static unsigned int *rle_tga_read32(unsigned int *b, int w, ALLEGRO_FILE *f) { int color, count, c = 0; do { count = al_fgetc(f); if (count & 0x80) { /* run-length packet */ count = (count & 0x7F) + 1; c += count; if (c > w) { /* Stepped past the end of the line, error */ return NULL; } color = single_tga_read32(f); while (count--) *b++ = color; } else { /* raw packet */ count++; c += count; if (c > w) { /* Stepped past the end of the line, error */ return NULL; } b = raw_tga_read32(b, count, f); } } while (c < w); return b; } /* single_tga_read24: * Helper for reading a single 24-bit data from TGA files. */ static INLINE void single_tga_read24(ALLEGRO_FILE *f, unsigned char color[3]) { al_fread(f, color, 3); } /* raw_tga_read24: * Helper for reading 24-bit raw data from TGA files. * Returns pointer past the end. */ static unsigned char *raw_tga_read24(unsigned char *b, int w, ALLEGRO_FILE *f) { while (w--) { single_tga_read24(f, b); b += 3; } return b; } /* rle_tga_read24: * Helper for reading 24-bit RLE data from TGA files. * Returns pointer past the end or NULL for error. */ static unsigned char *rle_tga_read24(unsigned char *b, int w, ALLEGRO_FILE *f) { int count, c = 0; unsigned char color[3]; do { count = al_fgetc(f); if (count & 0x80) { /* run-length packet */ count = (count & 0x7F) + 1; c += count; if (c > w) { /* Stepped past the end of the line, error */ return NULL; } single_tga_read24(f, color); while (count--) { b[0] = color[0]; b[1] = color[1]; b[2] = color[2]; b += 3; } } else { /* raw packet */ count++; c += count; if (c > w) { /* Stepped past the end of the line, error */ return NULL; } b = raw_tga_read24(b, count, f); } } while (c < w); return b; } /* single_tga_read16: * Helper for reading a single 16-bit data from TGA files. */ static INLINE int single_tga_read16(ALLEGRO_FILE *f) { return al_fread16le(f); } /* raw_tga_read16: * Helper for reading 16-bit raw data from TGA files. * Returns pointer past the end. */ static unsigned short *raw_tga_read16(unsigned short *b, int w, ALLEGRO_FILE *f) { while (w--) *b++ = single_tga_read16(f); return b; } /* rle_tga_read16: * Helper for reading 16-bit RLE data from TGA files. * Returns pointer past the end or NULL for error. */ static unsigned short *rle_tga_read16(unsigned short *b, int w, ALLEGRO_FILE *f) { int color, count, c = 0; do { count = al_fgetc(f); if (count & 0x80) { /* run-length packet */ count = (count & 0x7F) + 1; c += count; if (c > w) { /* Stepped past the end of the line, error */ return NULL; } color = single_tga_read16(f); while (count--) *b++ = color; } else { /* raw packet */ count++; c += count; if (c > w) { /* Stepped past the end of the line, error */ return NULL; } b = raw_tga_read16(b, count, f); } } while (c < w); return b; } typedef unsigned char palette_entry[3]; /* Like load_tga, but starts loading from the current place in the ALLEGRO_FILE * specified. If successful the offset into the file will be left just after * the image data. If unsuccessful the offset into the file is unspecified, * i.e. you must either reset the offset to some known place or close the * packfile. The packfile is not closed by this function. */ ALLEGRO_BITMAP *_al_load_tga_f(ALLEGRO_FILE *f, int flags) { unsigned char image_id[256]; palette_entry image_palette[256]; unsigned char id_length, palette_type, image_type, palette_entry_size; unsigned char bpp, descriptor_bits; short unsigned int palette_colors; short unsigned int palette_start; short unsigned int image_width, image_height; bool left_to_right; bool top_to_bottom; unsigned int c, i; int y; int compressed; ALLEGRO_BITMAP *bmp; ALLEGRO_LOCKED_REGION *lr; unsigned char *buf; bool premul = !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA); ASSERT(f); id_length = al_fgetc(f); palette_type = al_fgetc(f); image_type = al_fgetc(f); palette_start = al_fread16le(f); /* first_color */ palette_colors = al_fread16le(f); palette_entry_size = al_fgetc(f); al_fread16le(f); /* left */ al_fread16le(f); /* top */ image_width = al_fread16le(f); image_height = al_fread16le(f); bpp = al_fgetc(f); descriptor_bits = al_fgetc(f); left_to_right = !(descriptor_bits & (1 << 4)); top_to_bottom = (descriptor_bits & (1 << 5)); al_fread(f, image_id, id_length); /* Image type: * 0 = no image data * 1 = uncompressed color mapped * 2 = uncompressed true color * 3 = grayscale * 9 = RLE color mapped * 10 = RLE true color * 11 = RLE grayscale */ compressed = (image_type & 8); image_type &= 7; if ((image_type < 1) || (image_type > 3)) { ALLEGRO_ERROR("Invalid image type %d.\n", image_type); return NULL; } switch (image_type) { case 1: /* paletted image */ /* Only support 8 bit palettes (up to 256 entries) though in principle the file format could have more(?)*/ if ((palette_type != 1) || (bpp != 8) || (palette_start + palette_colors) > 256) { ALLEGRO_ERROR("Invalid image/palette/bpp combination %d/%d/%d.\n", image_type, palette_type, bpp); return NULL; } break; case 2: /* truecolor image */ if ((palette_type == 0) && ((bpp == 15) || (bpp == 16))) { bpp = 15; } else if ((palette_type == 0) && ((bpp == 24) || (bpp == 32))) { } else { ALLEGRO_ERROR("Invalid image/palette/bpp combination %d/%d/%d.\n", image_type, palette_type, bpp); return NULL; } break; case 3: /* grayscale image */ if ((palette_type != 0) || (bpp != 8)) { ALLEGRO_ERROR("Invalid image/palette/bpp combination %d/%d/%d.\n", image_type, palette_type, bpp); return NULL; } for (i=0; i<256; i++) { image_palette[i][0] = i; image_palette[i][1] = i; image_palette[i][2] = i; } break; default: ALLEGRO_ERROR("Invalid image type %d.\n", image_type); return NULL; } if (palette_type == 0) { /* No-op */ } else if (palette_type == 1) { for (i = 0; i < palette_colors; i++) { palette_entry *entry = image_palette + palette_start + i; switch (palette_entry_size) { case 16: c = al_fread16le(f); (*entry)[0] = (c & 0x1F) << 3; (*entry)[1] = ((c >> 5) & 0x1F) << 3; (*entry)[2] = ((c >> 10) & 0x1F) << 3; break; case 24: (*entry)[0] = al_fgetc(f); (*entry)[1] = al_fgetc(f); (*entry)[2] = al_fgetc(f); break; case 32: (*entry)[0] = al_fgetc(f); (*entry)[1] = al_fgetc(f); (*entry)[2] = al_fgetc(f); al_fgetc(f); /* Ignore 4th byte (alpha) */ break; } } } else { ALLEGRO_ERROR("Invalid palette type %d.\n", palette_type); return NULL; } bmp = al_create_bitmap(image_width, image_height); if (!bmp) { ALLEGRO_ERROR("Failed to create bitmap.\n"); return NULL; } al_set_errno(0); lr = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_WRITEONLY); if (!lr) { ALLEGRO_ERROR("Failed to lock bitmap.\n"); al_destroy_bitmap(bmp); return NULL; } /* bpp + 1 accounts for 15 bpp. */ buf = al_malloc(image_width * ((bpp + 1) / 8)); if (!buf) { al_unlock_bitmap(bmp); al_destroy_bitmap(bmp); ALLEGRO_ERROR("Failed to allocate enough memory.\n"); return NULL; } for (y = 0; y < image_height; y++) { int true_y = (top_to_bottom) ? y : (image_height - 1 - y); switch (image_type) { case 1: case 3: { unsigned char *ptr; if (compressed) ptr = rle_tga_read8(buf, image_width, f); else ptr = raw_tga_read8(buf, image_width, f); if (!ptr) { al_free(buf); al_unlock_bitmap(bmp); al_destroy_bitmap(bmp); ALLEGRO_ERROR("Invalid image data.\n"); return NULL; } } for (i = 0; i < image_width; i++) { int true_x = (left_to_right) ? i : (image_width - 1 - i); int pix = buf[i]; unsigned char *dest = (unsigned char *)lr->data + lr->pitch*true_y + true_x*4; if (pix < palette_start || pix >= (palette_start + palette_colors)) { al_free(buf); al_unlock_bitmap(bmp); al_destroy_bitmap(bmp); ALLEGRO_ERROR("Invalid image data.\n"); return NULL; } palette_entry* entry = image_palette + pix; dest[0] = (*entry)[2]; dest[1] = (*entry)[1]; dest[2] = (*entry)[0]; dest[3] = 255; } break; case 2: if (bpp == 32) { unsigned int *ptr; if (compressed) ptr = rle_tga_read32((unsigned int *)buf, image_width, f); else ptr = raw_tga_read32((unsigned int *)buf, image_width, f); if (!ptr) { al_free(buf); al_unlock_bitmap(bmp); al_destroy_bitmap(bmp); ALLEGRO_ERROR("Invalid image data.\n"); return NULL; } for (i = 0; i < image_width; i++) { int true_x = (left_to_right) ? i : (image_width - 1 - i); unsigned char *dest = (unsigned char *)lr->data + lr->pitch*true_y + true_x*4; #ifdef ALLEGRO_BIG_ENDIAN int a = buf[i * 4 + 0]; int r = buf[i * 4 + 1]; int g = buf[i * 4 + 2]; int b = buf[i * 4 + 3]; #else int b = buf[i * 4 + 0]; int g = buf[i * 4 + 1]; int r = buf[i * 4 + 2]; int a = buf[i * 4 + 3]; #endif if (premul) { r = r * a / 255; g = g * a / 255; b = b * a / 255; } dest[0] = r; dest[1] = g; dest[2] = b; dest[3] = a; } } else if (bpp == 24) { unsigned char *ptr; if (compressed) ptr = rle_tga_read24(buf, image_width, f); else ptr = raw_tga_read24(buf, image_width, f); if (!ptr) { al_free(buf); al_unlock_bitmap(bmp); al_destroy_bitmap(bmp); ALLEGRO_ERROR("Invalid image data.\n"); return NULL; } for (i = 0; i < image_width; i++) { int true_x = (left_to_right) ? i : (image_width - 1 - i); int b = buf[i * 3 + 0]; int g = buf[i * 3 + 1]; int r = buf[i * 3 + 2]; unsigned char *dest = (unsigned char *)lr->data + lr->pitch*true_y + true_x*4; dest[0] = r; dest[1] = g; dest[2] = b; dest[3] = 255; } } else { unsigned short *ptr; if (compressed) ptr = rle_tga_read16((unsigned short *)buf, image_width, f); else ptr = raw_tga_read16((unsigned short *)buf, image_width, f); if (!ptr) { al_free(buf); al_unlock_bitmap(bmp); al_destroy_bitmap(bmp); ALLEGRO_ERROR("Invalid image data.\n"); return NULL; } for (i = 0; i < image_width; i++) { int true_x = (left_to_right) ? i : (image_width - 1 - i); int pix = *((unsigned short *)(buf + i * 2)); /* TODO - do something with the 1-bit A value (alpha?) */ int r = _al_rgb_scale_5[(pix >> 10) & 0x1F]; int g = _al_rgb_scale_5[(pix >> 5) & 0x1F]; int b = _al_rgb_scale_5[(pix & 0x1F)]; unsigned char *dest = (unsigned char *)lr->data + lr->pitch*true_y + true_x*4; dest[0] = r; dest[1] = g; dest[2] = b; dest[3] = 255; } } break; } } al_free(buf); al_unlock_bitmap(bmp); if (al_get_errno()) { ALLEGRO_ERROR("Error detected: %d.\n", al_get_errno()); al_destroy_bitmap(bmp); return NULL; } return bmp; } /* Like save_tga but writes into the ALLEGRO_FILE given instead of a new file. * The packfile is not closed after writing is completed. On success the * offset into the file is left after the TGA file just written. On failure * the offset is left at the end of whatever incomplete data was written. */ bool _al_save_tga_f(ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp) { int x, y; int w, h; ASSERT(f); ASSERT(bmp); al_set_errno(0); w = al_get_bitmap_width(bmp); h = al_get_bitmap_height(bmp); al_fputc(f, 0); /* id length (no id saved) */ al_fputc(f, 0); /* palette type */ al_fputc(f, 2); /* image type */ al_fwrite16le(f, 0); /* first colour */ al_fwrite16le(f, 0); /* number of colours */ al_fputc(f, 0); /* palette entry size */ al_fwrite16le(f, 0); /* left */ al_fwrite16le(f, 0); /* top */ al_fwrite16le(f, w); /* width */ al_fwrite16le(f, h); /* height */ al_fputc(f, 32); /* bits per pixel */ al_fputc(f, 8); /* descriptor (bottom to top, 8-bit alpha) */ al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); for (y = h - 1; y >= 0; y--) { for (x = 0; x < w; x++) { ALLEGRO_COLOR c = al_get_pixel(bmp, x, y); unsigned char r, g, b, a; al_unmap_rgba(c, &r, &g, &b, &a); al_fputc(f, b); al_fputc(f, g); al_fputc(f, r); al_fputc(f, a); } } al_unlock_bitmap(bmp); return al_get_errno() ? false : true; } ALLEGRO_BITMAP *_al_load_tga(const char *filename, int flags) { ALLEGRO_FILE *f; ALLEGRO_BITMAP *bmp; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } bmp = _al_load_tga_f(f, flags); al_fclose(f); return bmp; } bool _al_save_tga(const char *filename, ALLEGRO_BITMAP *bmp) { ALLEGRO_FILE *f; bool retsave; bool retclose; ASSERT(filename); f = al_fopen(filename, "wb"); if (!f) { ALLEGRO_ERROR("Unable to open %s for writing.\n", filename); return false; } retsave = _al_save_tga_f(f, bmp); retclose = al_fclose(f); return retsave && retclose; } bool _al_identify_tga(ALLEGRO_FILE *f) { uint8_t x[4]; al_fgetc(f); // skip id length al_fread(f, x, 4); if (x[0] > 1) // TGA colormap must be 0 or 1 return false; if ((x[1] & 0xf7) == 0) // type must be 1, 2, 3, 9, 10 or 11 return false; if (x[2] != 0 || x[3] != 0) // color map must start at 0 return false; return true; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/image/webp.c000066400000000000000000000104311473414355200171120ustar00rootroot00000000000000/* Allegro wrapper routines for libwebp * by Sebastian Krzyszkowiak (dos@dosowisko.net). */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/internal/aintern_image.h" #include "iio.h" ALLEGRO_DEBUG_CHANNEL("image") /***************************************************************************** * Loading routines ****************************************************************************/ static ALLEGRO_BITMAP *load_from_buffer(const uint8_t* data, size_t data_size, int flags) { ALLEGRO_BITMAP *bmp; ALLEGRO_LOCKED_REGION *lock; bool premul = !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA); WebPDecoderConfig config; WebPInitDecoderConfig(&config); if (WebPGetFeatures(data, data_size, &config.input) != VP8_STATUS_OK) { ALLEGRO_ERROR("Could not read WebP stream info\n"); return NULL; } bmp = al_create_bitmap(config.input.width, config.input.height); if (!bmp) { ALLEGRO_ERROR("al_create_bitmap failed while loading WebP.\n"); return NULL; } lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_WRITEONLY); config.output.colorspace = premul ? MODE_rgbA : MODE_RGBA; config.output.u.RGBA.rgba = (uint8_t*)lock->data; config.output.u.RGBA.stride = lock->pitch; config.output.u.RGBA.size = lock->pitch * config.input.height; config.output.is_external_memory = 1; if (WebPDecode(data, data_size, &config) != VP8_STATUS_OK) { ALLEGRO_ERROR("Could not decode WebP stream\n"); al_destroy_bitmap(bmp); return NULL; } al_unlock_bitmap(bmp); return bmp; } ALLEGRO_BITMAP *_al_load_webp_f(ALLEGRO_FILE *fp, int flags) { ALLEGRO_ASSERT(fp); ALLEGRO_BITMAP *bmp; size_t data_size = al_fsize(fp); uint8_t *data = al_malloc(data_size * sizeof(uint8_t)); if (al_fread(fp, data, data_size) != data_size) { ALLEGRO_ERROR("Could not read WebP file\n"); free(data); return NULL; } bmp = load_from_buffer(data, data_size, flags); free(data); return bmp; } ALLEGRO_BITMAP *_al_load_webp(const char *filename, int flags) { ALLEGRO_FILE *fp; ALLEGRO_BITMAP *bmp; ALLEGRO_ASSERT(filename); fp = al_fopen(filename, "rb"); if (!fp) { ALLEGRO_ERROR("Unable to open %s for reading.\n", filename); return NULL; } bmp = _al_load_webp_f(fp, flags); al_fclose(fp); return bmp; } /***************************************************************************** * Saving routines ****************************************************************************/ bool _al_save_webp_f(ALLEGRO_FILE *fp, ALLEGRO_BITMAP *bmp) { ALLEGRO_LOCKED_REGION *lock; bool ret = false; lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_READONLY); if (!lock) { ALLEGRO_ERROR("Failed to lock bitmap.\n"); return false; } uint8_t *output = NULL; size_t size; const char* level = al_get_config_value(al_get_system_config(), "image", "webp_quality_level"); if (!level || strcmp(level, "lossless") == 0) { size = WebPEncodeLosslessRGBA((const uint8_t*)lock->data, al_get_bitmap_width(bmp), al_get_bitmap_height(bmp), lock->pitch, &output); } else { size = WebPEncodeRGBA((const uint8_t*)lock->data, al_get_bitmap_width(bmp), al_get_bitmap_height(bmp), lock->pitch, level ? strtol(level, NULL, 10) : 75, &output); } if (al_fwrite(fp, output, size) == size) { ret = true; } #if WEBP_DECODER_ABI_VERSION >= 0x0206 WebPFree(output); #else free(output); #endif al_unlock_bitmap(bmp); return ret; } bool _al_save_webp(const char *filename, ALLEGRO_BITMAP *bmp) { ALLEGRO_FILE *fp; bool retsave; bool retclose; ALLEGRO_ASSERT(filename); ALLEGRO_ASSERT(bmp); fp = al_fopen(filename, "wb"); if (!fp) { ALLEGRO_ERROR("Unable to open file %s for writing\n", filename); return false; } retsave = _al_save_webp_f(fp, bmp); if (!retsave) { ALLEGRO_ERROR("Unable to store WebP bitmap in file %s\n", filename); } retclose = al_fclose(fp); if (!retclose) { ALLEGRO_ERROR("Unable to close file %s\n", filename); } return retsave && retclose; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/main/000077500000000000000000000000001473414355200156545ustar00rootroot00000000000000allegro5-5.2.10.1/addons/main/CMakeLists.txt000066400000000000000000000006501473414355200204150ustar00rootroot00000000000000if(ALLEGRO_MACOSX) set(MAIN_SOURCES osx_main.m) set(SUPPORT_ALLEGRO_MAIN 1) endif(ALLEGRO_MACOSX) if(NOT SUPPORT_ALLEGRO_MAIN) set(MAIN_SOURCES generic_main.c) set(SUPPORT_ALLEGRO_MAIN 1) endif(NOT SUPPORT_ALLEGRO_MAIN) add_our_addon_library(allegro_main AllegroMain-${ALLEGRO_SOVERSION} "${MAIN_SOURCES}" "-DALLEGRO_SRC" "${ALLEGRO_LINK_WITH}" ) add_addon(main) # vim: set sts=4 sw=4 et: allegro5-5.2.10.1/addons/main/generic_main.c000066400000000000000000000002531473414355200204400ustar00rootroot00000000000000/* Empty file */ /* * MSVC will not generate an empty .lib file */ #ifdef _MSC_VER #include __declspec(dllexport) void _al_make_a_lib() { exit(1); } #endif allegro5-5.2.10.1/addons/main/osx_main.m000066400000000000000000000021671473414355200176550ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * main() function replacement for MacOS X. * * By Angelo Mottola. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/platform/aintosx.h" #ifndef ALLEGRO_MACOSX #error something is wrong with the makefile #endif #undef main extern int _al_mangled_main(int, char **); /* main: * Replacement for main function. */ int main(int argc, char *argv[]) { _al_osx_run_main(argc, argv, _al_mangled_main); return 0; } /* Local variables: */ /* c-basic-offset: 3 */ /* indent-tabs-mode: nil */ /* c-file-style: "linux" */ /* End: */ allegro5-5.2.10.1/addons/memfile/000077500000000000000000000000001473414355200163465ustar00rootroot00000000000000allegro5-5.2.10.1/addons/memfile/CMakeLists.txt000066400000000000000000000007671473414355200211200ustar00rootroot00000000000000 set(MEMFILE_SOURCES memfile.c) set(MEMFILE_INCLUDE_FILES allegro5/allegro_memfile.h) set_our_header_properties(${MEMFILE_INCLUDE_FILES}) add_our_addon_library(allegro_memfile AllegroMemfile-${ALLEGRO_SOVERSION} "${MEMFILE_SOURCES};${MEMFILE_INCLUDE_FILES}" "-DALLEGRO_MEMFILE_SRC" "${ALLEGRO_LINK_WITH}" ) install_our_headers(${MEMFILE_INCLUDE_FILES}) add_addon(memfile) #-----------------------------------------------------------------------------# # vi: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/addons/memfile/allegro5/000077500000000000000000000000001473414355200200605ustar00rootroot00000000000000allegro5-5.2.10.1/addons/memfile/allegro5/allegro_memfile.h000066400000000000000000000021551473414355200233570ustar00rootroot00000000000000#ifndef __al_included_allegro5_memfile_h #define __al_included_allegro5_memfile_h #include "allegro5/allegro.h" #ifdef __cplusplus extern "C" { #endif #if (defined ALLEGRO_MINGW32) || (defined ALLEGRO_MSVC) || (defined ALLEGRO_BCC32) #ifndef ALLEGRO_STATICLINK #ifdef ALLEGRO_MEMFILE_SRC #define _ALLEGRO_MEMFILE_DLL __declspec(dllexport) #else #define _ALLEGRO_MEMFILE_DLL __declspec(dllimport) #endif #else #define _ALLEGRO_MEMFILE_DLL #endif #endif #if defined ALLEGRO_MSVC #define ALLEGRO_MEMFILE_FUNC(type, name, args) _ALLEGRO_MEMFILE_DLL type __cdecl name args #elif defined ALLEGRO_MINGW32 #define ALLEGRO_MEMFILE_FUNC(type, name, args) extern type name args #elif defined ALLEGRO_BCC32 #define ALLEGRO_MEMFILE_FUNC(type, name, args) extern _ALLEGRO_MEMFILE_DLL type name args #else #define ALLEGRO_MEMFILE_FUNC AL_FUNC #endif ALLEGRO_MEMFILE_FUNC(ALLEGRO_FILE *, al_open_memfile, (void *mem, int64_t size, const char *mode)); ALLEGRO_MEMFILE_FUNC(uint32_t, al_get_allegro_memfile_version, (void)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/memfile/memfile.c000066400000000000000000000075471473414355200201450ustar00rootroot00000000000000#include #include "allegro5/allegro_memfile.h" typedef struct ALLEGRO_FILE_MEMFILE ALLEGRO_FILE_MEMFILE; struct ALLEGRO_FILE_MEMFILE { bool readable; bool writable; bool eof; int64_t size; int64_t pos; char *mem; }; static bool memfile_fclose(ALLEGRO_FILE *fp) { al_free(al_get_file_userdata(fp)); return true; } static size_t memfile_fread(ALLEGRO_FILE *fp, void *ptr, size_t size) { ALLEGRO_FILE_MEMFILE *mf = al_get_file_userdata(fp); size_t n = 0; if (!mf->readable) { al_set_errno(EPERM); return 0; } if (mf->size - mf->pos < (int64_t)size) { /* partial read */ n = mf->size - mf->pos; mf->eof = true; } else { n = size; } memcpy(ptr, mf->mem + mf->pos, n); mf->pos += n; return n; } static size_t memfile_fwrite(ALLEGRO_FILE *fp, const void *ptr, size_t size) { ALLEGRO_FILE_MEMFILE *mf = al_get_file_userdata(fp); size_t n; if (!mf->writable) { al_set_errno(EPERM); return 0; } if (mf->size - mf->pos < (int64_t)size) { /* partial write */ n = mf->size - mf->pos; mf->eof = true; } else { n = size; } memcpy(mf->mem + mf->pos, ptr, n); mf->pos += n; return n; } static bool memfile_fflush(ALLEGRO_FILE *fp) { (void)fp; return true; } static int64_t memfile_ftell(ALLEGRO_FILE *fp) { ALLEGRO_FILE_MEMFILE *mf = al_get_file_userdata(fp); return mf->pos; } static bool memfile_fseek(ALLEGRO_FILE *fp, int64_t offset, int whence) { ALLEGRO_FILE_MEMFILE *mf = al_get_file_userdata(fp); int64_t pos = mf->pos; switch (whence) { case ALLEGRO_SEEK_SET: pos = offset; break; case ALLEGRO_SEEK_CUR: pos = mf->pos + offset; break; case ALLEGRO_SEEK_END: pos = mf->size + offset; break; } if (pos >= mf->size) pos = mf->size; else if (pos < 0) pos = 0; mf->pos = pos; mf->eof = false; return true; } /* doesn't quite match up to stdio here, an feof after a seek will return false, even if it seeks past the end of the file */ static bool memfile_feof(ALLEGRO_FILE *fp) { ALLEGRO_FILE_MEMFILE *mf = al_get_file_userdata(fp); return mf->eof; } static int memfile_ferror(ALLEGRO_FILE *fp) { (void)fp; return 0; } static const char *memfile_ferrmsg(ALLEGRO_FILE *fp) { (void)fp; return ""; } static void memfile_fclearerr(ALLEGRO_FILE *fp) { ALLEGRO_FILE_MEMFILE *mf = al_get_file_userdata(fp); mf->eof = false; } static off_t memfile_fsize(ALLEGRO_FILE *fp) { ALLEGRO_FILE_MEMFILE *mf = al_get_file_userdata(fp); return mf->size; } static struct ALLEGRO_FILE_INTERFACE memfile_vtable = { NULL, /* open */ memfile_fclose, memfile_fread, memfile_fwrite, memfile_fflush, memfile_ftell, memfile_fseek, memfile_feof, memfile_ferror, memfile_ferrmsg, memfile_fclearerr, NULL, /* ungetc */ memfile_fsize }; /* Function: al_open_memfile */ ALLEGRO_FILE *al_open_memfile(void *mem, int64_t size, const char *mode) { ALLEGRO_FILE *memfile; ALLEGRO_FILE_MEMFILE *userdata = NULL; ASSERT(mem); ASSERT(size > 0); userdata = al_malloc(sizeof(ALLEGRO_FILE_MEMFILE)); if (!userdata) { al_set_errno(ENOMEM); return NULL; } memset(userdata, 0, sizeof(*userdata)); userdata->size = size; userdata->pos = 0; userdata->mem = mem; userdata->readable = strchr(mode, 'r') || strchr(mode, 'R'); userdata->writable = strchr(mode, 'w') || strchr(mode, 'W'); memfile = al_create_file_handle(&memfile_vtable, userdata); if (!memfile) { al_free(userdata); } return memfile; } /* Function: al_get_allegro_memfile_version */ uint32_t al_get_allegro_memfile_version(void) { return ALLEGRO_VERSION_INT; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/000077500000000000000000000000001473414355200175355ustar00rootroot00000000000000allegro5-5.2.10.1/addons/native_dialog/CMakeLists.txt000066400000000000000000000047041473414355200223020ustar00rootroot00000000000000set(NATIVE_DIALOG_INCLUDE_FILES allegro5/allegro_native_dialog.h) set_our_header_properties(${NATIVE_DIALOG_INCLUDE_FILES}) set(NATIVE_DIALOG_SOURCES dialog.c textlog.c menu.c ) set(GTK_NATIVE_DIALOG_SOURCES gtk_dialog.c gtk_filesel.c gtk_menu.c gtk_msgbox.c gtk_textlog.c gtk_thread.c gtk_xgtk.c ) if(APPLE AND NOT IPHONE) list(APPEND NATIVE_DIALOG_SOURCES osx_dialog.m) set(ALLEGRO_CFG_NATIVE_DIALOG_OSX 1) set(SUPPORT_NATIVE_DIALOG 1) endif(APPLE AND NOT IPHONE) if(APPLE AND IPHONE) list(APPEND NATIVE_DIALOG_SOURCES iphone_dialog.m) set(ALLEGRO_CFG_NATIVE_DIALOG_IPHONE 1) set(SUPPORT_NATIVE_DIALOG 1) endif(APPLE AND IPHONE) if(ANDROID) list(APPEND NATIVE_DIALOG_SOURCES android_dialog.c) set(ALLEGRO_CFG_NATIVE_DIALOG_ANDROID 1) set(SUPPORT_NATIVE_DIALOG 1) endif(ANDROID) if(WIN32) list(APPEND NATIVE_DIALOG_SOURCES win_dialog.c) set(ALLEGRO_CFG_NATIVE_DIALOG_WINDOWS 1) set(SUPPORT_NATIVE_DIALOG 1) endif(WIN32) if(NOT SUPPORT_NATIVE_DIALOG AND SUPPORT_X11 AND NOT ALLEGRO_RASPBERRYPI) pkg_check_modules(GTK gtk+-3.0) pkg_check_modules(GT gthread-2.0) if(GTK_FOUND AND GT_FOUND) list(APPEND NATIVE_DIALOG_SOURCES ${GTK_NATIVE_DIALOG_SOURCES}) list(APPEND NATIVE_DIALOG_INCLUDE_DIRECTORIES ${GTK_INCLUDE_DIRS} ${GT_INCLUDE_DIRS}) list(APPEND NATIVE_DIALOG_LIBRARIES ${GTK_LIBRARIES} ${GT_LIBRARIES}) set_source_files_properties( ${GTK_NATIVE_DIALOG_SOURCES} PROPERTIES COMPILE_FLAGS "${GTK_CFLAGS_STRING}" ) set(ALLEGRO_CFG_NATIVE_DIALOG_GTK 1) set(SUPPORT_NATIVE_DIALOG 1) endif() endif() if(SUPPORT_NATIVE_DIALOG) configure_file( allegro5/internal/aintern_native_dialog_cfg.h.cmake ${PROJECT_BINARY_DIR}/include/allegro5/internal/aintern_native_dialog_cfg.h ) include_directories(SYSTEM ${NATIVE_DIALOG_INCLUDE_DIRECTORIES}) # Note: allegro_dialog NOT allegro_native_dialog. add_our_addon_library(allegro_dialog AllegroDialog-${ALLEGRO_SOVERSION} "${NATIVE_DIALOG_SOURCES};${NATIVE_DIALOG_INCLUDE_FILES}" "-DALLEGRO_NATIVE_DIALOG_SRC" "${NATIVE_DIALOG_LIBRARIES};${ALLEGRO_LINK_WITH}" ) install_our_headers(${NATIVE_DIALOG_INCLUDE_FILES}) # Note: allegro_dialog NOT allegro_native_dialog. add_addon2(native_dialog allegro_dialog) endif(SUPPORT_NATIVE_DIALOG) # vim: set sts=4 sw=4 et: allegro5-5.2.10.1/addons/native_dialog/allegro5/000077500000000000000000000000001473414355200212475ustar00rootroot00000000000000allegro5-5.2.10.1/addons/native_dialog/allegro5/allegro_native_dialog.h000066400000000000000000000150101473414355200257270ustar00rootroot00000000000000#ifndef __al_included_allegro5_allegro_native_dialog_h #define __al_included_allegro5_allegro_native_dialog_h #include "allegro5/allegro.h" #ifdef __cplusplus extern "C" { #endif #if (defined ALLEGRO_MINGW32) || (defined ALLEGRO_MSVC) || (defined ALLEGRO_BCC32) #ifndef ALLEGRO_STATICLINK #ifdef ALLEGRO_NATIVE_DIALOG_SRC #define _ALLEGRO_DIALOG_DLL __declspec(dllexport) #else #define _ALLEGRO_DIALOG_DLL __declspec(dllimport) #endif #else #define _ALLEGRO_DIALOG_DLL #endif #endif #if defined ALLEGRO_MSVC #define ALLEGRO_DIALOG_FUNC(type, name, args) _ALLEGRO_DIALOG_DLL type __cdecl name args #elif defined ALLEGRO_MINGW32 #define ALLEGRO_DIALOG_FUNC(type, name, args) extern type name args #elif defined ALLEGRO_BCC32 #define ALLEGRO_DIALOG_FUNC(type, name, args) extern _ALLEGRO_DIALOG_DLL type name args #else #define ALLEGRO_DIALOG_FUNC AL_FUNC #endif #ifdef ALLEGRO_WITH_XWINDOWS #define ALLEGRO_GTK_TOPLEVEL ALLEGRO_GTK_TOPLEVEL_INTERNAL #endif /* Type: ALLEGRO_FILECHOOSER */ typedef struct ALLEGRO_FILECHOOSER ALLEGRO_FILECHOOSER; /* Type: ALLEGRO_TEXTLOG */ typedef struct ALLEGRO_TEXTLOG ALLEGRO_TEXTLOG; /* Type: ALLEGRO_MENU */ typedef struct ALLEGRO_MENU ALLEGRO_MENU; /* Type: ALLEGRO_MENU_INFO */ typedef struct ALLEGRO_MENU_INFO { const char *caption; uint16_t id; int flags; ALLEGRO_BITMAP *icon; } ALLEGRO_MENU_INFO; #define ALLEGRO_MENU_SEPARATOR { NULL, -1, 0, NULL } #define ALLEGRO_START_OF_MENU(caption, id) { caption "->", id, 0, NULL } #define ALLEGRO_END_OF_MENU { NULL, 0, 0, NULL } ALLEGRO_DIALOG_FUNC(bool, al_init_native_dialog_addon, (void)); ALLEGRO_DIALOG_FUNC(bool, al_is_native_dialog_addon_initialized, (void)); ALLEGRO_DIALOG_FUNC(void, al_shutdown_native_dialog_addon, (void)); ALLEGRO_DIALOG_FUNC(ALLEGRO_FILECHOOSER *, al_create_native_file_dialog, (char const *initial_path, char const *title, char const *patterns, int mode)); ALLEGRO_DIALOG_FUNC(bool, al_show_native_file_dialog, (ALLEGRO_DISPLAY *display, ALLEGRO_FILECHOOSER *dialog)); ALLEGRO_DIALOG_FUNC(int, al_get_native_file_dialog_count, (const ALLEGRO_FILECHOOSER *dialog)); ALLEGRO_DIALOG_FUNC(const char *, al_get_native_file_dialog_path, (const ALLEGRO_FILECHOOSER *dialog, size_t index)); ALLEGRO_DIALOG_FUNC(void, al_destroy_native_file_dialog, (ALLEGRO_FILECHOOSER *dialog)); ALLEGRO_DIALOG_FUNC(int, al_show_native_message_box, (ALLEGRO_DISPLAY *display, char const *title, char const *heading, char const *text, char const *buttons, int flags)); ALLEGRO_DIALOG_FUNC(ALLEGRO_TEXTLOG *, al_open_native_text_log, (char const *title, int flags)); ALLEGRO_DIALOG_FUNC(void, al_close_native_text_log, (ALLEGRO_TEXTLOG *textlog)); ALLEGRO_DIALOG_FUNC(void, al_append_native_text_log, (ALLEGRO_TEXTLOG *textlog, char const *format, ...)); ALLEGRO_DIALOG_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_native_text_log_event_source, (ALLEGRO_TEXTLOG *textlog)); /* creating/modifying menus */ ALLEGRO_DIALOG_FUNC(ALLEGRO_MENU *, al_create_menu, (void)); ALLEGRO_DIALOG_FUNC(ALLEGRO_MENU *, al_create_popup_menu, (void)); ALLEGRO_DIALOG_FUNC(ALLEGRO_MENU *, al_build_menu, (ALLEGRO_MENU_INFO *info)); ALLEGRO_DIALOG_FUNC(int, al_append_menu_item, (ALLEGRO_MENU *parent, char const *title, uint16_t id, int flags, ALLEGRO_BITMAP *icon, ALLEGRO_MENU *submenu)); ALLEGRO_DIALOG_FUNC(int, al_insert_menu_item, (ALLEGRO_MENU *parent, int pos, char const *title, uint16_t id, int flags, ALLEGRO_BITMAP *icon, ALLEGRO_MENU *submenu)); ALLEGRO_DIALOG_FUNC(bool, al_remove_menu_item, (ALLEGRO_MENU *menu, int pos)); ALLEGRO_DIALOG_FUNC(ALLEGRO_MENU *, al_clone_menu, (ALLEGRO_MENU *menu)); ALLEGRO_DIALOG_FUNC(ALLEGRO_MENU *, al_clone_menu_for_popup, (ALLEGRO_MENU *menu)); ALLEGRO_DIALOG_FUNC(void, al_destroy_menu, (ALLEGRO_MENU *menu)); /* properties */ ALLEGRO_DIALOG_FUNC(const char *, al_get_menu_item_caption, (ALLEGRO_MENU *menu, int pos)); ALLEGRO_DIALOG_FUNC(void, al_set_menu_item_caption, (ALLEGRO_MENU *menu, int pos, const char *caption)); ALLEGRO_DIALOG_FUNC(int, al_get_menu_item_flags, (ALLEGRO_MENU *menu, int pos)); ALLEGRO_DIALOG_FUNC(void, al_set_menu_item_flags, (ALLEGRO_MENU *menu, int pos, int flags)); ALLEGRO_DIALOG_FUNC(ALLEGRO_BITMAP *, al_get_menu_item_icon, (ALLEGRO_MENU *menu, int pos)); ALLEGRO_DIALOG_FUNC(void, al_set_menu_item_icon, (ALLEGRO_MENU *menu, int pos, ALLEGRO_BITMAP *icon)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_NATIVE_DIALOG_SRC) ALLEGRO_DIALOG_FUNC(int, al_toggle_menu_item_flags, (ALLEGRO_MENU *menu, int pos, int flags)); #endif /* querying menus */ ALLEGRO_DIALOG_FUNC(ALLEGRO_MENU *, al_find_menu, (ALLEGRO_MENU *haystack, uint16_t id)); ALLEGRO_DIALOG_FUNC(bool, al_find_menu_item, (ALLEGRO_MENU *haystack, uint16_t id, ALLEGRO_MENU **menu, int *index)); /* menu events */ ALLEGRO_DIALOG_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_default_menu_event_source, (void)); ALLEGRO_DIALOG_FUNC(ALLEGRO_EVENT_SOURCE *, al_enable_menu_event_source, (ALLEGRO_MENU *menu)); ALLEGRO_DIALOG_FUNC(void, al_disable_menu_event_source, (ALLEGRO_MENU *menu)); /* displaying menus */ ALLEGRO_DIALOG_FUNC(ALLEGRO_MENU *, al_get_display_menu, (ALLEGRO_DISPLAY *display)); ALLEGRO_DIALOG_FUNC(bool, al_set_display_menu, (ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu)); ALLEGRO_DIALOG_FUNC(bool, al_popup_menu, (ALLEGRO_MENU *popup, ALLEGRO_DISPLAY *display)); ALLEGRO_DIALOG_FUNC(ALLEGRO_MENU *, al_remove_display_menu, (ALLEGRO_DISPLAY *display)); ALLEGRO_DIALOG_FUNC(uint32_t, al_get_allegro_native_dialog_version, (void)); enum { ALLEGRO_FILECHOOSER_FILE_MUST_EXIST = 1, ALLEGRO_FILECHOOSER_SAVE = 2, ALLEGRO_FILECHOOSER_FOLDER = 4, ALLEGRO_FILECHOOSER_PICTURES = 8, ALLEGRO_FILECHOOSER_SHOW_HIDDEN = 16, ALLEGRO_FILECHOOSER_MULTIPLE = 32 }; enum { ALLEGRO_MESSAGEBOX_WARN = 1<<0, ALLEGRO_MESSAGEBOX_ERROR = 1<<1, ALLEGRO_MESSAGEBOX_OK_CANCEL = 1<<2, ALLEGRO_MESSAGEBOX_YES_NO = 1<<3, ALLEGRO_MESSAGEBOX_QUESTION = 1<<4 }; enum { ALLEGRO_TEXTLOG_NO_CLOSE = 1<<0, ALLEGRO_TEXTLOG_MONOSPACE = 1<<1 }; enum { ALLEGRO_EVENT_NATIVE_DIALOG_CLOSE = 600, ALLEGRO_EVENT_MENU_CLICK = 601 }; enum { ALLEGRO_MENU_ITEM_ENABLED = 0, ALLEGRO_MENU_ITEM_CHECKBOX = 1, ALLEGRO_MENU_ITEM_CHECKED = 2, ALLEGRO_MENU_ITEM_DISABLED = 4 }; #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/allegro5/internal/000077500000000000000000000000001473414355200230635ustar00rootroot00000000000000allegro5-5.2.10.1/addons/native_dialog/allegro5/internal/aintern_native_dialog.h000066400000000000000000000115271473414355200275670ustar00rootroot00000000000000#ifndef __al_included_allegro_aintern_native_dialog_h #define __al_included_allegro_aintern_native_dialog_h #include "allegro5/internal/aintern_list.h" #include "allegro5/internal/aintern_vector.h" #include "allegro5/internal/aintern_native_dialog_cfg.h" typedef struct { ALLEGRO_USTR_INFO info; bool is_mime; bool is_catchall; } _AL_PATTERN; typedef struct { ALLEGRO_USTR_INFO desc; _AL_VECTOR patterns_vec; } _AL_PATTERNS_AND_DESC; typedef struct ALLEGRO_NATIVE_DIALOG ALLEGRO_NATIVE_DIALOG; /* We could use different structs for the different dialogs. But why * bother. */ struct ALLEGRO_NATIVE_DIALOG { ALLEGRO_USTR *title; int flags; /* Only used by file chooser. */ ALLEGRO_PATH *fc_initial_path; size_t fc_path_count; ALLEGRO_PATH **fc_paths; /* Vector of _AL_PATTERNS_AND_DESC, substrings index into fc_patterns_ustr. */ _AL_VECTOR fc_patterns; ALLEGRO_USTR *fc_patterns_ustr; /* Only used by message box. */ ALLEGRO_USTR *mb_heading; ALLEGRO_USTR *mb_text; ALLEGRO_USTR *mb_buttons; int mb_pressed_button; /* Only used by text log. */ ALLEGRO_THREAD *tl_thread; ALLEGRO_COND *tl_text_cond; ALLEGRO_MUTEX *tl_text_mutex; ALLEGRO_USTR *tl_pending_text; bool tl_init_error; bool tl_done; bool tl_have_pending; ALLEGRO_EVENT_SOURCE tl_events; void *tl_textview; /* Only used by platform implementations. */ bool is_active; void *window; void *async_queue; _AL_LIST_ITEM *dtor_item; }; extern bool _al_init_native_dialog_addon(void); extern void _al_shutdown_native_dialog_addon(void); extern bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display, ALLEGRO_NATIVE_DIALOG *fd); extern int _al_show_native_message_box(ALLEGRO_DISPLAY *display, ALLEGRO_NATIVE_DIALOG *fd); extern bool _al_open_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog); extern void _al_close_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog); extern void _al_append_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog); typedef struct ALLEGRO_MENU_ITEM ALLEGRO_MENU_ITEM; struct ALLEGRO_MENU_ITEM { ALLEGRO_MENU *parent; ALLEGRO_MENU *popup; ALLEGRO_USTR *caption; ALLEGRO_BITMAP *icon; /* This id is unique. */ uint16_t unique_id; /* This id is user provided, can be not unique. */ uint16_t id; int flags; void *extra1, *extra2; }; /* _AL_MENU_ID keeps track of menu / id pairs to help determine which * menu belongs to an id. */ typedef struct _AL_MENU_ID _AL_MENU_ID; struct _AL_MENU_ID { ALLEGRO_MENU *menu; uint16_t unique_id; uint16_t id; }; struct ALLEGRO_MENU { ALLEGRO_EVENT_SOURCE es; ALLEGRO_DISPLAY *display; ALLEGRO_MENU_ITEM *parent; _AL_VECTOR items; bool is_event_source; bool is_popup_menu; void *extra1; }; /* Platform implementation must call this when a menu item is clicked. * display: the display associated with the menu * unique_id: the unique id associated with the menu item * * The function will find the appropriate ALLEGRO_MENU and emit the event. */ extern bool _al_emit_menu_event(ALLEGRO_DISPLAY *display, uint16_t unique_id); extern bool _al_walk_over_menu(ALLEGRO_MENU *menu, bool (*proc) (ALLEGRO_MENU *menu, ALLEGRO_MENU_ITEM *item, int index, void *extra), void *extra); _AL_MENU_ID *_al_find_parent_menu_by_id(ALLEGRO_DISPLAY *display, uint16_t unique_id); bool _al_find_menu_item_unique(ALLEGRO_MENU *haystack, uint16_t unique_id, ALLEGRO_MENU **menu, int *index); /* Platform Specific Functions * --------------------------- * Each of these should return true if successful. If at all possible, they * should all be implemented and always return true (if menus are implemented * at all). All of the parameters will be valid. */ extern bool _al_init_menu(ALLEGRO_MENU *menu); extern bool _al_init_popup_menu(ALLEGRO_MENU *menu); extern bool _al_destroy_menu(ALLEGRO_MENU *menu); /* The "int i" parameter represents the indexed location of the item in the * item->parent->items vector. This should map up identically to what is displayed * within the platform menu... However, if there are silent entries (e.g., on OS X), * the index may not represent what is seen on screen. If such discrepencies exist, * then the platform imlpementation must compensate accordingly. */ extern bool _al_insert_menu_item_at(ALLEGRO_MENU_ITEM *item, int i); extern bool _al_destroy_menu_item_at(ALLEGRO_MENU_ITEM *item, int i); extern bool _al_update_menu_item_at(ALLEGRO_MENU_ITEM *item, int i); extern bool _al_show_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu); extern bool _al_hide_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu); extern bool _al_show_popup_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu); /* Returns the height of the display taken up by the menu, so we can resize * the display to compensate. Windows only at the moment.*/ extern int _al_get_menu_display_height(void); #endif allegro5-5.2.10.1/addons/native_dialog/allegro5/internal/aintern_native_dialog_cfg.h.cmake000066400000000000000000000002641473414355200314610ustar00rootroot00000000000000#cmakedefine ALLEGRO_CFG_NATIVE_DIALOG_GTK #cmakedefine ALLEGRO_CFG_NATIVE_DIALOG_OSX #cmakedefine ALLEGRO_CFG_NATIVE_DIALOG_WINDOWS #cmakedefine ALLEGRO_CFG_NATIVE_DIALOG_ANDROID allegro5-5.2.10.1/addons/native_dialog/android_dialog.c000066400000000000000000000322531473414355200226450ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Native dialog addon for Android. * * By Alexandre Martins. */ #include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_android.h" #include "allegro5/internal/aintern_native_dialog.h" ALLEGRO_DEBUG_CHANNEL("android") static ALLEGRO_DISPLAY *get_active_display(void); static void wait_for_display_events(ALLEGRO_DISPLAY *dpy); static bool open_file_chooser(int flags, const char *patterns, const char *initial_path, ALLEGRO_PATH ***out_uri_strings, size_t *out_uri_count); static char *really_open_file_chooser(int flags, const char *patterns, const char *initial_path); static int show_message_box(const char *title, const char *message, const char *buttons, int flags); static void append_to_textlog(const char *tag, const char *message); static ALLEGRO_EVENT_QUEUE *queue = NULL; static ALLEGRO_MUTEX *mutex = NULL; bool _al_init_native_dialog_addon(void) { if (NULL == (mutex = al_create_mutex())) return false; if (NULL == (queue = al_create_event_queue())) { al_destroy_mutex(mutex); return false; } return true; } void _al_shutdown_native_dialog_addon(void) { al_destroy_mutex(mutex); mutex = NULL; /*al_destroy_event_queue(queue);*/ /* already released by Allegro's destructors */ queue = NULL; } bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display, ALLEGRO_NATIVE_DIALOG *fd) { /* al_show_native_file_dialog() has a blocking interface. Since there is a need to handle drawing halt and drawing resume events before this function returns, users must call it from a separate thread. */ (void)display; /* possibly NULL */ /* fail if the native dialog addon is not initialized */ if (!al_is_native_dialog_addon_initialized()) { ALLEGRO_DEBUG("the native dialog addon is not initialized"); return false; } /* only one file chooser may be opened at a time */ al_lock_mutex(mutex); /* initial path (optional) */ const char *initial_path = NULL; if (fd->fc_initial_path != NULL) initial_path = al_path_cstr(fd->fc_initial_path, '/'); /* release any pre-existing paths */ if (fd->fc_paths != NULL) { for (size_t i = 0; i < fd->fc_path_count; i++) al_destroy_path(fd->fc_paths[i]); al_free(fd->fc_paths); } /* register the event source */ ALLEGRO_DISPLAY *dpy = get_active_display(); if (dpy != NULL) al_register_event_source(queue, &dpy->es); /* open the file chooser */ ALLEGRO_DEBUG("waiting for the file chooser"); ALLEGRO_USTR *mime_patterns = al_ustr_new(""); bool first = true; bool any_catchalls = false; for (size_t i = 0; i < _al_vector_size(&fd->fc_patterns); i++) { _AL_PATTERNS_AND_DESC *patterns_and_desc = _al_vector_ref(&fd->fc_patterns, (int)i); for (size_t j = 0; j < _al_vector_size(&patterns_and_desc->patterns_vec); j++) { _AL_PATTERN *pattern = _al_vector_ref(&patterns_and_desc->patterns_vec, (int)j); if (pattern->is_catchall) { any_catchalls = true; break; } if (pattern->is_mime) { if (!first) al_ustr_append_chr(mime_patterns, ';'); first = false; al_ustr_append(mime_patterns, al_ref_info(&pattern->info)); } } } if (any_catchalls) al_ustr_truncate(mime_patterns, 0); bool ret = open_file_chooser(fd->flags, al_cstr(mime_patterns), initial_path, &fd->fc_paths, &fd->fc_path_count); al_ustr_free(mime_patterns); ALLEGRO_DEBUG("done waiting for the file chooser"); /* ensure predictable behavior */ if (dpy != NULL) { /* We expect al_show_native_file_dialog() to be called before a drawing halt. We expect it to return after a drawing resume. */ wait_for_display_events(dpy); /* unregister the event source */ al_unregister_event_source(queue, &dpy->es); } /* done! */ ALLEGRO_DEBUG("done"); al_unlock_mutex(mutex); return ret; } int _al_show_native_message_box(ALLEGRO_DISPLAY *display, ALLEGRO_NATIVE_DIALOG *nd) { const char *heading = al_cstr(nd->mb_heading); const char *text = al_cstr(nd->mb_text); const char *buttons = nd->mb_buttons != NULL ? al_cstr(nd->mb_buttons) : NULL; (void)display; return show_message_box(heading, text, buttons, nd->flags); } bool _al_open_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { textlog->is_active = true; return true; } void _al_close_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { textlog->is_active = false; } void _al_append_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { if (textlog->is_active) { const char *title = al_cstr(textlog->title); const char *text = al_cstr(textlog->tl_pending_text); append_to_textlog(title, text); al_ustr_truncate(textlog->tl_pending_text, 0); } } bool _al_init_menu(ALLEGRO_MENU *menu) { (void)menu; return false; } bool _al_init_popup_menu(ALLEGRO_MENU *menu) { (void)menu; return false; } bool _al_insert_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { (void)item; (void)i; return false; } bool _al_destroy_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { (void)item; (void)i; return false; } bool _al_update_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { (void)item; (void)i; return false; } bool _al_show_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { (void)display; (void)menu; return false; } bool _al_hide_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { (void)display; (void)menu; return false; } bool _al_show_popup_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { (void)display; (void)menu; return false; } int _al_get_menu_display_height(void) { return 0; } ALLEGRO_DISPLAY *get_active_display(void) { ALLEGRO_SYSTEM *sys = al_get_system_driver(); ASSERT(sys); if (_al_vector_size(&sys->displays) == 0) return NULL; ALLEGRO_DISPLAY **dptr = (ALLEGRO_DISPLAY **)_al_vector_ref(&sys->displays, 0); return *dptr; } void wait_for_display_events(ALLEGRO_DISPLAY *dpy) { ALLEGRO_DISPLAY_ANDROID *d = (ALLEGRO_DISPLAY_ANDROID *)dpy; ALLEGRO_TIMEOUT timeout; ALLEGRO_EVENT event; bool expected_state = false; memset(&event, 0, sizeof(event)); /* We expect a drawing halt event to be on the queue. If that is not true, then the drawing halt did not take place for some unusual reason */ ALLEGRO_DEBUG("looking for a ALLEGRO_EVENT_DISPLAY_HALT_DRAWING"); while (al_get_next_event(queue, &event)) { if (event.type == ALLEGRO_EVENT_DISPLAY_HALT_DRAWING) { expected_state = true; break; } } /* skip if we're in an unexpected state */ if (!expected_state) { ALLEGRO_DEBUG("ALLEGRO_EVENT_DISPLAY_HALT_DRAWING not found"); return; } wait_for_drawing_resume: /* wait for ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING */ ALLEGRO_DEBUG("waiting for ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING"); while (event.type != ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING) al_wait_for_event(queue, &event); ALLEGRO_DEBUG("done waiting for ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING"); /* wait for al_acknowledge_drawing_resume() */ ALLEGRO_DEBUG("waiting for al_acknowledge_drawing_resume"); al_lock_mutex(d->mutex); while (!d->resumed) al_wait_cond(d->cond, d->mutex); al_unlock_mutex(d->mutex); ALLEGRO_DEBUG("done waiting for al_acknowledge_drawing_resume"); /* A resize event takes place here, as can be seen in the implementation of AllegroSurface.nativeOnChange() at src/android_display.c (at the time of this writing). However, the Allegro documentation does not specify that a resize event must follow a drawing resume. We expect that the user will call al_acknowledge_resize() immediately. We don't wait for the acknowledgement of the resize event, in case the implementation changes someday. We just wait a little bit. */ ; /* check if a new ALLEGRO_EVENT_DISPLAY_HALT_DRAWING is emitted */ ALLEGRO_DEBUG("waiting for another ALLEGRO_EVENT_DISPLAY_HALT_DRAWING"); al_init_timeout(&timeout, 0.5); while (al_wait_for_event_until(queue, &event, &timeout)) { if (event.type == ALLEGRO_EVENT_DISPLAY_HALT_DRAWING) goto wait_for_drawing_resume; else if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) al_init_timeout(&timeout, 0.5); } ALLEGRO_DEBUG("done waiting for another ALLEGRO_EVENT_DISPLAY_HALT_DRAWING"); } bool open_file_chooser(int flags, const char *patterns, const char *initial_path, ALLEGRO_PATH ***out_uri_strings, size_t *out_uri_count) { const char URI_DELIMITER = '\n'; char *result = NULL; /* initialize the results */ *out_uri_count = 0; *out_uri_strings = NULL; /* open the file chooser */ result = really_open_file_chooser(flags, patterns, initial_path); /* error? */ if (result == NULL) return false; /* split the returned string. If the file chooser was cancelled, variable result is an empty string */ for (char *next_uri = result, *p = result; *p; p++) { if (*p == URI_DELIMITER) { int last = (*out_uri_count)++; *out_uri_strings = al_realloc(*out_uri_strings, (*out_uri_count) * sizeof(ALLEGRO_PATH**)); /* ALLEGRO_PATHs don't explicitly support URIs at this time, but this works nonetheless. See parse_path_string() at src/path.c */ *p = '\0'; (*out_uri_strings)[last] = al_create_path(next_uri); next_uri = p+1; } } /* success! */ free(result); return true; } char *really_open_file_chooser(int flags, const char *patterns, const char *initial_path) { char *result = NULL; JNIEnv *env = _al_android_get_jnienv(); jobject activity = _al_android_activity_object(); jobject dialog = _jni_callObjectMethod(env, activity, "getNativeDialogAddon", "()L" ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/AllegroDialog;"); jstring jpatterns = _jni_call(env, jstring, NewStringUTF, patterns != NULL ? patterns : ""); jstring jinitial_path = _jni_call(env, jstring, NewStringUTF, initial_path != NULL ? initial_path : ""); jstring jresult = (jstring)_jni_callObjectMethodV(env, dialog, "openFileChooser", "(ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;", (jint)flags, jpatterns, jinitial_path); jboolean is_null_result = _jni_call(env, jboolean, IsSameObject, jresult, NULL); if (!is_null_result) { const char *tmp = _jni_call(env, const char*, GetStringUTFChars, jresult, NULL); result = strdup(tmp); _jni_callv(env, ReleaseStringUTFChars, jresult, tmp); } _jni_callv(env, DeleteLocalRef, jresult); _jni_callv(env, DeleteLocalRef, jinitial_path); _jni_callv(env, DeleteLocalRef, jpatterns); _jni_callv(env, DeleteLocalRef, dialog); return result; } int show_message_box(const char *title, const char *message, const char *buttons, int flags) { JNIEnv *env = _al_android_get_jnienv(); jobject activity = _al_android_activity_object(); jobject dialog = _jni_callObjectMethod(env, activity, "getNativeDialogAddon", "()L" ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/AllegroDialog;"); jstring jtitle = _jni_call(env, jstring, NewStringUTF, title != NULL ? title : ""); jstring jmessage = _jni_call(env, jstring, NewStringUTF, message != NULL ? message : ""); jstring jbuttons = _jni_call(env, jstring, NewStringUTF, buttons != NULL ? buttons : ""); int result = _jni_callIntMethodV(env, dialog, "showMessageBox", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)I", jtitle, jmessage, jbuttons, (jint)flags); _jni_callv(env, DeleteLocalRef, jbuttons); _jni_callv(env, DeleteLocalRef, jmessage); _jni_callv(env, DeleteLocalRef, jtitle); _jni_callv(env, DeleteLocalRef, dialog); return result; } void append_to_textlog(const char *tag, const char *message) { JNIEnv *env = _al_android_get_jnienv(); jobject activity = _al_android_activity_object(); jobject dialog = _jni_callObjectMethod(env, activity, "getNativeDialogAddon", "()L" ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/AllegroDialog;"); jstring jtag = _jni_call(env, jstring, NewStringUTF, tag != NULL ? tag : ""); jstring jmessage = _jni_call(env, jstring, NewStringUTF, message != NULL ? message : ""); _jni_callVoidMethodV(env, dialog, "appendToTextLog", "(Ljava/lang/String;Ljava/lang/String;)V", jtag, jmessage); _jni_callv(env, DeleteLocalRef, jmessage); _jni_callv(env, DeleteLocalRef, jtag); _jni_callv(env, DeleteLocalRef, dialog); } /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/addons/native_dialog/dialog.c000066400000000000000000000177171473414355200211550ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_native_dialog.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_vector.h" ALLEGRO_DEBUG_CHANNEL("native_dialog") static bool inited_addon = false; static _AL_VECTOR make_patterns_and_desc_vec(const ALLEGRO_USTR* patterns_ustr); static void free_patterns_and_desc_vec(_AL_VECTOR *patterns_and_desc_vec); /* Function: al_init_native_dialog_addon */ bool al_init_native_dialog_addon(void) { if (!inited_addon) { if (!_al_init_native_dialog_addon()) { ALLEGRO_ERROR("_al_init_native_dialog_addon failed.\n"); return false; } inited_addon = true; al_init_user_event_source(al_get_default_menu_event_source()); _al_add_exit_func(al_shutdown_native_dialog_addon, "al_shutdown_native_dialog_addon"); } return true; } /* Function: al_is_native_dialog_addon_initialized */ bool al_is_native_dialog_addon_initialized(void) { return inited_addon; } /* Function: al_shutdown_native_dialog_addon */ void al_shutdown_native_dialog_addon(void) { if (inited_addon) { al_destroy_user_event_source(al_get_default_menu_event_source()); _al_shutdown_native_dialog_addon(); inited_addon = false; } } /* Function: al_create_native_file_dialog */ ALLEGRO_FILECHOOSER *al_create_native_file_dialog( char const *initial_path, char const *title, char const *patterns, int mode) { ALLEGRO_NATIVE_DIALOG *fc; fc = al_calloc(1, sizeof *fc); if (initial_path) { fc->fc_initial_path = al_create_path(initial_path); } fc->title = al_ustr_new(title); fc->fc_patterns_ustr = al_ustr_new(patterns); fc->fc_patterns = make_patterns_and_desc_vec(fc->fc_patterns_ustr); fc->flags = mode; fc->dtor_item = _al_register_destructor(_al_dtor_list, "native_dialog", fc, (void (*)(void *))al_destroy_native_file_dialog); return (ALLEGRO_FILECHOOSER *)fc; } /* Function: al_show_native_file_dialog */ bool al_show_native_file_dialog(ALLEGRO_DISPLAY *display, ALLEGRO_FILECHOOSER *dialog) { ALLEGRO_NATIVE_DIALOG *fd = (ALLEGRO_NATIVE_DIALOG *)dialog; return _al_show_native_file_dialog(display, fd); } /* Function: al_get_native_file_dialog_count */ int al_get_native_file_dialog_count(const ALLEGRO_FILECHOOSER *dialog) { const ALLEGRO_NATIVE_DIALOG *fc = (const ALLEGRO_NATIVE_DIALOG *)dialog; return fc->fc_path_count; } /* Function: al_get_native_file_dialog_path */ const char *al_get_native_file_dialog_path( const ALLEGRO_FILECHOOSER *dialog, size_t i) { const ALLEGRO_NATIVE_DIALOG *fc = (const ALLEGRO_NATIVE_DIALOG *)dialog; if (i < fc->fc_path_count) return al_path_cstr(fc->fc_paths[i], ALLEGRO_NATIVE_PATH_SEP); return NULL; } /* Function: al_destroy_native_file_dialog */ void al_destroy_native_file_dialog(ALLEGRO_FILECHOOSER *dialog) { ALLEGRO_NATIVE_DIALOG *fd = (ALLEGRO_NATIVE_DIALOG *)dialog; size_t i; if (!fd) return; _al_unregister_destructor(_al_dtor_list, fd->dtor_item); al_ustr_free(fd->title); al_destroy_path(fd->fc_initial_path); for (i = 0; i < fd->fc_path_count; i++) { al_destroy_path(fd->fc_paths[i]); } al_free(fd->fc_paths); free_patterns_and_desc_vec(&fd->fc_patterns); al_ustr_free(fd->fc_patterns_ustr); al_free(fd); } /* Function: al_show_native_message_box */ int al_show_native_message_box(ALLEGRO_DISPLAY *display, char const *title, char const *heading, char const *text, char const *buttons, int flags) { ALLEGRO_NATIVE_DIALOG *fc; int r; ASSERT(title); ASSERT(heading); ASSERT(text); /* Note: the message box code cannot assume that Allegro is installed. * al_malloc and ustr functions are okay (with the assumption that the * user doesn't change the memory management functions in another thread * while this message box is open). */ fc = al_calloc(1, sizeof *fc); fc->title = al_ustr_new(title); fc->mb_heading = al_ustr_new(heading); fc->mb_text = al_ustr_new(text); fc->mb_buttons = al_ustr_new(buttons); fc->flags = flags; r = _al_show_native_message_box(display, fc); al_ustr_free(fc->title); al_ustr_free(fc->mb_heading); al_ustr_free(fc->mb_text); al_ustr_free(fc->mb_buttons); al_free(fc); return r; } /* Function: al_get_allegro_native_dialog_version */ uint32_t al_get_allegro_native_dialog_version(void) { return ALLEGRO_VERSION_INT; } static _AL_VECTOR split_patterns(const ALLEGRO_USTR* ustr) { int pattern_start = 0; int cur_pos = 0; bool is_mime = false; bool is_catchall = true; _AL_VECTOR patterns_vec; _al_vector_init(&patterns_vec, sizeof(_AL_PATTERN)); /* This does a straightforward split on semicolons. We check for MIME types * and catchalls, as some backends care about this. */ while (true) { int32_t c = al_ustr_get(ustr, cur_pos); if (c == -1 || c == ';') { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *pattern_ustr = al_ref_buffer(&info, al_cstr(ustr) + pattern_start, cur_pos - pattern_start); if (al_ustr_length(pattern_ustr) > 0) { _AL_PATTERN pattern = { .info = info, .is_mime = is_mime, .is_catchall = is_catchall }; *((_AL_PATTERN*)_al_vector_alloc_back(&patterns_vec)) = pattern; } is_mime = false; is_catchall = true; pattern_start = cur_pos + 1; } else if (c == '/') { is_mime = true; is_catchall = false; } else if (c != '*' && c != '.') { is_catchall = false; } if (c == -1) { break; } al_ustr_next(ustr, &cur_pos); } return patterns_vec; } static _AL_VECTOR make_patterns_and_desc_vec(const ALLEGRO_USTR* patterns_ustr) { _AL_VECTOR patterns_and_desc_vec; _al_vector_init(&patterns_and_desc_vec, sizeof(_AL_PATTERNS_AND_DESC)); if (al_ustr_length(patterns_ustr) == 0) return patterns_and_desc_vec; int line_start = 0; int chunk_start = 0; int cur_pos = 0; /* Split by newlines + spaces simultaneously. Chunks are separated by * spaces, and the final chunk is interpreted as the actual patterns, while * the rest of the line is the "description". */ while (true) { int32_t c = al_ustr_get(patterns_ustr, cur_pos); if (c == ' ') { chunk_start = cur_pos + 1; } else if (c == '\n' || c == -1) { ALLEGRO_USTR_INFO desc_info, real_patterns_info; const ALLEGRO_USTR *ustr; /* Strip trailing whitespace. */ int desc_end = chunk_start - 1; for (; desc_end >= line_start; desc_end--) { if (al_ustr_get(patterns_ustr, desc_end) != ' ') break; } al_ref_ustr(&desc_info, patterns_ustr, line_start, desc_end + 1); ustr = al_ref_ustr(&real_patterns_info, patterns_ustr, chunk_start, cur_pos); _AL_VECTOR patterns_vec = split_patterns(ustr); if (_al_vector_size(&patterns_vec) > 0) { _AL_PATTERNS_AND_DESC patterns_and_desc = { .desc = desc_info, .patterns_vec = patterns_vec }; *((_AL_PATTERNS_AND_DESC*)_al_vector_alloc_back(&patterns_and_desc_vec)) = patterns_and_desc; } chunk_start = cur_pos + 1; line_start = cur_pos + 1; } if (c == -1) { break; } al_ustr_next(patterns_ustr, &cur_pos); } return patterns_and_desc_vec; } static void free_patterns_and_desc_vec(_AL_VECTOR *patterns_and_desc_vec) { for (size_t i = 0; i < _al_vector_size(patterns_and_desc_vec); i++) { _AL_PATTERNS_AND_DESC *patterns_and_desc = (_AL_PATTERNS_AND_DESC*)_al_vector_ref(patterns_and_desc_vec, i); _al_vector_free(&patterns_and_desc->patterns_vec); } _al_vector_free(patterns_and_desc_vec); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/gtk_dialog.c000066400000000000000000000033611473414355200220100ustar00rootroot00000000000000#include #include #include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_native_dialog.h" #include "allegro5/internal/aintern_native_dialog_cfg.h" #include "allegro5/internal/aintern_xdisplay.h" #include "gtk_dialog.h" #include "gtk_xgtk.h" ALLEGRO_DEBUG_CHANNEL("gtk_dialog") bool _al_init_native_dialog_addon(void) { int argc = 0; char **argv = NULL; gdk_set_allowed_backends("x11"); if (!gtk_init_check(&argc, &argv)) { ALLEGRO_ERROR("gtk_init_check failed\n"); return false; } return _al_gtk_set_display_overridable_interface(true); } void _al_shutdown_native_dialog_addon(void) { _al_gtk_set_display_overridable_interface(false); } static void really_make_transient(GtkWidget *window, ALLEGRO_DISPLAY_XGLX *glx) { GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window)); GdkDisplay *gdk = GDK_DISPLAY(gdk_window_get_display(gdk_window)); GdkWindow *parent = gdk_x11_window_lookup_for_display(gdk, glx->window); if (!parent) parent = gdk_x11_window_foreign_new_for_display(gdk, glx->window); if (gdk_window != NULL) gdk_window_set_transient_for(gdk_window, parent); } static void realized(GtkWidget *window, gpointer data) { really_make_transient(window, (void *)data); } void _al_gtk_make_transient(ALLEGRO_DISPLAY *display, GtkWidget *window) { /* Set the current display window (if any) as the parent of the dialog. */ ALLEGRO_DISPLAY_XGLX *glx = (void *)display; if (glx) { if (!gtk_widget_get_realized(window)) g_signal_connect(window, "realize", G_CALLBACK(realized), (void *)glx); else really_make_transient(window, glx); } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/gtk_dialog.h000066400000000000000000000020151473414355200220100ustar00rootroot00000000000000#ifndef __al_included_gtk_dialog_h #define __al_included_gtk_dialog_h #include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_native_dialog.h" #define ACK_OK ((void *)0x1111) #define ACK_ERROR ((void *)0x2222) #define ACK_OPENED ((void *)0x3333) #define ACK_CLOSED ((void *)0x4444) void _al_gtk_make_transient(ALLEGRO_DISPLAY *display, GtkWidget *window); bool _al_gtk_ensure_thread(void); /* The API is assumed to be synchronous, but the user calls will not be * on the GTK thread. The following structure is used to pass data from the * user thread to the GTK thread, and then wait until the GTK has processed it. */ typedef struct ARGS_BASE ARGS_BASE; struct ARGS_BASE { ALLEGRO_MUTEX *mutex; ALLEGRO_COND *cond; bool done; bool response; }; bool _al_gtk_init_args(void *ptr, size_t size); bool _al_gtk_wait_for_args(GSourceFunc func, void *data); void *_al_gtk_lock_args(gpointer data); gboolean _al_gtk_release_args(gpointer data); #endif allegro5-5.2.10.1/addons/native_dialog/gtk_filesel.c000066400000000000000000000130731473414355200221750ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * GTK native dialog implementation. * * See LICENSE.txt for copyright information. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_native_dialog.h" #include "gtk_dialog.h" #include "gtk_xgtk.h" typedef struct { ALLEGRO_DISPLAY *display; ALLEGRO_NATIVE_DIALOG *dialog; } GTK_FILE_DIALOG_MESSAGE; /* [nd_gtk thread] */ static gboolean create_gtk_file_dialog(gpointer data) { GTK_FILE_DIALOG_MESSAGE *msg = data; ALLEGRO_DISPLAY *display = msg->display; ALLEGRO_NATIVE_DIALOG *fd = msg->dialog; bool save = fd->flags & ALLEGRO_FILECHOOSER_SAVE; bool folder = fd->flags & ALLEGRO_FILECHOOSER_FOLDER; gint result; GtkWidget *window; window = gtk_file_chooser_dialog_new(al_cstr(fd->title), NULL, save ? GTK_FILE_CHOOSER_ACTION_SAVE : folder ? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL, save ? "_Save" : "_Open", GTK_RESPONSE_ACCEPT, NULL); _al_gtk_make_transient(display, window); if (save) { gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER(window), true); } if (fd->fc_initial_path) { bool is_dir; bool exists; const char *path = al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP); if (al_filename_exists(path)) { exists = true; ALLEGRO_FS_ENTRY *fs = al_create_fs_entry(path); is_dir = al_get_fs_entry_mode(fs) & ALLEGRO_FILEMODE_ISDIR; al_destroy_fs_entry(fs); } else { exists = false; is_dir = false; } if (is_dir) { gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(window), al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP)); } else if (exists) { gtk_file_chooser_set_filename (GTK_FILE_CHOOSER(window), al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP)); } else { ALLEGRO_PATH *dir_path = al_clone_path(fd->fc_initial_path); if (dir_path) { al_set_path_filename(dir_path, NULL); gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(window), al_path_cstr(dir_path, ALLEGRO_NATIVE_PATH_SEP)); if (save) { gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(window), al_get_path_filename(fd->fc_initial_path)); } al_destroy_path(dir_path); } } } if (fd->flags & ALLEGRO_FILECHOOSER_MULTIPLE) gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(window), true); for (size_t i = 0; i < _al_vector_size(&fd->fc_patterns); i++) { _AL_PATTERNS_AND_DESC *patterns_and_desc = _al_vector_ref(&fd->fc_patterns, i); const ALLEGRO_USTR *desc = al_ref_info(&patterns_and_desc->desc); GtkFileFilter* filter = gtk_file_filter_new(); if (al_ustr_size(desc) > 0) { char *cstr = al_cstr_dup(desc); gtk_file_filter_set_name(filter, cstr); al_free(cstr); } else { gtk_file_filter_set_name(filter, "All supported files"); } for (size_t j = 0; j < _al_vector_size(&patterns_and_desc->patterns_vec); j++) { _AL_PATTERN *pattern = _al_vector_ref(&patterns_and_desc->patterns_vec, j); char *cstr = al_cstr_dup(al_ref_info(&pattern->info)); if (pattern->is_mime) { gtk_file_filter_add_mime_type(filter, cstr); } else { gtk_file_filter_add_pattern(filter, cstr); } al_free(cstr); } gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(window), filter); } result = gtk_dialog_run(GTK_DIALOG(window)); if (result == GTK_RESPONSE_ACCEPT) { GSList* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(window)); int i; GSList* iter; fd->fc_path_count = g_slist_length(filenames); fd->fc_paths = al_malloc(fd->fc_path_count * sizeof(void *)); for (i = 0, iter = filenames; i < (int)fd->fc_path_count; i++, iter = g_slist_next(iter)) { fd->fc_paths[i] = al_create_path((const char*)iter->data); g_free(iter->data); } g_slist_free(filenames); } gtk_widget_destroy(window); ASSERT(fd->async_queue); g_async_queue_push(fd->async_queue, ACK_CLOSED); return FALSE; } /* [user thread] */ bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display, ALLEGRO_NATIVE_DIALOG *fd) { GTK_FILE_DIALOG_MESSAGE msg; if (!_al_gtk_ensure_thread()) return false; fd->async_queue = g_async_queue_new(); msg.display = display; msg.dialog = fd; g_timeout_add(0, create_gtk_file_dialog, &msg); /* Wait for a signal that the window is closed. */ while (g_async_queue_pop(fd->async_queue) != ACK_CLOSED) ; g_async_queue_unref(fd->async_queue); fd->async_queue = NULL; return true; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/gtk_menu.c000066400000000000000000000262171473414355200215220ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * GTK native dialog implementation. * * See LICENSE.txt for copyright information. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_native_dialog.h" #include "allegro5/internal/aintern_native_dialog_cfg.h" #include "gtk_dialog.h" #include "gtk_xgtk.h" ALLEGRO_DEBUG_CHANNEL("menu") typedef struct ARGS ARGS; struct ARGS { /* Must be first. */ ARGS_BASE base; GtkWidget *gtk_window; ALLEGRO_MENU *menu; ALLEGRO_MENU_ITEM *item; int i; }; typedef struct POPUP_ARGS POPUP_ARGS; struct POPUP_ARGS { /* Must be first. */ ARGS_BASE base; GtkWidget *gtk_window; ALLEGRO_MENU *menu; int x; int y; }; static void build_menu(GtkWidget *gmenu, ALLEGRO_MENU *amenu); /* [user thread] */ static bool clear_menu_extras(ALLEGRO_MENU *menu, ALLEGRO_MENU_ITEM *item, int index, void *extra) { (void) index; (void) extra; if (item) item->extra1 = NULL; else menu->extra1 = NULL; return false; } /* [user thread] */ static bool make_menu_item_args(ARGS *args, ALLEGRO_MENU_ITEM *item, int i) { if (_al_gtk_init_args(args, sizeof(*args))) { args->item = item; args->i = i; return true; } return false; } /* [gtk thread] */ static void menuitem_response(ALLEGRO_MENU_ITEM *menu_item) { if (menu_item->parent) _al_emit_menu_event(menu_item->parent->display, menu_item->unique_id); } /* [gtk thread] */ static void checkbox_on_toggle(ALLEGRO_MENU_ITEM *item) { /* make sure the menu item remains the same state */ if (gtk_check_menu_item_get_active(item->extra1)) { item->flags |= ALLEGRO_MENU_ITEM_CHECKED; } else { item->flags &= ~ALLEGRO_MENU_ITEM_CHECKED; } } /* [gtk thread] */ static GtkWidget *build_menu_item(ALLEGRO_MENU_ITEM *aitem) { GtkWidget *gitem; if (!aitem->caption) { gitem = gtk_separator_menu_item_new(); } else { ALLEGRO_USTR *caption = al_ustr_dup(aitem->caption); /* convert & to _ using unprintable chars as placeholders */ al_ustr_find_replace_cstr(caption, 0, "_", "\x01\x02"); al_ustr_find_replace_cstr(caption, 0, "&", "_"); al_ustr_find_replace_cstr(caption, 0, "\x01\x02", "__"); if (aitem->flags & ALLEGRO_MENU_ITEM_CHECKBOX) { gitem = gtk_check_menu_item_new_with_mnemonic(al_cstr(caption)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gitem), aitem->flags & ALLEGRO_MENU_ITEM_CHECKED); g_signal_connect_swapped (gitem, "toggled", G_CALLBACK(checkbox_on_toggle), (gpointer) aitem); } else { /* always create an image menu item, in case the user ever sets an icon */ gitem = gtk_menu_item_new_with_mnemonic(al_cstr(caption)); } al_ustr_free(caption); gtk_widget_set_sensitive(gitem, !(aitem->flags & ALLEGRO_MENU_ITEM_DISABLED)); aitem->extra1 = gitem; if (aitem->popup) { GtkWidget *gsubmenu = gtk_menu_new(); build_menu(gsubmenu, aitem->popup); aitem->popup->extra1 = gsubmenu; gtk_widget_show(gsubmenu); gtk_menu_item_set_submenu(GTK_MENU_ITEM(gitem), gsubmenu); } else if (aitem->id) { g_signal_connect_swapped (gitem, "activate", G_CALLBACK(menuitem_response), (gpointer) aitem); } } gtk_widget_show(gitem); return gitem; } /* [gtk thread] */ static void build_menu(GtkWidget *gmenu, ALLEGRO_MENU *amenu) { size_t i; for (i = 0; i < _al_vector_size(&amenu->items); ++i) { ALLEGRO_MENU_ITEM *aitem = * (ALLEGRO_MENU_ITEM **) _al_vector_ref(&amenu->items, i); GtkWidget *gitem = build_menu_item(aitem); gtk_menu_shell_append(GTK_MENU_SHELL(gmenu), gitem); } } /* [user thread] */ bool _al_init_menu(ALLEGRO_MENU *menu) { (void) menu; /* Do nothing here, because menu creation is defered until it is displayed. */ return true; } /* [user thread] */ bool _al_init_popup_menu(ALLEGRO_MENU *menu) { return _al_init_menu(menu); } /* [gtk thread] */ static gboolean do_destroy_menu(gpointer data) { ARGS *args = _al_gtk_lock_args(data); gtk_widget_destroy(args->menu->extra1); args->menu->extra1 = NULL; return _al_gtk_release_args(args); } /* [user thread] */ bool _al_destroy_menu(ALLEGRO_MENU *menu) { ARGS args; if (!menu->extra1) return true; if (!_al_gtk_init_args(&args, sizeof(args))) return false; args.menu = menu; _al_gtk_wait_for_args(do_destroy_menu, &args); _al_walk_over_menu(menu, clear_menu_extras, NULL); return true; } /* [gtk thread] */ static gboolean do_insert_menu_item_at(gpointer data) { ARGS *args = _al_gtk_lock_args(data); if (!args->item->extra1) { args->item->extra1 = build_menu_item(args->item); } gtk_menu_shell_insert(GTK_MENU_SHELL(args->item->parent->extra1), args->item->extra1, args->i); return _al_gtk_release_args(data); } /* [user thread] */ bool _al_insert_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { if (item->parent->extra1) { ARGS args; if (!_al_gtk_init_args(&args, sizeof(args))) return false; args.item = item; args.i = i; _al_gtk_wait_for_args(do_insert_menu_item_at, &args); } return true; } /* [gtk thread] */ static gboolean do_destroy_menu_item_at(gpointer data) { ARGS *args = _al_gtk_lock_args(data); gtk_widget_destroy(GTK_WIDGET(args->item->extra1)); args->item->extra1 = NULL; return _al_gtk_release_args(args); } /* [user thread] */ bool _al_destroy_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { if (item->extra1) { ARGS args; if (!make_menu_item_args(&args, item, i)) return false; _al_gtk_wait_for_args(do_destroy_menu_item_at, &args); if (item->popup) { /* if this has a submenu, then deleting this item will have automatically deleted all of its GTK widgets */ _al_walk_over_menu(item->popup, clear_menu_extras, NULL); } } return true; } /* [gtk thread] */ static gboolean do_update_menu_item_at(gpointer data) { ARGS *args = _al_gtk_lock_args(data); GtkWidget *gitem; gtk_widget_destroy(args->item->extra1); args->item->extra1 = NULL; gitem = build_menu_item(args->item); gtk_menu_shell_insert(GTK_MENU_SHELL(args->item->parent->extra1), gitem, args->i); return _al_gtk_release_args(args); } /* [user thread] */ bool _al_update_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { if (item->extra1) { ARGS args; if (!make_menu_item_args(&args, item, i)) return false; _al_gtk_wait_for_args(do_update_menu_item_at, &args); } return true; } /* [gtk thread] */ static gboolean do_show_display_menu(gpointer data) { ARGS *args = _al_gtk_lock_args(data); if (!args->menu->extra1) { GtkWidget *menu_bar = gtk_menu_bar_new(); build_menu(menu_bar, args->menu); GtkWidget *vbox = gtk_bin_get_child(GTK_BIN(args->gtk_window)); gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 0); gtk_widget_show(menu_bar); args->menu->extra1 = menu_bar; } gtk_widget_show(gtk_widget_get_parent(args->menu->extra1)); return _al_gtk_release_args(args); } /* [user thread] */ bool _al_show_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { GtkWidget *gtk_window; ARGS args; gtk_window = _al_gtk_get_window(display); if (!gtk_window) { return false; } if (!_al_gtk_init_args(&args, sizeof(args))) { return false; } args.gtk_window = gtk_window; args.menu = menu; return _al_gtk_wait_for_args(do_show_display_menu, &args); } /* [gtk thread] */ static gboolean do_hide_display_menu(gpointer data) { ARGS *args = _al_gtk_lock_args(data); gtk_widget_destroy(GTK_WIDGET(args->menu->extra1)); args->menu->extra1 = NULL; return _al_gtk_release_args(data); } /* [user thread] */ bool _al_hide_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { GtkWidget *gtk_window; ARGS args; if (!(gtk_window = _al_gtk_get_window(display))) return false; if (!_al_gtk_init_args(&args, sizeof(args))) return false; args.gtk_window = gtk_window; args.menu = menu; _al_gtk_wait_for_args(do_hide_display_menu, &args); _al_walk_over_menu(menu, clear_menu_extras, NULL); return true; } /* [gtk thread] */ static void popop_on_hide(ALLEGRO_MENU *menu) { (void) menu; /* in case we want to notify on popup close */ } /* [gtk thread] */ static gboolean do_show_popup_menu(gpointer data) { POPUP_ARGS *args = (POPUP_ARGS *) data; _al_gtk_lock_args(args); if (!args->menu->extra1) { GtkWidget *menu = gtk_menu_new(); build_menu(menu, args->menu); gtk_widget_show(menu); args->menu->extra1 = menu; g_signal_connect_swapped (menu, "hide", G_CALLBACK(popop_on_hide), (gpointer) args->menu); } #if GTK_CHECK_VERSION(3, 22, 0) GtkWidget *vbox = gtk_bin_get_child(GTK_BIN(args->gtk_window)); GList* list = gtk_container_get_children(GTK_CONTAINER(vbox)); int menu_height = 0; if (g_list_length(list) == 2) { GtkAllocation alloc; gtk_widget_get_allocation(GTK_WIDGET(list->data), &alloc); menu_height = alloc.height; } g_list_free(list); GdkSeat* seat = gdk_display_get_default_seat( gdk_window_get_display(gtk_widget_get_window(args->gtk_window))); GdkDevice *device = gdk_seat_get_pointer(seat); GdkEventButton event = { }; event.type = GDK_BUTTON_RELEASE; event.time = GDK_CURRENT_TIME; event.device = device; GdkRectangle rect = { .x=args->x, .y=args->y + menu_height, .width=1, .height=1 }; gtk_menu_popup_at_rect(args->menu->extra1, gtk_widget_get_window(args->gtk_window), &rect, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, (GdkEvent*)&event); #else gtk_menu_popup(args->menu->extra1, NULL, NULL, NULL, NULL, 1, 0); #endif args->base.response = true; _al_gtk_release_args(args); return FALSE; } bool _al_show_popup_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { GtkWidget *gtk_window; POPUP_ARGS args; ALLEGRO_MOUSE_STATE state; al_get_mouse_state(&state); if (!(gtk_window = _al_gtk_get_window(display))) return false; if (!_al_gtk_init_args(&args, sizeof(args))) { return false; } args.gtk_window = gtk_window; args.menu = menu; args.x = al_get_mouse_state_axis(&state, 0); args.y = al_get_mouse_state_axis(&state, 1); return _al_gtk_wait_for_args(do_show_popup_menu, &args); } int _al_get_menu_display_height(void) { return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/gtk_msgbox.c000066400000000000000000000104531473414355200220500ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * GTK native dialog implementation. * * See LICENSE.txt for copyright information. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_native_dialog.h" #include "gtk_dialog.h" #include "gtk_xgtk.h" typedef struct { ALLEGRO_DISPLAY *display; ALLEGRO_NATIVE_DIALOG *dialog; } Msg; /* Note: the message box code cannot assume that Allegro is installed. */ static void msgbox_destroy(GtkWidget *w, gpointer data) { ALLEGRO_NATIVE_DIALOG *nd = data; (void)w; ASSERT(nd->async_queue); g_async_queue_push(nd->async_queue, ACK_CLOSED); } static void msgbox_response(GtkDialog *dialog, gint response_id, gpointer user_data) { ALLEGRO_NATIVE_DIALOG *nd = (void *)user_data; (void)dialog; switch (response_id) { case GTK_RESPONSE_DELETE_EVENT: nd->mb_pressed_button = 0; break; case GTK_RESPONSE_YES: case GTK_RESPONSE_OK: nd->mb_pressed_button = 1; break; case GTK_RESPONSE_NO: case GTK_RESPONSE_CANCEL: nd->mb_pressed_button = 2; break; default: nd->mb_pressed_button = response_id; } } /* [gtk thread] */ static gboolean create_native_message_box(gpointer data) { Msg *msg = data; ALLEGRO_DISPLAY *display = msg->display; ALLEGRO_NATIVE_DIALOG *fd = msg->dialog; GtkWidget *window; /* Create a new file selection widget */ GtkMessageType type = GTK_MESSAGE_INFO; GtkButtonsType buttons = GTK_BUTTONS_OK; if (fd->flags & ALLEGRO_MESSAGEBOX_YES_NO) type = GTK_MESSAGE_QUESTION; if (fd->flags & ALLEGRO_MESSAGEBOX_QUESTION) type = GTK_MESSAGE_QUESTION; if (fd->flags & ALLEGRO_MESSAGEBOX_WARN) type = GTK_MESSAGE_WARNING; if (fd->flags & ALLEGRO_MESSAGEBOX_ERROR) type = GTK_MESSAGE_ERROR; if (fd->flags & ALLEGRO_MESSAGEBOX_YES_NO) buttons = GTK_BUTTONS_YES_NO; if (fd->flags & ALLEGRO_MESSAGEBOX_OK_CANCEL) buttons = GTK_BUTTONS_OK_CANCEL; if (fd->mb_buttons) buttons = GTK_BUTTONS_NONE; window = gtk_message_dialog_new(NULL, 0, type, buttons, "%s", al_cstr(fd->mb_heading)); gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(window), "%s", al_cstr(fd->mb_text)); _al_gtk_make_transient(display, window); if (fd->mb_buttons) { int i = 1; int pos = 0; while (1) { int next = al_ustr_find_chr(fd->mb_buttons, pos, '|'); int pos2 = next; if (next == -1) pos2 = al_ustr_size(fd->mb_buttons); ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *button_text; button_text = al_ref_ustr(&info, fd->mb_buttons, pos, pos2); pos = pos2 + 1; char buffer[256]; al_ustr_to_buffer(button_text, buffer, sizeof buffer); gtk_dialog_add_button(GTK_DIALOG(window), buffer, i++); if (next == -1) break; } } gtk_window_set_title(GTK_WINDOW(window), al_cstr(fd->title)); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(msgbox_destroy), fd); g_signal_connect(G_OBJECT(window), "response", G_CALLBACK(msgbox_response), fd); g_signal_connect_swapped(G_OBJECT(window), "response", G_CALLBACK(gtk_widget_destroy), window); gtk_widget_show(window); return FALSE; } /* [user thread] */ int _al_show_native_message_box(ALLEGRO_DISPLAY *display, ALLEGRO_NATIVE_DIALOG *fd) { Msg msg; if (!_al_gtk_ensure_thread()) return 0; /* "cancelled" */ fd->async_queue = g_async_queue_new(); msg.display = display; msg.dialog = fd; g_timeout_add(0, create_native_message_box, &msg); /* Wait for a signal that the window is closed. */ while (g_async_queue_pop(fd->async_queue) != ACK_CLOSED) ; g_async_queue_unref(fd->async_queue); fd->async_queue = NULL; return fd->mb_pressed_button; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/gtk_textlog.c000066400000000000000000000143761473414355200222470ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * GTK native dialog implementation. * * See LICENSE.txt for copyright information. */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_native_dialog.h" #include "gtk_dialog.h" #include "gtk_xgtk.h" typedef struct { ALLEGRO_NATIVE_DIALOG *dialog; } Msg; static void emit_close_event(ALLEGRO_NATIVE_DIALOG *textlog, bool keypress) { ALLEGRO_EVENT event; event.user.type = ALLEGRO_EVENT_NATIVE_DIALOG_CLOSE; event.user.timestamp = al_get_time(); event.user.data1 = (intptr_t)textlog; event.user.data2 = (intptr_t)keypress; al_emit_user_event(&textlog->tl_events, &event, NULL); } static gboolean textlog_delete(GtkWidget *w, GdkEvent *gevent, gpointer userdata) { ALLEGRO_NATIVE_DIALOG *textlog = userdata; (void)w; (void)gevent; if (!(textlog->flags & ALLEGRO_TEXTLOG_NO_CLOSE)) { emit_close_event(textlog, false); } /* Don't close the window. */ return TRUE; } static gboolean textlog_key_press(GtkWidget *w, GdkEventKey *gevent, gpointer userdata) { ALLEGRO_NATIVE_DIALOG *textlog = userdata; (void)w; if (gevent->keyval == GDK_KEY_Escape) { emit_close_event(textlog, true); } return FALSE; } static void textlog_destroy(GtkWidget *w, gpointer data) { ALLEGRO_NATIVE_DIALOG *nd = data; (void)w; ASSERT(nd->async_queue); g_async_queue_push(nd->async_queue, ACK_CLOSED); } /* [gtk thread] */ static gboolean create_native_text_log(gpointer data) { Msg *msg = data; ALLEGRO_NATIVE_DIALOG *textlog = msg->dialog; GtkCssProvider *css_provider; GtkStyleContext *context; /* Create a new text log window. */ GtkWidget *top = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(top), 640, 480); gtk_window_set_title(GTK_WINDOW(top), al_cstr(textlog->title)); if (textlog->flags & ALLEGRO_TEXTLOG_NO_CLOSE) { gtk_window_set_deletable(GTK_WINDOW(top), false); } else { g_signal_connect(G_OBJECT(top), "key-press-event", G_CALLBACK(textlog_key_press), textlog); } g_signal_connect(G_OBJECT(top), "delete-event", G_CALLBACK(textlog_delete), textlog); g_signal_connect(G_OBJECT(top), "destroy", G_CALLBACK(textlog_destroy), textlog); GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(top), scroll); GtkWidget *view = gtk_text_view_new(); gtk_text_view_set_editable(GTK_TEXT_VIEW(view), false); gtk_widget_set_name(GTK_WIDGET(view), "native_text_log"); if (textlog->flags & ALLEGRO_TEXTLOG_MONOSPACE) { css_provider = gtk_css_provider_new(); gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(css_provider), "#native_text_log {\n" " font-family: monospace;\n" "}\n", -1, NULL); context = gtk_widget_get_style_context(GTK_WIDGET(view)); gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); g_object_unref(css_provider); } gtk_container_add(GTK_CONTAINER(scroll), view); gtk_widget_show(view); gtk_widget_show(scroll); gtk_widget_show(top); textlog->window = top; textlog->tl_textview = view; ASSERT(textlog->async_queue); g_async_queue_push(textlog->async_queue, ACK_OPENED); return FALSE; } /* [user thread] */ bool _al_open_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { Msg msg; if (!_al_gtk_ensure_thread()) { textlog->tl_init_error = true; return false; } textlog->async_queue = g_async_queue_new(); msg.dialog = textlog; g_timeout_add(0, create_native_text_log, &msg); while (g_async_queue_pop(textlog->async_queue) != ACK_OPENED) ; return true; } /* [gtk thread] */ static gboolean do_append_native_text_log(gpointer data) { ALLEGRO_NATIVE_DIALOG *textlog = data; al_lock_mutex(textlog->tl_text_mutex); GtkTextView *tv = GTK_TEXT_VIEW(textlog->tl_textview); GtkTextBuffer *buffer = gtk_text_view_get_buffer(tv); GtkTextIter iter; GtkTextMark *mark; gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, al_cstr(textlog->tl_pending_text), -1); mark = gtk_text_buffer_create_mark(buffer, NULL, &iter, FALSE); gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(textlog->tl_textview), mark); gtk_text_buffer_delete_mark(buffer, mark); al_ustr_truncate(textlog->tl_pending_text, 0); textlog->tl_have_pending = false; al_unlock_mutex(textlog->tl_text_mutex); return FALSE; } /* [user thread] */ void _al_append_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { if (textlog->tl_have_pending) return; textlog->tl_have_pending = true; gdk_threads_add_timeout(100, do_append_native_text_log, textlog); } /* [gtk thread] */ static gboolean do_close_native_text_log(gpointer data) { ALLEGRO_NATIVE_DIALOG *textlog = data; /* Delay closing until appends are completed. */ if (textlog->tl_have_pending) { return TRUE; } /* This causes the GTK window as well as all of its children to * be freed. Further it will call the destroy function which we * connected to the destroy signal which in turn causes our * gtk thread to quit. */ gtk_widget_destroy(textlog->window); return FALSE; } /* [user thread] */ void _al_close_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { gdk_threads_add_timeout(0, do_close_native_text_log, textlog); while (g_async_queue_pop(textlog->async_queue) != ACK_CLOSED) ; g_async_queue_unref(textlog->async_queue); textlog->async_queue = NULL; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/gtk_thread.c000066400000000000000000000075241473414355200220250ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_native_dialog.h" #include "allegro5/internal/aintern_native_dialog_cfg.h" #include "gtk_dialog.h" #include "allegro5/internal/aintern_vector.h" ALLEGRO_DEBUG_CHANNEL("gtk") /* GTK is not thread safe. We launch a single thread which runs the GTK main * loop, and it is the only thread which calls into GTK. (g_timeout_add may be * called from other threads without locking.) * * We used to attempt to use gdk_threads_enter/gdk_threads_leave but hit * some problems with deadlocks so switched to this. */ // G_STATIC_MUTEX_INIT causes a warning about a missing initializer, so if we // have version 2.32 or newer don't use it to avoid the warning. #if GLIB_CHECK_VERSION(2, 32, 0) #define NEWER_GLIB 1 #else #define NEWER_GLIB 0 #endif #if NEWER_GLIB static GMutex nd_gtk_mutex; static void nd_gtk_lock(void) { g_mutex_lock(&nd_gtk_mutex); } static void nd_gtk_unlock(void) { g_mutex_unlock(&nd_gtk_mutex); } #else static GStaticMutex nd_gtk_mutex = G_STATIC_MUTEX_INIT; static void nd_gtk_lock(void) { g_static_mutex_lock(&nd_gtk_mutex); } static void nd_gtk_unlock(void) { g_static_mutex_unlock(&nd_gtk_mutex); } #endif static GThread *nd_gtk_thread = NULL; static void *nd_gtk_thread_func(void *data) { GAsyncQueue *queue = data; ALLEGRO_DEBUG("GLIB %d.%d.%d\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); g_async_queue_push(queue, ACK_OK); gtk_main(); ALLEGRO_INFO("GTK stopped.\n"); return NULL; } bool _al_gtk_ensure_thread(void) { bool ok = true; #if !NEWER_GLIB if (!g_thread_supported()) g_thread_init(NULL); #endif /* al_init_native_dialog_addon() didn't always exist so GTK might not have * been initialised. gtk_init_check knows if it's been initialised already * so we can just call it again. */ { int argc = 0; char **argv = NULL; if (!gtk_init_check(&argc, &argv)) { ALLEGRO_ERROR("gtk_init_check failed\n"); return false; } } nd_gtk_lock(); if (!nd_gtk_thread) { GAsyncQueue *queue = g_async_queue_new(); #if NEWER_GLIB nd_gtk_thread = g_thread_new("gtk thread", nd_gtk_thread_func, queue); #else bool joinable = FALSE; nd_gtk_thread = g_thread_create(nd_gtk_thread_func, queue, joinable, NULL); #endif if (!nd_gtk_thread) { ok = false; } else { ok = (g_async_queue_pop(queue) == ACK_OK); } g_async_queue_unref(queue); } nd_gtk_unlock(); return ok; } /* [user thread] */ bool _al_gtk_init_args(void *ptr, size_t size) { ARGS_BASE *args = (ARGS_BASE *)ptr; memset(args, 0, size); args->mutex = al_create_mutex(); if (!args->mutex) { return false; } args->cond = al_create_cond(); if (!args->cond) { al_destroy_mutex(args->mutex); return false; } args->done = false; args->response = true; return args; } /* [user thread] */ bool _al_gtk_wait_for_args(GSourceFunc func, void *data) { ARGS_BASE *args = (ARGS_BASE *) data; bool response; al_lock_mutex(args->mutex); g_timeout_add(0, func, data); while (args->done == false) { al_wait_cond(args->cond, args->mutex); } al_unlock_mutex(args->mutex); response = args->response; al_destroy_mutex(args->mutex); al_destroy_cond(args->cond); return response; } /* [gtk thread] */ void *_al_gtk_lock_args(gpointer data) { ARGS_BASE *args = (ARGS_BASE *) data; al_lock_mutex(args->mutex); return args; } /* [gtk thread] */ gboolean _al_gtk_release_args(gpointer data) { ARGS_BASE *args = (ARGS_BASE *) data; args->done = true; al_signal_cond(args->cond); al_unlock_mutex(args->mutex); return FALSE; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/gtk_xgtk.c000066400000000000000000000340651473414355200215330ustar00rootroot00000000000000#include #include #define ALLEGRO_INTERNAL_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/internal/aintern_native_dialog_cfg.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xevents.h" #include "allegro5/internal/aintern_xsystem.h" #include "gtk_dialog.h" #include "gtk_xgtk.h" ALLEGRO_DEBUG_CHANNEL("gtk") typedef struct ARGS_CREATE { ARGS_BASE base; /* must be first */ ALLEGRO_DISPLAY_XGLX *display; int w; int h; const char *title; } ARGS_CREATE; typedef struct { ARGS_BASE base; /* must be first */ ALLEGRO_DISPLAY_XGLX *display; bool is_last; } ARGS_DESTROY; typedef struct { ARGS_BASE base; /* must be first */ ALLEGRO_DISPLAY_XGLX *display; int w; int h; } ARGS_RESIZE; typedef struct { ARGS_BASE base; /* must be first */ ALLEGRO_DISPLAY_XGLX *display; const char *title; } ARGS_TITLE; typedef struct { ARGS_BASE base; /* must be first */ ALLEGRO_DISPLAY_XGLX *display; bool fullscreen; } ARGS_FULLSCREEN_WINDOW; typedef struct { ARGS_BASE base; /* must be first */ ALLEGRO_DISPLAY_XGLX *display; int x; int y; } ARGS_POSITION; typedef struct ARGS_SET_FLAG { ARGS_BASE base; /* must be first */ ALLEGRO_DISPLAY_XGLX *display; bool onoff; } ARGS_SET_FLAG; /* forward declarations */ static gboolean xgtk_quit_callback(GtkWidget *widget, GdkEvent *event, ALLEGRO_DISPLAY *display); static gboolean xgtk_handle_configure_event(GtkWidget *widget, GdkEventConfigure *event, ALLEGRO_DISPLAY *display); static void xgtk_set_fullscreen_window(ALLEGRO_DISPLAY *display, bool onoff); static struct ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE xgtk_override_vt; /* [gtk thread] */ static gboolean do_create_display_hook(gpointer data) { const ARGS_CREATE *args = _al_gtk_lock_args(data); ALLEGRO_DISPLAY *display = (ALLEGRO_DISPLAY *)args->display; ALLEGRO_DISPLAY_XGLX *d = args->display; const int w = args->w; const int h = args->h; GtkWidget *window; GtkWidget *vbox; GtkWidget *socket; window = gtk_window_new(GTK_WINDOW_TOPLEVEL); d->gtk->gtkwindow = window; gtk_window_set_default_size(GTK_WINDOW(window), w, h); g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(xgtk_quit_callback), display); g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(xgtk_handle_configure_event), display); vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_container_add(GTK_CONTAINER(window), vbox); socket = gtk_socket_new(); d->gtk->gtksocket = socket; gtk_box_pack_end(GTK_BOX(vbox), socket, TRUE, TRUE, 0); gtk_socket_add_id(GTK_SOCKET(socket), d->window); ALLEGRO_DEBUG("gtk_socket_add_id: window = %ld\n", d->window); gtk_window_set_title(GTK_WINDOW(window), args->title); gtk_widget_show_all(window); if (display->flags & ALLEGRO_RESIZABLE) { /* Allow socket widget to be resized smaller than initial size. */ gtk_widget_set_size_request(socket, -1, -1); gtk_window_set_resizable(GTK_WINDOW(window), true); } else { gtk_window_set_resizable(GTK_WINDOW(window), false); } if (display->flags & ALLEGRO_FULLSCREEN_WINDOW) { gtk_window_fullscreen(GTK_WINDOW(window)); } d->overridable_vt = &xgtk_override_vt; return _al_gtk_release_args(data); } /* [user thread] */ static bool xgtk_create_display_hook(ALLEGRO_DISPLAY *display, int w, int h) { ALLEGRO_DISPLAY_XGLX *d = (ALLEGRO_DISPLAY_XGLX *)display; ARGS_CREATE args; d->gtk = al_calloc(1, sizeof(*(d->gtk))); if (!d->gtk) { ALLEGRO_WARN("Out of memory\n"); return false; } if (!_al_gtk_ensure_thread()) { al_free(d->gtk); d->gtk = NULL; return false; } if (!_al_gtk_init_args(&args, sizeof(args))) { al_free(d->gtk); d->gtk = NULL; return false; } args.display = d; args.w = w; args.h = h; args.title = al_get_new_window_title(); return _al_gtk_wait_for_args(do_create_display_hook, &args); } static gboolean xgtk_quit_callback(GtkWidget *widget, GdkEvent *event, ALLEGRO_DISPLAY *display) { (void)widget; (void)event; _al_display_xglx_closebutton(display, NULL); return TRUE; } static gboolean xgtk_handle_configure_event(GtkWidget *widget, GdkEventConfigure *event, ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_XGLX *d = (ALLEGRO_DISPLAY_XGLX *)display; (void)widget; (void)event; /* Update our idea of the window position. * event->x, event->y is incorrect. */ gtk_window_get_position(GTK_WINDOW(d->gtk->gtkwindow), &d->x, &d->y); return FALSE; } /* [gtk thread] */ static gboolean do_destroy_display_hook(gpointer data) { ARGS_DESTROY *args = _al_gtk_lock_args(data); ALLEGRO_DISPLAY_XGLX *d = args->display; bool is_last = args->is_last; gtk_widget_destroy(d->gtk->gtkwindow); if (is_last) { gtk_main_quit(); } return _al_gtk_release_args(data); } /* [user thread] */ static void xgtk_destroy_display_hook(ALLEGRO_DISPLAY *display, bool is_last) { ALLEGRO_DISPLAY_XGLX *d = (ALLEGRO_DISPLAY_XGLX *)display; ARGS_DESTROY args; if (!_al_gtk_init_args(&args, sizeof(args))) return; args.display = d; args.is_last = is_last; _al_gtk_wait_for_args(do_destroy_display_hook, &args); al_free(d->gtk); d->gtk = NULL; } /* [gtk thread] */ static gboolean do_resize_display1(gpointer data) { ARGS_RESIZE *args = _al_gtk_lock_args(data); ALLEGRO_DISPLAY_XGLX *d = args->display; int w = args->w; int h = args->h; /* Using gtk_window_resize by itself is wrong because it does not take * into account the space occupied by other widgets in the window. * * Using gtk_widget_set_size_request by itself is also insufficient as it * sets the *minimum* size. If the socket widget was already larger then * it would do nothing. */ gtk_window_resize(GTK_WINDOW(d->gtk->gtkwindow), w, h); gtk_widget_set_size_request(d->gtk->gtksocket, w, h); return _al_gtk_release_args(data); } /* [gtk thread] */ static gboolean do_resize_display2(gpointer data) { ARGS_RESIZE *args = _al_gtk_lock_args(data); ALLEGRO_DISPLAY_XGLX *d = args->display; /* Remove the minimum size constraint again. */ gtk_widget_set_size_request(d->gtk->gtksocket, -1, -1); return _al_gtk_release_args(data); } /* [user thread] */ static bool xgtk_resize_display(ALLEGRO_DISPLAY *display, int w, int h) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *d = (ALLEGRO_DISPLAY_XGLX *)display; bool ret = true; _al_mutex_lock(&system->lock); if (w != display->w || h != display->h) { do { const int old_resize_count = d->resize_count; ARGS_RESIZE args; d->programmatic_resize = true; if (!_al_gtk_init_args(&args, sizeof(args))) { ret = false; break; } args.display = d; args.w = w; args.h = h; _al_gtk_wait_for_args(do_resize_display1, &args); _al_display_xglx_await_resize(display, old_resize_count, false); if (_al_gtk_init_args(&args, sizeof(args))) { args.display = d; _al_gtk_wait_for_args(do_resize_display2, &args); } d->programmatic_resize = false; } while (0); } _al_mutex_unlock(&system->lock); return ret; } /* [gtk thread] */ static gboolean do_set_window_title(gpointer data) { ARGS_TITLE *args = _al_gtk_lock_args(data); ALLEGRO_DISPLAY_XGLX *d = args->display; const char *title = args->title; gtk_window_set_title(GTK_WINDOW(d->gtk->gtkwindow), title); return _al_gtk_release_args(data); } /* [user thread] */ static void xgtk_set_window_title(ALLEGRO_DISPLAY *display, const char *title) { ARGS_TITLE args; if (_al_gtk_init_args(&args, sizeof(args))) { args.display = (ALLEGRO_DISPLAY_XGLX *)display; args.title = title; _al_gtk_wait_for_args(do_set_window_title, &args); } } /* [gtk thread] */ static gboolean do_set_fullscreen_window(gpointer data) { ARGS_FULLSCREEN_WINDOW *args = _al_gtk_lock_args(data); ALLEGRO_DISPLAY_XGLX *d = args->display; bool fullscreen = args->fullscreen; if (fullscreen) { gtk_window_fullscreen(GTK_WINDOW(d->gtk->gtkwindow)); } else { gtk_window_unfullscreen(GTK_WINDOW(d->gtk->gtkwindow)); } return _al_gtk_release_args(args); } /* [user thread] */ static void xgtk_set_fullscreen_window(ALLEGRO_DISPLAY *display, bool onoff) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *d = (ALLEGRO_DISPLAY_XGLX *)display; if (onoff == (display->flags & ALLEGRO_FULLSCREEN_WINDOW)) { return; } _al_mutex_lock(&system->lock); { int old_resize_count; ARGS_FULLSCREEN_WINDOW args; display->flags ^= ALLEGRO_FULLSCREEN_WINDOW; old_resize_count = d->resize_count; d->programmatic_resize = true; if (_al_gtk_init_args(&args, sizeof(args))) { args.display = d; args.fullscreen = onoff; _al_gtk_wait_for_args(do_set_fullscreen_window, &args); _al_display_xglx_await_resize(display, old_resize_count, (display->flags & ALLEGRO_FULLSCREEN)); } d->programmatic_resize = false; } _al_mutex_unlock(&system->lock); } /* [gtk thread] */ static gboolean do_set_window_position(gpointer data) { ARGS_POSITION *args = _al_gtk_lock_args(data); gtk_window_move(GTK_WINDOW(args->display->gtk->gtkwindow), args->x, args->y); return _al_gtk_release_args(args); } /* [user thread] */ static void xgtk_set_window_position(ALLEGRO_DISPLAY *display, int x, int y) { ARGS_POSITION args; if (_al_gtk_init_args(&args, sizeof(args))) { args.display = (ALLEGRO_DISPLAY_XGLX *)display; args.x = x; args.y = y; _al_gtk_wait_for_args(do_set_window_position, &args); } } /* [user thread] */ static bool xgtk_set_window_constraints(ALLEGRO_DISPLAY *display, int min_w, int min_h, int max_w, int max_h) { // FIXME (void)display; (void)min_w; (void)min_h; (void)max_w; (void)max_h; return true; } /* [gtk thread] */ static gboolean do_maximize(gpointer data) { ARGS_SET_FLAG *args = _al_gtk_lock_args(data); if (args->onoff) { gtk_window_maximize(GTK_WINDOW(args->display->gtk->gtkwindow)); } else { gtk_window_unmaximize(GTK_WINDOW(args->display->gtk->gtkwindow)); } return _al_gtk_release_args(args); } /* [gtk thread] */ static gboolean do_set_frameless(gpointer data) { ARGS_SET_FLAG *args = _al_gtk_lock_args(data); if (args->onoff) { gtk_window_set_decorated(GTK_WINDOW(args->display->gtk->gtkwindow), FALSE); } else { gtk_window_set_decorated(GTK_WINDOW(args->display->gtk->gtkwindow), TRUE); } return _al_gtk_release_args(args); } /* [user thread] */ static bool xgtk_set_display_flag(ALLEGRO_DISPLAY *display, int flag, bool onoff) { switch (flag) { case ALLEGRO_FRAMELESS: { if (!!(display->flags & ALLEGRO_FRAMELESS) == onoff) return true; ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ARGS_SET_FLAG args; _al_mutex_lock(&system->lock); if (_al_gtk_init_args(&args, sizeof(args))) { args.display = (ALLEGRO_DISPLAY_XGLX *)display; args.onoff = onoff; _al_gtk_wait_for_args(do_set_frameless, &args); if (onoff) display->flags |= ALLEGRO_FRAMELESS; else display->flags &= ~ALLEGRO_FRAMELESS; } _al_mutex_unlock(&system->lock); return true; } case ALLEGRO_MAXIMIZED: { if (!!(display->flags & ALLEGRO_MAXIMIZED) == onoff) return true; ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ARGS_SET_FLAG args; _al_mutex_lock(&system->lock); if (_al_gtk_init_args(&args, sizeof(args))) { args.display = (ALLEGRO_DISPLAY_XGLX *)display; args.onoff = onoff; ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; int old_resize_count = glx->resize_count; _al_gtk_wait_for_args(do_maximize, &args); _al_display_xglx_await_resize(display, old_resize_count, true); } _al_mutex_unlock(&system->lock); return true; } case ALLEGRO_FULLSCREEN_WINDOW: xgtk_set_fullscreen_window(display, onoff); return true; } return false; } /* [gtk thread] */ static gboolean do_check_maximized(gpointer data) { ARGS_SET_FLAG *args = _al_gtk_lock_args(data); args->onoff = gtk_window_is_maximized(GTK_WINDOW(args->display->gtk->gtkwindow)); return _al_gtk_release_args(args); } /* [user thread] */ static void xgtk_check_maximized(ALLEGRO_DISPLAY *display) { ARGS_SET_FLAG args; if (_al_gtk_init_args(&args, sizeof(args))) { args.display = (ALLEGRO_DISPLAY_XGLX *)display; _al_gtk_wait_for_args(do_check_maximized, &args); if (args.onoff) { display->flags |= ALLEGRO_MAXIMIZED; } else { display->flags &= ~ALLEGRO_MAXIMIZED; } } } static struct ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE xgtk_override_vt = { xgtk_create_display_hook, xgtk_destroy_display_hook, xgtk_resize_display, xgtk_set_window_title, xgtk_set_fullscreen_window, xgtk_set_window_position, xgtk_set_window_constraints, xgtk_set_display_flag, xgtk_check_maximized, }; bool _al_gtk_set_display_overridable_interface(bool on) { return _al_xwin_set_gtk_display_overridable_interface(ALLEGRO_VERSION_INT, (on) ? &xgtk_override_vt : NULL); } GtkWidget *_al_gtk_get_window(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_XGLX *d = (ALLEGRO_DISPLAY_XGLX *)display; if (d->overridable_vt == &xgtk_override_vt) { return d->gtk->gtkwindow; } ALLEGRO_WARN("Not display created with GTK.\n"); return NULL; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/gtk_xgtk.h000066400000000000000000000005701473414355200215320ustar00rootroot00000000000000#ifndef __al_included_allegro5_native_dialog_gtk_xgtk_h #define __al_included_allegro5_native_dialog_gtk_xgtk_h #include struct ALLEGRO_DISPLAY_XGLX_GTK { GtkWidget *gtkwindow; GtkWidget *gtksocket; }; bool _al_gtk_set_display_overridable_interface(bool on); GtkWidget *_al_gtk_get_window(ALLEGRO_DISPLAY *display); #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/iphone_dialog.m000066400000000000000000000076601473414355200225250ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_native_dialog.h" #include #include "allegro5/allegro_iphone_objc.h" bool _al_init_native_dialog_addon(void) { return true; } void _al_shutdown_native_dialog_addon(void) { } bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display, ALLEGRO_NATIVE_DIALOG *fd) { (void)display; (void)fd; return false; } @interface AlertDelegate : NSObject { ALLEGRO_MUTEX *mutex; ALLEGRO_COND *button_pressed; } @property ALLEGRO_MUTEX *mutex; @property ALLEGRO_COND *button_pressed; @end @implementation AlertDelegate @synthesize mutex; @synthesize button_pressed; - (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)bindex { (void)alert; (void)bindex; al_lock_mutex(mutex); al_signal_cond(button_pressed); al_unlock_mutex(mutex); } - (void) createAlert:(NSArray*)array { UIView *view = [array objectAtIndex:0]; UIAlertView *alert = [array objectAtIndex:1]; [view addSubview:alert]; [alert show]; [alert release]; } @end int _al_show_native_message_box(ALLEGRO_DISPLAY *display, ALLEGRO_NATIVE_DIALOG *nd) { (void)display; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; NSString *title = [NSString stringWithUTF8String:al_cstr(nd->title)]; NSString *heading = [NSString stringWithUTF8String:al_cstr(nd->mb_heading)]; NSString *text = [NSString stringWithUTF8String:al_cstr(nd->mb_text)]; NSString *ok = [NSString stringWithUTF8String:"Ok"]; NSString *message = [NSString stringWithFormat:@"%@\n\n%@", heading, text]; AlertDelegate *delegate = [[AlertDelegate alloc]init]; delegate.mutex = al_create_mutex(); delegate.button_pressed = al_create_cond(); // This needs to be done on the thread with the display due to TLS. UIView *view = al_iphone_get_view(al_get_current_display()); UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:delegate cancelButtonTitle:ok otherButtonTitles:nil]; [delegate performSelectorOnMainThread:@selector(createAlert:) withObject:@[view,alert] waitUntilDone:YES]; al_lock_mutex(delegate.mutex); al_wait_cond(delegate.button_pressed, delegate.mutex); al_unlock_mutex(delegate.mutex); al_destroy_cond(delegate.button_pressed); al_destroy_mutex(delegate.mutex); [delegate release]; [pool drain]; return 0; } bool _al_open_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { (void)textlog; return false; } void _al_close_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { (void) textlog; } void _al_append_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { (void) textlog; } bool _al_init_menu(ALLEGRO_MENU *menu) { (void) menu; return false; } bool _al_init_popup_menu(ALLEGRO_MENU *menu) { (void) menu; return false; } bool _al_insert_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { (void) item; (void) i; return false; } bool _al_destroy_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { (void) item; (void) i; return false; } bool _al_update_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { (void) item; (void) i; return false; } bool _al_show_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { (void) display; (void) menu; return false; } bool _al_hide_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { (void) display; (void) menu; return false; } bool _al_show_popup_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { (void) display; (void) menu; return false; } int _al_get_menu_display_height(void) { return 0; } allegro5-5.2.10.1/addons/native_dialog/menu.c000066400000000000000000000614651473414355200206610ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_native_dialog.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_vector.h" /* DISPLAY_MENU keeps track of which menu is associated with a display */ typedef struct DISPLAY_MENU DISPLAY_MENU; struct DISPLAY_MENU { ALLEGRO_DISPLAY *display; ALLEGRO_MENU *menu; }; static _AL_VECTOR display_menus = _AL_VECTOR_INITIALIZER(DISPLAY_MENU); /* The unique id. This is used to reverse lookup menus. * The primarily need for this arises from Windows, which cannot store * ALLEGRO_MENU_ID's wholesale.*/ static uint16_t unique_id; static _AL_VECTOR menu_ids = _AL_VECTOR_INITIALIZER(_AL_MENU_ID); /* The default event source is used with any menu that does not have its own event source enabled. */ static ALLEGRO_EVENT_SOURCE default_menu_es; /* Private functions */ static ALLEGRO_MENU *clone_menu(ALLEGRO_MENU *menu, bool popup); static ALLEGRO_MENU_ITEM *create_menu_item(char const *title, uint16_t id, int flags, ALLEGRO_MENU *popup); static void destroy_menu_item(ALLEGRO_MENU_ITEM *item); static bool find_menu_item_r(ALLEGRO_MENU *menu, ALLEGRO_MENU_ITEM *item, int index, void *extra); static ALLEGRO_MENU_ITEM *interpret_menu_id_param(ALLEGRO_MENU **menu, int *id); static ALLEGRO_MENU_INFO *parse_menu_info(ALLEGRO_MENU *parent, ALLEGRO_MENU_INFO *info); static bool set_menu_display_r(ALLEGRO_MENU *menu, ALLEGRO_MENU_ITEM *item, int index, void *extra); /* True if the id is actually unique. */ static bool get_unique_id(uint16_t* id) { if (unique_id + 1 == UINT16_MAX) { return false; } *id = unique_id++; return true; } /* The menu item owns the icon bitmap. It is converted to a memory bitmap * when set to make sure any system threads will be able to read the data. */ static void set_item_icon(ALLEGRO_MENU_ITEM *item, ALLEGRO_BITMAP *icon) { item->icon = icon; if (icon && al_get_bitmap_flags(item->icon) & ALLEGRO_VIDEO_BITMAP) { int old_flags = al_get_new_bitmap_flags(); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); item->icon = al_clone_bitmap(icon); al_destroy_bitmap(icon); al_set_new_bitmap_flags(old_flags); } } static ALLEGRO_MENU_ITEM *create_menu_item(char const *title, uint16_t id, int flags, ALLEGRO_MENU *popup) { ALLEGRO_MENU_ITEM *item = al_calloc(1, sizeof(*item)); if (!item) return NULL; if (!get_unique_id(&item->unique_id)) { return NULL; } if (flags & ALLEGRO_MENU_ITEM_CHECKED) flags |= ALLEGRO_MENU_ITEM_CHECKBOX; if (title) item->caption = al_ustr_new(title); item->id = id; item->flags = flags; item->popup = popup; return item; } /* Recursively walks over the entire menu structure, calling the user proc once per menu item, * and once per menu. The deepest menu is called first. If the proc returns true, then the * process terminates. It is not safe for the proc to modify the structure (add/remove items). */ bool _al_walk_over_menu(ALLEGRO_MENU *menu, bool (*proc)(ALLEGRO_MENU *menu, ALLEGRO_MENU_ITEM *item, int index, void *extra), void *extra) { ALLEGRO_MENU_ITEM **slot; size_t i; ASSERT(menu); ASSERT(proc); for (i = 0; i < _al_vector_size(&menu->items); ++i) { slot = _al_vector_ref(&menu->items, i); if ((*slot)->popup && _al_walk_over_menu((*slot)->popup, proc, extra)) return true; if (proc(menu, *slot, i, extra)) return true; } return proc(menu, NULL, -1, extra); } /* A callback proc for _al_walk_over_menu that sets each menu's display parameter * to the "extra" parameter. */ static bool set_menu_display_r(ALLEGRO_MENU *menu, ALLEGRO_MENU_ITEM *item, int index, void *extra) { (void) index; if (!item) { menu->display = extra; } return false; } /* A callback proc for _al_walk_over_menu that searches a menu for a given id. If found it sets * the "parent" parameter to the menu that contains it, and the "id" parameter to the index. */ static bool find_menu_item_r(ALLEGRO_MENU *menu, ALLEGRO_MENU_ITEM *item, int index, void *extra) { ALLEGRO_MENU_ITEM *info = (ALLEGRO_MENU_ITEM *) extra; if (item != NULL && info->id == item->id) { info->id = index; info->parent = menu; return true; } return false; } /* Like find_menu_item_r, but searches by unique_id. */ static bool find_menu_item_r_unique(ALLEGRO_MENU *menu, ALLEGRO_MENU_ITEM *item, int index, void *extra) { ALLEGRO_MENU_ITEM *info = (ALLEGRO_MENU_ITEM *) extra; if (item != NULL && info->unique_id == item->unique_id) { info->id = index; info->parent = menu; return true; } return false; } /* Carefully destroy a menu item... If the item is part of a menu, it must be * removed from it. */ static void destroy_menu_item(ALLEGRO_MENU_ITEM *item) { ASSERT(item); if (!item->parent) { /* This normally won't happen. */ _al_destroy_menu_item_at(item, -1); } else { size_t i; for (i = 0; i < _al_vector_size(&item->parent->items); ++i) { if (*(ALLEGRO_MENU_ITEM **)_al_vector_ref(&item->parent->items, i) == item) { /* Notify the platform that the item is to be removed. */ _al_destroy_menu_item_at(item, i); /* Remove the command from the look-up vector. */ if (item->id != 0) { _AL_MENU_ID *menu_id; size_t j; for (j = 0; j < _al_vector_size(&menu_ids); ++j) { menu_id = (_AL_MENU_ID *) _al_vector_ref(&menu_ids, j); if (menu_id->menu == item->parent && menu_id->unique_id == item->unique_id) { _al_vector_delete_at(&menu_ids, j); break; } } } /* Remove the menu from the parent's list. */ _al_vector_delete_at(&item->parent->items, i); break; } } } if (item->caption) al_ustr_free(item->caption); if (item->popup) { /* Delete the sub-menu. Must set the parent/display to NULL ahead of time to * avoid recursing back here. */ item->popup->parent = NULL; item->popup->display = NULL; al_destroy_menu(item->popup); } if (item->icon) { al_destroy_bitmap(item->icon); } al_free(item); } /* An ALLEGRO_MENU_INFO structure represents a heirarchy of menus. This function * recursively steps through it and builds the entire menu. */ static ALLEGRO_MENU_INFO *parse_menu_info(ALLEGRO_MENU *parent, ALLEGRO_MENU_INFO *info) { ASSERT(parent); ASSERT(info); /* The end of the menu is marked by a NULL caption and an id of 0. */ while (info->caption || info->id) { if (!info->caption) { /* A separator */ al_append_menu_item(parent, NULL, 0, 0, NULL, NULL); ++info; } else if (strlen(info->caption) > 2 && !strncmp("->", info->caption + strlen(info->caption) - 2, 2)) { /* An item with a sub-menu has a -> marker as part of its caption. * (e.g., "File->"). */ ALLEGRO_MENU *menu = al_create_menu(); if (menu) { /* Strip the -> mark off the end. */ ALLEGRO_USTR *s = al_ustr_new(info->caption); al_ustr_remove_range(s, al_ustr_size(s) - 2, al_ustr_size(s)); al_append_menu_item(parent, al_cstr(s), info->id, 0, NULL, menu); info = parse_menu_info(menu, info + 1); al_ustr_free(s); } } else { /* Just ar regular item */ al_append_menu_item(parent, info->caption, info->id, info->flags, info->icon, NULL); ++info; } } return info + 1; } /* All public functions that take a menu and id parameter have two interpretations: * * 1) If id > 0, then it represents an id anywhere within the menu structure, * including child menus. If there are non-unique IDs, the first one found is * returned, but the exact order is undefined. (IDs are meant to be unique.) * * 2) If id <= 0, then its absolute value represents an ordered index for that * exact menu. * * If the parameters are valid, it returns a pointer to the corresponding * MENU_ITEM, and the menu/id parameters are set to the item's parent and its * index. Otherwise (on invalid parameters), it returns NULL and the menu/id * parameters are left undefined. * * (Note that the private OS specific functions always take a direct index.) */ static ALLEGRO_MENU_ITEM *interpret_menu_id_param(ALLEGRO_MENU **menu, int *id) { if (*id > 0) { if (!al_find_menu_item(*menu, *id, menu, id)) return NULL; } else { *id = (0 - *id); if ((size_t) *id >= _al_vector_size(&((*menu)->items))) return NULL; } return *(ALLEGRO_MENU_ITEM **) _al_vector_ref(&((*menu)->items), (size_t) *id); } /* A helper function for al_clone_menu() and al_clone_menu_for_popup(). * Note that only the root menu is created as a "popup" (if popup == TRUE). */ static ALLEGRO_MENU *clone_menu(ALLEGRO_MENU *menu, bool popup) { ALLEGRO_MENU *clone = NULL; size_t i; if (menu) { clone = popup ? al_create_popup_menu() : al_create_menu(); for (i = 0; i < _al_vector_size(&menu->items); ++i) { const ALLEGRO_MENU_ITEM *item = *(ALLEGRO_MENU_ITEM **)_al_vector_ref(&menu->items, i); ALLEGRO_BITMAP *icon = item->icon; if (icon) icon = al_clone_bitmap(icon); al_append_menu_item(clone, item->caption ? al_cstr(item->caption) : NULL, item->id, item->flags, icon, al_clone_menu(item->popup)); } } return clone; } /* Function: al_create_menu */ ALLEGRO_MENU *al_create_menu(void) { ALLEGRO_MENU *m = al_calloc(1, sizeof(*m)); if (m) { _al_vector_init(&m->items, sizeof(ALLEGRO_MENU_ITEM*)); /* Make sure the platform actually supports menus */ if (!_al_init_menu(m)) { al_destroy_menu(m); m = NULL; } } return m; } /* Function: al_create_popup_menu */ ALLEGRO_MENU *al_create_popup_menu(void) { ALLEGRO_MENU *m = al_calloc(1, sizeof(*m)); if (m) { _al_vector_init(&m->items, sizeof(ALLEGRO_MENU_ITEM*)); if (!_al_init_popup_menu(m)) { al_destroy_menu(m); m = NULL; } else { /* Popups are slightly different... They can be used multiple times * with al_popup_menu(), but never as a display menu. */ m->is_popup_menu = true; } } return m; } /* Function: al_clone_menu */ ALLEGRO_MENU *al_clone_menu(ALLEGRO_MENU *menu) { return clone_menu(menu, false); } /* Function: al_clone_menu_for_popup */ ALLEGRO_MENU *al_clone_menu_for_popup(ALLEGRO_MENU *menu) { return clone_menu(menu, true); } /* Function: al_build_menu */ ALLEGRO_MENU *al_build_menu(ALLEGRO_MENU_INFO *info) { ALLEGRO_MENU *root = al_create_menu(); if (root) parse_menu_info(root, info); return root; } /* Function: al_append_menu_item */ int al_append_menu_item(ALLEGRO_MENU *parent, char const *title, uint16_t id, int flags, ALLEGRO_BITMAP *icon, ALLEGRO_MENU *submenu) { ASSERT(parent); /* Same thing as inserting a menu item at position == -SIZE */ return al_insert_menu_item(parent, 0 - (int) _al_vector_size(&parent->items), title, id, flags, icon, submenu); } /* Function: al_insert_menu_item */ int al_insert_menu_item(ALLEGRO_MENU *parent, int pos, char const *title, uint16_t id, int flags, ALLEGRO_BITMAP *icon, ALLEGRO_MENU *submenu) { ALLEGRO_MENU_ITEM *item; ALLEGRO_MENU_ITEM **slot; _AL_MENU_ID *menu_id; size_t i; ASSERT(parent); /* If not found, then treat as an append. */ if (!interpret_menu_id_param(&parent, &pos)) pos = _al_vector_size(&parent->items); /* At this point pos == the _index_ of where to insert */ /* The sub-menu must not already be in use. */ if (submenu && (submenu->display || submenu->parent || submenu->is_popup_menu)) return -1; item = create_menu_item(title, id, flags, submenu); if (!item) return -1; item->parent = parent; set_item_icon(item, icon); i = (size_t) pos; if (i >= _al_vector_size(&parent->items)) { /* Append */ i = _al_vector_size(&parent->items); slot = _al_vector_alloc_back(&parent->items); } else { /* Insert */ slot = _al_vector_alloc_mid(&parent->items, i); } if (!slot) { destroy_menu_item(item); return -1; } *slot = item; if (submenu) { submenu->parent = item; if (parent->display) _al_walk_over_menu(submenu, set_menu_display_r, parent->display); } _al_insert_menu_item_at(item, (int) i); if (id) { /* Append the menu's ID to the search vector */ menu_id = (_AL_MENU_ID *) _al_vector_alloc_back(&menu_ids); menu_id->unique_id = item->unique_id; menu_id->id = id; menu_id->menu = parent; } return (int) i; } /* Function: al_remove_menu_item */ bool al_remove_menu_item(ALLEGRO_MENU *menu, int pos) { ALLEGRO_MENU_ITEM *item; ASSERT(menu); item = interpret_menu_id_param(&menu, &pos); if (!item) return false; destroy_menu_item(item); return true; } /* Function: al_find_menu */ ALLEGRO_MENU *al_find_menu(ALLEGRO_MENU *haystack, uint16_t id) { int index; return !al_find_menu_item(haystack, id, &haystack, &index) ? NULL : (*(ALLEGRO_MENU_ITEM **)_al_vector_ref(&haystack->items, index))->popup; } /* Function: al_find_menu_item */ bool al_find_menu_item(ALLEGRO_MENU *haystack, uint16_t id, ALLEGRO_MENU **menu, int *index) { ALLEGRO_MENU_ITEM item; ASSERT(haystack); /* Abuse the ALLEGRO_MENU_ITEM struct as a container for the _al_walk_over_menu callback. * If found, it will return true, and the "parent" field will be the menu that and * the "id" will be the index. */ item.id = id; if (!_al_walk_over_menu(haystack, find_menu_item_r, &item)) return false; if (menu) *menu = item.parent; if (index) *index = item.id; return true; } /* As al_find_menu_item, but searches by the unique id. */ bool _al_find_menu_item_unique(ALLEGRO_MENU *haystack, uint16_t unique_id, ALLEGRO_MENU **menu, int *index) { ALLEGRO_MENU_ITEM item; ASSERT(haystack); item.unique_id = unique_id; if (!_al_walk_over_menu(haystack, find_menu_item_r_unique, &item)) return false; if (menu) *menu = item.parent; if (index) *index = item.id; return true; } /* Function: al_get_menu_item_caption */ const char *al_get_menu_item_caption(ALLEGRO_MENU *menu, int pos) { ALLEGRO_MENU_ITEM *item; ASSERT(menu); item = interpret_menu_id_param(&menu, &pos); return item && item->caption ? al_cstr(item->caption) : NULL; } /* Function: al_set_menu_item_caption */ void al_set_menu_item_caption(ALLEGRO_MENU *menu, int pos, const char *caption) { ALLEGRO_MENU_ITEM *item; ASSERT(menu); item = interpret_menu_id_param(&menu, &pos); if (item && item->caption) { al_ustr_free(item->caption); item->caption = al_ustr_new(caption); _al_update_menu_item_at(item, pos); } } /* Function: al_get_menu_item_flags */ int al_get_menu_item_flags(ALLEGRO_MENU *menu, int pos) { ALLEGRO_MENU_ITEM *item; ASSERT(menu); item = interpret_menu_id_param(&menu, &pos); return item ? item->flags : -1; } /* Function: al_set_menu_item_flags */ void al_set_menu_item_flags(ALLEGRO_MENU *menu, int pos, int flags) { ALLEGRO_MENU_ITEM *item; ASSERT(menu); item = interpret_menu_id_param(&menu, &pos); if (item) { /* The CHECKBOX flag is read-only after the menu is created, and * the CHECKED flag can only be set if it is a CHECKBOX. */ if (item->flags & ALLEGRO_MENU_ITEM_CHECKBOX) flags |= ALLEGRO_MENU_ITEM_CHECKBOX; else { flags &= ~ALLEGRO_MENU_ITEM_CHECKED; flags &= ~ALLEGRO_MENU_ITEM_CHECKBOX; } item->flags = flags; _al_update_menu_item_at(item, pos); } } /* Function: al_toggle_menu_item_flags */ int al_toggle_menu_item_flags(ALLEGRO_MENU *menu, int pos, int flags) { ALLEGRO_MENU_ITEM *item; ASSERT(menu); item = interpret_menu_id_param(&menu, &pos); if (!item) return -1; /* The CHECKBOX flag is read-only after the menu is created, and * the CHECKED flag can only be set if it is a CHECKBOX. */ flags &= ~ALLEGRO_MENU_ITEM_CHECKBOX; if (!(item->flags & ALLEGRO_MENU_ITEM_CHECKBOX)) { flags &= ~ALLEGRO_MENU_ITEM_CHECKED; } item->flags ^= flags; _al_update_menu_item_at(item, pos); return item->flags & flags; } /* Function: al_get_menu_item_icon */ ALLEGRO_BITMAP *al_get_menu_item_icon(ALLEGRO_MENU *menu, int pos) { ALLEGRO_MENU_ITEM *item; ASSERT(menu); item = interpret_menu_id_param(&menu, &pos); return item ? item->icon : NULL; } /* Function: al_set_menu_item_icon */ void al_set_menu_item_icon(ALLEGRO_MENU *menu, int pos, ALLEGRO_BITMAP *icon) { ALLEGRO_MENU_ITEM *item; ASSERT(menu); item = interpret_menu_id_param(&menu, &pos); if (item) { if (item->icon) al_destroy_bitmap(item->icon); set_item_icon(item, icon); _al_update_menu_item_at(item, pos); } } /* Function: al_destroy_menu */ void al_destroy_menu(ALLEGRO_MENU *menu) { ALLEGRO_MENU_ITEM **slot; size_t i; ASSERT(menu); if (menu->parent) { /* If the menu is attached to a menu item, then this is equivelant to removing that menu item. */ ALLEGRO_MENU *parent = menu->parent->parent; ASSERT(parent); for (i = 0; i < _al_vector_size(&parent->items); ++i) { slot = _al_vector_ref(&parent->items, i); if (*slot == menu->parent) { al_remove_menu_item(parent, 0 - (int) i); return; } } /* Should never get here. */ ASSERT(false); return; } else if (menu->display && !menu->is_popup_menu) { /* This is an active, top-level menu. */ al_remove_display_menu(menu->display); } /* Destroy each item associated with the menu. */ while (_al_vector_size(&menu->items)) { slot = _al_vector_ref_back(&menu->items); destroy_menu_item(*slot); } _al_vector_free(&menu->items); al_disable_menu_event_source(menu); al_free(menu); } /* Function: al_get_default_menu_event_source */ ALLEGRO_EVENT_SOURCE *al_get_default_menu_event_source(void) { return &default_menu_es; } /* Function: al_enable_menu_event_source */ ALLEGRO_EVENT_SOURCE *al_enable_menu_event_source(ALLEGRO_MENU *menu) { ASSERT(menu); if (!menu->is_event_source) { al_init_user_event_source(&menu->es); menu->is_event_source = true; } return &menu->es; } /* Function: al_disable_menu_event_source */ void al_disable_menu_event_source(ALLEGRO_MENU *menu) { ASSERT(menu); if (menu->is_event_source) { al_destroy_user_event_source(&menu->es); menu->is_event_source = false; } } /* Function: al_get_display_menu */ ALLEGRO_MENU *al_get_display_menu(ALLEGRO_DISPLAY *display) { size_t i; ASSERT(display); /* Search through the display_menus vector to see if this display has * a menu associated with it. */ for (i = 0; i < _al_vector_size(&display_menus); ++i) { DISPLAY_MENU *dm = (DISPLAY_MENU *) _al_vector_ref(&display_menus, i); if (dm->display == display) return dm->menu; } return NULL; } /* Function: al_set_display_menu */ bool al_set_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { DISPLAY_MENU *dm = NULL; size_t i; int menu_height = _al_get_menu_display_height(); bool automatic_menu_display_resize = true; const char* automatic_menu_display_resize_value = al_get_config_value(al_get_system_config(), "compatibility", "automatic_menu_display_resize"); if (automatic_menu_display_resize_value && strcmp(automatic_menu_display_resize_value, "false") == 0) automatic_menu_display_resize = false; ASSERT(display); /* Check if this display has a menu associated with it */ for (i = 0; i < _al_vector_size(&display_menus); ++i) { dm = (DISPLAY_MENU *) _al_vector_ref(&display_menus, i); if (dm->display == display) break; } /* If no display was found, reset dm to NULL */ if (i == _al_vector_size(&display_menus)) dm = NULL; if (!menu) { /* Removing the menu */ if (!dm) return false; _al_hide_display_menu(display, dm->menu); _al_walk_over_menu(dm->menu, set_menu_display_r, NULL); _al_vector_delete_at(&display_menus, i); if (automatic_menu_display_resize && menu_height > 0) { al_resize_display(display, al_get_display_width(display), al_get_display_height(display)); } } else { /* Setting the menu. It must not currently be attached to any * display, and it cannot have a parent menu. */ if (menu->display || menu->parent) return false; if (dm) { /* hide the existing menu */ _al_hide_display_menu(display, dm->menu); _al_walk_over_menu(dm->menu, set_menu_display_r, NULL); } if (!_al_show_display_menu(display, menu)) { /* Unable to set the new menu, but already have hidden the * previous one, so delete the display_menus slot. */ if (dm) _al_vector_delete_at(&display_menus, i); return false; } /* Set the entire menu tree as owned by the display */ _al_walk_over_menu(menu, set_menu_display_r, display); if (!dm) dm = _al_vector_alloc_back(&display_menus); if (automatic_menu_display_resize && menu_height > 0) { /* Temporarily disable the constraints so we don't send a RESIZE_EVENT. */ bool old_constraints = display->use_constraints; display->use_constraints = false; al_resize_display(display, al_get_display_width(display), al_get_display_height(display)); display->use_constraints = old_constraints; } dm->display = display; dm->menu = menu; } return true; } /* Function: al_popup_menu */ bool al_popup_menu(ALLEGRO_MENU *popup, ALLEGRO_DISPLAY *display) { bool ret; ASSERT(popup); if (!popup->is_popup_menu || popup->parent) return false; if (!display) display = al_get_current_display(); /* Set the entire menu tree as owned by the display */ _al_walk_over_menu(popup, set_menu_display_r, display); ret = _al_show_popup_menu(display, popup); if (!ret) { _al_walk_over_menu(popup, set_menu_display_r, NULL); } return ret; } /* Function: al_remove_display_menu */ ALLEGRO_MENU *al_remove_display_menu(ALLEGRO_DISPLAY *display) { ALLEGRO_MENU *menu; ASSERT(display); menu = al_get_display_menu(display); if (menu) al_set_display_menu(display, NULL); return menu; } /* Tries to find the menu that has a child with the given id. If display * is not NULL, then it must also match. The first match is returned. */ _AL_MENU_ID *_al_find_parent_menu_by_id(ALLEGRO_DISPLAY *display, uint16_t unique_id) { _AL_MENU_ID *menu_id; size_t i; for (i = 0; i < _al_vector_size(&menu_ids); ++i) { menu_id = (_AL_MENU_ID *) _al_vector_ref(&menu_ids, i); if (menu_id->unique_id == unique_id) { if (!display || menu_id->menu->display == display) { return menu_id; } } } return NULL; } /* Each platform implementation must call this when a menu has been clicked. * The display parameter should be sent if at all possible! If it isn't sent, * and the user is using non-unique ids, it won't know which display actually * triggered the menu click. */ bool _al_emit_menu_event(ALLEGRO_DISPLAY *display, uint16_t unique_id) { ALLEGRO_EVENT event; _AL_MENU_ID *menu_id = NULL; ALLEGRO_EVENT_SOURCE *source = al_get_default_menu_event_source(); /* try to find the menu that triggered the event */ menu_id = _al_find_parent_menu_by_id(display, unique_id); if (!menu_id) return false; if (menu_id->id == 0) return false; if (menu_id) { /* A menu was found associated with the id. See if it has an * event source associated with it, and adjust "source" accordingly. */ ALLEGRO_MENU *m = menu_id->menu; while (true) { if (m->is_event_source) { source = &m->es; break; } if (!m->parent) break; /* m->parent is of type MENU_ITEM, * which always has a parent of type MENU */ ASSERT(m->parent->parent); m = m->parent->parent; } } event.user.type = ALLEGRO_EVENT_MENU_CLICK; event.user.data1 = menu_id->id; event.user.data2 = (intptr_t) display; event.user.data3 = (intptr_t) menu_id->menu; al_emit_user_event(source, &event, NULL); return true; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/osx_dialog.m000066400000000000000000000662111473414355200220510ustar00rootroot00000000000000#import #import #import #if MAC_OS_X_VERSION_MIN_REQUIRED >= 110000 #include #endif #include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_native_dialog.h" #include "allegro5/platform/aintosx.h" #include "allegro5/allegro_osx.h" bool _al_init_native_dialog_addon(void) { return true; } void _al_shutdown_native_dialog_addon(void) { } #pragma mark File Dialog static NSArray * get_filter_array(const _AL_VECTOR *patterns) { NSMutableArray *filter_array = [[NSMutableArray alloc] init]; bool any_catchalls = false; for (size_t i = 0; i < _al_vector_size(patterns); i++) { _AL_PATTERNS_AND_DESC *patterns_and_desc = _al_vector_ref(patterns, (int)i); for (size_t j = 0; j < _al_vector_size(&patterns_and_desc->patterns_vec); j++) { _AL_PATTERN *pattern = _al_vector_ref(&patterns_and_desc->patterns_vec, (int)j); if (pattern->is_catchall) { any_catchalls = true; break; } char *cstr = al_cstr_dup(al_ref_info(&pattern->info)); NSString *filter_text = [NSString stringWithUTF8String: cstr]; al_free(cstr); if (!pattern->is_mime) { /* MacOS expects extensions, so make an attempt to extract them. */ NSArray *parts = [filter_text componentsSeparatedByString: @"."]; size_t num_parts = parts.count; if (num_parts <= 1) continue; /* Extensions with dots did not work for me, so just grab the last component. */ parts = [parts subarrayWithRange:NSMakeRange(num_parts - 1, 1)]; filter_text = [parts componentsJoinedByString: @"."]; } #if MAC_OS_X_VERSION_MIN_REQUIRED >= 110000 UTType *type; if (pattern->is_mime) type = [UTType typeWithMIMEType:filter_text]; else type = [UTType typeWithFilenameExtension:filter_text]; if (type != nil) [filter_array addObject: type]; #else if (pattern->is_mime) { continue; } [filter_array addObject: filter_text]; #endif } } if (any_catchalls) { filter_array = [[NSMutableArray alloc] init]; } return filter_array; } bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display, ALLEGRO_NATIVE_DIALOG *fd) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; (void)display; int mode = fd->flags; NSString *filename; NSURL *directory; /* Set initial directory to pass to the file selector */ if (fd->fc_initial_path) { ALLEGRO_PATH *initial_directory = al_clone_path(fd->fc_initial_path); /* Strip filename from path */ al_set_path_filename(initial_directory, NULL); /* Convert path and filename to NSString objects */ directory = [NSURL fileURLWithPath: [NSString stringWithUTF8String: al_path_cstr(initial_directory, '/')] isDirectory: YES]; filename = [NSString stringWithUTF8String: al_get_path_filename(fd->fc_initial_path)]; al_destroy_path(initial_directory); } else { directory = nil; filename = nil; } dispatch_sync(dispatch_get_main_queue(), ^{ /* We need slightly different code for SAVE and LOAD dialog boxes, which * are handled by slightly different classes. */ if (mode & ALLEGRO_FILECHOOSER_SAVE) { // Save dialog NSSavePanel *panel = [NSSavePanel savePanel]; NSArray *filter_array; /* Set file save dialog box options */ [panel setCanCreateDirectories: YES]; [panel setCanSelectHiddenExtension: YES]; [panel setAllowsOtherFileTypes: YES]; [panel setExtensionHidden: NO]; if (filename) { [panel setNameFieldStringValue:filename]; } if (_al_vector_size(&fd->fc_patterns) > 0) { filter_array = get_filter_array(&fd->fc_patterns); if (filter_array && [filter_array count] > 0) { #if MAC_OS_X_VERSION_MIN_REQUIRED >= 110000 [panel setAllowedContentTypes:filter_array]; #else [panel setAllowedFileTypes:filter_array]; #endif } } [panel setDirectoryURL: directory]; /* Open dialog box */ if ([panel runModal] == NSOKButton) { /* NOTE: at first glance, it looks as if this code might leak * memory, but in fact it doesn't: the string returned by * UTF8String is freed automatically when it goes out of scope * (according to the UTF8String docs anyway). */ const char *s = [[[panel URL] path] UTF8String]; fd->fc_path_count = 1; fd->fc_paths = al_malloc(fd->fc_path_count * sizeof *fd->fc_paths); fd->fc_paths[0] = al_create_path(s); } } else { // Open dialog NSOpenPanel *panel = [NSOpenPanel openPanel]; NSArray *filter_array; /* Set file selection box options */ if (mode & ALLEGRO_FILECHOOSER_FOLDER) { [panel setCanChooseFiles: NO]; [panel setCanChooseDirectories: YES]; } else { [panel setCanChooseFiles: YES]; [panel setCanChooseDirectories: NO]; } [panel setResolvesAliases:YES]; if (mode & ALLEGRO_FILECHOOSER_MULTIPLE) [panel setAllowsMultipleSelection: YES]; else [panel setAllowsMultipleSelection: NO]; [panel setDirectoryURL:directory]; if (filename) { [panel setNameFieldStringValue:filename]; } if (_al_vector_size(&fd->fc_patterns) > 0) { filter_array = get_filter_array(&fd->fc_patterns); if (filter_array && [filter_array count] > 0) { #if MAC_OS_X_VERSION_MIN_REQUIRED >= 110000 [panel setAllowedContentTypes:filter_array]; #else [panel setAllowedFileTypes:filter_array]; #endif } } /* Open dialog box */ if ([panel runModal] == NSOKButton) { size_t i; fd->fc_path_count = [[panel URLs] count]; fd->fc_paths = al_malloc(fd->fc_path_count * sizeof *fd->fc_paths); for (i = 0; i < fd->fc_path_count; i++) { /* NOTE: at first glance, it looks as if this code might leak * memory, but in fact it doesn't: the string returned by * UTF8String is freed automatically when it goes out of scope * (according to the UTF8String docs anyway). */ NSURL* url = [[panel URLs] objectAtIndex: i]; const char* s = [[url path] UTF8String]; fd->fc_paths[i] = al_create_path(s); } } } }); _al_osx_clear_mouse_state(); [pool release]; return true; } #pragma mark Alert Box int _al_show_native_message_box(ALLEGRO_DISPLAY *display, ALLEGRO_NATIVE_DIALOG *fd) { (void)display; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; dispatch_sync(dispatch_get_main_queue(), ^{ NSString* button_text; unsigned int i; NSAlert* box = [[NSAlert alloc] init]; if (fd->mb_buttons == NULL) { button_text = @"OK"; if (fd->flags & ALLEGRO_MESSAGEBOX_YES_NO) button_text = @"Yes|No"; if (fd->flags & ALLEGRO_MESSAGEBOX_OK_CANCEL) button_text = @"OK|Cancel"; } else { button_text = [NSString stringWithUTF8String: al_cstr(fd->mb_buttons)]; } NSArray* buttons = [button_text componentsSeparatedByString: @"|"]; [box setMessageText:[NSString stringWithUTF8String: al_cstr(fd->title)]]; [box setInformativeText:[NSString stringWithUTF8String: al_cstr(fd->mb_text)]]; [box setAlertStyle: NSWarningAlertStyle]; [[box window] setLevel: NSFloatingWindowLevel]; for (i = 0; i < [buttons count]; ++i) [box addButtonWithTitle: [buttons objectAtIndex: i]]; int retval = [box runModal]; fd->mb_pressed_button = retval + 1 - NSAlertFirstButtonReturn; [box release]; }); [pool release]; _al_osx_clear_mouse_state(); return fd->mb_pressed_button; } #pragma mark Text Log View #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 @interface ALLEGLogView : NSTextView #else @interface ALLogView : NSTextView #endif { @public ALLEGRO_NATIVE_DIALOG *textlog; } - (void)keyDown: (NSEvent*)event; - (BOOL)windowShouldClose: (id)sender; - (void)emitCloseEventWithKeypress: (BOOL)keypress; - (void)appendText: (NSString*)text; @end @implementation ALLEGLogView - (void)keyDown: (NSEvent*)event { if (([event keyCode] == 0x35) || // Escape (([event keyCode] == 0x0D) && ([event modifierFlags] & NSCommandKeyMask))) { // Command+W [[self window] close]; [self emitCloseEventWithKeypress: YES]; } else { [super keyDown: event]; } } - (BOOL)windowShouldClose: (id)sender { (void)sender; if (self->textlog->is_active) { if (!(self->textlog->flags & ALLEGRO_TEXTLOG_NO_CLOSE)) { [self emitCloseEventWithKeypress: NO]; } } return YES; } - (void)emitCloseEventWithKeypress: (BOOL)keypress { ALLEGRO_EVENT event; event.user.type = ALLEGRO_EVENT_NATIVE_DIALOG_CLOSE; event.user.timestamp = al_get_time(); event.user.data1 = (intptr_t)self->textlog; event.user.data2 = (intptr_t)keypress; al_emit_user_event(&self->textlog->tl_events, &event, NULL); } - (void)appendText: (NSString*)text { id keys[] = {NSForegroundColorAttributeName, NSFontAttributeName}; id objects[] = {[NSColor controlTextColor], [NSFont userFixedPitchFontOfSize: 0]}; int count = textlog->flags & ALLEGRO_TEXTLOG_MONOSPACE ? 2 : 1; NSDictionary *attributes = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:count]; NSAttributedString *attributedString = [[[NSAttributedString alloc] initWithString:text attributes:attributes] autorelease]; NSTextStorage* store = [self textStorage]; [store beginEditing]; [store appendAttributedString:attributedString]; [store endEditing]; [self scrollRangeToVisible: NSMakeRange(self.string.length, 0)]; } @end bool _al_open_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { NSRect rect = NSMakeRect(0, 0, 640, 480); int adapter = al_get_new_display_adapter(); NSScreen *screen; unsigned int mask = NSTitledWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask; if (!(textlog->flags & ALLEGRO_TEXTLOG_NO_CLOSE)) mask |= NSClosableWindowMask; if ((adapter >= 0) && (adapter < al_get_num_video_adapters())) { screen = [[NSScreen screens] objectAtIndex: adapter]; } else { screen = [NSScreen mainScreen]; } dispatch_sync(dispatch_get_main_queue(), ^{ NSWindow *win = [[NSWindow alloc] initWithContentRect: rect styleMask: mask backing: NSBackingStoreBuffered defer: NO screen: screen]; [win setReleasedWhenClosed: NO]; [win setTitle: @"Allegro Text Log"]; [win setMinSize: NSMakeSize(128, 128)]; NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame: rect]; [scrollView setHasHorizontalScroller: YES]; [scrollView setHasVerticalScroller: YES]; [scrollView setAutohidesScrollers: YES]; [scrollView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; [[scrollView contentView] setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; [[scrollView contentView] setAutoresizesSubviews: YES]; NSRect framerect = [[scrollView contentView] frame]; ALLEGLogView *view = [[ALLEGLogView alloc] initWithFrame: framerect]; view->textlog = textlog; [view setHorizontallyResizable: YES]; [view setVerticallyResizable: YES]; [view setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable]; [[view textContainer] setContainerSize: NSMakeSize(rect.size.width, 1000000)]; [[view textContainer] setWidthTracksTextView: NO]; [view setEditable: NO]; [scrollView setDocumentView: view]; [[win contentView] addSubview: scrollView]; [scrollView release]; [win setDelegate: view]; [win orderFront: nil]; /* Save handles for future use. */ textlog->window = win; // Non-owning reference textlog->tl_textview = view; // Non-owning reference }); /* Now notify al_show_native_textlog that the text log is ready. */ textlog->is_active = true; textlog->tl_done = true; return true; } void _al_close_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { NSWindow *win = (NSWindow *)textlog->window; __block bool is_visible = false; dispatch_sync(dispatch_get_main_queue(), ^{ is_visible = [win isVisible]; }); if (is_visible) { [win performSelectorOnMainThread:@selector(close) withObject:nil waitUntilDone:YES]; } [win performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO]; textlog->window = NULL; textlog->tl_textview = NULL; /* Notify everyone that we're gone. */ textlog->is_active = false; textlog->tl_done = true; } void _al_append_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { if (textlog->is_active) { ALLEGLogView *view = (ALLEGLogView *)textlog->tl_textview; NSString *text = [NSString stringWithUTF8String: al_cstr(textlog->tl_pending_text)]; [view performSelectorOnMainThread:@selector(appendText:) withObject:text waitUntilDone:NO]; al_ustr_truncate(textlog->tl_pending_text, 0); } } #pragma mark Menus /* This class manages the association between windows and menus. * OS X has one menu per application, but Allegro has one menu * per display (i.e. window) as Windows and Linux tend to do. * As a result this class is used to keep track of which menu * was assigned to which window. It listens for the notification when * a window becomes main and swaps in the corresponding menu. */ @interface ALLEGTargetManager : NSObject { NSMutableArray * _items; } +(ALLEGTargetManager*) sharedManager; -(id) init; -(void) dealloc; -(void) setMenu: (NSMenu*) menu forWindow:(NSWindow*) window; @end /* This class represents a menu item target. There is one of these * for each NSMenu and it handles all the items in that menu. It * maintains the correspondence between ALLEGRO_MENU_ITEMs and * NSMenuItems, taking into account the 'App menu' (the one with * the app's name in bold) which appears by convention on OS X. */ @interface ALLEGMenuTarget : NSObject { NSLock* lock; ALLEGRO_MENU* amenu; BOOL _hasAppMenu; NSMenu* _menu; } -(NSMenu*) menu; -(id) initWithMenu:(ALLEGRO_MENU*) amenu; // Designated initializer -(NSMenu*) menu; -(void) show; -(void) showPopup; -(void) insertItem:(ALLEGRO_MENU_ITEM*) item atIndex:(int) index; -(void) updateItem:(ALLEGRO_MENU_ITEM*) item atIndex: (int) index; -(void) destroyItem:(ALLEGRO_MENU_ITEM*) item atIndex: (int) index; -(void) activated: (id) sender; -(BOOL) validateMenuItem:(NSMenuItem *)menuItem; -(void) dealloc; +(ALLEGMenuTarget*) targetForMenu:(ALLEGRO_MENU*) amenu; @end /* Take a menu caption. If it has an accelerator char (preceeded by & or _) * remove the & or _ from the string and return the char. */ static NSString* extract_accelerator(NSMutableString* caption) { NSRange range = [caption rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"&_"]]; if (range.location != NSNotFound && range.location < [caption length]) { [caption deleteCharactersInRange:range]; return [caption substringWithRange: range]; } else { // Not found or you ended the string with & or _ return @""; } } bool _al_init_menu(ALLEGRO_MENU *amenu) { amenu->extra1 = [[ALLEGMenuTarget alloc] initWithMenu: amenu]; return true; } bool _al_init_popup_menu(ALLEGRO_MENU *amenu) { amenu->extra1 = [[ALLEGMenuTarget alloc] initWithMenu: amenu]; return true; } bool _al_insert_menu_item_at(ALLEGRO_MENU_ITEM *aitem, int i) { ALLEGMenuTarget* mt = [ALLEGMenuTarget targetForMenu: aitem->parent]; [mt insertItem: aitem atIndex: i]; return true; } bool _al_destroy_menu_item_at(ALLEGRO_MENU_ITEM *aitem, int i) { ALLEGMenuTarget* mt = [ALLEGMenuTarget targetForMenu: aitem->parent]; [mt destroyItem: aitem atIndex: i]; return true;} bool _al_update_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { ALLEGMenuTarget* mt = [ALLEGMenuTarget targetForMenu: item->parent]; [mt updateItem: item atIndex: i]; return true; } bool _al_show_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *amenu) { ALLEGMenuTarget* target = [ALLEGMenuTarget targetForMenu:amenu]; NSWindow* window = al_osx_get_window(display); [[ALLEGTargetManager sharedManager] setMenu:target.menu forWindow:window]; [target performSelectorOnMainThread:@selector(show) withObject:nil waitUntilDone:YES]; return true; } bool _al_hide_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { (void)menu; (void)display; /* Nowhere to hide on OS X */ return false; } bool _al_show_popup_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *amenu) { (void) display; ALLEGMenuTarget* target = [ALLEGMenuTarget targetForMenu: amenu]; [target performSelectorOnMainThread:@selector(showPopup) withObject:nil waitUntilDone:NO]; return true; } int _al_get_menu_display_height(void) { return 0; } @implementation ALLEGMenuTarget /* Initial conversion of ALLEGRO_MENU_ITEM to NSMenuItem. * The target (self) is set for the item. * The checkbox state is not set here, it's done dynamically in -validateMenuItem. */ -(NSMenuItem*) buildMenuItemFor:(ALLEGRO_MENU_ITEM*) aitem { NSMenuItem* item; if (aitem->caption && al_ustr_length(aitem->caption) > 0) { NSMutableString* title = [NSMutableString stringWithUTF8String:al_cstr(aitem->caption)]; NSString* key = extract_accelerator(title); item = [[NSMenuItem alloc] initWithTitle:title action:@selector(activated:) keyEquivalent:key]; [item setTarget:self]; aitem->extra1 = item; return item; } else { item = [NSMenuItem separatorItem]; } return item; } // Insert the app menu if it's not there already -(void) insertAppMenu { if (!self->_hasAppMenu) { NSMenuItem* apple = [[NSMenuItem alloc] init]; [apple setTitle:@"Apple"]; NSMenu* appleItems = [[NSMenu alloc] init]; [appleItems setTitle:@"Apple"]; [apple setSubmenu:appleItems]; [appleItems addItemWithTitle:@"Hide" action:@selector(hide:) keyEquivalent:@"h"]; [appleItems addItemWithTitle:@"Hide others" action:@selector(hideOtherApplications:) keyEquivalent:@""]; [appleItems addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; [appleItems addItem:[NSMenuItem separatorItem]]; [appleItems addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"]; [self.menu insertItem:apple atIndex:0]; [apple release]; self->_hasAppMenu = YES; } } // Get the NSMenuItem corresponding to this ALLEGRO_MENU_ITEM - (NSMenuItem*) itemForAllegroItem:(ALLEGRO_MENU_ITEM*) aitem { int index = _al_vector_find(&self->amenu->items, &aitem); if (index >= 0) { /* If the app menu is showing it will be at index 0 so account for this */ if (self->_hasAppMenu) { ++index; } return [self.menu itemAtIndex:index]; } else { return nil; } } // Get the ALLEGRO_MENU_ITEM corresponding to this NSMenuItem - (ALLEGRO_MENU_ITEM*) allegroItemforItem: (NSMenuItem*) mi { int i; ALLEGRO_MENU_ITEM * ami; for (i = 0; i < (int)_al_vector_size(&self->amenu->items); i++) { ami = *(ALLEGRO_MENU_ITEM**) _al_vector_ref(&self->amenu->items, i); if (ami->extra1 == mi) { return ami; } } return NULL; } // Create target with ALLEGRO_MENU bound to it. - (id)initWithMenu:(ALLEGRO_MENU*) source_menu { self = [super init]; if (self) { self->_hasAppMenu = NO; self->lock = [[NSLock alloc] init]; self->amenu = source_menu; self->_menu = [[NSMenu alloc] init]; } return self; } -(id) init { /* This isn't a valid initializer */ return nil; } // Manage the enabled and checked state (done dynamically by the framework) -(BOOL) validateMenuItem:(NSMenuItem *)menuItem { ALLEGRO_MENU_ITEM* aitem = [self allegroItemforItem:menuItem]; if (aitem) { int checked = (aitem->flags & (ALLEGRO_MENU_ITEM_CHECKBOX|ALLEGRO_MENU_ITEM_CHECKED)) == (ALLEGRO_MENU_ITEM_CHECKBOX|ALLEGRO_MENU_ITEM_CHECKED); [menuItem setState: checked ? NSOnState : NSOffState ]; return aitem->flags & ALLEGRO_MENU_ITEM_DISABLED ? NO : YES; } return YES; } - (void)dealloc { [self->lock release]; [self->_menu release]; [super dealloc]; } // Get the menu -(NSMenu*) menu { return self->_menu; } // Action event when the menu is selected -(void) activated:(id)sender { NSMenuItem* mitem = (NSMenuItem*) sender; ALLEGRO_MENU_ITEM* aitim = [self allegroItemforItem:mitem]; if (aitim) { if (aitim->flags & ALLEGRO_MENU_ITEM_CHECKBOX) { aitim->flags ^= ALLEGRO_MENU_ITEM_CHECKED; } _al_emit_menu_event(aitim->parent->display, aitim->unique_id); } } // Insert an item, keep the NSMenu in sync -(void) insertItem:(ALLEGRO_MENU_ITEM*) aitem atIndex: (int) index { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSMenuItem* item = [self buildMenuItemFor:aitem]; [self.menu insertItem:item atIndex:index]; if (aitem->popup) { ALLEGMenuTarget* sub = [ALLEGMenuTarget targetForMenu:aitem->popup]; [[sub menu] setTitle:[item title]]; [item setAction:nil]; [item setSubmenu:[sub menu]]; } [pool release]; } // Update an item (caption only, see -validateMenuItem: ) -(void) updateItem:(ALLEGRO_MENU_ITEM *)aitem atIndex:(int)index { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; (void) index; NSMenuItem* item = [self itemForAllegroItem:aitem]; NSMutableString* caption = [NSMutableString stringWithUTF8String:al_cstr(aitem->caption)]; NSString* key = extract_accelerator(caption); [item setTitle:caption]; [item setKeyEquivalent:key]; if (aitem->popup) { [item setEnabled:(aitem->flags & ALLEGRO_MENU_ITEM_DISABLED) ? NO : YES]; } [pool release]; } // Remove an item, keep the NSMenu in sync -(void) destroyItem:(ALLEGRO_MENU_ITEM *)aitem atIndex:(int)index { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; (void) index; NSMenuItem* item = [self itemForAllegroItem:aitem]; [item.menu removeItem:item]; [pool release]; } // Show the menu on the main application menu bar -(void) show { [self insertAppMenu]; [NSApp setMainMenu:self.menu]; } // Show the menu as a pop-up on the current key window. -(void) showPopup { NSWindow *window = [NSApp keyWindow]; NSPoint mouseLocation = [NSEvent mouseLocation]; NSPoint locationInWindow = [window convertScreenToBase: mouseLocation]; int eventType = NSLeftMouseDown; int winnum = [window windowNumber]; NSEvent *fakeMouseEvent = [NSEvent mouseEventWithType:eventType location:locationInWindow modifierFlags:0 timestamp:0 windowNumber:winnum context:nil eventNumber:0 clickCount:0 pressure:0]; [NSMenu popUpContextMenu:self.menu withEvent:fakeMouseEvent forView:[window contentView]]; } // Find the target associated with this ALLEGRO_MENU +(ALLEGMenuTarget*) targetForMenu:(ALLEGRO_MENU *)amenu { if (!amenu->extra1) { amenu->extra1 = [[ALLEGMenuTarget alloc] initWithMenu:amenu]; } return amenu->extra1; } @end // ALLEGMenuTarget static ALLEGTargetManager* _sharedmanager = nil; @implementation ALLEGTargetManager // Get the singleton manager object +(ALLEGTargetManager*) sharedManager { if (!_sharedmanager) { _sharedmanager = [[ALLEGTargetManager alloc] init]; } return _sharedmanager; } // Set up and register for notifications -(id) init { self = [super init]; if (self) { self->_items = [[NSMutableArray alloc] init]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onWindowChange:) name:NSWindowDidBecomeMainNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onWindowClose:) name:NSWindowWillCloseNotification object:nil]; } return self; } // Destroy and un-register -(void) dealloc { [self->_items release]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } // Find the index for a window which this object is managing or NSNotFound -(NSUInteger) indexForWindow:(NSWindow*) window { NSUInteger i; for (i=0; i<[self->_items count]; ++i) { NSDictionary* entry = [self->_items objectAtIndex:i]; if ([window isEqual:[entry valueForKey:@"window"]]) { return i; } } return NSNotFound; } // Event when main window changes - locate the matching menu and show it -(void) onWindowChange: (NSNotification*) notification { NSWindow* window = [notification object]; NSUInteger index = [self indexForWindow: window]; if (index != NSNotFound) { NSDictionary* entry = [self->_items objectAtIndex:index]; NSMenu* menu = [entry valueForKey:@"menu"]; [NSApp setMainMenu:menu]; } /* If not found we do nothing */ } // Event when window closes, remove it from the managed list -(void) onWindowClose: (NSNotification*) notification { NSWindow* window = [notification object]; NSUInteger index = [self indexForWindow: window]; if (index != NSNotFound) { [self->_items removeObjectAtIndex:index]; } /* If not found we do nothing */ } // Link a menu with a window, replace any existing link -(void) setMenu:(NSMenu *)menu forWindow:(NSWindow *)window { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSUInteger index = [self indexForWindow:window]; if (menu) { NSDictionary* newentry = [NSDictionary dictionaryWithObjectsAndKeys:menu, @"menu", window, @"window", nil]; if (index == NSNotFound) { [self->_items addObject: newentry]; } else { [self->_items replaceObjectAtIndex:index withObject: newentry]; } } else { /* Menu was null so delete */ if (index != NSNotFound) { [self->_items removeObjectAtIndex:index]; } } [pool release]; } @end // ALLEGTargetManager allegro5-5.2.10.1/addons/native_dialog/textlog.c000066400000000000000000000111231473414355200213650ustar00rootroot00000000000000#include #include #include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern_native_dialog.h" #include "allegro5/internal/aintern_native_dialog_cfg.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_system.h" /* The GTK and OSX implementations do not require an extra thread. * The Windows implementation does. */ #if defined(ALLEGRO_CFG_NATIVE_DIALOG_WINDOWS) #define TEXT_LOG_EXTRA_THREAD true #else #define TEXT_LOG_EXTRA_THREAD false #endif /* This will only return when the text window is closed. */ static void *text_log_thread_proc(ALLEGRO_THREAD *thread, void *arg) { ALLEGRO_NATIVE_DIALOG *textlog = arg; if (!_al_open_native_text_log(textlog)) { al_lock_mutex(textlog->tl_text_mutex); textlog->tl_init_error = true; al_signal_cond(textlog->tl_text_cond); al_unlock_mutex(textlog->tl_text_mutex); } return thread; } /* Function: al_open_native_text_log */ ALLEGRO_TEXTLOG *al_open_native_text_log(char const *title, int flags) { ALLEGRO_NATIVE_DIALOG *textlog = NULL; /* Avoid warnings when log windows are unimplemented. */ (void)title; (void)flags; textlog = al_calloc(1, sizeof *textlog); textlog->title = al_ustr_new(title); textlog->flags = flags; if (TEXT_LOG_EXTRA_THREAD) { textlog->tl_thread = al_create_thread(text_log_thread_proc, textlog); } textlog->tl_text_cond = al_create_cond(); textlog->tl_text_mutex = al_create_mutex(); textlog->tl_pending_text = al_ustr_new(""); al_init_user_event_source(&textlog->tl_events); textlog->tl_init_error = false; textlog->tl_done = false; if (TEXT_LOG_EXTRA_THREAD) { /* Unlike the other dialogs, this one never blocks as the intended * use case is a log window running in the background for debugging * purposes when no console can be used. Therefore we have it run * in a separate thread. */ al_start_thread(textlog->tl_thread); al_lock_mutex(textlog->tl_text_mutex); while (!textlog->tl_done && !textlog->tl_init_error) { al_wait_cond(textlog->tl_text_cond, textlog->tl_text_mutex); } al_unlock_mutex(textlog->tl_text_mutex); } else { textlog->tl_init_error = !_al_open_native_text_log(textlog); } if (textlog->tl_init_error) { al_close_native_text_log((ALLEGRO_TEXTLOG *)textlog); return NULL; } textlog->dtor_item = _al_register_destructor(_al_dtor_list, "textlog", textlog, (void (*)(void *))al_close_native_text_log); return (ALLEGRO_TEXTLOG *)textlog; } /* Function: al_close_native_text_log */ void al_close_native_text_log(ALLEGRO_TEXTLOG *textlog) { ALLEGRO_NATIVE_DIALOG *dialog = (ALLEGRO_NATIVE_DIALOG *)textlog; if (!dialog) return; if (!dialog->tl_init_error) { dialog->tl_done = false; if (TEXT_LOG_EXTRA_THREAD) { al_lock_mutex(dialog->tl_text_mutex); _al_close_native_text_log(dialog); while (!dialog->tl_done) { al_wait_cond(dialog->tl_text_cond, dialog->tl_text_mutex); } } else { _al_close_native_text_log(dialog); al_lock_mutex(dialog->tl_text_mutex); } _al_unregister_destructor(_al_dtor_list, dialog->dtor_item); } al_ustr_free(dialog->title); al_ustr_free(dialog->tl_pending_text); al_destroy_user_event_source(&dialog->tl_events); al_unlock_mutex(dialog->tl_text_mutex); if (TEXT_LOG_EXTRA_THREAD) { al_destroy_thread(dialog->tl_thread); } al_destroy_cond(dialog->tl_text_cond); al_destroy_mutex(dialog->tl_text_mutex); al_free(dialog); } /* Function: al_append_native_text_log */ void al_append_native_text_log(ALLEGRO_TEXTLOG *textlog, char const *format, ...) { ALLEGRO_NATIVE_DIALOG *dialog = (ALLEGRO_NATIVE_DIALOG *)textlog; va_list args; /* Fall back to printf if no window. */ if (!dialog) { va_start(args, format); vprintf(format, args); va_end(args); return; } al_lock_mutex(dialog->tl_text_mutex); /* We could optimise the case where format="%s". */ va_start(args, format); al_ustr_vappendf(dialog->tl_pending_text, format, args); va_end(args); _al_append_native_text_log(dialog); al_unlock_mutex(dialog->tl_text_mutex); } /* Function: al_get_native_text_log_event_source */ ALLEGRO_EVENT_SOURCE *al_get_native_text_log_event_source( ALLEGRO_TEXTLOG *textlog) { ALLEGRO_NATIVE_DIALOG *dialog = (ALLEGRO_NATIVE_DIALOG *)textlog; ASSERT(dialog); return &dialog->tl_events; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/native_dialog/win_dialog.c000066400000000000000000000662711473414355200220310ustar00rootroot00000000000000/* Each of these files implements the same, for different GUI toolkits: * * dialog.c - code shared between all platforms * gtk_dialog.c - GTK file open dialog * osx_dialog.m - OSX file open dialog * qt_dialog.cpp - Qt file open dialog * win_dialog.c - Windows file open dialog * */ #include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_native_dialog.h" #include "allegro5/platform/aintwin.h" #include "allegro5/internal/aintern_wunicode.h" #include "allegro5/allegro_windows.h" #include /* We use RichEdit by default. */ #include #include // for folder selector ALLEGRO_DEBUG_CHANNEL("win_dialog") #define WM_SHOW_POPUP (WM_APP + 42) #define WM_HIDE_MENU (WM_APP + 43) #define WM_SHOW_MENU (WM_APP + 44) /* Reference count for shared resources. */ static int wlog_count = 0; /* Handle of RichEdit module */ static void *wlog_rich_edit_module = 0; /* Name of the edit control. Depend on system resources. */ static TCHAR* wlog_edit_control = TEXT("EDIT"); /* True if output support unicode */ static bool wlog_unicode = false; static ALLEGRO_MUTEX* global_mutex; static ALLEGRO_COND* wm_size_cond; static bool got_wm_size_event = false; /* For Unicode support, define some helper functions * which work with either UTF-16 or ANSI code pages * depending on whether UNICODE is defined or not. */ /* tcreate_path: * Create path from TCHARs */ static ALLEGRO_PATH* _tcreate_path(const TCHAR* ts) { char* tmp = _twin_tchar_to_utf8(ts); ALLEGRO_PATH* path = al_create_path(tmp); al_free(tmp); return path; } /* tcreate_path: * Create directory path from TCHARs */ static ALLEGRO_PATH* _tcreate_path_for_directory(const TCHAR* ts) { char* tmp = _twin_tchar_to_utf8(ts); ALLEGRO_PATH* path = al_create_path_for_directory(tmp); al_free(tmp); return path; } bool _al_init_native_dialog_addon(void) { global_mutex = al_create_mutex(); wm_size_cond = al_create_cond(); if (!global_mutex || !wm_size_cond) { al_destroy_mutex(global_mutex); al_destroy_cond(wm_size_cond); return false; } return true; } void _al_shutdown_native_dialog_addon(void) { al_destroy_mutex(global_mutex); al_destroy_cond(wm_size_cond); global_mutex = NULL; wm_size_cond = NULL; } static INT CALLBACK _browse_callback_proc(HWND hwnd, UINT uMsg, LPARAM unused, LPARAM pData) { (void)unused; if (uMsg == BFFM_INITIALIZED) SendMessage(hwnd, BFFM_SETSELECTION, TRUE, pData); return 0; } static TCHAR* _extract_dirname(ALLEGRO_PATH *fullpath) { TCHAR* wpath = NULL; bool is_dir; const ALLEGRO_USTR *path = al_path_ustr(fullpath, ALLEGRO_NATIVE_PATH_SEP); if (al_filename_exists(al_cstr(path))) { ALLEGRO_FS_ENTRY *fs = al_create_fs_entry(al_cstr(path)); is_dir = al_get_fs_entry_mode(fs) & ALLEGRO_FILEMODE_ISDIR; al_destroy_fs_entry(fs); } else { is_dir = false; } if (is_dir) { wpath = _twin_ustr_to_tchar(path); } else { /* Extract the directory from the path. */ ALLEGRO_PATH* initial_dir_path = NULL; initial_dir_path = al_clone_path(fullpath); if (initial_dir_path) { al_set_path_filename(initial_dir_path, NULL); wpath = _twin_utf8_to_tchar(al_path_cstr(initial_dir_path, ALLEGRO_NATIVE_PATH_SEP)); al_destroy_path(initial_dir_path); } } return wpath; } static bool select_folder(ALLEGRO_DISPLAY_WIN *win_display, ALLEGRO_NATIVE_DIALOG *fd) { BROWSEINFO folderinfo; TCHAR* wpath = NULL; LPCITEMIDLIST pidl; /* Selected path */ TCHAR buf[MAX_PATH] = TEXT(""); /* Display name */ TCHAR dbuf[MAX_PATH] = TEXT(""); folderinfo.hwndOwner = win_display ? win_display->window : NULL; folderinfo.pidlRoot = NULL; folderinfo.pszDisplayName = dbuf; folderinfo.lpszTitle = _twin_ustr_to_tchar(fd->title); folderinfo.ulFlags = 0; folderinfo.lpfn = NULL; if (fd->fc_initial_path) { wpath = _extract_dirname(fd->fc_initial_path); folderinfo.lpfn = _browse_callback_proc; folderinfo.lParam = (LPARAM) wpath; } pidl = SHBrowseForFolder(&folderinfo); al_free((void*) folderinfo.lpszTitle); al_free(wpath); if (pidl) { SHGetPathFromIDList(pidl, buf); fd->fc_path_count = 1; fd->fc_paths = al_malloc(sizeof(void *)); fd->fc_paths[0] = _tcreate_path(buf); return true; } return false; } static ALLEGRO_USTR *create_filter_string(const _AL_VECTOR *patterns) { ALLEGRO_USTR *filter = al_ustr_new(""); for (size_t i = 0; i < _al_vector_size(patterns); i++) { _AL_PATTERNS_AND_DESC *patterns_and_desc = _al_vector_ref(patterns, i); bool any_valid = false; for (size_t j = 0; j < _al_vector_size(&patterns_and_desc->patterns_vec); j++) { _AL_PATTERN *pattern = _al_vector_ref(&patterns_and_desc->patterns_vec, j); any_valid |= !pattern->is_mime; } if (!any_valid) { continue; } const ALLEGRO_USTR *desc = al_ref_info(&patterns_and_desc->desc); if (al_ustr_size(desc) > 0) { al_ustr_append(filter, desc); } else { al_ustr_append_cstr(filter, "All supported files"); } al_ustr_append_chr(filter, '\0'); bool first = true; for (size_t j = 0; j < _al_vector_size(&patterns_and_desc->patterns_vec); j++) { _AL_PATTERN *pattern = _al_vector_ref(&patterns_and_desc->patterns_vec, j); if (!pattern->is_mime) { if (!first) { al_ustr_append_chr(filter, ';'); } first = false; if (pattern->is_catchall) al_ustr_append_cstr(filter, "*.*"); else al_ustr_append(filter, al_ref_info(&pattern->info)); } } al_ustr_append_chr(filter, '\0'); } al_ustr_append_chr(filter, '\0'); return filter; } static int skip_nul_terminated_string(TCHAR *s) { int i = 0; while (s[i]) i++; return i+1; } bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display, ALLEGRO_NATIVE_DIALOG *fd) { OPENFILENAME ofn; ALLEGRO_DISPLAY_WIN *win_display; int flags = 0; bool ret; TCHAR buf[4096]; const int BUFSIZE = sizeof(buf) / sizeof(TCHAR); TCHAR* wfilter = NULL; TCHAR* wpath = NULL; ALLEGRO_USTR *filter_string = NULL; buf[0] = '\0'; win_display = (ALLEGRO_DISPLAY_WIN *)display; if (fd->flags & ALLEGRO_FILECHOOSER_FOLDER) { return select_folder(win_display, fd); } /* Selecting a file. */ memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = win_display ? win_display->window : NULL; /* Create filter string. */ if (_al_vector_size(&fd->fc_patterns) > 0) { filter_string = create_filter_string(&fd->fc_patterns); wfilter = _twin_ustr_to_tchar(filter_string); ofn.lpstrFilter = wfilter; } else { /* List all files by default. */ ofn.lpstrFilter = TEXT("All Files\0*.*\0\0"); } /* Provide buffer for file chosen by dialog. */ ofn.lpstrFile = buf; ofn.nMaxFile = BUFSIZE; /* Initialize file name buffer and starting directory. */ if (fd->fc_initial_path) { wpath = _extract_dirname(fd->fc_initial_path); ofn.lpstrInitialDir = wpath; } if (fd->title) ofn.lpstrTitle = _twin_ustr_to_tchar(fd->title); flags |= OFN_NOCHANGEDIR | OFN_EXPLORER; if (fd->flags & ALLEGRO_FILECHOOSER_SAVE) { flags |= OFN_OVERWRITEPROMPT; } else { flags |= (fd->flags & ALLEGRO_FILECHOOSER_FILE_MUST_EXIST) ? OFN_FILEMUSTEXIST : 0; } flags |= (fd->flags & ALLEGRO_FILECHOOSER_MULTIPLE) ? OFN_ALLOWMULTISELECT : 0; flags |= (fd->flags & ALLEGRO_FILECHOOSER_SHOW_HIDDEN) ? 0x10000000 : 0; // NOTE: 0x10000000 is FORCESHOWHIDDEN ofn.Flags = flags; if (flags & OFN_OVERWRITEPROMPT) { ret = GetSaveFileName(&ofn); } else { ret = GetOpenFileName(&ofn); } al_free((void*) ofn.lpstrTitle); al_free(wfilter); al_free(wpath); al_ustr_free(filter_string); if (!ret) { DWORD err = GetLastError(); if (err != ERROR_SUCCESS) { ALLEGRO_ERROR("al_show_native_file_dialog failed: %s\n", _al_win_error(err)); } return false; } if (flags & OFN_ALLOWMULTISELECT) { int i = 0; /* Count number of file names in buf. */ fd->fc_path_count = 0; while (1) { int j = skip_nul_terminated_string(buf + i); if (j <= 1) break; fd->fc_path_count++; i += j; } } else { fd->fc_path_count = 1; } if (fd->fc_path_count == 1) { fd->fc_paths = al_malloc(sizeof(void *)); fd->fc_paths[0] = _tcreate_path(buf); } else { int i, p; /* If multiple files were selected, the first string in buf is the * directory name, followed by each of the file names terminated by NUL. */ fd->fc_path_count -= 1; fd->fc_paths = al_malloc(fd->fc_path_count * sizeof(void *)); i = skip_nul_terminated_string(buf); for (p = 0; p < (int)fd->fc_path_count; p++) { fd->fc_paths[p] = _tcreate_path_for_directory(buf); char* tmp = _twin_tchar_to_utf8(buf + i); al_set_path_filename(fd->fc_paths[p], tmp); al_free(tmp); i += skip_nul_terminated_string(buf+i); } } return true; } int _al_show_native_message_box(ALLEGRO_DISPLAY *display, ALLEGRO_NATIVE_DIALOG *fd) { UINT type = MB_SETFOREGROUND; int result; TCHAR *text, *title; /* Note: the message box code cannot assume that Allegro is installed. */ if (fd->flags & ALLEGRO_MESSAGEBOX_QUESTION) type |= MB_ICONQUESTION; else if (fd->flags & ALLEGRO_MESSAGEBOX_WARN) type |= MB_ICONWARNING; else if (fd->flags & ALLEGRO_MESSAGEBOX_ERROR) type |= MB_ICONERROR; else type |= MB_ICONINFORMATION; if (fd->flags & ALLEGRO_MESSAGEBOX_YES_NO) type |= MB_YESNO; else if (fd->flags & ALLEGRO_MESSAGEBOX_OK_CANCEL) type |= MB_OKCANCEL; /* heading + text are combined together */ if (al_ustr_size(fd->mb_heading)) al_ustr_append_cstr(fd->mb_heading, "\n\n"); al_ustr_append(fd->mb_heading, fd->mb_text); text = _twin_ustr_to_tchar(fd->mb_heading); if (!text) { return 0; } title = _twin_ustr_to_tchar(fd->title); if (!title) { al_free(text); return 0; } result = MessageBox(al_get_win_window_handle(display), text, title, type); al_free(text); al_free(title); if (result == IDYES || result == IDOK) return 1; else return 2; } /* Emit close event. */ static void wlog_emit_close_event(ALLEGRO_NATIVE_DIALOG *textlog, bool keypress) { ALLEGRO_EVENT event; event.user.type = ALLEGRO_EVENT_NATIVE_DIALOG_CLOSE; event.user.timestamp = al_get_time(); event.user.data1 = (intptr_t)textlog; event.user.data2 = (intptr_t)keypress; al_emit_user_event(&textlog->tl_events, &event, NULL); } /* convert_crlf: * Alter this string to change every LF to CRLF */ static ALLEGRO_USTR* convert_crlf(ALLEGRO_USTR* s) { int pos = 0; int ch, prev; while ((pos = al_ustr_find_chr(s, pos, '\n')) >= 0) { prev = pos; ch = al_ustr_prev_get(s, &prev); if (ch == -2) { return s; } else if (ch != '\r') { al_ustr_insert_chr(s, pos, '\r'); al_ustr_next(s, &pos); } al_ustr_next(s, &pos); } return s; } /* General function to output log message. */ static void wlog_do_append_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { int index; index = GetWindowTextLength(textlog->tl_textview); SendMessage(textlog->tl_textview, EM_SETSEL, (WPARAM)index, (LPARAM)index); convert_crlf(textlog->tl_pending_text); TCHAR* buf = _twin_utf8_to_tchar(al_cstr(textlog->tl_pending_text)); SendMessage(textlog->tl_textview, EM_REPLACESEL, 0, (LPARAM) buf); al_free(buf); al_ustr_truncate(textlog->tl_pending_text, 0); textlog->tl_have_pending = false; SendMessage(textlog->tl_textview, WM_VSCROLL, SB_BOTTOM, 0); } /* Text log window callback. */ static LRESULT CALLBACK wlog_text_log_callback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CREATESTRUCT* create_struct; ALLEGRO_NATIVE_DIALOG* textlog = (ALLEGRO_NATIVE_DIALOG*)GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (uMsg) { case WM_CREATE: /* Set user data for window, so we will be able to retrieve text log structure any time */ create_struct = (CREATESTRUCT*)lParam; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)create_struct->lpCreateParams); break; case WM_CLOSE: if (textlog->is_active) { if (!(textlog->flags & ALLEGRO_TEXTLOG_NO_CLOSE)) { wlog_emit_close_event(textlog, false); } return 0; } break; case WM_DESTROY: PostQuitMessage(0); break; case WM_KEYDOWN: if (wParam == VK_ESCAPE) { wlog_emit_close_event(textlog, true); } break; case WM_MOVE: InvalidateRect(hWnd, NULL, FALSE); break; case WM_SIZE: /* Match text log size to parent client area */ if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) { RECT client_rect; GetClientRect(hWnd, &client_rect); MoveWindow(textlog->tl_textview, client_rect.left, client_rect.top, client_rect.right - client_rect.left, client_rect.bottom - client_rect.top, TRUE); } break; case WM_USER: al_lock_mutex(textlog->tl_text_mutex); wlog_do_append_native_text_log(textlog); al_unlock_mutex(textlog->tl_text_mutex); break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } /* We hold textlog->tl_text_mutex. */ static bool open_native_text_log_inner(ALLEGRO_NATIVE_DIALOG *textlog) { LPCTSTR font_name; HWND hWnd; HWND hLog; RECT client_rect; HFONT hFont; MSG msg; BOOL ret; TCHAR* title; /* Create text log window. */ title = _twin_ustr_to_tchar(textlog->title); hWnd = CreateWindow(TEXT("Allegro Text Log"), title, WS_CAPTION | WS_SIZEBOX | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, (HINSTANCE)GetModuleHandle(NULL), textlog); al_free(title); if (!hWnd) { ALLEGRO_ERROR("CreateWindow failed\n"); return false; } /* Get client area of the log window. */ GetClientRect(hWnd, &client_rect); /* Create edit control. */ hLog = CreateWindow(wlog_edit_control, NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL | ES_READONLY, client_rect.left, client_rect.top, client_rect.right - client_rect.left, client_rect.bottom - client_rect.top, hWnd, NULL, (HINSTANCE)GetModuleHandle(NULL), NULL); if (!hLog) { ALLEGRO_ERROR("CreateWindow failed\n"); DestroyWindow(hWnd); return false; } /* Enable double-buffering. */ SetWindowLong(hLog, GWL_EXSTYLE, GetWindowLong(hLog, GWL_EXSTYLE) | 0x02000000L/*WS_EX_COMPOSITED*/); /* Select font name. */ if (textlog->flags & ALLEGRO_TEXTLOG_MONOSPACE) font_name = TEXT("Courier New"); else font_name = TEXT("Arial"); /* Create font and set font. */ hFont = CreateFont(-11, 0, 0, 0, FW_LIGHT, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH, font_name); /* Assign font to the text log. */ if (hFont) { SendMessage(hLog, WM_SETFONT, (WPARAM)hFont, 0); } /* We are ready to show our window. */ ShowWindow(hWnd, SW_NORMAL); /* Save handles for future use. */ textlog->window = hWnd; textlog->tl_textview = hLog; textlog->is_active = true; /* Now notify al_show_native_textlog that the text log is ready. */ textlog->tl_done = true; al_signal_cond(textlog->tl_text_cond); al_unlock_mutex(textlog->tl_text_mutex); /* Process messages. */ while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0) { if (ret != -1 && msg.message != WM_QUIT) { /* Intercept child window key down messages. Needed to track * hit of ESCAPE key while text log have focus. */ if (msg.hwnd != textlog->window && msg.message == WM_KEYDOWN) { PostMessage(textlog->window, WM_KEYDOWN, msg.wParam, msg.lParam); } TranslateMessage(&msg); DispatchMessage(&msg); } else break; } /* Close window. Should be already closed, this is just sanity. */ if (IsWindow(textlog->window)) { DestroyWindow(textlog->window); } /* Release font. We don't want to leave any garbage. */ DeleteObject(hFont); /* Notify everyone that we're gone. */ al_lock_mutex(textlog->tl_text_mutex); textlog->tl_done = true; al_signal_cond(textlog->tl_text_cond); return true; } bool _al_open_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { WNDCLASS text_log_class; bool rc; al_lock_mutex(textlog->tl_text_mutex); /* Note: the class registration and rich edit module loading are not * implemented in a thread-safe manner (pretty unlikely). */ /* Prepare text log class info. */ if (wlog_count == 0) { ALLEGRO_DEBUG("Register text log class\n"); memset(&text_log_class, 0, sizeof(text_log_class)); text_log_class.hInstance = (HINSTANCE)GetModuleHandle(NULL); text_log_class.lpszClassName = TEXT("Allegro Text Log"); text_log_class.lpfnWndProc = wlog_text_log_callback; text_log_class.hIcon = NULL; text_log_class.hCursor = NULL; text_log_class.lpszMenuName = NULL; text_log_class.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH); if (RegisterClass(&text_log_class) == 0) { /* Failure, window class is a basis and we do not have one. */ ALLEGRO_ERROR("RegisterClass failed\n"); al_unlock_mutex(textlog->tl_text_mutex); return false; } } /* Load RichEdit control. */ if (wlog_count == 0) { ALLEGRO_DEBUG("Load rich edit module\n"); ALLEGRO_ASSERT(!wlog_rich_edit_module); if ((wlog_rich_edit_module = _al_open_library("msftedit.dll"))) { /* 4.1 and emulation of 3.0, 2.0, 1.0 */ wlog_edit_control = TEXT("RICHEDIT50W"); /*MSFTEDIT_CLASS*/ wlog_unicode = true; } else if ((wlog_rich_edit_module = _al_open_library("riched20.dll"))) { /* 3.0, 2.0 */ wlog_edit_control = TEXT("RichEdit20W"); /*RICHEDIT_CLASS*/ wlog_unicode = true; } else if ((wlog_rich_edit_module = _al_open_library("riched32.dll"))) { /* 1.0 */ wlog_edit_control = TEXT("RichEdit"); /*RICHEDIT_CLASS*/ wlog_unicode = false; } else { wlog_edit_control = TEXT("EDIT"); wlog_unicode = false; } } wlog_count++; ALLEGRO_DEBUG("wlog_count = %d\n", wlog_count); rc = open_native_text_log_inner(textlog); wlog_count--; ALLEGRO_DEBUG("wlog_count = %d\n", wlog_count); /* Release RichEdit module. */ if (wlog_count == 0 && wlog_rich_edit_module) { ALLEGRO_DEBUG("Unload rich edit module\n"); _al_close_library(wlog_rich_edit_module); wlog_rich_edit_module = NULL; } /* Unregister window class. */ if (wlog_count == 0) { ALLEGRO_DEBUG("Unregister text log class\n"); UnregisterClass(TEXT("Allegro Text Log"), (HINSTANCE)GetModuleHandle(NULL)); } al_unlock_mutex(textlog->tl_text_mutex); return rc; } void _al_close_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { /* Just deactivate text log and send bye, bye message. */ if (IsWindow(textlog->window)) { textlog->is_active = false; PostMessage(textlog->window, WM_CLOSE, 0, 0); } } void _al_append_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog) { if (textlog->tl_have_pending) return; textlog->tl_have_pending = true; /* Post text as user message. This guarantees that the whole processing will * take place on text log thread. */ if (IsWindow(textlog->window)) { PostMessage(textlog->window, WM_USER, (WPARAM)textlog, 0); } } static bool menu_callback(ALLEGRO_DISPLAY *display, UINT msg, WPARAM wParam, LPARAM lParam, LPARAM* result, void *userdata) { (void) userdata; *result = 0; if (msg == WM_COMMAND && lParam == 0) { const int id = LOWORD(wParam); _AL_MENU_ID *menu_id = _al_find_parent_menu_by_id(display, id); if (menu_id) { int index; if (_al_find_menu_item_unique(menu_id->menu, id, NULL, &index)) { if (al_get_menu_item_flags(menu_id->menu, -index) & ALLEGRO_MENU_ITEM_CHECKBOX) { /* Toggle the checkbox, since Windows doesn't do that automatically. */ al_toggle_menu_item_flags(menu_id->menu, -index, ALLEGRO_MENU_ITEM_CHECKED); } } } _al_emit_menu_event(display, id); return true; } else if (msg == WM_SYSCOMMAND) { if ((wParam & 0xfff0) == SC_KEYMENU && al_get_display_menu(display) != NULL) { /* Allow the ALT key to open the menu * XXX: do we even want to do this? Should it be optional? */ DefWindowProc(al_get_win_window_handle(display), msg, wParam, lParam); return true; } } else if (msg == WM_SHOW_POPUP) { ALLEGRO_MENU *menu = (ALLEGRO_MENU *) lParam; HWND hwnd = al_get_win_window_handle(display); POINT pos; GetCursorPos(&pos); SetForegroundWindow(hwnd); TrackPopupMenuEx((HMENU) menu->extra1, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, pos.x, pos.y, hwnd, NULL); return true; } else if (msg == WM_HIDE_MENU) { SetMenu(al_get_win_window_handle(display), NULL); return true; } else if (msg == WM_SHOW_MENU) { ALLEGRO_MENU *menu = (ALLEGRO_MENU *) lParam; SetMenu(al_get_win_window_handle(display), (HMENU) menu->extra1); return true; } else if (msg == WM_SIZE) { ALLEGRO_DEBUG("Got the WM_SIZE event.\n"); got_wm_size_event = true; al_signal_cond(wm_size_cond); } else if (msg == WM_MENUSELECT) { /* XXX: could use this as a way to indicate the popup menu was canceled */ } return false; } static void init_menu_info(MENUITEMINFO *info, ALLEGRO_MENU_ITEM *menu) { memset(info, 0, sizeof(*info)); info->cbSize = sizeof(*info); info->fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_STRING | MIIM_CHECKMARKS; info->wID = menu->unique_id; if (!menu->caption) { info->fType = MFT_SEPARATOR; } else { info->fType = MFT_STRING; info->dwTypeData = _twin_ustr_to_tchar(menu->caption); info->cch = al_ustr_size(menu->caption); } if (menu->flags & ALLEGRO_MENU_ITEM_CHECKED) { info->fState |= MFS_CHECKED; } if (menu->flags & ALLEGRO_MENU_ITEM_DISABLED) { info->fState |= MFS_DISABLED; } if (menu->icon) { /* convert ALLEGRO_BITMAP to HBITMAP (could be moved into a public function) */ const int h = al_get_bitmap_height(menu->icon), w = al_get_bitmap_width(menu->icon); HDC hdc; HBITMAP hbmp; BITMAPINFO bi; uint8_t *data = NULL; ALLEGRO_LOCKED_REGION *lock; ZeroMemory(&bi, sizeof(BITMAPINFO)); bi.bmiHeader.biSize = sizeof(BITMAPINFO); bi.bmiHeader.biWidth = w; bi.bmiHeader.biHeight = -h; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; hdc = GetDC(menu->parent->display ? al_get_win_window_handle(menu->parent->display) : NULL); hbmp = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&data, NULL, 0); lock = al_lock_bitmap(menu->icon, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_READONLY); memcpy(data, lock->data, w * h * 4); al_unlock_bitmap(menu->icon); info->hbmpUnchecked = hbmp; menu->extra2 = hbmp; ReleaseDC(menu->parent->display ? al_get_win_window_handle(menu->parent->display) : NULL, hdc); } if (menu->popup) { info->hSubMenu = (HMENU) menu->popup->extra1; } } static void destroy_menu_info(MENUITEMINFO *info) { if (info->dwTypeData) { al_free(info->dwTypeData); } } bool _al_init_menu(ALLEGRO_MENU *menu) { menu->extra1 = CreateMenu(); return menu->extra1 != NULL; } bool _al_init_popup_menu(ALLEGRO_MENU *menu) { menu->extra1 = CreatePopupMenu(); return menu->extra1 != NULL; } bool _al_insert_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { MENUITEMINFO info; init_menu_info(&info, item); InsertMenuItem((HMENU) item->parent->extra1, i, TRUE, &info); destroy_menu_info(&info); return true; } bool _al_update_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { MENUITEMINFO info; init_menu_info(&info, item); SetMenuItemInfo((HMENU) item->parent->extra1, i, TRUE, &info); if (item->parent->display) DrawMenuBar(al_get_win_window_handle(item->parent->display)); destroy_menu_info(&info); return true; } bool _al_destroy_menu_item_at(ALLEGRO_MENU_ITEM *item, int i) { DeleteMenu((HMENU) item->parent->extra1, i, MF_BYPOSITION); if (item->parent->display) DrawMenuBar(al_get_win_window_handle(item->parent->display)); return true; } bool _al_show_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { HWND hwnd = al_get_win_window_handle(display); if (!hwnd) return false; ASSERT(menu->extra1); /* Note that duplicate callbacks are automatically filtered out, so it's safe to call this many times. */ al_win_add_window_callback(display, menu_callback, NULL); got_wm_size_event = false; PostMessage(al_get_win_window_handle(display), WM_SHOW_MENU, 0, (LPARAM) menu); /* Wait for the WM_SIZE event, otherwise the compensatory * al_resize_display (see menu.c) won't work right. */ if (wm_size_cond && global_mutex) { ALLEGRO_DEBUG("Sent WM_SHOW_MENU, waiting for WM_SIZE.\n"); al_lock_mutex(global_mutex); while (!got_wm_size_event) { al_wait_cond(wm_size_cond, global_mutex); } al_unlock_mutex(global_mutex); } return true; } bool _al_hide_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { HWND hwnd = al_get_win_window_handle(display); if (!hwnd) return false; /* Must be run from the main thread to avoid a crash. */ got_wm_size_event = false; PostMessage(al_get_win_window_handle(display), WM_HIDE_MENU, 0, (LPARAM) menu); /* Wait for the WM_SIZE event, otherwise the compensatory * al_resize_display (see menu.c) won't work right. */ if (wm_size_cond && global_mutex) { ALLEGRO_DEBUG("Sent WM_HIDE_MENU, waiting for WM_SIZE.\n"); al_lock_mutex(global_mutex); while (!got_wm_size_event) { al_wait_cond(wm_size_cond, global_mutex); } al_unlock_mutex(global_mutex); } (void) menu; return true; } bool _al_show_popup_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { /* The popup request must come from the main thread. */ if (!display) return false; al_win_add_window_callback(display, menu_callback, NULL); PostMessage(al_get_win_window_handle(display), WM_SHOW_POPUP, 0, (LPARAM) menu); return true; } int _al_get_menu_display_height(void) { return GetSystemMetrics(SM_CYMENU); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/physfs/000077500000000000000000000000001473414355200162445ustar00rootroot00000000000000allegro5-5.2.10.1/addons/physfs/CMakeLists.txt000066400000000000000000000012571473414355200210110ustar00rootroot00000000000000include_directories(SYSTEM ${PHYSFS_INCLUDE_DIR}) set(PHYSFS_SOURCES a5_physfs.c a5_physfs_dir.c) set(PHYSFS_INCLUDE_FILES allegro5/allegro_physfs.h) # This allows the monolith build to find the files. set(PHYSFS_INCLUDE_DIRECTORIES ${PHYSFS_INCLUDE_DIR}) set_our_header_properties(${PHYSFS_INCLUDE_FILES}) add_our_addon_library(allegro_physfs AllegroPhysfs-${ALLEGRO_SOVERSION} "${PHYSFS_SOURCES};${PHYSFS_INCLUDE_FILES}" "-DALLEGRO_PHYSFS_SRC" "${ALLEGRO_LINK_WITH};${PHYSFS_LIBRARIES}" ) install_our_headers(${PHYSFS_INCLUDE_FILES}) add_addon(physfs) #-----------------------------------------------------------------------------# # vi: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/addons/physfs/a5_physfs.c000066400000000000000000000136011473414355200203120ustar00rootroot00000000000000/* * PhysicsFS addon for Allegro. * * By Peter Wang. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_physfs.h" #include "allegro_physfs_intern.h" ALLEGRO_DEBUG_CHANNEL("physfs") typedef struct ALLEGRO_FILE_PHYSFS ALLEGRO_FILE_PHYSFS; struct ALLEGRO_FILE_PHYSFS { PHYSFS_file *phys; bool error_indicator; char error_msg[80]; }; /* forward declaration */ static const ALLEGRO_FILE_INTERFACE file_phys_vtable; const ALLEGRO_FILE_INTERFACE *_al_get_phys_vtable(void) { return &file_phys_vtable; } #define streq(a, b) (0 == strcmp(a, b)) static ALLEGRO_FILE_PHYSFS *cast_stream(ALLEGRO_FILE *f) { return (ALLEGRO_FILE_PHYSFS *)al_get_file_userdata(f); } static void phys_set_errno(ALLEGRO_FILE_PHYSFS *fp) { /* It might be worth mapping some common error strings from * PHYSFS_getLastError() onto errno values. There are no guarantees, * though. */ al_set_errno(-1); PHYSFS_ErrorCode error = PHYSFS_getLastErrorCode(); const char* msg = PHYSFS_getErrorByCode(error); if (error != PHYSFS_ERR_OK) { ALLEGRO_ERROR("PhysFS error code: %s\n", msg); } if (fp) { fp->error_indicator = true; if (error != PHYSFS_ERR_OK) { strncpy(fp->error_msg, msg, sizeof(fp->error_msg)); fp->error_msg[sizeof(fp->error_msg) - 1] = '\0'; } else { fp->error_msg[0] = '\0'; } } } static void *file_phys_fopen(const char *filename, const char *mode) { ALLEGRO_USTR *us; PHYSFS_file *phys; ALLEGRO_FILE_PHYSFS *fp; us = _al_physfs_process_path(filename); /* XXX handle '+' modes */ /* It might be worth adding a function to parse mode strings, to be * shared amongst these kinds of addons. */ if (streq(mode, "r") || streq(mode, "rb")) phys = PHYSFS_openRead(al_cstr(us)); else if (streq(mode, "w") || streq(mode, "wb")) phys = PHYSFS_openWrite(al_cstr(us)); else if (streq(mode, "a") || streq(mode, "ab")) phys = PHYSFS_openAppend(al_cstr(us)); else phys = NULL; al_ustr_free(us); if (!phys) { phys_set_errno(NULL); return NULL; } fp = al_malloc(sizeof(*fp)); if (!fp) { al_set_errno(ENOMEM); PHYSFS_close(phys); return NULL; } fp->phys = phys; fp->error_indicator = false; fp->error_msg[0] = '\0'; return fp; } static bool file_phys_fclose(ALLEGRO_FILE *f) { ALLEGRO_FILE_PHYSFS *fp = cast_stream(f); PHYSFS_file *phys_fp = fp->phys; al_free(fp); if (PHYSFS_close(phys_fp) == 0) { al_set_errno(-1); return false; } return true; } static size_t file_phys_fread(ALLEGRO_FILE *f, void *buf, size_t buf_size) { ALLEGRO_FILE_PHYSFS *fp = cast_stream(f); PHYSFS_sint64 n; if (buf_size == 0) return 0; n = PHYSFS_readBytes(fp->phys, buf, buf_size); if (n < 0) { phys_set_errno(fp); return 0; } return n; } static size_t file_phys_fwrite(ALLEGRO_FILE *f, const void *buf, size_t buf_size) { ALLEGRO_FILE_PHYSFS *fp = cast_stream(f); PHYSFS_sint64 n; n = PHYSFS_writeBytes(fp->phys, buf, buf_size); if (n < 0) { phys_set_errno(fp); return 0; } return n; } static bool file_phys_fflush(ALLEGRO_FILE *f) { ALLEGRO_FILE_PHYSFS *fp = cast_stream(f); if (!PHYSFS_flush(fp->phys)) { phys_set_errno(fp); return false; } return true; } static int64_t file_phys_ftell(ALLEGRO_FILE *f) { ALLEGRO_FILE_PHYSFS *fp = cast_stream(f); PHYSFS_sint64 n; n = PHYSFS_tell(fp->phys); if (n < 0) { phys_set_errno(fp); return -1; } return n; } static bool file_phys_seek(ALLEGRO_FILE *f, int64_t offset, int whence) { ALLEGRO_FILE_PHYSFS *fp = cast_stream(f); PHYSFS_sint64 base; switch (whence) { case ALLEGRO_SEEK_SET: base = 0; break; case ALLEGRO_SEEK_CUR: base = PHYSFS_tell(fp->phys); if (base < 0) { phys_set_errno(fp); return false; } break; case ALLEGRO_SEEK_END: base = PHYSFS_fileLength(fp->phys); if (base < 0) { phys_set_errno(fp); return false; } break; default: al_set_errno(EINVAL); return false; } if (!PHYSFS_seek(fp->phys, base + offset)) { phys_set_errno(fp); return false; } return true; } static bool file_phys_feof(ALLEGRO_FILE *f) { ALLEGRO_FILE_PHYSFS *fp = cast_stream(f); return PHYSFS_eof(fp->phys); } static int file_phys_ferror(ALLEGRO_FILE *f) { ALLEGRO_FILE_PHYSFS *fp = cast_stream(f); return (fp->error_indicator) ? 1 : 0; } static const char *file_phys_ferrmsg(ALLEGRO_FILE *f) { ALLEGRO_FILE_PHYSFS *fp = cast_stream(f); if (fp->error_indicator) return fp->error_msg; else return ""; } static void file_phys_fclearerr(ALLEGRO_FILE *f) { ALLEGRO_FILE_PHYSFS *fp = cast_stream(f); fp->error_indicator = false; /* PhysicsFS doesn't provide a way to clear the EOF indicator. */ } static off_t file_phys_fsize(ALLEGRO_FILE *f) { ALLEGRO_FILE_PHYSFS *fp = cast_stream(f); PHYSFS_sint64 n; n = PHYSFS_fileLength(fp->phys); if (n < 0) { phys_set_errno(fp); return -1; } return n; } static const ALLEGRO_FILE_INTERFACE file_phys_vtable = { file_phys_fopen, file_phys_fclose, file_phys_fread, file_phys_fwrite, file_phys_fflush, file_phys_ftell, file_phys_seek, file_phys_feof, file_phys_ferror, file_phys_ferrmsg, file_phys_fclearerr, NULL, /* ungetc */ file_phys_fsize }; /* Function: al_set_physfs_file_interface */ void al_set_physfs_file_interface(void) { al_set_new_file_interface(&file_phys_vtable); _al_set_physfs_fs_interface(); } /* Function: al_get_allegro_physfs_version */ uint32_t al_get_allegro_physfs_version(void) { return ALLEGRO_VERSION_INT; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/physfs/a5_physfs_dir.c000066400000000000000000000162111473414355200211500ustar00rootroot00000000000000/* * Filesystem driver for the PhysFS addon. * * By Elias Pschernig. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_physfs.h" #include "allegro_physfs_intern.h" #if defined(ENOTSUP) #define NOTSUP ENOTSUP #elif defined(ENOSYS) #define NOTSUP ENOSYS #else #define NOTSUP EINVAL #endif typedef struct ALLEGRO_FS_ENTRY_PHYSFS ALLEGRO_FS_ENTRY_PHYSFS; struct ALLEGRO_FS_ENTRY_PHYSFS { ALLEGRO_FS_ENTRY fs_entry; /* must be first */ ALLEGRO_PATH *path; const char *path_cstr; /* For directory listing. */ char **file_list; char **file_list_pos; bool is_dir_open; }; /* forward declaration */ static const ALLEGRO_FS_INTERFACE fs_phys_vtable; /* current working directory */ /* We cannot use ALLEGRO_USTR because we have nowhere to free it. */ static char fs_phys_cwd[1024] = "/"; static bool path_is_absolute(const char *path) { return (path && path[0] == '/'); } static void ensure_trailing_slash(ALLEGRO_USTR *us) { int pos = al_ustr_size(us); if (al_ustr_prev_get(us, &pos) != '/') { al_ustr_append_chr(us, '/'); } } ALLEGRO_USTR *_al_physfs_process_path(const char *path) { ALLEGRO_USTR *us; ALLEGRO_PATH *p = al_create_path(path); ALLEGRO_PATH *cwd = al_create_path(fs_phys_cwd); al_rebase_path(cwd, p); al_destroy_path(cwd); /* PHYSFS always uses / separator. */ us = al_ustr_dup(al_path_ustr(p, '/')); al_destroy_path(p); return us; } static ALLEGRO_FS_ENTRY *fs_phys_create_entry(const char *path) { ALLEGRO_FS_ENTRY_PHYSFS *e; ALLEGRO_USTR *us; e = al_calloc(1, sizeof *e); if (!e) return NULL; e->fs_entry.vtable = &fs_phys_vtable; us = _al_physfs_process_path(path); e->path = al_create_path(al_cstr(us)); al_ustr_free(us); if (!e->path) { al_free(e); return NULL; } e->path_cstr = al_path_cstr(e->path, '/'); return &e->fs_entry; } static char *fs_phys_get_current_directory(void) { size_t size = strlen(fs_phys_cwd) + 1; char *s = al_malloc(size); if (s) { memcpy(s, fs_phys_cwd, size); } return s; } static bool fs_phys_change_directory(const char *path) { ALLEGRO_USTR *us; bool ret; PHYSFS_Stat stat; /* '/' root is guaranteed to exist but PHYSFS won't find it. */ if (path[0] == '/' && path[1] == '\0') { fs_phys_cwd[0] = '/'; fs_phys_cwd[1] = '\0'; return true; } /* Figure out which directory we are trying to change to. */ if (path_is_absolute(path)) us = al_ustr_new(path); else us = _al_physfs_process_path(path); ret = false; if (!PHYSFS_stat(al_cstr(us), &stat)) return false; if (stat.filetype == PHYSFS_FILETYPE_DIRECTORY ) { ensure_trailing_slash(us); /* Copy to static buffer. */ if ((size_t) al_ustr_size(us) < sizeof(fs_phys_cwd)) { al_ustr_to_buffer(us, fs_phys_cwd, sizeof(fs_phys_cwd)); ret = true; } } al_ustr_free(us); return ret; } static bool fs_phys_filename_exists(const char *path) { ALLEGRO_USTR *us; bool ret; us = _al_physfs_process_path(path); ret = PHYSFS_exists(al_cstr(us)) ? true : false; al_ustr_free(us); return ret; } static bool fs_phys_remove_filename(const char *path) { ALLEGRO_USTR *us; bool ret; us = _al_physfs_process_path(path); ret = PHYSFS_delete(al_cstr(us)) ? true : false; al_ustr_free(us); return ret; } static bool fs_phys_make_directory(const char *path) { ALLEGRO_USTR *us; bool ret; us = _al_physfs_process_path(path); ret = PHYSFS_mkdir(al_cstr(us)) ? true : false; al_ustr_free(us); return ret; } static const char *fs_phys_entry_name(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_PHYSFS *e = (ALLEGRO_FS_ENTRY_PHYSFS *)fse; return al_path_cstr(e->path, '/'); } static bool fs_phys_update_entry(ALLEGRO_FS_ENTRY *fse) { (void)fse; return true; } static off_t fs_phys_entry_size(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_PHYSFS *e = (ALLEGRO_FS_ENTRY_PHYSFS *)fse; PHYSFS_file *f = PHYSFS_openRead(e->path_cstr); if (f) { off_t s = PHYSFS_fileLength(f); PHYSFS_close(f); return s; } return 0; } static uint32_t fs_phys_entry_mode(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_PHYSFS *e = (ALLEGRO_FS_ENTRY_PHYSFS *)fse; uint32_t mode = ALLEGRO_FILEMODE_READ; PHYSFS_Stat stat; if (!PHYSFS_stat(e->path_cstr, &stat)) return mode; if (stat.filetype == PHYSFS_FILETYPE_DIRECTORY ) mode |= ALLEGRO_FILEMODE_ISDIR | ALLEGRO_FILEMODE_EXECUTE; else mode |= ALLEGRO_FILEMODE_ISFILE; return mode; } static time_t fs_phys_entry_mtime(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_PHYSFS *e = (ALLEGRO_FS_ENTRY_PHYSFS *)fse; PHYSFS_Stat stat; if (!PHYSFS_stat(e->path_cstr, &stat)) return -1; return stat.modtime; } static bool fs_phys_entry_exists(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_PHYSFS *e = (ALLEGRO_FS_ENTRY_PHYSFS *)fse; return PHYSFS_exists(e->path_cstr) != 0; } static bool fs_phys_remove_entry(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_PHYSFS *e = (ALLEGRO_FS_ENTRY_PHYSFS *)fse; return PHYSFS_delete(e->path_cstr) != 0; } static bool fs_phys_open_directory(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_PHYSFS *e = (ALLEGRO_FS_ENTRY_PHYSFS *)fse; e->file_list = PHYSFS_enumerateFiles(e->path_cstr); e->file_list_pos = e->file_list; e->is_dir_open = true; return true; } static ALLEGRO_FS_ENTRY *fs_phys_read_directory(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_PHYSFS *e = (ALLEGRO_FS_ENTRY_PHYSFS *)fse; ALLEGRO_FS_ENTRY *next; ALLEGRO_USTR *tmp; if (!e->file_list_pos) return NULL; if (!*e->file_list_pos) return NULL; tmp = al_ustr_new(e->path_cstr); ensure_trailing_slash(tmp); al_ustr_append_cstr(tmp, *e->file_list_pos); next = fs_phys_create_entry(al_cstr(tmp)); al_ustr_free(tmp); e->file_list_pos++; return next; } static bool fs_phys_close_directory(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_PHYSFS *e = (ALLEGRO_FS_ENTRY_PHYSFS *)fse; PHYSFS_freeList(e->file_list); e->file_list = NULL; e->is_dir_open = false; return true; } static void fs_phys_destroy_entry(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_PHYSFS *e = (ALLEGRO_FS_ENTRY_PHYSFS *)fse; if (e->is_dir_open) fs_phys_close_directory(fse); al_destroy_path(e->path); al_free(e); } static ALLEGRO_FILE *fs_phys_open_file(ALLEGRO_FS_ENTRY *fse, const char *mode) { return al_fopen_interface(_al_get_phys_vtable(), fs_phys_entry_name(fse), mode); } static const ALLEGRO_FS_INTERFACE fs_phys_vtable = { fs_phys_create_entry, fs_phys_destroy_entry, fs_phys_entry_name, fs_phys_update_entry, fs_phys_entry_mode, fs_phys_entry_mtime, fs_phys_entry_mtime, fs_phys_entry_mtime, fs_phys_entry_size, fs_phys_entry_exists, fs_phys_remove_entry, fs_phys_open_directory, fs_phys_read_directory, fs_phys_close_directory, fs_phys_filename_exists, fs_phys_remove_filename, fs_phys_get_current_directory, fs_phys_change_directory, fs_phys_make_directory, fs_phys_open_file }; void _al_set_physfs_fs_interface(void) { al_set_fs_interface(&fs_phys_vtable); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/physfs/allegro5/000077500000000000000000000000001473414355200177565ustar00rootroot00000000000000allegro5-5.2.10.1/addons/physfs/allegro5/allegro_physfs.h000066400000000000000000000021151473414355200231470ustar00rootroot00000000000000#ifndef __al_included_allegro5_allegro_physfs_h #define __al_included_allegro5_allegro_physfs_h #include "allegro5/allegro.h" #ifdef __cplusplus extern "C" { #endif #if (defined ALLEGRO_MINGW32) || (defined ALLEGRO_MSVC) || (defined ALLEGRO_BCC32) #ifndef ALLEGRO_STATICLINK #ifdef ALLEGRO_PHYSFS_SRC #define _ALLEGRO_PHYSFS_DLL __declspec(dllexport) #else #define _ALLEGRO_PHYSFS_DLL __declspec(dllimport) #endif #else #define _ALLEGRO_PHYSFS_DLL #endif #endif #if defined ALLEGRO_MSVC #define ALLEGRO_PHYSFS_FUNC(type, name, args) _ALLEGRO_PHYSFS_DLL type __cdecl name args #elif defined ALLEGRO_MINGW32 #define ALLEGRO_PHYSFS_FUNC(type, name, args) extern type name args #elif defined ALLEGRO_BCC32 #define ALLEGRO_PHYSFS_FUNC(type, name, args) extern _ALLEGRO_PHYSFS_DLL type name args #else #define ALLEGRO_PHYSFS_FUNC AL_FUNC #endif ALLEGRO_PHYSFS_FUNC(void, al_set_physfs_file_interface, (void)); ALLEGRO_PHYSFS_FUNC(uint32_t, al_get_allegro_physfs_version, (void)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/physfs/allegro_physfs_intern.h000066400000000000000000000004211473414355200230120ustar00rootroot00000000000000#ifndef __al_included_allegro5_allegro_physfs_intern_h #define __al_included_allegro5_allegro_physfs_intern_h void _al_set_physfs_fs_interface(void); const ALLEGRO_FILE_INTERFACE *_al_get_phys_vtable(void); ALLEGRO_USTR *_al_physfs_process_path(const char *path); #endif allegro5-5.2.10.1/addons/primitives/000077500000000000000000000000001473414355200171235ustar00rootroot00000000000000allegro5-5.2.10.1/addons/primitives/CMakeLists.txt000066400000000000000000000016301473414355200216630ustar00rootroot00000000000000set(PRIMITIVES_SOURCES high_primitives.c line_soft.c point_soft.c polygon.c polyline.c prim_directx.cpp prim_opengl.c prim_soft.c prim_util.c primitives.c triangulator.c ) if(WIN32) # Add this file conditionally. # The Debian folks want to remove it because it contains precompiled code. list(APPEND PRIMITIVES_SOURCES directx_shaders.cpp) endif(WIN32) set(PRIMITIVES_INCLUDE_FILES allegro5/allegro_primitives.h) set_our_header_properties(${PRIMITIVES_INCLUDE_FILES}) add_our_addon_library(allegro_primitives AllegroPrimitives-${ALLEGRO_SOVERSION} "${PRIMITIVES_SOURCES};${PRIMITIVES_INCLUDE_FILES}" "-DALLEGRO_PRIMITIVES_SRC" "${ALLEGRO_LINK_WITH}" ) install_our_headers(${PRIMITIVES_INCLUDE_FILES}) add_addon(primitives) #-----------------------------------------------------------------------------# # vi: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/addons/primitives/allegro5/000077500000000000000000000000001473414355200206355ustar00rootroot00000000000000allegro5-5.2.10.1/addons/primitives/allegro5/allegro_primitives.h000066400000000000000000000241601473414355200247110ustar00rootroot00000000000000#ifndef __al_included_allegro5_allegro_primitives_h #define __al_included_allegro5_allegro_primitives_h #include #if (defined ALLEGRO_MINGW32) || (defined ALLEGRO_MSVC) || (defined ALLEGRO_BCC32) #ifndef ALLEGRO_STATICLINK #ifdef ALLEGRO_PRIMITIVES_SRC #define _ALLEGRO_PRIM_DLL __declspec(dllexport) #else #define _ALLEGRO_PRIM_DLL __declspec(dllimport) #endif #else #define _ALLEGRO_PRIM_DLL #endif #endif #if defined ALLEGRO_MSVC #define ALLEGRO_PRIM_FUNC(type, name, args) _ALLEGRO_PRIM_DLL type __cdecl name args #elif defined ALLEGRO_MINGW32 #define ALLEGRO_PRIM_FUNC(type, name, args) extern type name args #elif defined ALLEGRO_BCC32 #define ALLEGRO_PRIM_FUNC(type, name, args) extern _ALLEGRO_PRIM_DLL type name args #else #define ALLEGRO_PRIM_FUNC AL_FUNC #endif #ifdef __cplusplus extern "C" { #endif /* Enum: ALLEGRO_PRIM_TYPE */ typedef enum ALLEGRO_PRIM_TYPE { ALLEGRO_PRIM_LINE_LIST, ALLEGRO_PRIM_LINE_STRIP, ALLEGRO_PRIM_LINE_LOOP, ALLEGRO_PRIM_TRIANGLE_LIST, ALLEGRO_PRIM_TRIANGLE_STRIP, ALLEGRO_PRIM_TRIANGLE_FAN, ALLEGRO_PRIM_POINT_LIST, ALLEGRO_PRIM_NUM_TYPES } ALLEGRO_PRIM_TYPE; enum { ALLEGRO_PRIM_MAX_USER_ATTR = _ALLEGRO_PRIM_MAX_USER_ATTR }; /* Enum: ALLEGRO_PRIM_ATTR */ typedef enum ALLEGRO_PRIM_ATTR { ALLEGRO_PRIM_POSITION = 1, ALLEGRO_PRIM_COLOR_ATTR, ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_TEX_COORD_PIXEL, ALLEGRO_PRIM_USER_ATTR, ALLEGRO_PRIM_ATTR_NUM = ALLEGRO_PRIM_USER_ATTR + ALLEGRO_PRIM_MAX_USER_ATTR } ALLEGRO_PRIM_ATTR; /* Enum: ALLEGRO_PRIM_STORAGE */ typedef enum ALLEGRO_PRIM_STORAGE { ALLEGRO_PRIM_FLOAT_2, ALLEGRO_PRIM_FLOAT_3, ALLEGRO_PRIM_SHORT_2, ALLEGRO_PRIM_FLOAT_1, ALLEGRO_PRIM_FLOAT_4, ALLEGRO_PRIM_UBYTE_4, ALLEGRO_PRIM_SHORT_4, ALLEGRO_PRIM_NORMALIZED_UBYTE_4, ALLEGRO_PRIM_NORMALIZED_SHORT_2, ALLEGRO_PRIM_NORMALIZED_SHORT_4, ALLEGRO_PRIM_NORMALIZED_USHORT_2, ALLEGRO_PRIM_NORMALIZED_USHORT_4, ALLEGRO_PRIM_HALF_FLOAT_2, ALLEGRO_PRIM_HALF_FLOAT_4 } ALLEGRO_PRIM_STORAGE; /* Enum: ALLEGRO_LINE_JOIN */ typedef enum ALLEGRO_LINE_JOIN { ALLEGRO_LINE_JOIN_NONE, ALLEGRO_LINE_JOIN_BEVEL, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_JOIN_MITER, ALLEGRO_LINE_JOIN_MITRE = ALLEGRO_LINE_JOIN_MITER } ALLEGRO_LINE_JOIN; /* Enum: ALLEGRO_LINE_CAP */ typedef enum ALLEGRO_LINE_CAP { ALLEGRO_LINE_CAP_NONE, ALLEGRO_LINE_CAP_SQUARE, ALLEGRO_LINE_CAP_ROUND, ALLEGRO_LINE_CAP_TRIANGLE, ALLEGRO_LINE_CAP_CLOSED } ALLEGRO_LINE_CAP; /* Enum: ALLEGRO_PRIM_BUFFER_FLAGS */ typedef enum ALLEGRO_PRIM_BUFFER_FLAGS { ALLEGRO_PRIM_BUFFER_STREAM = 0x01, ALLEGRO_PRIM_BUFFER_STATIC = 0x02, ALLEGRO_PRIM_BUFFER_DYNAMIC = 0x04, ALLEGRO_PRIM_BUFFER_READWRITE = 0x08 } ALLEGRO_PRIM_BUFFER_FLAGS; /* Enum: ALLEGRO_VERTEX_CACHE_SIZE */ #define ALLEGRO_VERTEX_CACHE_SIZE 256 /* Enum: ALLEGRO_PRIM_QUALITY */ #define ALLEGRO_PRIM_QUALITY 10 /* Type: ALLEGRO_VERTEX_ELEMENT */ typedef struct ALLEGRO_VERTEX_ELEMENT ALLEGRO_VERTEX_ELEMENT; struct ALLEGRO_VERTEX_ELEMENT { int attribute; int storage; int offset; }; /* Type: ALLEGRO_VERTEX_DECL */ typedef struct ALLEGRO_VERTEX_DECL ALLEGRO_VERTEX_DECL; /* Duplicated in allegro5/internal/aintern_tri_soft.h */ #ifndef _ALLEGRO_VERTEX_DEFINED #define _ALLEGRO_VERTEX_DEFINED /* Type: ALLEGRO_VERTEX */ typedef struct ALLEGRO_VERTEX ALLEGRO_VERTEX; struct ALLEGRO_VERTEX { float x, y, z; float u, v; ALLEGRO_COLOR color; }; #endif /* Type: ALLEGRO_VERTEX_BUFFER */ typedef struct ALLEGRO_VERTEX_BUFFER ALLEGRO_VERTEX_BUFFER; /* Type: ALLEGRO_INDEX_BUFFER */ typedef struct ALLEGRO_INDEX_BUFFER ALLEGRO_INDEX_BUFFER; ALLEGRO_PRIM_FUNC(uint32_t, al_get_allegro_primitives_version, (void)); /* * Primary Functions */ ALLEGRO_PRIM_FUNC(bool, al_init_primitives_addon, (void)); ALLEGRO_PRIM_FUNC(bool, al_is_primitives_addon_initialized, (void)); ALLEGRO_PRIM_FUNC(void, al_shutdown_primitives_addon, (void)); ALLEGRO_PRIM_FUNC(int, al_draw_prim, (const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, ALLEGRO_BITMAP* texture, int start, int end, int type)); ALLEGRO_PRIM_FUNC(int, al_draw_indexed_prim, (const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, ALLEGRO_BITMAP* texture, const int* indices, int num_vtx, int type)); ALLEGRO_PRIM_FUNC(int, al_draw_vertex_buffer, (ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_BITMAP* texture, int start, int end, int type)); ALLEGRO_PRIM_FUNC(int, al_draw_indexed_buffer, (ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_BITMAP* texture, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type)); ALLEGRO_PRIM_FUNC(ALLEGRO_VERTEX_DECL*, al_create_vertex_decl, (const ALLEGRO_VERTEX_ELEMENT* elements, int stride)); ALLEGRO_PRIM_FUNC(void, al_destroy_vertex_decl, (ALLEGRO_VERTEX_DECL* decl)); /* * Vertex buffers */ ALLEGRO_PRIM_FUNC(ALLEGRO_VERTEX_BUFFER*, al_create_vertex_buffer, (ALLEGRO_VERTEX_DECL* decl, const void* initial_data, int num_vertices, int flags)); ALLEGRO_PRIM_FUNC(void, al_destroy_vertex_buffer, (ALLEGRO_VERTEX_BUFFER* buffer)); ALLEGRO_PRIM_FUNC(void*, al_lock_vertex_buffer, (ALLEGRO_VERTEX_BUFFER* buffer, int offset, int length, int flags)); ALLEGRO_PRIM_FUNC(void, al_unlock_vertex_buffer, (ALLEGRO_VERTEX_BUFFER* buffer)); ALLEGRO_PRIM_FUNC(int, al_get_vertex_buffer_size, (ALLEGRO_VERTEX_BUFFER* buffer)); /* * Index buffers */ ALLEGRO_PRIM_FUNC(ALLEGRO_INDEX_BUFFER*, al_create_index_buffer, (int index_size, const void* initial_data, int num_indices, int flags)); ALLEGRO_PRIM_FUNC(void, al_destroy_index_buffer, (ALLEGRO_INDEX_BUFFER* buffer)); ALLEGRO_PRIM_FUNC(void*, al_lock_index_buffer, (ALLEGRO_INDEX_BUFFER* buffer, int offset, int length, int flags)); ALLEGRO_PRIM_FUNC(void, al_unlock_index_buffer, (ALLEGRO_INDEX_BUFFER* buffer)); ALLEGRO_PRIM_FUNC(int, al_get_index_buffer_size, (ALLEGRO_INDEX_BUFFER* buffer)); /* * Utilities for high level primitives. */ ALLEGRO_PRIM_FUNC(bool, al_triangulate_polygon, (const float* vertices, size_t vertex_stride, const int* vertex_counts, void (*emit_triangle)(int, int, int, void*), void* userdata)); /* * Custom primitives */ ALLEGRO_PRIM_FUNC(void, al_draw_soft_triangle, (ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, ALLEGRO_VERTEX* v3, uintptr_t state, void (*init)(uintptr_t, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*), void (*first)(uintptr_t, int, int, int, int), void (*step)(uintptr_t, int), void (*draw)(uintptr_t, int, int, int))); ALLEGRO_PRIM_FUNC(void, al_draw_soft_line, (ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, uintptr_t state, void (*first)(uintptr_t, int, int, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*), void (*step)(uintptr_t, int), void (*draw)(uintptr_t, int, int))); /* *High level primitives */ ALLEGRO_PRIM_FUNC(void, al_draw_line, (float x1, float y1, float x2, float y2, ALLEGRO_COLOR color, float thickness)); ALLEGRO_PRIM_FUNC(void, al_draw_triangle, (float x1, float y1, float x2, float y2, float x3, float y3, ALLEGRO_COLOR color, float thickness)); ALLEGRO_PRIM_FUNC(void, al_draw_rectangle, (float x1, float y1, float x2, float y2, ALLEGRO_COLOR color, float thickness)); ALLEGRO_PRIM_FUNC(void, al_draw_rounded_rectangle, (float x1, float y1, float x2, float y2, float rx, float ry, ALLEGRO_COLOR color, float thickness)); ALLEGRO_PRIM_FUNC(void, al_calculate_arc, (float* dest, int stride, float cx, float cy, float rx, float ry, float start_theta, float delta_theta, float thickness, int num_points)); ALLEGRO_PRIM_FUNC(void, al_draw_circle, (float cx, float cy, float r, ALLEGRO_COLOR color, float thickness)); ALLEGRO_PRIM_FUNC(void, al_draw_ellipse, (float cx, float cy, float rx, float ry, ALLEGRO_COLOR color, float thickness)); ALLEGRO_PRIM_FUNC(void, al_draw_arc, (float cx, float cy, float r, float start_theta, float delta_theta, ALLEGRO_COLOR color, float thickness)); ALLEGRO_PRIM_FUNC(void, al_draw_elliptical_arc, (float cx, float cy, float rx, float ry, float start_theta, float delta_theta, ALLEGRO_COLOR color, float thickness)); ALLEGRO_PRIM_FUNC(void, al_draw_pieslice, (float cx, float cy, float r, float start_theta, float delta_theta, ALLEGRO_COLOR color, float thickness)); ALLEGRO_PRIM_FUNC(void, al_calculate_spline, (float* dest, int stride, const float points[8], float thickness, int num_segments)); ALLEGRO_PRIM_FUNC(void, al_draw_spline, (const float points[8], ALLEGRO_COLOR color, float thickness)); ALLEGRO_PRIM_FUNC(void, al_calculate_ribbon, (float* dest, int dest_stride, const float *points, int points_stride, float thickness, int num_segments)); ALLEGRO_PRIM_FUNC(void, al_draw_ribbon, (const float *points, int points_stride, ALLEGRO_COLOR color, float thickness, int num_segments)); ALLEGRO_PRIM_FUNC(void, al_draw_filled_triangle, (float x1, float y1, float x2, float y2, float x3, float y3, ALLEGRO_COLOR color)); ALLEGRO_PRIM_FUNC(void, al_draw_filled_rectangle, (float x1, float y1, float x2, float y2, ALLEGRO_COLOR color)); ALLEGRO_PRIM_FUNC(void, al_draw_filled_ellipse, (float cx, float cy, float rx, float ry, ALLEGRO_COLOR color)); ALLEGRO_PRIM_FUNC(void, al_draw_filled_circle, (float cx, float cy, float r, ALLEGRO_COLOR color)); ALLEGRO_PRIM_FUNC(void, al_draw_filled_pieslice, (float cx, float cy, float r, float start_theta, float delta_theta, ALLEGRO_COLOR color)); ALLEGRO_PRIM_FUNC(void, al_draw_filled_rounded_rectangle, (float x1, float y1, float x2, float y2, float rx, float ry, ALLEGRO_COLOR color)); ALLEGRO_PRIM_FUNC(void, al_draw_polyline, (const float* vertices, int vertex_stride, int vertex_count, int join_style, int cap_style, ALLEGRO_COLOR color, float thickness, float miter_limit)); ALLEGRO_PRIM_FUNC(void, al_draw_polygon, (const float* vertices, int vertex_count, int join_style, ALLEGRO_COLOR color, float thickness, float miter_limit)); ALLEGRO_PRIM_FUNC(void, al_draw_filled_polygon, (const float* vertices, int vertex_count, ALLEGRO_COLOR color)); ALLEGRO_PRIM_FUNC(void, al_draw_filled_polygon_with_holes, (const float* vertices, const int* vertex_counts, ALLEGRO_COLOR color)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/primitives/allegro5/internal/000077500000000000000000000000001473414355200224515ustar00rootroot00000000000000allegro5-5.2.10.1/addons/primitives/allegro5/internal/aintern_prim.h000066400000000000000000000047541473414355200253230ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_prim_h #define __al_included_allegro5_aintern_prim_h #ifdef __cplusplus extern "C" { #endif enum ALLEGRO_PRIM_VERTEX_CACHE_TYPE { ALLEGRO_PRIM_VERTEX_CACHE_TRIANGLE, ALLEGRO_PRIM_VERTEX_CACHE_LINE_STRIP }; struct ALLEGRO_VERTEX_DECL { ALLEGRO_VERTEX_ELEMENT* elements; int stride; void* d3d_decl; void* d3d_dummy_shader; }; typedef struct ALLEGRO_PRIM_VERTEX_CACHE { ALLEGRO_VERTEX buffer[ALLEGRO_VERTEX_CACHE_SIZE]; ALLEGRO_VERTEX* current; size_t size; ALLEGRO_COLOR color; int prim_type; void* user_data; } ALLEGRO_PRIM_VERTEX_CACHE; typedef struct ALLEGRO_BUFFER_COMMON { uintptr_t handle; bool write_only; /* In elements */ int size; bool is_locked; int lock_flags; void* locked_memory; /* These three are in bytes */ int local_buffer_length; int lock_offset; int lock_length; } ALLEGRO_BUFFER_COMMON; struct ALLEGRO_VERTEX_BUFFER { ALLEGRO_VERTEX_DECL* decl; ALLEGRO_BUFFER_COMMON common; }; struct ALLEGRO_INDEX_BUFFER { int index_size; ALLEGRO_BUFFER_COMMON common; }; /* Internal cache for primitives. */ void _al_prim_cache_init(ALLEGRO_PRIM_VERTEX_CACHE* cache, int prim_type, ALLEGRO_COLOR color); void _al_prim_cache_init_ex(ALLEGRO_PRIM_VERTEX_CACHE* cache, int prim_type, ALLEGRO_COLOR color, void* user_data); void _al_prim_cache_term(ALLEGRO_PRIM_VERTEX_CACHE* cache); void _al_prim_cache_flush(ALLEGRO_PRIM_VERTEX_CACHE* cache); void _al_prim_cache_push_point(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* v); void _al_prim_cache_push_triangle(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* v0, const float* v1, const float* v2); /* Internal functions. */ float _al_prim_get_scale(void); float _al_prim_normalize(float* vector); int _al_prim_test_line_side(const float* origin, const float* normal, const float* point); bool _al_prim_is_point_in_triangle(const float* point, const float* v0, const float* v1, const float* v2); bool _al_prim_intersect_segment(const float* v0, const float* v1, const float* p0, const float* p1, float* point, float* t0, float* t1); bool _al_prim_are_points_equal(const float* point_a, const float* point_b); int _al_bitmap_region_is_locked(ALLEGRO_BITMAP* bmp, int x1, int y1, int x2, int y2); int _al_draw_buffer_common_soft(ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_BITMAP* texture, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/primitives/allegro5/internal/aintern_prim_directx.h000066400000000000000000000037541473414355200270440ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_prim_directx_h #define __al_included_allegro5_aintern_prim_directx_h struct ALLEGRO_BITMAP; struct ALLEGRO_VERTEX; #ifdef __cplusplus extern "C" { #endif int _al_draw_prim_directx(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, int start, int end, int type); int _al_draw_prim_indexed_directx(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, const int* indices, int num_vtx, int type); void _al_set_d3d_decl(ALLEGRO_DISPLAY* display, ALLEGRO_VERTEX_DECL* ret); bool _al_create_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER* buf, const void* initial_data, size_t num_vertices, int flags); void _al_destroy_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER* buf); void* _al_lock_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER* buf); void _al_unlock_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER* buf); bool _al_create_index_buffer_directx(ALLEGRO_INDEX_BUFFER* buf, const void* initial_data, size_t num_indices, int flags); void _al_destroy_index_buffer_directx(ALLEGRO_INDEX_BUFFER* buf); void* _al_lock_index_buffer_directx(ALLEGRO_INDEX_BUFFER* buf); void _al_unlock_index_buffer_directx(ALLEGRO_INDEX_BUFFER* buf); int _al_draw_vertex_buffer_directx(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, int start, int end, int type); int _al_draw_indexed_buffer_directx(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type); bool _al_init_d3d_driver(void); void _al_shutdown_d3d_driver(void); void* _al_create_default_primitives_shader(void* dev); void _al_setup_default_primitives_shader(void* dev, void* shader); void _al_setup_primitives_shader(void* dev, const ALLEGRO_VERTEX_DECL* decl); void _al_create_primitives_shader(void* dev, ALLEGRO_VERTEX_DECL* decl); void _al_set_texture_matrix(void* dev, float* mat); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/primitives/allegro5/internal/aintern_prim_opengl.h000066400000000000000000000026231473414355200266600ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_prim_opengl_h #define __al_included_allegro5_aintern_prim_opengl_h int _al_draw_prim_opengl(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, int start, int end, int type); int _al_draw_prim_indexed_opengl(ALLEGRO_BITMAP *target, ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, const int* indices, int num_vtx, int type); bool _al_create_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER* buf, const void* initial_data, size_t num_vertices, int flags); void _al_destroy_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER* buf); void* _al_lock_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER* buf); void _al_unlock_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER* buf); bool _al_create_index_buffer_opengl(ALLEGRO_INDEX_BUFFER* buf, const void* initial_data, size_t num_indices, int flags); void _al_destroy_index_buffer_opengl(ALLEGRO_INDEX_BUFFER* buf); void* _al_lock_index_buffer_opengl(ALLEGRO_INDEX_BUFFER* buf); void _al_unlock_index_buffer_opengl(ALLEGRO_INDEX_BUFFER* buf); int _al_draw_vertex_buffer_opengl(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, int start, int end, int type); int _al_draw_indexed_buffer_opengl(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type); #endif allegro5-5.2.10.1/addons/primitives/allegro5/internal/aintern_prim_soft.h000066400000000000000000000013611473414355200263450ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_prim_soft_h #define __al_included_allegro5_aintern_prim_soft_h struct ALLEGRO_BITMAP; struct ALLEGRO_VERTEX; enum ALLEGRO_BITMAP_WRAP; #ifdef __cplusplus extern "C" { #endif int _al_fix_texcoord(float var, int max_var, ALLEGRO_BITMAP_WRAP wrap); int _al_draw_prim_soft(ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, int start, int end, int type); int _al_draw_prim_indexed_soft(ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, const int* indices, int num_vtx, int type); void _al_line_2d(ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2); void _al_point_2d(ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX* v); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/primitives/high_primitives.c000066400000000000000000001220131473414355200224600ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Some high level routines, provided for user's convinience. * * * By Pavel Sountsov. * * * Bezier spline plotter By Seymour Shlien. * * Optimised version by Sven Sandberg. * * I'm not sure wether or not we still use the Castelau Algorithm * described in the book :o) * * Interactive Computer Graphics * by Peter Burger and Duncan Gillies * Addison-Wesley Publishing Co 1989 * ISBN 0-201-17439-1 * * The 4 th order Bezier curve is a cubic curve passing * through the first and fourth point. The curve does * not pass through the middle two points. They are merely * guide points which control the shape of the curve. The * curve is tangent to the lines joining points 1 and 2 * and points 3 and 4. * * See readme.txt for copyright information. */ #define ALLEGRO_INTERNAL_UNSTABLE #include "allegro5/allegro_primitives.h" #ifdef ALLEGRO_CFG_OPENGL #include "allegro5/allegro_opengl.h" #endif #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/debug.h" #include ALLEGRO_DEBUG_CHANNEL("primitives") #ifdef ALLEGRO_MSVC #define hypotf(x, y) _hypotf((x), (y)) #endif #define LOCAL_VERTEX_CACHE ALLEGRO_VERTEX vertex_cache[ALLEGRO_VERTEX_CACHE_SIZE] /* * Make an estimate of the scale of the current transformation. * We do this by computing the determinants of the 2D section of the transformation matrix. */ static float get_scale(void) { #define DET2D(T) (fabs((T)->m[0][0] * (T)->m[1][1] - (T)->m[0][1] * (T)->m[1][0])) const ALLEGRO_TRANSFORM* t = al_get_current_transform(); float scale_sq = DET2D(t); ALLEGRO_BITMAP* b = al_get_target_bitmap(); if (b) { const ALLEGRO_TRANSFORM* p = al_get_current_projection_transform(); /* Divide by 4.0f as the screen coordinates range from -1 to 1 on both axes. */ scale_sq *= DET2D(p) * al_get_bitmap_width(b) * al_get_bitmap_height(b) / 4.0f; } return sqrtf(scale_sq); #undef DET2D } /* Function: al_draw_line */ void al_draw_line(float x1, float y1, float x2, float y2, ALLEGRO_COLOR color, float thickness) { if (thickness > 0) { int ii; float tx, ty; float len = hypotf(x2 - x1, y2 - y1); ALLEGRO_VERTEX vtx[4]; if (len == 0) return; tx = 0.5f * thickness * (y2 - y1) / len; ty = 0.5f * thickness * -(x2 - x1) / len; vtx[0].x = x1 + tx; vtx[0].y = y1 + ty; vtx[1].x = x1 - tx; vtx[1].y = y1 - ty; vtx[2].x = x2 - tx; vtx[2].y = y2 - ty; vtx[3].x = x2 + tx; vtx[3].y = y2 + ty; for (ii = 0; ii < 4; ii++) { vtx[ii].color = color; vtx[ii].z = 0; } al_draw_prim(vtx, 0, 0, 0, 4, ALLEGRO_PRIM_TRIANGLE_FAN); } else { ALLEGRO_VERTEX vtx[2]; vtx[0].x = x1; vtx[0].y = y1; vtx[1].x = x2; vtx[1].y = y2; vtx[0].color = color; vtx[1].color = color; vtx[0].z = 0; vtx[1].z = 0; al_draw_prim(vtx, 0, 0, 0, 2, ALLEGRO_PRIM_LINE_LIST); } } /* Function: al_draw_triangle */ void al_draw_triangle(float x1, float y1, float x2, float y2, float x3, float y3, ALLEGRO_COLOR color, float thickness) { if (thickness > 0) { int ii = 0; float side1, side2, side3; float perimeter, semi_perimeter; float outer_frac, inner_frac; float incenter_x, incenter_y; float incircle_rad; int idx = 0; ALLEGRO_VERTEX vtx[5]; float x[3] = {x1, x2, x3}; float y[3] = {y1, y2, y3}; ALLEGRO_VERTEX first_inner_vtx; ALLEGRO_VERTEX first_outer_vtx; ALLEGRO_VERTEX ini_vtx; float cross = (x[1] - x[0]) * (y[2] - y[0]) - (x[2] - x[0]) * (y[1] - y[0]); ini_vtx.x = ini_vtx.y = ini_vtx.z = ini_vtx.u = ini_vtx.v = 0; ini_vtx.color = color; first_inner_vtx = ini_vtx; first_outer_vtx = ini_vtx; /* * If the triangle is very flat, draw it as a line */ if(fabsf(cross) < 0.0001f) { float tx, ty, lx, ly; float len; /* * Find the obtuse vertex via two dot products */ float dot = (x[1] - x[0]) * (x[2] - x[0]) + (y[1] - y[0]) * (y[2] - y[0]); if(dot < 0) { x1 = x[1]; y1 = y[1]; x2 = x[2]; y2 = y[2]; } else { dot = (x[0] - x[1]) * (x[2] - x[1]) + (y[0] - y[1]) * (y[2] - y[1]); if(dot < 0) { x1 = x[0]; y1 = y[0]; x2 = x[2]; y2 = y[2]; } else { x1 = x[0]; y1 = y[0]; x2 = x[1]; y2 = y[1]; } } len = hypotf(x2 - x1, y2 - y1); if (len == 0) return; tx = 0.5f * thickness * (y2 - y1) / len; ty = 0.5f * thickness * -(x2 - x1) / len; lx = 0.5f * thickness * (x2 - x1) / len; ly = 0.5f * thickness * (y2 - y1) / len; vtx[0].x = x1 + tx - lx; vtx[0].y = y1 + ty - ly; vtx[1].x = x1 - tx - lx; vtx[1].y = y1 - ty - ly; vtx[2].x = x2 - tx + lx; vtx[2].y = y2 - ty + ly; vtx[3].x = x2 + tx + lx; vtx[3].y = y2 + ty + ly; for (ii = 0; ii < 4; ii++) { vtx[ii].color = color; vtx[ii].z = 0; } al_draw_prim(vtx, 0, 0, 0, 4, ALLEGRO_PRIM_TRIANGLE_FAN); return; } else if(cross > 0) { /* * Points need to be wound correctly for the algorithm to work */ float t; t = x[1]; x[1] = x[2]; x[2] = t; t = y[1]; y[1] = y[2]; y[2] = t; } side1 = hypotf(x[1] - x[0], y[1] - y[0]); side2 = hypotf(x[2] - x[0], y[2] - y[0]); side3 = hypotf(x[2] - x[1], y[2] - y[1]); perimeter = side1 + side2 + side3; semi_perimeter = perimeter / 2.0f; if (semi_perimeter < 0.00001f) return; incircle_rad = sqrtf((semi_perimeter - side1) * (semi_perimeter - side2) * (semi_perimeter - side3) / semi_perimeter); if (incircle_rad < 0.00001f) return; outer_frac = (incircle_rad + thickness / 2) / incircle_rad; inner_frac = (incircle_rad - thickness / 2) / incircle_rad; if(inner_frac < 0) inner_frac = 0; incenter_x = (side1 * x[2] + side2 * x[1] + side3 * x[0]) / perimeter; incenter_y = (side1 * y[2] + side2 * y[1] + side3 * y[0]) / perimeter; #define DRAW \ if(ii != 0) { \ vtx[idx++] = outer_vtx; \ vtx[idx++] = inner_vtx; \ \ al_draw_prim(vtx, 0, 0, 0, idx, ALLEGRO_PRIM_TRIANGLE_FAN); \ \ idx = 0; \ } /* * Iterate across the vertices, and draw each side of the triangle separately */ for(ii = 0; ii < 3; ii++) { float vert_x = x[ii] - incenter_x; float vert_y = y[ii] - incenter_y; float o_dx = vert_x * outer_frac; float o_dy = vert_y * outer_frac; float i_dx = vert_x * inner_frac; float i_dy = vert_y * inner_frac; float tdx = o_dx - i_dx; float tdy = o_dy - i_dy; ALLEGRO_VERTEX inner_vtx = ini_vtx; ALLEGRO_VERTEX outer_vtx = ini_vtx; if(tdx * tdx + tdy * tdy > 16 * thickness * thickness) { float x_pos = x[(ii + 1) % 3]; float y_pos = y[(ii + 1) % 3]; float x_neg = x[(ii + 2) % 3]; float y_neg = y[(ii + 2) % 3]; float x1_x2 = x[ii] - x_pos; float y1_y2 = y[ii] - y_pos; float x1_x3 = x[ii] - x_neg; float y1_y3 = y[ii] - y_neg; float mag_1_2 = hypotf(x1_x2, y1_y2); float mag_1_3 = hypotf(x1_x3, y1_y3); ALLEGRO_VERTEX next_vtx = ini_vtx; x1_x2 *= thickness / 2 / mag_1_2; y1_y2 *= thickness / 2 / mag_1_2; x1_x3 *= thickness / 2 / mag_1_3; y1_y3 *= thickness / 2 / mag_1_3; outer_vtx.x = x[ii] + x1_x3 - y1_y3; outer_vtx.y = y[ii] + y1_y3 + x1_x3; inner_vtx.x = incenter_x + i_dx; inner_vtx.y = incenter_y + i_dy; next_vtx.x = x[ii] + x1_x2 + y1_y2; next_vtx.y = y[ii] + y1_y2 - x1_x2; DRAW vtx[idx++] = inner_vtx; vtx[idx++] = outer_vtx; vtx[idx++] = next_vtx; } else { inner_vtx.x = incenter_x + i_dx; inner_vtx.y = incenter_y + i_dy; outer_vtx.x = incenter_x + o_dx; outer_vtx.y = incenter_y + o_dy; DRAW vtx[idx++] = inner_vtx; vtx[idx++] = outer_vtx; } if(ii == 0) { first_inner_vtx = inner_vtx; first_outer_vtx = outer_vtx; } } vtx[idx++] = first_outer_vtx; vtx[idx++] = first_inner_vtx; al_draw_prim(vtx, 0, 0, 0, idx, ALLEGRO_PRIM_TRIANGLE_FAN); #undef DRAW } else { ALLEGRO_VERTEX vtx[3]; vtx[0].x = x1; vtx[0].y = y1; vtx[1].x = x2; vtx[1].y = y2; vtx[2].x = x3; vtx[2].y = y3; vtx[0].color = color; vtx[1].color = color; vtx[2].color = color; vtx[0].z = 0; vtx[1].z = 0; vtx[2].z = 0; al_draw_prim(vtx, 0, 0, 0, 3, ALLEGRO_PRIM_LINE_LOOP); } } /* Function: al_draw_filled_triangle */ void al_draw_filled_triangle(float x1, float y1, float x2, float y2, float x3, float y3, ALLEGRO_COLOR color) { ALLEGRO_VERTEX vtx[3]; vtx[0].x = x1; vtx[0].y = y1; vtx[1].x = x2; vtx[1].y = y2; vtx[2].x = x3; vtx[2].y = y3; vtx[0].color = color; vtx[1].color = color; vtx[2].color = color; vtx[0].z = 0; vtx[1].z = 0; vtx[2].z = 0; al_draw_prim(vtx, 0, 0, 0, 3, ALLEGRO_PRIM_TRIANGLE_LIST); } /* Function: al_draw_rectangle */ void al_draw_rectangle(float x1, float y1, float x2, float y2, ALLEGRO_COLOR color, float thickness) { int ii; if (thickness > 0) { float t = thickness / 2; ALLEGRO_VERTEX vtx[10]; vtx[0].x = x1 - t; vtx[0].y = y1 - t; vtx[1].x = x1 + t; vtx[1].y = y1 + t; vtx[2].x = x2 + t; vtx[2].y = y1 - t; vtx[3].x = x2 - t; vtx[3].y = y1 + t; vtx[4].x = x2 + t; vtx[4].y = y2 + t; vtx[5].x = x2 - t; vtx[5].y = y2 - t; vtx[6].x = x1 - t; vtx[6].y = y2 + t; vtx[7].x = x1 + t; vtx[7].y = y2 - t; vtx[8].x = x1 - t; vtx[8].y = y1 - t; vtx[9].x = x1 + t; vtx[9].y = y1 + t; for (ii = 0; ii < 10; ii++) { vtx[ii].color = color; vtx[ii].z = 0; } al_draw_prim(vtx, 0, 0, 0, 10, ALLEGRO_PRIM_TRIANGLE_STRIP); } else { ALLEGRO_VERTEX vtx[4]; vtx[0].x = x1; vtx[0].y = y1; vtx[1].x = x2; vtx[1].y = y1; vtx[2].x = x2; vtx[2].y = y2; vtx[3].x = x1; vtx[3].y = y2; for (ii = 0; ii < 4; ii++) { vtx[ii].color = color; vtx[ii].z = 0; } al_draw_prim(vtx, 0, 0, 0, 4, ALLEGRO_PRIM_LINE_LOOP); } } /* Function: al_draw_filled_rectangle */ void al_draw_filled_rectangle(float x1, float y1, float x2, float y2, ALLEGRO_COLOR color) { ALLEGRO_VERTEX vtx[4]; int ii; vtx[0].x = x1; vtx[0].y = y1; vtx[1].x = x1; vtx[1].y = y2; vtx[2].x = x2; vtx[2].y = y2; vtx[3].x = x2; vtx[3].y = y1; for (ii = 0; ii < 4; ii++) { vtx[ii].color = color; vtx[ii].z = 0; } al_draw_prim(vtx, 0, 0, 0, 4, ALLEGRO_PRIM_TRIANGLE_FAN); } /* Function: al_calculate_arc */ void al_calculate_arc(float* dest, int stride, float cx, float cy, float rx, float ry, float start_theta, float delta_theta, float thickness, int num_points) { float theta; float c; float s; float x, y, t; int ii; ASSERT(dest); ASSERT(num_points > 1); ASSERT(rx >= 0); ASSERT(ry >= 0); if (thickness > 0.0f) { theta = delta_theta / ((float)(num_points) - 1); c = cosf(theta); s = sinf(theta); x = cosf(start_theta); y = sinf(start_theta); if (rx == ry) { /* The circle case is particularly simple */ float r1 = rx - thickness / 2.0f; float r2 = rx + thickness / 2.0f; for (ii = 0; ii < num_points; ii ++) { *dest = r2 * x + cx; *(dest + 1) = r2 * y + cy; dest = (float*)(((char*)dest) + stride); *dest = r1 * x + cx; *(dest + 1) = r1 * y + cy; dest = (float*)(((char*)dest) + stride); t = x; x = c * x - s * y; y = s * t + c * y; } } else { if (rx != 0 && ry != 0) { for (ii = 0; ii < num_points; ii++) { float denom = hypotf(ry * x, rx * y); float nx = thickness / 2 * ry * x / denom; float ny = thickness / 2 * rx * y / denom; *dest = rx * x + cx + nx; *(dest + 1) = ry * y + cy + ny; dest = (float*)(((char*)dest) + stride); *dest = rx * x + cx - nx; *(dest + 1) = ry * y + cy - ny; dest = (float*)(((char*)dest) + stride); t = x; x = c * x - s * y; y = s * t + c * y; } } } } else { theta = delta_theta / ((float)num_points - 1); c = cosf(theta); s = sinf(theta); x = cosf(start_theta); y = sinf(start_theta); for (ii = 0; ii < num_points; ii++) { *dest = rx * x + cx; *(dest + 1) = ry * y + cy; dest = (float*)(((char*)dest) + stride); t = x; x = c * x - s * y; y = s * t + c * y; } } } /* Function: al_draw_pieslice */ void al_draw_pieslice(float cx, float cy, float r, float start_theta, float delta_theta, ALLEGRO_COLOR color, float thickness) { LOCAL_VERTEX_CACHE; float scale = get_scale(); int num_segments, ii; ASSERT(r >= 0); /* Just makes things a bit easier */ if(delta_theta < 0) { delta_theta = -delta_theta; start_theta -= delta_theta; } if (thickness <= 0) { num_segments = fabs(delta_theta / (2 * ALLEGRO_PI) * ALLEGRO_PRIM_QUALITY * sqrtf(scale * r)); if (num_segments < 2) num_segments = 2; if (num_segments + 1 >= ALLEGRO_VERTEX_CACHE_SIZE) { num_segments = ALLEGRO_VERTEX_CACHE_SIZE - 1 - 1; } al_calculate_arc(&(vertex_cache[1].x), sizeof(ALLEGRO_VERTEX), cx, cy, r, r, start_theta, delta_theta, 0, num_segments); vertex_cache[0].x = cx; vertex_cache[0].y = cy; for (ii = 0; ii < num_segments + 1; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, num_segments + 1, ALLEGRO_PRIM_LINE_LOOP); } else { float ht = thickness / 2; float inner_side_angle = asinf(ht / (r - ht)); float outer_side_angle = asinf(ht / (r + ht)); float central_angle = delta_theta - 2 * inner_side_angle; bool inverted_winding = ((int)(delta_theta / ALLEGRO_PI)) % 2 == 1; float midangle = start_theta + (fmodf(delta_theta + ALLEGRO_PI, 2 * ALLEGRO_PI) - ALLEGRO_PI) / 2; float midpoint_dir_x = cosf(midangle); float midpoint_dir_y = sinf(midangle); float side_dir_x = cosf(start_theta); float side_dir_y = sinf(start_theta); float sine_half_delta = fabsf(side_dir_x * midpoint_dir_y - side_dir_y * midpoint_dir_x); /* Cross product */ float connect_len = ht / sine_half_delta; bool blunt_tip = connect_len > 2 * thickness; /* The angle is big enough for there to be a hole in the middle */ if (central_angle > 0) { float central_start_angle = start_theta + inner_side_angle; size_t vtx_id; int vtx_delta; /* Two inner hole vertices and the apex (2 vertices if the apex is blunt) */ int extra_vtx = blunt_tip ? 4 : 3; al_draw_arc(cx, cy, r, central_start_angle, central_angle, color, thickness); vertex_cache[0].x = cx + (r - thickness / 2) * cosf(central_start_angle); vertex_cache[0].y = cy + (r - thickness / 2) * sinf(central_start_angle); num_segments = (inner_side_angle + outer_side_angle) / (2 * ALLEGRO_PI) * ALLEGRO_PRIM_QUALITY * sqrtf(scale * (r + ht)); if (num_segments < 2) num_segments = 2; if (num_segments + extra_vtx >= ALLEGRO_VERTEX_CACHE_SIZE) num_segments = ALLEGRO_VERTEX_CACHE_SIZE - 1 - extra_vtx; al_calculate_arc(&(vertex_cache[1].x), sizeof(ALLEGRO_VERTEX), cx, cy, r + ht, r + ht, central_start_angle, -(outer_side_angle + inner_side_angle), 0, num_segments); /* Do the tip */ vtx_id = num_segments + 1 + (inverted_winding ? (1 + (blunt_tip ? 1 : 0)) : 0); vtx_delta = inverted_winding ? -1 : 1; if (blunt_tip) { float vx = ht * (side_dir_y * (inverted_winding ? -1 : 1) - side_dir_x); float vy = ht * (-side_dir_x * (inverted_winding ? -1 : 1) - side_dir_y); float dot = vx * midpoint_dir_x + vy * midpoint_dir_y; vertex_cache[vtx_id].x = cx + vx; vertex_cache[vtx_id].y = cy + vy; vtx_id += vtx_delta; vertex_cache[vtx_id].x = cx + dot * midpoint_dir_x; vertex_cache[vtx_id].y = cy + dot * midpoint_dir_y; } else { vertex_cache[vtx_id].x = cx - connect_len * midpoint_dir_x; vertex_cache[vtx_id].y = cy - connect_len * midpoint_dir_y; } vtx_id += vtx_delta; if(connect_len > r - ht) connect_len = r - ht; vertex_cache[vtx_id].x = cx + connect_len * midpoint_dir_x; vertex_cache[vtx_id].y = cy + connect_len * midpoint_dir_y; for (ii = 0; ii < num_segments + extra_vtx; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, num_segments + extra_vtx, ALLEGRO_PRIM_TRIANGLE_FAN); /* Mirror the vertices and draw them again */ for (ii = 0; ii < num_segments + extra_vtx; ii++) { float dot = (vertex_cache[ii].x - cx) * midpoint_dir_x + (vertex_cache[ii].y - cy) * midpoint_dir_y; vertex_cache[ii].x = 2 * cx + 2 * dot * midpoint_dir_x - vertex_cache[ii].x; vertex_cache[ii].y = 2 * cy + 2 * dot * midpoint_dir_y - vertex_cache[ii].y; } al_draw_prim(vertex_cache, 0, 0, 0, num_segments + extra_vtx, ALLEGRO_PRIM_TRIANGLE_FAN); } else { /* Apex: 2 vertices if the apex is blunt) */ int extra_vtx = blunt_tip ? 2 : 1; num_segments = (2 * outer_side_angle) / (2 * ALLEGRO_PI) * ALLEGRO_PRIM_QUALITY * sqrtf(scale * (r + ht)); if (num_segments < 2) num_segments = 2; if (num_segments + extra_vtx >= ALLEGRO_VERTEX_CACHE_SIZE) num_segments = ALLEGRO_VERTEX_CACHE_SIZE - 1 - extra_vtx; al_calculate_arc(&(vertex_cache[1].x), sizeof(ALLEGRO_VERTEX), cx, cy, r + ht, r + ht, start_theta - outer_side_angle, 2 * outer_side_angle + delta_theta, 0, num_segments); if (blunt_tip) { float vx = ht * (side_dir_y - side_dir_x); float vy = ht * (-side_dir_x - side_dir_y); float dot = vx * midpoint_dir_x + vy * midpoint_dir_y; vertex_cache[0].x = cx + vx; vertex_cache[0].y = cy + vy; vx = 2 * dot * midpoint_dir_x - vx; vy = 2 * dot * midpoint_dir_y - vy; vertex_cache[num_segments + 1].x = cx + vx; vertex_cache[num_segments + 1].y = cy + vy; } else { vertex_cache[0].x = cx - connect_len * midpoint_dir_x; vertex_cache[0].y = cy - connect_len * midpoint_dir_y; } for (ii = 0; ii < num_segments + extra_vtx; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, num_segments + extra_vtx, ALLEGRO_PRIM_TRIANGLE_FAN); } } } /* Function: al_draw_filled_pieslice */ void al_draw_filled_pieslice(float cx, float cy, float r, float start_theta, float delta_theta, ALLEGRO_COLOR color) { LOCAL_VERTEX_CACHE; float scale = get_scale(); int num_segments, ii; ASSERT(r >= 0); num_segments = fabs(delta_theta / (2 * ALLEGRO_PI) * ALLEGRO_PRIM_QUALITY * sqrtf(scale * r)); if (num_segments < 2) num_segments = 2; if (num_segments + 1 >= ALLEGRO_VERTEX_CACHE_SIZE) { num_segments = ALLEGRO_VERTEX_CACHE_SIZE - 1 - 1; } al_calculate_arc(&(vertex_cache[1].x), sizeof(ALLEGRO_VERTEX), cx, cy, r, r, start_theta, delta_theta, 0, num_segments); vertex_cache[0].x = cx; vertex_cache[0].y = cy; for (ii = 0; ii < num_segments + 1; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, num_segments + 1, ALLEGRO_PRIM_TRIANGLE_FAN); } /* Function: al_draw_ellipse */ void al_draw_ellipse(float cx, float cy, float rx, float ry, ALLEGRO_COLOR color, float thickness) { LOCAL_VERTEX_CACHE; float scale = get_scale(); ASSERT(rx >= 0); ASSERT(ry >= 0); if (thickness > 0) { int num_segments = ALLEGRO_PRIM_QUALITY * sqrtf(scale * (rx + ry) / 2.0f); int ii; /* In case rx and ry are both 0. */ if (num_segments < 2) return; if (2 * num_segments >= ALLEGRO_VERTEX_CACHE_SIZE) { num_segments = (ALLEGRO_VERTEX_CACHE_SIZE - 1) / 2; } al_calculate_arc(&(vertex_cache[0].x), sizeof(ALLEGRO_VERTEX), cx, cy, rx, ry, 0, ALLEGRO_PI * 2, thickness, num_segments); for (ii = 0; ii < 2 * num_segments; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, 2 * num_segments, ALLEGRO_PRIM_TRIANGLE_STRIP); } else { int num_segments = ALLEGRO_PRIM_QUALITY * sqrtf(scale * (rx + ry) / 2.0f); int ii; /* In case rx and ry are both 0. */ if (num_segments < 2) return; if (num_segments >= ALLEGRO_VERTEX_CACHE_SIZE) { num_segments = ALLEGRO_VERTEX_CACHE_SIZE - 1; } al_calculate_arc(&(vertex_cache[0].x), sizeof(ALLEGRO_VERTEX), cx, cy, rx, ry, 0, ALLEGRO_PI * 2, 0, num_segments); for (ii = 0; ii < num_segments; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, num_segments - 1, ALLEGRO_PRIM_LINE_LOOP); } } /* Function: al_draw_filled_ellipse */ void al_draw_filled_ellipse(float cx, float cy, float rx, float ry, ALLEGRO_COLOR color) { LOCAL_VERTEX_CACHE; int num_segments, ii; float scale = get_scale(); ASSERT(rx >= 0); ASSERT(ry >= 0); num_segments = ALLEGRO_PRIM_QUALITY * sqrtf(scale * (rx + ry) / 2.0f); /* In case rx and ry are both close to 0. If al_calculate_arc is passed * 0 or 1 it will assert. */ if (num_segments < 2) return; if (num_segments >= ALLEGRO_VERTEX_CACHE_SIZE) { num_segments = ALLEGRO_VERTEX_CACHE_SIZE - 1; } al_calculate_arc(&(vertex_cache[1].x), sizeof(ALLEGRO_VERTEX), cx, cy, rx, ry, 0, ALLEGRO_PI * 2, 0, num_segments); vertex_cache[0].x = cx; vertex_cache[0].y = cy; for (ii = 0; ii < num_segments + 1; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, num_segments + 1, ALLEGRO_PRIM_TRIANGLE_FAN); } /* Function: al_draw_circle */ void al_draw_circle(float cx, float cy, float r, ALLEGRO_COLOR color, float thickness) { al_draw_ellipse(cx, cy, r, r, color, thickness); } /* Function: al_draw_filled_circle */ void al_draw_filled_circle(float cx, float cy, float r, ALLEGRO_COLOR color) { al_draw_filled_ellipse(cx, cy, r, r, color); } /* Function: al_draw_elliptical_arc */ void al_draw_elliptical_arc(float cx, float cy, float rx, float ry, float start_theta, float delta_theta, ALLEGRO_COLOR color, float thickness) { LOCAL_VERTEX_CACHE; float scale = get_scale(); ASSERT(rx >= 0 && ry >= 0); if (thickness > 0) { int num_segments = fabs(delta_theta / (2 * ALLEGRO_PI) * ALLEGRO_PRIM_QUALITY * sqrtf(scale * (rx + ry) / 2.0f)); int ii; if (num_segments < 2) num_segments = 2; if (2 * num_segments >= ALLEGRO_VERTEX_CACHE_SIZE) { num_segments = (ALLEGRO_VERTEX_CACHE_SIZE - 1) / 2; } al_calculate_arc(&(vertex_cache[0].x), sizeof(ALLEGRO_VERTEX), cx, cy, rx, ry, start_theta, delta_theta, thickness, num_segments); for (ii = 0; ii < 2 * num_segments; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, 2 * num_segments, ALLEGRO_PRIM_TRIANGLE_STRIP); } else { int num_segments = fabs(delta_theta / (2 * ALLEGRO_PI) * ALLEGRO_PRIM_QUALITY * sqrtf(scale * (rx + ry) / 2.0f)); int ii; if (num_segments < 2) num_segments = 2; if (num_segments >= ALLEGRO_VERTEX_CACHE_SIZE) { num_segments = ALLEGRO_VERTEX_CACHE_SIZE - 1; } al_calculate_arc(&(vertex_cache[0].x), sizeof(ALLEGRO_VERTEX), cx, cy, rx, ry, start_theta, delta_theta, 0, num_segments); for (ii = 0; ii < num_segments; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, num_segments, ALLEGRO_PRIM_LINE_STRIP); } } /* Function: al_draw_arc */ void al_draw_arc(float cx, float cy, float r, float start_theta, float delta_theta, ALLEGRO_COLOR color, float thickness) { al_draw_elliptical_arc(cx, cy, r, r, start_theta, delta_theta, color, thickness); } /* Function: al_draw_rounded_rectangle */ void al_draw_rounded_rectangle(float x1, float y1, float x2, float y2, float rx, float ry, ALLEGRO_COLOR color, float thickness) { LOCAL_VERTEX_CACHE; float scale = get_scale(); ASSERT(rx >= 0); ASSERT(ry >= 0); if (thickness > 0) { int num_segments = ALLEGRO_PRIM_QUALITY * sqrtf(scale * (rx + ry) / 2.0f) / 4; int ii; /* In case rx and ry are both 0. */ if (num_segments < 2) { al_draw_rectangle(x1, y1, x2, y2, color, thickness); return; } if (8 * num_segments + 2 >= ALLEGRO_VERTEX_CACHE_SIZE) { num_segments = (ALLEGRO_VERTEX_CACHE_SIZE - 3) / 8; } al_calculate_arc(&(vertex_cache[0].x), sizeof(ALLEGRO_VERTEX), 0, 0, rx, ry, 0, ALLEGRO_PI / 2, thickness, num_segments); for (ii = 0; ii < 2 * num_segments; ii += 2) { vertex_cache[ii + 2 * num_segments + 1].x = x1 + rx - vertex_cache[2 * num_segments - 1 - ii].x; vertex_cache[ii + 2 * num_segments + 1].y = y1 + ry - vertex_cache[2 * num_segments - 1 - ii].y; vertex_cache[ii + 2 * num_segments].x = x1 + rx - vertex_cache[2 * num_segments - 1 - ii - 1].x; vertex_cache[ii + 2 * num_segments].y = y1 + ry - vertex_cache[2 * num_segments - 1 - ii - 1].y; vertex_cache[ii + 4 * num_segments].x = x1 + rx - vertex_cache[ii].x; vertex_cache[ii + 4 * num_segments].y = y2 - ry + vertex_cache[ii].y; vertex_cache[ii + 4 * num_segments + 1].x = x1 + rx - vertex_cache[ii + 1].x; vertex_cache[ii + 4 * num_segments + 1].y = y2 - ry + vertex_cache[ii + 1].y; vertex_cache[ii + 6 * num_segments + 1].x = x2 - rx + vertex_cache[2 * num_segments - 1 - ii].x; vertex_cache[ii + 6 * num_segments + 1].y = y2 - ry + vertex_cache[2 * num_segments - 1 - ii].y; vertex_cache[ii + 6 * num_segments].x = x2 - rx + vertex_cache[2 * num_segments - 1 - ii - 1].x; vertex_cache[ii + 6 * num_segments].y = y2 - ry + vertex_cache[2 * num_segments - 1 - ii - 1].y; } for (ii = 0; ii < 2 * num_segments; ii += 2) { vertex_cache[ii].x = x2 - rx + vertex_cache[ii].x; vertex_cache[ii].y = y1 + ry - vertex_cache[ii].y; vertex_cache[ii + 1].x = x2 - rx + vertex_cache[ii + 1].x; vertex_cache[ii + 1].y = y1 + ry - vertex_cache[ii + 1].y; } vertex_cache[8 * num_segments] = vertex_cache[0]; vertex_cache[8 * num_segments + 1] = vertex_cache[1]; for (ii = 0; ii < 8 * num_segments + 2; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, 8 * num_segments + 2, ALLEGRO_PRIM_TRIANGLE_STRIP); } else { int num_segments = ALLEGRO_PRIM_QUALITY * sqrtf(scale * (rx + ry) / 2.0f) / 4; int ii; /* In case rx and ry are both 0. */ if (num_segments < 2) { al_draw_rectangle(x1, y1, x2, y2, color, thickness); return; } if (num_segments * 4 >= ALLEGRO_VERTEX_CACHE_SIZE) { num_segments = (ALLEGRO_VERTEX_CACHE_SIZE - 1) / 4; } al_calculate_arc(&(vertex_cache[0].x), sizeof(ALLEGRO_VERTEX), 0, 0, rx, ry, 0, ALLEGRO_PI / 2, 0, num_segments + 1); for (ii = 0; ii < num_segments; ii++) { vertex_cache[ii + 1 * num_segments].x = x1 + rx - vertex_cache[num_segments - 1 - ii].x; vertex_cache[ii + 1 * num_segments].y = y1 + ry - vertex_cache[num_segments - 1 - ii].y; vertex_cache[ii + 2 * num_segments].x = x1 + rx - vertex_cache[ii].x; vertex_cache[ii + 2 * num_segments].y = y2 - ry + vertex_cache[ii].y; vertex_cache[ii + 3 * num_segments].x = x2 - rx + vertex_cache[num_segments - 1 - ii].x; vertex_cache[ii + 3 * num_segments].y = y2 - ry + vertex_cache[num_segments - 1 - ii].y; } for (ii = 0; ii < num_segments; ii++) { vertex_cache[ii].x = x2 - rx + vertex_cache[ii].x; vertex_cache[ii].y = y1 + ry - vertex_cache[ii].y; } for (ii = 0; ii < 4 * num_segments; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, 4 * num_segments, ALLEGRO_PRIM_LINE_LOOP); } } /* Function: al_draw_filled_rounded_rectangle */ void al_draw_filled_rounded_rectangle(float x1, float y1, float x2, float y2, float rx, float ry, ALLEGRO_COLOR color) { LOCAL_VERTEX_CACHE; int ii; float scale = get_scale(); int num_segments = ALLEGRO_PRIM_QUALITY * sqrtf(scale * (rx + ry) / 2.0f) / 4; ASSERT(rx >= 0); ASSERT(ry >= 0); /* In case rx and ry are both 0. */ if (num_segments < 2) { al_draw_filled_rectangle(x1, y1, x2, y2, color); return; } if (num_segments * 4 >= ALLEGRO_VERTEX_CACHE_SIZE) { num_segments = (ALLEGRO_VERTEX_CACHE_SIZE - 1) / 4; } al_calculate_arc(&(vertex_cache[0].x), sizeof(ALLEGRO_VERTEX), 0, 0, rx, ry, 0, ALLEGRO_PI / 2, 0, num_segments + 1); for (ii = 0; ii < num_segments; ii++) { vertex_cache[ii + 1 * num_segments].x = x1 + rx - vertex_cache[num_segments - 1 - ii].x; vertex_cache[ii + 1 * num_segments].y = y1 + ry - vertex_cache[num_segments - 1 - ii].y; vertex_cache[ii + 2 * num_segments].x = x1 + rx - vertex_cache[ii].x; vertex_cache[ii + 2 * num_segments].y = y2 - ry + vertex_cache[ii].y; vertex_cache[ii + 3 * num_segments].x = x2 - rx + vertex_cache[num_segments - 1 - ii].x; vertex_cache[ii + 3 * num_segments].y = y2 - ry + vertex_cache[num_segments - 1 - ii].y; } for (ii = 0; ii < num_segments; ii++) { vertex_cache[ii].x = x2 - rx + vertex_cache[ii].x; vertex_cache[ii].y = y1 + ry - vertex_cache[ii].y; } for (ii = 0; ii < 4 * num_segments; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } /* TODO: Doing this as a triangle fan just doesn't sound all that great, perhaps shuffle the vertices somehow to at least make it a strip */ al_draw_prim(vertex_cache, 0, 0, 0, 4 * num_segments, ALLEGRO_PRIM_TRIANGLE_FAN); } /* Function: al_calculate_spline */ void al_calculate_spline(float* dest, int stride, const float points[8], float thickness, int num_segments) { /* Derivatives of x(t) and y(t). */ float x, dx, ddx, dddx; float y, dy, ddy, dddy; int ii = 0; /* Temp variables used in the setup. */ float dt, dt2, dt3; float xdt2_term, xdt3_term; float ydt2_term, ydt3_term; /* This is enough to avoid malloc in ex_prim, which I take as a reasonable * guess to what a common number of segments might be. To be honest, it * probably makes no difference. */ float cache_point_buffer_storage[150]; float* cache_point_buffer = cache_point_buffer_storage; ASSERT(num_segments > 1); ASSERT(points); if (num_segments > (int)(sizeof(cache_point_buffer_storage) / sizeof(float) / 2)) { cache_point_buffer = al_malloc(2 * sizeof(float) * num_segments); } dt = 1.0 / (num_segments - 1); dt2 = (dt * dt); dt3 = (dt2 * dt); /* x coordinates. */ xdt2_term = 3 * (points[4] - 2 * points[2] + points[0]); xdt3_term = points[6] + 3 * (-points[4] + points[2]) - points[0]; xdt2_term = dt2 * xdt2_term; xdt3_term = dt3 * xdt3_term; dddx = 6 * xdt3_term; ddx = -6 * xdt3_term + 2 * xdt2_term; dx = xdt3_term - xdt2_term + 3 * dt * (points[2] - points[0]); x = points[0]; /* y coordinates. */ ydt2_term = 3 * (points[5] - 2 * points[3] + points[1]); ydt3_term = points[7] + 3 * (-points[5] + points[3]) - points[1]; ydt2_term = dt2 * ydt2_term; ydt3_term = dt3 * ydt3_term; dddy = 6 * ydt3_term; ddy = -6 * ydt3_term + 2 * ydt2_term; dy = ydt3_term - ydt2_term + dt * 3 * (points[3] - points[1]); y = points[1]; cache_point_buffer[2 * ii] = x; cache_point_buffer[2 * ii + 1] = y; for (ii = 1; ii < num_segments; ii++) { ddx += dddx; dx += ddx; x += dx; ddy += dddy; dy += ddy; y += dy; cache_point_buffer[2 * ii] = x; cache_point_buffer[2 * ii + 1] = y; } al_calculate_ribbon(dest, stride, cache_point_buffer, 2 * sizeof(float), thickness, num_segments); if (cache_point_buffer != cache_point_buffer_storage) { al_free(cache_point_buffer); } } /* Function: al_draw_spline */ void al_draw_spline(const float points[8], ALLEGRO_COLOR color, float thickness) { int ii; float scale = get_scale(); int num_segments = (int)(sqrtf(hypotf(points[2] - points[0], points[3] - points[1]) + hypotf(points[4] - points[2], points[5] - points[3]) + hypotf(points[6] - points[4], points[7] - points[5])) * 1.2 * ALLEGRO_PRIM_QUALITY * scale / 10); LOCAL_VERTEX_CACHE; if(num_segments < 2) num_segments = 2; if (thickness > 0) { if (2 * num_segments >= ALLEGRO_VERTEX_CACHE_SIZE) { num_segments = (ALLEGRO_VERTEX_CACHE_SIZE - 1) / 2; } al_calculate_spline(&(vertex_cache[0].x), sizeof(ALLEGRO_VERTEX), points, thickness, num_segments); for (ii = 0; ii < 2 * num_segments; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, 2 * num_segments, ALLEGRO_PRIM_TRIANGLE_STRIP); } else { if (num_segments >= ALLEGRO_VERTEX_CACHE_SIZE) { num_segments = ALLEGRO_VERTEX_CACHE_SIZE - 1; } al_calculate_spline(&(vertex_cache[0].x), sizeof(ALLEGRO_VERTEX), points, thickness, num_segments); for (ii = 0; ii < num_segments; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, num_segments, ALLEGRO_PRIM_LINE_STRIP); } } /* Function: al_calculate_ribbon */ void al_calculate_ribbon(float* dest, int dest_stride, const float *points, int points_stride, float thickness, int num_segments) { ASSERT(points); ASSERT(num_segments >= 2); if (thickness > 0) { int ii = 0; float x, y; float cur_dir_x; float cur_dir_y; float prev_dir_x = 0; float prev_dir_y = 0; float t = thickness / 2; float tx, ty; float nx, ny; float sign = 1; for (ii = 0; ii < 2 * num_segments - 2; ii += 2) { float dir_len; x = *points; y = *(points + 1); points = (float*)(((char*)points) + points_stride); cur_dir_x = *(points) - x; cur_dir_y = *(points + 1) - y; dir_len = hypotf(cur_dir_x, cur_dir_y); if(dir_len > 0.000001f) { cur_dir_x /= dir_len; cur_dir_y /= dir_len; } else if (ii == 0) { cur_dir_x = 1; cur_dir_y = 0; } else { cur_dir_x = prev_dir_x; cur_dir_y = prev_dir_y; } if (ii == 0) { tx = -t * cur_dir_y; ty = t * cur_dir_x; nx = 0; ny = 0; } else { float dot = cur_dir_x * prev_dir_x + cur_dir_y * prev_dir_y; float norm_len, cosine; if(dot < 0) { /* * This is by no means exact, but seems to produce acceptable results */ float tx_; tx = cur_dir_x - prev_dir_x; ty = cur_dir_y - prev_dir_y; norm_len = hypotf(tx, ty); tx /= norm_len; ty /= norm_len; cosine = tx * cur_dir_x + ty * cur_dir_y; nx = -t * tx / cosine; ny = -t * ty / cosine; tx_ = tx; tx = -t * ty * cosine; ty = t * tx_ * cosine; sign = -sign; } else { float new_norm_len; tx = cur_dir_y + prev_dir_y; ty = -(cur_dir_x + prev_dir_x); norm_len = hypotf(tx, ty); tx /= norm_len; ty /= norm_len; cosine = tx * (-cur_dir_y) + ty * (cur_dir_x); new_norm_len = t / cosine; tx *= new_norm_len; ty *= new_norm_len; nx = 0; ny = 0; } } *dest = x - sign * tx + nx; *(dest + 1) = y - sign * ty + ny; dest = (float*)(((char*)dest) + dest_stride); *dest = x + sign * tx + nx; *(dest + 1) = y + sign * ty + ny; dest = (float*)(((char*)dest) + dest_stride); prev_dir_x = cur_dir_x; prev_dir_y = cur_dir_y; } tx = -t * prev_dir_y; ty = t * prev_dir_x; x = *points; y = *(points + 1); *dest = x - sign * tx; *(dest + 1) = y - sign * ty; dest = (float*)(((char*)dest) + dest_stride); *dest = x + sign * tx; *(dest + 1) = y + sign * ty; } else { int ii; for (ii = 0; ii < num_segments; ii++) { *dest = *points; *(dest + 1) = *(points + 1); dest = (float*)(((char*)dest) + dest_stride); points = (float*)(((char*)points) + points_stride); } } } /* Function: al_draw_ribbon */ void al_draw_ribbon(const float *points, int points_stride, ALLEGRO_COLOR color, float thickness, int num_segments) { LOCAL_VERTEX_CACHE; int ii; if (num_segments * (thickness > 0 ? 2 : 1) > ALLEGRO_VERTEX_CACHE_SIZE) { ALLEGRO_ERROR("Ribbon has too many segments.\n"); return; } al_calculate_ribbon(&(vertex_cache[0].x), sizeof(ALLEGRO_VERTEX), points, points_stride, thickness, num_segments); if (thickness > 0) { for (ii = 0; ii < 2 * num_segments; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, 2 * num_segments, ALLEGRO_PRIM_TRIANGLE_STRIP); } else { for (ii = 0; ii < num_segments; ii++) { vertex_cache[ii].color = color; vertex_cache[ii].z = 0; } al_draw_prim(vertex_cache, 0, 0, 0, num_segments, ALLEGRO_PRIM_LINE_STRIP); } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/primitives/line_soft.c000066400000000000000000000472021473414355200212560ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Software line implementation functions. * * * By Pavel Sountsov. * * See readme.txt for copyright information. */ #define ALLEGRO_INTERNAL_UNSTABLE #define _AL_NO_BLEND_INLINE_FUNC #include "allegro5/allegro.h" #include "allegro5/allegro_primitives.h" #include "allegro5/internal/aintern_blend.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_pixels.h" #include "allegro5/internal/aintern_prim.h" #include "allegro5/internal/aintern_prim_soft.h" #include /* Nomenclature shader_{texture}_{grad,solid}_{any,rgb888,rgba8888,etc}_{draw_{shade,opaque},step,first} */ typedef void (*shader_draw)(uintptr_t, int, int); typedef void (*shader_first)(uintptr_t, int, int, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*); typedef void (*shader_step)(uintptr_t, int); typedef struct { ALLEGRO_COLOR color; } state_solid_any_2d; static void shader_solid_any_draw_shade(uintptr_t state, int x, int y) { state_solid_any_2d* s = (state_solid_any_2d*)state; al_put_blended_pixel(x, y, s->color); } static void shader_solid_any_draw_opaque(uintptr_t state, int x, int y) { state_solid_any_2d* s = (state_solid_any_2d*)state; al_put_pixel(x, y, s->color); } static void shader_solid_any_first(uintptr_t state, int start_x, int start_y, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2) { state_solid_any_2d* s = (state_solid_any_2d*)state; s->color = v1->color; (void)start_x; (void)start_y; (void)v2; } static void shader_solid_any_step(uintptr_t state, int minor_step) { (void)state; (void)minor_step; } /*----------------------------------------------------*/ typedef struct { state_solid_any_2d solid; ALLEGRO_COLOR minor_color; ALLEGRO_COLOR major_color; } state_grad_any_2d; static void get_interpolation_parameters(int start_x, int start_y, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, float* param, float* minor_delta_param, float* major_delta_param) { float dx = v2->x - v1->x; float dy = v2->y - v1->y; float lensq = dx * dx + dy * dy; if (lensq == 0) { lensq = 0.0001f; *param = 0; } else { *param = ((float)start_x - v1->x) * dx + ((float)start_y - v1->y) * dy; *param /= lensq; } dx = fabsf(dx); dy = fabsf(dy); if (dx > dy) *minor_delta_param = dx / lensq; else *minor_delta_param = dy / lensq; *major_delta_param = (dx + dy) / lensq; } static void shader_grad_any_first(uintptr_t state, int start_x, int start_y, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2) { float param; float minor_delta_param; float major_delta_param; state_grad_any_2d* st = (state_grad_any_2d*)state; ALLEGRO_COLOR diff, v1c, v2c; v1c = v1->color; v2c = v2->color; get_interpolation_parameters(start_x, start_y, v1, v2, ¶m, &minor_delta_param, &major_delta_param); diff.a = v2c.a - v1c.a; diff.r = v2c.r - v1c.r; diff.g = v2c.g - v1c.g; diff.b = v2c.b - v1c.b; st->solid.color.a = v1c.a + diff.a * param; st->solid.color.r = v1c.r + diff.r * param; st->solid.color.g = v1c.g + diff.g * param; st->solid.color.b = v1c.b + diff.b * param; st->minor_color.a = diff.a * minor_delta_param; st->minor_color.r = diff.r * minor_delta_param; st->minor_color.g = diff.g * minor_delta_param; st->minor_color.b = diff.b * minor_delta_param; st->major_color.a = diff.a * major_delta_param; st->major_color.r = diff.r * major_delta_param; st->major_color.g = diff.g * major_delta_param; st->major_color.b = diff.b * major_delta_param; } static void shader_grad_any_step(uintptr_t state, int minor_step) { state_grad_any_2d* s = (state_grad_any_2d*)state; if (minor_step) { s->solid.color.a += s->minor_color.a; s->solid.color.r += s->minor_color.r; s->solid.color.g += s->minor_color.g; s->solid.color.b += s->minor_color.b; } else { s->solid.color.a += s->major_color.a; s->solid.color.r += s->major_color.r; s->solid.color.g += s->major_color.g; s->solid.color.b += s->major_color.b; } } /*===================== Texture Shaders =======================*/ #define SHADE_COLORS(A, B) \ A.r = B.r * A.r; \ A.g = B.g * A.g; \ A.b = B.b * A.b; \ A.a = B.a * A.a; typedef struct { ALLEGRO_COLOR color; ALLEGRO_BITMAP* texture; int w, h; float u, v; float minor_du; float minor_dv; float major_du; float major_dv; } state_texture_solid_any_2d; static void get_texcoords(state_texture_solid_any_2d *s, int *u, int *v) { ALLEGRO_BITMAP_WRAP wrap_u, wrap_v; _al_get_bitmap_wrap(s->texture, &wrap_u, &wrap_v); *u = _al_fix_texcoord(s->u, s->w, wrap_u); *v = _al_fix_texcoord(s->v, s->h, wrap_v); } #define GET_UV int u, v; get_texcoords((state_texture_solid_any_2d*)s, &u, &v); static void shader_texture_solid_any_draw_shade(uintptr_t state, int x, int y) { state_texture_solid_any_2d* s = (state_texture_solid_any_2d*)state; GET_UV ALLEGRO_COLOR color = al_get_pixel(s->texture, u, v); SHADE_COLORS(color, s->color) al_put_blended_pixel(x, y, color); } static void shader_texture_solid_any_draw_shade_white(uintptr_t state, int x, int y) { state_texture_solid_any_2d* s = (state_texture_solid_any_2d*)state; GET_UV al_put_blended_pixel(x, y, al_get_pixel(s->texture, u, v)); } static void shader_texture_solid_any_draw_opaque(uintptr_t state, int x, int y) { state_texture_solid_any_2d* s = (state_texture_solid_any_2d*)state; GET_UV ALLEGRO_COLOR color = al_get_pixel(s->texture, u, v); SHADE_COLORS(color, s->color) al_put_pixel(x, y, color); } static void shader_texture_solid_any_draw_opaque_white(uintptr_t state, int x, int y) { state_texture_solid_any_2d* s = (state_texture_solid_any_2d*)state; GET_UV al_put_pixel(x, y, al_get_pixel(s->texture, u, v)); } static void shader_texture_solid_any_first(uintptr_t state, int start_x, int start_y, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2) { float param; float minor_delta_param; float major_delta_param; state_texture_solid_any_2d* st = (state_texture_solid_any_2d*)state; float du, dv; ALLEGRO_COLOR v1c; v1c = v1->color; get_interpolation_parameters(start_x, start_y, v1, v2, ¶m, &minor_delta_param, &major_delta_param); st->w = al_get_bitmap_width(st->texture); st->h = al_get_bitmap_height(st->texture); du = v2->u - v1->u; dv = v2->v - v1->v; st->color.r = v1c.r; st->color.g = v1c.g; st->color.b = v1c.b; st->color.a = v1c.a; st->u = v1->u + du * param; st->v = v1->v + dv * param; st->minor_du = du * minor_delta_param; st->minor_dv = dv * minor_delta_param; st->major_du = du * major_delta_param; st->major_dv = dv * major_delta_param; } static void shader_texture_solid_any_step(uintptr_t state, int minor_step) { state_texture_solid_any_2d* s = (state_texture_solid_any_2d*)state; if (minor_step) { s->u += s->minor_du; s->v += s->minor_dv; } else { s->u += s->major_du; s->v += s->major_dv; } } /*----------------------------------------------------*/ typedef struct { state_texture_solid_any_2d solid; ALLEGRO_COLOR minor_color; ALLEGRO_COLOR major_color; } state_texture_grad_any_2d; static void shader_texture_grad_any_first(uintptr_t state, int start_x, int start_y, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2) { float param; float minor_delta_param; float major_delta_param; state_texture_grad_any_2d* st = (state_texture_grad_any_2d*)state; float du, dv; ALLEGRO_COLOR diff, v1c, v2c; v1c = v1->color; v2c = v2->color; get_interpolation_parameters(start_x, start_y, v1, v2, ¶m, &minor_delta_param, &major_delta_param); st->solid.w = al_get_bitmap_width(st->solid.texture); st->solid.h = al_get_bitmap_height(st->solid.texture); du = v2->u - v1->u; dv = v2->v - v1->v; st->solid.color.r = v1c.r; st->solid.color.g = v1c.g; st->solid.color.b = v1c.b; st->solid.color.a = v1c.a; st->solid.u = v1->u + du * param; st->solid.v = v1->v + dv * param; st->solid.minor_du = du * minor_delta_param; st->solid.minor_dv = dv * minor_delta_param; st->solid.major_du = du * major_delta_param; st->solid.major_dv = dv * major_delta_param; diff.a = v2c.a - v1c.a; diff.r = v2c.r - v1c.r; diff.g = v2c.g - v1c.g; diff.b = v2c.b - v1c.b; st->solid.color.a = v1c.a + diff.a * param; st->solid.color.r = v1c.r + diff.r * param; st->solid.color.g = v1c.g + diff.g * param; st->solid.color.b = v1c.b + diff.b * param; st->minor_color.a = diff.a * minor_delta_param; st->minor_color.r = diff.r * minor_delta_param; st->minor_color.g = diff.g * minor_delta_param; st->minor_color.b = diff.b * minor_delta_param; st->major_color.a = diff.a * major_delta_param; st->major_color.r = diff.r * major_delta_param; st->major_color.g = diff.g * major_delta_param; st->major_color.b = diff.b * major_delta_param; } static void shader_texture_grad_any_step(uintptr_t state, int minor_step) { state_texture_grad_any_2d* s = (state_texture_grad_any_2d*)state; shader_texture_solid_any_step(state, minor_step); if (minor_step) { s->solid.color.a += s->minor_color.a; s->solid.color.r += s->minor_color.r; s->solid.color.g += s->minor_color.g; s->solid.color.b += s->minor_color.b; } else { s->solid.color.a += s->major_color.a; s->solid.color.r += s->major_color.r; s->solid.color.g += s->major_color.g; s->solid.color.b += s->major_color.b; } } static void line_stepper(uintptr_t state, shader_first first, shader_step step, shader_draw draw, ALLEGRO_VERTEX* vtx1, ALLEGRO_VERTEX* vtx2) { float x1, y1, x2, y2; float dx, dy; int end_x, end_y; if (vtx2->y < vtx1->y) { ALLEGRO_VERTEX* t; t = vtx1; vtx1 = vtx2; vtx2 = t; } vtx1->x -= 0.5001f; vtx1->y -= 0.5001f; vtx2->x -= 0.5001f; vtx2->y -= 0.5001f; x1 = vtx1->x; y1 = vtx1->y; x2 = vtx2->x; y2 = vtx2->y; dx = x2 - x1; dy = y2 - y1; end_x = floorf(x2 + 0.5f); end_y = floorf(y2 + 0.5f); #define FIRST \ first(state, x, y, vtx1, vtx2); \ if((x2 - x1) * ((float)x - x1) + (y2 - y1) * ((float)y - y1) >= 0) \ draw(state, x, y); \ (void)minor; #define STEP \ step(state, minor); \ draw(state, x, y); #define LAST \ step(state, minor); \ if((x1 - x2) * ((float)x - x2) + (y1 - y2) * ((float)y - y2) > 0) \ draw(state, x, y); #define WORKER(var1, var2, comp, dvar1, dvar2, derr1, derr2, func) \ { \ int minor = 1; \ if(err comp) \ { \ var1 += dvar1; \ err += derr1; \ minor = 0; \ } \ \ func \ \ var2 += dvar2; \ err += derr2; \ } if (dx > 0) { if (dx > dy) { int x = floorf(x1 + 0.5f); int y = floorf(y1); float err = (y1 - (float)y) * dx - (x1 - (float)x) * dy; if (x < end_x) { WORKER(y, x, > 0.5f * dx, 1, 1, -dx, dy, FIRST) } while (x < end_x) { WORKER(y, x, > 0.5f * dx, 1, 1, -dx, dy, STEP) } if (x <= end_x) { WORKER(y, x, > 0.5f * dx, 1, 1, -dx, dy, LAST) } } else { int x = floorf(x1); int y = floorf(y1 + 0.5f); float err = (x1 - (float)x) * dy - (y1 - (float)y) * dx; if (y < end_y) { WORKER(x, y, > 0.5f * dy, 1, 1, -dy, dx, FIRST) } while (y < end_y) { WORKER(x, y, > 0.5f * dy, 1, 1, -dy, dx, STEP) } if (y <= end_y) { WORKER(x, y, > 0.5f * dy, 1, 1, -dy, dx, LAST) } } } else { if (-dx > dy) { int x = floorf(x1 + 0.5f); int y = floorf(y1); float err = (y1 - (float)y) * dx - (x1 - (float)x) * dy; if (x > end_x) { WORKER(y, x, <= 0.5f * dx, 1, -1, -dx, -dy, FIRST) } while (x > end_x) { WORKER(y, x, <= 0.5f * dx, 1, -1, -dx, -dy, STEP) } if (x >= end_x) { WORKER(y, x, <= 0.5f * dx, 1, -1, -dx, -dy, LAST) } } else { int x = floorf(x1); int y = floorf(y1 + 0.5f); float err = (x1 - (float)x) * dy - (y1 - (float)y) * dx; /* This is the only correction that needs to be made in the opposite direction of dy (or dx) */ if (err > 0.5f * dy) { x += 1; err -= dy; } if (y < end_y) { WORKER(x, y, <= -0.5f * dy, -1, 1, dy, dx, FIRST) } while (y < end_y) { WORKER(x, y, <= -0.5f * dy, -1, 1, dy, dx, STEP) } if (y <= end_y) { WORKER(x, y, <= -0.5f * dy, -1, 1, dy, dx, LAST) } } } #undef FIRST #undef LAST #undef STEP #undef WORKER } /* This one will check to see what exactly we need to draw... I.e. this will call all of the actual renderers and set the appropriate callbacks */ void _al_line_2d(ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2) { int shade = 1; int grad = 1; int op, src_mode, dst_mode, op_alpha, src_alpha, dst_alpha; ALLEGRO_COLOR v1c, v2c; v1c = v1->color; v2c = v2->color; al_get_separate_blender(&op, &src_mode, &dst_mode, &op_alpha, &src_alpha, &dst_alpha); if (_AL_DEST_IS_ZERO && _AL_SRC_NOT_MODIFIED) { shade = 0; } if (v1c.r == v2c.r && v1c.g == v2c.g && v1c.b == v2c.b && v1c.a == v2c.a) { grad = 0; } if (texture) { if (grad) { state_texture_grad_any_2d state; state.solid.texture = texture; if (shade) { al_draw_soft_line(v1, v2, (uintptr_t)&state, shader_texture_grad_any_first, shader_texture_grad_any_step, shader_texture_solid_any_draw_shade); } else { al_draw_soft_line(v1, v2, (uintptr_t)&state, shader_texture_grad_any_first, shader_texture_grad_any_step, shader_texture_solid_any_draw_opaque); } } else { int white = 0; state_texture_solid_any_2d state; if (v1c.r == 1 && v1c.g == 1 && v1c.b == 1 && v1c.a == 1) { white = 1; } state.texture = texture; if (shade) { if(white) { al_draw_soft_line(v1, v2, (uintptr_t)&state, shader_texture_solid_any_first, shader_texture_solid_any_step, shader_texture_solid_any_draw_shade_white); } else { al_draw_soft_line(v1, v2, (uintptr_t)&state, shader_texture_solid_any_first, shader_texture_solid_any_step, shader_texture_solid_any_draw_shade); } } else { if(white) { al_draw_soft_line(v1, v2, (uintptr_t)&state, shader_texture_solid_any_first, shader_texture_solid_any_step, shader_texture_solid_any_draw_opaque_white); } else { al_draw_soft_line(v1, v2, (uintptr_t)&state, shader_texture_solid_any_first, shader_texture_solid_any_step, shader_texture_solid_any_draw_opaque); } } } } else { if (grad) { state_grad_any_2d state; if (shade) { al_draw_soft_line(v1, v2, (uintptr_t)&state, shader_grad_any_first, shader_grad_any_step, shader_solid_any_draw_shade); } else { al_draw_soft_line(v1, v2, (uintptr_t)&state, shader_grad_any_first, shader_grad_any_step, shader_solid_any_draw_opaque); } } else { state_solid_any_2d state; if (shade) { al_draw_soft_line(v1, v2, (uintptr_t)&state, shader_solid_any_first, shader_solid_any_step, shader_solid_any_draw_shade); } else { al_draw_soft_line(v1, v2, (uintptr_t)&state, shader_solid_any_first, shader_solid_any_step, shader_solid_any_draw_opaque); } } } } /* Function: al_draw_soft_line */ void al_draw_soft_line(ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, uintptr_t state, void (*first)(uintptr_t, int, int, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*), void (*step)(uintptr_t, int), void (*draw)(uintptr_t, int, int)) { /* Copy the vertices, because we need to alter them a bit before drawing. */ ALLEGRO_VERTEX vtx1 = *v1; ALLEGRO_VERTEX vtx2 = *v2; ALLEGRO_BITMAP *target = al_get_target_bitmap(); int need_unlock = 0; ALLEGRO_LOCKED_REGION *lr; int min_x, max_x, min_y, max_y; int clip_min_x, clip_min_y, clip_max_x, clip_max_y; al_get_clipping_rectangle(&clip_min_x, &clip_min_y, &clip_max_x, &clip_max_y); clip_max_x += clip_min_x; clip_max_y += clip_min_y; /* TODO: Need to clip them first, make a copy of the vertices first then */ /* Lock the region we are drawing to. We are choosing the minimum and maximum possible pixels touched from the formula (easily verified by following the above algorithm). */ if (vtx1.x >= vtx2.x) { max_x = (int)ceilf(vtx1.x) + 1; min_x = (int)floorf(vtx2.x) - 1; } else { max_x = (int)ceilf(vtx2.x) + 1; min_x = (int)floorf(vtx1.x) - 1; } if (vtx1.y >= vtx2.y) { max_y = (int)ceilf(vtx1.y) + 1; min_y = (int)floorf(vtx2.y) - 1; } else { max_y = (int)ceilf(vtx2.y) + 1; min_y = (int)floorf(vtx1.y) - 1; } /* TODO: This bit is temporary, the min max's will be guaranteed to be within the bitmap once clipping is implemented */ if (min_x >= clip_max_x || min_y >= clip_max_y) return; if (max_x >= clip_max_x) max_x = clip_max_x; if (max_y >= clip_max_y) max_y = clip_max_y; if (max_x < clip_min_x || max_y < clip_min_y) return; if (min_x < clip_min_x) min_x = clip_min_x; if (min_y < clip_min_y) min_y = clip_min_y; if (al_is_bitmap_locked(target)) { if (!_al_bitmap_region_is_locked(target, min_x, min_y, max_x - min_x, max_y - min_y) || _al_pixel_format_is_video_only(target->locked_region.format)) return; } else { if (!(lr = al_lock_bitmap_region(target, min_x, min_y, max_x - min_x, max_y - min_y, ALLEGRO_PIXEL_FORMAT_ANY, 0))) return; need_unlock = 1; } line_stepper(state, first, step, draw, &vtx1, &vtx2); if (need_unlock) al_unlock_bitmap(target); } allegro5-5.2.10.1/addons/primitives/nshader.cpp000066400000000000000000000167221473414355200212630ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * This program is used to pre-compile some dummy shaders from * nshader.fx to be used in directx_shaders.c file. You will need * fxc.exe which can be found in a Direct3D SDK (June 2010 has it). * * Usage: Run the program and it will regenerate precompiled_shaders.inc. * (Make a backup of the old ones if you need them). * * Note, that this is not supposed to be compiled into the library. * Compile this manually if needed. * * By Michał Cichoń. * * See readme.txt for copyright information. */ # include # include # include # include # include # include # include # include # include using namespace std; typedef unsigned char byte_t; typedef vector byte_vector_t; struct technique_t { string name; string shader; byte_vector_t binary; }; typedef vector technique_vector_t; int compile(const string& source, const string& dest) { return system(("fxc /nologo /Tfx_2_0 /Fc " + dest + " " + source + " > nul").c_str()); } int assemble(const string& source, const string& dest, const string& entrypoint) { return system(("fxc /nologo /O3 /Fo " + dest + " " + source + " /E " + entrypoint + " > nul").c_str()); } bool extract_shader(technique_t& technique, istream& stream) { technique.shader.clear(); bool inside = false; bool record = false; string line; while (!getline(stream, line).fail()) { if (!inside && !record) { string::size_type pos = line.find_first_of("asm"); if (pos == string::npos || line.compare(pos, 3, "asm") != 0) continue; // strip everything to including "asm" keyword line = line.substr(pos + 3); inside = true; } if (inside && !record) { string::size_type pos = line.find_first_of("{"); if (pos == string::npos) continue; record = true; continue; } if (inside && record) { string::size_type pos = line.find_first_of("}"); if (pos != string::npos) return true; string::size_type non_white = line.find_first_not_of(" "); if (non_white != string::npos) technique.shader += line.substr(non_white) + "\n"; else technique.shader += "\n"; } } return false; } int extract_techniques(technique_vector_t& techniques, const string& filename) { techniques.clear(); ifstream file(filename.c_str()); if (!file) return 0; technique_t technique; string line; while (!getline(file, line).fail()) { string::size_type pos = line.find_first_of("technique"); if (pos != 0 || line.compare(pos, 9, "technique") != 0) continue; technique.name = line.substr(10); if (technique.name.empty()) { cerr << " Unnamed technique. Skipping..." << endl; continue; } cout << " Found: " << technique.name << endl; if (!extract_shader(technique, file)) { cerr << " Failed! Skipping..." << endl; continue; } techniques.push_back(technique); } return (int)techniques.size(); } int assemble_technique(const string& filename, technique_t& technique) { const string dest = "vshader.vso"; int result = assemble(filename, dest, "vs_" + technique.name); if (result) return result; ifstream file(dest.c_str(), ios::in | ios::binary); if (!file) { _unlink(dest.c_str()); return 1; } file.seekg(0, ios::end); technique.binary.resize(file.tellg()); file.seekg(0, ios::beg); file.read((char*)&technique.binary.front(), technique.binary.size()); file.close(); _unlink(dest.c_str()); return 0; } int assemble_techniques(const string& filename, technique_vector_t& techniques) { int count = 0; technique_vector_t::iterator it, it_end = techniques.end(); for (it = techniques.begin(); it != it_end; ++it) { technique_t& technique = *it; cout << " Processing: " << technique.name << endl; int assembled = assemble_technique(filename, technique); if (assembled) { cerr << " Failed." << endl; continue; } ++count; } return count; } char toupper2(char c) { return toupper(c); } int generate_table(ostream& output, technique_t& technique) { const int bytes_per_line = 16; string::size_type pos = 0; string name = technique.name, line; while ((pos = name.find_first_of('_', pos)) != string::npos) name[pos] = ' '; transform(name.begin(), name.end(), name.begin(), toupper2); output << "/*" << endl; output << " " << name << endl << endl; istringstream shader(technique.shader); while (!getline(shader, line).fail()) output << " " << line << endl; output << "*/" << endl; output << "static const uint8_t _al_vs_" << technique.name << "[] = {" << endl; for (size_t i = 0; i < technique.binary.size(); ++i) { if ((i % bytes_per_line) == 0) output << " "; output << "0x" << setw(2) << setfill('0') << hex << (int)technique.binary[i]; if (i != technique.binary.size() - 1) { if ((i % bytes_per_line) == (bytes_per_line - 1)) output << "," << endl; else output << ", "; } } output << endl; output.unsetf(ios::hex); output << "};" << endl; return 0; } int generate_tables(ostream& output, technique_vector_t& techniques) { int count = 0; output << "/* Generated using nshader.cpp. Do not hand edit. */" << endl; technique_vector_t::iterator it, it_end = techniques.end(); for (it = techniques.begin(); it != it_end; ++it) { technique_t& technique = *it; cout << " Processing: " << technique.name << endl; int generated = generate_table(output, technique); if (generated) { cerr << " Failed." << endl; continue; } output << endl; ++count; } return count; } int main() { const string source = "nshader.fx"; const string compiled = "nshader.fxc"; const string output = "precompiled_shaders.inc"; cout << "Compiling NULL shader..." << endl; if (int result = compile(source, compiled)) { cout << " Failed!" << endl; return result; } cout << "Done." << endl << endl; cout << "Extracting techniques..." << endl; technique_vector_t techniques; int found = extract_techniques(techniques, compiled); if (found) cout << "Done. " << found << " technique(s) extracted." << endl << endl; else cout << "Done. No techniques extracted." << endl << endl; _unlink(compiled.c_str()); if (found == 0) return 0; cout << "Assembling techniques..." << endl; int assembled = assemble_techniques(source, techniques); if (assembled) cout << "Done. " << assembled << " technique(s) assembled." << endl << endl; else cout << "Done. No assembled techniques." << endl << endl; if (assembled == 0) return 0; cout << "Generating tables..." << endl; ofstream output_file(output.c_str()); int tables = generate_tables(output_file, techniques); cout << "Done. " << tables << " table(s) generated." << endl << endl; return 0; } allegro5-5.2.10.1/addons/primitives/nshader.fx000066400000000000000000000105061473414355200211100ustar00rootroot00000000000000# define CAT(a, b) CAT_I(a, b) # define CAT_I(a, b) CAT_II(a ## b) # define CAT_II(res) res # define JOIN1(a) a # define JOIN2(a, b) CAT(a, b) # define JOIN3(a, b, c) CAT(JOIN2(a, b), c) # define JOIN4(a, b, c, d) CAT(JOIN3(a, b, c), d) # define JOIN5(a, b, c, d, e) CAT(JOIN4(a, b, c, d), e) # define JOIN6(a, b, c, d, e, f) CAT(JOIN5(a, b, c, d, e), f) # define JOIN7(a, b, c, d, e, f, g) CAT(JOIN6(a, b, c, d, e, f), g) # define JOIN8(a, b, c, d, e, f, g, h) CAT(JOIN7(a, b, c, d, e, f, g), h) # define DECL_VS_IN1(v0) struct JOIN2(vs_input_, v0) { _in_##v0 } # define DECL_VS_IN2(v0, v1) struct JOIN4(vs_input_, v0, _, v1) { _in_##v0 _in_##v1 } # define DECL_VS_IN3(v0, v1, v2) struct JOIN6(vs_input_, v0, _, v1, _, v2) { _in_##v0 _in_##v1 _in_##v2 } # define DECL_VS_OUT1(v0) struct JOIN2(vs_output_, v0) { _out_##v0 } # define DECL_VS_OUT2(v0, v1) struct JOIN4(vs_output_, v0, _, v1) { _out_##v0 _out_##v1 } # define DECL_VS_OUT3(v0, v1, v2) struct JOIN6(vs_output_, v0, _, v1, _, v2) { _out_##v0 _out_##v1 _out_##v2 } # define DEF_VS_BODY1(v0) void JOIN2(vs_, v0) (in JOIN2(vs_input_, v0) i, out JOIN2(vs_output_, v0) o) { _op_##v0 } # define DEF_VS_BODY2(v0, v1) void JOIN4(vs_, v0, _, v1) (in JOIN4(vs_input_, v0, _, v1) i, out JOIN4(vs_output_, v0, _) o) { _op_##v0 _op_##v1 } # define DEF_VS_BODY3(v0, v1, v2) void JOIN6(vs_, v0, _, v1, _, v2)(in JOIN6(vs_input_, v0, _, v1, _, v2) i, out JOIN6(vs_output_, v0, _, v1, _, v2) o) { _op_##v0 _op_##v1 _op_##v2 } # define DEF_TECH1(v0) technique JOIN1(v0) { pass { VertexShader = compile vs_1_1 JOIN2(vs_, v0)(); } } # define DEF_TECH2(v0, v1) technique JOIN3(v0, _, v1) { pass { VertexShader = compile vs_1_1 JOIN4(vs_, v0, _, v1)(); } } # define DEF_TECH3(v0, v1, v2) technique JOIN5(v0, _, v1, _, v2) { pass { VertexShader = compile vs_1_1 JOIN6(vs_, v0, _, v1, _, v2)(); } } # define DEF_VS1(v0) DECL_VS_IN1(v0); DECL_VS_OUT1(v0); DEF_VS_BODY1(v0) DEF_TECH1(v0) # define DEF_VS2(v0, v1) DECL_VS_IN2(v0, v1); DECL_VS_OUT2(v0, v1); DEF_VS_BODY2(v0, v1) DEF_TECH2(v0, v1) # define DEF_VS3(v0, v1, v2) DECL_VS_IN3(v0, v1, v2); DECL_VS_OUT3(v0, v1, v2); DEF_VS_BODY3(v0, v1, v2) DEF_TECH3(v0, v1, v2) # define _in_pos0 # define _in_pos2 float2 pos : POSITION; # define _in_pos3 float3 pos : POSITION; # define _in_tex0 # define _in_tex2 float2 tex : TEXCOORD0; # define _in_col0 # define _in_col4 float4 col : TEXCOORD1; # define _out_pos0 float4 pos : POSITION; # define _out_pos2 float4 pos : POSITION; # define _out_pos3 float4 pos : POSITION; # define _out_tex0 # define _out_tex2 float2 tex : TEXCOORD0; # define _out_col0 float4 col : COLOR0; # define _out_col4 float4 col : COLOR0; # define _op_pos0 o.pos = float4(0.0f, 0.0f, 0.0f, 1.0f); # define _op_pos2 o.pos = mul(float4(i.pos.xy, 0.0f, 1.0f), g_world_view_proj); # define _op_pos3 o.pos = mul(float4(i.pos.xyz, 1.0f), g_world_view_proj); # define _op_tex0 # define _op_tex2 o.tex = mul(float4(i.tex.xy, 1.0f, 0.0f), g_texture_proj).xy; # define _op_col0 o.col = float4(1.0f, 1.0f, 1.0f, 1.0f); # define _op_col4 o.col = i.col; float4x4 g_world_view_proj : register(c0); float4x4 g_texture_proj : register(c4); DEF_VS3(pos3, tex2, col4); DEF_VS3(pos3, tex2, col0); DEF_VS3(pos3, tex0, col4); DEF_VS3(pos3, tex0, col0); DEF_VS3(pos2, tex2, col4); DEF_VS3(pos2, tex2, col0); DEF_VS3(pos2, tex0, col4); DEF_VS3(pos2, tex0, col0); DEF_VS3(pos0, tex2, col4); DEF_VS3(pos0, tex2, col0); DEF_VS3(pos0, tex0, col4); DEF_VS3(pos0, tex0, col0); allegro5-5.2.10.1/addons/primitives/point_soft.c000066400000000000000000000062501473414355200214560ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Software point implementation functions. * * * By Pavel Sountsov. * * See readme.txt for copyright information. */ #define _AL_NO_BLEND_INLINE_FUNC #define ALLEGRO_INTERNAL_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/allegro_primitives.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_blend.h" #include "allegro5/internal/aintern_prim.h" #include "allegro5/internal/aintern_prim_soft.h" #include int _al_fix_texcoord(float var, int max_var, ALLEGRO_BITMAP_WRAP wrap) { int ivar = (int)floorf(var); float ret; switch (wrap) { case ALLEGRO_BITMAP_WRAP_CLAMP: if (ivar < 0) ret = 0; else if (ivar > max_var - 1) ret = max_var - 1; else ret = ivar; break; case ALLEGRO_BITMAP_WRAP_MIRROR: { ret = ivar % max_var; if(ret < 0) ret += max_var; if ((int)floorf((float)ivar / max_var) % 2) ret = max_var - 1 - ret; break; } default: { ret = ivar % max_var; if(ret < 0) ret += max_var; } } return ret; } void _al_point_2d(ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX* v) { int shade = 1; int op, src_mode, dst_mode, op_alpha, src_alpha, dst_alpha; ALLEGRO_COLOR vc; int clip_min_x, clip_min_y, clip_max_x, clip_max_y; int x = (int)floorf(v->x); int y = (int)floorf(v->x); al_get_clipping_rectangle(&clip_min_x, &clip_min_y, &clip_max_x, &clip_max_y); clip_max_x += clip_min_x; clip_max_y += clip_min_y; if(x < clip_min_x || x >= clip_max_x || y < clip_min_y || y >= clip_max_y) return; vc = v->color; al_get_separate_blender(&op, &src_mode, &dst_mode, &op_alpha, &src_alpha, &dst_alpha); if (_AL_DEST_IS_ZERO && _AL_SRC_NOT_MODIFIED) { shade = 0; } if (texture) { ALLEGRO_BITMAP_WRAP wrap_u, wrap_v; _al_get_bitmap_wrap(texture, &wrap_u, &wrap_v); int iu = _al_fix_texcoord(v->u, al_get_bitmap_width(texture), wrap_u); int iv = _al_fix_texcoord(v->v, al_get_bitmap_height(texture), wrap_v); ALLEGRO_COLOR color = al_get_pixel(texture, iu, iv); if(vc.r != 1 || vc.g != 1 || vc.b != 1 || vc.a != 1) { color.r *= vc.r; color.g *= vc.g; color.b *= vc.b; color.a *= vc.a; } if (shade) { al_put_blended_pixel(v->x, v->y, color); } else { al_put_pixel(v->x, v->y, color); } } else { ALLEGRO_COLOR color = al_map_rgba_f(vc.r, vc.g, vc.b, vc.a); if (shade) { al_put_blended_pixel(v->x, v->y, color); } else { al_put_pixel(v->x, v->y, color); } } } allegro5-5.2.10.1/addons/primitives/polygon.c000066400000000000000000000047731473414355200207710ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Polygon with holes drawing routines. * * * By Michał Cichoń. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_primitives.h" #include "allegro5/internal/aintern_prim.h" #include #ifdef ALLEGRO_MSVC #define hypotf(x, y) _hypotf((x), (y)) #endif static void polygon_push_triangle_callback(int i0, int i1, int i2, void* user_data) { ALLEGRO_PRIM_VERTEX_CACHE* cache = (ALLEGRO_PRIM_VERTEX_CACHE*)user_data; const float* vertices = (const float*)cache->user_data; const float* v0 = vertices + (i0 * 2); const float* v1 = vertices + (i1 * 2); const float* v2 = vertices + (i2 * 2); _al_prim_cache_push_triangle(cache, v0, v1, v2); } /* Function: al_draw_polygon */ void al_draw_polygon(const float *vertices, int vertex_count, int join_style, ALLEGRO_COLOR color, float thickness, float miter_limit) { al_draw_polyline(vertices, 2 * sizeof(float), vertex_count, join_style, ALLEGRO_LINE_CAP_CLOSED, color, thickness, miter_limit); } /* Function: al_draw_filled_polygon */ void al_draw_filled_polygon(const float *vertices, int vertex_count, ALLEGRO_COLOR color) { ALLEGRO_PRIM_VERTEX_CACHE cache; int vertex_counts[2]; _al_prim_cache_init_ex(&cache, ALLEGRO_PRIM_VERTEX_CACHE_TRIANGLE, color, (void*)vertices); vertex_counts[0] = vertex_count; vertex_counts[1] = 0; /* terminator */ al_triangulate_polygon(vertices, sizeof(float) * 2, vertex_counts, polygon_push_triangle_callback, &cache); _al_prim_cache_flush(&cache); } /* Function: al_draw_filled_polygon_with_holes */ void al_draw_filled_polygon_with_holes(const float *vertices, const int *vertex_counts, ALLEGRO_COLOR color) { ALLEGRO_PRIM_VERTEX_CACHE cache; _al_prim_cache_init_ex(&cache, ALLEGRO_PRIM_VERTEX_CACHE_TRIANGLE, color, (void*)vertices); al_triangulate_polygon(vertices, sizeof(float) * 2, vertex_counts, polygon_push_triangle_callback, &cache); _al_prim_cache_flush(&cache); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/primitives/polyline.c000066400000000000000000000405321473414355200211260ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Polyline primitive. * * * By Michał Cichoń. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_primitives.h" #include "allegro5/internal/aintern_list.h" #include "allegro5/internal/aintern_prim.h" #include #include /* * Computes direction, normal direction and the length of the segment. */ static float compute_direction_and_normal(const float* begin, const float* end, float* dir, float* normal) { float length; /* Determine direction, normal direction and length of the line segment. */ dir[0] = end[0] - begin[0]; dir[1] = end[1] - begin[1]; length = _al_prim_normalize(dir); normal[0] = -dir[1]; normal[1] = dir[0]; return length; } /* * Compute end cross points. */ static void compute_end_cross_points(const float* v0, const float* v1, float radius, float* p0, float* p1) { float dir[2]; float normal[2]; /* XXX delete this parameter? */ (void)radius; compute_direction_and_normal(v0, v1, dir, normal); p0[0] = v1[0] + normal[0] * radius; p0[1] = v1[1] + normal[1] * radius; p1[0] = v1[0] - normal[0] * radius; p1[1] = v1[1] - normal[1] * radius; } /* * Compute cross points. */ static void compute_cross_points(const float* v0, const float* v1, const float* v2, float radius, float* l0, float* l1, float* r0, float* r1, float* out_middle, float* out_angle, float* out_miter_distance) { float normal_0[2], normal_1[2]; float dir_0[2], dir_1[2]; float middle[2]; float diff[2]; float miter_distance; float angle; float len_0, len_1; bool sharp = false; /* Compute directions. */ len_0 = compute_direction_and_normal(v0, v1, dir_0, normal_0); len_1 = compute_direction_and_normal(v1, v2, dir_1, normal_1); /* Compute angle of deflection between segments. */ diff[0] = dir_0[0] * dir_1[0] + dir_0[1] * dir_1[1]; diff[1] = -(dir_0[0] * dir_1[1] - dir_0[1] * dir_1[0]); angle = (diff[0] || diff[1]) ? atan2f(diff[1], diff[0]) : 0.0f; /* Calculate miter distance. */ miter_distance = angle != 0.0f ? radius / cosf(fabsf(angle) * 0.5f) : radius; /* If the angle is too sharp, we give up on trying not to overdraw. */ if (miter_distance < 0) { sharp = true; miter_distance = 0; } if (miter_distance > len_0) { sharp = true; miter_distance = len_0; } if(miter_distance > len_1) { sharp = true; miter_distance = len_1; } middle[0] = normal_0[0] + normal_1[0]; middle[1] = normal_0[1] + normal_1[1]; if (middle[0] == middle[1] && middle[0] == 0.0) { middle[0] = dir_1[0]; middle[1] = dir_1[1]; } _al_prim_normalize(middle); /* Compute points. */ if (angle > 0.0f) { l0[0] = v1[0] + normal_0[0] * radius; l0[1] = v1[1] + normal_0[1] * radius; r0[0] = v1[0] + normal_1[0] * radius; r0[1] = v1[1] + normal_1[1] * radius; if (sharp) { l1[0] = v1[0] - normal_0[0] * radius; l1[1] = v1[1] - normal_0[1] * radius; r1[0] = v1[0] - normal_1[0] * radius; r1[1] = v1[1] - normal_1[1] * radius; } else { l1[0] = r1[0] = v1[0] - middle[0] * miter_distance; l1[1] = r1[1] = v1[1] - middle[1] * miter_distance; } } else { middle[0] = -middle[0]; middle[1] = -middle[1]; l1[0] = v1[0] - normal_0[0] * radius; l1[1] = v1[1] - normal_0[1] * radius; r1[0] = v1[0] - normal_1[0] * radius; r1[1] = v1[1] - normal_1[1] * radius; if (sharp) { l0[0] = v1[0] + normal_0[0] * radius; l0[1] = v1[1] + normal_0[1] * radius; r0[0] = v1[0] + normal_1[0] * radius; r0[1] = v1[1] + normal_1[1] * radius; } else { l0[0] = r0[0] = v1[0] - middle[0] * miter_distance; l0[1] = r0[1] = v1[1] - middle[1] * miter_distance; } } if (out_angle) *out_angle = angle; if (out_miter_distance) *out_miter_distance = miter_distance; if (out_middle) memcpy(out_middle, middle, sizeof(float) * 2); } /* * Emits filled arc. * * Arc is defined by pivot point, radius, start and end angle. * Starting and ending angle are wrapped to two pi range. */ static void emit_arc(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, float start, float end, float radius, int segments) { float arc; float c, s, t; float v0[2]; float v1[2]; float cp[2]; int i; /* This is very small arc, we will draw nothing. */ if (fabsf(end - start) < 0.001f) return; /* Make sure start both start angle is located in the * range [0, 2 * pi) and end angle is greater than * start angle. */ start = fmodf(start, ALLEGRO_PI * 2.0f); end = fmodf(end, ALLEGRO_PI * 2.0f); if (end <= start) end += ALLEGRO_PI * 2.0f; arc = end - start; segments = (int)(segments * arc / ALLEGRO_PI * 2.0f); if (segments < 1) segments = 1; c = cosf(arc / segments); s = sinf(arc / segments); cp[0] = cosf(start) * radius; cp[1] = sinf(start) * radius; v0[0] = cp[0] + pivot[0]; v0[1] = cp[1] + pivot[1]; for (i = 0; i < segments - 1; ++i) { t = cp[0]; cp[0] = c * cp[0] - s * cp[1]; cp[1] = s * t + c * cp[1]; v1[0] = cp[0] + pivot[0]; v1[1] = cp[1] + pivot[1]; _al_prim_cache_push_triangle(cache, v0, pivot, v1); v0[0] = v1[0]; v0[1] = v1[1]; } v1[0] = cosf(end) * radius + pivot[0]; v1[1] = sinf(end) * radius + pivot[1]; _al_prim_cache_push_triangle(cache, v0, pivot, v1); } /* * Emits square cap. * * Square cap is an rectangle with edges lengths equal to radius * and double radius, first along direction second along normal * direction. */ static void emit_square_end_cap(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* dir, const float* normal, float radius) { /* Prepare all four vertices of the rectangle. */ float v0[2] = { pivot[0] + normal[0] * radius, pivot[1] + normal[1] * radius }; float v1[2] = { pivot[0] - normal[0] * radius, pivot[1] - normal[1] * radius }; float v2[2] = { v0[0] + dir[0] * radius, v0[1] + dir[1] * radius }; float v3[2] = { v1[0] + dir[0] * radius, v1[1] + dir[1] * radius }; /* Emit. */ _al_prim_cache_push_triangle(cache, v0, v2, v3); _al_prim_cache_push_triangle(cache, v0, v3, v1); } /* * Emits triangular cap. */ static void emit_triange_end_cap(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* dir, const float* normal, float radius) { /* Prepare all four vertices of the rectangle. */ float v0[2] = { pivot[0] + normal[0] * radius, pivot[1] + normal[1] * radius }; float v1[2] = { pivot[0] - normal[0] * radius, pivot[1] - normal[1] * radius }; float v2[2] = { pivot[0] + dir[0] * radius, pivot[1] + dir[1] * radius }; /* Emit. */ _al_prim_cache_push_triangle(cache, v0, v2, v1); } /* * Emits rounded cap. */ static void emit_round_end_cap(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* dir, const float* normal, float radius) { float angle = atan2f(-normal[1], -normal[0]); /* XXX delete these parameters? */ (void)dir; (void)radius; emit_arc(cache, pivot, angle, angle + ALLEGRO_PI, radius, 16); } /* * Emits end cap. * * Direction of the end cap is defined by vector [v1 - v0]. p0 and p1 are starting * and ending point of the cap. Both should be located on the circle with center * in v1 and specified radius. p0 have to be located on the negative and p0 on the * positive half plane defined by direction vector. */ static void emit_end_cap(ALLEGRO_PRIM_VERTEX_CACHE* cache, int cap_style, const float* v0, const float* v1, float radius) { float dir[2]; float normal[2]; /* Do do not want you to call this function for closed cap. * It is special and there is nothing we can do with it there. */ ASSERT(cap_style != ALLEGRO_LINE_CAP_CLOSED); /* There nothing we can do for this kind of ending cap. */ if (cap_style == ALLEGRO_LINE_CAP_NONE) return; /* Compute normal and direction for our segment. */ compute_direction_and_normal(v0, v1, dir, normal); /* Emit vertices for cap. */ if (cap_style == ALLEGRO_LINE_CAP_SQUARE) emit_square_end_cap(cache, v1, dir, normal, radius); else if (cap_style == ALLEGRO_LINE_CAP_TRIANGLE) emit_triange_end_cap(cache, v1, dir, normal, radius); else if (cap_style == ALLEGRO_LINE_CAP_ROUND) emit_round_end_cap(cache, v1, dir, normal, radius); else { ASSERT("Unknown or unsupported style of ending cap." && false); } } /* * Emits bevel join. */ static void emit_bevel_join(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* p0, const float* p1) { _al_prim_cache_push_triangle(cache, pivot, p0, p1); } /* * Emits round join. */ static void emit_round_join(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* p0, const float* p1, float radius) { float start = atan2f(p1[1] - pivot[1], p1[0] - pivot[0]); float end = atan2f(p0[1] - pivot[1], p0[0] - pivot[0]); if (end < start) end += ALLEGRO_PI * 2.0f; emit_arc(cache, pivot, start, end, radius, 16); } /* * Emits miter join. */ static void emit_miter_join(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* p0, const float* p1, float radius, const float* middle, float angle, float miter_distance, float max_miter_distance) { /* XXX delete this parameter? */ (void)radius; if (miter_distance > max_miter_distance) { float normal[2] = { -middle[1], middle[0] }; float offset = (miter_distance - max_miter_distance) * tanf((ALLEGRO_PI - fabsf(angle)) * 0.5f); float v0[2] = { pivot[0] + middle[0] * max_miter_distance + normal[0] * offset, pivot[1] + middle[1] * max_miter_distance + normal[1] * offset }; float v1[2] = { pivot[0] + middle[0] * max_miter_distance - normal[0] * offset, pivot[1] + middle[1] * max_miter_distance - normal[1] * offset }; _al_prim_cache_push_triangle(cache, pivot, v0, v1); _al_prim_cache_push_triangle(cache, pivot, p0, v0); _al_prim_cache_push_triangle(cache, pivot, p1, v1); } else { float miter[2] = { pivot[0] + middle[0] * miter_distance, pivot[1] + middle[1] * miter_distance, }; _al_prim_cache_push_triangle(cache, pivot, p0, miter); _al_prim_cache_push_triangle(cache, pivot, miter, p1); } } /* Emit join between segments. */ static void emit_join(ALLEGRO_PRIM_VERTEX_CACHE* cache, int join_style, const float* pivot, const float* p0, const float* p1, float radius, const float* middle, float angle, float miter_distance, float miter_limit) { /* There is nothing to do for this type of join. */ if (join_style == ALLEGRO_LINE_JOIN_NONE) return; if (join_style == ALLEGRO_LINE_JOIN_BEVEL) emit_bevel_join(cache, pivot, p0, p1); else if (join_style == ALLEGRO_LINE_JOIN_ROUND) emit_round_join(cache, pivot, p0, p1, radius); else if (join_style == ALLEGRO_LINE_JOIN_MITER) emit_miter_join(cache, pivot, p0, p1, radius, middle, angle, miter_distance, miter_limit * radius); else { ASSERT("Unknown or unsupported style of join." && false); } } static void emit_polyline(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* vertices, int vertex_stride, int vertex_count, int join_style, int cap_style, float thickness, float miter_limit) { # define VERTEX(index) ((const float*)(((uint8_t*)vertices) + vertex_stride * ((vertex_count + (index)) % vertex_count))) float l0[2], l1[2]; float r0[2], r1[2]; float p0[2], p1[2]; float radius; int steps; int i; ASSERT(thickness > 0.0f); /* Discard invalid lines. */ if (vertex_count < 2) return; radius = 0.5f * thickness; /* Single line cannot be closed. If user forgot to explicitly specify * most desired alternative cap style, we just disable capping at all. */ if (vertex_count == 2 && cap_style == ALLEGRO_LINE_CAP_CLOSED) cap_style = ALLEGRO_LINE_CAP_NONE; /* Prepare initial set of vertices. */ if (cap_style != ALLEGRO_LINE_CAP_CLOSED) { /* We can emit ending caps right now. * * VERTEX(-2) and similar are safe, because it at this place * it is guaranteed that there are at least two vertices * in the buffer. */ emit_end_cap(cache, cap_style, VERTEX(1), VERTEX(0), radius); emit_end_cap(cache, cap_style, VERTEX(-2), VERTEX(-1), radius); /* Compute points on the left side of the very first segment. */ compute_end_cross_points(VERTEX(1), VERTEX(0), radius, p1, p0); /* For non-closed line we have N - 1 steps, but since we iterate * from one, N is right value. */ steps = vertex_count; } else { /* Compute points on the left side of the very first segment. */ compute_cross_points(VERTEX(-1), VERTEX(0), VERTEX(1), radius, l0, l1, p0, p1, NULL, NULL, NULL); /* Closed line use N steps, because last vertex have to be * connected with first one. */ steps = vertex_count + 1; } /* Process segments. */ for (i = 1; i < steps; ++i) { /* Pick vertex and their neighbors. */ const float* v0 = VERTEX(i - 1); const float* v1 = VERTEX(i); const float* v2 = VERTEX(i + 1); /* Choose correct cross points. */ if ((cap_style == ALLEGRO_LINE_CAP_CLOSED) || (i < steps - 1)) { float middle[2]; float miter_distance; float angle; /* Compute cross points. */ compute_cross_points(v0, v1, v2, radius, l0, l1, r0, r1, middle, &angle, &miter_distance); /* Emit join. */ if (angle >= 0.0f) emit_join(cache, join_style, v1, l0, r0, radius, middle, angle, miter_distance, miter_limit); else emit_join(cache, join_style, v1, r1, l1, radius, middle, angle, miter_distance, miter_limit); } else compute_end_cross_points(v0, v1, radius, l0, l1); /* Emit triangles. */ _al_prim_cache_push_triangle(cache, v0, v1, l1); _al_prim_cache_push_triangle(cache, v0, l1, p1); _al_prim_cache_push_triangle(cache, v0, p0, l0); _al_prim_cache_push_triangle(cache, v0, l0, v1); /* Save current most right vertices. */ memcpy(p0, r0, sizeof(float) * 2); memcpy(p1, r1, sizeof(float) * 2); } # undef VERTEX } static void do_draw_polyline(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* vertices, int vertex_stride, int vertex_count, int join_style, int cap_style, ALLEGRO_COLOR color, float thickness, float miter_limit) { if (thickness > 0.0f) { _al_prim_cache_init(cache, ALLEGRO_PRIM_VERTEX_CACHE_TRIANGLE, color); emit_polyline(cache, vertices, vertex_stride, vertex_count, join_style, cap_style, thickness, miter_limit); _al_prim_cache_term(cache); } else { # define VERTEX(index) ((const float*)(((uint8_t*)vertices) + vertex_stride * ((vertex_count + (index)) % vertex_count))) int i; _al_prim_cache_init(cache, ALLEGRO_PRIM_VERTEX_CACHE_LINE_STRIP, color); for (i = 0; i < vertex_count; ++i) { if (cache->size >= (ALLEGRO_VERTEX_CACHE_SIZE - 2)) _al_prim_cache_flush(cache); _al_prim_cache_push_point(cache, VERTEX(i)); } if (cap_style == ALLEGRO_LINE_CAP_CLOSED && vertex_count > 2) { if (cache->size >= (ALLEGRO_VERTEX_CACHE_SIZE - 2)) _al_prim_cache_flush(cache); _al_prim_cache_push_point(cache, VERTEX(0)); } _al_prim_cache_term(cache); # undef VERTEX } } /* Function: al_draw_polyline */ void al_draw_polyline(const float* vertices, int vertex_stride, int vertex_count, int join_style, int cap_style, ALLEGRO_COLOR color, float thickness, float miter_limit) { ALLEGRO_PRIM_VERTEX_CACHE cache; do_draw_polyline(&cache, vertices, vertex_stride, vertex_count, join_style, cap_style, color, thickness, miter_limit); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/primitives/precompiled_shaders.inc000066400000000000000000000722401473414355200236370ustar00rootroot00000000000000/* Generated using nshader.cpp. Do not hand edit. */ /* POS3 TEX2 COL4 // // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 // // Parameters: // // float4x4 g_texture_proj; // float4x4 g_world_view_proj; // // // Registers: // // Name Reg Size // ----------------- ----- ---- // g_world_view_proj c0 4 // g_texture_proj c4 2 // vs_1_1 def c6, 1, 0, 0, 0 dcl_position v0 dcl_texcoord v1 dcl_texcoord1 v2 mad r0, v0.xyzx, c6.xxxy, c6.yyyx dp4 oPos.x, r0, c0 dp4 oPos.y, r0, c1 dp4 oPos.z, r0, c2 dp4 oPos.w, r0, c3 mad r0.xyz, v1.xyxw, c6.xxyw, c6.yyxw dp3 oT0.x, r0, c4 dp3 oT0.y, r0, c5 mov oD0, v2 // approximately 9 instruction slots used */ static const uint8_t _al_vs_pos3_tex2_col4[] = { 0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x2d, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x12, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0x76, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0xab, 0x51, 0x00, 0x00, 0x05, 0x06, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x80, 0x02, 0x00, 0x0f, 0x90, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x24, 0x90, 0x06, 0x00, 0x40, 0xa0, 0x06, 0x00, 0x15, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x02, 0x00, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x03, 0x00, 0xe4, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80, 0x01, 0x00, 0xc4, 0x90, 0x06, 0x00, 0xd0, 0xa0, 0x06, 0x00, 0xc5, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x04, 0x00, 0xe4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x05, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xd0, 0x02, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00 }; /* POS3 TEX2 COL0 // // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 // // Parameters: // // float4x4 g_texture_proj; // float4x4 g_world_view_proj; // // // Registers: // // Name Reg Size // ----------------- ----- ---- // g_world_view_proj c0 4 // g_texture_proj c4 2 // vs_1_1 def c6, 1, 0, 0, 0 dcl_position v0 dcl_texcoord v1 mad r0, v0.xyzx, c6.xxxy, c6.yyyx dp4 oPos.x, r0, c0 dp4 oPos.y, r0, c1 dp4 oPos.z, r0, c2 dp4 oPos.w, r0, c3 mad r0.xyz, v1.xyxw, c6.xxyw, c6.yyxw dp3 oT0.x, r0, c4 dp3 oT0.y, r0, c5 mov oD0, c6.x // approximately 9 instruction slots used */ static const uint8_t _al_vs_pos3_tex2_col0[] = { 0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x2d, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x12, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0x76, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0xab, 0x51, 0x00, 0x00, 0x05, 0x06, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0f, 0x90, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x24, 0x90, 0x06, 0x00, 0x40, 0xa0, 0x06, 0x00, 0x15, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x02, 0x00, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x03, 0x00, 0xe4, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80, 0x01, 0x00, 0xc4, 0x90, 0x06, 0x00, 0xd0, 0xa0, 0x06, 0x00, 0xc5, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x04, 0x00, 0xe4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x05, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xd0, 0x06, 0x00, 0x00, 0xa0, 0xff, 0xff, 0x00, 0x00 }; /* POS3 TEX0 COL4 // // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 // // Parameters: // // float4x4 g_world_view_proj; // // // Registers: // // Name Reg Size // ----------------- ----- ---- // g_world_view_proj c0 4 // vs_1_1 def c4, 1, 0, 0, 0 dcl_position v0 dcl_texcoord1 v1 mad r0, v0.xyzx, c4.xxxy, c4.yyyx dp4 oPos.x, r0, c0 dp4 oPos.y, r0, c1 dp4 oPos.z, r0, c2 dp4 oPos.w, r0, c3 mov oD0, v1 // approximately 6 instruction slots used */ static const uint8_t _al_vs_pos3_tex0_col4[] = { 0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x24, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0xab, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x51, 0x00, 0x00, 0x05, 0x04, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x80, 0x01, 0x00, 0x0f, 0x90, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x24, 0x90, 0x04, 0x00, 0x40, 0xa0, 0x04, 0x00, 0x15, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x02, 0x00, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x03, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xd0, 0x01, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00 }; /* POS3 TEX0 COL0 // // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 // // Parameters: // // float4x4 g_world_view_proj; // // // Registers: // // Name Reg Size // ----------------- ----- ---- // g_world_view_proj c0 4 // vs_1_1 def c4, 1, 0, 0, 0 dcl_position v0 mad r0, v0.xyzx, c4.xxxy, c4.yyyx dp4 oPos.x, r0, c0 dp4 oPos.y, r0, c1 dp4 oPos.z, r0, c2 dp4 oPos.w, r0, c3 mov oD0, c4.x // approximately 6 instruction slots used */ static const uint8_t _al_vs_pos3_tex0_col0[] = { 0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x24, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0xab, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x51, 0x00, 0x00, 0x05, 0x04, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x24, 0x90, 0x04, 0x00, 0x40, 0xa0, 0x04, 0x00, 0x15, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x02, 0x00, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x03, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xd0, 0x04, 0x00, 0x00, 0xa0, 0xff, 0xff, 0x00, 0x00 }; /* POS2 TEX2 COL4 // // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 // // Parameters: // // float4x4 g_texture_proj; // float4x4 g_world_view_proj; // // // Registers: // // Name Reg Size // ----------------- ----- ---- // g_world_view_proj c0 4 // g_texture_proj c4 2 // vs_1_1 def c6, 1, 0, 0, 0 dcl_position v0 dcl_texcoord v1 dcl_texcoord1 v2 mad r0.xyz, v0.xyxw, c6.xxyw, c6.yyxw dp3 oPos.x, r0, c0.xyww dp3 oPos.y, r0, c1.xyww dp3 oPos.z, r0, c2.xyww dp3 oPos.w, r0, c3.xyww mad r0.xyz, v1.xyxw, c6.xxyw, c6.yyxw dp3 oT0.x, r0, c4 dp3 oT0.y, r0, c5 mov oD0, v2 // approximately 9 instruction slots used */ static const uint8_t _al_vs_pos2_tex2_col4[] = { 0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x2d, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x12, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0x76, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0xab, 0x51, 0x00, 0x00, 0x05, 0x06, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x80, 0x02, 0x00, 0x0f, 0x90, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xc4, 0x90, 0x06, 0x00, 0xd0, 0xa0, 0x06, 0x00, 0xc5, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xf4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xf4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x02, 0x00, 0xf4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x03, 0x00, 0xf4, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80, 0x01, 0x00, 0xc4, 0x90, 0x06, 0x00, 0xd0, 0xa0, 0x06, 0x00, 0xc5, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x04, 0x00, 0xe4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x05, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xd0, 0x02, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00 }; /* POS2 TEX2 COL0 // // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 // // Parameters: // // float4x4 g_texture_proj; // float4x4 g_world_view_proj; // // // Registers: // // Name Reg Size // ----------------- ----- ---- // g_world_view_proj c0 4 // g_texture_proj c4 2 // vs_1_1 def c6, 1, 0, 0, 0 dcl_position v0 dcl_texcoord v1 mad r0.xyz, v0.xyxw, c6.xxyw, c6.yyxw dp3 oPos.x, r0, c0.xyww dp3 oPos.y, r0, c1.xyww dp3 oPos.z, r0, c2.xyww dp3 oPos.w, r0, c3.xyww mad r0.xyz, v1.xyxw, c6.xxyw, c6.yyxw dp3 oT0.x, r0, c4 dp3 oT0.y, r0, c5 mov oD0, c6.x // approximately 9 instruction slots used */ static const uint8_t _al_vs_pos2_tex2_col0[] = { 0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x2d, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x12, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0x76, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0xab, 0x51, 0x00, 0x00, 0x05, 0x06, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0f, 0x90, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xc4, 0x90, 0x06, 0x00, 0xd0, 0xa0, 0x06, 0x00, 0xc5, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xf4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xf4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x02, 0x00, 0xf4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x03, 0x00, 0xf4, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80, 0x01, 0x00, 0xc4, 0x90, 0x06, 0x00, 0xd0, 0xa0, 0x06, 0x00, 0xc5, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x04, 0x00, 0xe4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x05, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xd0, 0x06, 0x00, 0x00, 0xa0, 0xff, 0xff, 0x00, 0x00 }; /* POS2 TEX0 COL4 // // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 // // Parameters: // // float4x4 g_world_view_proj; // // // Registers: // // Name Reg Size // ----------------- ----- ---- // g_world_view_proj c0 4 // vs_1_1 def c4, 1, 0, 0, 0 dcl_position v0 dcl_texcoord1 v1 mad r0.xyz, v0.xyxw, c4.xxyw, c4.yyxw dp3 oPos.x, r0, c0.xyww dp3 oPos.y, r0, c1.xyww dp3 oPos.z, r0, c2.xyww dp3 oPos.w, r0, c3.xyww mov oD0, v1 // approximately 6 instruction slots used */ static const uint8_t _al_vs_pos2_tex0_col4[] = { 0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x24, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0xab, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x51, 0x00, 0x00, 0x05, 0x04, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x80, 0x01, 0x00, 0x0f, 0x90, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xc4, 0x90, 0x04, 0x00, 0xd0, 0xa0, 0x04, 0x00, 0xc5, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xf4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xf4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x02, 0x00, 0xf4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x03, 0x00, 0xf4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xd0, 0x01, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00 }; /* POS2 TEX0 COL0 // // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 // // Parameters: // // float4x4 g_world_view_proj; // // // Registers: // // Name Reg Size // ----------------- ----- ---- // g_world_view_proj c0 4 // vs_1_1 def c4, 1, 0, 0, 0 dcl_position v0 mad r0.xyz, v0.xyxw, c4.xxyw, c4.yyxw dp3 oPos.x, r0, c0.xyww dp3 oPos.y, r0, c1.xyww dp3 oPos.z, r0, c2.xyww dp3 oPos.w, r0, c3.xyww mov oD0, c4.x // approximately 6 instruction slots used */ static const uint8_t _al_vs_pos2_tex0_col0[] = { 0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x24, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0xab, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x51, 0x00, 0x00, 0x05, 0x04, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xc4, 0x90, 0x04, 0x00, 0xd0, 0xa0, 0x04, 0x00, 0xc5, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xf4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xf4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x02, 0x00, 0xf4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0xc0, 0x00, 0x00, 0xe4, 0x80, 0x03, 0x00, 0xf4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xd0, 0x04, 0x00, 0x00, 0xa0, 0xff, 0xff, 0x00, 0x00 }; /* POS0 TEX2 COL4 // // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 // // Parameters: // // float4x4 g_texture_proj; // // // Registers: // // Name Reg Size // -------------- ----- ---- // g_texture_proj c4 2 // vs_1_1 def c0, 1, 0, 0, 0 dcl_texcoord v0 dcl_texcoord1 v1 mad r0.xyz, v0.xyxw, c0.xxyw, c0.yyxw dp3 oT0.x, r0, c4 dp3 oT0.y, r0, c5 mov oPos, c0.yyyx mov oD0, v1 // approximately 5 instruction slots used */ static const uint8_t _al_vs_pos0_tex2_col4[] = { 0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x23, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x51, 0x00, 0x00, 0x05, 0x00, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x80, 0x01, 0x00, 0x0f, 0x90, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xc4, 0x90, 0x00, 0x00, 0xd0, 0xa0, 0x00, 0x00, 0xc5, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x04, 0x00, 0xe4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x05, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x15, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xd0, 0x01, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00 }; /* POS0 TEX2 COL0 // // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 // // Parameters: // // float4x4 g_texture_proj; // // // Registers: // // Name Reg Size // -------------- ----- ---- // g_texture_proj c4 2 // vs_1_1 def c0, 1, 0, 0, 0 dcl_texcoord v0 mad r0.xyz, v0.xyxw, c0.xxyw, c0.yyxw dp3 oT0.x, r0, c4 dp3 oT0.y, r0, c5 mov oPos, c0.yyyx mov oD0, c0.x // approximately 5 instruction slots used */ static const uint8_t _al_vs_pos0_tex2_col0[] = { 0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x23, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x00, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x51, 0x00, 0x00, 0x05, 0x00, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xc4, 0x90, 0x00, 0x00, 0xd0, 0xa0, 0x00, 0x00, 0xc5, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x04, 0x00, 0xe4, 0xa0, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x05, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x15, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xd0, 0x00, 0x00, 0x00, 0xa0, 0xff, 0xff, 0x00, 0x00 }; /* POS0 TEX0 COL4 // // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 vs_1_1 def c0, 0, 1, 0, 0 dcl_texcoord1 v0 mov oPos, c0.xxxy mov oD0, v0 // approximately 2 instruction slots used */ static const uint8_t _al_vs_pos0_tex0_col4[] = { 0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x16, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x76, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x51, 0x00, 0x00, 0x05, 0x00, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x40, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xd0, 0x00, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00 }; /* POS0 TEX0 COL0 // // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 vs_1_1 def c0, 0, 1, 0, 0 mov oPos, c0.xxxy mov oD0, c0.y // approximately 2 instruction slots used */ static const uint8_t _al_vs_pos0_tex0_col0[] = { 0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x16, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x76, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x51, 0x00, 0x00, 0x05, 0x00, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x40, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0xd0, 0x00, 0x00, 0x55, 0xa0, 0xff, 0xff, 0x00, 0x00 }; allegro5-5.2.10.1/addons/primitives/prim_directx.cpp000066400000000000000000001105711473414355200223250ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * DirectX implementation of some of the primitive routines. * * * By Pavel Sountsov. * * See readme.txt for copyright information. */ #define ALLEGRO_INTERNAL_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/allegro_primitives.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_prim_directx.h" #include "allegro5/internal/aintern_prim_soft.h" #include "allegro5/internal/aintern_prim.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/platform/alplatf.h" #ifdef ALLEGRO_CFG_D3D #include "allegro5/allegro_direct3d.h" #include "allegro5/internal/aintern_direct3d.h" ALLEGRO_DEBUG_CHANNEL("d3d_primitives") static ALLEGRO_MUTEX *d3d_mutex; /* * In the context of this file, legacy cards pretty much refer to older Intel cards. * They are distinguished by three misfeatures: * 1. They don't support shaders * 2. They don't support custom vertices * 3. DrawIndexedPrimitiveUP is broken * * Since shaders are used 100% of the time, this means that for these cards * the incoming vertices are first converted into the vertex type that these cards * can handle. */ static bool legacy_card = false; static bool know_card_type = false; static bool is_legacy_card(void) { if (!know_card_type) { ALLEGRO_CONFIG* sys_cfg = al_get_system_config(); const char* detection_setting = al_get_config_value(sys_cfg, "graphics", "prim_d3d_legacy_detection"); detection_setting = detection_setting ? detection_setting : "default"; if (strcmp(detection_setting, "default") == 0) { D3DCAPS9 caps; LPDIRECT3DDEVICE9 device = al_get_d3d_device(al_get_current_display()); device->GetDeviceCaps(&caps); if (caps.PixelShaderVersion < D3DPS_VERSION(2, 0)) legacy_card = true; } else if(strcmp(detection_setting, "force_legacy") == 0) { legacy_card = true; } else if(strcmp(detection_setting, "force_modern") == 0) { legacy_card = false; } else { ALLEGRO_WARN("Invalid setting for prim_d3d_legacy_detection.\n"); legacy_card = false; } if (legacy_card) { ALLEGRO_WARN("Your GPU is considered legacy! Some of the features of the primitives addon will be slower/disabled.\n"); } know_card_type = true; } return legacy_card; } struct LEGACY_VERTEX { float x, y, z; DWORD color; float u, v; }; static uint8_t* legacy_buffer; static size_t legacy_buffer_size = 0; #define A5V_FVF (D3DFVF_XYZ | D3DFVF_TEX2 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE4(1)) #define A5V_LEGACY_FVF (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1) struct DISPLAY_LOCAL_DATA { LPDIRECT3DDEVICE9 device; LPDIRECT3DVERTEXSHADER9 shader; ALLEGRO_INDEX_BUFFER* loop_index_buffer; }; static DISPLAY_LOCAL_DATA* display_local_data; static int display_local_data_size = 0; static void display_invalidated(ALLEGRO_DISPLAY* display) { int ii; LPDIRECT3DDEVICE9 device = al_get_d3d_device(display); /* * If there is no mutex, the addon has been shutdown earlier */ if(!d3d_mutex) return; al_lock_mutex(d3d_mutex); for(ii = 0; ii < display_local_data_size; ii++) { if(display_local_data[ii].device == device) { display_local_data[ii].shader->Release(); display_local_data[ii] = display_local_data[display_local_data_size - 1]; display_local_data_size--; break; } } al_unlock_mutex(d3d_mutex); } static DISPLAY_LOCAL_DATA get_display_local_data(ALLEGRO_DISPLAY* display) { LPDIRECT3DDEVICE9 device = al_get_d3d_device(display); DISPLAY_LOCAL_DATA ret; bool create_new = false; /* * Lock the mutex so that the entries are not messed up by a * display blowing up/being created */ al_lock_mutex(d3d_mutex); if (display_local_data_size == 0) { display_local_data = (DISPLAY_LOCAL_DATA*)al_malloc(sizeof(DISPLAY_LOCAL_DATA)); display_local_data_size = 1; create_new = true; } else if (display_local_data[0].device != device) { int ii; bool found = false; for(ii = 1; ii < display_local_data_size; ii++) { if(display_local_data[ii].device == device) { /* * Move this entry to the front, so the search goes faster * next time - presumably the al_draw_prim will be called * several times for each display before switching again */ DISPLAY_LOCAL_DATA t = display_local_data[0]; display_local_data[0] = display_local_data[ii]; display_local_data[ii] = t; found = true; break; } } if (!found) { DISPLAY_LOCAL_DATA t = display_local_data[0]; display_local_data_size++; display_local_data = (DISPLAY_LOCAL_DATA *)al_realloc(display_local_data, sizeof(DISPLAY_LOCAL_DATA) * display_local_data_size); display_local_data[display_local_data_size - 1] = t; create_new = true; } } if (create_new) { int initial_indices[2] = {0, 0}; display_local_data[0].device = device; display_local_data[0].shader = (LPDIRECT3DVERTEXSHADER9)_al_create_default_primitives_shader(device); display_local_data[0].loop_index_buffer = al_create_index_buffer(sizeof(int), initial_indices, 2, 0); _al_add_display_invalidated_callback(display, &display_invalidated); } ret = display_local_data[0]; al_unlock_mutex(d3d_mutex); return ret; } static void destroy_display_local_data(void) { int ii; for(ii = 0; ii < display_local_data_size; ii++) { display_local_data[ii].shader->Release(); al_destroy_index_buffer(display_local_data[ii].loop_index_buffer); } display_local_data_size = 0; al_free(display_local_data); display_local_data = NULL; } #endif bool _al_init_d3d_driver(void) { #ifdef ALLEGRO_CFG_D3D d3d_mutex = al_create_mutex(); #endif return true; } void _al_shutdown_d3d_driver(void) { #ifdef ALLEGRO_CFG_D3D al_destroy_mutex(d3d_mutex); al_free(legacy_buffer); d3d_mutex = NULL; legacy_buffer = NULL; destroy_display_local_data(); legacy_card = false; know_card_type = false; legacy_buffer_size = 0; #endif } #ifdef ALLEGRO_CFG_D3D static void* convert_to_legacy_vertices(const void* vtxs, int num_vertices, const int* indices, bool loop, bool pp) { const ALLEGRO_VERTEX* vtx = (const ALLEGRO_VERTEX *)vtxs; int ii; int num_needed_vertices = num_vertices; size_t needed_size; if (pp && !indices && !loop) { return (void *)vtxs; } if(loop) num_needed_vertices++; needed_size = num_needed_vertices * (pp ? sizeof(ALLEGRO_VERTEX) : sizeof(LEGACY_VERTEX)); if(legacy_buffer == 0) { legacy_buffer = (uint8_t *)al_malloc(needed_size); legacy_buffer_size = needed_size; } else if (needed_size > legacy_buffer_size) { size_t new_size = needed_size * 1.5; legacy_buffer = (uint8_t *)al_realloc(legacy_buffer, new_size); legacy_buffer_size = new_size; } if (pp) { ALLEGRO_VERTEX *buffer = (ALLEGRO_VERTEX *)legacy_buffer; for(ii = 0; ii < num_vertices; ii++) { if(indices) buffer[ii] = vtx[indices[ii]]; else buffer[ii] = vtx[ii]; } if(loop) buffer[num_vertices] = buffer[0]; } else { LEGACY_VERTEX *buffer = (LEGACY_VERTEX *)legacy_buffer; for(ii = 0; ii < num_vertices; ii++) { ALLEGRO_VERTEX vertex; if(indices) vertex = vtx[indices[ii]]; else vertex = vtx[ii]; buffer[ii].x = vertex.x; buffer[ii].y = vertex.y; buffer[ii].z = vertex.z; buffer[ii].u = vertex.u; buffer[ii].v = vertex.v; buffer[ii].color = D3DCOLOR_COLORVALUE(vertex.color.r, vertex.color.g, vertex.color.b, vertex.color.a); } if(loop) buffer[num_vertices] = buffer[0]; } return legacy_buffer; } struct D3D_STATE { DWORD old_wrap_state[2]; DWORD old_ttf_state; IDirect3DVertexShader9* old_vtx_shader; }; static D3D_STATE setup_state(LPDIRECT3DDEVICE9 device, const ALLEGRO_VERTEX_DECL* decl, ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, DISPLAY_LOCAL_DATA data) { D3D_STATE state; ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target); ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)disp; if (!(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) { IDirect3DPixelShader9* old_pix_shader; device->GetVertexShader(&state.old_vtx_shader); device->GetPixelShader(&old_pix_shader); if(!old_pix_shader) { _al_d3d_set_blender(d3d_disp); } if(!state.old_vtx_shader) { /* Prepare the default shader */ if(!is_legacy_card()) { if(decl) _al_setup_primitives_shader(device, decl); else _al_setup_default_primitives_shader(device, data.shader); } } } else { state.old_vtx_shader = NULL; _al_d3d_set_blender(d3d_disp); } /* Set the vertex declarations */ if(is_legacy_card() && !(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) { device->SetFVF(A5V_LEGACY_FVF); } else { if(decl) { device->SetVertexDeclaration((IDirect3DVertexDeclaration9*)decl->d3d_decl); } else { device->SetFVF(A5V_FVF); } } if(!state.old_vtx_shader || (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) { /* Set up the texture */ if (texture) { LPDIRECT3DTEXTURE9 d3d_texture; int tex_x, tex_y; D3DSURFACE_DESC desc; float mat[4][4] = { {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1} }; d3d_texture = al_get_d3d_video_texture(texture); d3d_texture->GetLevelDesc(0, &desc); al_get_d3d_texture_position(texture, &tex_x, &tex_y); if(decl) { if(decl->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL].attribute) { mat[0][0] = 1.0f / desc.Width; mat[1][1] = 1.0f / desc.Height; } else { mat[0][0] = (float)al_get_bitmap_width(texture) / desc.Width; mat[1][1] = (float)al_get_bitmap_height(texture) / desc.Height; } } else { mat[0][0] = 1.0f / desc.Width; mat[1][1] = 1.0f / desc.Height; } mat[2][0] = (float)tex_x / desc.Width; mat[2][1] = (float)tex_y / desc.Height; if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_SHADER_HLSL d3d_disp->effect->SetMatrix(ALLEGRO_SHADER_VAR_TEX_MATRIX, (D3DXMATRIX *)mat); d3d_disp->effect->SetBool(ALLEGRO_SHADER_VAR_USE_TEX_MATRIX, true); d3d_disp->effect->SetBool(ALLEGRO_SHADER_VAR_USE_TEX, true); d3d_disp->effect->SetTexture(ALLEGRO_SHADER_VAR_TEX, d3d_texture); #endif } else { if(is_legacy_card()) { device->GetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, &state.old_ttf_state); device->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2); device->SetTransform(D3DTS_TEXTURE0, (D3DMATRIX *)&mat); } else { _al_set_texture_matrix(device, mat[0]); } } device->SetTexture(0, d3d_texture); } else { /* Don't unbind the texture here if shaders are used, since the user may * have set the 0'th texture unit manually via the shader API. */ if (!(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) { device->SetTexture(0, NULL); } } } if (texture) { device->GetSamplerState(0, D3DSAMP_ADDRESSU, &state.old_wrap_state[0]); device->GetSamplerState(0, D3DSAMP_ADDRESSV, &state.old_wrap_state[1]); _al_set_d3d_sampler_state(device, 0, texture, true); } return state; } static void revert_state(D3D_STATE state, LPDIRECT3DDEVICE9 device, ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture) { ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target); ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)disp; (void)d3d_disp; #ifdef ALLEGRO_CFG_SHADER_HLSL if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { d3d_disp->effect->End(); d3d_disp->effect->SetBool(ALLEGRO_SHADER_VAR_USE_TEX_MATRIX, false); d3d_disp->effect->SetBool(ALLEGRO_SHADER_VAR_USE_TEX, false); } #endif if (texture) { device->SetSamplerState(0, D3DSAMP_ADDRESSU, state.old_wrap_state[0]); device->SetSamplerState(0, D3DSAMP_ADDRESSV, state.old_wrap_state[1]); } if(!state.old_vtx_shader && is_legacy_card() && texture) { device->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, state.old_ttf_state); } if (!(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) { if(!state.old_vtx_shader) device->SetVertexShader(0); } } static int draw_prim_raw(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, const void* vtx, const ALLEGRO_VERTEX_DECL* decl, const int* indices, int num_vtx, int type) { int stride; int num_primitives = 0; LPDIRECT3DDEVICE9 device; int min_idx = 0, max_idx = num_vtx - 1; ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target); ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)disp; UINT required_passes = 1; unsigned int i; D3D_STATE state; DISPLAY_LOCAL_DATA data; (void)d3d_disp; if (al_is_d3d_device_lost(disp)) { return 0; } if (is_legacy_card() && !(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) { stride = (int)sizeof(LEGACY_VERTEX); } else { stride = (decl ? decl->stride : (int)sizeof(ALLEGRO_VERTEX)); } /* Check for early exit */ if((is_legacy_card() && decl) || (decl && decl->d3d_decl == 0)) { if(!indices) return _al_draw_prim_soft(texture, vtx, decl, 0, num_vtx, type); else return _al_draw_prim_indexed_soft(texture, vtx, decl, indices, num_vtx, type); } int num_idx = num_vtx; if(indices) { int ii; for(ii = 0; ii < num_vtx; ii++) { int idx = indices[ii]; if(ii == 0) { min_idx = idx; max_idx = idx; } else if (idx < min_idx) { min_idx = idx; } else if (idx > max_idx) { max_idx = idx; } } num_idx = max_idx + 1 - min_idx; } device = al_get_d3d_device(disp); data = get_display_local_data(disp); state = setup_state(device, decl, target, texture, data); /* Convert vertices for legacy cards */ if(is_legacy_card()) { al_lock_mutex(d3d_mutex); vtx = convert_to_legacy_vertices(vtx, num_vtx, indices, type == ALLEGRO_PRIM_LINE_LOOP, disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE); } #ifdef ALLEGRO_CFG_SHADER_HLSL if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { d3d_disp->effect->Begin(&required_passes, 0); } #endif for (i = 0; i < required_passes; i++) { #ifdef ALLEGRO_CFG_SHADER_HLSL if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { d3d_disp->effect->BeginPass(i); } #endif if (!indices || is_legacy_card()) { switch (type) { case ALLEGRO_PRIM_LINE_LIST: { num_primitives = num_vtx / 2; device->DrawPrimitiveUP(D3DPT_LINELIST, num_primitives, vtx, stride); break; }; case ALLEGRO_PRIM_LINE_STRIP: { num_primitives = num_vtx - 1; device->DrawPrimitiveUP(D3DPT_LINESTRIP, num_primitives, vtx, stride); break; }; case ALLEGRO_PRIM_LINE_LOOP: { num_primitives = num_vtx - 1; device->DrawPrimitiveUP(D3DPT_LINESTRIP, num_primitives, vtx, stride); if(!is_legacy_card()) { int in[2]; in[0] = 0; in[1] = num_vtx-1; device->DrawIndexedPrimitiveUP(D3DPT_LINELIST, 0, num_vtx, 1, in, D3DFMT_INDEX32, vtx, stride); } else { device->DrawPrimitiveUP(D3DPT_LINELIST, 1, (char*)vtx + stride * (num_vtx - 1), stride); } break; }; case ALLEGRO_PRIM_TRIANGLE_LIST: { num_primitives = num_vtx / 3; device->DrawPrimitiveUP(D3DPT_TRIANGLELIST, num_primitives, vtx, stride); break; }; case ALLEGRO_PRIM_TRIANGLE_STRIP: { num_primitives = num_vtx - 2; device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, num_primitives, vtx, stride); break; }; case ALLEGRO_PRIM_TRIANGLE_FAN: { num_primitives = num_vtx - 2; device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, num_primitives, vtx, stride); break; }; case ALLEGRO_PRIM_POINT_LIST: { num_primitives = num_vtx; device->DrawPrimitiveUP(D3DPT_POINTLIST, num_primitives, vtx, stride); break; }; } } else { switch (type) { case ALLEGRO_PRIM_LINE_LIST: { num_primitives = num_vtx / 2; device->DrawIndexedPrimitiveUP(D3DPT_LINELIST, min_idx, num_idx, num_primitives, indices, D3DFMT_INDEX32, vtx, stride); break; }; case ALLEGRO_PRIM_LINE_STRIP: { num_primitives = num_vtx - 1; device->DrawIndexedPrimitiveUP(D3DPT_LINESTRIP, min_idx, num_idx, num_primitives, indices, D3DFMT_INDEX32, vtx, stride); break; }; case ALLEGRO_PRIM_LINE_LOOP: { int in[2]; num_primitives = num_vtx - 1; device->DrawIndexedPrimitiveUP(D3DPT_LINESTRIP, min_idx, num_idx, num_primitives, indices, D3DFMT_INDEX32, vtx, stride); in[0] = indices[0]; in[1] = indices[num_vtx-1]; min_idx = in[0] > in[1] ? in[1] : in[0]; max_idx = in[0] > in[1] ? in[0] : in[1]; num_idx = max_idx - min_idx + 1; device->DrawIndexedPrimitiveUP(D3DPT_LINELIST, min_idx, num_idx, 1, in, D3DFMT_INDEX32, vtx, stride); break; }; case ALLEGRO_PRIM_TRIANGLE_LIST: { num_primitives = num_vtx / 3; device->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, min_idx, num_idx, num_primitives, indices, D3DFMT_INDEX32, vtx, stride); break; }; case ALLEGRO_PRIM_TRIANGLE_STRIP: { num_primitives = num_vtx - 2; device->DrawIndexedPrimitiveUP(D3DPT_TRIANGLESTRIP, min_idx, num_idx, num_primitives, indices, D3DFMT_INDEX32, vtx, stride); break; }; case ALLEGRO_PRIM_TRIANGLE_FAN: { num_primitives = num_vtx - 2; device->DrawIndexedPrimitiveUP(D3DPT_TRIANGLEFAN, min_idx, num_idx, num_primitives, indices, D3DFMT_INDEX32, vtx, stride); break; }; case ALLEGRO_PRIM_POINT_LIST: { /* * D3D does not support point lists in indexed mode, so we draw them using the non-indexed mode. To gain at least a semblance * of speed, we detect consecutive runs of vertices and draw them using a single DrawPrimitiveUP call */ int ii = 0; int start_idx = indices[0]; int run_length = 0; for(ii = 0; ii < num_vtx; ii++) { run_length++; if(indices[ii] + 1 != indices[ii + 1] || ii == num_vtx - 1) { device->DrawPrimitiveUP(D3DPT_POINTLIST, run_length, (const char*)vtx + start_idx * stride, stride); if(ii != num_vtx - 1) start_idx = indices[ii + 1]; run_length = 0; } } break; }; } } #ifdef ALLEGRO_CFG_SHADER_HLSL if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { d3d_disp->effect->EndPass(); } #endif } if(is_legacy_card()) al_unlock_mutex(d3d_mutex); revert_state(state, device, target, texture); return num_primitives; } #endif int _al_draw_prim_directx(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, int start, int end, int type) { #ifdef ALLEGRO_CFG_D3D int stride = decl ? decl->stride : (int)sizeof(ALLEGRO_VERTEX); return draw_prim_raw(target, texture, (const char*)vtxs + start * stride, decl, 0, end - start, type); #else (void)target; (void)texture; (void)vtxs; (void)start; (void)end; (void)type; (void)decl; return 0; #endif } int _al_draw_prim_indexed_directx(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, const int* indices, int num_vtx, int type) { #ifdef ALLEGRO_CFG_D3D return draw_prim_raw(target, texture, vtxs, decl, indices, num_vtx, type); #else (void)target; (void)texture; (void)vtxs; (void)indices; (void)num_vtx; (void)type; (void)decl; return 0; #endif } #ifdef ALLEGRO_CFG_D3D static int draw_buffer_raw(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type) { int num_primitives = 0; int num_vtx = end - start; LPDIRECT3DDEVICE9 device; ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target); ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)disp; UINT required_passes = 1; unsigned int i; D3D_STATE state; DISPLAY_LOCAL_DATA data; (void)d3d_disp; if (al_is_d3d_device_lost(disp)) { return 0; } /* Check for early exit for legacy cards */ if (vertex_buffer->decl && vertex_buffer->decl->d3d_decl == 0) { return _al_draw_buffer_common_soft(vertex_buffer, texture, index_buffer, start, end, type); } device = al_get_d3d_device(disp); data = get_display_local_data(disp); state = setup_state(device, vertex_buffer->decl, target, texture, data); device->SetStreamSource(0, (IDirect3DVertexBuffer9*)vertex_buffer->common.handle, 0, vertex_buffer->decl ? vertex_buffer->decl->stride : (int)sizeof(ALLEGRO_VERTEX)); if (index_buffer) { device->SetIndices((IDirect3DIndexBuffer9*)index_buffer->common.handle); } #ifdef ALLEGRO_CFG_SHADER_HLSL if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { d3d_disp->effect->Begin(&required_passes, 0); } #endif for (i = 0; i < required_passes; i++) { #ifdef ALLEGRO_CFG_SHADER_HLSL if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { d3d_disp->effect->BeginPass(i); } #endif if (!index_buffer) { switch (type) { case ALLEGRO_PRIM_LINE_LIST: { num_primitives = num_vtx / 2; device->DrawPrimitive(D3DPT_LINELIST, start, num_primitives); break; }; case ALLEGRO_PRIM_LINE_STRIP: { num_primitives = num_vtx - 1; device->DrawPrimitive(D3DPT_LINESTRIP, start, num_primitives); break; }; case ALLEGRO_PRIM_LINE_LOOP: { int* indices; num_primitives = num_vtx - 1; device->DrawPrimitive(D3DPT_LINESTRIP, start, num_primitives); if (data.loop_index_buffer) { al_lock_mutex(d3d_mutex); indices = (int*)al_lock_index_buffer(data.loop_index_buffer, 0, 2, ALLEGRO_LOCK_WRITEONLY); ASSERT(indices); indices[0] = start; indices[1] = start + num_vtx - 1; al_unlock_index_buffer(data.loop_index_buffer); device->SetIndices((IDirect3DIndexBuffer9*)data.loop_index_buffer->common.handle); device->DrawIndexedPrimitive(D3DPT_LINESTRIP, 0, 0, al_get_vertex_buffer_size(vertex_buffer), 0, 1); al_unlock_mutex(d3d_mutex); } break; }; case ALLEGRO_PRIM_TRIANGLE_LIST: { num_primitives = num_vtx / 3; device->DrawPrimitive(D3DPT_TRIANGLELIST, start, num_primitives); break; }; case ALLEGRO_PRIM_TRIANGLE_STRIP: { num_primitives = num_vtx - 2; device->DrawPrimitive(D3DPT_TRIANGLESTRIP, start, num_primitives); break; }; case ALLEGRO_PRIM_TRIANGLE_FAN: { num_primitives = num_vtx - 2; device->DrawPrimitive(D3DPT_TRIANGLEFAN, start, num_primitives); break; }; case ALLEGRO_PRIM_POINT_LIST: { num_primitives = num_vtx; device->DrawPrimitive(D3DPT_POINTLIST, start, num_primitives); break; }; } } else { int vbuff_size = al_get_vertex_buffer_size(vertex_buffer); switch (type) { case ALLEGRO_PRIM_LINE_LIST: { num_primitives = num_vtx / 2; device->DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, vbuff_size, start, num_primitives); break; }; case ALLEGRO_PRIM_LINE_STRIP: { num_primitives = num_vtx - 1; device->DrawIndexedPrimitive(D3DPT_LINESTRIP, 0, 0, vbuff_size, start, num_primitives); break; }; case ALLEGRO_PRIM_LINE_LOOP: { /* Unimplemented, too hard to do in a consistent fashion. */ break; }; case ALLEGRO_PRIM_TRIANGLE_LIST: { num_primitives = num_vtx / 3; device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, vbuff_size, start, num_primitives); break; }; case ALLEGRO_PRIM_TRIANGLE_STRIP: { num_primitives = num_vtx - 2; device->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, vbuff_size, start, num_primitives); break; }; case ALLEGRO_PRIM_TRIANGLE_FAN: { num_primitives = num_vtx - 2; device->DrawIndexedPrimitive(D3DPT_TRIANGLEFAN, 0, 0, vbuff_size, start, num_primitives); break; }; case ALLEGRO_PRIM_POINT_LIST: { /* Unimplemented, too hard to do in a consistent fashion. */ break; }; } } #ifdef ALLEGRO_CFG_SHADER_HLSL if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { d3d_disp->effect->EndPass(); } #endif } if (is_legacy_card()) al_unlock_mutex(d3d_mutex); revert_state(state, device, target, texture); return num_primitives; } #endif int _al_draw_vertex_buffer_directx(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, int start, int end, int type) { #ifdef ALLEGRO_CFG_D3D return draw_buffer_raw(target, texture, vertex_buffer, NULL, start, end, type); #else (void)target; (void)texture; (void)vertex_buffer; (void)start; (void)end; (void)type; return 0; #endif } int _al_draw_indexed_buffer_directx(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type) { #ifdef ALLEGRO_CFG_D3D return draw_buffer_raw(target, texture, vertex_buffer, index_buffer, start, end, type); #else (void)target; (void)texture; (void)vertex_buffer; (void)index_buffer; (void)start; (void)end; (void)type; return 0; #endif } #ifdef ALLEGRO_CFG_D3D static int convert_storage(int storage) { switch(storage) { case ALLEGRO_PRIM_FLOAT_2: return D3DDECLTYPE_FLOAT2; break; case ALLEGRO_PRIM_FLOAT_3: return D3DDECLTYPE_FLOAT3; break; case ALLEGRO_PRIM_SHORT_2: return D3DDECLTYPE_SHORT2; break; case ALLEGRO_PRIM_FLOAT_1: return D3DDECLTYPE_FLOAT1; break; case ALLEGRO_PRIM_FLOAT_4: return D3DDECLTYPE_FLOAT4; break; case ALLEGRO_PRIM_UBYTE_4: return D3DDECLTYPE_UBYTE4; break; case ALLEGRO_PRIM_SHORT_4: return D3DDECLTYPE_SHORT4; break; case ALLEGRO_PRIM_NORMALIZED_UBYTE_4: return D3DDECLTYPE_UBYTE4N; break; case ALLEGRO_PRIM_NORMALIZED_SHORT_2: return D3DDECLTYPE_SHORT2N; break; case ALLEGRO_PRIM_NORMALIZED_SHORT_4: return D3DDECLTYPE_SHORT4N; break; case ALLEGRO_PRIM_NORMALIZED_USHORT_2: return D3DDECLTYPE_USHORT2N; break; case ALLEGRO_PRIM_NORMALIZED_USHORT_4: return D3DDECLTYPE_USHORT4N; break; case ALLEGRO_PRIM_HALF_FLOAT_2: return D3DDECLTYPE_FLOAT16_2; break; case ALLEGRO_PRIM_HALF_FLOAT_4: return D3DDECLTYPE_FLOAT16_4; break; default: ASSERT(0); return D3DDECLTYPE_UNUSED; } } #endif void _al_set_d3d_decl(ALLEGRO_DISPLAY* display, ALLEGRO_VERTEX_DECL* ret) { #ifdef ALLEGRO_CFG_D3D { LPDIRECT3DDEVICE9 device; D3DVERTEXELEMENT9 d3delements[ALLEGRO_PRIM_ATTR_NUM + 1]; int idx = 0; ALLEGRO_VERTEX_ELEMENT* e; D3DCAPS9 caps; device = al_get_d3d_device(display); device->GetDeviceCaps(&caps); if(caps.PixelShaderVersion < D3DPS_VERSION(3, 0)) { ret->d3d_decl = 0; } else { int i; e = &ret->elements[ALLEGRO_PRIM_POSITION]; if(e->attribute) { d3delements[idx].Stream = 0; d3delements[idx].Offset = e->offset; d3delements[idx].Type = convert_storage(e->storage); d3delements[idx].Method = D3DDECLMETHOD_DEFAULT; d3delements[idx].Usage = D3DDECLUSAGE_POSITION; d3delements[idx].UsageIndex = 0; idx++; } e = &ret->elements[ALLEGRO_PRIM_TEX_COORD]; if(!e->attribute) e = &ret->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL]; if(e->attribute) { d3delements[idx].Stream = 0; d3delements[idx].Offset = e->offset; d3delements[idx].Type = convert_storage(e->storage); d3delements[idx].Method = D3DDECLMETHOD_DEFAULT; d3delements[idx].Usage = D3DDECLUSAGE_TEXCOORD; d3delements[idx].UsageIndex = 0; idx++; } e = &ret->elements[ALLEGRO_PRIM_COLOR_ATTR]; if(e->attribute) { d3delements[idx].Stream = 0; d3delements[idx].Offset = e->offset; d3delements[idx].Type = D3DDECLTYPE_FLOAT4; d3delements[idx].Method = D3DDECLMETHOD_DEFAULT; d3delements[idx].Usage = D3DDECLUSAGE_TEXCOORD; d3delements[idx].UsageIndex = 1; idx++; } for (i = 0; i < _ALLEGRO_PRIM_MAX_USER_ATTR; i++) { e = &ret->elements[ALLEGRO_PRIM_USER_ATTR + i]; if (e->attribute) { d3delements[idx].Stream = 0; d3delements[idx].Offset = e->offset; d3delements[idx].Type = convert_storage(e->storage); d3delements[idx].Method = D3DDECLMETHOD_DEFAULT; d3delements[idx].Usage = D3DDECLUSAGE_TEXCOORD; d3delements[idx].UsageIndex = 2 + i; idx++; } } d3delements[idx].Stream = 0xFF; d3delements[idx].Offset = 0; d3delements[idx].Type = D3DDECLTYPE_UNUSED; d3delements[idx].Method = 0; d3delements[idx].Usage = 0; d3delements[idx].UsageIndex = 0; device->CreateVertexDeclaration(d3delements, (IDirect3DVertexDeclaration9**)&ret->d3d_decl); } _al_create_primitives_shader(device, ret); } #else (void)display; ret->d3d_decl = 0; #endif } bool _al_create_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER* buf, const void* initial_data, size_t num_vertices, int flags) { #ifdef ALLEGRO_CFG_D3D LPDIRECT3DDEVICE9 device; IDirect3DVertexBuffer9* d3d_vbuff; DWORD fvf = A5V_FVF; int stride = buf->decl ? buf->decl->stride : (int)sizeof(ALLEGRO_VERTEX); HRESULT res; void* locked_memory; /* There's just no point */ if (is_legacy_card()) { ALLEGRO_WARN("Cannot create vertex buffer for a legacy card.\n"); return false; } device = al_get_d3d_device(al_get_current_display()); if (buf->decl) { device->SetVertexDeclaration((IDirect3DVertexDeclaration9*)buf->decl->d3d_decl); fvf = 0; } res = device->CreateVertexBuffer(stride * num_vertices, !(flags & ALLEGRO_PRIM_BUFFER_READWRITE) ? D3DUSAGE_WRITEONLY : 0, fvf, D3DPOOL_MANAGED, &d3d_vbuff, 0); if (res != D3D_OK) { ALLEGRO_WARN("CreateVertexBuffer failed: %ld.\n", res); return false; } if (initial_data != NULL) { d3d_vbuff->Lock(0, 0, &locked_memory, 0); memcpy(locked_memory, initial_data, stride * num_vertices); d3d_vbuff->Unlock(); } buf->common.handle = (uintptr_t)d3d_vbuff; return true; #else (void)buf; (void)initial_data; (void)num_vertices; (void)flags; return false; #endif } bool _al_create_index_buffer_directx(ALLEGRO_INDEX_BUFFER* buf, const void* initial_data, size_t num_indices, int flags) { #ifdef ALLEGRO_CFG_D3D LPDIRECT3DDEVICE9 device; IDirect3DIndexBuffer9* d3d_ibuff; HRESULT res; void* locked_memory; /* There's just no point */ if (is_legacy_card()) { ALLEGRO_WARN("Cannot create index buffer for a legacy card.\n"); return false; } device = al_get_d3d_device(al_get_current_display()); res = device->CreateIndexBuffer(num_indices * buf->index_size, !(flags & ALLEGRO_PRIM_BUFFER_READWRITE) ? D3DUSAGE_WRITEONLY : 0, buf->index_size == 4 ? D3DFMT_INDEX32 : D3DFMT_INDEX16, D3DPOOL_MANAGED, &d3d_ibuff, 0); if (res != D3D_OK) { ALLEGRO_WARN("CreateIndexBuffer failed: %ld.\n", res); return false; } if (initial_data != NULL) { d3d_ibuff->Lock(0, 0, &locked_memory, 0); memcpy(locked_memory, initial_data, num_indices * buf->index_size); d3d_ibuff->Unlock(); } buf->common.handle = (uintptr_t)d3d_ibuff; return true; #else (void)buf; (void)initial_data; (void)num_indices; (void)flags; return false; #endif } void _al_destroy_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER* buf) { #ifdef ALLEGRO_CFG_D3D ((IDirect3DVertexBuffer9*)buf->common.handle)->Release(); #else (void)buf; #endif } void _al_destroy_index_buffer_directx(ALLEGRO_INDEX_BUFFER* buf) { #ifdef ALLEGRO_CFG_D3D ((IDirect3DIndexBuffer9*)buf->common.handle)->Release(); #else (void)buf; #endif } void* _al_lock_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER* buf) { #ifdef ALLEGRO_CFG_D3D DWORD flags = buf->common.lock_flags == ALLEGRO_LOCK_READONLY ? D3DLOCK_READONLY : 0; HRESULT res; res = ((IDirect3DVertexBuffer9*)buf->common.handle)->Lock((UINT)buf->common.lock_offset, (UINT)buf->common.lock_length, &buf->common.locked_memory, flags); if (res != D3D_OK) { ALLEGRO_WARN("Locking vertex buffer failed: %ld.\n", res); return 0; } return buf->common.locked_memory; #else (void)buf; return 0; #endif } void* _al_lock_index_buffer_directx(ALLEGRO_INDEX_BUFFER* buf) { #ifdef ALLEGRO_CFG_D3D DWORD flags = buf->common.lock_flags == ALLEGRO_LOCK_READONLY ? D3DLOCK_READONLY : 0; HRESULT res; res = ((IDirect3DIndexBuffer9*)buf->common.handle)->Lock((UINT)buf->common.lock_offset, (UINT)buf->common.lock_length, &buf->common.locked_memory, flags); if (res != D3D_OK) { ALLEGRO_WARN("Locking index buffer failed: %ld.\n", res); return 0; } return buf->common.locked_memory; #else (void)buf; return 0; #endif } void _al_unlock_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER* buf) { #ifdef ALLEGRO_CFG_D3D ((IDirect3DVertexBuffer9*)buf->common.handle)->Unlock(); #else (void)buf; #endif } void _al_unlock_index_buffer_directx(ALLEGRO_INDEX_BUFFER* buf) { #ifdef ALLEGRO_CFG_D3D ((IDirect3DIndexBuffer9*)buf->common.handle)->Unlock(); #else (void)buf; #endif } allegro5-5.2.10.1/addons/primitives/prim_opengl.c000066400000000000000000000627401473414355200216130ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * OpenGL implementation of some of the primitive routines. * * * By Pavel Sountsov. * * See readme.txt for copyright information. */ #define ALLEGRO_INTERNAL_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/allegro_primitives.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_prim_opengl.h" #include "allegro5/internal/aintern_prim_soft.h" #include "allegro5/platform/alplatf.h" #include "allegro5/internal/aintern_prim.h" #ifdef ALLEGRO_CFG_OPENGL #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern_opengl.h" static void convert_storage(ALLEGRO_PRIM_STORAGE storage, GLenum* type, int* ncoord, bool* normalized) { switch(storage) { case ALLEGRO_PRIM_FLOAT_2: *type = GL_FLOAT; *ncoord = 2; *normalized = false; break; case ALLEGRO_PRIM_FLOAT_3: *type = GL_FLOAT; *ncoord = 3; *normalized = false; break; case ALLEGRO_PRIM_SHORT_2: *type = GL_SHORT; *ncoord = 2; *normalized = false; break; case ALLEGRO_PRIM_FLOAT_1: *type = GL_FLOAT; *ncoord = 1; *normalized = false; break; case ALLEGRO_PRIM_FLOAT_4: *type = GL_FLOAT; *ncoord = 4; *normalized = false; break; case ALLEGRO_PRIM_UBYTE_4: *type = GL_UNSIGNED_BYTE; *ncoord = 4; *normalized = false; break; case ALLEGRO_PRIM_SHORT_4: *type = GL_SHORT; *ncoord = 4; *normalized = false; break; case ALLEGRO_PRIM_NORMALIZED_UBYTE_4: *type = GL_UNSIGNED_BYTE; *ncoord = 4; *normalized = true; break; case ALLEGRO_PRIM_NORMALIZED_SHORT_2: *type = GL_SHORT; *ncoord = 2; *normalized = true; break; case ALLEGRO_PRIM_NORMALIZED_SHORT_4: *type = GL_SHORT; *ncoord = 4; *normalized = true; break; case ALLEGRO_PRIM_NORMALIZED_USHORT_2: *type = GL_UNSIGNED_SHORT; *ncoord = 2; *normalized = true; break; case ALLEGRO_PRIM_NORMALIZED_USHORT_4: *type = GL_UNSIGNED_SHORT; *ncoord = 4; *normalized = true; break; #ifndef ALLEGRO_CFG_OPENGLES case ALLEGRO_PRIM_HALF_FLOAT_2: *type = GL_HALF_FLOAT; *ncoord = 2; *normalized = false; break; case ALLEGRO_PRIM_HALF_FLOAT_4: *type = GL_HALF_FLOAT; *ncoord = 4; *normalized = false; break; #endif default: ASSERT(0); } } static void setup_state(const char* vtxs, const ALLEGRO_VERTEX_DECL* decl, ALLEGRO_BITMAP* texture) { ALLEGRO_DISPLAY *display = al_get_current_display(); GLenum type; int ncoord; bool normalized; if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if(decl) { ALLEGRO_VERTEX_ELEMENT* e; int i; e = &decl->elements[ALLEGRO_PRIM_POSITION]; if(e->attribute) { convert_storage(e->storage, &type, &ncoord, &normalized); if (display->ogl_extras->varlocs.pos_loc >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.pos_loc, ncoord, type, normalized, decl->stride, vtxs + e->offset); glEnableVertexAttribArray(display->ogl_extras->varlocs.pos_loc); } } else { if (display->ogl_extras->varlocs.pos_loc >= 0) { glDisableVertexAttribArray(display->ogl_extras->varlocs.pos_loc); } } e = &decl->elements[ALLEGRO_PRIM_TEX_COORD]; if(!e->attribute) e = &decl->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL]; if(e->attribute) { convert_storage(e->storage, &type, &ncoord, &normalized); if (display->ogl_extras->varlocs.texcoord_loc >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.texcoord_loc, ncoord, type, normalized, decl->stride, vtxs + e->offset); glEnableVertexAttribArray(display->ogl_extras->varlocs.texcoord_loc); } } else { if (display->ogl_extras->varlocs.texcoord_loc >= 0) { glDisableVertexAttribArray(display->ogl_extras->varlocs.texcoord_loc); } } e = &decl->elements[ALLEGRO_PRIM_COLOR_ATTR]; if(e->attribute) { if (display->ogl_extras->varlocs.color_loc >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.color_loc, 4, GL_FLOAT, true, decl->stride, vtxs + e->offset); glEnableVertexAttribArray(display->ogl_extras->varlocs.color_loc); } } else { if (display->ogl_extras->varlocs.color_loc >= 0) { glDisableVertexAttribArray(display->ogl_extras->varlocs.color_loc); } } for (i = 0; i < _ALLEGRO_PRIM_MAX_USER_ATTR; i++) { e = &decl->elements[ALLEGRO_PRIM_USER_ATTR + i]; if (e->attribute) { convert_storage(e->storage, &type, &ncoord, &normalized); if (display->ogl_extras->varlocs.user_attr_loc[i] >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.user_attr_loc[i], ncoord, type, normalized, decl->stride, vtxs + e->offset); glEnableVertexAttribArray(display->ogl_extras->varlocs.user_attr_loc[i]); } } else { if (display->ogl_extras->varlocs.user_attr_loc[i] >= 0) { glDisableVertexAttribArray(display->ogl_extras->varlocs.user_attr_loc[i]); } } } } else { if (display->ogl_extras->varlocs.pos_loc >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.pos_loc, 3, GL_FLOAT, false, sizeof(ALLEGRO_VERTEX), vtxs + offsetof(ALLEGRO_VERTEX, x)); glEnableVertexAttribArray(display->ogl_extras->varlocs.pos_loc); } if (display->ogl_extras->varlocs.texcoord_loc >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.texcoord_loc, 2, GL_FLOAT, false, sizeof(ALLEGRO_VERTEX), vtxs + offsetof(ALLEGRO_VERTEX, u)); glEnableVertexAttribArray(display->ogl_extras->varlocs.texcoord_loc); } if (display->ogl_extras->varlocs.color_loc >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.color_loc, 4, GL_FLOAT, true, sizeof(ALLEGRO_VERTEX), vtxs + offsetof(ALLEGRO_VERTEX, color)); glEnableVertexAttribArray(display->ogl_extras->varlocs.color_loc); } } #endif } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION if(decl) { ALLEGRO_VERTEX_ELEMENT* e; e = &decl->elements[ALLEGRO_PRIM_POSITION]; if(e->attribute) { glEnableClientState(GL_VERTEX_ARRAY); convert_storage(e->storage, &type, &ncoord, &normalized); glVertexPointer(ncoord, type, decl->stride, vtxs + e->offset); } else { glDisableClientState(GL_VERTEX_ARRAY); } e = &decl->elements[ALLEGRO_PRIM_TEX_COORD]; if(!e->attribute) e = &decl->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL]; if(texture && e->attribute) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); convert_storage(e->storage, &type, &ncoord, &normalized); glTexCoordPointer(ncoord, type, decl->stride, vtxs + e->offset); } else { glDisableClientState(GL_TEXTURE_COORD_ARRAY); } e = &decl->elements[ALLEGRO_PRIM_COLOR_ATTR]; if(e->attribute) { glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_FLOAT, decl->stride, vtxs + e->offset); } else { glDisableClientState(GL_COLOR_ARRAY); glColor4f(1, 1, 1, 1); } } else { glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); if (!(display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) glDisableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(ALLEGRO_VERTEX), vtxs + offsetof(ALLEGRO_VERTEX, x)); glColorPointer(4, GL_FLOAT, sizeof(ALLEGRO_VERTEX), vtxs + offsetof(ALLEGRO_VERTEX, color)); glTexCoordPointer(2, GL_FLOAT, sizeof(ALLEGRO_VERTEX), vtxs + offsetof(ALLEGRO_VERTEX, u)); } #endif } if (texture) { GLuint gl_texture = al_get_opengl_texture(texture); int true_w, true_h; int tex_x, tex_y; float mat[4][4] = { {1, 0, 0, 0}, {0, -1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1} }; int height; if (texture->parent) height = texture->parent->h; else height = texture->h; al_get_opengl_texture_size(texture, &true_w, &true_h); al_get_opengl_texture_position(texture, &tex_x, &tex_y); mat[3][0] = (float)tex_x / true_w; mat[3][1] = (float)(height - tex_y) / true_h; if(decl) { if(decl->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL].attribute) { mat[0][0] = 1.0f / true_w; mat[1][1] = -1.0f / true_h; } else { mat[0][0] = (float)al_get_bitmap_width(texture) / true_w; mat[1][1] = -(float)al_get_bitmap_height(texture) / true_h; } } else { mat[0][0] = 1.0f / true_w; mat[1][1] = -1.0f / true_h; } if (!(display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) { glBindTexture(GL_TEXTURE_2D, gl_texture); } ALLEGRO_BITMAP_WRAP wrap_u, wrap_v; _al_get_bitmap_wrap(texture, &wrap_u, &wrap_v); if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE GLint handle; handle = display->ogl_extras->varlocs.tex_matrix_loc; if (handle >= 0) glUniformMatrix4fv(handle, 1, false, (float *)mat); handle = display->ogl_extras->varlocs.use_tex_matrix_loc; if (handle >= 0) glUniform1i(handle, 1); if (display->ogl_extras->varlocs.use_tex_loc >= 0) { glUniform1i(display->ogl_extras->varlocs.use_tex_loc, 1); } if (display->ogl_extras->varlocs.tex_loc >= 0) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, al_get_opengl_texture(texture)); glUniform1i(display->ogl_extras->varlocs.tex_loc, 0); // 0th sampler if (wrap_u == ALLEGRO_BITMAP_WRAP_DEFAULT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); if (wrap_v == ALLEGRO_BITMAP_WRAP_DEFAULT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } #endif } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION glMatrixMode(GL_TEXTURE); glLoadMatrixf(mat[0]); glMatrixMode(GL_MODELVIEW); glEnable(GL_TEXTURE_2D); if (wrap_u == ALLEGRO_BITMAP_WRAP_DEFAULT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); if (wrap_v == ALLEGRO_BITMAP_WRAP_DEFAULT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); #endif } } else { /* Don't unbind the texture here if shaders are used, since the user may * have set the 0'th texture unit manually via the shader API. */ if (!(display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) { glBindTexture(GL_TEXTURE_2D, 0); } } } static void revert_state(ALLEGRO_BITMAP* texture) { ALLEGRO_DISPLAY *display = al_get_current_display(); if(texture) { ALLEGRO_BITMAP_WRAP wrap_u, wrap_v; _al_get_bitmap_wrap(texture, &wrap_u, &wrap_v); if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE float identity[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; GLint handle; handle = display->ogl_extras->varlocs.tex_matrix_loc; if (handle >= 0) glUniformMatrix4fv(handle, 1, false, identity); handle = display->ogl_extras->varlocs.use_tex_matrix_loc; if (handle >= 0) glUniform1i(handle, 0); if (display->ogl_extras->varlocs.use_tex_loc >= 0) glUniform1i(display->ogl_extras->varlocs.use_tex_loc, 0); if (display->ogl_extras->varlocs.tex_loc >= 0) { if (wrap_u == ALLEGRO_BITMAP_WRAP_DEFAULT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); if (wrap_v == ALLEGRO_BITMAP_WRAP_DEFAULT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } #endif } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION if (wrap_u == ALLEGRO_BITMAP_WRAP_DEFAULT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); if (wrap_v == ALLEGRO_BITMAP_WRAP_DEFAULT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glDisable(GL_TEXTURE_2D); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); #endif } } if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.pos_loc >= 0) glDisableVertexAttribArray(display->ogl_extras->varlocs.pos_loc); if (display->ogl_extras->varlocs.color_loc >= 0) glDisableVertexAttribArray(display->ogl_extras->varlocs.color_loc); if (display->ogl_extras->varlocs.texcoord_loc >= 0) glDisableVertexAttribArray(display->ogl_extras->varlocs.texcoord_loc); #endif } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); #endif } } static int draw_prim_raw(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, const void* vtx, const ALLEGRO_VERTEX_DECL* decl, int start, int end, int type) { int num_primitives = 0; ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target); ALLEGRO_BITMAP *opengl_target = target; ALLEGRO_BITMAP_EXTRA_OPENGL *extra; int num_vtx = end - start; if (target->parent) { opengl_target = target->parent; } extra = opengl_target->extra; if ((!extra->is_backbuffer && disp->ogl_extras->opengl_target != opengl_target) || al_is_bitmap_locked(target)) { if (vertex_buffer) { return _al_draw_buffer_common_soft(vertex_buffer, texture, NULL, start, end, type); } else { return _al_draw_prim_soft(texture, vtx, decl, start, end, type); } } if (vertex_buffer) { glBindBuffer(GL_ARRAY_BUFFER, (GLuint)vertex_buffer->common.handle); } _al_opengl_set_blender(disp); setup_state(vtx, decl, texture); switch (type) { case ALLEGRO_PRIM_LINE_LIST: { glDrawArrays(GL_LINES, start, num_vtx); num_primitives = num_vtx / 2; break; }; case ALLEGRO_PRIM_LINE_STRIP: { glDrawArrays(GL_LINE_STRIP, start, num_vtx); num_primitives = num_vtx - 1; break; }; case ALLEGRO_PRIM_LINE_LOOP: { glDrawArrays(GL_LINE_LOOP, start, num_vtx); num_primitives = num_vtx; break; }; case ALLEGRO_PRIM_TRIANGLE_LIST: { glDrawArrays(GL_TRIANGLES, start, num_vtx); num_primitives = num_vtx / 3; break; }; case ALLEGRO_PRIM_TRIANGLE_STRIP: { glDrawArrays(GL_TRIANGLE_STRIP, start, num_vtx); num_primitives = num_vtx - 2; break; }; case ALLEGRO_PRIM_TRIANGLE_FAN: { glDrawArrays(GL_TRIANGLE_FAN, start, num_vtx); num_primitives = num_vtx - 2; break; }; case ALLEGRO_PRIM_POINT_LIST: { glDrawArrays(GL_POINTS, start, num_vtx); num_primitives = num_vtx; break; }; } revert_state(texture); if (vertex_buffer) { glBindBuffer(GL_ARRAY_BUFFER, 0); } return num_primitives; } static int draw_prim_indexed_raw(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, const void* vtx, const ALLEGRO_VERTEX_DECL* decl, ALLEGRO_INDEX_BUFFER* index_buffer, const int* indices, int start, int end, int type) { int num_primitives = 0; ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target); ALLEGRO_BITMAP *opengl_target = target; ALLEGRO_BITMAP_EXTRA_OPENGL *extra; const char* idx = (const char*)indices; int start_offset = 0; GLenum idx_size = GL_UNSIGNED_INT; bool use_buffers = index_buffer != NULL; int num_vtx = end - start; #if defined ALLEGRO_IPHONE GLushort* iphone_idx = NULL; #endif if (use_buffers) { idx_size = index_buffer->index_size == 4 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; start_offset = start * index_buffer->index_size; } if (target->parent) { opengl_target = target->parent; } extra = opengl_target->extra; if ((!extra->is_backbuffer && disp->ogl_extras->opengl_target != opengl_target) || al_is_bitmap_locked(target)) { if (use_buffers) { return _al_draw_buffer_common_soft(vertex_buffer, texture, index_buffer, start, end, type); } else { return _al_draw_prim_indexed_soft(texture, vtx, decl, indices, num_vtx, type); } } #if defined ALLEGRO_IPHONE if (!use_buffers) { int ii; iphone_idx = al_malloc(num_vtx * sizeof(GLushort)); for (ii = start; ii < end; ii++) { iphone_idx[ii] = (GLushort)indices[ii]; } idx = iphone_idx; start = 0; idx_size = GL_UNSIGNED_SHORT; } #endif _al_opengl_set_blender(disp); if (use_buffers) { glBindBuffer(GL_ARRAY_BUFFER, (GLuint)vertex_buffer->common.handle); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)index_buffer->common.handle); } setup_state(vtx, decl, texture); switch (type) { case ALLEGRO_PRIM_LINE_LIST: { glDrawElements(GL_LINES, num_vtx, idx_size, idx + start_offset); num_primitives = num_vtx / 2; break; }; case ALLEGRO_PRIM_LINE_STRIP: { glDrawElements(GL_LINE_STRIP, num_vtx, idx_size, idx + start_offset); num_primitives = num_vtx - 1; break; }; case ALLEGRO_PRIM_LINE_LOOP: { /* Unimplemented, as it's too hard to do for Direct3D */ break; }; case ALLEGRO_PRIM_TRIANGLE_LIST: { glDrawElements(GL_TRIANGLES, num_vtx, idx_size, idx + start_offset); num_primitives = num_vtx / 3; break; }; case ALLEGRO_PRIM_TRIANGLE_STRIP: { glDrawElements(GL_TRIANGLE_STRIP, num_vtx, idx_size, idx + start_offset); num_primitives = num_vtx - 2; break; }; case ALLEGRO_PRIM_TRIANGLE_FAN: { glDrawElements(GL_TRIANGLE_FAN, num_vtx, idx_size, idx + start_offset); num_primitives = num_vtx - 2; break; }; case ALLEGRO_PRIM_POINT_LIST: { /* Unimplemented, as it's too hard to do for Direct3D */ break; }; } revert_state(texture); if (use_buffers) { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } #if defined ALLEGRO_IPHONE al_free(iphone_idx); #endif return num_primitives; } #endif /* ALLEGRO_CFG_OPENGL */ int _al_draw_prim_opengl(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, int start, int end, int type) { #ifdef ALLEGRO_CFG_OPENGL return draw_prim_raw(target, texture, 0, vtxs, decl, start, end, type); #else (void)target; (void)texture; (void)vtxs; (void)start; (void)end; (void)type; (void)decl; return 0; #endif } int _al_draw_vertex_buffer_opengl(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, int start, int end, int type) { #ifdef ALLEGRO_CFG_OPENGL return draw_prim_raw(target, texture, vertex_buffer, 0, vertex_buffer->decl, start, end, type); #else (void)target; (void)texture; (void)vertex_buffer; (void)start; (void)end; (void)type; return 0; #endif } int _al_draw_prim_indexed_opengl(ALLEGRO_BITMAP *target, ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, const int* indices, int num_vtx, int type) { #ifdef ALLEGRO_CFG_OPENGL return draw_prim_indexed_raw(target, texture, NULL, vtxs, decl, NULL, indices, 0, num_vtx, type); #else (void)target; (void)texture; (void)vtxs; (void)decl; (void)indices; (void)num_vtx; (void)type; return 0; #endif } int _al_draw_indexed_buffer_opengl(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type) { #ifdef ALLEGRO_CFG_OPENGL return draw_prim_indexed_raw(target, texture, vertex_buffer, NULL, vertex_buffer->decl, index_buffer, NULL, start, end, type); #else (void)target; (void)texture; (void)vertex_buffer; (void)index_buffer; (void)start; (void)end; (void)type; return 0; #endif } #ifdef ALLEGRO_CFG_OPENGL static bool create_buffer_common(ALLEGRO_BUFFER_COMMON* common, GLenum type, const void* initial_data, GLsizeiptr size, int flags) { GLuint vbo; GLenum usage; switch (flags) { #if !defined ALLEGRO_CFG_OPENGLES case ALLEGRO_PRIM_BUFFER_STREAM: usage = GL_STREAM_DRAW; break; #endif case ALLEGRO_PRIM_BUFFER_STATIC: usage = GL_STATIC_DRAW; break; case ALLEGRO_PRIM_BUFFER_DYNAMIC: usage = GL_DYNAMIC_DRAW; break; default: usage = GL_STATIC_DRAW; } glGenBuffers(1, &vbo); glBindBuffer(type, vbo); glBufferData(type, size, initial_data, usage); glBindBuffer(type, 0); if (glGetError()) return false; common->handle = vbo; common->local_buffer_length = 0; return true; } #endif bool _al_create_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER* buf, const void* initial_data, size_t num_vertices, int flags) { #ifdef ALLEGRO_CFG_OPENGL int stride = buf->decl ? buf->decl->stride : (int)sizeof(ALLEGRO_VERTEX); return create_buffer_common(&buf->common, GL_ARRAY_BUFFER, initial_data, num_vertices * stride, flags); #else (void)buf; (void)initial_data; (void)num_vertices; (void)flags; return false; #endif } bool _al_create_index_buffer_opengl(ALLEGRO_INDEX_BUFFER* buf, const void* initial_data, size_t num_indices, int flags) { #ifdef ALLEGRO_CFG_OPENGL return create_buffer_common(&buf->common, GL_ELEMENT_ARRAY_BUFFER, initial_data, num_indices * buf->index_size, flags);; #else (void)buf; (void)initial_data; (void)num_indices; (void)flags; return false; #endif } void _al_destroy_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER* buf) { #ifdef ALLEGRO_CFG_OPENGL glDeleteBuffers(1, (GLuint*)&buf->common.handle); al_free(buf->common.locked_memory); #else (void)buf; #endif } void _al_destroy_index_buffer_opengl(ALLEGRO_INDEX_BUFFER* buf) { #ifdef ALLEGRO_CFG_OPENGL glDeleteBuffers(1, (GLuint*)&buf->common.handle); al_free(buf->common.locked_memory); #else (void)buf; #endif } #ifdef ALLEGRO_CFG_OPENGL static void* lock_buffer_common(ALLEGRO_BUFFER_COMMON* common, GLenum type) { if (common->local_buffer_length < common->lock_length) { common->locked_memory = al_realloc(common->locked_memory, common->lock_length); common->local_buffer_length = common->lock_length; } if (common->lock_flags != ALLEGRO_LOCK_WRITEONLY) { #if !defined ALLEGRO_CFG_OPENGLES glBindBuffer(type, (GLuint)common->handle); glGetBufferSubData(type, common->lock_offset, common->lock_length, common->locked_memory); glBindBuffer(type, 0); if (glGetError()) return 0; #else (void)type; return 0; #endif } return common->locked_memory; } #endif void* _al_lock_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER* buf) { #ifdef ALLEGRO_CFG_OPENGL return lock_buffer_common(&buf->common, GL_ARRAY_BUFFER); #else (void)buf; return 0; #endif } void* _al_lock_index_buffer_opengl(ALLEGRO_INDEX_BUFFER* buf) { #ifdef ALLEGRO_CFG_OPENGL return lock_buffer_common(&buf->common, GL_ELEMENT_ARRAY_BUFFER); #else (void)buf; return 0; #endif } #ifdef ALLEGRO_CFG_OPENGL static void unlock_buffer_common(ALLEGRO_BUFFER_COMMON* common, GLenum type) { if (common->lock_flags != ALLEGRO_LOCK_READONLY) { glBindBuffer(type, (GLuint)common->handle); glBufferSubData(type, common->lock_offset, common->lock_length, common->locked_memory); glBindBuffer(type, 0); } } #endif void _al_unlock_vertex_buffer_opengl(ALLEGRO_VERTEX_BUFFER* buf) { #ifdef ALLEGRO_CFG_OPENGL unlock_buffer_common(&buf->common, GL_ARRAY_BUFFER); #else (void)buf; #endif } void _al_unlock_index_buffer_opengl(ALLEGRO_INDEX_BUFFER* buf) { #ifdef ALLEGRO_CFG_OPENGL unlock_buffer_common(&buf->common, GL_ELEMENT_ARRAY_BUFFER); #else (void)buf; #endif } allegro5-5.2.10.1/addons/primitives/prim_soft.c000066400000000000000000000410101473414355200212650ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Software implementation of some of the primitive routines. * * * By Pavel Sountsov. * * See readme.txt for copyright information. */ #define ALLEGRO_INTERNAL_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/allegro_primitives.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_prim_soft.h" #include "allegro5/internal/aintern_prim.h" #include "allegro5/internal/aintern_tri_soft.h" /* The vertex cache allows for bulk transformation of vertices, for faster run speeds */ #define LOCAL_VERTEX_CACHE ALLEGRO_VERTEX vertex_cache[ALLEGRO_VERTEX_CACHE_SIZE] static void convert_vtx(ALLEGRO_BITMAP* texture, const char* src, ALLEGRO_VERTEX* dest, const ALLEGRO_VERTEX_DECL* decl) { ALLEGRO_VERTEX_ELEMENT* e; if(!decl) { *dest = *((ALLEGRO_VERTEX*)src); return; } e = &decl->elements[ALLEGRO_PRIM_POSITION]; if(e->attribute) { switch(e->storage) { case ALLEGRO_PRIM_FLOAT_2: case ALLEGRO_PRIM_FLOAT_3: { float *ptr = (float*)(src + e->offset); dest->x = *(ptr); dest->y = *(ptr + 1); break; } case ALLEGRO_PRIM_SHORT_2: { short *ptr = (short*)(src + e->offset); dest->x = (float)*(ptr); dest->y = (float)*(ptr + 1); break; } } } else { dest->x = 0; dest->y = 0; } e = &decl->elements[ALLEGRO_PRIM_TEX_COORD]; if(!e->attribute) e = &decl->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL]; if(e->attribute) { switch(e->storage) { case ALLEGRO_PRIM_FLOAT_2: case ALLEGRO_PRIM_FLOAT_3: { float *ptr = (float*)(src + e->offset); dest->u = *(ptr); dest->v = *(ptr + 1); break; } case ALLEGRO_PRIM_SHORT_2: { short *ptr = (short*)(src + e->offset); dest->u = (float)*(ptr); dest->v = (float)*(ptr + 1); break; } } if(texture && e->attribute == ALLEGRO_PRIM_TEX_COORD) { dest->u *= (float)al_get_bitmap_width(texture); dest->v *= (float)al_get_bitmap_height(texture); } } else { dest->u = 0; dest->v = 0; } e = &decl->elements[ALLEGRO_PRIM_COLOR_ATTR]; if(e->attribute) { dest->color = *(ALLEGRO_COLOR*)(src + e->offset); } else { dest->color = al_map_rgba_f(1,1,1,1); } } int _al_draw_prim_soft(ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, int start, int end, int type) { LOCAL_VERTEX_CACHE; int num_primitives; int num_vtx; int use_cache; int stride = decl ? decl->stride : (int)sizeof(ALLEGRO_VERTEX); const ALLEGRO_TRANSFORM* global_trans = al_get_current_transform(); num_primitives = 0; num_vtx = end - start; use_cache = num_vtx < ALLEGRO_VERTEX_CACHE_SIZE; if (texture) al_lock_bitmap(texture, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); if (use_cache) { int ii; int n = 0; const char* vtxptr = (const char*)vtxs + start * stride; for (ii = 0; ii < num_vtx; ii++) { convert_vtx(texture, vtxptr, &vertex_cache[ii], decl); al_transform_coordinates(global_trans, &vertex_cache[ii].x, &vertex_cache[ii].y); n++; vtxptr += stride; } } #define SET_VERTEX(v, idx) \ convert_vtx(texture, (const char*)vtxs + stride * (idx), &v, decl); \ al_transform_coordinates(global_trans, &v.x, &v.y); \ switch (type) { case ALLEGRO_PRIM_LINE_LIST: { if (use_cache) { int ii; for (ii = 0; ii < num_vtx - 1; ii += 2) { _al_line_2d(texture, &vertex_cache[ii], &vertex_cache[ii + 1]); } } else { int ii; for (ii = start; ii < end - 1; ii += 2) { ALLEGRO_VERTEX v1, v2; SET_VERTEX(v1, ii); SET_VERTEX(v2, ii + 1); _al_line_2d(texture, &v1, &v2); } } num_primitives = num_vtx / 2; break; }; case ALLEGRO_PRIM_LINE_STRIP: { if (use_cache) { int ii; for (ii = 1; ii < num_vtx; ii++) { _al_line_2d(texture, &vertex_cache[ii - 1], &vertex_cache[ii]); } } else { int ii; int idx = 1; ALLEGRO_VERTEX vtx[2]; SET_VERTEX(vtx[0], start); for (ii = start + 1; ii < end; ii++) { SET_VERTEX(vtx[idx], ii) _al_line_2d(texture, &vtx[0], &vtx[1]); idx = 1 - idx; } } num_primitives = num_vtx - 1; break; }; case ALLEGRO_PRIM_LINE_LOOP: { if (use_cache) { int ii; for (ii = 1; ii < num_vtx; ii++) { _al_line_2d(texture, &vertex_cache[ii - 1], &vertex_cache[ii]); } _al_line_2d(texture, &vertex_cache[num_vtx - 1], &vertex_cache[0]); } else { int ii; int idx = 1; ALLEGRO_VERTEX vtx[2]; SET_VERTEX(vtx[0], start); for (ii = start + 1; ii < end; ii++) { SET_VERTEX(vtx[idx], ii) _al_line_2d(texture, &vtx[idx], &vtx[1 - idx]); idx = 1 - idx; } SET_VERTEX(vtx[idx], start) _al_line_2d(texture, &vtx[idx], &vtx[1 - idx]); } num_primitives = num_vtx; break; }; case ALLEGRO_PRIM_TRIANGLE_LIST: { if (use_cache) { int ii; for (ii = 0; ii < num_vtx - 2; ii += 3) { _al_triangle_2d(texture, &vertex_cache[ii], &vertex_cache[ii + 1], &vertex_cache[ii + 2]); } } else { int ii; for (ii = start; ii < end - 2; ii += 3) { ALLEGRO_VERTEX v1, v2, v3; SET_VERTEX(v1, ii); SET_VERTEX(v2, ii + 1); SET_VERTEX(v3, ii + 2); _al_triangle_2d(texture, &v1, &v2, &v3); } } num_primitives = num_vtx / 3; break; }; case ALLEGRO_PRIM_TRIANGLE_STRIP: { if (use_cache) { int ii; for (ii = 2; ii < num_vtx; ii++) { _al_triangle_2d(texture, &vertex_cache[ii - 2], &vertex_cache[ii - 1], &vertex_cache[ii]); } } else { int ii; int idx = 2; ALLEGRO_VERTEX vtx[3]; SET_VERTEX(vtx[0], start); SET_VERTEX(vtx[1], start + 1); for (ii = start + 2; ii < end; ii++) { SET_VERTEX(vtx[idx], ii); _al_triangle_2d(texture, &vtx[0], &vtx[1], &vtx[2]); idx = (idx + 1) % 3; } } num_primitives = num_vtx - 2; break; }; case ALLEGRO_PRIM_TRIANGLE_FAN: { if (use_cache) { int ii; for (ii = 1; ii < num_vtx; ii++) { _al_triangle_2d(texture, &vertex_cache[0], &vertex_cache[ii], &vertex_cache[ii - 1]); } } else { int ii; int idx = 1; ALLEGRO_VERTEX v0; ALLEGRO_VERTEX vtx[2]; SET_VERTEX(v0, start); SET_VERTEX(vtx[0], start + 1); for (ii = start + 1; ii < end; ii++) { SET_VERTEX(vtx[idx], ii) _al_triangle_2d(texture, &v0, &vtx[0], &vtx[1]); idx = 1 - idx; } } num_primitives = num_vtx - 2; break; }; case ALLEGRO_PRIM_POINT_LIST: { if (use_cache) { int ii; for (ii = 0; ii < num_vtx; ii++) { _al_point_2d(texture, &vertex_cache[ii]); } } else { int ii; for (ii = start; ii < end; ii++) { ALLEGRO_VERTEX v; SET_VERTEX(v, ii); _al_point_2d(texture, &v); } } num_primitives = num_vtx; break; }; } if(texture) al_unlock_bitmap(texture); return num_primitives; #undef SET_VERTEX } int _al_draw_prim_indexed_soft(ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, const int* indices, int num_vtx, int type) { LOCAL_VERTEX_CACHE; int num_primitives; int use_cache; int min_idx, max_idx; int ii; int stride = decl ? decl->stride : (int)sizeof(ALLEGRO_VERTEX); const ALLEGRO_TRANSFORM* global_trans = al_get_current_transform(); num_primitives = 0; use_cache = 1; min_idx = indices[0]; max_idx = indices[0]; /* Determine the range we are dealing with */ for (ii = 1; ii < num_vtx; ii++) { int idx = indices[ii]; if (max_idx < idx) max_idx = idx; else if (min_idx > indices[ii]) min_idx = idx; } if (max_idx - min_idx >= ALLEGRO_VERTEX_CACHE_SIZE) { use_cache = 0; } if (texture) al_lock_bitmap(texture, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); if (use_cache) { int ii; for (ii = 0; ii < num_vtx; ii++) { int idx = indices[ii]; convert_vtx(texture, (const char*)vtxs + idx * stride, &vertex_cache[idx - min_idx], decl); al_transform_coordinates(global_trans, &vertex_cache[idx - min_idx].x, &vertex_cache[idx - min_idx].y); } } #define SET_VERTEX(v, idx) \ convert_vtx(texture, (const char*)vtxs + stride * (idx), &v, decl); \ al_transform_coordinates(global_trans, &v.x, &v.y); \ switch (type) { case ALLEGRO_PRIM_LINE_LIST: { if (use_cache) { int ii; for (ii = 0; ii < num_vtx - 1; ii += 2) { int idx1 = indices[ii] - min_idx; int idx2 = indices[ii + 1] - min_idx; _al_line_2d(texture, &vertex_cache[idx1], &vertex_cache[idx2]); } } else { int ii; for (ii = 0; ii < num_vtx - 1; ii += 2) { int idx1 = indices[ii]; int idx2 = indices[ii + 1]; ALLEGRO_VERTEX v1, v2; SET_VERTEX(v1, idx1); SET_VERTEX(v2, idx2); _al_line_2d(texture, &v1, &v2); } } num_primitives = num_vtx / 2; break; }; case ALLEGRO_PRIM_LINE_STRIP: { if (use_cache) { int ii; for (ii = 1; ii < num_vtx; ii++) { int idx1 = indices[ii - 1] - min_idx; int idx2 = indices[ii] - min_idx; _al_line_2d(texture, &vertex_cache[idx1], &vertex_cache[idx2]); } } else { int ii; int idx = 1; ALLEGRO_VERTEX vtx[2]; SET_VERTEX(vtx[0], indices[0]); for (ii = 1; ii < num_vtx; ii++) { SET_VERTEX(vtx[idx], indices[ii]) _al_line_2d(texture, &vtx[0], &vtx[1]); idx = 1 - idx; } } num_primitives = num_vtx - 1; break; }; case ALLEGRO_PRIM_LINE_LOOP: { if (use_cache) { int ii; int idx1, idx2; for (ii = 1; ii < num_vtx; ii++) { int idx1 = indices[ii - 1] - min_idx; int idx2 = indices[ii] - min_idx; _al_line_2d(texture, &vertex_cache[idx1], &vertex_cache[idx2]); } idx1 = indices[0] - min_idx; idx2 = indices[num_vtx - 1] - min_idx; _al_line_2d(texture, &vertex_cache[idx2], &vertex_cache[idx1]); } else { int ii; int idx = 1; ALLEGRO_VERTEX vtx[2]; SET_VERTEX(vtx[0], indices[0]); for (ii = 1; ii < num_vtx; ii++) { SET_VERTEX(vtx[idx], indices[ii]) _al_line_2d(texture, &vtx[0], &vtx[1]); idx = 1 - idx; } SET_VERTEX(vtx[idx], indices[0]) _al_line_2d(texture, &vtx[0], &vtx[1]); } num_primitives = num_vtx; break; }; case ALLEGRO_PRIM_TRIANGLE_LIST: { if (use_cache) { int ii; for (ii = 0; ii < num_vtx - 2; ii += 3) { int idx1 = indices[ii] - min_idx; int idx2 = indices[ii + 1] - min_idx; int idx3 = indices[ii + 2] - min_idx; _al_triangle_2d(texture, &vertex_cache[idx1], &vertex_cache[idx2], &vertex_cache[idx3]); } } else { int ii; for (ii = 0; ii < num_vtx - 2; ii += 3) { int idx1 = indices[ii]; int idx2 = indices[ii + 1]; int idx3 = indices[ii + 2]; ALLEGRO_VERTEX v1, v2, v3; SET_VERTEX(v1, idx1); SET_VERTEX(v2, idx2); SET_VERTEX(v3, idx3); _al_triangle_2d(texture, &v1, &v2, &v3); } } num_primitives = num_vtx / 3; break; }; case ALLEGRO_PRIM_TRIANGLE_STRIP: { if (use_cache) { int ii; for (ii = 2; ii < num_vtx; ii++) { int idx1 = indices[ii - 2] - min_idx; int idx2 = indices[ii - 1] - min_idx; int idx3 = indices[ii] - min_idx; _al_triangle_2d(texture, &vertex_cache[idx1], &vertex_cache[idx2], &vertex_cache[idx3]); } } else { int ii; int idx = 2; ALLEGRO_VERTEX vtx[3]; SET_VERTEX(vtx[0], indices[0]); SET_VERTEX(vtx[1], indices[1]); for (ii = 2; ii < num_vtx; ii ++) { SET_VERTEX(vtx[idx], indices[ii]); _al_triangle_2d(texture, &vtx[0], &vtx[1], &vtx[2]); idx = (idx + 1) % 3; } } num_primitives = num_vtx - 2; break; }; case ALLEGRO_PRIM_TRIANGLE_FAN: { if (use_cache) { int ii; int idx0 = indices[0] - min_idx; for (ii = 1; ii < num_vtx; ii++) { int idx1 = indices[ii] - min_idx; int idx2 = indices[ii - 1] - min_idx; _al_triangle_2d(texture, &vertex_cache[idx0], &vertex_cache[idx1], &vertex_cache[idx2]); } } else { int ii; int idx = 1; ALLEGRO_VERTEX v0; ALLEGRO_VERTEX vtx[2]; SET_VERTEX(v0, indices[0]); SET_VERTEX(vtx[0], indices[1]); for (ii = 2; ii < num_vtx; ii ++) { SET_VERTEX(vtx[idx], indices[ii]) _al_triangle_2d(texture, &v0, &vtx[0], &vtx[1]); idx = 1 - idx; } } num_primitives = num_vtx - 2; break; }; case ALLEGRO_PRIM_POINT_LIST: { if (use_cache) { int ii; for (ii = 0; ii < num_vtx; ii++) { int idx = indices[ii] - min_idx; _al_point_2d(texture, &vertex_cache[idx]); } } else { int ii; for (ii = 0; ii < num_vtx; ii++) { ALLEGRO_VERTEX v; SET_VERTEX(v, indices[ii]); _al_point_2d(texture, &v); } } num_primitives = num_vtx; break; }; } if(texture) al_unlock_bitmap(texture); return num_primitives; #undef SET_VERTEX } /* Function: al_draw_soft_triangle */ void al_draw_soft_triangle( ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, ALLEGRO_VERTEX* v3, uintptr_t state, void (*init)(uintptr_t, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*), void (*first)(uintptr_t, int, int, int, int), void (*step)(uintptr_t, int), void (*draw)(uintptr_t, int, int, int)) { _al_draw_soft_triangle(v1, v2, v3, state, init, first, step, draw); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/primitives/prim_util.c000066400000000000000000000155251473414355200213030ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Common utilities. * * * By Michał Cichoń. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_primitives.h" #include "allegro5/internal/aintern_list.h" #include "allegro5/internal/aintern_prim.h" #include #include #ifdef ALLEGRO_MSVC #define hypotf(x, y) _hypotf((x), (y)) #endif # define AL_EPSILON 0.001f /* * Make an estimate of the scale of the current transformation. */ float _al_prim_get_scale(void) { const ALLEGRO_TRANSFORM* t = al_get_current_transform(); return (hypotf(t->m[0][0], t->m[0][1]) + hypotf(t->m[1][0], t->m[1][1])) / 2; } /* * Normalizes vector. */ float _al_prim_normalize(float* vector) { float length; float inv_length; length = hypotf(vector[0], vector[1]); inv_length = length > 0.0f ? 1.0f / length : 1.0f; vector[0] *= inv_length; vector[1] *= inv_length; return length; } /* * Tests on which side of the line point is placed. * Positive value will be returned if point is on half plane * determined by normal vector. Negative value will be returned * if point is on negative half plane determined by normal vector. * Zero will be returned if point lie on the line. */ int _al_prim_test_line_side(const float* origin, const float* normal, const float* point) { float c = -(origin[0] * normal[0] + origin[1] * normal[1]); float d = point[0] * normal[0] + point[1] * normal[1] + c; if (d < 0.0f)/*-AL_EPSILON)*/ return -1; else if (d > 0.0f)/*AL_EPSILON)*/ return 1; else return 0; } /* * Tests if point is inside of the triangle defined by vertices v0, v1 and v2. * * Order of vertices does not have matter. */ bool _al_prim_is_point_in_triangle(const float* point, const float* v0, const float* v1, const float* v2) { float edge_normal_0[2] = { -(v1[1] - v0[1]), v1[0] - v0[0] }; float edge_normal_1[2] = { -(v2[1] - v1[1]), v2[0] - v1[0] }; float edge_normal_2[2] = { -(v0[1] - v2[1]), v0[0] - v2[0] }; int edge_side_0 = _al_prim_test_line_side(v0, edge_normal_0, point); int edge_side_1 = _al_prim_test_line_side(v1, edge_normal_1, point); int edge_side_2 = _al_prim_test_line_side(v2, edge_normal_2, point); if (edge_side_0 && edge_side_1 && edge_side_2) return (edge_side_0 == edge_side_1) && (edge_side_0 == edge_side_2); else if (0 == edge_side_0) return (edge_side_1 == edge_side_2); else if (0 == edge_side_1) return (edge_side_0 == edge_side_2); else /*if (0 == edge_side_2)*/ return (edge_side_0 == edge_side_1); } /* * Tests for intersection of lines defined by points { v0, v1 } * and { p0, p1 }. * * Returns true if intersection point was determined. If pointers * are provided time and exact point of intersection will be returned. * If test fails false will be returned. Intersection point and time * variables will not be altered in this case. * * Intersection time is in { v0, v1 } line space. */ bool _al_prim_intersect_segment(const float* v0, const float* v1, const float* p0, const float* p1, float* point/* = NULL*/, float* t0/* = NULL*/, float* t1/* = NULL*/) { float num, denom, time; denom = (p1[1] - p0[1]) * (v1[0] - v0[0]) - (p1[0] - p0[0]) * (v1[1] - v0[1]); if (fabsf(denom) == 0.0f) return false; num = (p1[0] - p0[0]) * (v0[1] - p0[1]) - (p1[1] - p0[1]) * (v0[0] - p0[0]); time = (num / denom); if (t0) *t0 = time; if (t1) { const float num2 = (v1[0] - v0[0]) * (v0[1] - p0[1]) - (v1[1] - v0[1]) * (v0[0] - p0[0]); *t1 = (num2 / denom); } if (point) { point[0] = v0[0] + time * (v1[0] - v0[0]); point[1] = v0[1] + time * (v1[1] - v0[1]); } return true; } /* * Compares two points for equality. * * This is not exact comparison but it is sufficient * for our needs. */ bool _al_prim_are_points_equal(const float* point_a, const float* point_b) { return (fabsf(point_a[0] - point_b[0]) < AL_EPSILON) && (fabsf(point_a[1] - point_b[1]) < AL_EPSILON); } /* * */ void _al_prim_cache_init(ALLEGRO_PRIM_VERTEX_CACHE* cache, int prim_type, ALLEGRO_COLOR color) { _al_prim_cache_init_ex(cache, prim_type, color, NULL); } void _al_prim_cache_init_ex(ALLEGRO_PRIM_VERTEX_CACHE* cache, int prim_type, ALLEGRO_COLOR color, void* user_data) { cache->size = 0; cache->current = cache->buffer; cache->color = color; cache->prim_type = prim_type; cache->user_data = user_data; } void _al_prim_cache_term(ALLEGRO_PRIM_VERTEX_CACHE* cache) { _al_prim_cache_flush(cache); } void _al_prim_cache_flush(ALLEGRO_PRIM_VERTEX_CACHE* cache) { if (cache->size == 0) return; if (cache->prim_type == ALLEGRO_PRIM_VERTEX_CACHE_TRIANGLE) al_draw_prim(cache->buffer, NULL, NULL, 0, cache->size, ALLEGRO_PRIM_TRIANGLE_LIST); else if (cache->prim_type == ALLEGRO_PRIM_VERTEX_CACHE_LINE_STRIP) al_draw_prim(cache->buffer, NULL, NULL, 0, cache->size, ALLEGRO_PRIM_LINE_STRIP); if (cache->prim_type == ALLEGRO_PRIM_VERTEX_CACHE_LINE_STRIP) { cache->buffer[0] = *(cache->current - 1); cache->current = cache->buffer + 1; cache->size = 1; } else { cache->current = cache->buffer; cache->size = 0; } } void _al_prim_cache_push_triangle(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* v0, const float* v1, const float* v2) { if (cache->size >= (ALLEGRO_VERTEX_CACHE_SIZE - 3)) _al_prim_cache_flush(cache); cache->current->x = v0[0]; cache->current->y = v0[1]; cache->current->z = 0.0f; cache->current->color = cache->color; ++cache->current; cache->current->x = v1[0]; cache->current->y = v1[1]; cache->current->z = 0.0f; cache->current->color = cache->color; ++cache->current; cache->current->x = v2[0]; cache->current->y = v2[1]; cache->current->z = 0.0f; cache->current->color = cache->color; ++cache->current; cache->size += 3; //al_draw_triangle(v0[0], v0[1], v1[0], v1[1], v2[0], v2[1], cache->color, 1.0f); } void _al_prim_cache_push_point(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* v) { if (cache->size >= (ALLEGRO_VERTEX_CACHE_SIZE - 1)) _al_prim_cache_flush(cache); cache->current->x = v[0]; cache->current->y = v[1]; cache->current->z = 0.0f; cache->current->color = cache->color; ++cache->current; ++cache->size; } allegro5-5.2.10.1/addons/primitives/primitives.c000066400000000000000000000412071473414355200214660ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Core primitive addon functions. * * * By Pavel Sountsov. * * See readme.txt for copyright information. */ #define ALLEGRO_INTERNAL_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/allegro_primitives.h" #include "allegro5/platform/alplatf.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_pixels.h" #include "allegro5/internal/aintern_prim.h" #include "allegro5/internal/aintern_prim_directx.h" #include "allegro5/internal/aintern_prim_opengl.h" #include "allegro5/internal/aintern_prim_soft.h" #include #ifdef ALLEGRO_CFG_OPENGL #include "allegro5/allegro_opengl.h" #endif #ifndef ALLEGRO_DIRECT3D #define ALLEGRO_DIRECT3D ALLEGRO_DIRECT3D_INTERNAL #endif ALLEGRO_DEBUG_CHANNEL("primitives") static bool addon_initialized = false; /* Function: al_init_primitives_addon */ bool al_init_primitives_addon(void) { bool ret = true; ret &= _al_init_d3d_driver(); addon_initialized = ret; _al_add_exit_func(al_shutdown_primitives_addon, "primitives_shutdown"); return ret; } /* Function: al_is_primitives_addon_initialized */ bool al_is_primitives_addon_initialized(void) { return addon_initialized; } /* Function: al_shutdown_primitives_addon */ void al_shutdown_primitives_addon(void) { _al_shutdown_d3d_driver(); addon_initialized = false; } /* Function: al_draw_prim */ int al_draw_prim(const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, ALLEGRO_BITMAP* texture, int start, int end, int type) { ALLEGRO_BITMAP *target; int ret = 0; ASSERT(addon_initialized); ASSERT(vtxs); ASSERT(end >= start); ASSERT(start >= 0); ASSERT(type >= 0 && type < ALLEGRO_PRIM_NUM_TYPES); target = al_get_target_bitmap(); /* In theory, if we ever get a camera concept for this addon, the transformation into * view space should occur here */ if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP || (texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP) || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) { ret = _al_draw_prim_soft(texture, vtxs, decl, start, end, type); } else { int flags = al_get_display_flags(_al_get_bitmap_display(target)); if (flags & ALLEGRO_OPENGL) { ret = _al_draw_prim_opengl(target, texture, vtxs, decl, start, end, type); } else if (flags & ALLEGRO_DIRECT3D) { ret = _al_draw_prim_directx(target, texture, vtxs, decl, start, end, type); } } return ret; } /* Function: al_draw_indexed_prim */ int al_draw_indexed_prim(const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, ALLEGRO_BITMAP* texture, const int* indices, int num_vtx, int type) { ALLEGRO_BITMAP *target; int ret = 0; ASSERT(addon_initialized); ASSERT(vtxs); ASSERT(indices); ASSERT(num_vtx > 0); ASSERT(type >= 0 && type < ALLEGRO_PRIM_NUM_TYPES); target = al_get_target_bitmap(); /* In theory, if we ever get a camera concept for this addon, the transformation into * view space should occur here */ if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP || (texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP) || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) { ret = _al_draw_prim_indexed_soft(texture, vtxs, decl, indices, num_vtx, type); } else { int flags = al_get_display_flags(_al_get_bitmap_display(target)); if (flags & ALLEGRO_OPENGL) { ret = _al_draw_prim_indexed_opengl(target, texture, vtxs, decl, indices, num_vtx, type); } else if (flags & ALLEGRO_DIRECT3D) { ret = _al_draw_prim_indexed_directx(target, texture, vtxs, decl, indices, num_vtx, type); } } return ret; } int _al_bitmap_region_is_locked(ALLEGRO_BITMAP* bmp, int x1, int y1, int w, int h) { ASSERT(bmp); if (!al_is_bitmap_locked(bmp)) return 0; if (x1 + w > bmp->lock_x && y1 + h > bmp->lock_y && x1 < bmp->lock_x + bmp->lock_w && y1 < bmp->lock_y + bmp->lock_h) return 1; return 0; } /* Function: al_get_allegro_primitives_version */ uint32_t al_get_allegro_primitives_version(void) { return ALLEGRO_VERSION_INT; } /* Function: al_create_vertex_decl */ ALLEGRO_VERTEX_DECL* al_create_vertex_decl(const ALLEGRO_VERTEX_ELEMENT* elements, int stride) { ALLEGRO_VERTEX_DECL* ret; ALLEGRO_DISPLAY* display; ALLEGRO_VERTEX_ELEMENT* e; int flags; ASSERT(addon_initialized); ret = al_malloc(sizeof(ALLEGRO_VERTEX_DECL)); ret->elements = al_calloc(1, sizeof(ALLEGRO_VERTEX_ELEMENT) * ALLEGRO_PRIM_ATTR_NUM); while(elements->attribute) { #ifdef ALLEGRO_CFG_OPENGLES if (elements->storage == ALLEGRO_PRIM_HALF_FLOAT_2 || elements->storage == ALLEGRO_PRIM_HALF_FLOAT_4) { ALLEGRO_WARN("This platform does not support ALLEGRO_PRIM_HALF_FLOAT_2 or ALLEGRO_PRIM_HALF_FLOAT_4.\n"); goto fail; } #endif ret->elements[elements->attribute] = *elements; elements++; } e = &ret->elements[ALLEGRO_PRIM_POSITION]; if (e->attribute) { if (e->storage != ALLEGRO_PRIM_FLOAT_2 && e->storage != ALLEGRO_PRIM_FLOAT_3 && e->storage != ALLEGRO_PRIM_SHORT_2) { ALLEGRO_WARN("Invalid storage for ALLEGRO_PRIM_POSITION.\n"); goto fail; } } e = &ret->elements[ALLEGRO_PRIM_TEX_COORD]; if(!e->attribute) e = &ret->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL]; if (e->attribute) { if (e->storage != ALLEGRO_PRIM_FLOAT_2 && e->storage != ALLEGRO_PRIM_SHORT_2) { ALLEGRO_WARN("Invalid storage for %s.\n", ret->elements[ALLEGRO_PRIM_TEX_COORD].attribute ? "ALLEGRO_PRIM_TEX_COORD" : "ALLEGRO_PRIM_TEX_COORD_PIXEL"); goto fail; } } display = al_get_current_display(); flags = al_get_display_flags(display); if (flags & ALLEGRO_DIRECT3D) { _al_set_d3d_decl(display, ret); } ret->stride = stride; return ret; fail: al_free(ret->elements); al_free(ret); return NULL; } /* Function: al_destroy_vertex_decl */ void al_destroy_vertex_decl(ALLEGRO_VERTEX_DECL* decl) { if (!decl) return; al_free(decl->elements); /* * TODO: Somehow free the d3d_decl */ al_free(decl); } /* Function: al_create_vertex_buffer */ ALLEGRO_VERTEX_BUFFER* al_create_vertex_buffer(ALLEGRO_VERTEX_DECL* decl, const void* initial_data, int num_vertices, int flags) { ALLEGRO_VERTEX_BUFFER* ret; int display_flags = al_get_display_flags(al_get_current_display()); ASSERT(addon_initialized); ret = al_calloc(1, sizeof(ALLEGRO_VERTEX_BUFFER)); ret->common.size = num_vertices; ret->common.write_only = !(flags & ALLEGRO_PRIM_BUFFER_READWRITE); ret->decl = decl; #if defined ALLEGRO_IPHONE || defined ALLEGRO_ANDROID if (flags & ALLEGRO_PRIM_BUFFER_READWRITE) goto fail; #endif if (display_flags & ALLEGRO_OPENGL) { if (_al_create_vertex_buffer_opengl(ret, initial_data, num_vertices, flags)) return ret; } else if (display_flags & ALLEGRO_DIRECT3D) { if (_al_create_vertex_buffer_directx(ret, initial_data, num_vertices, flags)) return ret; } /* Silence the warning */ goto fail; fail: al_free(ret); return 0; } /* Function: al_create_index_buffer */ ALLEGRO_INDEX_BUFFER* al_create_index_buffer(int index_size, const void* initial_data, int num_indices, int flags) { ALLEGRO_INDEX_BUFFER* ret; int display_flags = al_get_display_flags(al_get_current_display()); ASSERT(addon_initialized); ASSERT(index_size == 2 || index_size == 4); ret = al_calloc(1, sizeof(ALLEGRO_INDEX_BUFFER)); ret->common.size = num_indices; ret->common.write_only = !(flags & ALLEGRO_PRIM_BUFFER_READWRITE); ret->index_size = index_size; #if defined ALLEGRO_IPHONE || defined ALLEGRO_ANDROID if (flags & ALLEGRO_PRIM_BUFFER_READWRITE) goto fail; #endif #if defined ALLEGRO_IPHONE if (index_size == 4) goto fail; #endif if (display_flags & ALLEGRO_OPENGL) { if (_al_create_index_buffer_opengl(ret, initial_data, num_indices, flags)) return ret; } else if (display_flags & ALLEGRO_DIRECT3D) { if (_al_create_index_buffer_directx(ret, initial_data, num_indices, flags)) return ret; } /* Silence the warning */ goto fail; fail: al_free(ret); return NULL; } /* Function: al_destroy_vertex_buffer */ void al_destroy_vertex_buffer(ALLEGRO_VERTEX_BUFFER* buffer) { if (buffer == 0) return; int flags = al_get_display_flags(al_get_current_display()); ASSERT(addon_initialized); al_unlock_vertex_buffer(buffer); if (flags & ALLEGRO_OPENGL) { _al_destroy_vertex_buffer_opengl(buffer); } else if (flags & ALLEGRO_DIRECT3D) { _al_destroy_vertex_buffer_directx(buffer); } al_free(buffer); } /* Function: al_destroy_index_buffer */ void al_destroy_index_buffer(ALLEGRO_INDEX_BUFFER* buffer) { if (buffer == 0) return; int flags = al_get_display_flags(al_get_current_display()); ASSERT(addon_initialized); al_unlock_index_buffer(buffer); if (flags & ALLEGRO_OPENGL) { _al_destroy_index_buffer_opengl(buffer); } else if (flags & ALLEGRO_DIRECT3D) { _al_destroy_index_buffer_directx(buffer); } al_free(buffer); } /* The sizes are in bytes here */ static bool lock_buffer_common(ALLEGRO_BUFFER_COMMON* common, int offset, int length, int flags) { if (common->is_locked || (common->write_only && flags != ALLEGRO_LOCK_WRITEONLY)) return false; common->lock_offset = offset; common->lock_length = length; common->lock_flags = flags; common->is_locked = true; return true; } /* Function: al_lock_vertex_buffer */ void* al_lock_vertex_buffer(ALLEGRO_VERTEX_BUFFER* buffer, int offset, int length, int flags) { int stride; int disp_flags = al_get_display_flags(al_get_current_display()); ASSERT(buffer); ASSERT(addon_initialized); if (offset + length > buffer->common.size) return NULL; stride = buffer->decl ? buffer->decl->stride : (int)sizeof(ALLEGRO_VERTEX); if (!lock_buffer_common(&buffer->common, offset * stride, length * stride, flags)) return NULL; if (disp_flags & ALLEGRO_OPENGL) { return _al_lock_vertex_buffer_opengl(buffer); } else if (disp_flags & ALLEGRO_DIRECT3D) { return _al_lock_vertex_buffer_directx(buffer); } else { return NULL; } } /* Function: al_lock_index_buffer */ void* al_lock_index_buffer(ALLEGRO_INDEX_BUFFER* buffer, int offset, int length, int flags) { int disp_flags = al_get_display_flags(al_get_current_display()); ASSERT(buffer); ASSERT(addon_initialized); if (offset + length > buffer->common.size) return NULL; if (!lock_buffer_common(&buffer->common, offset * buffer->index_size, length * buffer->index_size, flags)) return NULL; if (disp_flags & ALLEGRO_OPENGL) { return _al_lock_index_buffer_opengl(buffer); } else if (disp_flags & ALLEGRO_DIRECT3D) { return _al_lock_index_buffer_directx(buffer); } else { return NULL; } } /* Function: al_unlock_vertex_buffer */ void al_unlock_vertex_buffer(ALLEGRO_VERTEX_BUFFER* buffer) { int flags = al_get_display_flags(al_get_current_display()); ASSERT(buffer); ASSERT(addon_initialized); if (!buffer->common.is_locked) return; buffer->common.is_locked = false; if (flags & ALLEGRO_OPENGL) { _al_unlock_vertex_buffer_opengl(buffer); } else if (flags & ALLEGRO_DIRECT3D) { _al_unlock_vertex_buffer_directx(buffer); } } /* Function: al_unlock_index_buffer */ void al_unlock_index_buffer(ALLEGRO_INDEX_BUFFER* buffer) { int flags = al_get_display_flags(al_get_current_display()); ASSERT(buffer); ASSERT(addon_initialized); if (!buffer->common.is_locked) return; buffer->common.is_locked = false; if (flags & ALLEGRO_OPENGL) { _al_unlock_index_buffer_opengl(buffer); } else if (flags & ALLEGRO_DIRECT3D) { _al_unlock_index_buffer_directx(buffer); } } /* Software fallback for buffer drawing */ int _al_draw_buffer_common_soft(ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_BITMAP* texture, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type) { void* vtx; int num_primitives = 0; int num_vtx = end - start; int vtx_lock_start = index_buffer ? 0 : start; int vtx_lock_len = index_buffer ? al_get_vertex_buffer_size(vertex_buffer) : num_vtx; if (vertex_buffer->common.write_only || (index_buffer && index_buffer->common.write_only)) { return 0; } vtx = al_lock_vertex_buffer(vertex_buffer, vtx_lock_start, vtx_lock_len, ALLEGRO_LOCK_READONLY); ASSERT(vtx); if (index_buffer) { void* idx; int* int_idx = NULL; int ii; idx = al_lock_index_buffer(index_buffer, start, num_vtx, ALLEGRO_LOCK_READONLY); ASSERT(idx); if (index_buffer->index_size != 4) { int_idx = al_malloc(num_vtx * sizeof(int)); for (ii = 0; ii < num_vtx; ii++) { int_idx[ii] = ((unsigned short*)idx)[ii]; } idx = int_idx; } num_primitives = _al_draw_prim_indexed_soft(texture, vtx, vertex_buffer->decl, idx, num_vtx, type); al_unlock_index_buffer(index_buffer); al_free(int_idx); } else { num_primitives = _al_draw_prim_soft(texture, vtx, vertex_buffer->decl, 0, num_vtx, type); } al_unlock_vertex_buffer(vertex_buffer); return num_primitives; } /* Function: al_draw_vertex_buffer */ int al_draw_vertex_buffer(ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_BITMAP* texture, int start, int end, int type) { ALLEGRO_BITMAP *target; int ret = 0; ASSERT(addon_initialized); ASSERT(end >= start); ASSERT(start >= 0); ASSERT(end <= al_get_vertex_buffer_size(vertex_buffer)); ASSERT(type >= 0 && type < ALLEGRO_PRIM_NUM_TYPES); ASSERT(vertex_buffer); ASSERT(!vertex_buffer->common.is_locked); target = al_get_target_bitmap(); if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP || (texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP) || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) { ret = _al_draw_buffer_common_soft(vertex_buffer, texture, NULL, start, end, type); } else { int flags = al_get_display_flags(al_get_current_display()); if (flags & ALLEGRO_OPENGL) { ret = _al_draw_vertex_buffer_opengl(target, texture, vertex_buffer, start, end, type); } else if (flags & ALLEGRO_DIRECT3D) { ret = _al_draw_vertex_buffer_directx(target, texture, vertex_buffer, start, end, type); } } return ret; } /* Function: al_draw_indexed_buffer */ int al_draw_indexed_buffer(ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_BITMAP* texture, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type) { ALLEGRO_BITMAP *target; int ret = 0; ASSERT(addon_initialized); ASSERT(end >= start); ASSERT(start >= 0); ASSERT(end <= al_get_index_buffer_size(index_buffer)); ASSERT(type >= 0 && type < ALLEGRO_PRIM_NUM_TYPES); ASSERT(vertex_buffer); ASSERT(!vertex_buffer->common.is_locked); ASSERT(index_buffer); ASSERT(!index_buffer->common.is_locked); target = al_get_target_bitmap(); if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP || (texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP) || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) { ret = _al_draw_buffer_common_soft(vertex_buffer, texture, index_buffer, start, end, type); } else { int flags = al_get_display_flags(al_get_current_display()); if (flags & ALLEGRO_OPENGL) { ret = _al_draw_indexed_buffer_opengl(target, texture, vertex_buffer, index_buffer, start, end, type); } else if (flags & ALLEGRO_DIRECT3D) { ret = _al_draw_indexed_buffer_directx(target, texture, vertex_buffer, index_buffer, start, end, type); } } return ret; } /* Function: al_get_vertex_buffer_size */ int al_get_vertex_buffer_size(ALLEGRO_VERTEX_BUFFER* buffer) { ASSERT(buffer); return buffer->common.size; } /* Function: al_get_index_buffer_size */ int al_get_index_buffer_size(ALLEGRO_INDEX_BUFFER* buffer) { ASSERT(buffer); return buffer->common.size; } allegro5-5.2.10.1/addons/primitives/triangulator.c000066400000000000000000000620411473414355200220050ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Polygon triangulation with holes. * * * By Michał Cichoń. * * See readme.txt for copyright information. */ # include "allegro5/allegro.h" # include "allegro5/allegro_primitives.h" # include "allegro5/internal/aintern_prim.h" # include "allegro5/internal/aintern_list.h" # include # include # define POLY_DEBUG 0 /* */ # define POLY_VERTEX_ATTR_REFLEX 0x0001 # define POLY_VERTEX_ATTR_EAR_CLIP 0x0002 # define POLY_VERTEX_ATTR_ALL (POLY_VERTEX_ATTR_REFLEX | POLY_VERTEX_ATTR_EAR_CLIP) typedef void (*POLY_EMIT_TRIANGLE)(int, int, int, void*); typedef struct POLY { const float* vertex_buffer; size_t vertex_stride; size_t vertex_count; const int* split_indices; size_t split_stride; size_t split_count; POLY_EMIT_TRIANGLE emit; void* userdata; _AL_LIST* vertex_list; _AL_LIST* reflex_list; _AL_LIST* ear_list; } POLY; typedef struct POLY_SPLIT { int begin; size_t size; float* point; int max_index; } POLY_SPLIT; # if POLY_DEBUG typedef void (*poly_debug_draw_text_t)(float x, float y, int line, const char* format, ...); #if defined _MSC_VER #define EXPORT __declspec(dllexport) #else #define EXPORT #define __noop ((void)0) #endif EXPORT int g_poly_debug_split_step = -1; EXPORT int g_poly_debug_step = -1; EXPORT int g_poly_debug_step_current = 0; EXPORT poly_debug_draw_text_t g_poly_debug_draw_text = NULL; EXPORT float g_poly_debug_scale = 1.0f; #undef EXPORT # define POLY_DEBUG_TEXT(x,y,...) (g_poly_debug_draw_text ? g_poly_debug_draw_text(x,y,INT_MAX,__VA_ARGS__) : __noop) # define POLY_DEBUG_TEXT_LINE(x,y,line,...) (g_poly_debug_draw_text ? g_poly_debug_draw_text(x,y,line,__VA_ARGS__) : __noop) # endif /* Internal functions. */ static bool poly_initialize(POLY* poly); static void poly_classify_vertices(_AL_LIST* vertices, _AL_LIST* reflex, _AL_LIST* ear); static void poly_classify_vertices_in_range(_AL_LIST_ITEM* begin, _AL_LIST_ITEM* end, _AL_LIST* vertices, _AL_LIST* reflex, _AL_LIST* ear); static void poly_do_triangulate(POLY* poly); static _AL_LIST* poly_create_split_list(POLY* polygon); static void poly_split_list_dtor(void* user_data); /* * Seek for closest intersection point of polygon with a ray directed * to the right. * * Returns true if intersection was found. 'point', 'edge0' and 'edge1' * are set to proper values (if not NULL). * Returns false if intersection was not fount and none of above * are modified. */ static bool poly_find_closest_intersection(_AL_LIST* vertices, const float* vertex, float* point, _AL_LIST_ITEM** edge0, _AL_LIST_ITEM** edge1) { size_t i; const float* v0 = NULL; float v1[2]; float intersection[2]; float t0, t1; float best_point[2] = {0, 0}; float best_t; _AL_LIST_ITEM* item = NULL; _AL_LIST_ITEM* next = NULL; _AL_LIST_ITEM* best_e0 = NULL; _AL_LIST_ITEM* best_e1 = NULL; /* Assemble line pointing to the right. */ v0 = vertex; v1[0] = v0[0] + 1.0f; v1[1] = v0[1]; /* Seek for the closest intersection. */ best_t = FLT_MAX; item = _al_list_front(vertices); next = _al_list_next_circular(vertices, item); for (i = 0; i < _al_list_size(vertices); ++i, item = next, next = _al_list_next_circular(vertices, next)) { float* p0 = (float*)_al_list_item_data(item); float* p1 = (float*)_al_list_item_data(next); /* Perform quick rejection. * * We are interested only with outer edges. That mean only those * whose go from the bottom to the up. Note we cannot intersect * parallel line. * * Second condition reject edges lying completely on the left * side of ray origin. */ if ((p0[1] < p1[1]) || (p0[0] <= vertex[0] && p1[0] <= vertex[0])) continue; if (_al_prim_intersect_segment(v0, v1, p0, p1, intersection, &t0, &t1) && (t1 >= 0.0f) && (t1 <= 1.0f) && (t0 >= 0.0f) && (t0 < best_t)) { best_t = t0; best_point[0] = intersection[0]; best_point[1] = intersection[1]; best_e0 = item; best_e1 = next; } } if (NULL != best_e0) { if (NULL != point) { point[0] = best_point[0]; point[1] = best_point[1]; } if (NULL != edge0) *edge0 = best_e0; if (NULL != edge1) *edge1 = best_e1; # if POLY_DEBUG //al_draw_line(v0[0], v0[1], point[0], point[1], al_map_rgb(255, 0, 0), 0.0f); # endif return true; } else return false; } /* * Seek for the best vertex in polygon for doing split. * * Returns vertex after which split (hole) vertices * can be inserted. */ static _AL_LIST_ITEM* poly_find_outter_split_vertex(POLY* polygon, POLY_SPLIT* split) { float intersection[2]; _AL_LIST_ITEM* edge_vertex_0; _AL_LIST_ITEM* edge_vertex_1; _AL_LIST_ITEM* vertex; _AL_LIST_ITEM* reflex_item; _AL_LIST_ITEM* best_vertex; float best_distance; float* p0; float* p1; float* p; if (!poly_find_closest_intersection(polygon->vertex_list, split->point, intersection, &edge_vertex_0, &edge_vertex_1)) return NULL; p0 = (float*)_al_list_item_data(edge_vertex_0); p1 = (float*)_al_list_item_data(edge_vertex_1); /* Maybe we hit an edge vertex? */ if (_al_prim_are_points_equal(split->point, p0)) return edge_vertex_0; if (_al_prim_are_points_equal(split->point, p1)) return edge_vertex_1; /* No luck. Pick point which most far away from us. */ if (p0[0] > p1[0]) { vertex = edge_vertex_0; p = p0; } else { vertex = edge_vertex_1; p = p1; } /* Seek in reflex vertices. */ best_vertex = NULL; best_distance = FLT_MAX; for (reflex_item = _al_list_front(polygon->reflex_list); reflex_item; reflex_item = _al_list_next(polygon->reflex_list, reflex_item)) { _AL_LIST_ITEM* reflex_vertex = (_AL_LIST_ITEM*)_al_list_item_data(reflex_item); float* reflex_point = (float*)_al_list_item_data(reflex_vertex); if (_al_prim_is_point_in_triangle(reflex_point, split->point, p, intersection)) { float diff_x = reflex_point[0] - split->point[0]; float diff_y = reflex_point[1] - split->point[1]; float dist = diff_x * diff_x + diff_y * diff_y; if (dist < best_distance) { best_distance = dist; best_vertex = reflex_vertex; } } } if (NULL != best_vertex) vertex = best_vertex; //# if POLY_DEBUG // p0 = (float*)_al_list_item_data(vertex); // al_draw_line(p0[0], p0[1], intersection[0], intersection[1], al_map_rgb(255, 0, 0), 0.0f); //# endif return vertex; } # define POLY_VERTEX(index) ((float*)(((uint8_t*)polygon->vertex_buffer) + (index) * polygon->vertex_stride)) # define POLY_SPLIT(index) (*((int*)(((uint8_t*)polygon->split_indices) + (index) * polygon->split_stride))) # define POLY_SPLIT_INDEX(split) (((uint8_t*)split - (uint8_t*)polygon->split_indices) / polygon->split_stride) /* * Create list of the splits. */ static _AL_LIST* poly_create_split_list(POLY* polygon) { int i; int last_split; _AL_LIST* list = _al_list_create_static(polygon->split_count); POLY_SPLIT* splits = (POLY_SPLIT*)al_malloc(polygon->split_count * sizeof(POLY_SPLIT)); if ((NULL == list) || (NULL == splits)) { _al_list_destroy(list); al_free(splits); return NULL; } /* Set list destructor, so we will don't worry about * manually releasing allocated memory. */ _al_list_set_dtor(list, poly_split_list_dtor); _al_list_set_user_data(list, splits); last_split = POLY_SPLIT(0); for (i = 1; i < (int)polygon->split_count; ++i) { int j; float max; POLY_SPLIT* split = splits + i; _AL_LIST_ITEM* where; split->begin = last_split; split->size = POLY_SPLIT(i) - last_split; last_split = last_split + split->size; max = -FLT_MAX; split->max_index = -1; for (j = split->begin; j < split->begin + (int)split->size; ++j) { float* point = POLY_VERTEX(j); if (point[0] >= max) { max = point[0]; split->point = point; split->max_index = j; } } split->max_index -= split->begin; ASSERT(split->max_index >= 0); where = NULL; if (!_al_list_is_empty(list)) { for (where = _al_list_front(list); where; where = _al_list_next(list, where)) { POLY_SPLIT* local_split = (POLY_SPLIT*)_al_list_item_data(where); if (local_split->point[0] < max) break; } } if (NULL == where) _al_list_push_back(list, split); else _al_list_insert_before(list, where, split); } return list; } /* * Release memory allocated by split list. This method * serve as callback to the list. */ static void poly_split_list_dtor(void* user_data) { /* This is array of POLY_SPLIT. */ al_free(user_data); } /* * Perform initialization step to polygon triangulation. * * Three linked list are initialized: vertex_list, reflex_list * and ear_list. * * All provided splits (holes) are resolved in this step. * Therefore at the end we have simple polygon. */ static bool poly_initialize(POLY* polygon) { _AL_LIST* vertex_list; _AL_LIST* reflex_list; _AL_LIST* ear_list; _AL_LIST* split_list; _AL_LIST_ITEM* split_item; size_t vertex_count; bool use_split_list; size_t j; int i; # if POLY_DEBUG if (g_poly_debug_split_step >= 0) polygon->split_count = min(g_poly_debug_split_step, polygon->split_count); # endif /* Every hole add two extra vertices to the list. */ vertex_count = polygon->vertex_count + (polygon->split_count - 1) * 2; /* Create lists for polygon. */ vertex_list = _al_list_create_static(vertex_count); reflex_list = _al_list_create_static(vertex_count); ear_list = _al_list_create_static(vertex_count); if (polygon->split_count > 1) { split_list = poly_create_split_list(polygon); use_split_list = true; } else { split_list = NULL; use_split_list = false; } if ((NULL == vertex_list) || (NULL == reflex_list) || (NULL == ear_list) || (use_split_list && (NULL == split_list))) { _al_list_destroy(vertex_list); _al_list_destroy(reflex_list); _al_list_destroy(ear_list); _al_list_destroy(split_list); return false; } /* Store lists in polygon. */ polygon->vertex_list = vertex_list; polygon->reflex_list = reflex_list; polygon->ear_list = ear_list; /* Push main polygon outline. */ for (i = 0; i < POLY_SPLIT(0); ++i) _al_list_push_back(vertex_list, POLY_VERTEX(i)); if (use_split_list) { # if POLY_DEBUG int current_split = 0; # endif poly_classify_vertices(vertex_list, reflex_list, NULL); /* Resolve all holes. */ for (split_item = _al_list_front(split_list); split_item; split_item = _al_list_next(split_list, split_item)) { _AL_LIST_ITEM* first_vertex; _AL_LIST_ITEM* last_vertex; POLY_SPLIT* split; # if POLY_DEBUG if (g_poly_debug_split_step >= 0 && current_split >= g_poly_debug_split_step) break; ++current_split; # endif split = (POLY_SPLIT*)_al_list_item_data(split_item); first_vertex = poly_find_outter_split_vertex(polygon, split); if (NULL == first_vertex) break; /* Insert hole vertices. */ last_vertex = first_vertex; for (j = 0; j <= split->size; ++j) last_vertex = _al_list_insert_after(vertex_list, last_vertex, POLY_VERTEX(split->begin + ((j + split->max_index) % split->size))); last_vertex = _al_list_insert_after(vertex_list, last_vertex, _al_list_item_data(first_vertex)); _al_list_remove(reflex_list, first_vertex); poly_classify_vertices_in_range(first_vertex, _al_list_next(vertex_list, last_vertex), vertex_list, reflex_list, NULL); } _al_list_destroy(split_list); poly_classify_vertices(vertex_list, NULL, ear_list); } else /* Initialize reflex and ear vertex lists. */ poly_classify_vertices(vertex_list, reflex_list, ear_list); return true; } # undef POLY_VERTEX # undef POLY_SPLIT # undef POLY_SPLIT_INDEX /* * Compute polygon vertex attributes. Currently supported attributes are: * - ear clip * - reflex * * Vertex is an ear clip when triangle made by their edges does not contain * any other vertices. * * Vertex is a reflex when angle between edges is greater or equal * to 180 degrees. * * Optionally function may take reflex list (if not NULL). In this case test * for ear clip is performed only on reflex vertices not on entire polygon. * This is used for triangulation speed optimization, because convex * (non reflect) vertices will never became reflex. * * Flags are used to determine for which attribute we want to check. * Use POLY_VERTEX_ATTR_ALL to test for all attributes. */ static int poly_compute_vertex_attributes(_AL_LIST* vertices, _AL_LIST_ITEM* item, int flags, _AL_LIST* reflex) { size_t i; _AL_LIST_ITEM* prev = _al_list_previous_circular(vertices, item); _AL_LIST_ITEM* next = _al_list_next_circular(vertices, item); _AL_LIST_ITEM* point = NULL; int result = 0; float* v0; float* v1; float* v2; float cross; // Oops, degenerate triangle in store. if (_al_list_size(vertices) < 3) return result; // Get points. v0 = (float*)_al_list_item_data(prev); v1 = (float*)_al_list_item_data(item); v2 = (float*)_al_list_item_data(next); // Compute the cross product between the two edges cross = (v0[0] - v1[0]) * (v2[1] - v1[1]) - (v0[1] - v1[1]) * (v2[0] - v1[0]); # if POLY_DEBUG if (g_poly_debug_step == g_poly_debug_step_current) { float step = 0.25f * 0.0f; float dir0[2] = { v0[0] - v1[0], v0[1] - v1[1] }; float dir2[2] = { v2[0] - v1[0], v2[1] - v1[1] }; POLY_DEBUG_TEXT(v1[0], v1[1], "%d", cross > 0); al_draw_line(v1[0], v1[1], v1[0] + dir0[0] * step, v1[1] + dir0[1] * step, al_map_rgb(255, 0, 0), 4.0f * g_poly_debug_scale); al_draw_line(v1[0], v1[1], v1[0] + dir2[0] * step, v1[1] + dir2[1] * step, al_map_rgb(255, 0, 0), 4.0f * g_poly_debug_scale); } # endif // If internal angle is less than 180 degrees then we may // have an ear clip vertex, otherwise we have reflex. if (cross >= 0) { if (flags & POLY_VERTEX_ATTR_EAR_CLIP) { _AL_LIST_ITEM* start; _AL_LIST* search_list; size_t size; if (reflex) { search_list = reflex; size = _al_list_size(search_list); start = _al_list_front(reflex); } else { search_list = vertices; size = _al_list_size(search_list) - 3; start = _al_list_next_circular(search_list, next); } // Check for ear vertex. point = start; for (i = 0; i < size; ++i, point = _al_list_next_circular(search_list, point)) { float* v; // TODO: optimize this by removing if if (search_list == reflex) v = (float*)_al_list_item_data((_AL_LIST_ITEM*)_al_list_item_data(point)); else v = (float*)_al_list_item_data(point); // Ignore vertices which belong to the triangle. if ((v == v0) || (v == v1) || (v == v2)) continue; // Set point to NULL if we find any point inside the triangle. if (_al_prim_is_point_in_triangle(v, v0, v1, v2)) { point = NULL; break; } } // If point is not NULL, we have ear vertex. if ((NULL != point) || _al_list_is_empty(search_list)) result |= POLY_VERTEX_ATTR_EAR_CLIP; } } else if (flags & POLY_VERTEX_ATTR_REFLEX) result |= POLY_VERTEX_ATTR_REFLEX; return result; } /* * Classify all vertices into reflex or ear group. * * One of target group may be NULL so it will be simply ignored. */ static void poly_classify_vertices(_AL_LIST* vertices, _AL_LIST* reflex, _AL_LIST* ear) { poly_classify_vertices_in_range(_al_list_front(vertices), NULL, vertices, reflex, ear); } /* * Classify selected range of vertices [begin, end) into * reflex or ear group. * * One of target group may be NULL so it will be simply ignored. */ static void poly_classify_vertices_in_range(_AL_LIST_ITEM* begin, _AL_LIST_ITEM* end, _AL_LIST* vertices, _AL_LIST* reflex, _AL_LIST* ear) { _AL_LIST_ITEM* item = NULL; int attribute_mask = 0; if (NULL != ear) attribute_mask |= POLY_VERTEX_ATTR_EAR_CLIP; if (NULL != reflex) attribute_mask |= POLY_VERTEX_ATTR_REFLEX; for (item = begin; item != end; item = _al_list_next(vertices, item)) { int attr = poly_compute_vertex_attributes(vertices, item, attribute_mask, NULL); if (0 == attr) continue; if (attr & POLY_VERTEX_ATTR_EAR_CLIP) _al_list_push_back(ear, item); if (attr & POLY_VERTEX_ATTR_REFLEX) _al_list_push_back(reflex, item); } } /* * Reclassify vertex. After triangle was emitted one vertex * is removed from the list. Two neighbor vertices may * change their attributes. In this place we have general * function which update lists to match new attributes * of provided vertex. */ static void poly_update_vertex_attributes(_AL_LIST* vertices, _AL_LIST* reflex, _AL_LIST* ear, _AL_LIST_ITEM* vertex) { _AL_LIST_ITEM* item; int attr = poly_compute_vertex_attributes(vertices, vertex, POLY_VERTEX_ATTR_ALL, reflex); // Update reflex list only if an attribute change. item = _al_list_find_first(reflex, vertex); if (attr & POLY_VERTEX_ATTR_REFLEX) { if (NULL == item) _al_list_push_back(reflex, vertex); _al_list_remove(ear, vertex); } else { if (NULL != item) _al_list_erase(reflex, item); item = _al_list_find_first(ear, vertex); if (attr & POLY_VERTEX_ATTR_EAR_CLIP) { if (NULL == item) _al_list_push_front(ear, vertex); } else { if (NULL != item) _al_list_erase(ear, item); } } } /* * Triangulator iterate trough list of ear vertices * and clip isolated triangles. This process repeats * until there are ear vertices. */ static void poly_do_triangulate(POLY* polygon) { # define VERTEX_INDEX(vertex) ((((uint8_t*)vertex) - ((uint8_t*)polygon->vertex_buffer)) / polygon->vertex_stride) # if POLY_DEBUG g_poly_debug_step_current = 0; { _AL_LIST_ITEM* item; _AL_LIST_ITEM* next; int* histogram = al_calloc(_al_list_size(polygon->vertex_list), sizeof(int)); /*std::map histogram;*/ int index = 0; for (item = _al_list_front(polygon->vertex_list); item; item = _al_list_next(polygon->vertex_list, item)) { float* point0; float* point1; float n[2]; float l, r; char status[3] = { 0 }; int status_index = 0; next = _al_list_next_circular(polygon->vertex_list, item); point0 = (float*)_al_list_item_data(item); point1 = (float*)_al_list_item_data(next); n[0] = -(point1[1] - point0[1]); n[1] = point1[0] - point0[0]; l = 2.0f * sqrtf(n[0] * n[0] + n[1] * n[1]); n[0] /= l; n[1] /= l; r = 1.0f * 0.0f; al_draw_line(point0[0] + n[0] * r, point0[1] + n[1] * r, point1[0] + n[0] * r, point1[1] + n[1] * r, al_map_rgba(255, 0, 255, 128), r * g_poly_debug_scale); if (_al_list_contains(polygon->reflex_list, item)) status[status_index++] = 'R'; if (_al_list_contains(polygon->ear_list, item)) status[status_index++] = 'E'; POLY_DEBUG_TEXT_LINE(point0[0], point0[1], -histogram[VERTEX_INDEX(point0)], "%s %d", status, index++); ++histogram[VERTEX_INDEX(point0)]; } al_free(histogram); } # endif // Repeat until there are ear clips. while (!_al_list_is_empty(polygon->ear_list)) { _AL_LIST_ITEM* ear_item; _AL_LIST_ITEM* vertex_item; _AL_LIST_ITEM* next; _AL_LIST_ITEM* prev; float* v0; float* v1; float* v2; // Get point and corresponding item on polygon->vertex_list list. ear_item = _al_list_front(polygon->ear_list); vertex_item = (_AL_LIST_ITEM*)_al_list_item_data(ear_item); prev = _al_list_previous_circular(polygon->vertex_list, vertex_item); next = _al_list_next_circular(polygon->vertex_list, vertex_item); v0 = (float*)_al_list_item_data(prev); v1 = (float*)_al_list_item_data(vertex_item); v2 = (float*)_al_list_item_data(next); # if POLY_DEBUG if (g_poly_debug_step == g_poly_debug_step_current) { _AL_LIST_ITEM* item; ALLEGRO_COLOR color; int second = 0; al_draw_filled_triangle(v0[0], v0[1], v1[0], v1[1], v2[0], v2[1], al_map_rgba(0, 0, 255, 64)); for (item = _al_list_front(polygon->vertex_list); item; item = _al_list_next(polygon->vertex_list, item)) { float* point = (float*)_al_list_item_data(item); al_draw_filled_circle(point[0], point[1], 6.0f * g_poly_debug_scale, al_map_rgb(255, 255, 255)); } for (item = _al_list_front(polygon->reflex_list); item; item = _al_list_next(polygon->reflex_list, item)) { float* point = (float*)_al_list_item_data((_AL_LIST_ITEM*)_al_list_item_data(item)); al_draw_filled_circle(point[0], point[1], 6.0f * g_poly_debug_scale, al_map_rgb(255, 255, 0)); } color = al_map_rgb(255, 0, 0); second = _al_list_size(polygon->ear_list) - 1; for (item = _al_list_back(polygon->ear_list); item; item = _al_list_previous(polygon->ear_list, item), --second) { float* point = (float*)_al_list_item_data((_AL_LIST_ITEM*)_al_list_item_data(item)); if (second == 0) color = al_map_rgb(0, 255, 0); else if (second == 1) color = al_map_rgb(0, 0, 255); al_draw_circle(point[0], point[1], 9.0f * g_poly_debug_scale, color, 2.0f * g_poly_debug_scale); } } if (g_poly_debug_step >= 0 && g_poly_debug_step_current >= g_poly_debug_step) break; g_poly_debug_step_current++; # endif // Emit triangle. polygon->emit(VERTEX_INDEX(v0), VERTEX_INDEX(v1), VERTEX_INDEX(v2), polygon->userdata); // Remove polygon->ear_list clip from all lists. _al_list_erase(polygon->ear_list, ear_item); _al_list_erase(polygon->vertex_list, vertex_item); _al_list_erase(polygon->reflex_list, _al_list_find_first(polygon->reflex_list, vertex_item)); // Update attributes of corner vertices. poly_update_vertex_attributes(polygon->vertex_list, polygon->reflex_list, polygon->ear_list, prev); poly_update_vertex_attributes(polygon->vertex_list, polygon->reflex_list, polygon->ear_list, next); } # undef VERTEX_INDEX } /* Function: al_triangulate_polygon * General triangulation function. */ bool al_triangulate_polygon( const float* vertices, size_t vertex_stride, const int* vertex_counts, void (*emit_triangle)(int, int, int, void*), void* userdata) { POLY polygon; int vertex_count; int split_count; int *splits; int i; bool ret; for (i = 0; vertex_counts[i] > 0; i++) { /* do nothing */ } ASSERT(i > 0); split_count = i; splits = malloc(split_count * sizeof(int)); if (!splits) { return false; } vertex_count = 0; for (i = 0; i < split_count; i++) { vertex_count += vertex_counts[i]; splits[i] = vertex_count; } memset(&polygon, 0, sizeof(polygon)); polygon.vertex_buffer = vertices; polygon.vertex_stride = vertex_stride; polygon.vertex_count = vertex_count; polygon.split_indices = splits; polygon.split_stride = sizeof(int); /* XXX can simplify code now */ polygon.split_count = split_count; polygon.emit = emit_triangle; polygon.userdata = userdata; if (poly_initialize(&polygon)) { poly_do_triangulate(&polygon); _al_list_destroy(polygon.vertex_list); _al_list_destroy(polygon.reflex_list); _al_list_destroy(polygon.ear_list); ret = true; } else { ret = false; } free(splits); return ret; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/ttf/000077500000000000000000000000001473414355200155255ustar00rootroot00000000000000allegro5-5.2.10.1/addons/ttf/CMakeLists.txt000066400000000000000000000012671473414355200202730ustar00rootroot00000000000000include_directories(../font) include_directories(SYSTEM ${FREETYPE_INCLUDE_DIRS}) set(TTF_SOURCES ttf.c) set(TTF_INCLUDE_FILES allegro5/allegro_ttf.h) set_our_header_properties(${TTF_INCLUDE_FILES}) configure_file( allegro5/internal/aintern_ttf_cfg.h.cmake ${PROJECT_BINARY_DIR}/include/allegro5/internal/aintern_ttf_cfg.h ) add_our_addon_library(allegro_ttf AllegroTTF-${ALLEGRO_SOVERSION} "${TTF_SOURCES};${TTF_INCLUDE_FILES}" "-DALLEGRO_TTF_SRC" "${FONT_LINK_WITH};${TTF_LIBRARIES}" ) install_our_headers(${TTF_INCLUDE_FILES}) add_addon(ttf) #-----------------------------------------------------------------------------# # vi: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/addons/ttf/allegro5/000077500000000000000000000000001473414355200172375ustar00rootroot00000000000000allegro5-5.2.10.1/addons/ttf/allegro5/allegro_ttf.h000066400000000000000000000033371473414355200217200ustar00rootroot00000000000000#ifndef __al_included_allegro5_allegro_ttf_h #define __al_included_allegro5_allegro_ttf_h #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #ifdef __cplusplus extern "C" { #endif #define ALLEGRO_TTF_NO_KERNING 1 #define ALLEGRO_TTF_MONOCHROME 2 #define ALLEGRO_TTF_NO_AUTOHINT 4 #if (defined ALLEGRO_MINGW32) || (defined ALLEGRO_MSVC) || (defined ALLEGRO_BCC32) #ifndef ALLEGRO_STATICLINK #ifdef ALLEGRO_TTF_SRC #define _ALLEGRO_TTF_DLL __declspec(dllexport) #else #define _ALLEGRO_TTF_DLL __declspec(dllimport) #endif #else #define _ALLEGRO_TTF_DLL #endif #endif #if defined ALLEGRO_MSVC #define ALLEGRO_TTF_FUNC(type, name, args) _ALLEGRO_TTF_DLL type __cdecl name args #elif defined ALLEGRO_MINGW32 #define ALLEGRO_TTF_FUNC(type, name, args) extern type name args #elif defined ALLEGRO_BCC32 #define ALLEGRO_TTF_FUNC(type, name, args) extern _ALLEGRO_TTF_DLL type name args #else #define ALLEGRO_TTF_FUNC AL_FUNC #endif ALLEGRO_TTF_FUNC(ALLEGRO_FONT *, al_load_ttf_font, (char const *filename, int size, int flags)); ALLEGRO_TTF_FUNC(ALLEGRO_FONT *, al_load_ttf_font_f, (ALLEGRO_FILE *file, char const *filename, int size, int flags)); ALLEGRO_TTF_FUNC(ALLEGRO_FONT *, al_load_ttf_font_stretch, (char const *filename, int w, int h, int flags)); ALLEGRO_TTF_FUNC(ALLEGRO_FONT *, al_load_ttf_font_stretch_f, (ALLEGRO_FILE *file, char const *filename, int w, int h, int flags)); ALLEGRO_TTF_FUNC(bool, al_init_ttf_addon, (void)); ALLEGRO_TTF_FUNC(bool, al_is_ttf_addon_initialized, (void)); ALLEGRO_TTF_FUNC(void, al_shutdown_ttf_addon, (void)); ALLEGRO_TTF_FUNC(uint32_t, al_get_allegro_ttf_version, (void)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/ttf/allegro5/internal/000077500000000000000000000000001473414355200210535ustar00rootroot00000000000000allegro5-5.2.10.1/addons/ttf/allegro5/internal/aintern_ttf_cfg.h.cmake000066400000000000000000000000461473414355200254370ustar00rootroot00000000000000#cmakedefine ALLEGRO_CFG_TTF_FREETYPE allegro5-5.2.10.1/addons/ttf/ttf.c000066400000000000000000000764361473414355200165060ustar00rootroot00000000000000#define ALLEGRO_INTERNAL_UNSTABLE #include "allegro5/allegro.h" #ifdef ALLEGRO_CFG_OPENGL #include "allegro5/allegro_opengl.h" #endif #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_vector.h" #include "allegro5/allegro_ttf.h" #include "allegro5/internal/aintern_font.h" #include "allegro5/internal/aintern_ttf_cfg.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_exitfunc.h" #include #include FT_FREETYPE_H #include ALLEGRO_DEBUG_CHANNEL("font") /* Some low-end drivers enable automatic S3TC compression, which * requires glTexSubImage2D to only work on multiples of aligned * 4x4 pixel blocks with some buggy OpenGL drivers. * There's not much we can do about that in general - if the user * locks a portion of a bitmap not conformin to this it will fail * with such a driver. * * However in many programs this is no problem at all safe for rendering * glyphs and simply aligning to 4 pixels here fixes it. */ #define ALIGN_TO_4_PIXEL #define RANGE_SIZE 128 typedef struct REGION { short x; short y; short w; short h; } REGION; typedef struct ALLEGRO_TTF_GLYPH_DATA { ALLEGRO_BITMAP *page_bitmap; REGION region; short offset_x; short offset_y; short advance; } ALLEGRO_TTF_GLYPH_DATA; typedef struct ALLEGRO_TTF_GLYPH_RANGE { int32_t range_start; ALLEGRO_TTF_GLYPH_DATA *glyphs; /* [RANGE_SIZE] */ } ALLEGRO_TTF_GLYPH_RANGE; typedef struct ALLEGRO_TTF_FONT_DATA { FT_Face face; int flags; _AL_VECTOR glyph_ranges; /* sorted array of of ALLEGRO_TTF_GLYPH_RANGE */ _AL_VECTOR page_bitmaps; /* of ALLEGRO_BITMAP pointers */ int page_pos_x; int page_pos_y; int page_line_height; ALLEGRO_LOCKED_REGION *page_lr; FT_StreamRec stream; ALLEGRO_FILE *file; unsigned long base_offset; unsigned long offset; int bitmap_format; int bitmap_flags; int min_page_size; int max_page_size; bool skip_cache_misses; } ALLEGRO_TTF_FONT_DATA; /* globals */ static bool ttf_inited; static FT_Library ft; static ALLEGRO_FONT_VTABLE vt; static INLINE int align4(int x) { #ifdef ALIGN_TO_4_PIXEL return (x + 3) & ~3; #else return x; #endif } /* Returns false if the glyph is invalid. */ static bool get_glyph(ALLEGRO_TTF_FONT_DATA *data, int ft_index, ALLEGRO_TTF_GLYPH_DATA **glyph) { ALLEGRO_TTF_GLYPH_RANGE *range; int32_t range_start; int lo, hi, mid; ASSERT(glyph); range_start = ft_index - (ft_index % RANGE_SIZE); /* Binary search for the range. */ lo = 0; hi = _al_vector_size(&data->glyph_ranges); mid = (hi + lo)/2; range = NULL; while (lo < hi) { ALLEGRO_TTF_GLYPH_RANGE *r = _al_vector_ref(&data->glyph_ranges, mid); if (r->range_start == range_start) { range = r; break; } else if (r->range_start < range_start) { lo = mid + 1; } else { hi = mid; } mid = (hi + lo)/2; } if (!range) { range = _al_vector_alloc_mid(&data->glyph_ranges, mid); range->range_start = range_start; range->glyphs = al_calloc(RANGE_SIZE, sizeof(ALLEGRO_TTF_GLYPH_DATA)); } *glyph = &range->glyphs[ft_index - range_start]; /* If we're skipping cache misses and it isn't already cached, return it as invalid. */ if (data->skip_cache_misses && !(*glyph)->page_bitmap && (*glyph)->region.x >= 0) { return false; } return ft_index != 0; } static void unlock_current_page(ALLEGRO_TTF_FONT_DATA *data) { if (data->page_lr) { ALLEGRO_BITMAP **back = _al_vector_ref_back(&data->page_bitmaps); ASSERT(al_is_bitmap_locked(*back)); al_unlock_bitmap(*back); data->page_lr = NULL; ALLEGRO_DEBUG("Unlocking page: %p\n", *back); } } static ALLEGRO_BITMAP *push_new_page(ALLEGRO_TTF_FONT_DATA *data, int glyph_size) { ALLEGRO_BITMAP **back; ALLEGRO_BITMAP *page; ALLEGRO_STATE state; int page_size = 1; /* 16 seems to work well. A particular problem are fixed width fonts which * take an inordinate amount of space. */ while (page_size < 16 * glyph_size) { page_size *= 2; } if (page_size < data->min_page_size) { page_size = data->min_page_size; } if (page_size > data->max_page_size) { page_size = data->max_page_size; } if (glyph_size > page_size) { ALLEGRO_ERROR("Unable create new page, glyph too large: %d > %d\n", glyph_size, page_size); return NULL; } unlock_current_page(data); /* The bitmap will be destroyed when the parent font is destroyed so * it is not safe to register a destructor for it. */ _al_push_destructor_owner(); al_store_state(&state, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS); al_set_new_bitmap_format(data->bitmap_format); al_set_new_bitmap_flags(data->bitmap_flags); page = al_create_bitmap(page_size, page_size); al_restore_state(&state); _al_pop_destructor_owner(); if (page) { back = _al_vector_alloc_back(&data->page_bitmaps); *back = page; data->page_pos_x = 0; data->page_pos_y = 0; data->page_line_height = 0; } return page; } static unsigned char *alloc_glyph_region(ALLEGRO_TTF_FONT_DATA *data, int ft_index, int w, int h, bool new, ALLEGRO_TTF_GLYPH_DATA *glyph, bool lock_whole_page) { ALLEGRO_BITMAP *page; int w4 = align4(w); int h4 = align4(h); int glyph_size = w4 > h4 ? w4 : h4; bool lock = false; if (_al_vector_is_empty(&data->page_bitmaps) || new) { page = push_new_page(data, glyph_size); if (!page) { ALLEGRO_ERROR("Failed to create a new page for glyph %d.\n", ft_index); return NULL; } } else { ALLEGRO_BITMAP **back = _al_vector_ref_back(&data->page_bitmaps); page = *back; } ALLEGRO_DEBUG("Glyph %d: %dx%d (%dx%d)%s\n", ft_index, w, h, w4, h4, new ? " new" : ""); if (data->page_pos_x + w4 > al_get_bitmap_width(page)) { data->page_pos_y += data->page_line_height; data->page_pos_y = align4(data->page_pos_y); data->page_pos_x = 0; data->page_line_height = 0; } if (data->page_pos_y + h4 > al_get_bitmap_height(page)) { return alloc_glyph_region(data, ft_index, w, h, true, glyph, lock_whole_page); } glyph->page_bitmap = page; glyph->region.x = data->page_pos_x; glyph->region.y = data->page_pos_y; glyph->region.w = w; glyph->region.h = h; data->page_pos_x = align4(data->page_pos_x + w4); if (h > data->page_line_height) { data->page_line_height = h4; } REGION lock_rect; if (lock_whole_page) { lock_rect.x = 0; lock_rect.y = 0; lock_rect.w = al_get_bitmap_width(page); lock_rect.h = al_get_bitmap_height(page); if (!data->page_lr) { lock = true; ALLEGRO_DEBUG("Locking whole page: %p\n", page); } } else { /* Unlock just in case... */ unlock_current_page(data); lock_rect.x = glyph->region.x; lock_rect.y = glyph->region.y; lock_rect.w = w4; lock_rect.h = h4; lock = true; ALLEGRO_DEBUG("Locking glyph region: %p %d %d %d %d\n", page, lock_rect.x, lock_rect.y, lock_rect.w, lock_rect.h); } if (lock) { char *ptr; int i; data->page_lr = al_lock_bitmap_region(page, lock_rect.x, lock_rect.y, lock_rect.w, lock_rect.h, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_WRITEONLY); if (!data->page_lr) { ALLEGRO_ERROR("Failed to lock page.\n"); return NULL; } if (data->flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA) { /* Fill in border with "transparent white" * to make anti-aliasing work well when rotation * and/or scaling transforms are in effect * FIXME We could clear just the border */ for (i = 0; i < lock_rect.h; i++) { ptr = (char *)(data->page_lr->data) + (i * data->page_lr->pitch); int j; for (j = 0; j < lock_rect.w; ++j) { *ptr++ = 255; *ptr++ = 255; *ptr++ = 255; *ptr++ = 0; } } } else { /* Clear the data so we don't get garbage when using filtering * FIXME We could clear just the border but I'm not convinced that * would be faster (yet) */ for (i = 0; i < lock_rect.h; i++) { ptr = (char *)(data->page_lr->data) + (i * data->page_lr->pitch); memset(ptr, 0, lock_rect.w * 4); } } } ASSERT(data->page_lr); /* Copy a displaced pointer for the glyph. */ return (unsigned char *)data->page_lr->data + ((glyph->region.y + 2) - lock_rect.y) * data->page_lr->pitch + ((glyph->region.x + 2) - lock_rect.x) * sizeof(int32_t); } static void copy_glyph_mono(ALLEGRO_TTF_FONT_DATA *font_data, FT_Face face, unsigned char *glyph_data) { int pitch = font_data->page_lr->pitch; int x, y; for (y = 0; y < (int)face->glyph->bitmap.rows; y++) { unsigned char const *ptr = face->glyph->bitmap.buffer + face->glyph->bitmap.pitch * y; unsigned char *dptr = glyph_data + pitch * y; int bit = 0; if (font_data->flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA) { /* FIXME We could just set the alpha byte since the * region was cleared above when allocated */ for (x = 0; x < (int)face->glyph->bitmap.width; x++) { unsigned char set = ((*ptr >> (7-bit)) & 1) ? 255 : 0; *dptr++ = 255; *dptr++ = 255; *dptr++ = 255; *dptr++ = set; bit = (bit + 1) & 7; if (bit == 0) { ptr++; } } } else { for (x = 0; x < (int)face->glyph->bitmap.width; x++) { unsigned char set = ((*ptr >> (7-bit)) & 1) ? 255 : 0; *dptr++ = set; *dptr++ = set; *dptr++ = set; *dptr++ = set; bit = (bit + 1) & 7; if (bit == 0) { ptr++; } } } } } static void copy_glyph_color(ALLEGRO_TTF_FONT_DATA *font_data, FT_Face face, unsigned char *glyph_data) { int pitch = font_data->page_lr->pitch; int x, y; for (y = 0; y < (int)face->glyph->bitmap.rows; y++) { unsigned char const *ptr = face->glyph->bitmap.buffer + face->glyph->bitmap.pitch * y; unsigned char *dptr = glyph_data + pitch * y; if (font_data->flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA) { /* FIXME We could just set the alpha byte since the * region was cleared above when allocated */ for (x = 0; x < (int)face->glyph->bitmap.width; x++) { unsigned char c = *ptr; *dptr++ = 255; *dptr++ = 255; *dptr++ = 255; *dptr++ = c; ptr++; } } else { for (x = 0; x < (int)face->glyph->bitmap.width; x++) { unsigned char c = *ptr; *dptr++ = c; *dptr++ = c; *dptr++ = c; *dptr++ = c; ptr++; } } } } /* NOTE: this function may disable the bitmap hold drawing state * and leave the current page bitmap locked. * * NOTE: We have previously tried to be more clever about caching multiple * glyphs during incidental cache misses, but found that approach to be slower. */ static void cache_glyph(ALLEGRO_TTF_FONT_DATA *font_data, FT_Face face, int ft_index, ALLEGRO_TTF_GLYPH_DATA *glyph, bool lock_whole_page) { FT_Int32 ft_load_flags; FT_Error e; int w, h; unsigned char *glyph_data; if (glyph->page_bitmap || glyph->region.x < 0) return; /* We shouldn't ever get here, as cache misses * should have been set to ft_index = 0. */ ASSERT(!(font_data->skip_cache_misses && !lock_whole_page)); // FIXME: make this a config setting? FT_LOAD_FORCE_AUTOHINT // FIXME: Investigate why some fonts don't work without the // NO_BITMAP flags. Supposedly using that flag makes small sizes // look bad so ideally we would not used it. ft_load_flags = FT_LOAD_RENDER | FT_LOAD_NO_BITMAP; if (font_data->flags & ALLEGRO_TTF_MONOCHROME) ft_load_flags |= FT_LOAD_TARGET_MONO; if (font_data->flags & ALLEGRO_TTF_NO_AUTOHINT) ft_load_flags |= FT_LOAD_NO_AUTOHINT; e = FT_Load_Glyph(face, ft_index, ft_load_flags); if (e) { ALLEGRO_WARN("Failed loading glyph %d from.\n", ft_index); } glyph->offset_x = face->glyph->bitmap_left; glyph->offset_y = (face->size->metrics.ascender >> 6) - face->glyph->bitmap_top; glyph->advance = face->glyph->advance.x >> 6; w = face->glyph->bitmap.width; h = face->glyph->bitmap.rows; if (w == 0 || h == 0) { /* Mark this glyph so we won't try to cache it next time. */ glyph->region.x = -1; glyph->region.y = -1; glyph->page_bitmap = NULL; /* Even though this glyph has no "region", include the 2-pixel border in the size */ glyph->region.w = w + 4; glyph->region.h = h + 4; ALLEGRO_DEBUG("Glyph %d has zero size.\n", ft_index); return; } /* Each glyph has a 2-pixel border all around. Note: The border is kept * even against the outer bitmap edge, to ensure consistent rendering. */ glyph_data = alloc_glyph_region(font_data, ft_index, w + 4, h + 4, false, glyph, lock_whole_page); if (glyph_data == NULL) { return; } if (font_data->flags & ALLEGRO_TTF_MONOCHROME) copy_glyph_mono(font_data, face, glyph_data); else copy_glyph_color(font_data, face, glyph_data); if (!lock_whole_page) { unlock_current_page(font_data); } } /* WARNING: It is only valid to call this function when the current page is empty * (or already locked), otherwise it will gibberify the current glyphs on that page. * * This leaves the current page unlocked. */ static void cache_glyphs(ALLEGRO_TTF_FONT_DATA *data, const char *text, size_t text_size) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR* ustr = al_ref_buffer(&info, text, text_size); FT_Face face = data->face; int pos = 0; int32_t ch; while ((ch = al_ustr_get_next(ustr, &pos)) >= 0) { ALLEGRO_TTF_GLYPH_DATA *glyph; int ft_index = FT_Get_Char_Index(face, ch); get_glyph(data, ft_index, &glyph); cache_glyph(data, face, ft_index, glyph, true); } } static int get_kerning(ALLEGRO_TTF_FONT_DATA const *data, FT_Face face, int prev_ft_index, int ft_index) { /* Do kerning? */ if (!(data->flags & ALLEGRO_TTF_NO_KERNING) && prev_ft_index != -1) { FT_Vector delta; FT_Get_Kerning(face, prev_ft_index, ft_index, FT_KERNING_DEFAULT, &delta); return delta.x >> 6; } return 0; } static bool ttf_get_glyph_worker(ALLEGRO_FONT const *f, int prev_ft_index, int ft_index, int prev_codepoint, int codepoint, ALLEGRO_GLYPH *info) { ALLEGRO_TTF_FONT_DATA *data = f->data; FT_Face face = data->face; ALLEGRO_TTF_GLYPH_DATA *glyph; int advance = 0; if (!get_glyph(data, ft_index, &glyph)) { if (f->fallback) return f->fallback->vtable->get_glyph(f->fallback, prev_codepoint, codepoint, info); else { get_glyph(data, 0, &glyph); ft_index = 0; } } cache_glyph(data, face, ft_index, glyph, false); advance += get_kerning(data, face, prev_ft_index, ft_index); info->bitmap = glyph->page_bitmap; /* the adjustments below remove the 2-pixel border from the glyph */ if (info->bitmap) { info->x = glyph->region.x + 2; info->y = glyph->region.y + 2; } else { info->x = -1; info->y = -1; } info->w = glyph->region.w - 4; info->h = glyph->region.h - 4; info->kerning = advance; info->offset_x = glyph->offset_x; info->offset_y = glyph->offset_y; info->advance = glyph->advance + advance; return ft_index != 0; } static bool ttf_get_glyph(ALLEGRO_FONT const *f, int prev_codepoint, int codepoint, ALLEGRO_GLYPH *glyph) { ALLEGRO_TTF_FONT_DATA *data = f->data; FT_Face face = data->face; int prev_ft_index = (prev_codepoint == -1) ? -1 : (int)FT_Get_Char_Index(face, prev_codepoint); int ft_index = FT_Get_Char_Index(face, codepoint); return ttf_get_glyph_worker(f, prev_ft_index, ft_index, prev_codepoint, codepoint, glyph); } static int render_glyph(ALLEGRO_FONT const *f, ALLEGRO_COLOR color, int prev_ft_index, int ft_index, int32_t prev_ch, int32_t ch, float xpos, float ypos) { ALLEGRO_GLYPH glyph; if (ttf_get_glyph_worker(f, prev_ft_index, ft_index, prev_ch, ch, &glyph) == false) return 0; if (glyph.bitmap != NULL) { /* * Include 1 pixel of the 2-pixel border when drawing glyph. * This improves render results when rotating and scaling. */ al_draw_tinted_bitmap_region( glyph.bitmap, color, glyph.x - 1, glyph.y - 1, glyph.w + 2, glyph.h + 2, xpos + glyph.offset_x + glyph.kerning - 1, ypos + glyph.offset_y - 1, 0 ); } return glyph.advance; } static int ttf_font_height(ALLEGRO_FONT const *f) { ASSERT(f); return f->height; } static int ttf_font_ascent(ALLEGRO_FONT const *f) { ALLEGRO_TTF_FONT_DATA *data; FT_Face face; ASSERT(f); data = f->data; face = data->face; return face->size->metrics.ascender >> 6; } static int ttf_font_descent(ALLEGRO_FONT const *f) { ALLEGRO_TTF_FONT_DATA *data; FT_Face face; ASSERT(f); data = f->data; face = data->face; return (-face->size->metrics.descender) >> 6; } static int ttf_render_char(ALLEGRO_FONT const *f, ALLEGRO_COLOR color, int ch, float xpos, float ypos) { ALLEGRO_TTF_FONT_DATA *data = f->data; FT_Face face = data->face; int advance = 0; int32_t ch32 = (int32_t) ch; int ft_index = FT_Get_Char_Index(face, ch32); advance = render_glyph(f, color, -1, ft_index, -1, ch, xpos, ypos); return advance; } static int ttf_char_length(ALLEGRO_FONT const *f, int ch) { int result; ALLEGRO_TTF_FONT_DATA *data = f->data; ALLEGRO_TTF_GLYPH_DATA *glyph; FT_Face face = data->face; int ft_index = FT_Get_Char_Index(face, ch); if (!get_glyph(data, ft_index, &glyph)) { if (f->fallback) { return al_get_glyph_width(f->fallback, ch); } else { get_glyph(data, 0, &glyph); ft_index = 0; } } cache_glyph(data, face, ft_index, glyph, false); result = glyph->region.w - 4; /* Remove 2-pixel border from width */ return result; } static int ttf_render(ALLEGRO_FONT const *f, ALLEGRO_COLOR color, const ALLEGRO_USTR *text, float x, float y) { ALLEGRO_TTF_FONT_DATA *data = f->data; FT_Face face = data->face; int pos = 0; int advance = 0; int prev_ft_index = -1; int32_t prev_ch = -1; int32_t ch; bool hold; hold = al_is_bitmap_drawing_held(); al_hold_bitmap_drawing(true); while ((ch = al_ustr_get_next(text, &pos)) >= 0) { int ft_index = FT_Get_Char_Index(face, ch); advance += render_glyph(f, color, prev_ft_index, ft_index, prev_ch, ch, x + advance, y); prev_ft_index = ft_index; prev_ch = ch; } al_hold_bitmap_drawing(hold); return advance; } static int ttf_text_length(ALLEGRO_FONT const *f, const ALLEGRO_USTR *text) { int pos = 0; int x = 0; int32_t ch, nch; nch = al_ustr_get_next(text, &pos); while (nch >= 0) { ch = nch; nch = al_ustr_get_next(text, &pos); x += al_get_glyph_advance(f, ch, nch < 0 ? ALLEGRO_NO_KERNING : nch); } return x; } static void ttf_get_text_dimensions(ALLEGRO_FONT const *f, ALLEGRO_USTR const *text, int *bbx, int *bby, int *bbw, int *bbh) { int pos = 0; bool first = true; int x = 0; int32_t ch, nch; int ymin = f->height; int ymax = 0; *bbx = 0; nch = al_ustr_get_next(text, &pos); while (nch >= 0) { int gx, gy, gw, gh; ch = nch; nch = al_ustr_get_next(text, &pos); if (!al_get_glyph_dimensions(f, ch, &gx, &gy, &gw, &gh)) { continue; } if (nch < 0) { x += gx + gw; } else { x += al_get_glyph_advance(f, ch, nch); } if (gy < ymin) { ymin = gy; } if (gh+gy > ymax) { ymax = gh + gy; } if (first) { *bbx = gx; first = false; } } *bby = ymin; *bbw = x - *bbx; *bbh = ymax - ymin; } #ifdef DEBUG_CACHE #include "allegro5/allegro_image.h" static void debug_cache(ALLEGRO_FONT *f) { ALLEGRO_TTF_FONT_DATA *data = f->data; _AL_VECTOR *v = &data->page_bitmaps; static int j = 0; int i; al_init_image_addon(); for (i = 0; i < (int)_al_vector_size(v); i++) { ALLEGRO_BITMAP **bmp = _al_vector_ref(v, i); ALLEGRO_USTR *u = al_ustr_newf("font%d_%d.png", j, i); al_save_bitmap(al_cstr(u), *bmp); al_ustr_free(u); } j++; } #endif static void ttf_destroy(ALLEGRO_FONT *f) { ALLEGRO_TTF_FONT_DATA *data = f->data; int i; unlock_current_page(data); #ifdef DEBUG_CACHE debug_cache(f); #endif FT_Done_Face(data->face); for (i = _al_vector_size(&data->glyph_ranges) - 1; i >= 0; i--) { ALLEGRO_TTF_GLYPH_RANGE *range = _al_vector_ref(&data->glyph_ranges, i); al_free(range->glyphs); } _al_vector_free(&data->glyph_ranges); for (i = _al_vector_size(&data->page_bitmaps) - 1; i >= 0; i--) { ALLEGRO_BITMAP **bmp = _al_vector_ref(&data->page_bitmaps, i); al_destroy_bitmap(*bmp); } _al_vector_free(&data->page_bitmaps); al_free(data); al_free(f); } static unsigned long ftread(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) { ALLEGRO_TTF_FONT_DATA *data = stream->pathname.pointer; unsigned long bytes; if (count == 0) return 0; if (offset != data->offset) al_fseek(data->file, data->base_offset + offset, ALLEGRO_SEEK_SET); bytes = al_fread(data->file, buffer, count); data->offset = offset + bytes; return bytes; } static void ftclose(FT_Stream stream) { ALLEGRO_TTF_FONT_DATA *data = stream->pathname.pointer; al_fclose(data->file); data->file = NULL; } /* Function: al_load_ttf_font_f */ ALLEGRO_FONT *al_load_ttf_font_f(ALLEGRO_FILE *file, char const *filename, int size, int flags) { return al_load_ttf_font_stretch_f(file, filename, 0, size, flags); } /* Function: al_load_ttf_font_stretch_f */ ALLEGRO_FONT *al_load_ttf_font_stretch_f(ALLEGRO_FILE *file, char const *filename, int w, int h, int flags) { FT_Face face; ALLEGRO_TTF_FONT_DATA *data; ALLEGRO_FONT *f; ALLEGRO_PATH *path; FT_Open_Args args; int result; ALLEGRO_CONFIG* system_cfg = al_get_system_config(); const char* min_page_size_str = al_get_config_value(system_cfg, "ttf", "min_page_size"); const char* max_page_size_str = al_get_config_value(system_cfg, "ttf", "max_page_size"); const char* cache_str = al_get_config_value(system_cfg, "ttf", "cache_text"); const char* skip_cache_misses_str = al_get_config_value(system_cfg, "ttf", "skip_cache_misses"); if ((h > 0 && w < 0) || (h < 0 && w > 0)) { ALLEGRO_ERROR("Height/width have opposite signs (w = %d, h = %d).\n", w, h); return NULL; } data = al_calloc(1, sizeof *data); data->stream.read = ftread; data->stream.close = ftclose; data->stream.pathname.pointer = data; data->base_offset = al_ftell(file); data->stream.size = al_fsize(file); data->file = file; data->bitmap_format = al_get_new_bitmap_format(); data->bitmap_flags = al_get_new_bitmap_flags(); data->min_page_size = 256; data->max_page_size = 8192; if (min_page_size_str) { int min_page_size = atoi(min_page_size_str); if (min_page_size > 0) { data->min_page_size = min_page_size; } } if (max_page_size_str) { int max_page_size = atoi(max_page_size_str); if (max_page_size > 0 && max_page_size >= data->min_page_size) { data->max_page_size = max_page_size; } } if (skip_cache_misses_str && !strcmp(skip_cache_misses_str, "true")) { data->skip_cache_misses = true; } memset(&args, 0, sizeof args); args.flags = FT_OPEN_STREAM; args.stream = &data->stream; if ((result = FT_Open_Face(ft, &args, 0, &face)) != 0) { ALLEGRO_ERROR("Reading %s failed. Freetype error code %d\n", filename, result); // Note: Freetype already closed the file for us. al_free(data); return NULL; } // FIXME: The below doesn't use Allegro's streaming. /* Small hack for Type1 fonts which store kerning information in * a separate file - and we try to guess the name of that file. */ path = al_create_path(filename); if (!strcmp(al_get_path_extension(path), ".pfa")) { const char *helper; ALLEGRO_DEBUG("Type1 font assumed for %s.\n", filename); al_set_path_extension(path, ".afm"); helper = al_path_cstr(path, '/'); FT_Attach_File(face, helper); ALLEGRO_DEBUG("Guessed afm file %s.\n", helper); al_set_path_extension(path, ".tfm"); helper = al_path_cstr(path, '/'); FT_Attach_File(face, helper); ALLEGRO_DEBUG("Guessed tfm file %s.\n", helper); } al_destroy_path(path); if (h > 0) { FT_Set_Pixel_Sizes(face, w, h); } else { /* Set the "real dimension" of the font to be the passed size, * in pixels. */ FT_Size_RequestRec req; ASSERT(w <= 0); ASSERT(h <= 0); req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM; req.width = (-w) << 6; req.height = (-h) << 6; req.horiResolution = 0; req.vertResolution = 0; FT_Request_Size(face, &req); } ALLEGRO_DEBUG("Font %s loaded with pixel size %d x %d.\n", filename, w, h); ALLEGRO_DEBUG(" ascent=%.1f, descent=%.1f, height=%.1f\n", face->size->metrics.ascender / 64.0, face->size->metrics.descender / 64.0, face->size->metrics.height / 64.0); data->face = face; data->flags = flags; _al_vector_init(&data->glyph_ranges, sizeof(ALLEGRO_TTF_GLYPH_RANGE)); _al_vector_init(&data->page_bitmaps, sizeof(ALLEGRO_BITMAP*)); if (data->skip_cache_misses) { cache_glyphs(data, "\0", 1); } if (cache_str) { cache_glyphs(data, cache_str, strlen(cache_str)); } unlock_current_page(data); f = al_calloc(sizeof *f, 1); f->height = face->size->metrics.height >> 6; f->vtable = &vt; f->data = data; f->dtor_item = _al_register_destructor(_al_dtor_list, "ttf_font", f, (void (*)(void *))al_destroy_font); return f; } /* Function: al_load_ttf_font */ ALLEGRO_FONT *al_load_ttf_font(char const *filename, int size, int flags) { return al_load_ttf_font_stretch(filename, 0, size, flags); } /* Function: al_load_ttf_font_stretch */ ALLEGRO_FONT *al_load_ttf_font_stretch(char const *filename, int w, int h, int flags) { ALLEGRO_FILE *f; ALLEGRO_FONT *font; ASSERT(filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_ERROR("Unable to open file for reading: %s\n", filename); return NULL; } /* The file handle is owned by the function and the file is usually only * closed when the font is destroyed, in case Freetype has to load data * at a later time. */ font = al_load_ttf_font_stretch_f(f, filename, w, h, flags); return font; } static int ttf_get_font_ranges(ALLEGRO_FONT *font, int ranges_count, int *ranges) { ALLEGRO_TTF_FONT_DATA *data = font->data; FT_UInt g; FT_ULong unicode = FT_Get_First_Char(data->face, &g); int i = 0; if (i < ranges_count) { ranges[i * 2 + 0] = unicode; ranges[i * 2 + 1] = unicode; } while (g) { FT_ULong unicode2 = FT_Get_Next_Char(data->face, unicode, &g); if (unicode + 1 != unicode2) { if (i < ranges_count) { ranges[i * 2 + 1] = unicode; if (i + 1 < ranges_count) { ranges[(i + 1) * 2 + 0] = unicode2; } } i++; } if (i < ranges_count) { ranges[i * 2 + 1] = unicode2; } unicode = unicode2; } return i; } static bool ttf_get_glyph_dimensions(ALLEGRO_FONT const *f, int codepoint, int *bbx, int *bby, int *bbw, int *bbh) { ALLEGRO_TTF_FONT_DATA *data = f->data; ALLEGRO_TTF_GLYPH_DATA *glyph; FT_Face face = data->face; int ft_index = FT_Get_Char_Index(face, codepoint); if (!get_glyph(data, ft_index, &glyph)) { if (f->fallback) { return al_get_glyph_dimensions(f->fallback, codepoint, bbx, bby, bbw, bbh); } else { get_glyph(data, 0, &glyph); ft_index = 0; } } cache_glyph(data, face, ft_index, glyph, false); *bbx = glyph->offset_x; *bbw = glyph->region.w - 4; *bbh = glyph->region.h - 4; *bby = glyph->offset_y; return true; } static int ttf_get_glyph_advance(ALLEGRO_FONT const *f, int codepoint1, int codepoint2) { ALLEGRO_TTF_FONT_DATA *data = f->data; FT_Face face = data->face; int ft_index = FT_Get_Char_Index(face, codepoint1); ALLEGRO_TTF_GLYPH_DATA *glyph; int kerning = 0; int advance = 0; if (codepoint1 == ALLEGRO_NO_KERNING) { return 0; } if (!get_glyph(data, ft_index, &glyph)) { if (f->fallback) { return al_get_glyph_advance(f->fallback, codepoint1, codepoint2); } else { get_glyph(data, 0, &glyph); ft_index = 0; } } cache_glyph(data, face, ft_index, glyph, false); if (codepoint2 != ALLEGRO_NO_KERNING) { int ft_index1 = FT_Get_Char_Index(face, codepoint1); int ft_index2 = FT_Get_Char_Index(face, codepoint2); kerning = get_kerning(data, face, ft_index1, ft_index2); } advance = glyph->advance; return advance + kerning; } /* Function: al_init_ttf_addon */ bool al_init_ttf_addon(void) { if (ttf_inited) { ALLEGRO_WARN("TTF addon already initialised.\n"); return true; } FT_Init_FreeType(&ft); vt.font_height = ttf_font_height; vt.font_ascent = ttf_font_ascent; vt.font_descent = ttf_font_descent; vt.char_length = ttf_char_length; vt.text_length = ttf_text_length; vt.render_char = ttf_render_char; vt.render = ttf_render; vt.destroy = ttf_destroy; vt.get_text_dimensions = ttf_get_text_dimensions; vt.get_font_ranges = ttf_get_font_ranges; vt.get_glyph_dimensions = ttf_get_glyph_dimensions; vt.get_glyph_advance = ttf_get_glyph_advance; vt.get_glyph = ttf_get_glyph; al_register_font_loader(".ttf", al_load_ttf_font); _al_add_exit_func(al_shutdown_ttf_addon, "al_shutdown_ttf_addon"); /* Can't fail right now - in the future we might dynamically load * the FreeType DLL here and/or initialize FreeType (which both * could fail and would cause a false return). */ ttf_inited = true; return ttf_inited; } /* Function: al_is_ttf_addon_initialized */ bool al_is_ttf_addon_initialized(void) { return ttf_inited; } /* Function: al_shutdown_ttf_addon */ void al_shutdown_ttf_addon(void) { if (!ttf_inited) { ALLEGRO_ERROR("TTF addon not initialised.\n"); return; } al_register_font_loader(".ttf", NULL); FT_Done_FreeType(ft); ttf_inited = false; } /* Function: al_get_allegro_ttf_version */ uint32_t al_get_allegro_ttf_version(void) { return ALLEGRO_VERSION_INT; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/video/000077500000000000000000000000001473414355200160365ustar00rootroot00000000000000allegro5-5.2.10.1/addons/video/CMakeLists.txt000066400000000000000000000030611473414355200205760ustar00rootroot00000000000000option(WANT_OGG_VIDEO "Enable Ogg video (requires Theora and Vorbis)" on) set(VIDEO_SOURCES video.c ) set(VIDEO_INCLUDE_FILES allegro5/allegro_video.h) include_directories(../audio ../image .) set_our_header_properties(${VIDEO_INCLUDE_FILES}) # For monolith build. set(VIDEO_INCLUDE_DIRECTORIES) if(WANT_OGG_VIDEO) find_package(Theora) find_package(Vorbis) if(THEORA_FOUND AND VORBIS_FOUND) set(SUPPORT_OGG_VIDEO 1) endif() endif(WANT_OGG_VIDEO) if(SUPPORT_OGG_VIDEO) list(APPEND VIDEO_INCLUDE_DIRECTORIES ${OGG_INCLUDE_DIR} ${VORBIS_INCLUDE_DIR} ${THEORA_INCLUDE_DIR} ) list(APPEND VIDEO_SOURCES ogv.c) set(SUPPORT_VIDEO 1) set(ALLEGRO_CFG_VIDEO_HAVE_OGV 1) set(VIDEO_LIBRARIES ${VIDEO_LIBRARIES} ${THEORA_LIBRARIES} ${VORBIS_LIBRARIES}) endif(SUPPORT_OGG_VIDEO) if(NOT SUPPORT_VIDEO) message("WARNING: allegro_video wanted but no supported backend found") return() endif(NOT SUPPORT_VIDEO) include_directories(SYSTEM ${VIDEO_INCLUDE_DIRECTORIES}) configure_file( allegro5/internal/aintern_video_cfg.h.cmake ${PROJECT_BINARY_DIR}/include/allegro5/internal/aintern_video_cfg.h ) add_our_addon_library(allegro_video AllegroVideo-${ALLEGRO_SOVERSION} "${VIDEO_SOURCES};${VIDEO_INCLUDE_FILES}" "-DALLEGRO_VIDEO_SRC" "${ALLEGRO_LINK_WITH};${AUDIO_LINK_WITH};${VIDEO_LIBRARIES}" ) install_our_headers(${VIDEO_INCLUDE_FILES}) add_addon(video) #-----------------------------------------------------------------------------# # vi: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/addons/video/allegro5/000077500000000000000000000000001473414355200175505ustar00rootroot00000000000000allegro5-5.2.10.1/addons/video/allegro5/allegro_video.h000066400000000000000000000060231473414355200225350ustar00rootroot00000000000000#ifndef __al_included_allegro_video_h #define __al_included_allegro_video_h #ifdef __cplusplus extern "C" { #endif #include "allegro5/allegro5.h" #include "allegro5/allegro_audio.h" #if (defined ALLEGRO_MINGW32) || (defined ALLEGRO_MSVC) || (defined ALLEGRO_BCC32) #ifndef ALLEGRO_STATICLINK #ifdef ALLEGRO_VIDEO_SRC #define _ALLEGRO_VIDEO_DLL __declspec(dllexport) #else #define _ALLEGRO_VIDEO_DLL __declspec(dllimport) #endif #else #define _ALLEGRO_VIDEO_DLL #endif #endif #if defined ALLEGRO_MSVC #define ALLEGRO_VIDEO_FUNC(type, name, args) _ALLEGRO_VIDEO_DLL type __cdecl name args #elif defined ALLEGRO_MINGW32 #define ALLEGRO_VIDEO_FUNC(type, name, args) extern type name args #elif defined ALLEGRO_BCC32 #define ALLEGRO_VIDEO_FUNC(type, name, args) extern _ALLEGRO_VIDEO_DLL type name args #else #define ALLEGRO_VIDEO_FUNC AL_FUNC #endif /* Enum: ALLEGRO_VIDEO_EVENT_TYPE */ enum ALLEGRO_VIDEO_EVENT_TYPE { ALLEGRO_EVENT_VIDEO_FRAME_SHOW = 550, ALLEGRO_EVENT_VIDEO_FINISHED = 551, _ALLEGRO_EVENT_VIDEO_SEEK = 552 /* internal */ }; enum ALLEGRO_VIDEO_POSITION_TYPE { ALLEGRO_VIDEO_POSITION_ACTUAL = 0, ALLEGRO_VIDEO_POSITION_VIDEO_DECODE = 1, ALLEGRO_VIDEO_POSITION_AUDIO_DECODE = 2 }; /* Enum: ALLEGRO_VIDEO_POSITION_TYPE */ typedef enum ALLEGRO_VIDEO_POSITION_TYPE ALLEGRO_VIDEO_POSITION_TYPE; typedef struct ALLEGRO_VIDEO ALLEGRO_VIDEO; ALLEGRO_VIDEO_FUNC(ALLEGRO_VIDEO *, al_open_video, (char const *filename)); ALLEGRO_VIDEO_FUNC(void, al_close_video, (ALLEGRO_VIDEO *video)); ALLEGRO_VIDEO_FUNC(void, al_start_video, (ALLEGRO_VIDEO *video, ALLEGRO_MIXER *mixer)); ALLEGRO_VIDEO_FUNC(void, al_start_video_with_voice, (ALLEGRO_VIDEO *video, ALLEGRO_VOICE *voice)); ALLEGRO_VIDEO_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_video_event_source, (ALLEGRO_VIDEO *video)); ALLEGRO_VIDEO_FUNC(void, al_set_video_playing, (ALLEGRO_VIDEO *video, bool playing)); ALLEGRO_VIDEO_FUNC(bool, al_is_video_playing, (ALLEGRO_VIDEO *video)); ALLEGRO_VIDEO_FUNC(double, al_get_video_audio_rate, (ALLEGRO_VIDEO *video)); ALLEGRO_VIDEO_FUNC(double, al_get_video_fps, (ALLEGRO_VIDEO *video)); ALLEGRO_VIDEO_FUNC(float, al_get_video_scaled_width, (ALLEGRO_VIDEO *video)); ALLEGRO_VIDEO_FUNC(float, al_get_video_scaled_height, (ALLEGRO_VIDEO *video)); ALLEGRO_VIDEO_FUNC(ALLEGRO_BITMAP *, al_get_video_frame, (ALLEGRO_VIDEO *video)); ALLEGRO_VIDEO_FUNC(double, al_get_video_position, (ALLEGRO_VIDEO *video, ALLEGRO_VIDEO_POSITION_TYPE which)); ALLEGRO_VIDEO_FUNC(bool, al_seek_video, (ALLEGRO_VIDEO *video, double pos_in_seconds)); ALLEGRO_VIDEO_FUNC(bool, al_init_video_addon, (void)); ALLEGRO_VIDEO_FUNC(bool, al_is_video_addon_initialized, (void)); ALLEGRO_VIDEO_FUNC(void, al_shutdown_video_addon, (void)); ALLEGRO_VIDEO_FUNC(uint32_t, al_get_allegro_video_version, (void)); ALLEGRO_VIDEO_FUNC(char const *, al_identify_video_f, (ALLEGRO_FILE *fp)); ALLEGRO_VIDEO_FUNC(char const *, al_identify_video, (char const *filename)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/addons/video/allegro5/internal/000077500000000000000000000000001473414355200213645ustar00rootroot00000000000000allegro5-5.2.10.1/addons/video/allegro5/internal/aintern_video.h000066400000000000000000000025101473414355200243610ustar00rootroot00000000000000#ifndef __al_included_allegro_aintern_video_h #define __al_included_allegro_aintern_video_h #include "allegro5/internal/aintern_list.h" typedef struct ALLEGRO_VIDEO_INTERFACE { bool (*open_video)(ALLEGRO_VIDEO *video); bool (*close_video)(ALLEGRO_VIDEO *video); bool (*start_video)(ALLEGRO_VIDEO *video); bool (*set_video_playing)(ALLEGRO_VIDEO *video); bool (*seek_video)(ALLEGRO_VIDEO *video, double seek_to); bool (*update_video)(ALLEGRO_VIDEO *video); } ALLEGRO_VIDEO_INTERFACE; struct ALLEGRO_VIDEO { ALLEGRO_VIDEO_INTERFACE *vtable; /* video */ ALLEGRO_BITMAP *current_frame; double video_position; double fps; float scaled_width; float scaled_height; /* audio */ ALLEGRO_MIXER *mixer; ALLEGRO_VOICE *voice; ALLEGRO_AUDIO_STREAM *audio; double audio_position; double audio_rate; /* general */ bool es_inited; ALLEGRO_EVENT_SOURCE es; ALLEGRO_PATH *filename; bool playing; double position; _AL_LIST_ITEM *dtor_item; /* implementation specific */ void *data; }; typedef bool (*ALLEGRO_VIDEO_IDENTIFIER_FUNCTION)(ALLEGRO_FILE *f); void _al_compute_scaled_dimensions(int frame_w, int frame_h, float aspect_ratio, float *scaled_w, float *scaled_h); ALLEGRO_VIDEO_INTERFACE *_al_video_ogv_vtable(void); bool _al_video_identify_ogv(ALLEGRO_FILE *f); #endif allegro5-5.2.10.1/addons/video/allegro5/internal/aintern_video_cfg.h.cmake000066400000000000000000000000501473414355200262540ustar00rootroot00000000000000#cmakedefine ALLEGRO_CFG_VIDEO_HAVE_OGV allegro5-5.2.10.1/addons/video/ogv.c000066400000000000000000001047611473414355200170060ustar00rootroot00000000000000/* Ogg Theora/Vorbis video backend * * TODO: * - seeking * - generate video frame events * - better ycbcr->rgb * - improve frame skipping * - Ogg Skeleton support * - pass Theora test suite * * NOTE: we treat Ogg timestamps as the beginning of frames. In reality they * are end timestamps. Normally this should not be noticeable, but can make a * difference. */ #include #include "allegro5/allegro5.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_video.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_vector.h" #include "allegro5/internal/aintern_video.h" #include #include #include #include ALLEGRO_DEBUG_CHANNEL("video") /* XXX probably should be based on stream parameters */ static const int NUM_FRAGS = 2; static const int FRAG_SAMPLES = 4096; static const int RGB_PIXEL_FORMAT = ALLEGRO_PIXEL_FORMAT_ABGR_8888; typedef struct OGG_VIDEO OGG_VIDEO; typedef struct STREAM STREAM; typedef struct THEORA_STREAM THEORA_STREAM; typedef struct VORBIS_STREAM VORBIS_STREAM; typedef struct PACKET_NODE PACKET_NODE; enum { STREAM_TYPE_UNKNOWN = 0, STREAM_TYPE_THEORA, STREAM_TYPE_VORBIS }; struct PACKET_NODE { PACKET_NODE *next; ogg_packet pkt; }; struct THEORA_STREAM { th_info info; th_comment comment; th_setup_info *setup; th_dec_ctx *ctx; ogg_int64_t prev_framenum; double frame_duration; }; struct VORBIS_STREAM { vorbis_info info; vorbis_comment comment; bool inited_for_data; vorbis_dsp_state dsp; vorbis_block block; int channels; float *next_fragment; /* channels * FRAG_SAMPLES elements */ int next_fragment_pos; }; struct STREAM { int stream_type; bool active; bool headers_done; ogg_stream_state state; PACKET_NODE *packet_queue; union { THEORA_STREAM theora; VORBIS_STREAM vorbis; } u; }; struct OGG_VIDEO { ALLEGRO_FILE *fp; bool reached_eof; ogg_sync_state sync_state; _AL_VECTOR streams; /* vector of STREAM pointers */ STREAM *selected_video_stream; /* one of the streams */ STREAM *selected_audio_stream; /* one of the streams */ int seek_counter; /* Video output. */ th_pixel_fmt pixel_fmt; th_ycbcr_buffer buffer; bool buffer_dirty; unsigned char* rgb_data; ALLEGRO_BITMAP *frame_bmp; ALLEGRO_BITMAP *pic_bmp; /* frame_bmp, or subbitmap thereof */ ALLEGRO_EVENT_SOURCE evtsrc; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_MUTEX *mutex; ALLEGRO_COND *cond; ALLEGRO_THREAD *thread; }; /* forward declarations */ static bool ogv_close_video(ALLEGRO_VIDEO *video); /* Packet queue. */ static PACKET_NODE *create_packet_node(ogg_packet *packet) { PACKET_NODE *node = al_malloc(sizeof(PACKET_NODE)); node->next = NULL; node->pkt = *packet; node->pkt.packet = al_malloc(packet->bytes); memcpy(node->pkt.packet, packet->packet, packet->bytes); return node; } static void free_packet_node(PACKET_NODE *node) { ASSERT(node->next == NULL); al_free(node->pkt.packet); al_free(node); } static void add_tail_packet(STREAM *stream, PACKET_NODE *node) { PACKET_NODE *cur; ASSERT(node->next == NULL); for (cur = stream->packet_queue; cur != NULL; cur = cur->next) { if (cur->next == NULL) { cur->next = node; ASSERT(cur->pkt.packetno < node->pkt.packetno); return; } } ASSERT(stream->packet_queue == NULL); stream->packet_queue = node; } static void add_head_packet(STREAM *stream, PACKET_NODE *node) { ASSERT(node->next == NULL); node->next = stream->packet_queue; stream->packet_queue = node; if (node->next) { ASSERT(node->pkt.packetno < node->next->pkt.packetno); } } static PACKET_NODE *take_head_packet(STREAM *stream) { PACKET_NODE *cur; cur = stream->packet_queue; if (!cur) { return NULL; } if (cur->next) { ASSERT(cur->pkt.packetno < cur->next->pkt.packetno); } stream->packet_queue = cur->next; cur->next = NULL; return cur; } static void free_packet_queue(STREAM *stream) { while (stream->packet_queue) { PACKET_NODE *node = stream->packet_queue; stream->packet_queue = node->next; node->next = NULL; free_packet_node(node); } } static void deactivate_stream(STREAM *stream) { stream->active = false; free_packet_queue(stream); } /* Logical streams. */ static STREAM *create_stream(OGG_VIDEO *ogv, int serial) { STREAM *stream; STREAM **slot; stream = al_calloc(1, sizeof(STREAM)); stream->stream_type = STREAM_TYPE_UNKNOWN; stream->active = true; stream->headers_done = false; ogg_stream_init(&stream->state, serial); stream->packet_queue = NULL; slot = _al_vector_alloc_back(&ogv->streams); (*slot) = stream; return stream; } static STREAM *find_stream(OGG_VIDEO *ogv, int serial) { unsigned i; for (i = 0; i < _al_vector_size(&ogv->streams); i++) { STREAM **slot = _al_vector_ref(&ogv->streams, i); STREAM *stream = *slot; if (stream->state.serialno == serial) { return stream; } } return NULL; } static void free_stream(STREAM *stream) { ASSERT(stream); ogg_stream_clear(&stream->state); free_packet_queue(stream); switch (stream->stream_type) { case STREAM_TYPE_UNKNOWN: break; case STREAM_TYPE_THEORA: { THEORA_STREAM *tstream = &stream->u.theora; ALLEGRO_DEBUG("Clean up Theora.\n"); th_info_clear(&tstream->info); th_comment_clear(&tstream->comment); if (tstream->setup) { th_setup_free(tstream->setup); } if (tstream->ctx) { th_decode_free(tstream->ctx); } } break; case STREAM_TYPE_VORBIS: { VORBIS_STREAM *vstream = &stream->u.vorbis; ALLEGRO_DEBUG("Clean up Vorbis.\n"); vorbis_info_clear(&vstream->info); vorbis_comment_clear(&vstream->comment); if (vstream->inited_for_data) { vorbis_block_clear(&vstream->block); vorbis_dsp_clear(&vstream->dsp); } al_free(vstream->next_fragment); } break; } al_free(stream); } /* Returns true if got a page. */ static bool read_page(OGG_VIDEO *ogv, ogg_page *page) { const int buffer_size = 4096; if (al_feof(ogv->fp) || al_ferror(ogv->fp)) { ogv->reached_eof = true; return ogg_sync_pageout(&ogv->sync_state, page) == 1; } while (ogg_sync_pageout(&ogv->sync_state, page) != 1) { char *buffer; size_t bytes; int rc; buffer = ogg_sync_buffer(&ogv->sync_state, buffer_size); bytes = al_fread(ogv->fp, buffer, buffer_size); if (bytes == 0) { ALLEGRO_DEBUG("End of file.\n"); return false; } rc = ogg_sync_wrote(&ogv->sync_state, bytes); ASSERT(rc == 0); } return true; } /* Return true if got a packet for the stream. */ static bool read_packet(OGG_VIDEO *ogv, STREAM *stream, ogg_packet *packet) { ogg_page page; int rc; for (;;) { rc = ogg_stream_packetout(&stream->state, packet); if (rc == 1) { /* Got a packet for stream. */ return true; } if (read_page(ogv, &page)) { STREAM *page_stream = find_stream(ogv, ogg_page_serialno(&page)); if (page_stream && page_stream->active) { rc = ogg_stream_pagein(&page_stream->state, &page); ASSERT(rc == 0); } } else { return false; } } } /* Header decoding. */ static bool try_decode_theora_header(STREAM *stream, ogg_packet *packet) { int rc; switch (stream->stream_type) { case STREAM_TYPE_UNKNOWN: th_info_init(&stream->u.theora.info); th_comment_init(&stream->u.theora.comment); break; case STREAM_TYPE_THEORA: break; case STREAM_TYPE_VORBIS: return false; } if (stream->headers_done) { add_tail_packet(stream, create_packet_node(packet)); return true; } rc = th_decode_headerin(&stream->u.theora.info, &stream->u.theora.comment, &stream->u.theora.setup, packet); if (rc > 0) { /* Successfully parsed a Theora header. */ if (stream->stream_type == STREAM_TYPE_UNKNOWN) { ALLEGRO_DEBUG("Found Theora stream.\n"); stream->stream_type = STREAM_TYPE_THEORA; } return true; } if (rc == 0) { /* First Theora data packet. */ add_tail_packet(stream, create_packet_node(packet)); stream->headers_done = true; return true; } th_info_clear(&stream->u.theora.info); th_comment_clear(&stream->u.theora.comment); return false; } static int try_decode_vorbis_header(STREAM *stream, ogg_packet *packet) { int rc; switch (stream->stream_type) { case STREAM_TYPE_UNKNOWN: vorbis_info_init(&stream->u.vorbis.info); vorbis_comment_init(&stream->u.vorbis.comment); break; case STREAM_TYPE_VORBIS: break; case STREAM_TYPE_THEORA: return false; } rc = vorbis_synthesis_headerin(&stream->u.vorbis.info, &stream->u.vorbis.comment, packet); if (rc == 0) { /* Successfully parsed a Vorbis header. */ if (stream->stream_type == STREAM_TYPE_UNKNOWN) { ALLEGRO_INFO("Found Vorbis stream.\n"); stream->stream_type = STREAM_TYPE_VORBIS; stream->u.vorbis.inited_for_data = false; } return true; } if (stream->stream_type == STREAM_TYPE_VORBIS && rc == OV_ENOTVORBIS) { /* First data packet. */ add_tail_packet(stream, create_packet_node(packet)); stream->headers_done = true; return true; } vorbis_info_clear(&stream->u.vorbis.info); vorbis_comment_clear(&stream->u.vorbis.comment); return false; } static bool all_headers_done(OGG_VIDEO *ogv) { bool have_something = false; unsigned i; for (i = 0; i < _al_vector_size(&ogv->streams); i++) { STREAM **slot = _al_vector_ref(&ogv->streams, i); STREAM *stream = *slot; switch (stream->stream_type) { case STREAM_TYPE_THEORA: case STREAM_TYPE_VORBIS: have_something = true; if (!stream->headers_done) return false; break; case STREAM_TYPE_UNKNOWN: break; } } return have_something; } static void read_headers(OGG_VIDEO *ogv) { ogg_page page; ogg_packet packet; STREAM *stream; int serial; int rc; ALLEGRO_DEBUG("Begin reading headers.\n"); do { /* Read a page of data. */ if (!read_page(ogv, &page)) { break; } /* Which stream is this page for? */ serial = ogg_page_serialno(&page); /* Start a new stream or find an existing one. */ if (ogg_page_bos(&page)) { stream = create_stream(ogv, serial); } else { stream = find_stream(ogv, serial); } if (!stream) { ALLEGRO_WARN("No stream for serial: %x\n", serial); continue; } if (!stream->active) { continue; } /* Add the page to the stream. */ rc = ogg_stream_pagein(&stream->state, &page); ASSERT(rc == 0); /* Look for a complete packet. */ rc = ogg_stream_packetpeek(&stream->state, &packet); if (rc == 0) { continue; } if (rc == -1) { ALLEGRO_WARN("No packet due to lost sync or hole in data.\n"); continue; } /* Try to decode the packet as a Theora or Vorbis header. */ if (!try_decode_theora_header(stream, &packet)) { if (!try_decode_vorbis_header(stream, &packet)) { ALLEGRO_DEBUG("Unknown packet type ignored.\n"); } } /* Consume the packet. */ rc = ogg_stream_packetout(&stream->state, &packet); ASSERT(rc == 1); } while (!all_headers_done(ogv)); ALLEGRO_DEBUG("End reading headers.\n"); } /* Vorbis streams. */ static void setup_vorbis_stream_decode(ALLEGRO_VIDEO *video, STREAM *stream) { VORBIS_STREAM * const vstream = &stream->u.vorbis; int rc; rc = vorbis_synthesis_init(&vstream->dsp, &vstream->info); ASSERT(rc == 0); rc = vorbis_block_init(&vstream->dsp, &vstream->block); ASSERT(rc == 0); vstream->inited_for_data = true; video->audio_rate = vstream->info.rate; vstream->channels = vstream->info.channels; vstream->next_fragment = al_calloc(vstream->channels * FRAG_SAMPLES, sizeof(float)); ALLEGRO_INFO("Audio rate: %f\n", video->audio_rate); ALLEGRO_INFO("Audio channels: %d\n", vstream->channels); } static void handle_vorbis_data(VORBIS_STREAM *vstream, ogg_packet *packet) { int rc; rc = vorbis_synthesis(&vstream->block, packet); if (rc != 0) { ALLEGRO_ERROR("vorbis_synthesis returned %d\n", rc); return; } rc = vorbis_synthesis_blockin(&vstream->dsp, &vstream->block); if (rc != 0) { ALLEGRO_ERROR("vorbis_synthesis_blockin returned %d\n", rc); return; } } static bool generate_next_audio_fragment(VORBIS_STREAM *vstream) { float **pcm = NULL; float *p; int samples; int i, ch; int rc; samples = vorbis_synthesis_pcmout(&vstream->dsp, &pcm); if (samples == 0) { return false; } if (samples > FRAG_SAMPLES - vstream->next_fragment_pos) { samples = FRAG_SAMPLES - vstream->next_fragment_pos; } ASSERT(vstream->next_fragment); p = &vstream->next_fragment[ vstream->channels * vstream->next_fragment_pos]; if (vstream->channels == 2) { for (i = 0; i < samples; i++) { *p++ = pcm[0][i]; *p++ = pcm[1][i]; } } else if (vstream->channels == 1) { for (i = 0; i < samples; i++) { *p++ = pcm[0][i]; } } else { for (i = 0; i < samples; i++) { for (ch = 0; ch < vstream->channels; ch++) { *p++ = pcm[ch][i]; } } } vstream->next_fragment_pos += samples; rc = vorbis_synthesis_read(&vstream->dsp, samples); ASSERT(rc == 0); return true; } static void poll_vorbis_decode(OGG_VIDEO *ogv, STREAM *vstream_outer) { VORBIS_STREAM * const vstream = &vstream_outer->u.vorbis; while (vstream->next_fragment_pos < FRAG_SAMPLES && generate_next_audio_fragment(vstream)) { } while (vstream->next_fragment_pos < FRAG_SAMPLES) { PACKET_NODE *node; ogg_packet packet; node = take_head_packet(vstream_outer); if (node) { handle_vorbis_data(vstream, &node->pkt); generate_next_audio_fragment(vstream); free_packet_node(node); } else if (read_packet(ogv, vstream_outer, &packet)) { handle_vorbis_data(vstream, &packet); generate_next_audio_fragment(vstream); } else { break; } } } static ALLEGRO_AUDIO_STREAM *create_audio_stream(const ALLEGRO_VIDEO *video, const STREAM *vstream_outer) { const VORBIS_STREAM *vstream = &vstream_outer->u.vorbis; ALLEGRO_AUDIO_STREAM *audio; int chanconf; int rc; switch (vstream->channels) { case 1: chanconf = ALLEGRO_CHANNEL_CONF_1; break; case 2: chanconf = ALLEGRO_CHANNEL_CONF_2; break; case 3: chanconf = ALLEGRO_CHANNEL_CONF_3; break; case 4: chanconf = ALLEGRO_CHANNEL_CONF_4; break; case 6: chanconf = ALLEGRO_CHANNEL_CONF_5_1; break; case 7: chanconf = ALLEGRO_CHANNEL_CONF_6_1; break; case 8: chanconf = ALLEGRO_CHANNEL_CONF_7_1; break; default: ALLEGRO_WARN("Unsupported number of channels: %d\n", vstream->channels); return NULL; } audio = al_create_audio_stream(NUM_FRAGS, FRAG_SAMPLES, vstream->info.rate, ALLEGRO_AUDIO_DEPTH_FLOAT32, chanconf); if (!audio) { ALLEGRO_ERROR("Could not create audio stream.\n"); return NULL; } if (video->mixer) { rc = al_attach_audio_stream_to_mixer(audio, video->mixer); } else if (video->voice) { rc = al_attach_audio_stream_to_voice(audio, video->voice); } else { rc = al_attach_audio_stream_to_mixer(audio, al_get_default_mixer()); } if (rc) { ALLEGRO_DEBUG("Audio stream ready.\n"); } else { ALLEGRO_ERROR("Could not attach audio stream.\n"); al_destroy_audio_stream(audio); audio = NULL; } return audio; } static void update_audio_fragment(ALLEGRO_AUDIO_STREAM *audio_stream, VORBIS_STREAM *vstream, bool paused, bool reached_eof) { float *frag; frag = al_get_audio_stream_fragment(audio_stream); if (!frag) return; if (paused || vstream->next_fragment_pos < FRAG_SAMPLES) { if (!paused && !reached_eof) { ALLEGRO_WARN("Next fragment not ready.\n"); } memset(frag, 0, vstream->channels * FRAG_SAMPLES * sizeof(float)); } else { memcpy(frag, vstream->next_fragment, vstream->channels * FRAG_SAMPLES * sizeof(float)); vstream->next_fragment_pos = 0; } al_set_audio_stream_fragment(audio_stream, frag); } /* Theora streams. */ static void setup_theora_stream_decode(ALLEGRO_VIDEO *video, OGG_VIDEO *ogv, STREAM *tstream_outer) { THEORA_STREAM * const tstream = &tstream_outer->u.theora; int frame_w = tstream->info.frame_width; int frame_h = tstream->info.frame_height; int pic_x = tstream->info.pic_x; int pic_y = tstream->info.pic_y; int pic_w = tstream->info.pic_width; int pic_h = tstream->info.pic_height; float aspect_ratio = 1.0; tstream->ctx = th_decode_alloc(&tstream->info, tstream->setup); ASSERT(tstream->ctx); th_setup_free(tstream->setup); tstream->setup = NULL; ogv->pixel_fmt = tstream->info.pixel_fmt; ogv->frame_bmp = al_create_bitmap(frame_w, frame_h); if (pic_x == 0 && pic_y == 0 && pic_w == frame_w && pic_h == frame_h) { ogv->pic_bmp = ogv->frame_bmp; } else { ogv->pic_bmp = al_create_sub_bitmap(ogv->frame_bmp, pic_x, pic_y, pic_w, pic_h); } ogv->rgb_data = al_malloc(al_get_pixel_size(RGB_PIXEL_FORMAT) * frame_w * frame_h); video->fps = (double)tstream->info.fps_numerator / (double)tstream->info.fps_denominator; tstream->frame_duration = (double)tstream->info.fps_denominator / (double)tstream->info.fps_numerator; if (tstream->info.aspect_denominator != 0) { aspect_ratio = (double)(pic_w * tstream->info.aspect_numerator) / (double)(pic_h * tstream->info.aspect_denominator); } _al_compute_scaled_dimensions(pic_w, pic_h, aspect_ratio, &video->scaled_width, &video->scaled_height); tstream->prev_framenum = -1; ALLEGRO_INFO("Frame size: %dx%d\n", frame_w, frame_h); ALLEGRO_INFO("Picture size: %dx%d\n", pic_w, pic_h); ALLEGRO_INFO("Scaled size: %fx%f\n", video->scaled_width, video->scaled_height); ALLEGRO_INFO("FPS: %f\n", video->fps); ALLEGRO_INFO("Frame_duration: %f\n", tstream->frame_duration); } static int64_t get_theora_framenum(THEORA_STREAM *tstream, ogg_packet *packet) { if (packet->granulepos > 0) { return th_granule_frame(&tstream->info, packet->granulepos); } return tstream->prev_framenum + 1; } static bool handle_theora_data(ALLEGRO_VIDEO *video, THEORA_STREAM *tstream, ogg_packet *packet, bool *ret_new_frame) { int64_t expected_framenum; int64_t framenum; int rc; expected_framenum = tstream->prev_framenum + 1; framenum = get_theora_framenum(tstream, packet); if (framenum > expected_framenum) { /* Packet is for a later frame, don't decode it yet. */ ALLEGRO_DEBUG("Expected frame %ld, got %ld\n", (long)expected_framenum, (long)framenum); video->video_position += tstream->frame_duration; tstream->prev_framenum++; return false; } if (framenum < expected_framenum) { ALLEGRO_DEBUG("Expected frame %ld, got %ld (decoding anyway)\n", (long)expected_framenum, (long)framenum); } rc = th_decode_packetin(tstream->ctx, packet, NULL); if (rc != TH_EBADPACKET) { /* HACK: When we seek to beginning, the first few packets are actually * headers. To properly fix this, those packets should be ignored when we * do the seeking (see the XXX there). */ ASSERT(rc == 0 || rc == TH_DUPFRAME); } if (rc == 0) { *ret_new_frame = true; video->video_position = framenum * tstream->frame_duration; tstream->prev_framenum = framenum; } return true; } /* Y'CrCb to RGB conversion. */ /* XXX simple slow implementation */ static unsigned char clamp(int x) { if (x < 0) return 0; if (x > 255) return 255; return x; } static INLINE void ycbcr_to_rgb(th_ycbcr_buffer buffer, unsigned char* rgb_data, int pixel_size, int pitch, int xshift, int yshift) { const int w = buffer[0].width; const int h = buffer[0].height; int x, y; for (y = 0; y < h; y++) { const int y2 = y >> yshift; for (x = 0; x < w; x++) { const int x2 = x >> xshift; unsigned char * const data = rgb_data + y * pitch + x * pixel_size; const int yp = buffer[0].data[y * buffer[0].stride + x ]; const int cb = buffer[1].data[y2 * buffer[1].stride + x2]; const int cr = buffer[2].data[y2 * buffer[2].stride + x2]; const int C = yp - 16; const int D = cb - 128; const int E = cr - 128; data[0] = clamp((298*C + 409*E + 128) >> 8); data[1] = clamp((298*C - 100*D - 208*E + 128) >> 8); data[2] = clamp((298*C + 516*D + 128) >> 8); data[3] = 0xff; } } } static void convert_buffer_to_rgba(OGG_VIDEO *ogv) { const int pixel_size = al_get_pixel_size(RGB_PIXEL_FORMAT); const int pitch = pixel_size * al_get_bitmap_width(ogv->frame_bmp); switch (ogv->pixel_fmt) { case TH_PF_420: ycbcr_to_rgb(ogv->buffer, ogv->rgb_data, pixel_size, pitch, 1, 1); break; case TH_PF_422: ycbcr_to_rgb(ogv->buffer, ogv->rgb_data, pixel_size, pitch, 1, 0); break; case TH_PF_444: ycbcr_to_rgb(ogv->buffer, ogv->rgb_data, pixel_size, pitch, 0, 0); break; default: ALLEGRO_ERROR("Unsupported pixel format.\n"); break; } } static int poll_theora_decode(ALLEGRO_VIDEO *video, STREAM *tstream_outer) { OGG_VIDEO * const ogv = video->data; THEORA_STREAM * const tstream = &tstream_outer->u.theora; bool new_frame = false; int num_frames = 0; int rc; while (video->video_position < video->position) { PACKET_NODE *node; ogg_packet packet; node = take_head_packet(tstream_outer); if (node) { if (handle_theora_data(video, tstream, &node->pkt, &new_frame)) { free_packet_node(node); num_frames++; } else { add_head_packet(tstream_outer, node); } } else if (read_packet(ogv, tstream_outer, &packet)) { if (handle_theora_data(video, tstream, &packet, &new_frame)) { num_frames++; } else { add_head_packet(tstream_outer, create_packet_node(&packet)); } } else { break; } /* Only skip frames if we are really falling behind, not just slightly * ahead of the target position. * XXX improve frame skipping algorithm */ if (video->video_position >= video->position - 3.0*tstream->frame_duration) { break; } } if (new_frame) { ALLEGRO_EVENT event; al_lock_mutex(ogv->mutex); rc = th_decode_ycbcr_out(tstream->ctx, ogv->buffer); ASSERT(rc == 0); convert_buffer_to_rgba(ogv); ogv->buffer_dirty = true; event.type = ALLEGRO_EVENT_VIDEO_FRAME_SHOW; event.user.data1 = (intptr_t)video; al_emit_user_event(&video->es, &event, NULL); al_unlock_mutex(ogv->mutex); } return num_frames; } /* Seeking. */ static void seek_to_beginning(ALLEGRO_VIDEO *video, OGG_VIDEO *ogv, THEORA_STREAM *tstream) { unsigned i; int rc; bool seeked; for (i = 0; i < _al_vector_size(&ogv->streams); i++) { STREAM **slot = _al_vector_ref(&ogv->streams, i); STREAM *stream = *slot; ogg_stream_reset(&stream->state); free_packet_queue(stream); } if (tstream) { ogg_int64_t granpos = 0; rc = th_decode_ctl(tstream->ctx, TH_DECCTL_SET_GRANPOS, &granpos, sizeof(granpos)); ASSERT(rc == 0); tstream->prev_framenum = -1; } rc = ogg_sync_reset(&ogv->sync_state); ASSERT(rc == 0); seeked = al_fseek(ogv->fp, 0, SEEK_SET); ASSERT(seeked); /* XXX read enough file data to get into position */ ogv->reached_eof = false; video->audio_position = 0.0; video->video_position = 0.0; video->position = 0.0; /* XXX maybe clear backlog of time and stream fragment events */ } /* Decode thread. */ static void *decode_thread_func(ALLEGRO_THREAD *thread, void *_video) { ALLEGRO_VIDEO * const video = _video; OGG_VIDEO * const ogv = video->data; STREAM *tstream_outer; THEORA_STREAM *tstream = NULL; STREAM *vstream_outer; VORBIS_STREAM *vstream = NULL; ALLEGRO_TIMER *timer; double audio_pos_step = 0.0; double timer_dur; ALLEGRO_DEBUG("Thread started.\n"); /* Destruction is handled by al_close_video. */ _al_push_destructor_owner(); tstream_outer = ogv->selected_video_stream; if (tstream_outer) { ASSERT(tstream_outer->stream_type == STREAM_TYPE_THEORA); tstream = &tstream_outer->u.theora; } vstream_outer = ogv->selected_audio_stream; if (vstream_outer) { ASSERT(vstream_outer->stream_type == STREAM_TYPE_VORBIS); video->audio = create_audio_stream(video, vstream_outer); if (video->audio) { vstream = &vstream_outer->u.vorbis; audio_pos_step = (double)FRAG_SAMPLES / vstream->info.rate; } else { deactivate_stream(vstream_outer); vstream_outer = NULL; } } if (!tstream_outer && !vstream_outer) { ALLEGRO_WARN("No audio or video stream found.\n"); _al_pop_destructor_owner(); return NULL; } timer_dur = 1.0; if (audio_pos_step != 0.0) { timer_dur = audio_pos_step / NUM_FRAGS; } if (tstream && tstream->frame_duration < timer_dur) { timer_dur = tstream->frame_duration; } timer = al_create_timer(timer_dur); al_register_event_source(ogv->queue, al_get_timer_event_source(timer)); if (video->audio) { al_register_event_source(ogv->queue, al_get_audio_stream_event_source(video->audio)); } _al_pop_destructor_owner(); ALLEGRO_DEBUG("Begin decode loop.\n"); al_start_timer(timer); while (!al_get_thread_should_stop(thread)) { ALLEGRO_EVENT ev; al_wait_for_event(ogv->queue, &ev); if (ev.type == _ALLEGRO_EVENT_VIDEO_SEEK) { double seek_to = ev.user.data1 / 1.0e6; /* XXX we only know how to seek to start of video */ ASSERT(seek_to <= 0.0); al_lock_mutex(ogv->mutex); seek_to_beginning(video, ogv, tstream); ogv->seek_counter++; al_broadcast_cond(ogv->cond); al_unlock_mutex(ogv->mutex); continue; } if (ev.type == ALLEGRO_EVENT_TIMER) { if (vstream_outer && video->playing) { poll_vorbis_decode(ogv, vstream_outer); } /* If no audio then video is master. */ if (!video->audio && video->playing && !ogv->reached_eof) { video->position += tstream->frame_duration; } if (tstream_outer) { poll_theora_decode(video, tstream_outer); } if (video->playing && ogv->reached_eof) { ALLEGRO_EVENT event; video->playing = false; event.type = ALLEGRO_EVENT_VIDEO_FINISHED; event.user.data1 = (intptr_t)video; al_emit_user_event(&video->es, &event, NULL); } } if (ev.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT) { /* Audio clock is master when it exists. */ /* XXX This doesn't work well when the process is paused then resumed, * due to a problem with the audio addon. We get a flood of * fragment events which pushes the position field ahead of the * real audio position. */ if (video->playing && !ogv->reached_eof) { video->audio_position += audio_pos_step; video->position = video->audio_position - NUM_FRAGS * audio_pos_step; } update_audio_fragment(video->audio, vstream, !video->playing, ogv->reached_eof); } } ALLEGRO_DEBUG("End decode loop.\n"); if (video->audio) { al_drain_audio_stream(video->audio); al_destroy_audio_stream(video->audio); video->audio = NULL; } al_destroy_timer(timer); ALLEGRO_DEBUG("Thread exit.\n"); return NULL; } static bool update_frame_bmp(OGG_VIDEO *ogv) { ALLEGRO_LOCKED_REGION *lr; int y; int pitch = al_get_pixel_size(RGB_PIXEL_FORMAT) * al_get_bitmap_width(ogv->frame_bmp); lr = al_lock_bitmap(ogv->frame_bmp, RGB_PIXEL_FORMAT, ALLEGRO_LOCK_WRITEONLY); if (!lr) { ALLEGRO_ERROR("Failed to lock bitmap.\n"); return false; } for (y = 0; y < al_get_bitmap_height(ogv->frame_bmp); y++) { memcpy((unsigned char*)lr->data + y * lr->pitch, ogv->rgb_data + y * pitch, pitch); } al_unlock_bitmap(ogv->frame_bmp); return true; } /* Video interface. */ static bool do_open_video(ALLEGRO_VIDEO *video, OGG_VIDEO *ogv) { unsigned i; read_headers(ogv); /* Select the first Theora and Vorbis tracks. */ for (i = 0; i < _al_vector_size(&ogv->streams); i++) { STREAM **slot = _al_vector_ref(&ogv->streams, i); STREAM *stream = *slot; if (stream->stream_type == STREAM_TYPE_THEORA && !ogv->selected_video_stream) { setup_theora_stream_decode(video, ogv, stream); ogv->selected_video_stream = stream; } else if (stream->stream_type == STREAM_TYPE_VORBIS && !ogv->selected_audio_stream) { setup_vorbis_stream_decode(video, stream); ogv->selected_audio_stream = stream; } else { deactivate_stream(stream); } } return ogv->selected_video_stream || ogv->selected_audio_stream; } static bool ogv_open_video(ALLEGRO_VIDEO *video) { const char *filename; ALLEGRO_FILE *fp; OGG_VIDEO *ogv; int rc; filename = al_path_cstr(video->filename, ALLEGRO_NATIVE_PATH_SEP); fp = al_fopen(filename, "rb"); if (!fp) { ALLEGRO_WARN("Failed to open %s.\n", filename); return false; } ogv = al_calloc(1, sizeof(OGG_VIDEO)); if (!ogv) { ALLEGRO_ERROR("Out of memory.\n"); al_fclose(fp); return false; } ogv->fp = fp; rc = ogg_sync_init(&ogv->sync_state); ASSERT(rc == 0); _al_vector_init(&ogv->streams, sizeof(STREAM *)); if (!do_open_video(video, ogv)) { ALLEGRO_ERROR("No audio or video stream found.\n"); ogv_close_video(video); return false; } /* ogv->mutex and ogv->thread are created in ogv_start_video. */ video->data = ogv; return true; } static bool ogv_close_video(ALLEGRO_VIDEO *video) { OGG_VIDEO *ogv; unsigned i; ogv = video->data; if (ogv) { if (ogv->thread) { al_join_thread(ogv->thread, NULL); al_destroy_user_event_source(&ogv->evtsrc); al_destroy_event_queue(ogv->queue); al_destroy_mutex(ogv->mutex); al_destroy_cond(ogv->cond); al_destroy_thread(ogv->thread); } al_fclose(ogv->fp); ogg_sync_clear(&ogv->sync_state); for (i = 0; i < _al_vector_size(&ogv->streams); i++) { STREAM **slot = _al_vector_ref(&ogv->streams, i); free_stream(*slot); } _al_vector_free(&ogv->streams); if (ogv->pic_bmp != ogv->frame_bmp) { al_destroy_bitmap(ogv->pic_bmp); } al_destroy_bitmap(ogv->frame_bmp); al_free(ogv->rgb_data); al_free(ogv); } video->data = NULL; return true; } static bool ogv_start_video(ALLEGRO_VIDEO *video) { OGG_VIDEO *ogv = video->data; if (ogv->thread != NULL) { ALLEGRO_ERROR("Thread already created.\n"); return false; } ogv->thread = al_create_thread(decode_thread_func, video); if (!ogv->thread) { ALLEGRO_ERROR("Could not create thread.\n"); return false; } al_init_user_event_source(&ogv->evtsrc); ogv->queue = al_create_event_queue(); ogv->mutex = al_create_mutex(); ogv->cond = al_create_cond(); al_register_event_source(ogv->queue, &ogv->evtsrc); al_start_thread(ogv->thread); return true; } static bool ogv_set_video_playing(ALLEGRO_VIDEO *video) { OGG_VIDEO * const ogv = video->data; if (ogv->reached_eof) { video->playing = false; } return true; } static bool ogv_seek_video(ALLEGRO_VIDEO *video, double seek_to) { OGG_VIDEO *ogv = video->data; ALLEGRO_EVENT ev; int seek_counter; /* XXX we only know how to seek to beginning */ if (seek_to > 0.0) { return false; } al_lock_mutex(ogv->mutex); seek_counter = ogv->seek_counter; ev.user.type = _ALLEGRO_EVENT_VIDEO_SEEK; ev.user.data1 = seek_to * 1.0e6; ev.user.data2 = 0; ev.user.data3 = 0; ev.user.data4 = 0; al_emit_user_event(&ogv->evtsrc, &ev, NULL); while (seek_counter == ogv->seek_counter) { al_wait_cond(ogv->cond, ogv->mutex); } al_unlock_mutex(ogv->mutex); return true; } static bool ogv_update_video(ALLEGRO_VIDEO *video) { OGG_VIDEO *ogv = video->data; int w, h; bool ret; al_lock_mutex(ogv->mutex); w = ogv->buffer[0].width; h = ogv->buffer[0].height; if (w > 0 && h && h > 0 && ogv->frame_bmp) { ASSERT(w == al_get_bitmap_width(ogv->frame_bmp)); ASSERT(h == al_get_bitmap_height(ogv->frame_bmp)); if (ogv->buffer_dirty) { ret = update_frame_bmp(ogv); ogv->buffer_dirty = false; } else { ret = true; } video->current_frame = ogv->pic_bmp; } else { /* No frame ready yet. */ ret = false; } al_unlock_mutex(ogv->mutex); return ret; } static ALLEGRO_VIDEO_INTERFACE ogv_vtable = { ogv_open_video, ogv_close_video, ogv_start_video, ogv_set_video_playing, ogv_seek_video, ogv_update_video, }; ALLEGRO_VIDEO_INTERFACE *_al_video_ogv_vtable(void) { return &ogv_vtable; } bool _al_video_identify_ogv(ALLEGRO_FILE *f) { uint8_t x[4]; if (al_fread(f, x, 4) < 4) return false; /* TODO: This technically only verifies that this is an OGG container, * saying nothing of the contents. Maybe refactor read_headers and make * use of it here. */ if (memcmp(x, "OggS", 4) == 0) return true; return false; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/addons/video/video.c000066400000000000000000000207751473414355200173230ustar00rootroot00000000000000/* This is just a quick hack. But good enough for our use of displaying * a short intro video when our game starts up - so might as well share * it. * * Known bugs: * * - Only very crude synching. Audio is slightly delayed and some * videos seem to constantly drift off and then the audio gets all * distorted... * * - Seeking/Pausing doesn't really work. * * - Memory leaks. Easy to fix but don't have time right now. * * Missing features: * * - Stream information. For example allow selection of one of several * audio streams or subtitle overlay streams. * * - Non audio/video streams. For example something like: * ALLEGRO_USTR *al_get_video_subtitle(float *x, float *y); * * - Buffering. Right now buffering is hardcoded to a fixed size which * seemed enough for streaming 720p from disk in my tests. Obviously * when streaming higher bandwidth or from a source with high * fluctuation like an internet stream this won't work at all. * * - Provide an audio stream for the audio. Then could use this to * stream audio files. Right now opening an .mp3 with the video * addon will play it but only with the video API instead of Allegro's * normal audio streaming API... * * - Audio/Video sync. For a game user-controlled sync is probably not * too important as it can just ship with a properly synchronizeded * video. However right now the audio delay is completely ignored. * * - Additional drivers. Also redo the API a bit so not everything * has to be done by the driver. */ #include "allegro5/allegro5.h" #include "allegro5/allegro_video.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_video.h" #include "allegro5/internal/aintern_video_cfg.h" #include "allegro5/internal/aintern_vector.h" ALLEGRO_DEBUG_CHANNEL("video") /* globals */ static bool video_inited = false; typedef struct VideoHandler { const char *extension; ALLEGRO_VIDEO_INTERFACE *vtable; ALLEGRO_VIDEO_IDENTIFIER_FUNCTION identifier; } VideoHandler; static _AL_VECTOR handlers = _AL_VECTOR_INITIALIZER(VideoHandler); static const char* identify_video(ALLEGRO_FILE *f) { size_t i; for (i = 0; i < _al_vector_size(&handlers); i++) { VideoHandler *l = _al_vector_ref(&handlers, i); if (l->identifier(f)) { return l->extension; } } return NULL; } static ALLEGRO_VIDEO_INTERFACE *find_handler(const char *extension) { size_t i; for (i = 0; i < _al_vector_size(&handlers); i++) { VideoHandler *l = _al_vector_ref(&handlers, i); if (0 == _al_stricmp(extension, l->extension)) { return l->vtable; } } return NULL; } static void add_handler(const char *extension, ALLEGRO_VIDEO_INTERFACE *vtable, ALLEGRO_VIDEO_IDENTIFIER_FUNCTION identifier) { VideoHandler *v = _al_vector_alloc_back(&handlers); v->extension = extension; v->vtable = vtable; v->identifier = identifier; } /* Function: al_open_video */ ALLEGRO_VIDEO *al_open_video(char const *filename) { ALLEGRO_VIDEO *video; const char *ext; video = al_calloc(1, sizeof *video); ASSERT(filename); ext = al_identify_video(filename); if (!ext) { ext = strrchr(filename, '.'); if (!ext) { ALLEGRO_ERROR("Could not identify video %s!\n", filename); } } video->vtable = find_handler(ext); if (video->vtable == NULL) { ALLEGRO_ERROR("No handler for video extension %s - " "therefore not trying to load %s.\n", ext, filename); al_free(video); return NULL; } video->filename = al_create_path(filename); if (!video->vtable->open_video(video)) { ALLEGRO_ERROR("Could not open %s.\n", filename); al_destroy_path(video->filename); al_free(video); return NULL; } al_init_user_event_source(&video->es); video->es_inited = true; video->dtor_item = _al_register_destructor(_al_dtor_list, "video", video, (void (*)(void *)) al_close_video); return video; } /* Function: al_close_video */ void al_close_video(ALLEGRO_VIDEO *video) { if (video) { video->vtable->close_video(video); if (video->es_inited) { al_destroy_user_event_source(&video->es); } al_destroy_path(video->filename); _al_unregister_destructor(_al_dtor_list, video->dtor_item); al_free(video); } } /* Function: al_get_video_event_source */ ALLEGRO_EVENT_SOURCE *al_get_video_event_source(ALLEGRO_VIDEO *video) { ASSERT(video); return &video->es; } /* Function: al_start_video */ void al_start_video(ALLEGRO_VIDEO *video, ALLEGRO_MIXER *mixer) { ASSERT(video); /* XXX why is this not just a parameter? */ video->mixer = mixer; video->playing = true; /* Destruction is handled by al_close_video. */ _al_push_destructor_owner(); video->vtable->start_video(video); _al_pop_destructor_owner(); } /* Function: al_start_video_with_voice */ void al_start_video_with_voice(ALLEGRO_VIDEO *video, ALLEGRO_VOICE *voice) { ASSERT(video); /* XXX why is voice not just a parameter? */ video->voice = voice; video->vtable->start_video(video); } /* Function: al_set_video_playing */ void al_set_video_playing(ALLEGRO_VIDEO *video, bool play) { ASSERT(video); if (play != video->playing) { video->playing = play; video->vtable->set_video_playing(video); } } /* Function: al_is_video_playing */ bool al_is_video_playing(ALLEGRO_VIDEO *video) { ASSERT(video); return video->playing; } /* Function: al_get_video_frame */ ALLEGRO_BITMAP *al_get_video_frame(ALLEGRO_VIDEO *video) { ASSERT(video); video->vtable->update_video(video); return video->current_frame; } /* Function: al_get_video_position */ double al_get_video_position(ALLEGRO_VIDEO *video, ALLEGRO_VIDEO_POSITION_TYPE which) { ASSERT(video); if (which == ALLEGRO_VIDEO_POSITION_VIDEO_DECODE) return video->video_position; if (which == ALLEGRO_VIDEO_POSITION_AUDIO_DECODE) return video->audio_position; return video->position; } /* Function: al_seek_video */ bool al_seek_video(ALLEGRO_VIDEO *video, double pos_in_seconds) { ASSERT(video); return video->vtable->seek_video(video, pos_in_seconds); } /* Function: al_get_video_audio_rate */ double al_get_video_audio_rate(ALLEGRO_VIDEO *video) { ASSERT(video); return video->audio_rate; } /* Function: al_get_video_fps */ double al_get_video_fps(ALLEGRO_VIDEO *video) { ASSERT(video); return video->fps; } /* Function: al_get_video_scaled_width */ float al_get_video_scaled_width(ALLEGRO_VIDEO *video) { ASSERT(video); return video->scaled_width; } /* Function: al_get_video_scaled_height */ float al_get_video_scaled_height(ALLEGRO_VIDEO *video) { ASSERT(video); return video->scaled_height; } /* Function: al_init_video_addon */ bool al_init_video_addon(void) { if (video_inited) return true; #ifdef ALLEGRO_CFG_VIDEO_HAVE_OGV add_handler(".ogv", _al_video_ogv_vtable(), _al_video_identify_ogv); #endif if (_al_vector_size(&handlers) == 0) { ALLEGRO_WARN("No video handlers available!\n"); return false; } _al_add_exit_func(al_shutdown_video_addon, "al_shutdown_video_addon"); video_inited = true; return true; } /* Function: al_is_video_addon_initialized */ bool al_is_video_addon_initialized(void) { return video_inited; } /* Function: al_shutdown_video_addon */ void al_shutdown_video_addon(void) { if (!video_inited) return; _al_vector_free(&handlers); video_inited = false; } /* Function: al_get_allegro_video_version */ uint32_t al_get_allegro_video_version(void) { return ALLEGRO_VERSION_INT; } /* Function: al_identify_video_f */ char const *al_identify_video_f(ALLEGRO_FILE *fp) { return identify_video(fp); } /* Function: al_identify_video */ char const *al_identify_video(char const *filename) { char const *ext; ALLEGRO_FILE *fp = al_fopen(filename, "rb"); if (!fp) return NULL; ext = identify_video(fp); al_fclose(fp); return ext; } /* The returned width and height are always greater than or equal to the frame * width and height. */ void _al_compute_scaled_dimensions(int frame_w, int frame_h, float aspect_ratio, float *scaled_w, float *scaled_h) { if (aspect_ratio > 1.0) { *scaled_w = frame_h * aspect_ratio; *scaled_h = frame_h; } else { *scaled_w = frame_w; *scaled_h = frame_w / aspect_ratio; } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/allegro5.cfg000066400000000000000000000205041473414355200156540ustar00rootroot00000000000000# # Configuration file for the Allegro 5 library. # # This file should be either in the same directory as your program. # # On Unix, this file may also be stored as ~/.allegro5rc or /etc/allegro5rc. # If multiple files exist, they will be merged, with values from more specific # files overriding the less specific files. [graphics] # Graphics driver. # Can be 'default', 'opengl' or 'direct3d' (Windows only). driver=default # Display configuration selection mode. # # Under Linux, it can be used to force the old GLX 1.2 way of choosing # display settings or the new FBConfig method introduced with GLX 1.3. # # Under Windows, when using the OpenGL driver, setting it to old will # use DescribePixelFormat and new will use wglGetPixelFormatAttribivARB # (provided by WGL_ARB_pixel_format extension). # # Can be 'old' and 'new'. Default is 'new'. config_selection=new # What method to use to detect legacy cards for the Direct3D backend of the # primitives addon. Can be 'default', which means it'll check that the pixel # shader version supported is below some value. 'force_legacy' will force it to # detect as a legacy card. 'force_modern' will force it to detect is as a modern # card. prim_d3d_legacy_detection=default # For compatibility reasons, video bitmaps smaller than this size are # backed by textures with this size. This is often no longer necessary # on more modern systems, and should be set to < 16 if you're creating # bitmaps smaller than this size. Note that on Android, this is ignored # if smaller than 32. min_bitmap_size=16 [audio] # Driver can be 'default', 'openal', 'alsa', 'oss', 'pulseaudio' or 'directsound' # depending on platform. driver=default # Mixer quality can be 'linear' (default), 'cubic' (best), or 'point' (bad). # default_mixer_quality=linear # The frequency to use for the default voice/mixer. Default: 44100. # primary_voice_frequency=44100 # primary_mixer_frequency=44100 # Can be 'int16', otherwise defaults to float32. # primary_voice_depth=float32 # primary_mixer_depth=float32 [oss] # You can skip probing for OSS4 driver by setting this option to 'yes'. # Default is 'no'. force_ver3=no # When OSS3 is used, you can choose a sound device here. # Default is '/dev/dsp'. device=/dev/dsp [alsa] # Set the ALSA sound device. # Default is 'default'. device=default # Set the ALSA capture device, e.g. hw:0,0 # Default is 'default'. capture_device=default # Set the period size (in samples) # Note that this is erroneously called 'buffer_size' for backwards # compatibility. buffer_size=32 # Set the buffer size (in samples) buffer_size2=2048 [pulseaudio] # Set the buffer size (in samples) buffer_size=1024 [directsound] # Set the DirectSound buffer size (in samples) buffer_size = 8192 # Which window to attach the device to. Can be 'desktop', or 'foreground'. Try # flipping this if there are issues initializing audio. window = desktop [opengl] # If you want to support old OpenGL versions, you can make Allegro # believe an older version than what you actually have is used with # this key. This is only for testing/debugging purposes. # force_opengl_version = 1.2 [opengl_disabled_extensions] # Any OpenGL extensions can be listed here to make Allegro report them # as not available. The extensions used by Allegro itself if available # are shown below - uncommenting them would disable them: # GL_ARB_texture_non_power_of_two=0 # GL_EXT_framebuffer_object=0 [image] # Gamma handling of PNG files. # A value of 0.0 means: Don't do any gamma correction. # A value of -1.0 means: Use the value from the environment variable # SCREEN_GAMMA (if available), otherwise fallback to a value of 2.2 # (a good guess for PC monitors, and the value for sRGB colourspace). # Otherwise, the value is taken as-is. png_screen_gamma = -1.0 # Compression level for PNG files. Possible values: 0-9, "best", "fastest", # "none" or "default" (a sane compromise between size and speed). png_compression_level = default # Quality level for JPEG files. Possible values: 0-100 jpeg_quality_level = 75 # Quality level for WebP files. Possible values: 0-100 or "lossless" webp_quality_level = lossless [joystick] # Linux: Allegro normally searches for joystick device N at /dev/input/jsN. # You can override the device file path on a per-device basis, like this. # device0=/dev/input/by-id/usb-blahblah-joystick # Windows: You can choose between the XINPUT or DIRECTINPUT driver for # joysticks and force feedback joysticks. Xinput is the more modern # system, but DirectInput has more force feedback capabilities for older # joysticks. driver=XINPUT # Windows: Use this to force an XInput DLL version, example "3" forces # xinput1_3.dll. By default, the latest version is used. # force_xinput_version = 3 [keyboard] # You can trap/untrap the mouse cursor within a window with a key combination # of your choice, e.g. "Ctrl-G", "Shift-Ctrl-G", "Ctrl-LShift", "RWin". # This feature currently only works on X11 and Windows. # toggle_mouse_grab_key = ScrollLock # By default, you can press Ctrl-Alt-Delete or Ctrl-Alt-End to quit Allegro # programs. Set this to false to disable this feature. This only works on # Linux. # enable_three_finger_exit = true # By default, pressing the LED toggling keys (e.g. CapsLock) will also toggle # the LED on the keyboard. Setting this to false disable that connection. # This can only be controled on non-X11 Linux. # enable_key_led_toggle = true [trace] # Comma-separated list of channels to log. Default is "all" which # disables channel filtering. Some possible channels are: # system,display,keyboard,opengl # Channel names can be prefixed with - to exclude only those channels. # Each addon and source-file can define additional channels though so # there are more. channels=all # Log-level. Can be one of debug, info, warn, error, none or empty. # In debug builds if it is empty or unset, then the level is set to debug. # In release builds if it is empty or unset, then the level is set to none. # If not none, Allegro will write out the logs to an allegro.log file next to # the binary. Use ALLEGRO_TRACE environment variable to control that file # location. A special filename of - (dash) means logging to stdout. # You can override this value via the ALLEGRO_TRACE_LEVEL environment variable. level= # Set to 0 to disable line numbers in log files. lines=1 # Set to 0 to disable timestamps in log files. timestamps=1 # Set to 0 to disable function names in log files. functions=1 [x11] # Can be fullscreen_only, always, never bypass_compositor = fullscreen_only [xkeymap] # Override X11 keycode. The below example maps X11 code 52 (Y) to Allegro # code 26 (Z) and X11 code 29 (Z) to Allegro code 25 (Y). # 52=26 # 29=25 [shader] # If you want to support override version of the d3dx9_xx.dll library # define this value. # By default, latest installed version is used. # force_d3dx9_version = 36 [ttf] # Set these to something other than 0 to override the default page sizes for TTF # glyphs. min_page_size = 0 max_page_size = 0 # This entry contains characters that will be pre-catched during font loading. # cache_text = a bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ # Uncomment if you want only the characters in the cache_text entry to ever be drawn # skip_cache_misses = true [osx] # If set to false, then Allegro will send ALLEGRO_EVENT_DISPLAY_HALT_DRAWING # and ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING events when the user resizes a # window. Drawing while resizing ("live resizing") has historically been buggy, # so setting this to false allows you to opt out of this behavior and detect # when the resize happens. allow_live_resize = true [compatibility] # Prior to 5.2.4 on Windows you had to manually resize the display when # showing the menu using the dialog addon. After 5.2.4 this is done # automatically, but may break old code that handled this eventuality. # Set this to false for such code. automatic_menu_display_resize = true # On OSX outside an app bundle, on system init allegro manually promotes the process # to a graphical application. This may be undesirable for console applications. Set # this to false to disable this behavior. osx_tell_dock_outside_bundle = true # To restore behavior of older code versions, specify this value to the # Allegro version that had the desired old behavior. # joystick_version = 5.2.9 # keyboard_version = 5.2.9 # Prefer using DUMB rather than OpenMPT to decode module files. acodec_prefer_dumb = false allegro5-5.2.10.1/android/000077500000000000000000000000001473414355200151005ustar00rootroot00000000000000allegro5-5.2.10.1/android/CMakeLists.txt000066400000000000000000000042271473414355200176450ustar00rootroot00000000000000set(PROJECT ${CMAKE_CURRENT_BINARY_DIR}/gradle_project) set(PROJECT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/gradle_project) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(AAR_NAME allegro-debug.aar) set(ASSEMBLE assembleDebug) else() set(AAR_NAME allegro-release.aar) set(ASSEMBLE assembleRelease) endif() set(ALLEGRO_AAR ${LIBRARY_OUTPUT_PATH}/${AAR_NAME}) set(ALLEGRO_AAR ${ALLEGRO_AAR} PARENT_SCOPE) if (NOT EXISTS "$ENV{ANDROID_HOME}") set(ENV{ANDROID_HOME} "$ENV{HOME}/Android/Sdk") endif() if (NOT EXISTS "$ENV{ANDROID_HOME}") message(FATAL_ERROR "Please set the ANDROID_HOME environment variable to the location of your Android SDK, or install Android Studio in the default location ($ENV{HOME}/Android/Sdk))") endif() set(ANDROID_HOME $ENV{ANDROID_HOME}) message(STATUS "Using Android SDK from ${ANDROID_HOME}.") file(GLOB javas "${PROJECT_SOURCE}/allegro/src/main/java/org/liballeg/android/*.java") configure_file( ${PROJECT_SOURCE}/local.properties ${PROJECT}/local.properties) set(GRADLE_PROJECT allegro) configure_file( ${PROJECT_SOURCE}/settings.gradle ${PROJECT}/settings.gradle) set(COPY_FILES ${PROJECT_SOURCE}/allegro/src/main/AndroidManifest.xml ${PROJECT_SOURCE}/gradle.properties ${PROJECT_SOURCE}/build.gradle ${PROJECT_SOURCE}/gradlew ${PROJECT_SOURCE}/gradle/wrapper/gradle-wrapper.jar ${PROJECT_SOURCE}/gradle/wrapper/gradle-wrapper.properties ${PROJECT_SOURCE}/allegro/build.gradle ${PROJECT_SOURCE}/allegro/src/main/AndroidManifest.xml ${javas} ) list(APPEND COPIED_FILES ${PROJECT}/local.properties) foreach(copy ${COPY_FILES}) string(REPLACE "${PROJECT_SOURCE}/" "${PROJECT}/" target ${copy}) add_custom_command( OUTPUT ${target} DEPENDS ${copy} COMMAND ${CMAKE_COMMAND} -E copy ${copy} ${target} ) list(APPEND COPIED_FILES ${target}) endforeach() add_custom_command( OUTPUT ${ALLEGRO_AAR} DEPENDS ${COPIED_FILES} WORKING_DIRECTORY ${PROJECT} COMMAND ./gradlew ${ASSEMBLE} COMMAND ${CMAKE_COMMAND} -E copy allegro/build/outputs/aar/${AAR_NAME} ${ALLEGRO_AAR} ) add_custom_target(aar ALL DEPENDS ${ALLEGRO_AAR}) allegro5-5.2.10.1/android/gradle_project/000077500000000000000000000000001473414355200200645ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/000077500000000000000000000000001473414355200215115ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/build.gradle000066400000000000000000000004351473414355200237720ustar00rootroot00000000000000apply plugin: 'com.android.library' android { compileSdkVersion 33 defaultConfig { minSdkVersion 15 targetSdkVersion 33 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false } } } allegro5-5.2.10.1/android/gradle_project/allegro/src/000077500000000000000000000000001473414355200223005ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/000077500000000000000000000000001473414355200232245ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/AndroidManifest.xml000066400000000000000000000004031473414355200270120ustar00rootroot00000000000000 allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/000077500000000000000000000000001473414355200241455ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/000077500000000000000000000000001473414355200247345ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/000077500000000000000000000000001473414355200265075ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/android/000077500000000000000000000000001473414355200301275ustar00rootroot00000000000000AllegroAPKList.java000066400000000000000000000027451473414355200335000ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/androidpackage org.liballeg.android; import java.io.IOException; import android.util.Log; import java.io.InputStream; class AllegroAPKList { static String list(AllegroActivity activity, String path) { /* The getAssets().list() method is *very* finicky about asset * names, there must be no leading, trailing or double slashes * or it fails. */ while (path.startsWith("/")) path = path.substring(1); while (path.endsWith("/")) path = path.substring(0, path.length() - 1); try { String[] files = activity.getResources().getAssets().list(path); String ret = ""; for (String file : files) { if (!ret.isEmpty()) ret += ";"; ret += file; /* We cannot use openfs as that causes an exception on any * compressed files. The only thing we can do is open a * stream - if that fails we assume it is a directory, * otherwise a normal file. */ try { file = path + "/" + file; while (file.startsWith("/")) file = file.substring(1); InputStream s = activity.getResources().getAssets().open(file); s.close(); } catch (IOException e) { ret += "/"; } } return ret; } catch (IOException e) { Log.d("APK", e.toString()); return ""; } } } AllegroAPKStream.java000066400000000000000000000061731473414355200340170ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/androidpackage org.liballeg.android; import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; import android.util.Log; import java.io.IOException; import java.io.InputStream; class AllegroAPKStream { private static final String TAG = "AllegroAPKStream"; private AllegroActivity activity; private String fn; private InputStream in; private long pos = 0; private long fsize = -1; private boolean at_eof = false; AllegroAPKStream(AllegroActivity activity, String filename) { this.activity = activity; fn = Path.simplifyPath(filename); if (!fn.equals(filename)) { Log.d(TAG, filename + " simplified to: " + fn); } } boolean open() { try { AssetFileDescriptor fd; fd = activity.getResources().getAssets().openFd(fn); fsize = fd.getLength(); fd.close(); } catch (IOException e) { Log.w(TAG, "could not get file size: " + e.toString()); fsize = -1; } return reopen(); } boolean reopen() { if (in != null) { close(); in = null; } try { in = activity.getResources().getAssets().open(fn, AssetManager.ACCESS_RANDOM); } catch (IOException e) { Log.d(TAG, "Got IOException in reopen. fn='" + fn + "'"); return false; } in.mark((int)Math.pow(2, 31)); pos = 0; at_eof = false; return true; } boolean close() { try { in.close(); in = null; return true; } catch (IOException e) { Log.d(TAG, "IOException in close"); return false; } } boolean seek(long seekto) { at_eof = false; if (seekto >= pos) { long seek_ahead = seekto - pos; return force_skip(seek_ahead); } /* Seek backwards by rewinding to start of file first. */ try { in.reset(); pos = 0; } catch (IOException e) { if (!reopen()) { /* Leaves pos wherever it lands! */ return false; } } return force_skip(seekto); } private boolean force_skip(long n) { if (n <= 0) return true; /* NOTE: in.skip doesn't work here! */ byte[] b = new byte[(int)n]; while (n > 0) { int res; try { res = in.read(b, 0, (int)n); } catch (IOException e) { Log.d(TAG, "IOException: " + e.toString()); return false; } if (res <= 0) break; pos += res; n -= res; } return true; } long tell() { return pos; } int read(byte[] b) { try { int ret = in.read(b); if (ret > 0) pos += ret; else if (ret == -1) { at_eof = true; } return ret; } catch (IOException e) { Log.d(TAG, "IOException in read"); return -1; } } long size() { return fsize; } boolean eof() { return at_eof; } } /* vim: set sts=3 sw=3 et: */ AllegroActivity.java000066400000000000000000000545161473414355200340300ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/androidpackage org.liballeg.android; import android.app.Activity; import android.content.Intent; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.content.res.Configuration; import android.hardware.display.DisplayManager; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.graphics.Rect; import android.util.Log; import android.view.Display; import android.view.SurfaceHolder; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import java.io.File; import java.lang.Runnable; import java.lang.String; import android.view.InputDevice; import java.util.Vector; import android.os.Build; import android.view.View; import android.view.KeyEvent; import android.window.OnBackInvokedCallback; import android.window.OnBackInvokedDispatcher; import android.net.Uri; import android.os.ParcelFileDescriptor; import java.io.FileNotFoundException; public class AllegroActivity extends Activity { /* properties */ private String userLibName = "libapp.so"; private Handler handler; private Sensors sensors; private Configuration currentConfig; private AllegroSurface surface; private ScreenLock screenLock; private boolean exitedMain = false; private boolean joystickReconfigureNotified = false; private Vector joysticks; private Clipboard clipboard; private DisplayManager.DisplayListener displayListener; private AllegroDialog dialog = null; public final static int JS_A = 0; public final static int JS_B = 1; public final static int JS_X = 2; public final static int JS_Y = 3; public final static int JS_L1 = 4; public final static int JS_R1 = 5; public final static int JS_DPAD_L = 6; public final static int JS_DPAD_R = 7; public final static int JS_DPAD_U = 8; public final static int JS_DPAD_D = 9; public final static int JS_START = 10; // middle right (start, menu) public final static int JS_SELECT = 11; // middle left (select, back) public final static int JS_MODE = 12; // middle (mode, guide) public final static int JS_THUMBL = 13; public final static int JS_THUMBR = 14; public final static int JS_L2 = 15; public final static int JS_R2 = 16; public final static int JS_C = 17; public final static int JS_Z = 18; public final static int JS_DPAD_CENTER = 19; public final static int JS_BUTTON_1 = 20; // generic gamepad buttons public final static int JS_BUTTON_2 = 21; public final static int JS_BUTTON_3 = 22; public final static int JS_BUTTON_4 = 23; public final static int JS_BUTTON_5 = 24; public final static int JS_BUTTON_6 = 25; public final static int JS_BUTTON_7 = 26; public final static int JS_BUTTON_8 = 27; public final static int JS_BUTTON_9 = 28; public final static int JS_BUTTON_10 = 29; public final static int JS_BUTTON_11 = 30; public final static int JS_BUTTON_12 = 31; public final static int JS_BUTTON_13 = 32; public final static int JS_BUTTON_14 = 33; public final static int JS_BUTTON_15 = 34; public final static int JS_BUTTON_16 = 35; public boolean joystickActive = false; /* native methods we call */ native boolean nativeOnCreate(); native void nativeOnPause(); native void nativeOnResume(); native void nativeOnDestroy(); native void nativeOnOrientationChange(int orientation, boolean init); native void nativeSendJoystickConfigurationEvent(); /* methods native code calls */ String getUserLibName() { //ApplicationInfo appInfo = getApplicationInfo(); //String libDir = Reflect.getField(appInfo, "nativeLibraryDir"); ///* Android < 2.3 doesn't have .nativeLibraryDir */ //if (libDir == null) { //libDir = appInfo.dataDir + "/lib"; //} //return libDir + "/" + userLibName; return userLibName; } String getResourcesDir() { //return getApplicationInfo().dataDir + "/assets"; //return getApplicationInfo().sourceDir + "/assets/"; return getFilesDir().getAbsolutePath(); } String getPubDataDir() { return getFilesDir().getAbsolutePath(); } String getTempDir() { return getCacheDir().getAbsolutePath(); } String getApkPath() { return getApplicationInfo().sourceDir; } String getModel() { return android.os.Build.MODEL; } String getManufacturer() { return android.os.Build.MANUFACTURER; } Rect getDisplaySize() { Display display = getWindowManager().getDefaultDisplay(); Rect size = new Rect(); if (android.os.Build.VERSION.SDK_INT >= 13) { display.getRectSize(size); } else { size.left = 0; size.top = 0; size.right = display.getWidth(); size.bottom = display.getHeight(); } return size; } void postRunnable(Runnable runme) { try { Log.d("AllegroActivity", "postRunnable"); handler.post( runme ); } catch (Exception x) { Log.d("AllegroActivity", "postRunnable exception: " + x.getMessage()); } } void createSurface() { try { Log.d("AllegroActivity", "createSurface"); surface = new AllegroSurface(getApplicationContext(), getWindowManager().getDefaultDisplay(), this); SurfaceHolder holder = surface.getHolder(); holder.addCallback(surface); holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); //setContentView(surface); Window win = getWindow(); win.setContentView(surface); Log.d("AllegroActivity", "createSurface end"); } catch (Exception x) { Log.d("AllegroActivity", "createSurface exception: " + x.getMessage()); } } void postCreateSurface() { try { Log.d("AllegroActivity", "postCreateSurface"); handler.post(new Runnable() { public void run() { createSurface(); } }); } catch (Exception x) { Log.d("AllegroActivity", "postCreateSurface exception: " + x.getMessage()); } } void destroySurface() { Log.d("AllegroActivity", "destroySurface"); ViewGroup vg = (ViewGroup)(surface.getParent()); vg.removeView(surface); surface = null; } void postDestroySurface() { try { Log.d("AllegroActivity", "postDestroySurface"); handler.post(new Runnable() { public void run() { destroySurface(); } }); } catch (Exception x) { Log.d("AllegroActivity", "postDestroySurface exception: " + x.getMessage()); } } void postFinish() { exitedMain = true; try { Log.d("AllegroActivity", "posting finish!"); handler.post(new Runnable() { public void run() { try { AllegroActivity.this.finish(); System.exit(0); } catch (Exception x) { Log.d("AllegroActivity", "inner exception: " + x.getMessage()); } } }); } catch (Exception x) { Log.d("AllegroActivity", "exception: " + x.getMessage()); } } boolean getMainReturned() { return exitedMain; } boolean inhibitScreenLock(boolean inhibit) { if (screenLock == null) { screenLock = new ScreenLock(this); } return screenLock.inhibitScreenLock(inhibit); } /* end of functions native code calls */ public AllegroActivity(String userLibName) { super(); this.userLibName = userLibName; joysticks = new Vector(); reconfigureJoysticks(); Thread t = new Thread() { public void run() { while (true) { try { Thread.sleep(100); } catch (Exception e) { } if (joystickReconfigureNotified) { continue; } int[] all = InputDevice.getDeviceIds(); boolean doConfigure = false; int count = 0; for (int i = 0; i < all.length; i++) { if (isJoystick(all[i])) { if (!joysticks.contains(all[i])) { doConfigure = true; break; } else { count++; } } } if (!doConfigure) { if (count != joysticks.size()) { doConfigure = true; } } if (doConfigure) { Log.d("AllegroActivity", "Sending joystick reconfigure event"); joystickReconfigureNotified = true; nativeSendJoystickConfigurationEvent(); } } } }; t.start(); } public void updateOrientation() { dismissMessageBox(); nativeOnOrientationChange(getAllegroOrientation(), false); } /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("AllegroActivity", "onCreate"); Log.d("AllegroActivity", "Files Dir: " + getFilesDir()); File extdir = Environment.getExternalStorageDirectory(); boolean mExternalStorageAvailable = false; boolean mExternalStorageWriteable = false; String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { // We can read and write the media mExternalStorageAvailable = mExternalStorageWriteable = true; } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { // We can only read the media mExternalStorageAvailable = true; mExternalStorageWriteable = false; } else { // Something else is wrong. It may be one of many other states, but // all we need to know is we can neither read nor write mExternalStorageAvailable = mExternalStorageWriteable = false; } Log.d("AllegroActivity", "External Storage Dir: " + extdir.getAbsolutePath()); Log.d("AllegroActivity", "External Files Dir: " + getExternalFilesDir(null)); Log.d("AllegroActivity", "external: avail = " + mExternalStorageAvailable + " writable = " + mExternalStorageWriteable); Log.d("AllegroActivity", "sourceDir: " + getApplicationInfo().sourceDir); Log.d("AllegroActivity", "publicSourceDir: " + getApplicationInfo().publicSourceDir); handler = new Handler(); sensors = new Sensors(getApplicationContext()); clipboard = new Clipboard(this); currentConfig = new Configuration(getResources().getConfiguration()); Log.d("AllegroActivity", "before nativeOnCreate"); if (!nativeOnCreate()) { finish(); Log.d("AllegroActivity", "nativeOnCreate failed"); return; } requestWindowFeature(Window.FEATURE_NO_TITLE); this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); if (Build.VERSION.SDK_INT >= 33) { // handle the back button / gesture on API level 33+ getOnBackInvokedDispatcher().registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, new OnBackInvokedCallback() { @Override public void onBackInvoked() { // these will be mapped to ALLEGRO_KEY_BACK KeyEvent keyDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK); KeyEvent keyUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK); dispatchKeyEvent(keyDown); dispatchKeyEvent(keyUp); } } ); } Log.d("AllegroActivity", "onCreate end"); } @Override public void onStart() { super.onStart(); Log.d("AllegroActivity", "onStart"); final AllegroActivity activity = this; displayListener = new DisplayManager.DisplayListener() { @Override public void onDisplayAdded(int displayId) {} @Override public void onDisplayRemoved(int displayId) {} @Override public void onDisplayChanged(int displayId) { activity.updateOrientation(); } }; DisplayManager displayManager = (DisplayManager) getApplicationContext().getSystemService(getApplicationContext().DISPLAY_SERVICE); displayManager.registerDisplayListener(displayListener, handler); nativeOnOrientationChange(getAllegroOrientation(), true); Log.d("AllegroActivity", "onStart end"); } @Override public void onRestart() { super.onRestart(); Log.d("AllegroActivity", "onRestart."); } @Override public void onStop() { super.onStop(); Log.d("AllegroActivity", "onStop."); DisplayManager displayManager = (DisplayManager) getApplicationContext().getSystemService(getApplicationContext().DISPLAY_SERVICE); displayManager.unregisterDisplayListener(displayListener); // TODO: Should we destroy the surface here? // onStop is paired with onRestart and onCreate with onDestroy - // if we destroy the surface here we need to handle onRestart to // recreate it but we currently do not. } /** Called when the activity is paused. */ @Override public void onPause() { super.onPause(); Log.d("AllegroActivity", "onPause"); sensors.unlisten(); dismissMessageBox(); nativeOnPause(); Log.d("AllegroActivity", "onPause end"); } /** Called when the activity is resumed/unpaused */ @Override public void onResume() { Log.d("AllegroActivity", "onResume"); super.onResume(); sensors.listen(); nativeOnResume(); /* This is needed to get joysticks working again */ reconfigureJoysticks(); Log.d("AllegroActivity", "onResume end"); } /** Called when the activity is destroyed */ @Override public void onDestroy() { super.onDestroy(); Log.d("AllegroActivity", "onDestroy"); nativeOnDestroy(); Log.d("AllegroActivity", "onDestroy end"); } /** Called when config has changed */ @Override public void onConfigurationChanged(Configuration conf) { super.onConfigurationChanged(conf); Log.d("AllegroActivity", "onConfigurationChanged"); // compare conf.orientation with some saved value int changes = currentConfig.diff(conf); Log.d("AllegroActivity", "changes: " + Integer.toBinaryString(changes)); if ((changes & ActivityInfo.CONFIG_FONT_SCALE) != 0) Log.d("AllegroActivity", "font scale changed"); if ((changes & ActivityInfo.CONFIG_MCC) != 0) Log.d("AllegroActivity", "mcc changed"); if ((changes & ActivityInfo.CONFIG_MNC) != 0) Log.d("AllegroActivity", " changed"); if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) Log.d("AllegroActivity", "locale changed"); if ((changes & ActivityInfo.CONFIG_TOUCHSCREEN) != 0) Log.d("AllegroActivity", "touchscreen changed"); if ((changes & ActivityInfo.CONFIG_KEYBOARD) != 0) Log.d("AllegroActivity", "keyboard changed"); if ((changes & ActivityInfo.CONFIG_NAVIGATION) != 0) Log.d("AllegroActivity", "navigation changed"); if ((changes & ActivityInfo.CONFIG_ORIENTATION) != 0) { Log.d("AllegroActivity", "orientation changed"); updateOrientation(); } if ((changes & ActivityInfo.CONFIG_SCREEN_LAYOUT) != 0) Log.d("AllegroActivity", "screen layout changed"); if ((changes & ActivityInfo.CONFIG_UI_MODE) != 0) Log.d("AllegroActivity", "ui mode changed"); if (currentConfig.screenLayout != conf.screenLayout) { Log.d("AllegroActivity", "screenLayout changed!"); } Log.d("AllegroActivity", "old orientation: " + currentConfig.orientation + ", new orientation: " + conf.orientation); currentConfig = new Configuration(conf); } /** Called when app is frozen **/ @Override public void onSaveInstanceState(Bundle state) { Log.d("AllegroActivity", "onSaveInstanceState"); /* do nothing? */ /* This should get rid of the following warning: * couldn't save which view has focus because the focused view has no id. */ } void setAllegroOrientation(int alleg_orientation) { setRequestedOrientation(Const.toAndroidOrientation(alleg_orientation)); } int getAllegroOrientation() { int rotation; if (Reflect.methodExists(getWindowManager().getDefaultDisplay(), "getRotation")) { /* 2.2+ */ rotation = getWindowManager().getDefaultDisplay().getRotation(); } else { rotation = getWindowManager().getDefaultDisplay().getOrientation(); } return Const.toAllegroOrientation(rotation); } String getOsVersion() { return android.os.Build.VERSION.RELEASE; } public int openFileDescriptor(String uriString, String mode) { final int NOT_FOUND = -1, UNSUPPORTED = -2; if (Build.VERSION.SDK_INT < 12) return UNSUPPORTED; try { // See https://developer.android.com/reference/android/content/ContentResolver#openFileDescriptor(android.net.Uri,%20java.lang.String) Uri uri = Uri.parse(uriString); // content:// or file:// ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(uri, mode); // the user is responsible for closing this file descriptor return pfd.detachFd(); // API 12+ } catch (FileNotFoundException e) { // permission issues? Log.e("AllegroActivity", "openFileDescriptor: file not found or invalid mode"); } return NOT_FOUND; } private boolean isJoystick(int id) { InputDevice input = InputDevice.getDevice(id); int sources = input.getSources(); // the device is a game controller if it has gamepad buttons, control sticks, or both boolean hasAnalogSticks = ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK); boolean hasGamepadButtons = ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD); return hasGamepadButtons || hasAnalogSticks; } public void reconfigureJoysticks() { joysticks.clear(); int[] all = InputDevice.getDeviceIds(); Log.d("AllegroActivity", "Number of input devices: " + all.length); for (int i = 0; i < all.length; i++) { if (isJoystick(all[i])) { joysticks.add(all[i]); Log.d("AllegroActivity", "Found joystick. Index=" + (joysticks.size()-1) + " id=" + all[i]); } } joystickReconfigureNotified = false; } public int getNumJoysticks() { return joysticks.size(); } public int indexOfJoystick(int id) { return joysticks.indexOf(id, 0); } public String getJoystickName(int index) { if (index >= 0 && index < joysticks.size()) { int id = joysticks.get(index); InputDevice input = InputDevice.getDevice(id); if (input != null) return input.getName(); } return ""; } public void setJoystickActive() { joystickActive = true; } public void setJoystickInactive() { joystickActive = false; } private boolean got_clip = false; private String clip_text; private boolean set_clip = false; private boolean set_clip_result; public String getClipboardText() { got_clip = false; try { runOnUiThread(new Runnable() { @Override public void run() { clip_text = clipboard.getText(); got_clip = true; } }); } catch (Exception e) { Log.d("AllegroActivity", "getClipboardText failed"); clip_text = ""; got_clip = true; } while (got_clip == false); return clip_text; } public boolean hasClipboardText() { return clipboard.hasText(); } public boolean setClipboardText(String text) { final String t = text; set_clip = false; try { runOnUiThread(new Runnable() { @Override public void run() { set_clip_result = clipboard.setText(t); set_clip = true; } }); } catch (Exception e) { Log.d("AllegroActivity", "setClipboardText failed"); set_clip_result = false; set_clip = true; } while (set_clip == false); return set_clip_result; } public void setAllegroFrameless(final boolean on) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { runOnUiThread(new Runnable() { @Override public void run() { View view = AllegroActivity.this.getWindow().getDecorView(); int flags = view.getSystemUiVisibility(); int bits = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; if (on) flags |= bits; else flags &= ~bits; view.setSystemUiVisibility(flags); } }); } } public AllegroDialog getNativeDialogAddon() { if (dialog == null) dialog = new AllegroDialog(this); // lazy instantiation return dialog; } private void dismissMessageBox() { // Message boxes block the calling thread. If the app receives a drawing // halt/resume or a display resize event, Allegro will block until these // events are acknowledged. If they are emitted while a message box is // visible and if their acknowledgement takes place in the same thread // that spawned the message box, then the app will freeze. A deadlock // will occur because the events can't be acknowledged while the message // box is blocking the same thread. We should not block in this case. if (dialog != null) dialog.dismissMessageBox(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent resultData) { super.onActivityResult(requestCode, resultCode, resultData); if (dialog != null) dialog.onActivityResult(requestCode, resultCode, resultData); } } /* vim: set sts=3 sw=3 et: */ AllegroDialog.java000066400000000000000000000551111473414355200334230ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/androidpackage org.liballeg.android; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.net.Uri; import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.text.TextUtils; import android.util.Log; import android.webkit.MimeTypeMap; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; /** * Native Dialog Addon */ public class AllegroDialog { private final AllegroActivity activity; private final AllegroMessageBox messageBox = new AllegroMessageBox(); private final AllegroFileChooser fileChooser = new AllegroFileChooser(); private final AllegroTextLog textLog = new AllegroTextLog(); public AllegroDialog(AllegroActivity activity) { this.activity = activity; } public int showMessageBox(String title, String message, String buttons, int flags) { return messageBox.show(activity, title, message, buttons, flags); } public void dismissMessageBox() { messageBox.dismiss(); } public void appendToTextLog(String tag, String message) { textLog.append(tag, message); } public String openFileChooser(int flags, String patterns, String initialPath) { return fileChooser.open(activity, flags, patterns, initialPath); } public void onActivityResult(int requestCode, int resultCode, Intent resultData) { if (requestCode == AllegroFileChooser.REQUEST_FILE_CHOOSER) fileChooser.onActivityResult(requestCode, resultCode, resultData); } } /** * A Message Box implementation */ class AllegroMessageBox { private static final String TAG = "AllegroMessageBox"; private static final int NO_BUTTON = 0; private static final int POSITIVE_BUTTON = 1; private static final int NEGATIVE_BUTTON = 2; private static final int NEUTRAL_BUTTON = 3; private AlertDialog currentDialog = null; public int show(final Activity activity, final String title, final String message, final String buttons, final int flags) { final MutableInteger result = new MutableInteger(NO_BUTTON); // use a boxed integer final Looper looper = myLooper(); // create and show an alert dialog activity.runOnUiThread(new Runnable() { @Override public void run() { // create an alert dialog AlertDialog newDialog = createAlertDialog(activity, title, message, buttons, flags, result, looper); // only one alert dialog can be active at any given time if (currentDialog != null) currentDialog.dismiss(); // show the alert dialog currentDialog = newDialog; showAlertDialog(currentDialog, activity); } }); // make the dialog a modal Log.d(TAG, "Waiting for user input"); try { Looper.loop(); } catch (LooperInterrupterException e) { ; } Log.d(TAG, "Result = " + result.get()); // done! return result.get(); } public void dismiss() { if (currentDialog != null) { Log.d(TAG, "Dismissed by Allegro"); currentDialog.dismiss(); } } private AlertDialog createAlertDialog(Activity activity, String title, String message, String buttons, int flags, MutableInteger result, Looper looper) { final LooperInterrupter interrupter = new LooperInterrupter(looper); OnClickListenerGenerator resultSetter = new OnClickListenerGenerator(result); AlertDialog.Builder builder = new AlertDialog.Builder(activity); // configure the alert dialog builder.setTitle(title); builder.setMessage(message); builder.setCancelable(true); if (0 != (flags & AllegroDialogConst.ALLEGRO_MESSAGEBOX_WARN)) builder.setIcon(android.R.drawable.ic_dialog_alert); else if (0 != (flags & AllegroDialogConst.ALLEGRO_MESSAGEBOX_ERROR)) builder.setIcon(android.R.drawable.ic_dialog_alert); // ic_delete else if (0 != (flags & AllegroDialogConst.ALLEGRO_MESSAGEBOX_QUESTION)) builder.setIcon(android.R.drawable.ic_dialog_info); builder.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { dialog.dismiss(); } }); builder.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { if (dialog == currentDialog) currentDialog = null; interrupter.interrupt(); } }); // configure the buttons boolean wantCustomButtons = !buttons.equals(""); String[] buttonText = wantCustomButtons ? buttons.split("\\|") : null; if (!wantCustomButtons) { builder.setPositiveButton(android.R.string.ok, resultSetter.generate(POSITIVE_BUTTON)); if (0 != (flags & (AllegroDialogConst.ALLEGRO_MESSAGEBOX_OK_CANCEL | AllegroDialogConst.ALLEGRO_MESSAGEBOX_YES_NO))) { // unfortunately, android.R.string.yes and android.R.string.no // are deprecated and resolve to android.R.string.ok and // android.R.string.cancel, respectively. builder.setNegativeButton(android.R.string.cancel, resultSetter.generate(NEGATIVE_BUTTON)); } } else if (buttonText.length == 1) { builder.setPositiveButton(buttonText[0], resultSetter.generate(POSITIVE_BUTTON)); } else if (buttonText.length == 2) { builder.setPositiveButton(buttonText[0], resultSetter.generate(POSITIVE_BUTTON)); builder.setNegativeButton(buttonText[1], resultSetter.generate(NEGATIVE_BUTTON)); } else if (buttonText.length >= 3) { // we support up to 3 buttons builder.setPositiveButton(buttonText[0], resultSetter.generate(POSITIVE_BUTTON)); builder.setNegativeButton(buttonText[1], resultSetter.generate(NEGATIVE_BUTTON)); builder.setNeutralButton(buttonText[2], resultSetter.generate(NEUTRAL_BUTTON)); } // create the alert dialog return builder.create(); } private void showAlertDialog(AlertDialog dialog, Activity activity) { ImmersiveDialogWrapper dlg = new ImmersiveDialogWrapper(dialog); dlg.show(activity); } private Looper myLooper() { // Looper.prepare() will raise an exception if a Looper already exists in the thread try { Looper.prepare(); } catch (Exception e) { ; } return Looper.myLooper(); } private class LooperInterrupter extends Handler { public LooperInterrupter(Looper looper) { super(looper); } public void interrupt() { sendMessage(obtainMessage()); } @Override public void handleMessage(Message msg) { throw new LooperInterrupterException(); } } private class LooperInterrupterException extends RuntimeException { } private class MutableInteger { private int value; public MutableInteger(int value) { this.value = value; } public void set(int value) { this.value = value; } public int get() { return value; } } private class OnClickListenerGenerator { private final MutableInteger result; public OnClickListenerGenerator(MutableInteger result) { this.result = result; } public DialogInterface.OnClickListener generate(final int value) { return new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.set(value); dialog.dismiss(); } }; } } private class ImmersiveDialogWrapper { /* This class wraps a Dialog object with code that handles the immersive mode in a special way. Message boxes have a blocking interface. When the app is in immersive mode (i.e., the ALLEGRO_FRAMELESS display flag is on), a deadlock may occur as soon as a message box is invoked. That will happen if the thread that calls al_acknowledge_resize() is the same thread that invokes the message box. Without a special handling of the immersive mode, the Android system will momentarily show the navigation bar and trigger a surface change as soon as the message box is called forth. This, in turn, triggers a display resize event. In summary, here is what happens: - Allegro will block the UI thread until ALLEGRO_EVENT_DISPLAY_RESIZE is acknowledged. - The thread that invoked the message box from native code will remain blocked until the alert dialog is dismissed. - The thread that invoked the message box cannot possibly acknowledge the display resize while it is blocked. - The alert dialog is displayed from the UI thread. If the UI thread is blocked, then the dialog can't be dismissed. If the dialog isn't dismissed, then the thread that invoked the message box will remain blocked. - Unless al_acknowledge_resize() is called by some other thread, then both threads will be waiting forever. Deadlock! The solution below prevents the deadlock from occurring by preventing the triggering of a display resize event in the first place. This is achieved with a little trick that makes the dialog non-focusable while it's being created. */ private final Dialog dialog; public ImmersiveDialogWrapper(Dialog dialog) { this.dialog = dialog; } public void show(Activity activity) { if (!isInImmersiveMode(activity)) { dialog.show(); return; } // This solution is based on https://stackoverflow.com/a/23207365 View view = activity.getWindow().getDecorView(); int immersiveFlags = view.getSystemUiVisibility(); Window dialogWindow = dialog.getWindow(); dialogWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); dialog.show(); dialogWindow.getDecorView().setSystemUiVisibility(immersiveFlags); dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); } private boolean isInImmersiveMode(Activity activity) { if (Build.VERSION.SDK_INT < 19) return false; // This is based on AllegroActivity.setAllegroFrameless() View view = activity.getWindow().getDecorView(); int flags = view.getSystemUiVisibility(); final int IMMERSIVE_FLAGS = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; return (flags & IMMERSIVE_FLAGS) != 0; } } } /** * A file chooser based on the Storage Access Framework (API level 19+) */ class AllegroFileChooser { public static final int REQUEST_FILE_CHOOSER = 0xF11E; private static final String TAG = "AllegroFileChooser"; private static final String URI_DELIMITER = "\n"; // the Line Feed character cannot be part of a URI (RFC 3986) private CountDownLatch signal = null; private Uri[] resultUri = null; private boolean canceled = false; public String open(Activity activity, int flags, String patterns, String initialPath) { String result; try { // only one file chooser can be opened at any given time if (signal != null) throw new UnsupportedOperationException("Only one file chooser can be opened at any given time"); signal = new CountDownLatch(1); // reset the result resultUri = null; canceled = false; // get an URI from the initial path Uri initialUri = getUriFromInitialPath(initialPath); // get the mime types from the patterns String[] mimeTypes = getMimeTypesFromPatterns(patterns); Log.d(TAG, "Patterns: " + patterns); Log.d(TAG, "Mime types: " + TextUtils.join(";", mimeTypes)); // open the file chooser // note: onActivityResult() will be called on the UI thread reallyOpen(activity, flags, mimeTypes, initialUri); /* The Allegro API specifies that al_show_native_file_dialog() blocks the calling thread until it returns. Since there is a need to handle ALLEGRO_EVENT_DISPLAY_HALT_DRAWING before this function returns, this must be called from a different thread. If al_show_native_file_dialog() is not called from a different thread, then the app will freeze. That will happen after the Activity is paused and before it is stopped. The freezing will take place in two places: at AllegroSurface.nativeOnDestroy() and in here. 1) Here we wait for onActivityResult(), which is called after the we have the results of the file chooser. 2) At AllegroSurface.nativeOnDestroy(), we find a condition variable that waits for al_acknowledge_drawing_halt(). Such acknowledgement cannot happen because the file chooser is blocking. This fact, in turn, freezes the normal life cycle of the Activity after onPause() and before onStopped(). As a consequence, since onActivityResult() would be called by the system only after onStopped() and before onRestart(), we never get a result from the file chooser and the app freezes. Solution: call al_show_native_file_dialog() from another thread. */ // block the calling thread Log.d(TAG, "Waiting for user input"); signal.await(); signal = null; Log.d(TAG, "The file chooser has just been closed!"); } catch (Exception e) { Log.e(TAG, e.getMessage(), e); resultUri = null; } // process the result // due to the constraints of Scoped Storage, we return content:// URIs instead of file paths if (resultUri != null) { Log.d(TAG, "Result: success"); StringBuilder sb = new StringBuilder(); for (int i = 0; i < resultUri.length; i++) { sb.append(resultUri[i].toString()); sb.append(URI_DELIMITER); } result = sb.toString(); } else if (canceled) { Log.d(TAG, "Result: canceled"); result = ""; } else { Log.d(TAG, "Result: failure"); result = null; } // done! resultUri = null; return result; } public void onActivityResult(int requestCode, int resultCode, Intent resultData) { if (requestCode != REQUEST_FILE_CHOOSER) return; // canceled? if (resultCode != Activity.RESULT_OK || resultData == null) { canceled = (resultCode != Activity.RESULT_OK); close(null); return; } // check for multiple results if (Build.VERSION.SDK_INT >= 16) { android.content.ClipData clipData = resultData.getClipData(); if (clipData != null) { // multiple results int n = clipData.getItemCount(); Uri[] uri = new Uri[n]; for (int i = 0; i < n; i++) uri[i] = clipData.getItemAt(i).getUri(); close(uri); return; } } // single result Uri uri = resultData.getData(); if (uri != null) { close(new Uri[] { uri }); return; } // shouldn't happen close(null); } private void close(Uri[] result) { // store the result, which is null or an array of content:// URIs resultUri = result; // unblock the calling thread if (signal != null) signal.countDown(); } private void reallyOpen(Activity activity, int flags, String[] mimeTypes, Uri initialUri) throws RuntimeException { if (Build.VERSION.SDK_INT < 19) throw new UnsupportedOperationException("Unsupported operation in API level " + Build.VERSION.SDK_INT); String action = selectAction(flags); Intent intent = new Intent(action); if (0 != (flags & AllegroDialogConst.ALLEGRO_FILECHOOSER_SAVE)) { // "Save file" if (mimeTypes.length != 1) { intent.setType("*/*"); if (mimeTypes.length > 0) intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes); } else intent.setType(mimeTypes[0]); } else if (0 == (flags & AllegroDialogConst.ALLEGRO_FILECHOOSER_FOLDER)) { // "Load file" if (mimeTypes.length != 1) { intent.setType("*/*"); if (mimeTypes.length > 0) intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes); else if (0 != (flags & AllegroDialogConst.ALLEGRO_FILECHOOSER_PICTURES)) intent.setType("image/*"); } else intent.setType(mimeTypes[0]); } if (0 == (flags & AllegroDialogConst.ALLEGRO_FILECHOOSER_FOLDER)) intent.addCategory(Intent.CATEGORY_OPENABLE); if (0 != (flags & AllegroDialogConst.ALLEGRO_FILECHOOSER_MULTIPLE)) intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); if (Build.VERSION.SDK_INT >= 26) { if (initialUri != null) intent.putExtra(android.provider.DocumentsContract.EXTRA_INITIAL_URI, initialUri); } // invoke the intent Log.d(TAG, "invoking intent " + action); activity.startActivityForResult(intent, REQUEST_FILE_CHOOSER); // throws ActivityNotFoundException /* "To support media file access on devices that run Android 9 (API level 28) or lower, declare the READ_EXTERNAL_STORAGE permission and set the maxSdkVersion to 28." https://developer.android.com/training/data-storage/shared/documents-files */ } private String selectAction(int flags) throws UnsupportedOperationException { if (0 != (flags & AllegroDialogConst.ALLEGRO_FILECHOOSER_FOLDER)) { if (Build.VERSION.SDK_INT < 21) throw new UnsupportedOperationException("Unsupported operation in API level " + Build.VERSION.SDK_INT); return Intent.ACTION_OPEN_DOCUMENT_TREE; } if (0 != (flags & AllegroDialogConst.ALLEGRO_FILECHOOSER_SAVE)) { /* "ACTION_CREATE_DOCUMENT cannot overwrite an existing file. If your app tries to save a file with the same name, the system appends a number in parentheses at the end of the file name. For example, if your app tries to save a file called confirmation.pdf in a directory that already has a file with that name, the system saves the new file with the name confirmation(1).pdf." https://developer.android.com/training/data-storage/shared/documents-files#create-file */ return Intent.ACTION_CREATE_DOCUMENT; } return Intent.ACTION_OPEN_DOCUMENT; } String[] getMimeTypesFromPatterns(String patterns) { MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton(); String[] pattern = patterns.toLowerCase().split(";"); ArrayList mimeType = new ArrayList(); for (int i = 0; i < pattern.length; i++) { String mime = getMimeTypeFromPattern(pattern[i], mimeTypeMap); if (mime != null) // we discard unknown mime types mimeType.add(mime); } return mimeType.toArray(new String[0]); } private String getMimeTypeFromPattern(String pattern, MimeTypeMap mimeTypeMap) { // a pattern may be a mime type or an extension if (pattern.contains("/")) return pattern; // assume it's a mime type else if (pattern.equals("") || pattern.equals(".") || pattern.equals("*.")) return null; // ignore empty else if (pattern.equals("*.*") || pattern.equals("*") || pattern.equals(".*")) return "*/*"; // return any else if (pattern.startsWith(".")) return mimeTypeMap.getMimeTypeFromExtension(pattern.substring(1)); // remove leading '.' else if (pattern.startsWith("*.")) return mimeTypeMap.getMimeTypeFromExtension(pattern.substring(2)); // possibly null else return mimeTypeMap.getMimeTypeFromExtension(pattern); // possibly null } private Uri getUriFromInitialPath(String initialPath) { // "Location should specify a document URI or a tree URI with document ID." // https://developer.android.com/reference/android/provider/DocumentsContract.html#EXTRA_INITIAL_URI if (initialPath.startsWith("content://")) return Uri.parse(initialPath); return null; } } /** * An implementation of the text log */ class AllegroTextLog { public void append(String tag, String message) { Log.i(tag, message); } } /** * Constants of the Native Dialog Addon */ class AllegroDialogConst { // allegro_native_dialog.h public static final int ALLEGRO_FILECHOOSER_FILE_MUST_EXIST = 1; public static final int ALLEGRO_FILECHOOSER_SAVE = 2; public static final int ALLEGRO_FILECHOOSER_FOLDER = 4; public static final int ALLEGRO_FILECHOOSER_PICTURES = 8; public static final int ALLEGRO_FILECHOOSER_SHOW_HIDDEN = 16; public static final int ALLEGRO_FILECHOOSER_MULTIPLE = 32; public static final int ALLEGRO_MESSAGEBOX_WARN = 1; public static final int ALLEGRO_MESSAGEBOX_ERROR = 2; public static final int ALLEGRO_MESSAGEBOX_OK_CANCEL = 4; public static final int ALLEGRO_MESSAGEBOX_YES_NO = 8; public static final int ALLEGRO_MESSAGEBOX_QUESTION = 16; } /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/android/AllegroEGL.java000066400000000000000000000256361473414355200327230ustar00rootroot00000000000000package org.liballeg.android; import android.content.Context; import android.util.Log; import java.util.ArrayList; import java.util.HashMap; import javax.microedition.khronos.egl.*; class AllegroEGL { private static final String TAG = "AllegroEGL"; private static final int EGL_CONTEXT_MAJOR_VERSION = 0x3098; private static final int EGL_CONTEXT_MINOR_VERSION = 0x30fb; private static final int EGL_OPENGL_ES_BIT = 1; private static final int EGL_OPENGL_ES2_BIT = 4; private static HashMap eglErrors; private static void checkEglError(String prompt, EGL10 egl) { if (eglErrors == null) { eglErrors = new HashMap(); eglErrors.put(EGL10.EGL_BAD_DISPLAY, "EGL_BAD_DISPLAY"); eglErrors.put(EGL10.EGL_NOT_INITIALIZED, "EGL_NOT_INITIALIZED"); eglErrors.put(EGL10.EGL_BAD_SURFACE, "EGL_BAD_SURFACE"); eglErrors.put(EGL10.EGL_BAD_CONTEXT, "EGL_BAD_CONTEXT"); eglErrors.put(EGL10.EGL_BAD_MATCH, "EGL_BAD_MATCH"); eglErrors.put(EGL10.EGL_BAD_ACCESS, "EGL_BAD_ACCESS"); eglErrors.put(EGL10.EGL_BAD_NATIVE_PIXMAP, "EGL_BAD_NATIVE_PIXMAP"); eglErrors.put(EGL10.EGL_BAD_NATIVE_WINDOW, "EGL_BAD_NATIVE_WINDOW"); eglErrors.put(EGL10.EGL_BAD_CURRENT_SURFACE, "EGL_BAD_CURRENT_SURFACE"); eglErrors.put(EGL10.EGL_BAD_ALLOC, "EGL_BAD_ALLOC"); eglErrors.put(EGL10.EGL_BAD_CONFIG, "EGL_BAD_CONFIG"); eglErrors.put(EGL10.EGL_BAD_ATTRIBUTE, "EGL_BAD_ATTRIBUTE"); eglErrors.put(EGL11.EGL_CONTEXT_LOST, "EGL_CONTEXT_LOST"); } int error; while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { Log.e("Allegro", String.format("%s: EGL error: %s", prompt, eglErrors.get(error))); } } /* instance members */ private EGLContext egl_Context; private EGLSurface egl_Surface; private EGLDisplay egl_Display; private HashMap attribMap; private EGLConfig[] matchingConfigs; private EGLConfig chosenConfig; boolean egl_Init() { Log.d(TAG, "egl_Init"); EGL10 egl = (EGL10)EGLContext.getEGL(); EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); int[] egl_version = { 0, 0 }; if (!egl.eglInitialize(dpy, egl_version)) { Log.d(TAG, "egl_Init fail"); return false; } egl_Display = dpy; Log.d(TAG, "egl_Init OpenGL ES " + egl_version[0] + "." + egl_version[1]); return true; } void egl_Terminate() { egl_makeCurrent(); egl_destroySurface(); egl_destroyContext(); EGL10 egl = (EGL10)EGLContext.getEGL(); egl.eglTerminate(egl_Display); egl_Display = null; } void egl_initRequiredAttribs() { attribMap = new HashMap(); } void egl_setRequiredAttrib(int attr, int value) { int egl_attr = eglAttrib(attr); if (egl_attr >= 0) { attribMap.put(egl_attr, value); } } private int eglAttrib(int al_attr) { EGL10 egl = (EGL10)EGLContext.getEGL(); final int[] mapping = attribMapping(egl); for (int i = 0; i < mapping.length; i += 2) { if (al_attr == mapping[i + 1]) return mapping[i]; } assert(false); return -1; } private final int[] attribMapping(EGL10 egl) { return new int[] { egl.EGL_RED_SIZE, Const.ALLEGRO_RED_SIZE, egl.EGL_GREEN_SIZE, Const.ALLEGRO_GREEN_SIZE, egl.EGL_BLUE_SIZE, Const.ALLEGRO_BLUE_SIZE, egl.EGL_ALPHA_SIZE, Const.ALLEGRO_ALPHA_SIZE, egl.EGL_BUFFER_SIZE, Const.ALLEGRO_COLOR_SIZE, egl.EGL_DEPTH_SIZE, Const.ALLEGRO_DEPTH_SIZE, egl.EGL_STENCIL_SIZE, Const.ALLEGRO_STENCIL_SIZE, egl.EGL_SAMPLE_BUFFERS, Const.ALLEGRO_SAMPLE_BUFFERS, egl.EGL_SAMPLES, Const.ALLEGRO_SAMPLES }; } int egl_chooseConfig(boolean programmable_pipeline) { EGL10 egl = (EGL10)EGLContext.getEGL(); if (programmable_pipeline) { attribMap.put(EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT); } else { attribMap.put(EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT); } /* Populate the matchingConfigs array. */ matchingConfigs = new EGLConfig[20]; int[] num = new int[1]; boolean ok = egl.eglChooseConfig(egl_Display, requiredAttribsArray(), matchingConfigs, matchingConfigs.length, num); if (!ok || num[0] < 1) { Log.e(TAG, "No matching config"); return 0; } Log.d(TAG, "eglChooseConfig returned " + num[0] + " configurations."); return num[0]; } private int[] requiredAttribsArray() { final int n = attribMap.size(); final int[] arr = new int[n * 2 + 1]; int i = 0; for (int attrib : attribMap.keySet()) { arr[i++] = attrib; arr[i++] = attribMap.get(attrib); } arr[i] = EGL10.EGL_NONE; /* sentinel */ return arr; } void egl_getConfigAttribs(int index, int ret[]) { Log.d(TAG, "Getting attribs for config at index " + index); for (int i = 0; i < ret.length; i++) { ret[i] = 0; } final EGL10 egl = (EGL10)EGLContext.getEGL(); final EGLConfig config = matchingConfigs[index]; final int[] mapping = attribMapping(egl); final int box[] = new int[1]; for (int i = 0; i < mapping.length; i += 2) { int egl_attr = mapping[i]; int al_attr = mapping[i + 1]; if (egl.eglGetConfigAttrib(egl_Display, config, egl_attr, box)) { ret[al_attr] = box[0]; } else { Log.e(TAG, "eglGetConfigAttrib(" + egl_attr + ") failed\n"); } } } private int[] versionAttribList(int major, int minor) { return new int[] { EGL_CONTEXT_MAJOR_VERSION, major, EGL_CONTEXT_MINOR_VERSION, minor, EGL10.EGL_NONE }; } private int versionCode(int major, int minor) { return (major << 8) | minor; } /* Return values: * 0 - failure * 1 - success */ int egl_createContext(int configIndex, boolean programmable_pipeline, int major, int minor, boolean isRequiredMajor, boolean isRequiredMinor) { Log.d(TAG, "egl_createContext"); EGL10 egl = (EGL10)EGLContext.getEGL(); chosenConfig = matchingConfigs[configIndex]; matchingConfigs = null; attribMap = null; // we'll attempt to create a GLES context of version major.minor. // if major == minor == 0, then the user did not request a specific version. // minMajor.minMinor is the minimum acceptable version. int minMajor = (programmable_pipeline || major >= 2) ? 2 : 1; int minMinor = 0; if (isRequiredMajor && major > minMajor) minMajor = major; if (isRequiredMinor && minor > minMinor) minMinor = minor; int minVersion = versionCode(minMajor, minMinor); int wantedVersion = versionCode(major, minor); if (wantedVersion < minVersion) { if(isRequiredMajor || isRequiredMinor) { Log.d(TAG, "Can't require OpenGL ES version " + major + "." + minor); return 0; } major = minMajor; minor = minMinor; wantedVersion = minVersion; } Log.d(TAG, "egl_createContext: requesting OpenGL ES " + major + "." + minor); // request a GLES context version major.minor EGLContext ctx = egl.eglCreateContext(egl_Display, chosenConfig, EGL10.EGL_NO_CONTEXT, versionAttribList(major, minor)); if (ctx == EGL10.EGL_NO_CONTEXT) { // failed to create a GLES context of the requested version checkEglError("eglCreateContext", egl); Log.d(TAG, "egl_createContext failed. min version is " + minMajor + "." + minMinor); // try the min version instead, unless the user required the failed version if ((wantedVersion == minVersion) || (EGL10.EGL_NO_CONTEXT == (ctx = egl.eglCreateContext(egl_Display, chosenConfig, EGL10.EGL_NO_CONTEXT, versionAttribList(minMajor, minMinor)) ))) { // failed again checkEglError("eglCreateContext", egl); Log.d(TAG, "egl_createContext no context"); return 0; } } Log.d(TAG, "egl_createContext: success"); egl_Context = ctx; return 1; } private void egl_destroyContext() { EGL10 egl = (EGL10)EGLContext.getEGL(); Log.d(TAG, "destroying egl_Context"); egl.eglDestroyContext(egl_Display, egl_Context); egl_Context = EGL10.EGL_NO_CONTEXT; } boolean egl_createSurface(AllegroSurface parent) { EGL10 egl = (EGL10)EGLContext.getEGL(); EGLSurface surface = egl.eglCreateWindowSurface(egl_Display, chosenConfig, parent, null); if (surface == EGL10.EGL_NO_SURFACE) { Log.d(TAG, "egl_createSurface can't create surface: " + egl.eglGetError()); return false; } if (!egl.eglMakeCurrent(egl_Display, surface, surface, egl_Context)) { egl.eglDestroySurface(egl_Display, surface); Log.d(TAG, "egl_createSurface can't make current"); return false; } egl_Surface = surface; Log.d(TAG, "created new surface: " + surface); return true; } private void egl_destroySurface() { EGL10 egl = (EGL10)EGLContext.getEGL(); if (!egl.eglMakeCurrent(egl_Display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)) { Log.d(TAG, "could not clear current context"); } Log.d(TAG, "destroying egl_Surface"); egl.eglDestroySurface(egl_Display, egl_Surface); egl_Surface = EGL10.EGL_NO_SURFACE; } void egl_clearCurrent() { Log.d(TAG, "egl_clearCurrent"); EGL10 egl = (EGL10)EGLContext.getEGL(); if (!egl.eglMakeCurrent(egl_Display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)) { Log.d(TAG, "could not clear current context"); } Log.d(TAG, "egl_clearCurrent done"); } void egl_makeCurrent() { EGL10 egl = (EGL10)EGLContext.getEGL(); if (!egl.eglMakeCurrent(egl_Display, egl_Surface, egl_Surface, egl_Context)) { // egl.eglDestroySurface(egl_Display, surface); // egl.eglTerminate(egl_Display); // egl_Display = null; Log.d(TAG, "can't make thread current: "); checkEglError("eglMakeCurrent", egl); } } void egl_SwapBuffers() { try { EGL10 egl = (EGL10)EGLContext.getEGL(); // FIXME: Pretty sure flush is implicit with SwapBuffers //egl.eglWaitNative(EGL10.EGL_NATIVE_RENDERABLE, null); //egl.eglWaitGL(); egl.eglSwapBuffers(egl_Display, egl_Surface); checkEglError("eglSwapBuffers", egl); } catch (Exception x) { Log.d(TAG, "inner exception: " + x.getMessage()); } } } /* vim: set sts=3 sw=3 et: */ AllegroInputStream.java000066400000000000000000000030141473414355200344720ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/androidpackage org.liballeg.android; import java.io.InputStream; import android.util.Log; public class AllegroInputStream extends InputStream { private static final String TAG = "AllegroInputStream"; private long handle; public native int nativeRead(long handle, byte[] buffer, int offset, int length); public native void nativeClose(long handle); public AllegroInputStream(long handle) { super(); this.handle = handle; Log.d(TAG, "ctor handle:" + handle); } @Override public int available() { Log.d(TAG, "available"); return 0; } @Override public void close() { Log.d(TAG, "close"); nativeClose(handle); } @Override public void mark(int limit) { Log.d(TAG, "mark " + limit); } @Override public boolean markSupported() { Log.d(TAG, "markSupported"); return false; } @Override public int read() { byte buffer[] = new byte[1]; int ret = read(buffer, 0, buffer.length); if (ret != -1) return buffer[0]; else return -1; } @Override public int read(byte[] buffer) { return read(buffer, 0, buffer.length); } @Override public int read(byte[] buffer, int offset, int length) { Log.d(TAG, "read handle: " + handle + ", offset: " + offset + ", length: " + length); int ret = nativeRead(handle, buffer, offset, length); Log.d(TAG, "read end: ret = " + ret); return ret; } } /* vim: set sts=3 sw=3 et: */ AllegroJoystick.java000066400000000000000000000066021473414355200340240ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/androidpackage org.liballeg.android; import android.view.View.OnGenericMotionListener; import android.view.MotionEvent; import android.view.InputDevice; import android.view.View; class AllegroJoystick implements OnGenericMotionListener { private AllegroActivity activity; private AllegroSurface surface; public AllegroJoystick(AllegroActivity activity, AllegroSurface surface) { this.activity = activity; this.surface = surface; } private float axis0_x = 0.0f; private float axis0_y = 0.0f; private float axis0_hat_x = 0.0f; private float axis0_hat_y = 0.0f; private float axis1_x = 0.0f; private float axis1_y = 0.0f; private float axis_lt = 0.0f; private float axis_rt = 0.0f; private void handleHat(int index1, float old, float cur, int button1, int button2) { if (old == cur) return; if (old == 0) { if (cur < 0) surface.nativeOnJoystickButton(index1, button1, true); else surface.nativeOnJoystickButton(index1, button2, true); } else if (old < 0) { surface.nativeOnJoystickButton(index1, button1, false); if (cur > 0) { surface.nativeOnJoystickButton(index1, button2, true); } } else if (old > 0) { surface.nativeOnJoystickButton(index1, button2, false); if (cur < 0) { surface.nativeOnJoystickButton(index1, button1, true); } } } @Override public boolean onGenericMotion(View v, MotionEvent event) { if (activity.joystickActive == false) { return false; } int id = event.getDeviceId(); int index = activity.indexOfJoystick(id); if (index >= 0) { float ax = event.getAxisValue(MotionEvent.AXIS_X, 0); float ay = event.getAxisValue(MotionEvent.AXIS_Y, 0); float ahx = event.getAxisValue(MotionEvent.AXIS_HAT_X, 0); float ahy = event.getAxisValue(MotionEvent.AXIS_HAT_Y, 0); float az = event.getAxisValue(MotionEvent.AXIS_Z, 0); float arz = event.getAxisValue(MotionEvent.AXIS_RZ, 0); float alt = event.getAxisValue(MotionEvent.AXIS_BRAKE, 0); float art = event.getAxisValue(MotionEvent.AXIS_GAS, 0); if (ax != axis0_x || ay != axis0_y) { surface.nativeOnJoystickAxis(index, 0, 0, ax); surface.nativeOnJoystickAxis(index, 0, 1, ay); axis0_x = ax; axis0_y = ay; } else if (ahx != axis0_hat_x || ahy != axis0_hat_y) { handleHat(index, axis0_hat_x, ahx, AllegroActivity.JS_DPAD_L, AllegroActivity.JS_DPAD_R); handleHat(index, axis0_hat_y, ahy, AllegroActivity.JS_DPAD_U, AllegroActivity.JS_DPAD_D); axis0_hat_x = ahx; axis0_hat_y = ahy; } if (az != axis1_x || arz != axis1_y) { surface.nativeOnJoystickAxis(index, 1, 0, az); surface.nativeOnJoystickAxis(index, 1, 1, arz); axis1_x = az; axis1_y = arz; } if (alt != axis_lt) { surface.nativeOnJoystickAxis(index, 2, 0, alt); axis_lt = alt; } if (art != axis_rt) { surface.nativeOnJoystickAxis(index, 3, 0, art); axis_rt = art; } return true; } return false; } } AllegroSurface.java000066400000000000000000000077121473414355200336200ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/androidpackage org.liballeg.android; import android.content.Context; import android.graphics.Canvas; import android.util.Log; import android.view.Display; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; class AllegroSurface extends SurfaceView implements SurfaceHolder.Callback { /** native functions we call */ public native void nativeOnCreate(); public native boolean nativeOnDestroy(); public native void nativeOnChange(int format, int width, int height); public native void nativeOnJoystickAxis(int index, int stick, int axis, float value); public native void nativeOnJoystickButton(int index, int button, boolean down); private AllegroActivity activity; private AllegroJoystick joystick_listener; /** functions that native code calls */ boolean egl_Init() { return egl.egl_Init(); } void egl_initRequiredAttribs() { egl.egl_initRequiredAttribs(); } void egl_setRequiredAttrib(int attr, int value) { egl.egl_setRequiredAttrib(attr, value); } int egl_chooseConfig(boolean programmable_pipeline) { return egl.egl_chooseConfig(programmable_pipeline); } void egl_getConfigAttribs(int index, int ret[]) { egl.egl_getConfigAttribs(index, ret); } int egl_createContext(int configIndex, boolean programmable_pipeline, int major, int minor, boolean isRequiredMajor, boolean isRequiredMinor) { return egl.egl_createContext(configIndex, programmable_pipeline, major, minor, isRequiredMajor, isRequiredMinor); } boolean egl_createSurface() { return egl.egl_createSurface(this); } void egl_clearCurrent() { egl.egl_clearCurrent(); } void egl_makeCurrent() { egl.egl_makeCurrent(); } void egl_SwapBuffers() { egl.egl_SwapBuffers(); } /** main handlers */ private AllegroEGL egl; private KeyListener key_listener; private TouchListener touch_listener; public AllegroSurface(Context context, Display display, AllegroActivity activity) { super(context); Log.d("AllegroSurface", "PixelFormat=" + display.getPixelFormat()); getHolder().setFormat(display.getPixelFormat()); getHolder().addCallback(this); this.activity = activity; this.egl = new AllegroEGL(); this.key_listener = new KeyListener(context, activity); this.touch_listener = new TouchListener(); } private void grabFocus() { Log.d("AllegroSurface", "Grabbing focus"); setFocusable(true); setFocusableInTouchMode(true); requestFocus(); setOnKeyListener(key_listener); setOnTouchListener(touch_listener); if (android.os.Build.VERSION.SDK_INT >= 12) { joystick_listener = new AllegroJoystick(activity, this); setOnGenericMotionListener(joystick_listener); } } @Override public void surfaceCreated(SurfaceHolder holder) { Log.d("AllegroSurface", "surfaceCreated"); nativeOnCreate(); grabFocus(); Log.d("AllegroSurface", "surfaceCreated end"); } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.d("AllegroSurface", "surfaceDestroyed"); if (!nativeOnDestroy()) { Log.d("AllegroSurface", "No surface created, returning early"); return; } egl.egl_Terminate(); Log.d("AllegroSurface", "surfaceDestroyed end"); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.d("AllegroSurface", "surfaceChanged (width=" + width + " height=" + height + ")"); nativeOnChange(0xdeadbeef, width, height); Log.d("AllegroSurface", "surfaceChanged end"); } /* unused */ @Override public void onDraw(Canvas canvas) { } /* Events */ /* XXX not exposed in C API yet */ void setCaptureVolumeKeys(boolean onoff) { key_listener.setCaptureVolumeKeys(onoff); } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/android/Clipboard.java000066400000000000000000000040221473414355200326670ustar00rootroot00000000000000package org.liballeg.android; import android.app.Activity; import android.content.Context; import android.content.ClipData; import android.content.ClipboardManager; import android.util.Log; class Clipboard { private static final String TAG = "Clipboard"; private Activity activity; private boolean clip_thread_done = false; private String clipdata; Clipboard(Activity activity) { this.activity = activity; } public boolean setText(String text) { final String ss = text; Runnable runnable = new Runnable() { public void run() { ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText("allegro", ss); clipboard.setPrimaryClip(clip); clip_thread_done = true; }; }; activity.runOnUiThread(runnable); while (!clip_thread_done) ; clip_thread_done = false; return true; } public String getText() { Runnable runnable = new Runnable() { public void run() { ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = clipboard.getPrimaryClip(); if (clip == null) { clipdata = null; } else { ClipData.Item item = clip.getItemAt(0); if (item == null) { clipdata = null; } else { String text = item.coerceToText(activity.getApplicationContext()).toString(); clipdata = text; } } clip_thread_done = true; } }; activity.runOnUiThread(runnable); while (!clip_thread_done); clip_thread_done = false; return clipdata; } boolean hasText() { /* Lazy implementation... */ return this.getText() != null; } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/android/Const.java000066400000000000000000000073231473414355200320650ustar00rootroot00000000000000package org.liballeg.android; import android.content.pm.ActivityInfo; import android.view.Surface; final class Const { /* color.h */ static final int ALLEGRO_PIXEL_FORMAT_ABGR_8888 = 17; static final int ALLEGRO_PIXEL_FORMAT_BGR_565 = 20; static final int ALLEGRO_PIXEL_FORMAT_RGBA_4444 = 26; static final int ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 = 27; /* display.h */ static final int ALLEGRO_RED_SIZE = 0; static final int ALLEGRO_GREEN_SIZE = 1; static final int ALLEGRO_BLUE_SIZE = 2; static final int ALLEGRO_ALPHA_SIZE = 3; static final int ALLEGRO_COLOR_SIZE = 14; static final int ALLEGRO_DEPTH_SIZE = 15; static final int ALLEGRO_STENCIL_SIZE = 16; static final int ALLEGRO_SAMPLE_BUFFERS = 17; static final int ALLEGRO_SAMPLES = 18; static final int ALLEGRO_DISPLAY_ORIENTATION_UNKNOWN = 0; static final int ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES = 1; static final int ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES = 2; static final int ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES = 4; static final int ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES = 8; static final int ALLEGRO_DISPLAY_ORIENTATION_PORTRAIT = 5; static final int ALLEGRO_DISPLAY_ORIENTATION_LANDSCAPE = 10; static final int ALLEGRO_DISPLAY_ORIENTATION_ALL = 15; static final int ALLEGRO_DISPLAY_ORIENTATION_FACE_UP = 16; static final int ALLEGRO_DISPLAY_ORIENTATION_FACE_DOWN = 32; /* events.h */ static final int ALLEGRO_EVENT_TOUCH_BEGIN = 50; static final int ALLEGRO_EVENT_TOUCH_END = 51; static final int ALLEGRO_EVENT_TOUCH_MOVE = 52; static final int ALLEGRO_EVENT_TOUCH_CANCEL = 53; static int toAndroidOrientation(int alleg_orientation) { switch (alleg_orientation) { case ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES: return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; case ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES: return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; case ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES: return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; case ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES: return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; case ALLEGRO_DISPLAY_ORIENTATION_PORTRAIT: return ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT; case ALLEGRO_DISPLAY_ORIENTATION_LANDSCAPE: return ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE; case ALLEGRO_DISPLAY_ORIENTATION_ALL: return ActivityInfo.SCREEN_ORIENTATION_SENSOR; } return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } static int toAllegroOrientation(int rotation) { switch (rotation) { case Surface.ROTATION_0: return ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES; case Surface.ROTATION_180: return ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES; /* Android device orientations are the opposite of Allegro ones. * Allegro orientations are the orientation of the device, with 0 * being holding the device at normal orientation, 90 with the device * rotated 90 degrees clockwise and so on. Android orientations are * the orientations of the GRAPHICS. By rotating the device by 90 * degrees clockwise, the graphics are actually rotated 270 degrees, * and that's what Android uses. */ case Surface.ROTATION_90: return ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES; case Surface.ROTATION_270: return ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES; } return ALLEGRO_DISPLAY_ORIENTATION_UNKNOWN; } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/android/ImageLoader.java000066400000000000000000000063031473414355200331450ustar00rootroot00000000000000package org.liballeg.android; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Log; import java.io.InputStream; class ImageLoader { private static final String TAG = "ImageLoader"; static Bitmap decodeBitmapAsset(Activity activity, final String filename) { Bitmap decodedBitmap; Log.d(TAG, "decodeBitmapAsset begin"); try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_8888; // Only added in API level 19, avoid for now. // options.inPremultiplied = premul; InputStream is = activity.getResources().getAssets().open( Path.simplifyPath(filename)); decodedBitmap = BitmapFactory.decodeStream(is, null, options); is.close(); Log.d(TAG, "done waiting for decodeStream"); } catch (Exception ex) { Log.e(TAG, "decodeBitmapAsset exception: " + ex.getMessage()); decodedBitmap = null; } Log.d(TAG, "decodeBitmapAsset end"); return decodedBitmap; } static Bitmap decodeBitmapStream(final InputStream is) { Bitmap decodedBitmap; Log.d(TAG, "decodeBitmapStream begin"); try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_8888; // Only added in API level 19, avoid for now. // options.inPremultiplied = premul; decodedBitmap = BitmapFactory.decodeStream(is, null, options); Log.d(TAG, "done waiting for decodeStream"); } catch (Exception ex) { Log.e(TAG, "decodeBitmapStream exception: " + ex.getMessage()); decodedBitmap = null; } Log.d(TAG, "decodeBitmapStream end"); return decodedBitmap; } /* Unused yet */ /* static Bitmap decodeBitmapByteArray(byte[] array) { Bitmap decodedBitmap; Log.d(TAG, "decodeBitmapByteArray"); try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_8888; Bitmap bmp = BitmapFactory.decodeByteArray(array, 0, array.length, options); return bmp; } catch (Exception ex) { Log.e(TAG, "decodeBitmapByteArray exception: " + ex.getMessage()); } return null; } */ static int getBitmapFormat(Bitmap bitmap) { switch (bitmap.getConfig()) { case ALPHA_8: return Const.ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8; // not really case ARGB_4444: return Const.ALLEGRO_PIXEL_FORMAT_RGBA_4444; case ARGB_8888: return Const.ALLEGRO_PIXEL_FORMAT_ABGR_8888; case RGB_565: return Const.ALLEGRO_PIXEL_FORMAT_BGR_565; // untested default: assert(false); return -1; } } static int[] getPixels(Bitmap bmp) { int width = bmp.getWidth(); int height = bmp.getHeight(); int[] pixels = new int[width * height]; bmp.getPixels(pixels, 0, width, 0, 0, width, height); return pixels; } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/android/Key.java000066400000000000000000000545751473414355200315420ustar00rootroot00000000000000package org.liballeg.android; final class Key { /* keycodes.h */ static final int ALLEGRO_KEY_A = 1; static final int ALLEGRO_KEY_B = 2; static final int ALLEGRO_KEY_C = 3; static final int ALLEGRO_KEY_D = 4; static final int ALLEGRO_KEY_E = 5; static final int ALLEGRO_KEY_F = 6; static final int ALLEGRO_KEY_G = 7; static final int ALLEGRO_KEY_H = 8; static final int ALLEGRO_KEY_I = 9; static final int ALLEGRO_KEY_J = 10; static final int ALLEGRO_KEY_K = 11; static final int ALLEGRO_KEY_L = 12; static final int ALLEGRO_KEY_M = 13; static final int ALLEGRO_KEY_N = 14; static final int ALLEGRO_KEY_O = 15; static final int ALLEGRO_KEY_P = 16; static final int ALLEGRO_KEY_Q = 17; static final int ALLEGRO_KEY_R = 18; static final int ALLEGRO_KEY_S = 19; static final int ALLEGRO_KEY_T = 20; static final int ALLEGRO_KEY_U = 21; static final int ALLEGRO_KEY_V = 22; static final int ALLEGRO_KEY_W = 23; static final int ALLEGRO_KEY_X = 24; static final int ALLEGRO_KEY_Y = 25; static final int ALLEGRO_KEY_Z = 26; static final int ALLEGRO_KEY_0 = 27; static final int ALLEGRO_KEY_1 = 28; static final int ALLEGRO_KEY_2 = 29; static final int ALLEGRO_KEY_3 = 30; static final int ALLEGRO_KEY_4 = 31; static final int ALLEGRO_KEY_5 = 32; static final int ALLEGRO_KEY_6 = 33; static final int ALLEGRO_KEY_7 = 34; static final int ALLEGRO_KEY_8 = 35; static final int ALLEGRO_KEY_9 = 36; static final int ALLEGRO_KEY_PAD_0 = 37; static final int ALLEGRO_KEY_PAD_1 = 38; static final int ALLEGRO_KEY_PAD_2 = 39; static final int ALLEGRO_KEY_PAD_3 = 40; static final int ALLEGRO_KEY_PAD_4 = 41; static final int ALLEGRO_KEY_PAD_5 = 42; static final int ALLEGRO_KEY_PAD_6 = 43; static final int ALLEGRO_KEY_PAD_7 = 44; static final int ALLEGRO_KEY_PAD_8 = 45; static final int ALLEGRO_KEY_PAD_9 = 46; static final int ALLEGRO_KEY_F1 = 47; static final int ALLEGRO_KEY_F2 = 48; static final int ALLEGRO_KEY_F3 = 49; static final int ALLEGRO_KEY_F4 = 50; static final int ALLEGRO_KEY_F5 = 51; static final int ALLEGRO_KEY_F6 = 52; static final int ALLEGRO_KEY_F7 = 53; static final int ALLEGRO_KEY_F8 = 54; static final int ALLEGRO_KEY_F9 = 55; static final int ALLEGRO_KEY_F10 = 56; static final int ALLEGRO_KEY_F11 = 57; static final int ALLEGRO_KEY_F12 = 58; static final int ALLEGRO_KEY_ESCAPE = 59; static final int ALLEGRO_KEY_TILDE = 60; static final int ALLEGRO_KEY_MINUS = 61; static final int ALLEGRO_KEY_EQUALS = 62; static final int ALLEGRO_KEY_BACKSPACE = 63; static final int ALLEGRO_KEY_TAB = 64; static final int ALLEGRO_KEY_OPENBRACE = 65; static final int ALLEGRO_KEY_CLOSEBRACE = 66; static final int ALLEGRO_KEY_ENTER = 67; static final int ALLEGRO_KEY_SEMICOLON = 68; static final int ALLEGRO_KEY_QUOTE = 69; static final int ALLEGRO_KEY_BACKSLASH = 70; static final int ALLEGRO_KEY_BACKSLASH2 = 71; /* DirectInput calls this DIK_OEM_102: "< > | on UK/Germany keyboards" */ static final int ALLEGRO_KEY_COMMA = 72; static final int ALLEGRO_KEY_FULLSTOP = 73; static final int ALLEGRO_KEY_SLASH = 74; static final int ALLEGRO_KEY_SPACE = 75; static final int ALLEGRO_KEY_INSERT = 76; static final int ALLEGRO_KEY_DELETE = 77; static final int ALLEGRO_KEY_HOME = 78; static final int ALLEGRO_KEY_END = 79; static final int ALLEGRO_KEY_PGUP = 80; static final int ALLEGRO_KEY_PGDN = 81; static final int ALLEGRO_KEY_LEFT = 82; static final int ALLEGRO_KEY_RIGHT = 83; static final int ALLEGRO_KEY_UP = 84; static final int ALLEGRO_KEY_DOWN = 85; static final int ALLEGRO_KEY_PAD_SLASH = 86; static final int ALLEGRO_KEY_PAD_ASTERISK= 87; static final int ALLEGRO_KEY_PAD_MINUS = 88; static final int ALLEGRO_KEY_PAD_PLUS = 89; static final int ALLEGRO_KEY_PAD_DELETE = 90; static final int ALLEGRO_KEY_PAD_ENTER = 91; static final int ALLEGRO_KEY_PRINTSCREEN = 92; static final int ALLEGRO_KEY_PAUSE = 93; static final int ALLEGRO_KEY_ABNT_C1 = 94; static final int ALLEGRO_KEY_YEN = 95; static final int ALLEGRO_KEY_KANA = 96; static final int ALLEGRO_KEY_CONVERT = 97; static final int ALLEGRO_KEY_NOCONVERT = 98; static final int ALLEGRO_KEY_AT = 99; static final int ALLEGRO_KEY_CIRCUMFLEX = 100; static final int ALLEGRO_KEY_COLON2 = 101; static final int ALLEGRO_KEY_KANJI = 102; static final int ALLEGRO_KEY_PAD_EQUALS = 103; /* MacOS X */ static final int ALLEGRO_KEY_BACKQUOTE = 104; /* MacOS X */ static final int ALLEGRO_KEY_SEMICOLON2 = 105; /* MacOS X -- TODO: ask lillo what this should be */ static final int ALLEGRO_KEY_COMMAND = 106; /* MacOS X */ static final int ALLEGRO_KEY_BACK = 107; static final int ALLEGRO_KEY_VOLUME_UP = 108; static final int ALLEGRO_KEY_VOLUME_DOWN = 109; /* Some more standard Android keys. * These happen to be the ones used by the Xperia Play. */ static final int ALLEGRO_KEY_SEARCH = 110; static final int ALLEGRO_KEY_DPAD_CENTER = 111; static final int ALLEGRO_KEY_BUTTON_X = 112; static final int ALLEGRO_KEY_BUTTON_Y = 113; static final int ALLEGRO_KEY_DPAD_UP = 114; static final int ALLEGRO_KEY_DPAD_DOWN = 115; static final int ALLEGRO_KEY_DPAD_LEFT = 116; static final int ALLEGRO_KEY_DPAD_RIGHT = 117; static final int ALLEGRO_KEY_SELECT = 118; static final int ALLEGRO_KEY_START = 119; static final int ALLEGRO_KEY_BUTTON_L1 = 120; static final int ALLEGRO_KEY_BUTTON_R1 = 121; static final int ALLEGRO_KEY_BUTTON_L2 = 122; static final int ALLEGRO_KEY_BUTTON_R2 = 123; static final int ALLEGRO_KEY_BUTTON_A = 124; static final int ALLEGRO_KEY_BUTTON_B = 125; static final int ALLEGRO_KEY_THUMBL = 126; static final int ALLEGRO_KEY_THUMBR = 127; static final int ALLEGRO_KEY_UNKNOWN = 128; /* All codes up to before ALLEGRO_KEY_MODIFIERS can be freely * assigned as additional unknown keys, like various multimedia * and application keys keyboards may have. */ static final int ALLEGRO_KEY_MODIFIERS = 215; static final int ALLEGRO_KEY_LSHIFT = 215; static final int ALLEGRO_KEY_RSHIFT = 216; static final int ALLEGRO_KEY_LCTRL = 217; static final int ALLEGRO_KEY_RCTRL = 218; static final int ALLEGRO_KEY_ALT = 219; static final int ALLEGRO_KEY_ALTGR = 220; static final int ALLEGRO_KEY_LWIN = 221; static final int ALLEGRO_KEY_RWIN = 222; static final int ALLEGRO_KEY_MENU = 223; static final int ALLEGRO_KEY_SCROLLLOCK = 224; static final int ALLEGRO_KEY_NUMLOCK = 225; static final int ALLEGRO_KEY_CAPSLOCK = 226; static final int ALLEGRO_KEY_MAX = 227; protected static int[] keyMap = { ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_UNKNOWN ALLEGRO_KEY_LEFT, // KeyEvent.KEYCODE_SOFT_LEFT ALLEGRO_KEY_RIGHT, // KeyEvent.KEYCODE_SOFT_RIGHT ALLEGRO_KEY_HOME, // KeyEvent.KEYCODE_HOME ALLEGRO_KEY_BACK, // KeyEvent.KEYCODE_BACK ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_CALL ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ENDCALL ALLEGRO_KEY_0, // KeyEvent.KEYCODE_0 ALLEGRO_KEY_1, // KeyEvent.KEYCODE_1 ALLEGRO_KEY_2, // KeyEvent.KEYCODE_2 ALLEGRO_KEY_3, // KeyEvent.KEYCODE_3 ALLEGRO_KEY_4, // KeyEvent.KEYCODE_4 ALLEGRO_KEY_5, // KeyEvent.KEYCODE_5 ALLEGRO_KEY_6, // KeyEvent.KEYCODE_6 ALLEGRO_KEY_7, // KeyEvent.KEYCODE_7 ALLEGRO_KEY_8, // KeyEvent.KEYCODE_8 ALLEGRO_KEY_9, // KeyEvent.KEYCODE_9 ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_STAR ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_POUND ALLEGRO_KEY_UP, // KeyEvent.KEYCODE_DPAD_UP ALLEGRO_KEY_DOWN, // KeyEvent.KEYCODE_DPAD_DOWN ALLEGRO_KEY_LEFT, // KeyEvent.KEYCODE_DPAD_LEFT ALLEGRO_KEY_RIGHT, // KeyEvent.KEYCODE_DPAD_RIGHT ALLEGRO_KEY_ENTER, // KeyEvent.KEYCODE_DPAD_CENTER ALLEGRO_KEY_VOLUME_UP, // KeyEvent.KEYCODE_VOLUME_UP ALLEGRO_KEY_VOLUME_DOWN, // KeyEvent.KEYCODE_VOLUME_DOWN ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_POWER ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_CAMERA ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_CLEAR ALLEGRO_KEY_A, // KeyEvent.KEYCODE_A ALLEGRO_KEY_B, // KeyEvent.KEYCODE_B ALLEGRO_KEY_C, // KeyEvent.KEYCODE_B ALLEGRO_KEY_D, // KeyEvent.KEYCODE_D ALLEGRO_KEY_E, // KeyEvent.KEYCODE_E ALLEGRO_KEY_F, // KeyEvent.KEYCODE_F ALLEGRO_KEY_G, // KeyEvent.KEYCODE_G ALLEGRO_KEY_H, // KeyEvent.KEYCODE_H ALLEGRO_KEY_I, // KeyEvent.KEYCODE_I ALLEGRO_KEY_J, // KeyEvent.KEYCODE_J ALLEGRO_KEY_K, // KeyEvent.KEYCODE_K ALLEGRO_KEY_L, // KeyEvent.KEYCODE_L ALLEGRO_KEY_M, // KeyEvent.KEYCODE_M ALLEGRO_KEY_N, // KeyEvent.KEYCODE_N ALLEGRO_KEY_O, // KeyEvent.KEYCODE_O ALLEGRO_KEY_P, // KeyEvent.KEYCODE_P ALLEGRO_KEY_Q, // KeyEvent.KEYCODE_Q ALLEGRO_KEY_R, // KeyEvent.KEYCODE_R ALLEGRO_KEY_S, // KeyEvent.KEYCODE_S ALLEGRO_KEY_T, // KeyEvent.KEYCODE_T ALLEGRO_KEY_U, // KeyEvent.KEYCODE_U ALLEGRO_KEY_V, // KeyEvent.KEYCODE_V ALLEGRO_KEY_W, // KeyEvent.KEYCODE_W ALLEGRO_KEY_X, // KeyEvent.KEYCODE_X ALLEGRO_KEY_Y, // KeyEvent.KEYCODE_Y ALLEGRO_KEY_Z, // KeyEvent.KEYCODE_Z ALLEGRO_KEY_COMMA, // KeyEvent.KEYCODE_COMMA ALLEGRO_KEY_FULLSTOP, // KeyEvent.KEYCODE_PERIOD ALLEGRO_KEY_ALT, // KeyEvent.KEYCODE_ALT_LEFT ALLEGRO_KEY_ALTGR, // KeyEvent.KEYCODE_ALT_RIGHT ALLEGRO_KEY_LSHIFT, // KeyEvent.KEYCODE_SHIFT_LEFT ALLEGRO_KEY_RSHIFT, // KeyEvent.KEYCODE_SHIFT_RIGHT ALLEGRO_KEY_TAB, // KeyEvent.KEYCODE_TAB ALLEGRO_KEY_SPACE, // KeyEvent.KEYCODE_SPACE ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_SYM ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_EXPLORER ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ENVELOPE ALLEGRO_KEY_ENTER, // KeyEvent.KEYCODE_ENTER ALLEGRO_KEY_BACKSPACE, // KeyEvent.KEYCODE_DEL ALLEGRO_KEY_TILDE, // KeyEvent.KEYCODE_GRAVE ALLEGRO_KEY_MINUS, // KeyEvent.KEYCODE_MINUS ALLEGRO_KEY_EQUALS, // KeyEvent.KEYCODE_EQUALS ALLEGRO_KEY_OPENBRACE, // KeyEvent.KEYCODE_LEFT_BRACKET ALLEGRO_KEY_CLOSEBRACE, // KeyEvent.KEYCODE_RIGHT_BRACKET ALLEGRO_KEY_BACKSLASH, // KeyEvent.KEYCODE_BACKSLASH ALLEGRO_KEY_SEMICOLON, // KeyEvent.KEYCODE_SEMICOLON ALLEGRO_KEY_QUOTE, // KeyEvent.KEYCODE_APOSTROPHY ALLEGRO_KEY_SLASH, // KeyEvent.KEYCODE_SLASH ALLEGRO_KEY_AT, // KeyEvent.KEYCODE_AT ALLEGRO_KEY_NUMLOCK, // KeyEvent.KEYCODE_NUM ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_HEADSETHOOK ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_FOCUS ALLEGRO_KEY_PAD_PLUS, // KeyEvent.KEYCODE_PLUS ALLEGRO_KEY_MENU, // KeyEvent.KEYCODE_MENU ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_NOTIFICATION ALLEGRO_KEY_SEARCH, // KeyEvent.KEYCODE_SEARCH ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_MEDIA_STOP ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_MEDIA_NEXT ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_MEDIA_PREVIOUS ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_MEDIA_REWIND ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_MEDIA_FAST_FORWARD ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_MUTE ALLEGRO_KEY_PGUP, // KeyEvent.KEYCODE_PAGE_UP ALLEGRO_KEY_PGDN, // KeyEvent.KEYCODE_PAGE_DOWN ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_PICTSYMBOLS ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_SWITCH_CHARSET ALLEGRO_KEY_BUTTON_A, // KeyEvent.KEYCODE_BUTTON_A ALLEGRO_KEY_BUTTON_B, // KeyEvent.KEYCODE_BUTTON_B ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_BUTTON_C ALLEGRO_KEY_BUTTON_X, // KeyEvent.KEYCODE_BUTTON_X ALLEGRO_KEY_BUTTON_Y, // KeyEvent.KEYCODE_BUTTON_Y ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_BUTTON_Z ALLEGRO_KEY_BUTTON_L1, // KeyEvent.KEYCODE_BUTTON_L1 ALLEGRO_KEY_BUTTON_R1, // KeyEvent.KEYCODE_BUTTON_R1 ALLEGRO_KEY_BUTTON_L2, // KeyEvent.KEYCODE_BUTTON_L2 ALLEGRO_KEY_BUTTON_R2, // KeyEvent.KEYCODE_BUTTON_R2 ALLEGRO_KEY_THUMBL, // KeyEvent.KEYCODE_BUTTON_THUMBL ALLEGRO_KEY_THUMBR, // KeyEvent.KEYCODE_BUTTON_THUMBR ALLEGRO_KEY_START, // KeyEvent.KEYCODE_BUTTON_START ALLEGRO_KEY_SELECT, // KeyEvent.KEYCODE_BUTTON_SELECT ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_BUTTON_MODE ALLEGRO_KEY_ESCAPE, // KeyEvent.KEYCODE_ESCAPE (111) ALLEGRO_KEY_DELETE, // KeyEvent.KEYCODE_FORWARD_DELETE (112) ALLEGRO_KEY_LCTRL, // KeyEvent.KEYCODE_CTRL_LEFT (113) ALLEGRO_KEY_RCTRL, // KeyEvent.KEYCODE_CONTROL_RIGHT (114) ALLEGRO_KEY_CAPSLOCK, // KeyEvent.KEYCODE_CAPS_LOCK (115) ALLEGRO_KEY_SCROLLLOCK, // KeyEvent.KEYCODE_SCROLL_LOCK (116) ALLEGRO_KEY_LWIN, // KeyEvent.KEYCODE_META_LEFT (117) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (118) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (119) ALLEGRO_KEY_PRINTSCREEN, // KeyEvent.KEYCODE_SYSRQ (120) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (121) ALLEGRO_KEY_HOME, // KeyEvent.KEYCODE_MOVE_HOME (122) ALLEGRO_KEY_END, // KeyEvent.KEYCODE_MOVE_END (123) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (124) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (125) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (126) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (127) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (128) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (129) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (130) ALLEGRO_KEY_F1, // KeyEvent.KEYCODE_ (131) ALLEGRO_KEY_F2, // KeyEvent.KEYCODE_ (132) ALLEGRO_KEY_F3, // KeyEvent.KEYCODE_ (133) ALLEGRO_KEY_F4, // KeyEvent.KEYCODE_ (134) ALLEGRO_KEY_F5, // KeyEvent.KEYCODE_ (135) ALLEGRO_KEY_F6, // KeyEvent.KEYCODE_ (136) ALLEGRO_KEY_F7, // KeyEvent.KEYCODE_ (137) ALLEGRO_KEY_F8, // KeyEvent.KEYCODE_ (138) ALLEGRO_KEY_F9, // KeyEvent.KEYCODE_ (139) ALLEGRO_KEY_F10, // KeyEvent.KEYCODE_ (140) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (141) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (142) ALLEGRO_KEY_NUMLOCK, // KeyEvent.KEYCODE_NUM_LOCK (143) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (144) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (145) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (146) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (147) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (148) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (149) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (150) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (151) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (152) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (153) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (154) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (155) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (156) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (157) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (158) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (159) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (160) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (161) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (162) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (163) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (164) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (165) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (166) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (167) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (168) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (169) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (170) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (171) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (172) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (173) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (174) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (175) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (176) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (177) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (178) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (179) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (180) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (181) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (182) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (183) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (184) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (185) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (186) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (187) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (188) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (189) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (190) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (191) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (192) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (193) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (194) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (195) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (196) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (197) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (198) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (199) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (200) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (201) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (202) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (203) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (204) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (205) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (206) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (207) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (208) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (209) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (210) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (211) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (212) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (213) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (214) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (215) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (216) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (217) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (218) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (219) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (220) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (221) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (222) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (223) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (224) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (225) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (226) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (227) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (228) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (229) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (230) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (231) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (232) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (233) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (234) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (235) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (236) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (237) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (238) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (239) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (240) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (241) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (242) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (243) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (244) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (245) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (246) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (247) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (248) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (249) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (250) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (251) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (252) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (253) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (254) ALLEGRO_KEY_UNKNOWN, // KeyEvent.KEYCODE_ (255) }; /* Return Allegro key code for Android key code. */ static int alKey(int keyCode) { if (keyCode < keyMap.length) return keyMap[keyCode]; else return ALLEGRO_KEY_UNKNOWN; } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/android/KeyListener.java000066400000000000000000000161501473414355200332330ustar00rootroot00000000000000package org.liballeg.android; import android.media.AudioManager; import android.content.Context; import android.view.KeyEvent; import android.view.View; class KeyListener implements View.OnKeyListener { private Context context; private boolean captureVolume = false; private AllegroActivity activity; native void nativeOnKeyDown(int key); native void nativeOnKeyUp(int key); native void nativeOnKeyChar(int key, int unichar); native void nativeOnJoystickButton(int index, int button, boolean down); KeyListener(Context context, AllegroActivity activity) { this.context = context; this.activity = activity; } void setCaptureVolumeKeys(boolean onoff) { captureVolume = onoff; } public boolean onKeyboardKey(View v, int keyCode, KeyEvent event) { int unichar; if (event.getAction() == KeyEvent.ACTION_DOWN) { if (!captureVolume) { if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { volumeChange(1); return true; } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { volumeChange(-1); return true; } } if (Key.alKey(keyCode) == Key.ALLEGRO_KEY_BACKSPACE) { unichar = '\b'; } else if (Key.alKey(keyCode) == Key.ALLEGRO_KEY_ENTER) { unichar = '\r'; } else { unichar = event.getUnicodeChar(); } if (event.getRepeatCount() == 0) { nativeOnKeyDown(Key.alKey(keyCode)); nativeOnKeyChar(Key.alKey(keyCode), unichar); } else { nativeOnKeyChar(Key.alKey(keyCode), unichar); } return true; } else if (event.getAction() == KeyEvent.ACTION_UP) { nativeOnKeyUp(Key.alKey(keyCode)); return true; } return false; } private int getCode(int keyCode, KeyEvent event, int index1) { switch (keyCode) { // gamepad buttons case KeyEvent.KEYCODE_BUTTON_A: return AllegroActivity.JS_A; case KeyEvent.KEYCODE_BUTTON_B: return AllegroActivity.JS_B; case KeyEvent.KEYCODE_BUTTON_C: return AllegroActivity.JS_C; case KeyEvent.KEYCODE_BUTTON_X: return AllegroActivity.JS_X; case KeyEvent.KEYCODE_BUTTON_Y: return AllegroActivity.JS_Y; case KeyEvent.KEYCODE_BUTTON_Z: return AllegroActivity.JS_Z; case KeyEvent.KEYCODE_MENU: case KeyEvent.KEYCODE_BUTTON_START: return AllegroActivity.JS_START; case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_BUTTON_SELECT: return AllegroActivity.JS_SELECT; case KeyEvent.KEYCODE_BUTTON_MODE: return AllegroActivity.JS_MODE; case KeyEvent.KEYCODE_BUTTON_THUMBL: return AllegroActivity.JS_THUMBL; case KeyEvent.KEYCODE_BUTTON_THUMBR: return AllegroActivity.JS_THUMBR; case KeyEvent.KEYCODE_BUTTON_L1: return AllegroActivity.JS_L1; case KeyEvent.KEYCODE_BUTTON_R1: return AllegroActivity.JS_R1; case KeyEvent.KEYCODE_BUTTON_L2: return AllegroActivity.JS_L2; case KeyEvent.KEYCODE_BUTTON_R2: return AllegroActivity.JS_R2; // D-Pad case KeyEvent.KEYCODE_DPAD_CENTER: return AllegroActivity.JS_DPAD_CENTER; case KeyEvent.KEYCODE_DPAD_LEFT: if (event.getAction() == KeyEvent.ACTION_DOWN) nativeOnJoystickButton(index1, AllegroActivity.JS_DPAD_L, true); else nativeOnJoystickButton(index1, AllegroActivity.JS_DPAD_L, false); return -2; case KeyEvent.KEYCODE_DPAD_RIGHT: if (event.getAction() == KeyEvent.ACTION_DOWN) nativeOnJoystickButton(index1, AllegroActivity.JS_DPAD_R, true); else nativeOnJoystickButton(index1, AllegroActivity.JS_DPAD_R, false); return -2; case KeyEvent.KEYCODE_DPAD_UP: if (event.getAction() == KeyEvent.ACTION_DOWN) nativeOnJoystickButton(index1, AllegroActivity.JS_DPAD_U, true); else nativeOnJoystickButton(index1, AllegroActivity.JS_DPAD_U, false); return -2; case KeyEvent.KEYCODE_DPAD_DOWN: if (event.getAction() == KeyEvent.ACTION_DOWN) nativeOnJoystickButton(index1, AllegroActivity.JS_DPAD_D, true); else nativeOnJoystickButton(index1, AllegroActivity.JS_DPAD_D, false); return -2; // generic gamepad buttons case KeyEvent.KEYCODE_BUTTON_1: case KeyEvent.KEYCODE_BUTTON_2: case KeyEvent.KEYCODE_BUTTON_3: case KeyEvent.KEYCODE_BUTTON_4: case KeyEvent.KEYCODE_BUTTON_5: case KeyEvent.KEYCODE_BUTTON_6: case KeyEvent.KEYCODE_BUTTON_7: case KeyEvent.KEYCODE_BUTTON_8: case KeyEvent.KEYCODE_BUTTON_9: case KeyEvent.KEYCODE_BUTTON_10: case KeyEvent.KEYCODE_BUTTON_11: case KeyEvent.KEYCODE_BUTTON_12: case KeyEvent.KEYCODE_BUTTON_13: case KeyEvent.KEYCODE_BUTTON_14: case KeyEvent.KEYCODE_BUTTON_15: case KeyEvent.KEYCODE_BUTTON_16: return AllegroActivity.JS_BUTTON_1 + (keyCode - KeyEvent.KEYCODE_BUTTON_1); // not a joystick button default: return -1; } } public boolean onKey(View v, int keyCode, KeyEvent event) { /* We want media player controls to keep working in background apps */ if (keyCode == KeyEvent.KEYCODE_MEDIA_REWIND || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) { return false; } if (activity.joystickActive == false) { return onKeyboardKey(v, keyCode, event); } int id = event.getDeviceId(); int index = activity.indexOfJoystick(id); int code = -1; if (index >= 0) { code = getCode(keyCode, event, index); } if (code == -1) { return onKeyboardKey(v, keyCode, event); } else if (code == -2) { return true; } if (event.getAction() == KeyEvent.ACTION_DOWN) { if (event.getRepeatCount() == 0) { nativeOnJoystickButton(index, code, true); } } else { nativeOnJoystickButton(index, code, false); } return true; } private void volumeChange(int inc) { AudioManager mAudioManager = (AudioManager)this.context.getApplicationContext() .getSystemService(Context.AUDIO_SERVICE); int curr = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); int max = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); int vol = curr + inc; if (0 <= vol && vol <= max) { // Set a new volume level manually with the FLAG_SHOW_UI flag. mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, vol, AudioManager.FLAG_SHOW_UI); } } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/android/Path.java000066400000000000000000000013401473414355200316640ustar00rootroot00000000000000package org.liballeg.android; import android.text.TextUtils; import java.util.ArrayList; final class Path { // AssetManager does not interpret the path(!) so we do it here. static String simplifyPath(final String path) { final String[] pieces = path.split("/"); ArrayList keep = new ArrayList(); for (String piece : pieces) { if (piece.equals("")) continue; if (piece.equals(".")) continue; if (piece.equals("..")) { if (keep.size() > 0) keep.remove(keep.size() - 1); continue; } keep.add(piece); } return TextUtils.join("/", keep); } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/android/Reflect.java000066400000000000000000000051261473414355200323620ustar00rootroot00000000000000package org.liballeg.android; import android.util.Log; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; final class Reflect { static final String TAG = "Reflect"; static boolean fieldExists(Object obj, String fieldName) { try { Class cls = obj.getClass(); Field m = cls.getField(fieldName); return true; } catch (Exception x) { return false; } } static boolean methodExists(Object obj, String methName) { try { Class cls = obj.getClass(); Method m = cls.getMethod(methName); return true; } catch (Exception x) { return false; } } static T getField(Object obj, String field) { try { Class cls = obj.getClass(); Field f = cls.getField(field); return (T)f.get(obj); } catch (NoSuchFieldException x) { Log.v(TAG, "field " + field + " not found in class " + obj.getClass().getCanonicalName()); return null; } catch (IllegalArgumentException x) { Log.v(TAG, "IllegalArgumentException when getting field " + field + " from class " + obj.getClass().getCanonicalName()); return null; } catch (IllegalAccessException x) { Log.v(TAG, "field " + field + " is not accessible in class " + obj.getClass().getCanonicalName()); return null; } } static T callMethod(Object obj, String methName, Class [] types, Object... args) { try { Class cls = obj.getClass(); Method m = cls.getMethod(methName, types); return (T)m.invoke(obj, args); } catch (NoSuchMethodException x) { Log.v(TAG, "method " + methName + " does not exist in class " + obj.getClass().getCanonicalName()); return null; } catch (NullPointerException x) { Log.v(TAG, "can't invoke null method name"); return null; } catch (SecurityException x) { Log.v(TAG, "method " + methName + " is inaccessible in class " + obj.getClass().getCanonicalName()); return null; } catch (IllegalAccessException x) { Log.v(TAG, "method " + methName + " is inaccessible in class " + obj.getClass().getCanonicalName()); return null; } catch (InvocationTargetException x) { Log.v(TAG, "method " + methName + " threw an exception"); return null; } } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/android/ScreenLock.java000066400000000000000000000023071473414355200330240ustar00rootroot00000000000000package org.liballeg.android; import android.app.Activity; import android.util.Log; import android.view.Window; import android.view.WindowManager; class ScreenLock { private static final String TAG = "ScreenLock"; private Activity activity; ScreenLock(Activity activity) { this.activity = activity; } boolean inhibitScreenLock(boolean inhibit) { try { if (inhibit) { acquire(); } else if (!inhibit) { release(); } return true; } catch (Exception e) { Log.d(TAG, "Got exception in inhibitScreenLock: " + e.getMessage()); return false; } } private void acquire() { activity.runOnUiThread(new Runnable() { @Override public void run() { activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } }); } private void release() { activity.runOnUiThread(new Runnable() { @Override public void run() { activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } }); } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/android/Sensors.java000066400000000000000000000027521473414355200324340ustar00rootroot00000000000000package org.liballeg.android; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import java.util.List; public class Sensors implements SensorEventListener { private static SensorManager sensorManager; private List sensors; public native void nativeOnAccel(int id, float x, float y, float z); Sensors(Context context) { /* Only check for Accelerometers for now, not sure how we should utilize * other types. */ sensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); sensors = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER); } void listen() { for (int i = 0; i < sensors.size(); i++) { sensorManager.registerListener(this, sensors.get(i), SensorManager.SENSOR_DELAY_GAME); } } void unlisten() { for (int i = 0; i < sensors.size(); i++) { sensorManager.unregisterListener(this, sensors.get(i)); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { /* what to do? */ } @Override public void onSensorChanged(SensorEvent event) { int i = sensors.indexOf(event.sensor); if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { nativeOnAccel(i, event.values[0], event.values[1], event.values[2]); } } } /* vim: set sts=3 sw=3 et: */ TouchListener.java000066400000000000000000000077311473414355200335130ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/allegro/src/main/java/org/liballeg/androidpackage org.liballeg.android; import android.util.Log; import android.view.MotionEvent; import android.view.View; class TouchListener implements View.OnTouchListener { private static final String TAG = "TouchListener"; native void nativeOnTouch(int id, int action, float x, float y, boolean primary); TouchListener() { } // FIXME: Pull out android version detection into the setup and just check // some flags here, rather than checking for the existance of the fields and // methods over and over. @Override public boolean onTouch(View v, MotionEvent event) { int action = 0; int pointer_id = 0; Class[] no_args = new Class[0]; Class[] int_arg = new Class[1]; int_arg[0] = int.class; if (Reflect.methodExists(event, "getActionMasked")) { // android-8 / 2.2.x action = Reflect.callMethod(event, "getActionMasked", no_args); int ptr_idx = Reflect.callMethod(event, "getActionIndex", no_args); pointer_id = Reflect.callMethod(event, "getPointerId", int_arg, ptr_idx); } else { int raw_action = event.getAction(); if (Reflect.fieldExists(event, "ACTION_MASK")) { // android-5 / 2.0 int mask = Reflect.getField(event, "ACTION_MASK"); action = raw_action & mask; int ptr_id_mask = Reflect.getField(event, "ACTION_POINTER_ID_MASK"); int ptr_id_shift = Reflect.getField(event, "ACTION_POINTER_ID_SHIFT"); pointer_id = event.getPointerId((raw_action & ptr_id_mask) >> ptr_id_shift); } else { // android-4 / 1.6 /* no ACTION_MASK? no multi touch, no pointer_id, */ action = raw_action; } } boolean primary = false; if (action == MotionEvent.ACTION_DOWN) { primary = true; action = Const.ALLEGRO_EVENT_TOUCH_BEGIN; } else if (action == MotionEvent.ACTION_UP) { primary = true; action = Const.ALLEGRO_EVENT_TOUCH_END; } else if (action == MotionEvent.ACTION_MOVE) { action = Const.ALLEGRO_EVENT_TOUCH_MOVE; } else if (action == MotionEvent.ACTION_CANCEL) { action = Const.ALLEGRO_EVENT_TOUCH_CANCEL; } // android-5 / 2.0 else if (Reflect.fieldExists(event, "ACTION_POINTER_DOWN") && action == Reflect.getField(event, "ACTION_POINTER_DOWN")) { action = Const.ALLEGRO_EVENT_TOUCH_BEGIN; } else if (Reflect.fieldExists(event, "ACTION_POINTER_UP") && action == Reflect.getField(event, "ACTION_POINTER_UP")) { action = Const.ALLEGRO_EVENT_TOUCH_END; } else { Log.v(TAG, "unknown MotionEvent type: " + action); return false; } if (Reflect.methodExists(event, "getPointerCount")) { // android-5 / 2.0 int pointer_count = Reflect.callMethod(event, "getPointerCount", no_args); for (int i = 0; i < pointer_count; i++) { float x = Reflect.callMethod(event, "getX", int_arg, i); float y = Reflect.callMethod(event, "getY", int_arg, i); int id = Reflect.callMethod(event, "getPointerId", int_arg, i); /* Not entirely sure we need to report move events for non-primary * touches here but examples I've seen say that the * ACTION_[POINTER_][UP|DOWN] report all touches and they can * change between the last MOVE and the UP|DOWN event. */ if (id == pointer_id) { nativeOnTouch(id, action, x, y, primary); } else { nativeOnTouch(id, Const.ALLEGRO_EVENT_TOUCH_MOVE, x, y, primary); } } } else { nativeOnTouch(pointer_id, action, event.getX(), event.getY(), primary); } return true; } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/android/gradle_project/app/000077500000000000000000000000001473414355200206445ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/app/build.gradle000066400000000000000000000007131473414355200231240ustar00rootroot00000000000000apply plugin: 'com.android.application' android { compileSdkVersion 33 defaultConfig { applicationId "org.liballeg.${APP_ID}" minSdkVersion 15 targetSdkVersion 33 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile "org.liballeg.android:allegro:1.0@aar" } allegro5-5.2.10.1/android/gradle_project/app/src/000077500000000000000000000000001473414355200214335ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/app/src/main/000077500000000000000000000000001473414355200223575ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/app/src/main/AndroidManifest.xml000066400000000000000000000016371473414355200261570ustar00rootroot00000000000000 allegro5-5.2.10.1/android/gradle_project/app/src/main/java/000077500000000000000000000000001473414355200233005ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/app/src/main/java/org/000077500000000000000000000000001473414355200240675ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/app/src/main/java/org/liballeg/000077500000000000000000000000001473414355200256425ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/app/src/main/java/org/liballeg/app/000077500000000000000000000000001473414355200264225ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/app/src/main/java/org/liballeg/app/MainActivity.java000066400000000000000000000027001473414355200316650ustar00rootroot00000000000000package org.liballeg.app; import org.liballeg.android.AllegroActivity; import android.util.Log; public class MainActivity extends AllegroActivity { static void loadLibrary(String name) { try { // try loading the debug library first. Log.d("loadLibrary", name + "-debug"); System.loadLibrary(name + "-debug"); } catch (UnsatisfiedLinkError e) { try { // If it fails load the release library. Log.d("loadLibrary", name); System.loadLibrary(name); } catch (UnsatisfiedLinkError e2) { // We still continue as failing to load an addon may // not be a fatal error - for example if the TTF was // not built we can still run an example which does not // need that addon. Log.d("loadLibrary", name + " FAILED"); } } } static { loadLibrary("allegro"); loadLibrary("allegro_primitives"); loadLibrary("allegro_image"); loadLibrary("allegro_font"); loadLibrary("allegro_ttf"); loadLibrary("allegro_audio"); loadLibrary("allegro_acodec"); loadLibrary("allegro_color"); loadLibrary("allegro_memfile"); loadLibrary("allegro_physfs"); loadLibrary("allegro_video"); } public MainActivity() { super("libnative-lib.so"); } } allegro5-5.2.10.1/android/gradle_project/build.gradle000066400000000000000000000004131473414355200223410ustar00rootroot00000000000000buildscript { repositories { google() jcenter() } dependencies { classpath "com.android.tools.build:gradle:3.2.0" } } allprojects { repositories { google() jcenter() flatDir { dirs 'libs' } } } allegro5-5.2.10.1/android/gradle_project/gradle.properties000066400000000000000000000000431473414355200234350ustar00rootroot00000000000000#org.gradle.java.home=${JAVA_HOME} allegro5-5.2.10.1/android/gradle_project/gradle/000077500000000000000000000000001473414355200213225ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/gradle/wrapper/000077500000000000000000000000001473414355200230025ustar00rootroot00000000000000allegro5-5.2.10.1/android/gradle_project/gradle/wrapper/gradle-wrapper.properties000066400000000000000000000003101473414355200300260ustar00rootroot00000000000000distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists allegro5-5.2.10.1/android/gradle_project/gradlew000077500000000000000000000122601473414355200214400ustar00rootroot00000000000000#!/usr/bin/env sh ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn () { echo "$*" } die () { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Escape application args save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } APP_ARGS=$(save "$@") # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then cd "$(dirname "$0")" fi exec "$JAVACMD" "$@" allegro5-5.2.10.1/android/gradle_project/local.properties000066400000000000000000000000301473414355200232650ustar00rootroot00000000000000sdk.dir=${ANDROID_HOME} allegro5-5.2.10.1/android/gradle_project/settings.gradle000066400000000000000000000000351473414355200231020ustar00rootroot00000000000000include ":${GRADLE_PROJECT}" allegro5-5.2.10.1/appveyor.yml000066400000000000000000000010161473414355200160460ustar00rootroot00000000000000version: "{branch}-ci-{build}" clone_depth: 5 install: - mkdir deps - mkdir deps\include - mkdir deps\lib - nuget install AllegroDeps -Version 1.5.0 -OutputDirectory deps -ExcludeVersion - ps: move deps\AllegroDeps\build\native\include\* deps\include -force - ps: move deps\AllegroDeps\build\native\v140\win32\deps\lib\* deps\lib -force build_script: - mkdir build - cd build - cmake .. -G "Visual Studio 14 2015" -DWANT_ACODEC_DYNAMIC_LOAD=off -DFLAC_STATIC=on - cmake --build . --config RelWithDebInfo allegro5-5.2.10.1/cmake/000077500000000000000000000000001473414355200145405ustar00rootroot00000000000000allegro5-5.2.10.1/cmake/AllegroConfig.cmake.in000066400000000000000000000013711473414355200206640ustar00rootroot00000000000000# # Allegro Package Config # @PACKAGE_INIT@ set(ALLEGRO_PKG_BUGREPORT "@PROJECT_HOMEPAGE_URL@/issues") # Allegro Targets set(ALLEGRO_PKG_TARGETS "@ALLEGRO_TARGETS@") # Allegro Package Version set(ALLEGRO_PKG_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) set(ALLEGRO_PKG_VERSION_MINOR @PROJECT_VERSION_MINOR@) set(ALLEGRO_PKG_VERSION_PATCH @PROJECT_VERSION_PATCH@) set(ALLEGRO_PKG_VERSION @PROJECT_VERSION@) # Architecture, compiler and other low level flags set(ALLEGRO_PKG_LIBRARY_ARCHITECTURE "@CMAKE_LIBRARY_ARCHITECTURE@") set(ALLEGRO_PKG_COMPILER "@CMAKE_C_COMPILER_ID@") set(ALLEGRO_PKG_COMPILER_VERSION "@CMAKE_C_COMPILER_VERSION@") set(ALLEGRO_PKG_HOST_SYSTEM "@CMAKE_HOST_SYSTEM@") # Targets include("${CMAKE_CURRENT_LIST_DIR}/@PKG_TARGETS_NAME@.cmake") allegro5-5.2.10.1/cmake/AllegroFindFFMPEG.cmake000066400000000000000000000004751473414355200206230ustar00rootroot00000000000000# - Find FFMPEG # # FFMPEG_FOUND - true if FFMPEG is found # FFMPEG_CFLAGS - required compiler flags # FFMPEG_LDFLAGS - required linker flags # -lavcodec -lavformat -lswscale if(ALLEGRO_UNIX) pkg_check_modules(FFMPEG libavcodec libavformat libswscale libavutil) endif() # TODO: Windos and OSX allegro5-5.2.10.1/cmake/AllegroFindOSS.cmake000066400000000000000000000043621473414355200203220ustar00rootroot00000000000000# - Find Open Sound System # # OSS_FOUND - True if OSS headers found. # This file is Allegro-specific and requires the following variables to be # set elsewhere: # ALLEGRO_HAVE_MACHINE_SOUNDCARD_H # ALLEGRO_HAVE_LINUX_SOUNDCARD_H # ALLEGRO_HAVE_SYS_SOUNDCARD_H # ALLEGRO_HAVE_SOUNDCARD_H if(OSS_INCLUDE_DIR) # Already in cache, be silent set(OSS_FIND_QUIETLY TRUE) endif(OSS_INCLUDE_DIR) set(CMAKE_REQUIRED_DEFINITIONS) if(ALLEGRO_HAVE_SOUNDCARD_H OR ALLEGRO_HAVE_SYS_SOUNDCARD_H OR ALLEGRO_HAVE_MACHINE_SOUNDCARD_H OR ALLEGRO_LINUX_SYS_SOUNDCARD_H) if(ALLEGRO_HAVE_MACHINE_SOUNDCARD_H) set(CMAKE_REQUIRED_DEFINITIONS -DALLEGRO_HAVE_MACHINE_SOUNDCARD_H) endif(ALLEGRO_HAVE_MACHINE_SOUNDCARD_H) if(ALLEGRO_HAVE_LINUX_SOUNDCARD_H) set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -DALLEGRO_HAVE_LINUX_SOUNDCARD_H) endif(ALLEGRO_HAVE_LINUX_SOUNDCARD_H) if(ALLEGRO_HAVE_SYS_SOUNDCARD_H) set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -DALLEGRO_HAVE_SYS_SOUNDCARD_H) endif(ALLEGRO_HAVE_SYS_SOUNDCARD_H) if(ALLEGRO_HAVE_SOUNDCARD_H) set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -DALLEGRO_HAVE_SOUNDCARD_H) endif(ALLEGRO_HAVE_SOUNDCARD_H) run_c_compile_test(" #ifdef ALLEGRO_HAVE_SOUNDCARD_H #include #endif #ifdef ALLEGRO_HAVE_SYS_SOUNDCARD_H #include #endif #ifdef ALLEGRO_HAVE_LINUX_SOUNDCARD_H #include #endif #ifdef ALLEGRO_HAVE_MACHINE_SOUNDCARD_H #include #endif int main(void) { audio_buf_info abi; return 0; }" OSS_COMPILES ) set(CMAKE_REQUIRED_DEFINITIONS) endif(ALLEGRO_HAVE_SOUNDCARD_H OR ALLEGRO_HAVE_SYS_SOUNDCARD_H OR ALLEGRO_HAVE_MACHINE_SOUNDCARD_H OR ALLEGRO_LINUX_SYS_SOUNDCARD_H) # Handle the QUIETLY and REQUIRED arguments and set OSS_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(OSS DEFAULT_MSG OSS_COMPILES) mark_as_advanced(OSS_COMPILES) allegro5-5.2.10.1/cmake/AndroidApp.cmake000066400000000000000000000072401473414355200175660ustar00rootroot00000000000000function(add_android_app prog sources) set(PROJECT "${CMAKE_CURRENT_BINARY_DIR}/${prog}.project") set(PROJECT_SOURCE ${CMAKE_SOURCE_DIR}/android/gradle_project) set(native "${PROJECT}/app/src/main/jniLibs/${ANDROID_ABI}/libnative-lib.so") set(GRADLE_PROJECT app) set(ANDROID_HOME $ENV{ANDROID_HOME}) set(AAR ${PROJECT}/app/libs/allegro.aar) set(adb ${ANDROID_HOME}/platform-tools/adb) set(APP_ID ${prog}) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(SUFFIX "-debug") else() set(SUFFIX "") endif() configure_file( ${PROJECT_SOURCE}/settings.gradle ${PROJECT}/settings.gradle) configure_file( ${PROJECT_SOURCE}/local.properties ${PROJECT}/local.properties) configure_file( ${PROJECT_SOURCE}/app/src/main/AndroidManifest.xml ${PROJECT}/app/src/main/AndroidManifest.xml) configure_file( ${PROJECT_SOURCE}/app/build.gradle ${PROJECT}/app/build.gradle) set(COPY_FILES ${PROJECT_SOURCE}/gradle.properties ${PROJECT_SOURCE}/build.gradle ${PROJECT_SOURCE}/gradlew ${PROJECT_SOURCE}/gradle/wrapper/gradle-wrapper.jar ${PROJECT_SOURCE}/gradle/wrapper/gradle-wrapper.properties ${PROJECT_SOURCE}/app/src/main/java/org/liballeg/app/MainActivity.java ) get_property(JNI_LIBS GLOBAL PROPERTY JNI_LIBS) foreach(lib ${JNI_LIBS}) set(jnilib ${PROJECT}/app/src/main/jniLibs/${ANDROID_ABI}/lib${lib}${SUFFIX}.so) add_custom_command( OUTPUT ${jnilib} DEPENDS ${lib} COMMAND ${CMAKE_COMMAND} -E copy $ ${jnilib}) list(APPEND jnilibs ${jnilib}) endforeach() list(APPEND COPIED_FILES ${PROJECT}/local.properties) list(APPEND COPIED_FILES ${PROJECT}/app/src/main/AndroidManifest.xml) list(APPEND COPIED_FILES ${PROJECT}/app/build.gradle) foreach(copy ${COPY_FILES}) string(REPLACE "${PROJECT_SOURCE}/" "${PROJECT}/" target ${copy}) add_custom_command( OUTPUT ${target} DEPENDS ${copy} COMMAND ${CMAKE_COMMAND} -E copy ${copy} ${target} ) list(APPEND COPIED_FILES ${target}) endforeach() # The APK to output. We always build the examples in debug mode as # a release version would need to be signed. set(apk_path "${PROJECT}/app/build/outputs/apk/debug/app-debug.apk") # Build the application as a shared library. add_library(${prog} SHARED ${sources}) set_target_properties(${prog} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT}) target_link_libraries(${prog} ${JNI_LIBS}) # Get the path of the application's shared object. add_custom_command( OUTPUT ${native} DEPENDS ${prog} COMMAND ${CMAKE_COMMAND} -E copy $ ${native} ) add_custom_command( OUTPUT ${AAR} DEPENDS ${ALLEGRO_AAR} COMMAND ${CMAKE_COMMAND} -E copy ${ALLEGRO_AAR} ${AAR} ) # How to make the APK. add_custom_command( OUTPUT ${apk_path} DEPENDS ${native} ${jnilibs} ${COPIED_FILES} ${AAR} WORKING_DIRECTORY ${PROJECT} COMMAND ./gradlew assembleDebug ) add_custom_target(${prog}_apk ALL DEPENDS aar ${apk_path} ) # Useful targets for testing. add_custom_target(install_${prog} DEPENDS ${prog}_apk COMMAND ${adb} install -r ${apk_path} ) add_custom_target(run_${prog} DEPENDS install_${prog} COMMAND ${adb} shell 'am start -a android.intent.action.MAIN -n org.liballeg.${APP_ID}/org.liballeg.app.MainActivity' ) endfunction() allegro5-5.2.10.1/cmake/Common.cmake000066400000000000000000000367061473414355200170060ustar00rootroot00000000000000function(set_our_header_properties) foreach(file ${ARGN}) # Infer which subdirectory this header file should be installed. set(loc ${file}) string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" loc ${loc}) string(REGEX REPLACE "^include/" "" loc ${loc}) string(REGEX REPLACE "/[-A-Za-z0-9_]+[.](h|inl)$" "" loc ${loc}) string(REGEX REPLACE "^addons/[^/]+/" "" loc ${loc}) # If we have inferred correctly then it should be under allegro5. string(REGEX MATCH "^allegro5" matched ${loc}) if(matched STREQUAL "allegro5") # MACOSX_PACKAGE_LOCATION is also used in install_our_headers. set_source_files_properties(${file} PROPERTIES MACOSX_PACKAGE_LOCATION Headers/${loc} ) else() message(FATAL_ERROR "Could not infer where to install ${file}") endif() endforeach(file) endfunction(set_our_header_properties) # Normally CMake caches the "failure" result of a compile test, preventing it # from re-running. These helpers delete the cache variable on failure so that # CMake will try again next time. function(run_c_compile_test source var) check_c_source_compiles("${source}" ${var}) if (NOT ${var}) unset(${var} CACHE) endif(NOT ${var}) endfunction(run_c_compile_test) function(run_cxx_compile_test source var) check_cxx_source_compiles("${source}" ${var}) if (NOT ${var}) unset(${var} CACHE) endif(NOT ${var}) endfunction(run_cxx_compile_test) function(append_lib_type_suffix var) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_TOLOWER) if(CMAKE_BUILD_TYPE_TOLOWER STREQUAL "debug") set(${var} "${${var}}-debug" PARENT_SCOPE) endif(CMAKE_BUILD_TYPE_TOLOWER STREQUAL "debug") if(CMAKE_BUILD_TYPE_TOLOWER MATCHES "profile") set(${var} "${${var}}-profile" PARENT_SCOPE) endif(CMAKE_BUILD_TYPE_TOLOWER MATCHES "profile") endfunction(append_lib_type_suffix) function(append_lib_linkage_suffix var) if(NOT BUILD_SHARED_LIBS) set(${var} "${${var}}-static" PARENT_SCOPE) endif(NOT BUILD_SHARED_LIBS) endfunction(append_lib_linkage_suffix) # Oh my. CMake really is bad for this - but I couldn't find a better # way. function(sanitize_cmake_link_flags ...) set(return) foreach(lib ${ARGV}) # Watch out for -framework options (OS X) if(NOT lib MATCHES "-framework.*" AND NOT lib MATCHES ".*framework") # Remove absolute path. string(REGEX REPLACE "/.*/(.*)" "\\1" lib ${lib}) # Remove .a/.so/.dylib. string(REGEX REPLACE "lib(.*)\\.a" "\\1" lib ${lib}) string(REGEX REPLACE "lib(.*)\\.so" "\\1" lib ${lib}) string(REGEX REPLACE "lib(.*)\\.dylib" "\\1" lib ${lib}) # Remove -l prefix if it's there already. string(REGEX REPLACE "-l(.*)" "\\1" lib ${lib}) # Make sure we don't include our own libraries. # FIXME: Use a global list instead of a very unstable regexp. if(NOT lib MATCHES "allegro_.*" AND NOT lib STREQUAL "allegro" AND NOT lib STREQUAL "allegro_audio") set(return "${return} -l${lib}") endif() endif(NOT lib MATCHES "-framework.*" AND NOT lib MATCHES ".*framework") endforeach(lib) set(return ${return} PARENT_SCOPE) endfunction(sanitize_cmake_link_flags) function(add_our_library target framework_name sources extra_flags link_with) # BUILD_SHARED_LIBS controls whether this is a shared or static library. add_library(${target} ${sources}) target_include_directories(${target} INTERFACE $) list(APPEND ALLEGRO_TARGETS "${target}") list(REMOVE_DUPLICATES ALLEGRO_TARGETS) set(ALLEGRO_TARGETS "${ALLEGRO_TARGETS}" CACHE INTERNAL "internal") if(MSVC) # Compile with multiple processors set(extra_flags "${extra_flags} /MP") if(WANT_STATIC_RUNTIME) if(CMAKE_BUILD_TYPE STREQUAL Debug) set(extra_flags "${extra_flags} /MTd") else() set(extra_flags "${extra_flags} /MT") endif() if (NOT BUILD_SHARED_LIBS) # /Zl instructs MSVC to not mention the CRT used at all, # allowing the static libraries to be combined with any CRT version # in the final dll/exe. set(extra_flags "${extra_flags} /Zl") endif() endif() elseif(MINGW) if(WANT_STATIC_RUNTIME) # TODO: The -static is a bit of a hack for MSYS2 to force the static linking of pthreads. # There has to be a better way. set(extra_link_flags "-static-libgcc -static-libstdc++ -static -lpthread -Wl,--exclude-libs=libpthread.a -Wl,--exclude-libs=libgcc_eh.a") endif() endif() if(WIN32) set(extra_flags "${extra_flags} -DUNICODE -D_UNICODE") endif() if(NOT BUILD_SHARED_LIBS) set(static_flag "-DALLEGRO_STATICLINK") endif(NOT BUILD_SHARED_LIBS) if(NOT ANDROID) set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${extra_flags} ${static_flag} -DALLEGRO_LIB_BUILD" LINK_FLAGS "${extra_link_flags}" VERSION ${ALLEGRO_VERSION} SOVERSION ${ALLEGRO_SOVERSION} ) else(NOT ANDROID) set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${extra_flags} ${static_flag} -DALLEGRO_LIB_BUILD" ) set_property(GLOBAL APPEND PROPERTY JNI_LIBS ${target}) endif(NOT ANDROID) # Construct the output name. set(output_name ${target}) append_lib_type_suffix(output_name) append_lib_linkage_suffix(output_name) set_target_properties(${target} PROPERTIES OUTPUT_NAME ${output_name} ) # Put version numbers on DLLs but not on import libraries nor static # archives. Make MinGW not add a lib prefix to DLLs, to match MSVC. if(WIN32 AND SHARED) set_target_properties(${target} PROPERTIES PREFIX "" SUFFIX -${ALLEGRO_SOVERSION}.dll IMPORT_SUFFIX ${CMAKE_IMPORT_LIBRARY_SUFFIX} ) endif() # Suppress errors about _mangled_main_address being undefined on Mac OS X. if(MACOSX) set_target_properties(${target} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" ) endif(MACOSX) # Specify a list of libraries to be linked into the specified target. # Library dependencies are transitive by default. Any target which links # with this target will therefore pull in these dependencies automatically. target_link_libraries(${target} ${link_with}) # Set list of dependencies that the user would need to explicitly link with # if static linking. sanitize_cmake_link_flags(${link_with}) set_target_properties(${target} PROPERTIES static_link_with "${return}" ) set_our_framework_properties(${target} ${framework_name}) install_our_library(${target} ${output_name}) endfunction(add_our_library) macro(add_our_addon_library target framework_name sources extra_flags link_with) if(WANT_MONOLITH) set(MONOLITH_DEFINES "${MONOLITH_DEFINES} ${extra_flags}") else() add_our_library(${target} ${framework_name} "${sources}" "${extra_flags}" "${link_with}") if(ANDROID) record_android_load_libs(${target} "${link_with}") endif() endif() endmacro(add_our_addon_library) # Record in a custom target property 'ANDROID_LOAD_LIBS' the list of shared # objects that will need to be bundled with the APK and loaded manually if # linking with this target. function(record_android_load_libs target libs) set(load_libs) foreach(lib ${libs}) if(lib MATCHES "/lib[^/]+[.]so$" AND NOT lib MATCHES "/sysroot/") list(APPEND load_libs "${lib}") endif() endforeach() set_target_properties(${target} PROPERTIES ANDROID_LOAD_LIBS "${load_libs}") endfunction(record_android_load_libs) function(set_our_framework_properties target nm) if(WANT_FRAMEWORKS) if(WANT_EMBED) set(install_name_dir "@executable_path/../Frameworks") else() set(install_name_dir "${FRAMEWORK_INSTALL_PREFIX}") endif(WANT_EMBED) set_target_properties(${target} PROPERTIES FRAMEWORK on OUTPUT_NAME ${nm} INSTALL_NAME_DIR "${install_name_dir}" ) endif(WANT_FRAMEWORKS) endfunction(set_our_framework_properties) function(install_our_library target filename) install(TARGETS ${target} LIBRARY DESTINATION "lib${LIB_SUFFIX}" ARCHIVE DESTINATION "lib${LIB_SUFFIX}" FRAMEWORK DESTINATION "${FRAMEWORK_INSTALL_PREFIX}" RUNTIME DESTINATION "bin" # Doesn't work, see below. # PUBLIC_HEADER DESTINATION "include" ) if(MSVC AND BUILD_SHARED_LIBS) install(FILES ${CMAKE_BINARY_DIR}/lib/\${CMAKE_INSTALL_CONFIG_NAME}/${filename}.pdb DESTINATION lib CONFIGURATIONS Debug RelWithDebInfo ) endif() endfunction(install_our_library) # Unfortunately, CMake's PUBLIC_HEADER support doesn't install into nested # directories well, otherwise we could rely on install(TARGETS) to install # header files associated with the target. Instead we use the install(FILES) # to install headers. We reuse the MACOSX_PACKAGE_LOCATION property, # substituting the "Headers" prefix with "include". function(install_our_headers) if(NOT WANT_FRAMEWORKS) foreach(hdr ${ARGN}) get_source_file_property(LOC ${hdr} MACOSX_PACKAGE_LOCATION) string(REGEX REPLACE "^Headers" "include" LOC ${LOC}) install(FILES ${hdr} DESTINATION ${LOC}) endforeach() endif() endfunction(install_our_headers) function(fix_executable nm) if(IPHONE) string(REPLACE "_" "" bundle_nm ${nm}) set_target_properties(${nm} PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.liballeg.${bundle_nm}") # FIXME:We want those as project attributes, not target attributes, but I don't know how set_target_properties(${nm} PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer") # We have to add an icon to every executable on IPhone else # cmake won't create a resource copy build phase for us. # And re-creating those by hand would be a major pain. set_target_properties(${nm} PROPERTIES MACOSX_BUNDLE_ICON_FILE icon.png) set_source_files_properties("${CMAKE_SOURCE_DIR}/misc/icon.png" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources" ) endif(IPHONE) endfunction(fix_executable) # Ads a target for an executable target `nm`. # # Arguments: # # SRCS - Sources. If empty, assumes it to be ${nm}.c # LIBS - Libraries to link to. # DEFINES - Additional defines. # # Free variable: EXECUTABLE_TYPE function(add_our_executable nm) set(flags) # none set(single_args) # none set(multi_args SRCS LIBS DEFINES) cmake_parse_arguments(OPTS "${flags}" "${single_args}" "${multi_args}" ${ARGN}) if(NOT OPTS_SRCS) set(OPTS_SRCS "${nm}.c") endif() if(IPHONE) set(EXECUTABLE_TYPE MACOSX_BUNDLE) set(OPTS_SRCS ${OPTS_SRCS} "${CMAKE_SOURCE_DIR}/misc/icon.png") endif() add_executable(${nm} ${EXECUTABLE_TYPE} ${OPTS_SRCS}) target_link_libraries(${nm} ${OPTS_LIBS}) if(WANT_POPUP_EXAMPLES AND SUPPORT_NATIVE_DIALOG) list(APPEND OPTS_DEFINES ALLEGRO_POPUP_EXAMPLES) endif() if(NOT BUILD_SHARED_LIBS) list(APPEND OPTS_DEFINES ALLEGRO_STATICLINK) endif() foreach(d ${OPTS_DEFINES}) set_property(TARGET ${nm} APPEND PROPERTY COMPILE_DEFINITIONS ${d}) endforeach() set(extra_flags "") if(MSVC) # Compile with multiple processors set(extra_flags "/MP") if(WANT_STATIC_RUNTIME) if(CMAKE_BUILD_TYPE STREQUAL Debug) set(extra_flags "${extra_flags} /MTd") else() set(extra_flags "${extra_flags} /MT") endif() endif() endif() if(WIN32) set(extra_flags "${extra_flags} -DUNICODE -D_UNICODE") endif() set_target_properties(${nm} PROPERTIES COMPILE_FLAGS "${extra_flags}") if(MINGW) if(NOT CMAKE_BUILD_TYPE STREQUAL Debug) set_target_properties(${nm} PROPERTIES LINK_FLAGS "-Wl,-subsystem,windows") endif() endif() fix_executable(${nm}) endfunction() function(add_copy_commands src dest destfilesvar) set(destfiles) foreach(basename ${ARGN}) list(APPEND destfiles "${dest}/${basename}") add_custom_command( OUTPUT "${dest}/${basename}" DEPENDS "${src}/${basename}" COMMAND "${CMAKE_COMMAND}" -E copy "${src}/${basename}" "${dest}/${basename}" ) endforeach() set(${destfilesvar} "${destfiles}" PARENT_SCOPE) endfunction() # Recreate data directory for out-of-source builds. # Note: a symlink is unsafe as make clean will delete the contents # of the pointed-to directory. # # Files are only copied if they don't are inside a .svn folder so we # won't end up with read-only .svn folders in the build folder. function(copy_data_dir_to_build target src dest) if(IPHONE) return() endif(IPHONE) if(src STREQUAL dest) return() endif() file(GLOB_RECURSE files RELATIVE "${src}" "${src}/*") add_copy_commands("${src}" "${dest}" destfiles "${files}") add_custom_target(${target} DEPENDS ${destfiles}) endfunction(copy_data_dir_to_build) macro(add_monolith_sources var addon sources) foreach(s ${${sources}}) list(APPEND ${var} ${addon}/${s}) endforeach(s ${sources}) endmacro(add_monolith_sources addon sources) # This macro is called by each addon. It expects the following variables to # exist: # # ${ADDON}_SOURCES # ${ADDON}_INCLUDE_FILES # ${ADDON}_INCLUDE_DIRECTORIES # ${ADDON}_LINK_DIRECTORIES # ${ADDON}_DEFINES # ${ADDON}_LIBRARIES # # This is useful so we can build the monolith library without having any other # special code for it in the addon CMakeLists.txt files. macro(add_addon addon) add_addon2(${addon} allegro_${addon}) endmacro(add_addon) macro(add_addon2 addon addon_target) string(TOUPPER ${addon} ADDON) set(SUPPORT_${ADDON} 1 PARENT_SCOPE) set(${ADDON}_LINK_WITH ${addon_target} PARENT_SCOPE) add_monolith_sources(MONOLITH_SOURCES addons/${addon} ${ADDON}_SOURCES) add_monolith_sources(MONOLITH_SOURCES addons/${addon} ${ADDON}_INCLUDE_FILES) add_monolith_sources(MONOLITH_HEADERS addons/${addon} ${ADDON}_INCLUDE_FILES) set(MONOLITH_SOURCES ${MONOLITH_SOURCES} PARENT_SCOPE) list(APPEND MONOLITH_INCLUDE_DIRECTORIES ${${ADDON}_INCLUDE_DIRECTORIES}) list(APPEND MONOLITH_INCLUDE_DIRECTORIES addons/${addon}) list(APPEND MONOLITH_LINK_DIRECTORIES ${${ADDON}_LINK_DIRECTORIES}) list(APPEND MONOLITH_LIBRARIES ${${ADDON}_LIBRARIES}) set(MONOLITH_DEFINES "${MONOLITH_DEFINES} ${${ADDON}_DEFINES}") set(MONOLITH_INCLUDE_DIRECTORIES ${MONOLITH_INCLUDE_DIRECTORIES} PARENT_SCOPE) set(MONOLITH_LINK_DIRECTORIES ${MONOLITH_LINK_DIRECTORIES} PARENT_SCOPE) set(MONOLITH_LIBRARIES ${MONOLITH_LIBRARIES} PARENT_SCOPE) set(MONOLITH_HEADERS ${MONOLITH_HEADERS} PARENT_SCOPE) set(MONOLITH_DEFINES ${MONOLITH_DEFINES} PARENT_SCOPE) endmacro(add_addon2) #-----------------------------------------------------------------------------# # vim: set ft=cmake sts=4 sw=4 et: allegro5-5.2.10.1/cmake/FileList.cmake000066400000000000000000000201621473414355200172560ustar00rootroot00000000000000set(ALLEGRO_SRC_FILES src/allegro.c src/bitmap.c src/bitmap_draw.c src/bitmap_io.c src/bitmap_lock.c src/bitmap_pixel.c src/bitmap_type.c src/blenders.c src/clipboard.c src/config.c src/convert.c src/cpu.c src/debug.c src/display.c src/display_settings.c src/drawing.c src/dtor.c src/events.c src/evtsrc.c src/exitfunc.c src/file.c src/file_slice.c src/file_stdio.c src/fshook.c src/fshook_stdio.c src/fullscreen_mode.c src/haptic.c src/inline.c src/joynu.c src/keybdnu.c src/libc.c src/math.c src/memblit.c src/memdraw.c src/memory.c src/monitor.c src/mousenu.c src/mouse_cursor.c src/path.c src/pixels.c src/shader.c src/system.c src/threads.c src/timernu.c src/tls.c src/touch_input.c src/transformations.c src/tri_soft.c src/utf8.c src/misc/aatree.c src/misc/bstrlib.c src/misc/list.c src/misc/vector.c ) set(ALLEGRO_SRC_WIN_FILES src/win/wclipboard.c src/win/whapall.c src/win/whapdrv.c src/win/whaptic.cpp src/win/whapxi.c src/win/wjoyall.c src/win/wjoydrv.c src/win/wjoydxnu.cpp src/win/wjoyxi.c src/win/wkeyboard.c src/win/wmcursor.c src/win/wmouse.c src/win/wsystem.c src/win/wthread.c src/win/wtime.c src/win/wtouch_input.c src/win/wunicode.c src/win/wwindow.c src/win/wxthread.c ) set(ALLEGRO_SRC_D3D_FILES src/win/d3d_bmp.cpp src/win/d3d_disp.cpp src/win/d3d_display_formats.cpp src/win/d3d_render_state.cpp src/win/d3d_shader.cpp src/win/d3d_d3dx9.cpp ) set(ALLEGRO_SRC_OPENGL_FILES src/opengl/extensions.c src/opengl/ogl_bitmap.c src/opengl/ogl_display.c src/opengl/ogl_draw.c src/opengl/ogl_fbo.c src/opengl/ogl_lock.c src/opengl/ogl_lock_es.c src/opengl/ogl_render_state.c src/opengl/ogl_shader.c ) set(ALLEGRO_SRC_WGL_FILES src/win/wgl_disp.c ) set(ALLEGRO_SRC_UNIX_FILES src/unix/udrvlist.c src/unix/ufdwatch.c src/unix/ugfxdrv.c src/unix/uhapdrv.c src/unix/ujoydrv.c src/unix/ukeybd.c src/unix/umouse.c src/unix/upath.c src/unix/utime.c src/unix/uxthread.c ) set(ALLEGRO_SRC_X_FILES src/x/xclipboard.c src/x/xcursor.c src/x/xdisplay.c src/x/xdnd.c src/x/xevents.c src/x/xfullscreen.c src/x/xglx_config.c src/x/xkeyboard.c src/x/xmousenu.c src/x/xrandr.c src/x/xsystem.c src/x/xtouch.c src/x/xwindow.c src/linux/lhaptic.c src/linux/ljoynu.c ) set(ALLEGRO_SRC_MACOSX_FILES src/macosx/hidjoy.m src/macosx/hidjoy-10.4.m src/macosx/hidman.m src/macosx/keybd.m src/macosx/qzmouse.m src/macosx/system.m src/macosx/osxclipboard.m src/macosx/osxgl.m src/macosx/osx_app_delegate.m src/unix/utime.c src/unix/uxthread.c ) set(ALLEGRO_SRC_IPHONE_FILES src/iphone/allegroAppDelegate.m src/iphone/EAGLView.m src/iphone/ViewController.m src/iphone/iphone_clipboard.m src/iphone/iphone_display.m src/iphone/iphone_joystick.m src/iphone/iphone_keyboard.c src/iphone/iphone_main.m src/iphone/iphone_mouse.m src/iphone/iphone_path.m src/iphone/iphone_system.c src/iphone/iphone_touch_input.m src/unix/utime.c src/unix/uxthread.c ) set(ALLEGRO_SRC_ANDROID_FILES src/unix/ufdwatch.c src/unix/utime.c src/unix/uxthread.c src/android/android_apk_file.c src/android/android_clipboard.c src/android/android_display.c src/android/android_image.c src/android/android_input_stream.c src/android/android_joystick.c src/android/android_keyboard.c src/android/android_mouse.c src/android/android_sensors.c src/android/android_system.c src/android/android_touch.c src/android/jni_helpers.c src/linux/ljoynu.c src/android/android_apk_fs.c ) set(ALLEGRO_SRC_RASPBERRYPI_FILES src/unix/utime.c src/unix/uxthread.c src/linux/lkeybdnu.c src/linux/lmseev.c src/linux/lmsedrv.c src/linux/lhaptic.c src/linux/ljoynu.c src/x/xevents.c src/x/xkeyboard.c src/x/xmousenu.c src/x/xwindow.c src/raspberrypi/pisystem.c src/raspberrypi/pidisplay.c ) set(ALLEGRO_SRC_SDL_FILES src/sdl/sdl_system.c src/sdl/sdl_time.c src/sdl/sdl_thread.c src/sdl/sdl_display.c src/sdl/sdl_keyboard.c src/sdl/sdl_mouse.c src/sdl/sdl_touch.c src/sdl/sdl_joystick.c src/sdl/sdl_event_hack.c ) set(ALLEGRO_INCLUDE_ALLEGRO_FILES include/allegro5/allegro5.h include/allegro5/allegro.h include/allegro5/alcompat.h include/allegro5/altime.h include/allegro5/base.h include/allegro5/bitmap.h include/allegro5/bitmap_draw.h include/allegro5/bitmap_io.h include/allegro5/bitmap_lock.h include/allegro5/blender.h include/allegro5/clipboard.h include/allegro5/color.h include/allegro5/config.h include/allegro5/cpu.h include/allegro5/debug.h include/allegro5/display.h include/allegro5/drawing.h include/allegro5/error.h include/allegro5/events.h include/allegro5/file.h include/allegro5/fixed.h include/allegro5/fmaths.h include/allegro5/fshook.h include/allegro5/fullscreen_mode.h include/allegro5/haptic.h include/allegro5/joystick.h include/allegro5/keyboard.h include/allegro5/keycodes.h include/allegro5/memory.h include/allegro5/monitor.h include/allegro5/mouse.h include/allegro5/mouse_cursor.h include/allegro5/path.h include/allegro5/render_state.h include/allegro5/shader.h include/allegro5/system.h include/allegro5/threads.h include/allegro5/tls.h include/allegro5/touch_input.h include/allegro5/timer.h include/allegro5/transformations.h include/allegro5/utf8.h include/allegro5/allegro_direct3d.h include/allegro5/allegro_opengl.h ) set(ALLEGRO_INCLUDE_ALLEGRO_INLINE_FILES include/allegro5/inline/fmaths.inl ) set(ALLEGRO_INCLUDE_ALLEGRO_INTERNAL_FILES # Only files which need to be installed. include/allegro5/internal/alconfig.h ) set(ALLEGRO_INCLUDE_ALLEGRO_OPENGL_FILES include/allegro5/opengl/gl_ext.h ) set(ALLEGRO_INCLUDE_ALLEGRO_OPENGL_GLEXT_FILES include/allegro5/opengl/GLext/gl_ext_alias.h include/allegro5/opengl/GLext/gl_ext_defs.h include/allegro5/opengl/GLext/glx_ext_alias.h include/allegro5/opengl/GLext/glx_ext_defs.h include/allegro5/opengl/GLext/wgl_ext_alias.h include/allegro5/opengl/GLext/wgl_ext_defs.h include/allegro5/opengl/GLext/gl_ext_api.h include/allegro5/opengl/GLext/gl_ext_list.h include/allegro5/opengl/GLext/glx_ext_api.h include/allegro5/opengl/GLext/glx_ext_list.h include/allegro5/opengl/GLext/wgl_ext_api.h include/allegro5/opengl/GLext/wgl_ext_list.h ) set(ALLEGRO_INCLUDE_ALLEGRO_PLATFORM_FILES # Only files which need to be installed. include/allegro5/platform/alandroid.h include/allegro5/platform/alandroidcfg.h include/allegro5/platform/albcc32.h include/allegro5/platform/aliphone.h include/allegro5/platform/aliphonecfg.h include/allegro5/platform/almngw32.h include/allegro5/platform/almsvc.h include/allegro5/platform/alosx.h include/allegro5/platform/alosxcfg.h include/allegro5/platform/alraspberrypi.h include/allegro5/platform/alraspberrypicfg.h include/allegro5/platform/alucfg.h include/allegro5/platform/alunix.h include/allegro5/platform/alwatcom.h include/allegro5/platform/alwin.h include/allegro5/platform/astdbool.h include/allegro5/platform/astdint.h include/allegro5/platform/allegro_sdl_config.h ) set(ALLEGRO_INCLUDE_ALLEGRO_WINDOWS_FILES include/allegro5/allegro_windows.h ) set(ALLEGRO_INCLUDE_ALLEGRO_MACOSX_FILES include/allegro5/allegro_osx.h ) set(ALLEGRO_INCLUDE_ALLEGRO_IPHONE_FILES include/allegro5/allegro_iphone.h ) set(ALLEGRO_INCLUDE_ALLEGRO_ANDROID_FILES include/allegro5/allegro_android.h ) set(ALLEGRO_INCLUDE_ALLEGRO_PLATFORM_FILES_GENERATED include/allegro5/platform/alplatf.h ) set(ALLEGRO_INCLUDE_ALLEGRO_X_FILES include/allegro5/allegro_x.h ) allegro5-5.2.10.1/cmake/FindCg.cmake000066400000000000000000000104241473414355200166750ustar00rootroot00000000000000# NVIDIA Texture Tools 2.0 is licensed under the MIT license. # Copyright (c) 2007 NVIDIA Corporation # # Try to find NVIDIA's Cg compiler, runtime libraries, and include path. # Once done this will define # # CG_FOUND =system has NVIDIA Cg and it can be used. # CG_INCLUDE_PATH = directory where cg.h resides # CG_LIBRARY = full path to libCg.so (Cg.DLL on win32) # CG_GL_LIBRARY = full path to libCgGL.so (CgGL.dll on win32) # CG_D3D9_LIBRARY = full path to cgD3D9.dll # CG_COMPILER = full path to cgc (cgc.exe on win32) # # On OSX default to using the framework version of Cg. IF (APPLE) INCLUDE(${CMAKE_ROOT}/Modules/CMakeFindFrameworks.cmake) SET(CG_FRAMEWORK_INCLUDES) CMAKE_FIND_FRAMEWORKS(Cg) IF (Cg_FRAMEWORKS) FOREACH(dir ${Cg_FRAMEWORKS}) SET(CG_FRAMEWORK_INCLUDES ${CG_FRAMEWORK_INCLUDES} ${dir}/Headers ${dir}/PrivateHeaders) ENDFOREACH(dir) # Find the include dir FIND_PATH(CG_INCLUDE_PATH cg.h ${CG_FRAMEWORK_INCLUDES} ) # Since we are using Cg framework, we must link to it. # Note, we use weak linking, so that it works even when Cg is not available. SET(CG_LIBRARY "-weak_framework Cg" CACHE STRING "Cg library") SET(CG_GL_LIBRARY "-weak_framework Cg" CACHE STRING "Cg GL library") SET(CG_D3D9_LIBRARY "-weak_framework Cg" CACHE STRING "Cg D3D9 library") ENDIF (Cg_FRAMEWORKS) FIND_PROGRAM(CG_COMPILER cgc /usr/bin /usr/local/bin DOC "The Cg compiler" ) ELSE (APPLE) IF (WIN32) FIND_PROGRAM( CG_COMPILER cgc $ENV{CG_BIN_PATH} $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/bin $ENV{PROGRAMFILES}/Cg ${PROJECT_SOURCE_DIR}/../Cg DOC "The Cg Compiler" ) IF (CG_COMPILER) GET_FILENAME_COMPONENT(CG_COMPILER_DIR ${CG_COMPILER} PATH) GET_FILENAME_COMPONENT(CG_COMPILER_SUPER_DIR ${CG_COMPILER_DIR} PATH) ELSE (CG_COMPILER) SET (CG_COMPILER_DIR .) SET (CG_COMPILER_SUPER_DIR ..) ENDIF (CG_COMPILER) FIND_PATH( CG_INCLUDE_PATH Cg/cg.h $ENV{CG_INC_PATH} $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/include $ENV{PROGRAMFILES}/Cg ${PROJECT_SOURCE_DIR}/../Cg ${CG_COMPILER_SUPER_DIR}/include ${CG_COMPILER_DIR} DOC "The directory where Cg/cg.h resides" ) FIND_LIBRARY( CG_LIBRARY NAMES Cg PATHS $ENV{CG_LIB_PATH} $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/lib $ENV{PROGRAMFILES}/Cg ${PROJECT_SOURCE_DIR}/../Cg ${CG_COMPILER_SUPER_DIR}/lib ${CG_COMPILER_DIR} DOC "The Cg runtime library" ) FIND_LIBRARY( CG_GL_LIBRARY NAMES CgGL PATHS $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/lib $ENV{PROGRAMFILES}/Cg ${PROJECT_SOURCE_DIR}/../Cg ${CG_COMPILER_SUPER_DIR}/lib ${CG_COMPILER_DIR} DOC "The Cg GL runtime library" ) FIND_LIBRARY( CG_D3D9_LIBRARY NAMES cgD3D9 PATHS $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/lib $ENV{PROGRAMFILES}/Cg ${PROJECT_SOURCE_DIR}/../Cg ${CG_COMPILER_SUPER_DIR}/lib ${CG_COMPILER_DIR} DOC "The Cg D3D9 runtime library" ) ELSE (WIN32) FIND_PROGRAM( CG_COMPILER cgc /usr/bin /usr/local/bin DOC "The Cg Compiler" ) GET_FILENAME_COMPONENT(CG_COMPILER_DIR "${CG_COMPILER}" PATH) GET_FILENAME_COMPONENT(CG_COMPILER_SUPER_DIR "${CG_COMPILER_DIR}" PATH) FIND_PATH( CG_INCLUDE_PATH Cg/cg.h /usr/include /usr/local/include ${CG_COMPILER_SUPER_DIR}/include DOC "The directory where Cg/cg.h resides" ) FIND_LIBRARY( CG_LIBRARY Cg PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib ${CG_COMPILER_SUPER_DIR}/lib64 ${CG_COMPILER_SUPER_DIR}/lib DOC "The Cg runtime library" ) SET(CG_LIBRARY ${CG_LIBRARY} -lpthread) FIND_LIBRARY( CG_GL_LIBRARY CgGL PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib ${CG_COMPILER_SUPER_DIR}/lib64 ${CG_COMPILER_SUPER_DIR}/lib DOC "The Cg runtime library" ) ENDIF (WIN32) ENDIF (APPLE) IF (CG_INCLUDE_PATH) SET( CG_FOUND 1 CACHE STRING "Set to 1 if CG is found, 0 otherwise") ELSE (CG_INCLUDE_PATH) SET( CG_FOUND 0 CACHE STRING "Set to 1 if CG is found, 0 otherwise") ENDIF (CG_INCLUDE_PATH) MARK_AS_ADVANCED( CG_FOUND ) allegro5-5.2.10.1/cmake/FindDUMB.cmake000066400000000000000000000016451473414355200171000ustar00rootroot00000000000000# - Find DUMB # Find the native DUMB includes and libraries # # DUMB_INCLUDE_DIR - where to find DUMB headers. # DUMB_LIBRARIES - List of libraries when using libDUMB. # DUMB_FOUND - True if libDUMB found. if(DUMB_INCLUDE_DIR) # Already in cache, be silent set(DUMB_FIND_QUIETLY TRUE) endif(DUMB_INCLUDE_DIR) find_path(DUMB_INCLUDE_DIR dumb.h) find_library(DUMB_LIBRARY NAMES dumb libdumb dumb_static libdumb_static) # Handle the QUIETLY and REQUIRED arguments and set DUMB_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(DUMB DEFAULT_MSG DUMB_INCLUDE_DIR DUMB_LIBRARY) if(DUMB_FOUND) set(DUMB_LIBRARIES ${DUMB_LIBRARY}) if(NOT MSVC) set(DUMB_LIBRARIES ${DUMB_LIBRARIES};m) endif() else(DUMB_FOUND) set(DUMB_LIBRARIES) endif(DUMB_FOUND) mark_as_advanced(DUMB_INCLUDE_DIR DUMB_LIBRARY) allegro5-5.2.10.1/cmake/FindDXGuid.cmake000066400000000000000000000012511473414355200174660ustar00rootroot00000000000000# - Find dxguid # Find the dxguid libraries # # DXGUID_LIBRARIES - List of libraries # DXGUID_FOUND - True if dxguid found. find_library(DXGUID_LIBRARY NAMES dxguid HINTS "$ENV{DXSDK_DIR}/Lib/$ENV{PROCESSOR_ARCHITECTURE}" ) # Handle the QUIETLY and REQUIRED arguments and set DXGUID_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(DXGUID DEFAULT_MSG DXGUID_LIBRARY) if(DXGUID_FOUND) set(DXGUID_LIBRARIES ${DXGUID_LIBRARY}) else(DXGUID_FOUND) set(DXGUID_LIBRARIES) endif(DXGUID_FOUND) mark_as_advanced(DXGUID_INCLUDE_DIR DXGUID_LIBRARY) allegro5-5.2.10.1/cmake/FindDirectX.cmake000066400000000000000000000112201473414355200177010ustar00rootroot00000000000000# Finds various DirectX components: # # DINPUT # D3D9 # D3DX9 # DSOUND # XINPUT # # For each component, this will fill out the following variables # # ${COMPONENT}_INCLUDE_DIR - Where to find the component header. # ${COMPONENT}_LIBRARIES - List of libraries when using the component. # ${COMPONENT}_FOUND - True if the component is found. macro(check_winsdk_root_dir key) get_filename_component(CANDIDATE ${key} ABSOLUTE) if (EXISTS ${CANDIDATE}) set(WINSDK_ROOT_DIR ${CANDIDATE}) endif() endmacro() check_winsdk_root_dir("[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Microsoft SDKs\\\\Windows\\\\v7.0;InstallationFolder]") check_winsdk_root_dir("[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Microsoft SDKs\\\\Windows\\\\v7.0A;InstallationFolder]") check_winsdk_root_dir("[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Microsoft SDKs\\\\Windows\\\\v7.1;InstallationFolder]") check_winsdk_root_dir("[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Microsoft SDKs\\\\Windows\\\\v7.1A;InstallationFolder]") check_winsdk_root_dir("[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows Kits\\\\Installed Roots;KitsRoot]") check_winsdk_root_dir("[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows Kits\\\\Installed Roots;KitsRoot81]") # The Win10 SDK doesn't have many DX libraries (such as D3DX9), but it has some. # Find the Win10 SDK path. # https://github.com/microsoft/DirectXShaderCompiler/blob/main/cmake/modules/FindD3D12.cmake if ("$ENV{WIN10_SDK_PATH}$ENV{WIN10_SDK_VERSION}" STREQUAL "" ) get_filename_component(WIN10_SDK_PATH "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" ABSOLUTE CACHE) set (WIN10_SDK_VERSION ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}) elseif(TRUE) set (WIN10_SDK_PATH $ENV{WIN10_SDK_PATH}) set (WIN10_SDK_VERSION $ENV{WIN10_SDK_VERSION}) endif ("$ENV{WIN10_SDK_PATH}$ENV{WIN10_SDK_VERSION}" STREQUAL "" ) # WIN10_SDK_PATH will be something like C:\Program Files (x86)\Windows Kits\10 # WIN10_SDK_VERSION will be something like 10.0.14393 or 10.0.14393.0; we need the # one that matches the directory name. if (IS_DIRECTORY "${WIN10_SDK_PATH}/Include/${WIN10_SDK_VERSION}.0") set(WIN10_SDK_VERSION "${WIN10_SDK_VERSION}.0") endif (IS_DIRECTORY "${WIN10_SDK_PATH}/Include/${WIN10_SDK_VERSION}.0") if(CMAKE_CL_64 OR CMAKE_SIZEOF_VOID_P EQUAL 8) set(MINGW_W64_HINT "x86_64-w64-mingw32") set(PROCESSOR_SUFFIX "x64") else() set(MINGW_W64_HINT "i686-w64-mingw32") set(PROCESSOR_SUFFIX "x86") endif() macro(find_component name header library) if(${name}_INCLUDE_DIR) # Already in cache, be silent set(${name}_FIND_QUIETLY TRUE) endif(${name}_INCLUDE_DIR) if(MSVC) find_path(${name}_INCLUDE_DIR ${header} PATH_SUFFIXES Include Include/um Include/shared um shared PATHS "$ENV{DXSDK_DIR}" ${WINSDK_ROOT_DIR} ${WIN10_SDK_PATH}/Include/${WIN10_SDK_VERSION} ) find_library(${name}_LIBRARY NAMES lib${library} ${library} PATH_SUFFIXES Lib Lib/${PROCESSOR_SUFFIX} Lib/winv6.3/um/${PROCESSOR_SUFFIX} Lib/Win8/um/${PROCESSOR_SUFFIX} um/${PROCESSOR_SUFFIX} PATHS "$ENV{DXSDK_DIR}" ${WINSDK_ROOT_DIR} ${WIN10_SDK_PATH}/Lib/${WIN10_SDK_VERSION} ) else() find_path(${name}_INCLUDE_DIR ${header} PATH_SUFFIXES Include ${MINGW_W64_HINT}/include PATHS "$ENV{DXSDK_DIR}" ) find_library(${name}_LIBRARY NAMES lib${library} ${library} PATH_SUFFIXES ${MINGW_W64_HINT}/lib Lib Lib/${PROCESSOR_SUFFIX} PATHS "$ENV{DXSDK_DIR}" ) endif() # Handle the QUIETLY and REQUIRED arguments and set ${name}_FOUND to TRUE if # all listed variables are TRUE. set(FPHSA_NAME_MISMATCHED TRUE) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(${name} DEFAULT_MSG ${name}_INCLUDE_DIR ${name}_LIBRARY) if(${name}_FOUND) set(${name}_LIBRARIES ${${name}_LIBRARY}) else() set(${name}_LIBRARIES) endif() mark_as_advanced(${name}_INCLUDE_DIR ${name}_LIBRARY) endmacro() find_component(DINPUT dinput.h dinput8) find_component(D3D9 d3d9.h d3d9) find_component(D3DX9 d3dx9.h d3dx9) find_component(DSOUND dsound.h dsound) find_component(XINPUT xinput.h xinput) allegro5-5.2.10.1/cmake/FindENet.cmake000066400000000000000000000015451473414355200172030ustar00rootroot00000000000000# - Find ENet # Find the native ENet includes and libraries # # ENET_INCLUDE_DIR - where to find ENet headers. # ENET_LIBRARIES - List of libraries when using libenet. # ENET_FOUND - True if libenet found. if(ENET_INCLUDE_DIR) # Already in cache, be silent set(ENET_FIND_QUIETLY TRUE) endif(ENET_INCLUDE_DIR) find_path(ENET_INCLUDE_DIR enet/enet.h) find_library(ENET_LIBRARY NAMES enet enet_static libenet libenet_static) # Handle the QUIETLY and REQUIRED arguments and set ENET_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(ENET DEFAULT_MSG ENET_INCLUDE_DIR ENET_LIBRARY) if(ENET_FOUND) set(ENET_LIBRARIES ${ENET_LIBRARY}) else(ENET_FOUND) set(ENET_LIBRARIES) endif(ENET_FOUND) mark_as_advanced(ENET_INCLUDE_DIR ENET_LIBRARY) allegro5-5.2.10.1/cmake/FindFLAC.cmake000066400000000000000000000022621473414355200170520ustar00rootroot00000000000000# - Find FLAC # Find the native FLAC includes and libraries # # FLAC_INCLUDE_DIR - where to find FLAC headers. # FLAC_LIBRARIES - List of libraries when using libFLAC. # FLAC_FOUND - True if libFLAC found. if(FLAC_INCLUDE_DIR) # Already in cache, be silent set(FLAC_FIND_QUIETLY TRUE) endif(FLAC_INCLUDE_DIR) find_path(FLAC_INCLUDE_DIR FLAC/stream_decoder.h) # MSVC built libraries can name them *_static, which is good as it # distinguishes import libraries from static libraries with the same extension. find_library(FLAC_LIBRARY NAMES FLAC libFLAC libFLAC_dynamic libFLAC_static) find_library(OGG_LIBRARY NAMES ogg ogg_static libogg libogg_static) # Handle the QUIETLY and REQUIRED arguments and set FLAC_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(FLAC DEFAULT_MSG FLAC_INCLUDE_DIR OGG_LIBRARY FLAC_LIBRARY) if(FLAC_FOUND) set(FLAC_LIBRARIES ${FLAC_LIBRARY} ${OGG_LIBRARY}) if(WIN32) set(FLAC_LIBRARIES ${FLAC_LIBRARIES} wsock32) endif(WIN32) else(FLAC_FOUND) set(FLAC_LIBRARIES) endif(FLAC_FOUND) mark_as_advanced(FLAC_INCLUDE_DIR FLAC_LIBRARY) allegro5-5.2.10.1/cmake/FindFreeImage.cmake000066400000000000000000000030461473414355200201720ustar00rootroot00000000000000# # Try to find the FreeImage library and include path. # Once done this will define # # FREEIMAGE_FOUND # FREEIMAGE_INCLUDE_PATH # FREEIMAGE_LIBRARY # IF (WIN32) FIND_PATH( FREEIMAGE_INCLUDE_PATH FreeImage.h $ENV{FI_HOME}/include ${FREEIMAGE_ROOT_DIR}/include ${FREEIMAGE_ROOT_DIR} DOC "The directory where FreeImage.h resides") FIND_LIBRARY( FREEIMAGE_LIBRARY NAMES FreeImage freeimage PATHS $ENV{FI_HOME}/lib/$ENV{PROCESSOR_ARCHITECTURE} ${FREEIMAGE_ROOT_DIR}/lib ${FREEIMAGE_ROOT_DIR} DOC "The FreeImage library") ELSE (WIN32) FIND_PATH( FREEIMAGE_INCLUDE_PATH FreeImage.h /usr/include /usr/local/include /sw/include /opt/local/include DOC "The directory where FreeImage.h resides") FIND_LIBRARY( FREEIMAGE_LIBRARY NAMES FreeImage freeimage PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib /sw/lib /opt/local/lib DOC "The FreeImage library") ENDIF (WIN32) SET(FREEIMAGE_LIBRARIES ${FREEIMAGE_LIBRARY}) IF (FREEIMAGE_INCLUDE_PATH AND FREEIMAGE_LIBRARY) SET( FREEIMAGE_FOUND TRUE CACHE INTERNAL "Set to TRUE if FreeImage is found, FALSE otherwise") ELSE (FREEIMAGE_INCLUDE_PATH AND FREEIMAGE_LIBRARY) SET( FREEIMAGE_FOUND FALSE CACHE INTERNAL "Set to TRUE if FreeImage is found, FALSE otherwise") ENDIF (FREEIMAGE_INCLUDE_PATH AND FREEIMAGE_LIBRARY) MARK_AS_ADVANCED( FREEIMAGE_LIBRARY FREEIMAGE_LIBRARIES FREEIMAGE_INCLUDE_PATH) allegro5-5.2.10.1/cmake/FindGDIPLUS.cmake000066400000000000000000000043371473414355200174610ustar00rootroot00000000000000# - Find GDI+ # Find the GDI+ includes and libraries # # GDIPLUS_INCLUDE_DIR - where to find gdiplus.h # GDIPLUS_LIBRARIES - List of libraries when using GDI+. # GDIPLUS_FOUND - True if GDI+ found. if(GDIPLUS_INCLUDE_DIR) # Already in cache, be silent set(GDIPLUS_FIND_QUIETLY TRUE) endif(GDIPLUS_INCLUDE_DIR) macro(check_winsdk_root_dir key) get_filename_component(CANDIDATE ${key} ABSOLUTE) if (EXISTS ${CANDIDATE}) set(WINSDK_ROOT_DIR ${CANDIDATE}) endif() endmacro() check_winsdk_root_dir("[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Microsoft SDKs\\\\Windows\\\\v7.0;InstallationFolder]") check_winsdk_root_dir("[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Microsoft SDKs\\\\Windows\\\\v7.0A;InstallationFolder]") check_winsdk_root_dir("[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Microsoft SDKs\\\\Windows\\\\v7.1;InstallationFolder]") check_winsdk_root_dir("[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Microsoft SDKs\\\\Windows\\\\v7.1A;InstallationFolder]") check_winsdk_root_dir("[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows Kits\\\\Installed Roots;KitsRoot]") check_winsdk_root_dir("[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows Kits\\\\Installed Roots;KitsRoot81]") find_path(GDIPLUS_INCLUDE_DIR NAMES GdiPlus.h gdiplus.h PATH_SUFFIXES Include Include/um Include/shared PATHS "${WINSDK_ROOT_DIR}" ) if(EXISTS ${GDIPLUS_INCLUDE_DIR}/GdiPlus.h) set(GDIPLUS_LOWERCASE 0 CACHE INTERNAL "Is GdiPlus.h spelt with lowercase?") else() set(GDIPLUS_LOWERCASE 1 CACHE INTERNAL "Is GdiPlus.h spelt with lowercase?") endif() if (MINGW) find_library(GDIPLUS_LIBRARY NAMES libgdiplus gdiplus) else(MINGW) set(GDIPLUS_LIBRARY gdiplus) endif(MINGW) # Handle the QUIETLY and REQUIRED arguments and set GDIPLUS_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(GDIPLUS DEFAULT_MSG GDIPLUS_INCLUDE_DIR GDIPLUS_LIBRARY) if(GDIPLUS_FOUND) set(GDIPLUS_LIBRARIES ${GDIPLUS_LIBRARY}) else(GDIPLUS_FOUND) set(GDIPLUS_LIBRARIES) endif(GDIPLUS_FOUND) mark_as_advanced(GDIPLUS_INCLUDE_DIR GDIPLUS_LIBRARY GDIPLUS_LOWERCASE) allegro5-5.2.10.1/cmake/FindHarfBuzz.cmake000066400000000000000000000037511473414355200201040ustar00rootroot00000000000000# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #.rst: # FindHarfBuzz # ------------ # # Find the HarfBuzz text shaping engine includes and library. # # Imported Targets # ^^^^^^^^^^^^^^^^ # # This module defines the following :prop_tgt:`IMPORTED` target: # # ``HarfBuzz::HarfBuzz`` # The Harfbuzz ``harfbuzz`` library, if found # # Result Variables # ^^^^^^^^^^^^^^^^ # # This module will set the following variables in your project: # # ``HARFBUZZ_FOUND`` # true if the HarfBuzz headers and libraries were found # ``HARFBUZZ_INCLUDE_DIRS`` # directories containing the Harfbuzz headers. # ``HARFBUZZ_LIBRARIES`` # the library to link against # ``HARFBUZZ_VERSION_STRING`` # the version of harfbuzz found # Created by Ebrahim Byagowi. set(HARFBUZZ_FIND_ARGS HINTS ENV HARFBUZZ_DIR ) find_path( HARFBUZZ_INCLUDE_DIRS hb.h ${HARFBUZZ_FIND_ARGS} PATH_SUFFIXES src harfbuzz ) if(NOT HARFBUZZ_LIBRARY) find_library(HARFBUZZ_LIBRARY NAMES harfbuzz libharfbuzz ${HARFBUZZ_FIND_ARGS} PATH_SUFFIXES lib ) else() # on Windows, ensure paths are in canonical format (forward slahes): file(TO_CMAKE_PATH "${HARFBUZZ_LIBRARY}" HARFBUZZ_LIBRARY) endif() unset(HARFBUZZ_FIND_ARGS) # set the user variables set(HARFBUZZ_LIBRARIES "${HARFBUZZ_LIBRARY}") include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args( HarfBuzz REQUIRED_VARS HARFBUZZ_LIBRARY HARFBUZZ_INCLUDE_DIRS VERSION_VAR HARFBUZZ_VERSION_STRING ) if(HARFBUZZ_FOUND) if(NOT TARGET HarfBuzz::HarfBuzz) add_library(HarfBuzz::HarfBuzz UNKNOWN IMPORTED) set_target_properties(HarfBuzz::HarfBuzz PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${HARFBUZZ_INCLUDE_DIRS}") set_target_properties(HarfBuzz::HarfBuzz PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_LOCATION "${HARFBUZZ_LIBRARY}") endif() endif() allegro5-5.2.10.1/cmake/FindMiniMP3.cmake000066400000000000000000000010211473414355200175510ustar00rootroot00000000000000# - Try to find MiniMP3 (https://github.com/lieff/minimp3) # Once done, this will define # # MINIMP3_FOUND - system has MiniMP3 # MINIMP3_INCLUDE_DIRS - the MiniMP3 include directories # Look for the header file. find_path(MINIMP3_INCLUDE_DIRS NAMES minimp3.h minimp3_ex.h ) mark_as_advanced(MINIMP3_INCLUDE_DIRS) include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(MiniMP3 REQUIRED_VARS MINIMP3_INCLUDE_DIRS FOUND_VAR MINIMP3_FOUND) allegro5-5.2.10.1/cmake/FindOgg.cmake000066400000000000000000000015611473414355200170620ustar00rootroot00000000000000# - Find ogg # Find the native ogg includes and libraries # # OGG_INCLUDE_DIR - where to find ogg.h, etc. # OGG_LIBRARIES - List of libraries when using ogg. # OGG_FOUND - True if ogg found. if(OGG_INCLUDE_DIR) # Already in cache, be silent set(OGG_FIND_QUIETLY TRUE) endif(OGG_INCLUDE_DIR) find_path(OGG_INCLUDE_DIR ogg/ogg.h) # MSVC built ogg may be named ogg_static. # The provided project files name the library with the lib prefix. find_library(OGG_LIBRARY NAMES ogg ogg_static libogg libogg_static) # Handle the QUIETLY and REQUIRED arguments and set OGG_FOUND # to TRUE if all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(OGG DEFAULT_MSG OGG_INCLUDE_DIR OGG_LIBRARY) set(OGG_LIBRARIES ${OGG_LIBRARY}) mark_as_advanced(OGG_INCLUDE_DIR) mark_as_advanced(OGG_LIBRARY) allegro5-5.2.10.1/cmake/FindOpenGLES1.cmake000066400000000000000000000015651473414355200200070ustar00rootroot00000000000000# - Find OpenGLES # Find the native OpenGLES includes and libraries # # OPENGLES1_INCLUDE_DIR - where to find GLES/gl.h, etc. # OPENGLES1_LIBRARIES - List of libraries when using OpenGLES. # OPENGLES1_FOUND - True if OpenGLES found. if(OPENGLES1_INCLUDE_DIR) # Already in cache, be silent set(OPENGLES1_FIND_QUIETLY TRUE) endif(OPENGLES1_INCLUDE_DIR) find_path(OPENGLES1_INCLUDE_DIR GLES/gl.h) find_library(OPENGLES1_gl_LIBRARY NAMES GLESv1_CM) # Handle the QUIETLY and REQUIRED arguments and set OPENGLES1_FOUND # to TRUE if all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(OPENGLES1 DEFAULT_MSG OPENGLES1_INCLUDE_DIR OPENGLES1_gl_LIBRARY) set(OPENGLES1_LIBRARIES ${OPENGLES1_gl_LIBRARY}) mark_as_advanced(OPENGLES1_INCLUDE_DIR) mark_as_advanced(OPENGLES1_gl_LIBRARY) allegro5-5.2.10.1/cmake/FindOpenGLES2.cmake000066400000000000000000000025271473414355200200070ustar00rootroot00000000000000# - Find OpenGLES2 # Find the native OpenGLES2 includes and libraries # # OPENGLES2_INCLUDE_DIR - where to find GLES2/gl.h, etc. # OPENGLES2_LIBRARIES - List of libraries when using OpenGLES. # OPENGLES2_FOUND - True if OpenGLES found. if(OPENGLES2_INCLUDE_DIR) # Already in cache, be silent set(OPENGLES2_FIND_QUIETLY TRUE) endif(OPENGLES2_INCLUDE_DIR) find_path(OPENGLES2_INCLUDE_DIR GLES2/gl2.h) find_library(OPENGLES2_gl_LIBRARY NAMES GLESv2) find_library(OPENGLES2_egl_LIBRARY NAMES EGL) # Handle the QUIETLY and REQUIRED arguments and set OPENGLES2_FOUND # to TRUE if all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(OPENGLES2 DEFAULT_MSG OPENGLES2_INCLUDE_DIR OPENGLES2_gl_LIBRARY OPENGLES2_egl_LIBRARY) set(OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY} ${OPENGLES2_egl_LIBRARY}) if(ALLEGRO_RASPBERRYPI) if(EXISTS "/opt/vc/lib/libbrcmGLESv2.so") set(OPENGLES2_LIBRARIES "/opt/vc/lib/libbrcmGLESv2.so;/opt/vc/lib/libbrcmEGL.so;/opt/vc/lib/libbcm_host.so") else() set(OPENGLES2_LIBRARIES "/opt/vc/lib/libGLESv2.so;/opt/vc/lib/libEGL.so;/opt/vc/lib/libbcm_host.so") endif() endif(ALLEGRO_RASPBERRYPI) mark_as_advanced(OPENGLES2_INCLUDE_DIR) mark_as_advanced(OPENGLES2_gl_LIBRARY) mark_as_advanced(OPENGLES2_egl_LIBRARY) allegro5-5.2.10.1/cmake/FindOpenGLES3.cmake000066400000000000000000000020361473414355200200030ustar00rootroot00000000000000# - Find OpenGLES3 # Find the native OpenGLES3 includes and libraries # (based on FindOpenGLES2.cmake) # # OPENGLES3_INCLUDE_DIR - where to find GLES3/gl3.h, etc. # OPENGLES3_LIBRARIES - List of libraries when using OpenGLES. # OPENGLES3_FOUND - True if OpenGLES found. if(OPENGLES3_INCLUDE_DIR) # Already in cache, be silent set(OPENGLES3_FIND_QUIETLY TRUE) endif(OPENGLES3_INCLUDE_DIR) find_path(OPENGLES3_INCLUDE_DIR GLES3/gl3.h) find_library(OPENGLES3_gl_LIBRARY NAMES GLESv3) find_library(OPENGLES3_egl_LIBRARY NAMES EGL) # Handle the QUIETLY and REQUIRED arguments and set OPENGLES3_FOUND # to TRUE if all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(OPENGLES3 DEFAULT_MSG OPENGLES3_INCLUDE_DIR OPENGLES3_gl_LIBRARY OPENGLES3_egl_LIBRARY) set(OPENGLES3_LIBRARIES ${OPENGLES3_gl_LIBRARY} ${OPENGLES3_egl_LIBRARY}) mark_as_advanced(OPENGLES3_INCLUDE_DIR) mark_as_advanced(OPENGLES3_gl_LIBRARY) mark_as_advanced(OPENGLES3_egl_LIBRARY) allegro5-5.2.10.1/cmake/FindOpenMPT.cmake000066400000000000000000000016421473414355200176300ustar00rootroot00000000000000# - Find OPENMPT # Find the native OpenMPT includes and libraries # # OPENMPT_INCLUDE_DIR - where to find OpenMPT headers. # OPENMPT_LIBRARIES - List of libraries when using OpenMPT. # OPENMPT_FOUND - True if OpenMPT found. if(OPENMPT_INCLUDE_DIR) # Already in cache, be silent set(OPENMPT_FIND_QUIETLY TRUE) endif(OPENMPT_INCLUDE_DIR) find_path(OPENMPT_INCLUDE_DIR libopenmpt/libopenmpt.h) find_library(OPENMPT_LIBRARY NAMES openmpt) # Handle the QUIETLY and REQUIRED arguments and set OPENMPT_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(OPENMPT DEFAULT_MSG OPENMPT_INCLUDE_DIR OGG_LIBRARY OPENMPT_LIBRARY) if(OPENMPT_FOUND) set(OPENMPT_LIBRARIES ${OPENMPT_LIBRARY}) else(OPENMPT_FOUND) set(OPENMPT_LIBRARIES) endif(OPENMPT_FOUND) mark_as_advanced(OPENMPT_INCLUDE_DIR OPENMPT_LIBRARY) allegro5-5.2.10.1/cmake/FindOpenSL.cmake000066400000000000000000000016021473414355200175020ustar00rootroot00000000000000# - Find OpenSL (actually OpenSLES) # Find the OpenSLES includes and libraries # # OPENSL_INCLUDE_DIR - where to find dsound.h # OPENSL_LIBRARIES - List of libraries when using dsound. # OPENSL_FOUND - True if dsound found. if(OPENSL_INCLUDE_DIR) # Already in cache, be silent set(OPENSL_FIND_QUIETLY TRUE) endif(OPENSL_INCLUDE_DIR) find_path(OPENSL_INCLUDE_DIR SLES/OpenSLES.h) find_library(OPENSL_LIBRARY NAMES OpenSLES) # Handle the QUIETLY and REQUIRED arguments and set OPENSL_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(OPENSL DEFAULT_MSG OPENSL_INCLUDE_DIR OPENSL_LIBRARY) if(OPENSL_FOUND) set(OPENSL_LIBRARIES ${OPENSL_LIBRARY}) else(OPENSL_FOUND) set(OPENSL_LIBRARIES) endif(OPENSL_FOUND) mark_as_advanced(OPENSL_INCLUDE_DIR OPENSL_LIBRARY) allegro5-5.2.10.1/cmake/FindOpus.cmake000066400000000000000000000024661473414355200173010ustar00rootroot00000000000000# - Find opus # Find the native opus includes and libraries # # OPUS_INCLUDE_DIR - where to find opus.h, etc. # OPUS_LIBRARIES - List of libraries when using opus(file). # OPUS_FOUND - True if opus found. if(OPUS_INCLUDE_DIR) # Already in cache, be silent set(OPUS_FIND_QUIETLY TRUE) endif(OPUS_INCLUDE_DIR) find_package(Ogg) if(OGG_FOUND) find_path(OPUS_INCLUDE_DIR opusfile.h PATH_SUFFIXES opus) # MSVC built opus may be named opus_static # The provided project files name the library with the lib prefix. find_library(OPUS_LIBRARY NAMES opus opus_static libopus libopus_static) find_library(OPUSFILE_LIBRARY NAMES opusfile opusfile_static libopusfile libopusfile_static) # Handle the QUIETLY and REQUIRED arguments and set OPUS_FOUND # to TRUE if all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(OPUS DEFAULT_MSG OPUS_INCLUDE_DIR OPUS_LIBRARY OPUSFILE_LIBRARY) endif(OGG_FOUND) if(OPUS_FOUND) set(OPUS_LIBRARIES ${OPUSFILE_LIBRARY} ${OPUS_LIBRARY} ${OGG_LIBRARY}) else(OPUS_FOUND) set(OPUS_LIBRARIES) endif(OPUS_FOUND) mark_as_advanced(OPUS_INCLUDE_DIR) mark_as_advanced(OPUS_LIBRARY OPUSFILE_LIBRARY) allegro5-5.2.10.1/cmake/FindSDL2.cmake000066400000000000000000000161721473414355200170560ustar00rootroot00000000000000# Locate SDL2 library # This module defines # SDL2_LIBRARY, the name of the library to link against # SDL2_FOUND, if false, do not try to link to SDL2 # SDL2_INCLUDE_DIR, where to find SDL.h # # This module responds to the the flag: # SDL2_BUILDING_LIBRARY # If this is defined, then no SDL2main will be linked in because # only applications need main(). # Otherwise, it is assumed you are building an application and this # module will attempt to locate and set the the proper link flags # as part of the returned SDL2_LIBRARY variable. # # Don't forget to include SDLmain.h and SDLmain.m your project for the # OS X framework based version. (Other versions link to -lSDL2main which # this module will try to find on your behalf.) Also for OS X, this # module will automatically add the -framework Cocoa on your behalf. # # # Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration # and no SDL2_LIBRARY, it means CMake did not find your SDL2 library # (SDL2.dll, libsdl2.so, SDL2.framework, etc). # Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again. # Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value # as appropriate. These values are used to generate the final SDL2_LIBRARY # variable, but when these values are unset, SDL2_LIBRARY does not get created. # # # $SDL2DIR is an environment variable that would # correspond to the ./configure --prefix=$SDL2DIR # used in building SDL2. # l.e.galup 9-20-02 # # Modified by Eric Wing. # Added code to assist with automated building by using environmental variables # and providing a more controlled/consistent search behavior. # Added new modifications to recognize OS X frameworks and # additional Unix paths (FreeBSD, etc). # Also corrected the header search path to follow "proper" SDL guidelines. # Added a search for SDL2main which is needed by some platforms. # Added a search for threads which is needed by some platforms. # Added needed compile switches for MinGW. # # On OSX, this will prefer the Framework version (if found) over others. # People will have to manually change the cache values of # SDL2_LIBRARY to override this selection or set the CMake environment # CMAKE_INCLUDE_PATH to modify the search paths. # # Note that the header path has changed from SDL2/SDL.h to just SDL.h # This needed to change because "proper" SDL convention # is #include "SDL.h", not . This is done for portability # reasons because not all systems place things in SDL2/ (see FreeBSD). #============================================================================= # CMake - Cross Platform Makefile Generator # Copyright 2000-2017 Kitware, Inc. and Contributors # 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 name of Kitware, Inc. nor the names of 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 # HOLDER 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. #============================================================================= SET(SDL2_SEARCH_PATHS ~/Library/Frameworks /Library/Frameworks /usr/local /usr /sw # Fink /opt/local # DarwinPorts /opt/csw # Blastwave /opt ) FIND_PATH(SDL2_INCLUDE_DIR SDL.h HINTS $ENV{SDL2DIR} PATH_SUFFIXES include/SDL2 include PATHS ${SDL2_SEARCH_PATHS} ) FIND_LIBRARY(SDL2_LIBRARY_TEMP NAMES SDL2 HINTS $ENV{SDL2DIR} PATH_SUFFIXES lib64 lib PATHS ${SDL2_SEARCH_PATHS} ) IF(NOT SDL2_BUILDING_LIBRARY) IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") # Non-OS X framework versions expect you to also dynamically link to # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms # seem to provide SDL2main for compatibility even though they don't # necessarily need it. FIND_LIBRARY(SDL2MAIN_LIBRARY NAMES SDL2main HINTS $ENV{SDL2DIR} PATH_SUFFIXES lib64 lib PATHS ${SDL2_SEARCH_PATHS} ) ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") ENDIF(NOT SDL2_BUILDING_LIBRARY) # SDL2 may require threads on your system. # The Apple build may not need an explicit flag because one of the # frameworks may already provide it. # But for non-OSX systems, I will use the CMake Threads package. IF(NOT APPLE) FIND_PACKAGE(Threads) ENDIF(NOT APPLE) # MinGW needs an additional library, mwindows # It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows # (Actually on second look, I think it only needs one of the m* libraries.) IF(MINGW) SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") ENDIF(MINGW) IF(SDL2_LIBRARY_TEMP) # For SDL2main IF(NOT SDL2_BUILDING_LIBRARY) IF(SDL2MAIN_LIBRARY) SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP}) ENDIF(SDL2MAIN_LIBRARY) ENDIF(NOT SDL2_BUILDING_LIBRARY) # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. # CMake doesn't display the -framework Cocoa string in the UI even # though it actually is there if I modify a pre-used variable. # I think it has something to do with the CACHE STRING. # So I use a temporary variable until the end so I can set the # "real" variable in one-shot. IF(APPLE) SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa") ENDIF(APPLE) # For threads, as mentioned Apple doesn't need this. # In fact, there seems to be a problem if I used the Threads package # and try using this line, so I'm just skipping it entirely for OS X. IF(NOT APPLE) SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) ENDIF(NOT APPLE) # For MinGW library IF(MINGW) SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) ENDIF(MINGW) # Set the final string here so the GUI reflects the final state. SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found") # Set the temp variable to INTERNAL so it is not seen in the CMake GUI SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") ENDIF(SDL2_LIBRARY_TEMP) INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) allegro5-5.2.10.1/cmake/FindTheora.cmake000066400000000000000000000023651473414355200175730ustar00rootroot00000000000000# - Find theora # Find the native theora includes and libraries # # THEORA_INCLUDE_DIR - where to find theora.h, etc. # THEORA_LIBRARIES - List of libraries when using theora. # THEORA_FOUND - True if theora found. if(THEORA_INCLUDE_DIR) # Already in cache, be silent set(THEORA_FIND_QUIETLY TRUE) endif(THEORA_INCLUDE_DIR) find_package(Ogg) if(OGG_FOUND) find_path(THEORA_INCLUDE_DIR theora/theora.h) # MSVC built theora may be named *_static # The provided project files name the library with the lib prefix. find_library(THEORA_LIBRARY NAMES theoradec theoradec_static libtheoradec libtheoradec_static theora theora_static libtheora libtheora_static ) # Handle the QUIETLY and REQUIRED arguments and set THEORA_FOUND # to TRUE if all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(THEORA DEFAULT_MSG THEORA_INCLUDE_DIR THEORA_LIBRARY) endif(OGG_FOUND) if(THEORA_FOUND) set(THEORA_LIBRARIES ${THEORA_LIBRARY} ${OGG_LIBRARY}) else(THEORA_FOUND) set(THEORA_LIBRARIES) endif(THEORA_FOUND) mark_as_advanced(THEORA_INCLUDE_DIR) mark_as_advanced(THEORA_LIBRARY) allegro5-5.2.10.1/cmake/FindTremor.cmake000066400000000000000000000016231473414355200176150ustar00rootroot00000000000000# - Find Tremor # # TREMOR_INCLUDE_DIR - where to find Tremor headers. # TREMOR_LIBRAY - List of libraries when using libTremor. # TREMOR_FOUND - True if Tremor found. if(TREMOR_INCLUDE_DIR) # Already in cache, be silent set(TREMOR_FIND_QUIETLY TRUE) endif(TREMOR_INCLUDE_DIR) find_path(TREMOR_INCLUDE_DIR tremor/ivorbisfile.h) find_library(TREMOR_LIBRARY NAMES vorbisidec) # Handle the QUIETLY and REQUIRED arguments and set TREMOR_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(TREMOR DEFAULT_MSG TREMOR_INCLUDE_DIR TREMOR_LIBRARY) mark_as_advanced(TREMOR_INCLUDE_DIR TREMOR_LIBRARY) if(TREMOR_FOUND) set(TREMOR_LIBRARIES ${TREMOR_LIBRARY} ${OGG_LIBRARY}) else(TREMOR_FOUND) set(TREMOR_LIBRARIES) endif(TREMOR_FOUND) mark_as_advanced(TREMOR_INCLUDE_DIR TREMOR_LIBRARY) allegro5-5.2.10.1/cmake/FindVorbis.cmake000066400000000000000000000024561473414355200176160ustar00rootroot00000000000000# - Find vorbis # Find the native vorbis includes and libraries # # VORBIS_INCLUDE_DIR - where to find vorbis.h, etc. # VORBIS_LIBRARIES - List of libraries when using vorbis(file). # VORBIS_FOUND - True if vorbis found. if(VORBIS_INCLUDE_DIR) # Already in cache, be silent set(VORBIS_FIND_QUIETLY TRUE) endif(VORBIS_INCLUDE_DIR) find_package(Ogg) if(OGG_FOUND) find_path(VORBIS_INCLUDE_DIR vorbis/vorbisfile.h) # MSVC built vorbis may be named vorbis_static # The provided project files name the library with the lib prefix. find_library(VORBIS_LIBRARY NAMES vorbis vorbis_static libvorbis libvorbis_static) find_library(VORBISFILE_LIBRARY NAMES vorbisfile vorbisfile_static libvorbisfile libvorbisfile_static) # Handle the QUIETLY and REQUIRED arguments and set VORBIS_FOUND # to TRUE if all listed variables are TRUE. include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(VORBIS DEFAULT_MSG VORBIS_INCLUDE_DIR VORBIS_LIBRARY VORBISFILE_LIBRARY) endif(OGG_FOUND) if(VORBIS_FOUND) set(VORBIS_LIBRARIES ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY}) else(VORBIS_FOUND) set(VORBIS_LIBRARIES) endif(VORBIS_FOUND) mark_as_advanced(VORBIS_INCLUDE_DIR) mark_as_advanced(VORBIS_LIBRARY VORBISFILE_LIBRARY) allegro5-5.2.10.1/cmake/FindWebP.cmake000066400000000000000000000050441473414355200172030ustar00rootroot00000000000000# - Try to find WebP. # Once done, this will define # # WEBP_FOUND - system has WebP. # WEBP_INCLUDE_DIRS - the WebP. include directories # WEBP_LIBRARIES - link these to use WebP. # # Copyright (C) 2012 Raphael Kubo da Costa # Copyright (C) 2013 Igalia S.L. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. 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. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS 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 HOLDER OR ITS # 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. find_package(PkgConfig) pkg_check_modules(PC_WEBP QUIET libwebp libsharpyuv) # Look for the header file. find_path(WEBP_INCLUDE_DIRS NAMES webp/decode.h HINTS ${PC_WEBP_INCLUDEDIR} ${PC_WEBP_INCLUDE_DIRS} ) mark_as_advanced(WEBP_INCLUDE_DIRS) # Look for the library. find_library( WEBP_LIBRARY NAMES webp HINTS ${PC_WEBP_LIBDIR} ${PC_WEBP_LIBRARY_DIRS} ) if (WEBP_LIBRARY) list(APPEND WEBP_LIBRARIES ${WEBP_LIBRARY}) endif() # As of 1.3, libsharpyuv is split off from the main library. find_library( SHARPYUV_LIBRARY NAMES sharpyuv HINTS ${PC_WEBP_LIBDIR} ${PC_WEBP_LIBRARY_DIRS} ) if (SHARPYUV_LIBRARY) list(APPEND WEBP_LIBRARIES ${SHARPYUV_LIBRARY}) endif() set(WEBP_LIBRARIES ${WEBP_LIBRARIES} CACHE STRING "WebP libraries") mark_as_advanced(WEBP_LIBRARIES) include(FindPackageHandleStandardArgs) set(FPHSA_NAME_MISMATCHED TRUE) find_package_handle_standard_args(WebP REQUIRED_VARS WEBP_INCLUDE_DIRS WEBP_LIBRARIES FOUND_VAR WEBP_FOUND) allegro5-5.2.10.1/cmake/PreventInSourceBuilds.cmake000066400000000000000000000012651473414355200220040ustar00rootroot00000000000000# This function will prevent in-source builds # Based on https://github.com/InsightSoftwareConsortium/ITK/blob/1b5da45dc706e6d6803b52740fa50e0e5e7705e9/CMake/PreventInSourceBuilds.cmake function(PreventInSourceBuilds) # make sure the user doesn't play dirty with symlinks get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) # disallow in-source builds if("${srcdir}" STREQUAL "${bindir}") message(FATAL_ERROR "Allegro must not be configured to build in the source directory.\n" "Please refer to README.md\n" "Quitting configuration step") endif() endfunction() PreventInSourceBuilds() allegro5-5.2.10.1/cmake/Toolchain-iphone.cmake000066400000000000000000000004431473414355200207430ustar00rootroot00000000000000set (IPHONE 1) set (ALLEGRO_CFG_OPENGLES 1) set (IOS_PLATFORM "iphoneos" CACHE STRING "iOS platform (iphoneos or iphonesimulator)") mark_as_advanced(IOS_PLATFORM) set (CMAKE_OSX_SYSROOT "${IOS_PLATFORM}") set (CMAKE_MACOSX_BUNDLE YES) set (CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") allegro5-5.2.10.1/cmake/Toolchain-mingw.cmake000066400000000000000000000061121473414355200206010ustar00rootroot00000000000000# Use this command to build the Windows port of Allegro # with a mingw cross compiler: # # cmake -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchain-mingw.cmake . # # or for out of source: # # cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw.cmake .. # # You will need at least CMake 2.6.0. # # Adjust the following paths to suit your environment. # # This file was based on http://www.cmake.org/Wiki/CmakeMingw # the name of the target operating system set(CMAKE_SYSTEM_NAME Windows) # Assume the target architecture. # XXX for some reason the value set here gets cleared before we reach the # main CMakeLists.txt; see that file for a workaround. # set(CMAKE_SYSTEM_PROCESSOR i686) # Which compilers to use for C and C++, and location of target # environment. if(EXISTS /usr/i586-mingw32msvc) # First look in standard location as used by Debian/Ubuntu/etc. set(CMAKE_C_COMPILER i586-mingw32msvc-gcc) set(CMAKE_CXX_COMPILER i586-mingw32msvc-g++) set(CMAKE_RC_COMPILER i586-mingw32msvc-windres) set(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc) elseif(EXISTS /usr/i686-w64-mingw32) # First look in standard location as used by Debian/Ubuntu/etc. set(CMAKE_C_COMPILER i686-w64-mingw32-gcc) set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) set(CMAKE_RC_COMPILER i686-w64-mingw32-windres) set(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32) set(CMAKE_AR:FILEPATH /usr/bin/i686-w64-mingw32-ar) elseif(EXISTS /opt/mingw) # You can get a MinGW environment using the script at . # It downloads and builds MinGW and most of the dependencies for you. # You can use the toolchain file generated by MXE called `mxe-conf.cmake' # or you can use this file by adjusting the above and following paths. set(CMAKE_C_COMPILER /opt/mingw/usr/bin/i686-pc-mingw32-gcc) set(CMAKE_CXX_COMPILER /opt/mingw/usr/bin/i686-pc-mingw32-g++) set(CMAKE_RC_COMPILER /opt/mingw/usr/bin/i686-pc-mingw32-windres) set(CMAKE_FIND_ROOT_PATH /opt/mingw/usr/i686-pc-mingw32) else() # Else fill in local path which the user will likely adjust. # This is the location assumed by set(CMAKE_C_COMPILER /usr/local/cross-tools/bin/i386-mingw32-gcc) set(CMAKE_CXX_COMPILER /usr/local/cross-tools/bin/i386-mingw32-g++) set(CMAKE_RC_COMPILER /usr/local/cross-tools/bin/i386-mingw32-windres) set(CMAKE_FIND_ROOT_PATH /usr/local/cross-tools) endif() # Adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # Tell pkg-config not to look at the target environment's .pc files. # Setting PKG_CONFIG_LIBDIR sets the default search directory, but we have to # set PKG_CONFIG_PATH as well to prevent pkg-config falling back to the host's # path. set(ENV{PKG_CONFIG_LIBDIR} ${CMAKE_FIND_ROOT_PATH}/lib/pkgconfig) set(ENV{PKG_CONFIG_PATH} ${CMAKE_FIND_ROOT_PATH}/lib/pkgconfig) set(ENV{MINGDIR} ${CMAKE_FIND_ROOT_PATH}) allegro5-5.2.10.1/cmake/Toolchain-openwiz.cmake000066400000000000000000000005201473414355200211500ustar00rootroot00000000000000SET(GP2XWIZ on) SET(CMAKE_SYSTEM_NAME Linux) SET(CMAKE_C_COMPILER arm-openwiz-linux-gnu-gcc) SET(CMAKE_CXX_COMPILER arm-openwiz-linux-gnu-g++) SET(CMAKE_FIND_ROOT_PATH /home/trent/arm-openwiz-linux-gnu) SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) allegro5-5.2.10.1/cmake/Toolchain-raspberrypi.cmake000066400000000000000000000026651473414355200220330ustar00rootroot00000000000000SET(ALLEGRO_RASPBERRYPI 1) SET(CMAKE_SYSTEM_NAME Linux) IF("${TOOLCHAIN_ROOT}" STREQUAL "") SET(TOOLCHAIN_ROOT "/usr/bin") ENDIF("${TOOLCHAIN_ROOT}" STREQUAL "") IF("${TOOLCHAIN_PREFIX}" STREQUAL "") SET(TOOLCHAIN_PREFIX "") ENDIF("${TOOLCHAIN_PREFIX}" STREQUAL "") IF("${TOOLCHAIN_SUFFIX}" STREQUAL "") SET(TOOLCHAIN_SUFFIX "") ENDIF("${TOOLCHAIN_SUFFIX}" STREQUAL "") SET(CMAKE_C_FLAGS "-march=armv6 -mfpu=vfp -mfloat-abi=hard -Os") SET(CMAKE_CXX_FLAGS "-march=armv6 -mfpu=vfp -mfloat-abi=hard -Os") if(NOT DISTCC) set(CMAKE_C_COMPILER ${TOOLCHAIN_ROOT}/${TOOLCHAIN_PREFIX}gcc${TOOLCHAIN_SUFFIX}) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_ROOT}/${TOOLCHAIN_PREFIX}g++${TOOLCHAIN_SUFFIX}) endif() set(CMAKE_LINKER ${TOOLCHAIN_ROOT}/${TOOLCHAIN_PREFIX}ld${TOOLCHAIN_SUFFIX}) set(CMAKE_NM ${TOOLCHAIN_ROOT}/${TOOLCHAIN_PREFIX}nm${TOOLCHAIN_SUFFIX}) set(CMAKE_OBJCOPY ${TOOLCHAIN_ROOT}/${TOOLCHAIN_PREFIX}objcopy${TOOLCHAIN_SUFFIX}) set(CMAKE_OBJDUMP ${TOOLCHAIN_ROOT}/${TOOLCHAIN_PREFIX}objdump${TOOLCHAIN_SUFFIX}) set(CMAKE_STRIP ${TOOLCHAIN_ROOT}/${TOOLCHAIN_PREFIX}strip${TOOLCHAIN_SUFFIX}) set(CMAKE_RANLIB ${TOOLCHAIN_ROOT}/${TOOLCHAIN_PREFIX}ranlib${TOOLCHAIN_SUFFIX}) SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) include_directories( "/opt/vc/include" "/opt/vc/include/interface/vcos/pthreads" "/opt/vc/include/interface/vmcs_host/linux" ) allegro5-5.2.10.1/contrib/000077500000000000000000000000001473414355200151205ustar00rootroot00000000000000allegro5-5.2.10.1/contrib/luajit/000077500000000000000000000000001473414355200164105ustar00rootroot00000000000000allegro5-5.2.10.1/contrib/luajit/CMakeLists.txt000066400000000000000000000025611473414355200211540ustar00rootroot00000000000000include(FindPythonInterp) # Construct list of files whose modification should trigger a rebuild of # the Python API. foreach(x ${MONOLITH_SOURCES} ${MONOLITH_HEADERS} ${ALLEGRO_PUBLIC_HEADERS}) if(NOT ${x} MATCHES "^/.*") file(RELATIVE_PATH xrel ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/${x}) list(APPEND SOURCES ${xrel}) endif() endforeach() if(WIN32) add_custom_command( OUTPUT luajit_protos DEPENDS ${SOURCES} COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/python/checkdocs.py -c ${CMAKE_C_COMPILER} -p luajit_protos -b ${PROJECT_BINARY_DIR} -s ${PROJECT_SOURCE_DIR} -w ) else(WIN32) add_custom_command( OUTPUT luajit_protos DEPENDS ${SOURCES} COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/python/checkdocs.py -p luajit_protos -b ${PROJECT_BINARY_DIR} -s ${PROJECT_SOURCE_DIR} ) endif(WIN32) SET(release "") append_lib_type_suffix(release) append_lib_linkage_suffix(release) SET(version "${ALLEGRO_SOVERSION}") add_custom_target(luajit ALL DEPENDS luajit_protos COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/generate_luajit_ffi.py -p luajit_protos -o al5_ffi.lua -t \"${release}\" -v \"${version}\" ) allegro5-5.2.10.1/contrib/luajit/README.txt000066400000000000000000000007701473414355200201120ustar00rootroot00000000000000Luajit ====== The contents of this directory provides support for using Allegro5 from [Luajit][lj]. Usage ----- To create a Luajit FFI desciption we use the prototypes scraped using the checkdocs.py script. # output a file protos.txt ./python/checkdocs.py -p protos.txt -b build/ # use the prototypes to create Luajit datatypes for Allegro5 ./contrib/luajit/generate_luajit_ffi.py -p protos.txt -o al5_ffi.lua See the Luajit docs on how to use this file. [lj]: http://luajit.org allegro5-5.2.10.1/contrib/luajit/generate_luajit_ffi.py000077500000000000000000000167701473414355200227660ustar00rootroot00000000000000#!/usr/bin/env python3 """ This script will use the prototypes from "checkdocs.py -s" to concoct a 1:1 LuaJIT FFI wrapper for Allegro. Thanks to generate_python_ctypes.py. """ import sys import re import optparse class Allegro: def __init__(self): self.typesfw = [] self.typesfuncptr = [] self.typedecl = [] self.functions = [] self.constants = {} self.enums = [] def parse_protos(self, filename): deferred = [] # first pass: create all structs, but without fields for line in open(filename): name, proto = line.split(":", 1) proto = proto.lstrip() pwords = proto.split(' ') if name.endswith("()"): self.functions.append(proto) continue # anonymous structs have no name at all if name and not name.startswith("ALLEGRO_"): continue if name == "ALLEGRO_OGL_EXT_API": continue if pwords[0] in ('union', 'struct'): if '{' in proto: self.typedecl.append(proto) else: self.typesfw.append(proto) elif pwords[0] == 'typedef' and pwords[1] in ('union', 'struct'): if '{' in proto: self.typedecl.append(proto) else: self.typesfw.append(proto) elif proto.startswith("enum") or\ proto.startswith("typedef enum"): if name: self.enums.append('enum %s;' % name) deferred.append(("", proto)) elif proto.startswith("#define"): if not name.startswith("_") and not name.startswith("GL_"): i = eval(proto.split(None, 2)[2]) self.constants[name] = i else: mob = re.match("typedef (.*) " + name, proto) if mob: self.typesfw.append(proto) else: # Probably a function pointer self.typesfuncptr.append(proto) # Second pass of prototypes now we have seen them all. for name, proto in deferred: bo = proto.find("{") if bo == -1: continue bc = proto.rfind("}") braces = proto[bo + 1:bc] # Calculate enums if proto.startswith("enum") or \ proto.startswith("typedef enum"): fields = braces.split(",") i = 0 for field in fields: if "=" in field: fname, val = field.split("=", 1) fname = fname.strip() # replace any 'X' (an integer value in C) with # ord('X') to match up in Python val = re.sub("('.')", "ord(\\1)", val) try: i = int(eval(val, globals(), self.constants)) except NameError: i = val except Exception: raise ValueError( "Exception while parsing '{}'".format( val)) else: fname = field.strip() if not fname: continue self.constants[fname] = i try: i += 1 except TypeError: pass continue def typeorder(decls, declared): """ Order the types by dependency. """ decl, seen = set(), set() ordered = [] todo = decls[:] seen.add('ALLEGRO_EVENT_TYPE') seen.add('ALLEGRO_KEY_MAX') seen.add('ALLEGRO_USER_EVENT_DESCRIPTOR') def info(t): brk, brk2 = t.find('{'), t.rfind('}') tbrk = t[brk+1:brk2] if brk >= 0 and brk2 >= 0 else None tw = t.split(' ') name = None if tw[0] in ('struct', 'union'): name = tw[1] elif tw[0] == 'typedef': if tw[1] in ('struct', 'union'): name = tw[2] return name, tbrk for t in declared: name, _ = info(t) if name: decl.add(name) reall = re.compile('(ALLEGRO_\w+\s*\*?)') retname = re.compile('(ALLEGRO_\w+)') c = 0 while True: lb = len(todo) for t in todo[:]: name, brk = info(t) aldeps = reall.findall(brk) ok = True # print aldeps for rdep in aldeps: dep = retname.match(rdep).group(1) if dep.startswith('ALLEGRO_GL_'): continue # ignore if dep in decl and rdep[-1] == '*': continue # ok, seen type and ptr if not dep in seen: ok = False break if ok: ordered.append(t) todo.remove(t) seen.add(name) if len(todo) == 0: break elif lb == len(todo): c += 1 assert c < 10, 'loop, bad' # ordered += todo return ordered def main(): p = optparse.OptionParser() p.add_option("-o", "--output", help="location of generated file") p.add_option("-p", "--protos", help="A file with all " + "prototypes to generate LuaJIT FFI wrappers for, one per line. " "Generate it with docs/scripts/checkdocs.py -p") p.add_option("-t", "--type", help="the library type to " + "use, e.g. debug") p.add_option("-v", "--version", help="the library version to " + "use, e.g. 5.1") options, args = p.parse_args() if not options.protos: p.print_help() return al = Allegro() al.parse_protos(options.protos) f = open(options.output, "w") if options.output else sys.stdout release = options.type version = options.version f.write(r"""-- Generated by generate_luajit_ffi.py -- Release: %(release)s-%(version)s local ffi = require 'ffi' local allegro = {} """ % locals()) f.write('-- CONSTANTS\n') deferred = [] for name, val in sorted(al.constants.items()): try: if isinstance(val, str): val = int(eval(val, globals(), al.constants)) f.write('allegro.%s = %s\n' % (name, str(val))) except: deferred.append((name, val)) reconst = re.compile('([A-Za-z_]\w+)') for name, val in deferred: val = reconst.sub(r'allegro.\1', val) f.write('allegro.%s = %s\n' % (name, str(val))) f.write(r""" ffi.cdef[[ typedef uint64_t off_t; typedef int64_t time_t; typedef void* va_list; typedef int al_fixed; typedef unsigned int GLuint; typedef unsigned int ALLEGRO_EVENT_TYPE; enum { ALLEGRO_KEY_MAX = 227 }; """) # enums f.write('\n// ENUMS\n') reenum = re.compile('enum (\w+)') for e in al.enums: ename = reenum.match(e).group(1) f.write('typedef enum %s %s;\n' % (ename, ename)) # types f.write('\n// TYPES\n') for t in al.typesfw: f.write(t + "\n") for t in al.typesfuncptr: f.write(t + "\n") seen = al.typesfw[:] for t in typeorder(al.typedecl, seen): f.write(t + "\n") # functions f.write('\n// FUNCTIONS\n') for fn in al.functions: f.write(fn + "\n") f.write(']]\n') # end of cdef f.write(r""" return allegro """) f.close() main() allegro5-5.2.10.1/docs/000077500000000000000000000000001473414355200144105ustar00rootroot00000000000000allegro5-5.2.10.1/docs/CMakeLists.txt000066400000000000000000000127421473414355200171560ustar00rootroot00000000000000find_program(MAKEINFO NAMES makeinfo) mark_as_advanced(MAKEINFO) find_program(PANDOC NAMES pandoc) mark_as_advanced(PANDOC) # sh is only used for a developer-only target. find_program(SH NAMES ash dash sh) mark_as_advanced(SH) find_package(LATEX) find_program(CTAGS NAMES ctags) mark_as_advanced(CTAGS) #-----------------------------------------------------------------------------# set(DOC_GIT_REF "" CACHE STRING "Git ref to use for source links in the documentation. If empty, will query git for this.") set(REAL_DOC_GIT_REF "") if(DOC_GIT_REF) set(REAL_DOC_GIT_REF ${DOC_GIT_REF}) else() find_package(Git) if(GIT_FOUND) message(STATUS "Using git to determine git ref for documentation.") execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse HEAD WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} RESULT_VARIABLE GIT_RESULT OUTPUT_VARIABLE GIT_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE) if(GIT_RESULT EQUAL 0) set(REAL_DOC_GIT_REF ${GIT_OUTPUT}) endif() endif() endif() if(NOT REAL_DOC_GIT_REF) set(REAL_DOC_GIT_REF master) endif() message(STATUS "Using ${REAL_DOC_GIT_REF} as the git ref for source links in the documentation.") #-----------------------------------------------------------------------------# # Pandoc 1.10 changed handling of internal cross-references in Texinfo writer, # and LaTeX writer thereabouts. if(PANDOC) message(STATUS "Checking Pandoc version") execute_process( COMMAND ${PANDOC} --version OUTPUT_VARIABLE PANDOC_VERSION_TEXT ERROR_VARIABLE PANDOC_VERSION_TEXT ) if(PANDOC_VERSION_TEXT MATCHES "pandoc(.exe)? (1[.]1[0-9]|1[.][2-9][0-9]|[2-9])") # message(STATUS "Pandoc version is compatible") else() message(STATUS "Pandoc version is incompatible") set(PANDOC 0) endif() endif() #-----------------------------------------------------------------------------# set(all_docs) macro(add_info n) if(MAKEINFO) makedoc(src/${n}._tx -texi texi/${n}.texi) set(abs_info ${CMAKE_CURRENT_BINARY_DIR}/info/${n}.info) set(abs_texi ${CMAKE_CURRENT_BINARY_DIR}/texi/${n}.texi) list(APPEND all_docs ${abs_info}) add_custom_command( OUTPUT ${abs_info} DEPENDS ${abs_texi} COMMAND ${MAKEINFO} --no-split -o ${abs_info} ${abs_texi} ) endif(MAKEINFO) endmacro(add_info) #-----------------------------------------------------------------------------# function(pandoc source output) # extraargs... set(abs_source ${CMAKE_CURRENT_SOURCE_DIR}/${source}) set(abs_output ${CMAKE_CURRENT_BINARY_DIR}/${output}) # Use native Windows syntax to avoid "c:/foo.txt" being treated as a # remote URI by Pandoc 1.5 and 1.6. file(TO_NATIVE_PATH ${abs_source} abs_source_native) list(APPEND all_docs ${abs_output}) set(all_docs ${all_docs} PARENT_SCOPE) add_custom_command( OUTPUT ${abs_output} DEPENDS ${abs_source} COMMAND ${PANDOC} ${abs_source_native} --from markdown --toc --standalone ${ARGN} -o ${abs_output} ) endfunction(pandoc source output) function(texi2text source output) # The source file is a generated Texinfo file. set(abs_source ${CMAKE_CURRENT_BINARY_DIR}/${source}) set(abs_output ${CMAKE_CURRENT_BINARY_DIR}/${output}) list(APPEND all_docs ${abs_output}) set(all_docs ${all_docs} PARENT_SCOPE) # Writing to stdout suppresses the table of contents. # To get the table of contents, use `makeinfo -o ${output}`. add_custom_command( OUTPUT ${abs_output} DEPENDS ${abs_source} COMMAND ${MAKEINFO} --plaintext --paragraph-indent 0 --no-number-sections ${abs_source} > ${abs_output} ) endfunction(texi2text) if(PANDOC) pandoc(src/changes-5.0.txt html/changes-5.0.html -c pandoc.css) pandoc(src/changes-5.1.txt html/changes-5.1.html -c pandoc.css) pandoc(src/changes-5.2.txt html/changes-5.2.html -c pandoc.css) pandoc(src/changes-5.0.txt texi/changes-5.0.texi) pandoc(src/changes-5.1.txt texi/changes-5.1.texi) pandoc(src/changes-5.2.txt texi/changes-5.2.texi) if(MAKEINFO) texi2text(texi/changes-5.0.texi txt/changes-5.0.txt) texi2text(texi/changes-5.1.texi txt/changes-5.1.txt) texi2text(texi/changes-5.2.texi txt/changes-5.2.txt) endif(MAKEINFO) endif(PANDOC) add_custom_target(docs ALL DEPENDS ${all_docs} ) #-----------------------------------------------------------------------------# make_directory(${CMAKE_CURRENT_BINARY_DIR}/html/refman) make_directory(${CMAKE_CURRENT_BINARY_DIR}/txt) make_directory(${CMAKE_CURRENT_BINARY_DIR}/texi) make_directory(${CMAKE_CURRENT_BINARY_DIR}/latex) # Stick the ALLEGRO_VERSION into a file included by the latex template configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/src/refman/allegro_version.tex.cmake ${CMAKE_CURRENT_BINARY_DIR}/latex/allegro_version.tex @ONLY ) # Copy CSS files. configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/src/pandoc.css ${CMAKE_CURRENT_BINARY_DIR}/html/pandoc.css COPYONLY ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/src/pandoc.css ${CMAKE_CURRENT_BINARY_DIR}/html/refman/pandoc.css COPYONLY ) if(PANDOC AND NOT CMAKE_CROSSCOMPILING) include(Refman.cmake) endif() #-----------------------------------------------------------------------------# # vim: set sts=4 sw=4 et: allegro5-5.2.10.1/docs/Refman.cmake000066400000000000000000000363161473414355200166330ustar00rootroot00000000000000set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) set(SRC_REFMAN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/refman) # Put these in the order that they should appear in the Info or PDF manual. set(PAGES getting_started config display events file fixed fshook fullscreen_mode graphics haptic joystick keyboard memory misc monitor mouse path state system threads time timer touch transformations utf8 platform direct3d opengl audio acodec color font image main memfile native_dialog physfs primitives shader video ) set(PAGES_TXT) foreach(page ${PAGES}) list(APPEND PAGES_TXT ${SRC_REFMAN_DIR}/${page}.txt) endforeach(page) set(TITLE_TXT ${SRC_REFMAN_DIR}/title.txt) set(IMAGES primitives1 primitives2 LINE_CAP LINE_JOIN audio ) #-----------------------------------------------------------------------------# # # Paths # #-----------------------------------------------------------------------------# set(HTML_DIR ${CMAKE_CURRENT_BINARY_DIR}/html/refman) set(MAN_DIR ${CMAKE_CURRENT_BINARY_DIR}/man) set(INFO_DIR ${CMAKE_CURRENT_BINARY_DIR}/info) set(TEXI_DIR ${CMAKE_CURRENT_BINARY_DIR}/texi) set(LATEX_DIR ${CMAKE_CURRENT_BINARY_DIR}/latex) set(PDF_DIR ${CMAKE_CURRENT_BINARY_DIR}/pdf) set(PROTOS ${CMAKE_CURRENT_BINARY_DIR}/protos) set(API_EXAMPLES ${CMAKE_CURRENT_BINARY_DIR}/examples) set(PROTOS_TIMESTAMP ${PROTOS}.timestamp) set(EXAMPLES_DIR ${CMAKE_SOURCE_DIR}/examples) set(HTML_REFS ${CMAKE_CURRENT_BINARY_DIR}/html_refs) set(HTML_REFS_TIMESTAMP ${HTML_REFS}.timestamp) set(INDEX_ALL ${CMAKE_CURRENT_BINARY_DIR}/index_all.txt) set(SEARCH_INDEX_JS ${HTML_DIR}/search_index.js) set(SCRIPT_DIR ${CMAKE_SOURCE_DIR}/docs/scripts) set(MAKE_PROTOS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/make_protos) set(MAKE_HTML_REFS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/make_html_refs) set(MAKE_INDEX ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/make_index) set(SCAN_EXAMPLES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/scan_examples) set(MAKE_DOC ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/make_doc --pandoc "${PANDOC}" --protos ${PROTOS} --allegro5_cfg ${CMAKE_SOURCE_DIR}/allegro5.cfg --git_ref ${REAL_DOC_GIT_REF}) set(INSERT_TIMESTAMP ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/insert_timestamp) set(MAKE_SEARCH_INDEX ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/make_search_index) set(DAWK_SOURCES scripts/aatree.c scripts/dawk.c scripts/trex.c) add_executable(make_protos scripts/make_protos.c ${DAWK_SOURCES}) add_executable(make_html_refs scripts/make_html_refs.c ${DAWK_SOURCES}) add_executable(make_index scripts/make_index.c ${DAWK_SOURCES}) add_executable(make_doc scripts/make_doc.c scripts/make_man.c scripts/make_single.c ${DAWK_SOURCES}) add_executable(insert_timestamp scripts/insert_timestamp.c ${DAWK_SOURCES}) add_executable(make_search_index scripts/make_search_index.c ${DAWK_SOURCES}) add_executable(scan_examples scripts/scan_examples.c ${DAWK_SOURCES}) #-----------------------------------------------------------------------------# # # Protos # #-----------------------------------------------------------------------------# # The protos file is a list of function prototypes and type declarations # which can then be embedded into the documentation. # Rebuilding the documentation whenever a source file changes is irritating, # especially as public prototypes rarely change. Thus we keep a second file # called protos.timestamp which reflects the last time that the protos file # changed. We declare _that_ file as the dependency of other targets. # We can get into a situation where the protos file is newer than the source # files (up-to-date) but the protos.timestamp is older than the source files. # If the protos and protos.timestamp files are identical then each time # you run make, it will compare them and find them equal, so protos.timestamp # won't be updated. However that check is instantaneous. # ALL_SRCS is split into multiple lists, otherwise the make_protos command # line is too long for Windows >:-( We use relative paths for the same reason. file(GLOB_RECURSE ALL_SRCS1 ${CMAKE_SOURCE_DIR}/src/*.[chm] ${CMAKE_SOURCE_DIR}/src/*.[ch]pp ) file(GLOB_RECURSE ALL_SRCS2 ${CMAKE_SOURCE_DIR}/include/*.h ${CMAKE_SOURCE_DIR}/include/*.inl ) file(GLOB_RECURSE ALL_SRCS3 ${CMAKE_SOURCE_DIR}/addons/*.[chm] ${CMAKE_SOURCE_DIR}/addons/*.[ch]pp ) foreach(x ${ALL_SRCS1}) file(RELATIVE_PATH xrel ${CMAKE_SOURCE_DIR} ${x}) list(APPEND ALL_SRCS1_REL ${xrel}) endforeach() foreach(x ${ALL_SRCS2}) file(RELATIVE_PATH xrel ${CMAKE_SOURCE_DIR} ${x}) list(APPEND ALL_SRCS2_REL ${xrel}) endforeach() foreach(x ${ALL_SRCS3}) file(RELATIVE_PATH xrel ${CMAKE_SOURCE_DIR} ${x}) list(APPEND ALL_SRCS3_REL ${xrel}) endforeach() add_custom_command( OUTPUT ${PROTOS} DEPENDS ${ALL_SRCS1} ${ALL_SRCS2} ${ALL_SRCS3} make_protos WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${MAKE_PROTOS} ${ALL_SRCS1_REL} > ${PROTOS} COMMAND ${MAKE_PROTOS} ${ALL_SRCS2_REL} >> ${PROTOS} COMMAND ${MAKE_PROTOS} ${ALL_SRCS3_REL} >> ${PROTOS} ) add_custom_command( OUTPUT ${PROTOS_TIMESTAMP} DEPENDS ${PROTOS} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROTOS} ${PROTOS_TIMESTAMP} ) # For testing (command line too long for Windows) if(NOT WIN32) add_custom_target(gen_protos DEPENDS ${PROTOS}) endif() #-----------------------------------------------------------------------------# # # API Examples # #-----------------------------------------------------------------------------# # Build a list of all the API entries. Then cross-reference these against # which of the example files make use of them. set(RESP ${CMAKE_CURRENT_BINARY_DIR}/ex_files) file(GLOB EXAMPLE_FILES ${EXAMPLES_DIR}/*.c ${EXAMPLES_DIR}/*.cpp) file(GLOB EXAMPLE_FILES_REL RELATIVE ${CMAKE_SOURCE_DIR} ${EXAMPLES_DIR}/*.c ${EXAMPLES_DIR}/*.cpp) foreach(f IN LISTS EXAMPLE_FILES_REL) string(APPEND multiline "${f}\n") endforeach() file(WRITE ${RESP} "${multiline}") add_custom_command( OUTPUT ${API_EXAMPLES} DEPENDS ${PROTOS} ${EXAMPLE_FILES} ${SCAN_EXAMPLES} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${SCAN_EXAMPLES} --protos ${PROTOS} "@${RESP}" > ${API_EXAMPLES}.t COMMAND ${CMAKE_COMMAND} -E copy_if_different ${API_EXAMPLES}.t ${API_EXAMPLES}) #-----------------------------------------------------------------------------# # # HTML # #-----------------------------------------------------------------------------# # The html_refs file contains link definitions for each API entry. # It's used to resolve references across HTML pages. # The search_index.js file contains definitions for the autosuggest widget. add_custom_command( OUTPUT ${HTML_REFS} DEPENDS ${PAGES_TXT} make_html_refs COMMAND ${MAKE_HTML_REFS} ${PAGES_TXT} > ${HTML_REFS} ) add_custom_command( OUTPUT ${HTML_REFS_TIMESTAMP} DEPENDS ${HTML_REFS} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${HTML_REFS} ${HTML_REFS_TIMESTAMP} ) add_custom_command( OUTPUT ${INDEX_ALL} DEPENDS ${HTML_REFS_TIMESTAMP} make_index COMMAND ${MAKE_INDEX} ${HTML_REFS} > ${INDEX_ALL} ) add_custom_command( OUTPUT ${SEARCH_INDEX_JS} DEPENDS ${HTML_REFS_TIMESTAMP} make_search_index COMMAND ${MAKE_SEARCH_INDEX} ${HTML_REFS} > ${SEARCH_INDEX_JS} ) if(WANT_DOCS_HTML) foreach(inc inc.a inc.z) add_custom_command( OUTPUT ${inc}.html DEPENDS ${SRC_REFMAN_DIR}/${inc}.txt COMMAND ${PANDOC} ${SRC_REFMAN_DIR}/${inc}.txt --from markdown -o ${inc}.html ) endforeach(inc) set(HTML_PAGES) foreach(page ${PAGES} index index_all) if(page STREQUAL "index_all") set(page_src ${INDEX_ALL}) else() set(page_src ${SRC_REFMAN_DIR}/${page}.txt) endif() add_custom_command( OUTPUT ${HTML_DIR}/${page}.html DEPENDS ${PROTOS_TIMESTAMP} ${HTML_REFS_TIMESTAMP} ${page_src} ${CMAKE_CURRENT_BINARY_DIR}/inc.a.html ${CMAKE_CURRENT_BINARY_DIR}/inc.z.html ${SEARCH_INDEX_JS} ${API_EXAMPLES} make_doc insert_timestamp COMMAND ${INSERT_TIMESTAMP} ${CMAKE_SOURCE_DIR}/include/allegro5/base.h > inc.timestamp.html COMMAND ${MAKE_DOC} --examples ${API_EXAMPLES} --to html --raise-sections --include-before-body inc.a.html --include-after-body inc.timestamp.html --include-after-body inc.z.html --css pandoc.css --include-in-header ${SRC_DIR}/custom_header.html --standalone --toc -- ${page_src} ${HTML_REFS} > ${HTML_DIR}/${page}.html ) list(APPEND HTML_PAGES ${HTML_DIR}/${page}.html) endforeach(page) set(HTML_IMAGES) foreach(image ${IMAGES}) add_custom_command( OUTPUT ${HTML_DIR}/images/${image}.png DEPENDS ${SRC_REFMAN_DIR}/images/${image}.png COMMAND "${CMAKE_COMMAND}" -E copy "${SRC_REFMAN_DIR}/images/${image}.png" "${HTML_DIR}/images/${image}.png" ) list(APPEND HTML_IMAGES ${HTML_DIR}/images/${image}.png) endforeach(image) add_custom_target(html ALL DEPENDS ${HTML_PAGES} ${HTML_IMAGES}) foreach(file pandoc.css autosuggest.js) configure_file( ${SRC_DIR}/${file} ${HTML_DIR}/${file} COPYONLY) endforeach(file) endif(WANT_DOCS_HTML) #-----------------------------------------------------------------------------# # # Man pages # #-----------------------------------------------------------------------------# set(MANDIR "man" CACHE STRING "Install man pages into this directory") if(WANT_DOCS_MAN) make_directory(${MAN_DIR}) set(MAN_PAGES) foreach(page ${PAGES_TXT}) # Figure out the man pages that would be generated from this file. file(STRINGS ${page} lines REGEX "# API: ") if(lines) string(REGEX REPLACE "[#]* API: " ";" entries ${lines}) set(outputs) foreach(entry ${entries}) list(APPEND outputs ${MAN_DIR}/${entry}.3) endforeach(entry) add_custom_command( OUTPUT ${outputs} DEPENDS ${PROTOS_TIMESTAMP} ${page} make_doc COMMAND ${MAKE_DOC} --to man -- ${page} WORKING_DIRECTORY ${MAN_DIR} ) list(APPEND MAN_PAGES ${outputs}) endif(lines) endforeach(page) add_custom_target(man ALL DEPENDS ${MAN_PAGES}) install(FILES ${MAN_PAGES} DESTINATION ${MANDIR}/man3 ) endif(WANT_DOCS_MAN) #-----------------------------------------------------------------------------# # # Info # #-----------------------------------------------------------------------------# if(WANT_DOCS_INFO AND MAKEINFO) make_directory(${INFO_DIR}) make_directory(${TEXI_DIR}) add_custom_target(info ALL DEPENDS ${INFO_DIR}/refman.info) add_custom_command( OUTPUT ${INFO_DIR}/refman.info DEPENDS ${TEXI_DIR}/refman.texi COMMAND ${MAKEINFO} --paragraph-indent 0 --no-split ${TEXI_DIR}/refman.texi -o ${INFO_DIR}/refman.info ) add_custom_command( OUTPUT ${TEXI_DIR}/refman.texi DEPENDS ${PROTOS_TIMESTAMP} ${TITLE_TXT} ${PAGES_TXT} make_doc COMMAND ${MAKE_DOC} --to texinfo --standalone -- ${TITLE_TXT} ${PAGES_TXT} > ${TEXI_DIR}/refman.texi ) else() if(WANT_DOCS_INFO) message("Info documentation requires makeinfo") endif(WANT_DOCS_INFO) endif(WANT_DOCS_INFO AND MAKEINFO) #-----------------------------------------------------------------------------# # # LaTeX (PDF) # #-----------------------------------------------------------------------------# set(MAKE_PDF ${WANT_DOCS_PDF}) if(WANT_DOCS_PDF AND NOT PDFLATEX_COMPILER) set(MAKE_PDF 0) message("PDF generation requires pdflatex") endif() if(MAKE_PDF) add_custom_target(latex ALL DEPENDS ${LATEX_DIR}/refman.tex) add_custom_command( OUTPUT ${LATEX_DIR}/refman.tex DEPENDS ${PROTOS_TIMESTAMP} ${TITLE_TXT} ${PAGES_TXT} ${LATEX_DIR}/allegro_version.tex ${SRC_REFMAN_DIR}/latex.template make_doc COMMAND ${MAKE_DOC} --to latex --top-level-division=chapter --template ${SRC_REFMAN_DIR}/latex.template --standalone --toc --number-sections -- ${TITLE_TXT} ${PAGES_TXT} > ${LATEX_DIR}/refman.tex ) set(PDF_IMAGES) foreach(image ${IMAGES}) add_custom_command( OUTPUT ${LATEX_DIR}/images/${image}.png DEPENDS ${SRC_REFMAN_DIR}/images/${image}.png COMMAND "${CMAKE_COMMAND}" -E copy "${SRC_REFMAN_DIR}/images/${image}.png" "${LATEX_DIR}/images/${image}.png" ) list(APPEND PDF_IMAGES ${LATEX_DIR}/images/${image}.png) endforeach(image) make_directory(${PDF_DIR}) add_custom_target(pdf ALL DEPENDS ${PDF_DIR}/refman.pdf) add_custom_command( OUTPUT ${PDF_DIR}/refman.pdf DEPENDS ${LATEX_DIR}/refman.tex DEPENDS ${PDF_IMAGES} # Repeat three times to get cross references correct. COMMAND "${CMAKE_COMMAND}" -E chdir ${LATEX_DIR} ${PDFLATEX_COMPILER} -interaction nonstopmode -output-directory ${PDF_DIR} ${LATEX_DIR}/refman.tex COMMAND "${CMAKE_COMMAND}" -E chdir ${LATEX_DIR} ${PDFLATEX_COMPILER} -interaction nonstopmode -output-directory ${PDF_DIR} ${LATEX_DIR}/refman.tex COMMAND "${CMAKE_COMMAND}" -E chdir ${LATEX_DIR} ${PDFLATEX_COMPILER} -interaction nonstopmode -output-directory ${PDF_DIR} ${LATEX_DIR}/refman.tex ) endif(MAKE_PDF) #-----------------------------------------------------------------------------# # # Tags file # #-----------------------------------------------------------------------------# if(CTAGS) add_custom_target(gen_tags DEPENDS tags) add_custom_command( OUTPUT tags DEPENDS ${PAGES_TXT} COMMAND ${CTAGS} --langdef=allegrodoc --langmap=allegrodoc:.txt "--regex-allegrodoc=/^#+ API: (.+)/\\1/" ${PAGES_TXT} VERBATIM ) endif(CTAGS) #-----------------------------------------------------------------------------# # # Consistency check # #-----------------------------------------------------------------------------# add_custom_target(check_consistency DEPENDS ${PROTOS} COMMAND ${SH} ${SCRIPT_DIR}/check_consistency --protos ${PROTOS} ${PAGES_TXT} ) #-----------------------------------------------------------------------------# # vim: set sts=4 sw=4 et: allegro5-5.2.10.1/docs/scripts/000077500000000000000000000000001473414355200160775ustar00rootroot00000000000000allegro5-5.2.10.1/docs/scripts/aatree.c000066400000000000000000000037741473414355200175170ustar00rootroot00000000000000/* * AA tree, a type of self-balancing search tree. * * A. Andersson. "Balanced search trees made simple." * In Proc. Workshop on Algorithms and Data Structures, pages 60--71. * Springer Verlag, 1993. */ #include #include #include "aatree.h" Aatree aa_nil = { 0, &aa_nil, &aa_nil, "", "" }; static char *xstrdup(const char *s) { size_t n = strlen(s); char *p = malloc(n + 1); memcpy(p, s, n); p[n] = '\0'; return p; } static Aatree *skew(Aatree *T) { if (T == &aa_nil) return T; if (T->left->level == T->level) { Aatree *L = T->left; T->left = L->right; L->right = T; return L; } return T; } static Aatree *split(Aatree *T) { if (T == &aa_nil) return T; if (T->level == T->right->right->level) { Aatree *R = T->right; T->right = R->left; R->left = T; R->level = R->level + 1; return R; } return T; } Aatree *aa_singleton(const char *key, const char *value) { Aatree *T = malloc(sizeof(Aatree)); T->level = 1; T->left = &aa_nil; T->right = &aa_nil; T->key = xstrdup(key); T->value = xstrdup(value); return T; } Aatree *aa_insert(Aatree *T, const char *key, const char *value) { int cmp; if (T == &aa_nil) { return aa_singleton(key, value); } cmp = strcmp(key, T->key); if (cmp < 0) { T->left = aa_insert(T->left, key, value); } else if (cmp > 0) { T->right = aa_insert(T->right, key, value); } else { free(T->value); T->value = xstrdup(value); } T = skew(T); T = split(T); return T; } const char *aa_search(const Aatree *T, const char *key) { while (T != &aa_nil) { int cmp = strcmp(key, T->key); if (cmp == 0) return T->value; T = (cmp < 0) ? T->left : T->right; } return NULL; } void aa_destroy(Aatree *T) { if (T != &aa_nil) { aa_destroy(T->left); aa_destroy(T->right); free(T->key); free(T->value); free(T); } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/aatree.h000066400000000000000000000007111473414355200175100ustar00rootroot00000000000000#ifndef __included_aatree_h #define __included_aatree_h typedef struct Aatree Aatree; struct Aatree { int level; Aatree *left; Aatree *right; char *key; char *value; }; extern Aatree aa_nil; Aatree *aa_singleton(const char *key, const char *value); Aatree *aa_insert(Aatree *T, const char *key, const char *value); const char *aa_search(const Aatree *T, const char *key); void aa_destroy(Aatree *T); #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/check_consistency000077500000000000000000000020341473414355200215220ustar00rootroot00000000000000#!/bin/sh -e # # SYNOPSIS # # check_consistency [OPTION...] DOC-FILE... # # OPTION # # --protos FILE # # DESCRIPTION # # Check that functions and types marked in source code have corresponding # entries in the documentation, and vice versa. The protos file must be # present. # # ENVIRONMENT VARIABLES # # - PROTOS # export LC_ALL=C PROTOS=${PROTOS:-protos} case $1 in --protos) PROTOS=$2 shift 2 ;; esac if test ! -f "$PROTOS" then echo "check_consistency: missing protos file: $PROTOS" 1>&2 exit 1 fi TEMP_SRC=check_consistency.tmp1.$$ TEMP_DOC=check_consistency.tmp2.$$ trap 'rm -f $TEMP_SRC $TEMP_DOC' 0 1 2 3 13 15 cut -d':' -f1 "$PROTOS" | sort | uniq > $TEMP_SRC grep -h '# API: ' "$@" | cut -d' ' -f 3- | sort | uniq > $TEMP_DOC diff $TEMP_SRC $TEMP_DOC | while read -r marker name do case $marker in '>') echo "$name not in source (or missing Function: marker)" ;; '<') echo "$name not documented" ;; esac done # vim: set et: allegro5-5.2.10.1/docs/scripts/dawk.c000066400000000000000000000145251473414355200172000ustar00rootroot00000000000000/* Support for awk-style processing in C. */ #include #include #include #include #include /* I'd prefer to use the POSIX regexp interface, but for portability we need a * fallback, and supporting two regexp implementations is asking for trouble. * T-Rex is small and quick enough so we use it everywhere. However it * doesn't seem to behave properly on some expressions (which we can work * around when the regexps are fixed) so I couldn't recommend it in general. */ #include "dawk.h" #include "trex.h" typedef struct { const char *regex; TRex *reg; } re_cache_t; void (*d_cleanup)(void); static int d_argc; static char **d_argv; static int d_file_num; static FILE *d_file; dstr d_filename; int d_line_num; FILE *d_stdout; #define D_STDOUT (d_stdout ? d_stdout : stdout) #define MAX_RE_CACHE 16 static re_cache_t d_regex_cache[MAX_RE_CACHE]; static dstr d_submatches[MAX_MATCH]; dstr d_before_match; dstr d_after_match; /* Abort with an error message. */ void d_doabort(const char *filename, int line, const char *msg1, const char *msg2) { fprintf(stderr, "%s:%d: %s%s\n", filename, line, msg1, msg2); if (d_cleanup) { d_cleanup(); } exit(EXIT_FAILURE); } /* Prepare to read input from the files listed in argv. */ void d_init(int argc, char *argv[]) { d_argc = argc; d_argv = argv; d_file_num = 0; d_close_input(); } /* Open a single file for reading. */ void d_open_input(const char *filename) { if (d_file) { fclose(d_file); } d_file = fopen(filename, "r"); if (!d_file) { d_abort("could not open file for reading: ", filename); } d_assign(d_filename, filename); d_line_num = 0; d_file_num = -1; } /* Close input file. */ void d_close_input(void) { if (d_file) { fclose(d_file); } d_file = NULL; d_assign(d_filename, ""); } /* Read the next line from the current input file(s). */ bool d_getline(dstr var) { char *p = var; int c; /* Open the next file if necessary. */ if (!d_file) { if (d_file_num == -1 || d_file_num + 1 >= d_argc) { return false; } d_file_num++; d_file = fopen(d_argv[d_file_num], "r"); if (!d_file) { d_abort("could not open file for reading: ", d_argv[d_file_num]); } d_assign(d_filename, d_argv[d_file_num]); d_line_num = 0; } for (;;) { c = fgetc(d_file); if (c == EOF || c == '\n') { break; } *p++ = c; if (p - var >= MAX_STRING - 1) { fprintf(stderr, "dawk: string length limit reached\n"); break; } } *p = '\0'; if (c == EOF) { fclose(d_file); d_file = NULL; if (p == var) { return d_getline(var); } } else if (c == '\n') { d_line_num++; /* Remove trailing CR if present. */ if (p > var && p[-1] == '\r') { p[-1] = '\0'; } } return true; } /* Open a file for writing. */ void d_open_output(const char *filename) { FILE *f; d_close_output(); f = fopen(filename, "w"); if (!f) { d_abort("error opening file for writing: ", filename); } d_stdout = f; } /* Close the output file, reverting to standard output. */ void d_close_output(void) { if (d_stdout && d_stdout != stdout) { fclose(d_stdout); } d_stdout = NULL; } /* Print a line to the output file, with newline. */ void d_print(const char *s) { fprintf(D_STDOUT, "%s\n", s); } /* Print formatted output to the output file. */ void d_printf(const char *format, ...) { va_list ap; va_start(ap, format); vfprintf(D_STDOUT, format, ap); va_end(ap); } /* Assign a string. */ void d_assign(dstr to, const dstr from) { /* Might be overlapping. */ memmove(to, from, strlen(from) + 1); } /* Assign a length-delimited string. */ void d_assignn(dstr to, const dstr from, size_t n) { /* Might be overlapping. */ memmove(to, from, n); to[n] = '\0'; } static re_cache_t *compile_regex(const char *regex) { re_cache_t *re; int i; for (i = 0; i < MAX_RE_CACHE; i++) { re = &d_regex_cache[i]; if (re->regex == NULL) { re->regex = regex; re->reg = trex_compile(regex, NULL); if (re->reg == NULL) { d_abort("error compiling regular expression: ", regex); } } if (re->regex == regex) { return re; } } d_abort("too many regular expressions", ""); return NULL; } /* Match a string against the given regular expression. * Returns true on a successful match. */ bool d_match(dstr line, const char *regex) { re_cache_t *re; TRexMatch match; int i; re = compile_regex(regex); if (!trex_search(re->reg, line, NULL, NULL)) { return false; } trex_getsubexp(re->reg, 0, &match); d_assignn(d_before_match, line, match.begin - line); d_assign(d_after_match, match.begin + match.len); for (i = 0; i < MAX_MATCH; i++) { if (trex_getsubexp(re->reg, i, &match)) { if (match.begin) strncpy(d_submatches[i], match.begin, match.len); d_submatches[i][match.len] = '\0'; } else { d_submatches[i][0] = '\0'; } } return true; } /* Return a submatch from the previous d_match call. */ const char *d_submatch(int i) { return d_submatches[i]; } static const char *strrchr2(const char *s, char c1, char c2) { const char *p = s + strlen(s); for (; p >= s; p--) { if (*p == c1 || *p == c2) return p; } return NULL; } void d_basename(const char *filename, const char *newext, dstr output) { const char *start; char *dot; start = strrchr2(filename, '/', '\\'); if (start) strcpy(output, start + 1); else strcpy(output, filename); if (newext) { dot = strrchr(output, '.'); if (dot) strcpy(dot, newext); else strcat(output, newext); } } void d_tolower(const dstr src, dstr dest) { const char *s = src; char *d = dest; for (; *s; s++, d++) { *d = tolower(*s); } *d = '\0'; } void d_delchr(dstr str, char c) { const char *r = str; char *w = str; for (; *r; r++) { if (*r != c) { *w = *r; w++; } } *w = '\0'; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/dawk.h000066400000000000000000000026451473414355200172050ustar00rootroot00000000000000#ifndef __included_dawk_h #define __included_dawk_h #ifdef _MSC_VER #define bool int #define true 1 #define false 0 #else #include #endif #include #define MAX_STRING 3000 #define MAX_MATCH 8 typedef char dstr[MAX_STRING]; extern void (*d_cleanup)(void); extern dstr d_filename; extern int d_line_num; extern FILE *d_stdout; extern dstr d_before_match; extern dstr d_after_match; #define D_STDOUT (d_stdout ? d_stdout : stdout) #define d_abort(msg1, msg2) (d_doabort(__FILE__, __LINE__, (msg1), (msg2))) extern void d_doabort(const char *filename, int line, const char *msg1, const char *msg2); extern void d_init(int argc, char *argv[]); extern void d_open_input(const char *filename); extern void d_close_input(void); extern bool d_getline(dstr var); extern void d_open_output(const char *filename); extern void d_close_output(void); extern void d_print(const char *s); extern void d_printf(const char *format, ...); extern void d_assign(dstr to, const dstr from); extern void d_assignn(dstr to, const dstr from, size_t n); extern bool d_match(dstr line, const char *regex); extern const char *d_submatch(int i); extern void d_basename(const char *filename, const char *newext, dstr output); extern void d_tolower(const dstr src, dstr dest); extern void d_delchr(dstr str, char c); #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/insert_timestamp.c000066400000000000000000000037551473414355200216440ustar00rootroot00000000000000/* * Generate an fragment to be inserted at the bottom of HTML pages. * The timestamp follows RFC 3339. * We use UTC. */ #include #include #include #include #include #include #include "dawk.h" int main(int argc, char **argv) { time_t now; char buf[64]; char const *version = "unknown"; char *source_date_epoch; unsigned long long epoch; char *endptr; source_date_epoch = getenv("SOURCE_DATE_EPOCH"); if (source_date_epoch) { errno = 0; epoch = strtoull(source_date_epoch, &endptr, 10); if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0)) || (errno != 0 && epoch == 0)) { fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: strtoull: %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (endptr == source_date_epoch) { fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: No digits were found: %s\n", endptr); exit(EXIT_FAILURE); } if (*endptr != '\0') { fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: Trailing garbage: %s\n", endptr); exit(EXIT_FAILURE); } if (epoch > ULONG_MAX) { fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to %lu but was found to be: %llu \n", ULONG_MAX, epoch); exit(EXIT_FAILURE); } now = epoch; } else { now = time(NULL); } strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", gmtime(&now)); if (argc > 1) { dstr line; d_open_input(argv[1]); while (d_getline(line)) { if (d_match(line, "#define ALLEGRO_VERSION_STR *\"([^\"]*)\"")) { version = d_submatch(1); break; } } d_close_input(); } printf("

\n"); printf("Allegro version %s\n", version); printf(" - Last updated: %s\n", buf); printf("

\n"); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/make_doc.c000066400000000000000000000164341473414355200200150ustar00rootroot00000000000000/* * make_doc OPTIONS... [--] DOC-FILES * * Options are: * * --pandoc PANDOC * --protos PROTOS-FILE * --examples EXAMPLES-FILE * --to FORMAT (html, man, latex, texinfo, etc.) * --raise-sections * * Unknown options are passed through to Pandoc. */ #include #include #include #include #if defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || (_XOPEN_SOURCE >= 500) || defined(__APPLE__) #include #define USE_MKSTEMP 1 #elif defined(_MSC_VER) #define TEMPNAM(d, p) (_tempnam((d), (p))) #else #define TEMPNAM(d, p) (tempnam((d), (p))) #endif #include "aatree.h" #include "dawk.h" #include "make_doc.h" dstr pandoc = "pandoc"; dstr pandoc_options = ""; dstr protos_file = "protos"; dstr examples_file = ""; dstr to_format = "html"; dstr allegro5_cfg_filename = ""; bool raise_sections = false; dstr tmp_preprocess_output; dstr tmp_pandoc_output; dstr git_ref = "master"; static Aatree *protos = &aa_nil; static Aatree *examples = &aa_nil; static Aatree *sources = &aa_nil; static int process_options(int argc, char *argv[]); static void load_prototypes(const char *filename); static void load_examples(const char *filename); static void generate_temp_file(char *filename); static void remove_temp_files(void); int main(int argc, char *argv[]) { argc = process_options(argc, argv); load_prototypes(protos_file); load_examples(examples_file); generate_temp_file(tmp_preprocess_output); generate_temp_file(tmp_pandoc_output); d_cleanup = remove_temp_files; if (0 == strcmp(to_format, "man")) make_man_pages(argc, argv); else make_single_doc(argc, argv); d_cleanup(); return 0; } static int process_options(int argc, char *argv[]) { int i; for (i = 1; i < argc; ) { if (streq(argv[i], "--")) { i++; break; } if (argv[i][0] != '-') { break; } if (streq(argv[i], "--pandoc")) { d_assign(pandoc, argv[i + 1]); i += 2; } else if (streq(argv[i], "--protos")) { d_assign(protos_file, argv[i + 1]); i += 2; } else if (streq(argv[i], "--examples")) { d_assign(examples_file, argv[i + 1]); i += 2; } else if (streq(argv[i], "--to")) { d_assign(to_format, argv[i + 1]); i += 2; } else if (streq(argv[i], "--allegro5_cfg")) { d_assign(allegro5_cfg_filename, argv[i + 1]); i += 2; } else if (streq(argv[i], "--git_ref")) { d_assign(git_ref, argv[i + 1]); i += 2; } else if (streq(argv[i], "--raise-sections")) { raise_sections = true; i++; } else { /* Other options are assumed to be Pandoc options. */ strcat(pandoc_options, " "); strcat(pandoc_options, argv[i]); i++; if (i < argc && argv[i][0] != '-') { strcat(pandoc_options, " "); strcat(pandoc_options, argv[i]); i++; } } } /* Shift arguments, including sentinel, but not the command name. */ memmove(argv + 1, argv + i, (argc - i + 1) * sizeof(char *)); return argc - (i - 1); } static void load_prototypes(const char *filename) { dstr line; const char *name; const char *newtext; const char *file_name; const char *line_number; dstr text; d_open_input(filename); while (d_getline(line)) { if (d_match(line, "([^:]*): ([^:]*):([^:]*):([^:]*)")) { name = d_submatch(1); newtext = d_submatch(2); file_name = d_submatch(3); line_number = d_submatch(4); d_assign(text, lookup_prototype(name)); strcat(text, "\n"); strcat(text, newtext); protos = aa_insert(protos, name, text); d_assign(text, lookup_source(name)); if (strlen(text) == 0) { sprintf(text, "https://github.com/liballeg/allegro5/blob/%s/%s#L%s", git_ref, file_name, line_number); sources = aa_insert(sources, name, text); } } } d_close_input(); } static void load_examples(const char *filename) { dstr line; const char *name; const char *files; if (filename == NULL || *filename == '\0') { return; } d_open_input(filename); while (d_getline(line)) { if (d_match(line, "([^:]*): ")) { name = d_submatch(1); files = d_after_match; examples = aa_insert(examples, name, files); } } d_close_input(); } const char* example_source(dstr buffer, const char *file_name, const char *line_number) { sprintf(buffer, "https://github.com/liballeg/allegro5/blob/%s/%s#L%s", git_ref, file_name, line_number); return buffer; } char *load_allegro5_cfg(void) { FILE *f = fopen(allegro5_cfg_filename, "rb"); if (!f) { d_abort("could not open file for reading: ", allegro5_cfg_filename); } if (fseek(f, 0, SEEK_END)) { d_abort("could not seek to end: ", allegro5_cfg_filename); } long length = ftell(f); if (length == -1) { d_abort("could not tell length of file: ", allegro5_cfg_filename); } if (fseek(f, 0, SEEK_SET)) { d_abort("could not seek back to beginning: ", allegro5_cfg_filename); } char *ret = malloc(length + 1); size_t read_bytes = fread(ret, 1, length, f); if (read_bytes != (size_t)length) { d_abort("could not read file: ", allegro5_cfg_filename); } fclose(f); ret[length] = '\0'; return ret; } const char *lookup_prototype(const char *name) { const char *r = aa_search(protos, name); return (r) ? r : ""; } const char *lookup_source(const char *name) { const char *r = aa_search(sources, name); return (r) ? r : ""; } const char *lookup_example(const char *name) { return aa_search(examples, name); } void generate_temp_file(char *filename) { /* gcc won't shut up if we use tmpnam() so we'll use mkstemp() if it is * likely to be available. */ #ifdef USE_MKSTEMP int fd; d_assign(filename, "make_doc_tmp.XXXXXX"); fd = mkstemp(filename); if (fd == -1) { d_abort("could not generate temporary file name", ""); } close(fd); #else char *name = TEMPNAM(NULL, "make_doc_tmp."); if (!name) { d_abort("could not generate temporary file name", ""); } d_assign(filename, name); free(name); #endif } static void remove_temp_files(void) { remove(tmp_preprocess_output); remove(tmp_pandoc_output); } void call_pandoc(const char *input, const char *output, const char *extra_options) { dstr cmd; dstr input_native; char *p; strcpy(input_native, input); /* Use native Windows syntax to avoid "c:/foo.txt" being treated as a * remote URI by Pandoc 1.5 and 1.6. */ if (strlen(input_native) > 2 && isalpha(input_native[0]) && input_native[1] == ':') { for (p = input_native; *p != '\0'; p++) { if (*p == '/') *p = '\\'; } } sprintf(cmd, "\"%s\" %s %s %s --from markdown --to %s --output %s", pandoc, input_native, pandoc_options, extra_options, to_format, output); if (system(cmd) != 0) { d_abort("system call failed: ", cmd); } } /* Local Variables: */ /* c-basic-offset: 3 */ /* End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/make_doc.h000066400000000000000000000014561473414355200200200ustar00rootroot00000000000000#ifndef __included_make_doc_h #define __included_make_doc_h #include "dawk.h" extern dstr pandoc; extern dstr pandoc_options; extern dstr protos_file; extern dstr to_format; extern bool raise_sections; extern dstr tmp_preprocess_output; extern dstr tmp_pandoc_output; #define streq(a, b) (0 == strcmp((a), (b))) const char *lookup_prototype(const char *name); const char *lookup_source(const char *name); const char *lookup_example(const char *name); const char* example_source(dstr buffer, const char *file_name, const char *line_number); extern void call_pandoc(const char *input, const char *output, const char *extra_options); extern void make_single_doc(int argc, char *argv[]); extern void make_man_pages(int argc, char *argv[]); char *load_allegro5_cfg(void); #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/make_html_refs.c000066400000000000000000000016221473414355200212240ustar00rootroot00000000000000/* * make_html_refs DOC-FILE... * * Generate a file containing (HTML-specific) link definitions for each API * entry found. e.g. if foo.txt contains "# API: bar" then we generate: * * [bar]: foo.html#bar */ #include #include "dawk.h" /* Replicate pandoc's function to create a label anchor from the section * name. */ static void replace_spaces(char *s) { while (*s) { if (*s == ' ') *s = '-'; s++; } } int main(int argc, char *argv[]) { dstr line; dstr file; const char *name; dstr sec_id; d_init(argc, argv); while (d_getline(line)) { if (d_match(line, "^#+( API:| ) *")) { d_basename(d_filename, ".html", file); name = d_after_match; d_tolower(name, sec_id); replace_spaces(sec_id); d_printf("[%s]: %s#%s\n", name, file, sec_id); } } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/make_index.c000066400000000000000000000020401473414355200203430ustar00rootroot00000000000000/* * make_index HTML-REFS-FILE... * * Generate a file containing a list of links to all API entries. * The links are sorted using strcmp. */ #include #include #include "dawk.h" #include "aatree.h" static void print_link(const char *value) { d_printf("* [%s]\n", value); /* Work around Pandoc issue #182. */ d_printf("\n"); } static void pre_order_traversal(Aatree *node, void (*doit)(const char *)) { if (node->left != &aa_nil) { pre_order_traversal(node->left, doit); } doit(node->value); if (node->right != &aa_nil) { pre_order_traversal(node->right, doit); } } int main(int argc, char *argv[]) { dstr line; Aatree * root = &aa_nil; d_init(argc, argv); d_printf("# Index\n"); while ((d_getline(line))) { if (d_match(line, "^\\[([^\\]]*)")) { const char *ref = d_submatch(1); root = aa_insert(root, ref, ref); } } pre_order_traversal(root, print_link); aa_destroy(root); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/make_man.c000066400000000000000000000061711473414355200200200ustar00rootroot00000000000000#include #include #include "aatree.h" #include "dawk.h" #include "make_doc.h" #define MAX_NAMES 64 static const char *SECTION = "3"; static const char *MANUAL = "Allegro reference manual"; static const char *SUFFIX = "Allegro 5 API"; static dstr last_header; static dstr names[MAX_NAMES]; static void man_page_header(const char *name) { d_printf("%% %s(%s) %s\n", name, SECTION, MANUAL); d_print("# NAME"); d_print(name); d_printf(" \\- %s\n\n", SUFFIX); d_print("# SYNOPSIS"); d_print("~~~~c"); d_print(last_header); d_print(lookup_prototype(name)); d_print("~~~~"); d_print("# DESCRIPTION"); } static void call_pandoc_for_man(const char *input, int name_count) { dstr output_filename; int i; for (i = 0; i < name_count; i++) { sprintf(output_filename, "%s.%s", names[i], SECTION); call_pandoc(input, output_filename, "--standalone"); } } void make_man_pages(int argc, char *argv[]) { int output_level = 0; int name_count = 0; dstr line; d_init(argc, argv); while (d_getline(line)) { /* Stop outputting the current man page at the first line beginning with * the same or few number of hashes, i.e. at the same level or above. */ if (d_match(line, "^(#+) ") && output_level > 0) { int n = strlen(d_submatch(1)); if (n <= output_level) { d_close_output(); call_pandoc_for_man(tmp_preprocess_output, name_count); name_count = 0; output_level = 0; } } if (d_match(line, "^ *(#include.*)") && output_level == 0) { d_assign(last_header, d_submatch(1)); continue; } if (d_match(line, "^(#+) API: *(.*)")) { const char *hashes = d_submatch(1); const char *name = d_submatch(2); if (output_level == 0) { output_level = strlen(hashes); d_open_output(tmp_preprocess_output); man_page_header(name); } else { d_printf("%s %s\n", hashes, name); } if (name_count < MAX_NAMES) { d_assign(names[name_count], name); name_count++; } continue; } if (!output_level) { continue; } if (d_match(line, "^\\*?Return [Vv]alue:\\*?")) { d_print("# RETURN VALUE"); d_assign(line, d_after_match); } if (d_match(line, "^\\*?Since:\\*?")) { d_print("# SINCE"); d_assign(line, d_after_match); } if (d_match(line, "^\\*?See [Aa]lso:\\*?")) { d_print("# SEE ALSO"); d_assign(line, d_after_match); } /* Replace [al_foo] and [ALLEGRO_foo] by al_foo(3) and ALLEGRO_foo(3). */ while (d_match(line, "\\[((al_|ALLEGRO_)[^\\]]*)\\]")) { d_printf("%s", d_before_match); d_printf("%s(%s)", d_submatch(1), SECTION); d_assign(line, d_after_match); } d_print(line); } if (output_level > 0) { d_close_output(); call_pandoc_for_man(tmp_preprocess_output, name_count); name_count = 0; output_level = 0; } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/make_protos.c000066400000000000000000000023411473414355200205660ustar00rootroot00000000000000/* * make_protos SOURCE-FILE... * * Extract all the function prototypes and type/enum declarations which have * Natural Docs tags Function: Type: Enum: and print them to standard output. */ #include "dawk.h" int main(int argc, char *argv[]) { bool found_tag = false; bool do_print = false; dstr line = ""; dstr prefix = ""; d_init(argc, argv); while (d_getline(line)) { if (d_match(line, "/[*] (Function|Type|Enum): (.*)")) { found_tag = true; do_print = false; d_assign(prefix, d_submatch(2)); continue; } if (found_tag && d_match(line, "^ ?\\*/")) { found_tag = false; do_print = true; continue; } if (d_match(line, "^\\{|^$")) { do_print = false; continue; } /* Prototype ends on blank line. */ /* TODO: Should the above regexp match it? If so it doesn't here... */ if (line[0] == 0) { do_print = false; continue; } if (do_print) { printf("%s: %s:%s:%d\n", prefix, line, d_filename, d_line_num); } if (d_match(line, "\\{ *$|; *$")) { do_print = false; } } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/make_search_index.c000066400000000000000000000017731473414355200217040ustar00rootroot00000000000000/* * make_search_index html_refs > search_index.js * * Read html_refs and convert it to a Javascript index for autosuggest.js. */ #include #include #include "dawk.h" dstr *names; dstr *urls; int num_entries = 0; static int add_entry(void) { int i = num_entries++; names = realloc(names, num_entries * sizeof *names); urls = realloc(urls, num_entries * sizeof *urls); return i; } int main(int argc, char *argv[]) { dstr line; int i; d_init(argc, argv); while (d_getline(line)) { if (d_match(line, "^\\[(.*)\\]: (.*)")) { int i = add_entry(); strcpy(names[i], d_submatch(1)); strcpy(urls[i], d_submatch(2)); } } printf("var search_index = [\n"); for (i = 0; i < num_entries; i++) { printf("'%s',", names[i]); } printf("]\n"); printf("var search_urls = [\n"); for (i = 0; i < num_entries; i++) { printf("'%s',", urls[i]); } printf("]\n"); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/make_single.c000066400000000000000000000111201473414355200205140ustar00rootroot00000000000000#include #include #include "dawk.h" #include "make_doc.h" static void preprocess(void); static void postprocess_latex(void); static void cat(void); static void print_sans_backslashes(const char *p); static void insert_examples(void); static char current_api[64]; void make_single_doc(int argc, char *argv[]) { d_init(argc, argv); /* Hidden format for debugging. */ if (streq(to_format, "preprocess")) { preprocess(); return; } d_open_output(tmp_preprocess_output); preprocess(); d_close_output(); call_pandoc(tmp_preprocess_output, tmp_pandoc_output, ""); d_open_input(tmp_pandoc_output); if (streq(to_format, "latex")) postprocess_latex(); else cat(); d_close_input(); } static void preprocess(void) { dstr line; while (d_getline(line)) { /* If this is a heading, a new section is about to start. Insert the pending code examples (if any) beforehand. */ if (line[0] == '#') { insert_examples(); } /* Raise sections by one level. Top-most becomes the document title. */ if (line[0] == '#' && raise_sections) { if (line[1] == ' ') { line[0] = '%'; } else { char *p = strchr(line, ' '); if (p) { p[-1] = ' '; } } } /* Make sure there is a blank line between input files so paragraphs * across files don't get merged. But don't break document titles which * must be on the first line. */ if (d_line_num == 1 && line[0] != '%') { d_print(""); } if (d_match(line, "^(#+) +API: *")) { const char *hashes = d_submatch(1); const char *name = d_after_match; const char *text = lookup_prototype(name); const char *source = lookup_source(name); d_printf("%s %s\n", hashes, name); if (strcmp(text, "") != 0) { d_printf("~~~~c"); d_print(text); d_printf("~~~~"); } d_printf("\n[Source Code](%s)\n", source); strcpy(current_api, name); } else if (d_match(line, "^__ALLEGRO_5_CFG")) { char *allegro5_cfg = load_allegro5_cfg(); d_print(allegro5_cfg); free(allegro5_cfg); } else { d_print(line); } } /* Finally insert any examples for the last section */ insert_examples(); } static void postprocess_latex(void) { dstr line; while (d_getline(line)) { /* Insert \label{id} for all sections which are probably API entries. * T-Rex doesn't seem to backtrack properly if we write "(sub)*". */ if (d_match(line, "\\\\(sub)?(sub)?(sub)?(sub)?section\\{((al|ALLEGRO)[^}]+)")) { d_print(line); d_printf("\\label{"); print_sans_backslashes(d_submatch(5)); d_printf("}\n"); continue; } /* Replace `verbatim' environment by `Verbatim' from fancyvrb, * which gives us some flexibility over the formatting. */ if (d_match(line, "\\\\begin\\{verbatim\\}$")) { d_printf("%s", d_before_match); d_print("\\begin{Verbatim}"); continue; } if (d_match(line, "\\\\end\\{verbatim\\}$")) { d_printf("%s", d_before_match); d_print("\\end{Verbatim}"); continue; } d_print(line); } } static void cat(void) { dstr line; while (d_getline(line)) d_print(line); } static void print_sans_backslashes(const char *p) { for (; *p; p++) { if (*p != '\\') fputc(*p, D_STDOUT); } } static void insert_examples(void) { if (*current_api) { const char* exs = lookup_example(current_api); if (exs) { /* This will be of the form "FILE:LINE FILE:LINE FILE:LINE " */ dstr items; char* pitem = strcpy(items, exs); d_print("Examples:\n"); char* item; for (item = strtok(pitem, " "); item; item = strtok(NULL, " ")) { dstr buffer; char* colon = strchr(item, ':'); if (colon) { char* filename = item; char* line = colon + 1; *colon = '\0'; dstr base; d_basename(filename, NULL, base); d_printf("* [%s](%s)\n", base, example_source(buffer, filename, line)); } } d_print(""); } strcpy(current_api, ""); } } /* Local Variables: */ /* c-basic-offset: 3 */ /* indent-tabs-mode: nil */ /* End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/scan_examples.c000066400000000000000000000141131473414355200210650ustar00rootroot00000000000000/* * scan_examples OPTIONS EXAMPLE-FILES * * Load a prototypes file containing API elements * and scan files for examples using those elements * Output is to standard output and comprises lines * of the form "API: FILE:LINE FILE:LINE FILE:LINE" * No more than 3 examples will be output for each * API. * * Options are: * --protos PROTOS-FILE * * It is possible to use a response file to specify * options or files. Including @FILENAME on the * command line will read that file line-by-line * and insert each line as if it were specified on * the command line. This is to avoid very long * command lines. */ #include #include #include #include "dawk.h" #define SL_INITIAL_CAPACITY 64 #define EXAMPLES_PER_API 3 static dstr protos; typedef struct { char **items; int count; int capacity; } slist_t; static void sl_init(slist_t *); static void sl_free(slist_t *); static void sl_clear(slist_t *); static void sl_append(slist_t *, const char *); static void cleanup(void); static void load_api_list(void); static slist_t apis; static char **responsefile(int* pargc, char **argv); /* Table of which APIs are in which examples */ static int *table; /* Lookup to index the best examples */ typedef struct { /* Index into table */ int index; /* How many APIs are used in each example */ int count; /* Store a pointer to the file string for comparison purposes */ char *filename; } lookup_t; static lookup_t *lookup; static int compare(const void *pa, const void *pb) { int val = ((const lookup_t *) pa)->count - ((const lookup_t *) pb)->count; // if different count values, sort according to this. if (val != 0) return val; // But if the count value is the same, sort according to filename return strcmp( (char*)((const lookup_t *) pa)->filename, (char*)((const lookup_t *) pb)->filename); } int main(int argc, char* argv[]) { dstr line; int i, j; argv = responsefile(&argc, argv); /* Handle --protos flag */ if (argc >=3 && strcmp(argv[1], "--protos") == 0) { strcpy(protos, argv[2]); memmove(&argv[1], &argv[3], (&argv[argc] - &argv[3]) * sizeof(char*)); argc -= 2; } else { strcpy(protos, "protos"); } d_cleanup = cleanup; sl_init(&apis); load_api_list(); table = calloc(apis.count * argc, sizeof(int)); lookup = calloc(argc, sizeof(lookup_t)); for (j = 0; j < argc; ++j) { lookup[j].index = j; lookup[j].filename = argv[j]; } for (j = 1; j < argc; ++j) { d_open_input(argv[j]); while (d_getline(line)) { for (i = 0; i < apis.count; ++i) { if (strstr(line, apis.items[i])) { int *ptr = &table[i + j * apis.count]; if (*ptr == 0) { *ptr = d_line_num; ++lookup[j].count; } } } } d_close_input(); } /* Sort the files */ qsort(lookup, argc, sizeof(lookup_t), compare); /* Output the EXAMPLES_PER_API (three) 'best' examples. * * The 'best' is defined as the probability of having a usage of an API in * the set of all other API usages in the example. Effectively, this means * that examples with fewer other APIs showcased get selected. */ for (i = 0; i < apis.count; ++i) { int found = 0; for (j = 0; j < argc && found < EXAMPLES_PER_API; ++j) { int index = lookup[j].index; int line_num = table[i + index * apis.count]; if (line_num != 0) { if (found == 0) { d_printf("%s: ", apis.items[i]); } ++found; d_printf("%s:%d ", argv[index], line_num); } } if (found > 0) { d_print("\n"); } } d_cleanup(); return 0; } void cleanup(void) { free(table); free(lookup); sl_free(&apis); } void sl_init(slist_t* s) { s->items = NULL; s->count = s->capacity = 0; } void sl_append(slist_t *s, const char *item) { if (s->count == s->capacity) { int capacity = s->capacity == 0 ? SL_INITIAL_CAPACITY : (s->capacity * 2); s->items = realloc(s->items, capacity * sizeof(char*)); s->capacity = capacity; } s->items[s->count++] = strcpy(malloc(1+strlen(item)), item); } void sl_free(slist_t *s) { sl_clear(s); free(s->items); s->items = NULL; s->capacity = 0; } void sl_clear(slist_t *s) { int i; for (i = 0; i < s->count; ++i) { free(s->items[i]); } s->count = 0; } void load_api_list(void) { dstr line; d_open_input(protos); while (d_getline(line)) { int i; bool found = false; char *ptr = strchr(line, ':'); if (ptr) { *ptr = '\0'; for (i = apis.count - 1; i >=0; --i) { if (strcmp(line, apis.items[i]) == 0) { found = true; break; } } } if (!found) { sl_append(&apis, line); } } d_close_input(); } /* Re-process the command line args by loading any response files */ char **responsefile(int *pargc, char **argv) { static slist_t args; static char** new_argv; int argc = *pargc; int i; bool found_at = false; for (i = 1; i < argc; ++i) { if (*argv[i] == '@') { found_at = true; break; } } if (!found_at) { /* Nothing to do */ return argv; } sl_clear(&args); for (i = 0; i < argc; ++i) { if (*argv[i] == '@') { d_open_input(argv[i] + 1); dstr line; while (d_getline(line)) { sl_append(&args, line); } d_close_input(); } else { sl_append(&args, argv[i]); } } /* Make a copy because code might alter the argv array */ new_argv = realloc(new_argv, args.count * sizeof(char*)); memcpy(new_argv, args.items, args.count * sizeof(char*)); *pargc = args.count; return new_argv; } /* Local Variables: */ /* c-basic-offset: 3 */ /* indent-tabs-mode: nil */ /* End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/docs/scripts/trex.c000066400000000000000000000405641473414355200172360ustar00rootroot00000000000000/* see copyright notice in trex.h */ /* This copy contains minor changes by Allegro developers to prevent some * compiler warnings. One change makes trex_compile non-reentrant. */ #include #include #include #include #include "trex.h" #ifdef _UINCODE #define scisprint iswprint #define scstrlen wcslen #define scprintf wprintf #define _SC(x) L(x) #else #define scisprint isprint #define scstrlen strlen #define scprintf printf #define _SC(x) (x) #endif #ifdef TREX_DEBUG #include static const TRexChar *g_nnames[] = { _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"), _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"), _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"), _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB") }; #endif #define OP_GREEDY (MAX_CHAR+1) // * + ? {n} #define OP_OR (MAX_CHAR+2) #define OP_EXPR (MAX_CHAR+3) //parentesis () #define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:) #define OP_DOT (MAX_CHAR+5) #define OP_CLASS (MAX_CHAR+6) #define OP_CCLASS (MAX_CHAR+7) #define OP_NCLASS (MAX_CHAR+8) //negates class the [^ #define OP_RANGE (MAX_CHAR+9) #define OP_CHAR (MAX_CHAR+10) #define OP_EOL (MAX_CHAR+11) #define OP_BOL (MAX_CHAR+12) #define OP_WB (MAX_CHAR+13) #define TREX_SYMBOL_ANY_CHAR ('.') #define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+') #define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*') #define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?') #define TREX_SYMBOL_BRANCH ('|') #define TREX_SYMBOL_END_OF_STRING ('$') #define TREX_SYMBOL_BEGINNING_OF_STRING ('^') #define TREX_SYMBOL_ESCAPE_CHAR ('\\') typedef int TRexNodeType; typedef struct tagTRexNode{ TRexNodeType type; int left; int right; int next; }TRexNode; struct TRex{ const TRexChar *_eol; const TRexChar *_bol; const TRexChar *_p; int _first; int _op; TRexNode *_nodes; int _nallocated; int _nsize; int _nsubexpr; TRexMatch *_matches; int _currsubexp; void *_jmpbuf; const TRexChar **_error; }; static int trex_list(TRex *exp); static int trex_newnode(TRex *exp, TRexNodeType type) { TRexNode n; int newid; n.type = type; n.next = n.right = n.left = -1; if(type == OP_EXPR) n.right = exp->_nsubexpr++; if(exp->_nallocated < (exp->_nsize + 1)) { /* int oldsize = exp->_nallocated; */ exp->_nallocated *= 2; exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode)); } exp->_nodes[exp->_nsize++] = n; newid = exp->_nsize - 1; return (int)newid; } static void trex_error(TRex *exp,const TRexChar *error) { if(exp->_error) *exp->_error = error; longjmp(*((jmp_buf*)exp->_jmpbuf),-1); } static void trex_expect(TRex *exp, int n){ if((*exp->_p) != n) trex_error(exp, _SC("expected paren")); exp->_p++; } static TRexChar trex_escapechar(TRex *exp) { if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){ exp->_p++; switch(*exp->_p) { case 'v': exp->_p++; return '\v'; case 'n': exp->_p++; return '\n'; case 't': exp->_p++; return '\t'; case 'r': exp->_p++; return '\r'; case 'f': exp->_p++; return '\f'; default: return (*exp->_p++); } } else if(!scisprint(*exp->_p)) trex_error(exp,_SC("letter expected")); return (*exp->_p++); } static int trex_charclass(TRex *exp,int classid) { int n = trex_newnode(exp,OP_CCLASS); exp->_nodes[n].left = classid; return n; } static int trex_charnode(TRex *exp,TRexBool isclass) { TRexChar t; if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) { exp->_p++; switch(*exp->_p) { case 'n': exp->_p++; return trex_newnode(exp,'\n'); case 't': exp->_p++; return trex_newnode(exp,'\t'); case 'r': exp->_p++; return trex_newnode(exp,'\r'); case 'f': exp->_p++; return trex_newnode(exp,'\f'); case 'v': exp->_p++; return trex_newnode(exp,'\v'); case 'a': case 'A': case 'w': case 'W': case 's': case 'S': case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': case 'p': case 'P': case 'l': case 'u': { t = *exp->_p; exp->_p++; return trex_charclass(exp,t); } case 'b': case 'B': if(!isclass) { int node = trex_newnode(exp,OP_WB); exp->_nodes[node].left = *exp->_p; exp->_p++; return node; } //else default /* Intentional fallthrough */ default: t = *exp->_p; exp->_p++; return trex_newnode(exp,t); } } else if(!scisprint(*exp->_p)) { trex_error(exp,_SC("letter expected")); } t = *exp->_p; exp->_p++; return trex_newnode(exp,t); } static int trex_class(TRex *exp) { int ret = -1; int first = -1,chain; if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){ ret = trex_newnode(exp,OP_NCLASS); exp->_p++; }else ret = trex_newnode(exp,OP_CLASS); if(*exp->_p == ']') trex_error(exp,_SC("empty class")); chain = ret; while(*exp->_p != ']' && exp->_p != exp->_eol) { if(*exp->_p == '-' && first != -1){ int r,t; if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range")); r = trex_newnode(exp,OP_RANGE); if(first>*exp->_p) trex_error(exp,_SC("invalid range")); if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges")); exp->_nodes[r].left = exp->_nodes[first].type; t = trex_escapechar(exp); exp->_nodes[r].right = t; exp->_nodes[chain].next = r; chain = r; first = -1; } else{ if(first!=-1){ int c = first; exp->_nodes[chain].next = c; chain = c; first = trex_charnode(exp,TRex_True); } else{ first = trex_charnode(exp,TRex_True); } } } if(first!=-1){ int c = first; exp->_nodes[chain].next = c; chain = c; first = -1; } /* hack? */ exp->_nodes[ret].left = exp->_nodes[ret].next; exp->_nodes[ret].next = -1; return ret; } static int trex_parsenumber(TRex *exp) { int ret = *exp->_p-'0'; int positions = 10; exp->_p++; while(isdigit(*exp->_p)) { ret = ret*10+(*exp->_p++-'0'); if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant")); positions *= 10; }; return ret; } static int trex_element(TRex *exp) { int ret = -1; switch(*exp->_p) { case '(': { int expr,newn; exp->_p++; if(*exp->_p =='?') { exp->_p++; trex_expect(exp,':'); expr = trex_newnode(exp,OP_NOCAPEXPR); } else expr = trex_newnode(exp,OP_EXPR); newn = trex_list(exp); exp->_nodes[expr].left = newn; ret = expr; trex_expect(exp,')'); } break; case '[': exp->_p++; ret = trex_class(exp); trex_expect(exp,']'); break; case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break; case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break; default: ret = trex_charnode(exp,TRex_False); break; } { TRexBool isgreedy = TRex_False; unsigned short p0 = 0, p1 = 0; switch(*exp->_p){ case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break; case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break; case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break; case '{': exp->_p++; if(!isdigit(*exp->_p)) trex_error(exp,_SC("number expected")); p0 = (unsigned short)trex_parsenumber(exp); /*******************************/ switch(*exp->_p) { case '}': p1 = p0; exp->_p++; break; case ',': exp->_p++; p1 = 0xFFFF; if(isdigit(*exp->_p)){ p1 = (unsigned short)trex_parsenumber(exp); } trex_expect(exp,'}'); break; default: trex_error(exp,_SC(", or } expected")); } /*******************************/ isgreedy = TRex_True; break; } if(isgreedy) { int nnode = trex_newnode(exp,OP_GREEDY); exp->_nodes[nnode].left = ret; exp->_nodes[nnode].right = ((p0)<<16)|p1; ret = nnode; } } if((*exp->_p != TREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != TREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != TREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) { int nnode = trex_element(exp); exp->_nodes[ret].next = nnode; } return ret; } static int trex_list(TRex *exp) { int ret=-1,e; if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) { exp->_p++; ret = trex_newnode(exp,OP_BOL); } e = trex_element(exp); if(ret != -1) { exp->_nodes[ret].next = e; } else ret = e; if(*exp->_p == TREX_SYMBOL_BRANCH) { int temp,tright; exp->_p++; temp = trex_newnode(exp,OP_OR); exp->_nodes[temp].left = ret; tright = trex_list(exp); exp->_nodes[temp].right = tright; ret = temp; } return ret; } static TRexBool trex_matchcclass(int cclass,TRexChar c) { switch(cclass) { case 'a': return isalpha(c)?TRex_True:TRex_False; case 'A': return !isalpha(c)?TRex_True:TRex_False; case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False; case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False; case 's': return isspace(c)?TRex_True:TRex_False; case 'S': return !isspace(c)?TRex_True:TRex_False; case 'd': return isdigit(c)?TRex_True:TRex_False; case 'D': return !isdigit(c)?TRex_True:TRex_False; case 'x': return isxdigit(c)?TRex_True:TRex_False; case 'X': return !isxdigit(c)?TRex_True:TRex_False; case 'c': return iscntrl(c)?TRex_True:TRex_False; case 'C': return !iscntrl(c)?TRex_True:TRex_False; case 'p': return ispunct(c)?TRex_True:TRex_False; case 'P': return !ispunct(c)?TRex_True:TRex_False; case 'l': return islower(c)?TRex_True:TRex_False; case 'u': return isupper(c)?TRex_True:TRex_False; } return TRex_False; /*cannot happen*/ } static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c) { do { switch(node->type) { case OP_RANGE: if(c >= node->left && c <= node->right) return TRex_True; break; case OP_CCLASS: if(trex_matchcclass(node->left,c)) return TRex_True; break; default: if(c == node->type)return TRex_True; } } while((node->next != -1) && (node = &exp->_nodes[node->next])); return TRex_False; } static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next) { TRexNodeType type = node->type; switch(type) { case OP_GREEDY: { //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL; TRexNode *greedystop = NULL; int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0; const TRexChar *s=str, *good = str; if(node->next != -1) { greedystop = &exp->_nodes[node->next]; } else { greedystop = next; } while((nmaches == 0xFFFF || nmaches < p1)) { const TRexChar *stop; if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop))) break; nmaches++; good=s; if(greedystop) { //checks that 0 matches satisfy the expression(if so skips) //if not would always stop(for instance if is a '?') if(greedystop->type != OP_GREEDY || (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0)) { TRexNode *gnext = NULL; if(greedystop->next != -1) { gnext = &exp->_nodes[greedystop->next]; }else if(next && next->next != -1){ gnext = &exp->_nodes[next->next]; } stop = trex_matchnode(exp,greedystop,s,gnext); if(stop) { //if satisfied stop it if(p0 == p1 && p0 == nmaches) break; else if(nmaches >= p0 && p1 == 0xFFFF) break; else if(nmaches >= p0 && nmaches <= p1) break; } } } if(s >= exp->_eol) break; } if(p0 == p1 && p0 == nmaches) return good; else if(nmaches >= p0 && p1 == 0xFFFF) return good; else if(nmaches >= p0 && nmaches <= p1) return good; return NULL; } case OP_OR: { const TRexChar *asd = str; TRexNode *temp=&exp->_nodes[node->left]; while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) { if(temp->next != -1) temp = &exp->_nodes[temp->next]; else return asd; } asd = str; temp = &exp->_nodes[node->right]; while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) { if(temp->next != -1) temp = &exp->_nodes[temp->next]; else return asd; } return NULL; break; } case OP_EXPR: case OP_NOCAPEXPR:{ TRexNode *n = &exp->_nodes[node->left]; const TRexChar *cur = str; int capture = -1; if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) { capture = exp->_currsubexp; exp->_matches[capture].begin = cur; exp->_currsubexp++; } do { TRexNode *subnext = NULL; if(n->next != -1) { subnext = &exp->_nodes[n->next]; }else { subnext = next; } if(!(cur = trex_matchnode(exp,n,cur,subnext))) { if(capture != -1){ exp->_matches[capture].begin = 0; exp->_matches[capture].len = 0; } return NULL; } } while((n->next != -1) && (n = &exp->_nodes[n->next])); if(capture != -1) exp->_matches[capture].len = cur - exp->_matches[capture].begin; return cur; } case OP_WB: if((str == exp->_bol && !isspace(*str)) || (str == exp->_eol && !isspace(*(str-1))) || (!isspace(*str) && isspace(*(str+1))) || (isspace(*str) && !isspace(*(str+1))) ) { return (node->left == 'b')?str:NULL; } return (node->left == 'b')?NULL:str; case OP_BOL: if(str == exp->_bol) return str; return NULL; case OP_EOL: if(str == exp->_eol) return str; return NULL; case OP_DOT:{ str++; } return str; case OP_NCLASS: case OP_CLASS: if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) { str++; return str; } return NULL; case OP_CCLASS: if(trex_matchcclass(node->left,*str)) { str++; return str; } return NULL; default: /* char */ if(*str != node->type) return NULL; str++; return str; } return NULL; } /* public api */ TRex *trex_compile(const TRexChar *pattern,const TRexChar **error) { /* Prevent warnings about variables being lost across setjmp. Of course * this makes the code non-reentrant but make_doc doesn't mind. --pw */ static TRex *exp; exp = (TRex *)malloc(sizeof(TRex)); exp->_eol = exp->_bol = NULL; exp->_p = pattern; exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar); exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode)); exp->_nsize = 0; exp->_matches = 0; exp->_nsubexpr = 0; exp->_first = trex_newnode(exp,OP_EXPR); exp->_error = error; exp->_jmpbuf = malloc(sizeof(jmp_buf)); if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) { int res = trex_list(exp); exp->_nodes[exp->_first].left = res; if(*exp->_p!='\0') trex_error(exp,_SC("unexpected character")); #ifdef TREX_DEBUG { int nsize,i; TRexNode *t; nsize = exp->_nsize; t = &exp->_nodes[0]; scprintf(_SC("\n")); for(i = 0;i < nsize; i++) { if(exp->_nodes[i].type>MAX_CHAR) scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]); else scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type); scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next); } scprintf(_SC("\n")); } #endif exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch)); memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch)); } else{ trex_free(exp); return NULL; } return exp; } void trex_free(TRex *exp) { if(exp) { if(exp->_nodes) free(exp->_nodes); if(exp->_jmpbuf) free(exp->_jmpbuf); if(exp->_matches) free(exp->_matches); free(exp); } } TRexBool trex_match(TRex* exp,const TRexChar* text) { const TRexChar* res = NULL; exp->_bol = text; exp->_eol = text + scstrlen(text); exp->_currsubexp = 0; res = trex_matchnode(exp,exp->_nodes,text,NULL); if(res == NULL || res != exp->_eol) return TRex_False; return TRex_True; } TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end) { const TRexChar *cur = NULL; int node = exp->_first; if(text_begin >= text_end) return TRex_False; exp->_bol = text_begin; exp->_eol = text_end; do { cur = text_begin; while(node != -1) { exp->_currsubexp = 0; cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL); if(!cur) break; node = exp->_nodes[node].next; } text_begin++; } while(cur == NULL && text_begin != text_end); if(cur == NULL) return TRex_False; --text_begin; if(out_begin) *out_begin = text_begin; if(out_end) *out_end = cur; return TRex_True; } TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) { return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end); } int trex_getsubexpcount(TRex* exp) { return exp->_nsubexpr; } TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp) { if( n<0 || n >= exp->_nsubexpr) return TRex_False; *subexp = exp->_matches[n]; return TRex_True; } allegro5-5.2.10.1/docs/scripts/trex.h000066400000000000000000000041551473414355200172370ustar00rootroot00000000000000#ifndef _TREX_H_ #define _TREX_H_ /*************************************************************** T-Rex a tiny regular expression library Copyright (C) 2003-2006 Alberto Demichelis 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. ****************************************************************/ #ifdef _UNICODE #define TRexChar unsigned short #define MAX_CHAR 0xFFFF #define _TREXC(c) L##c #define trex_strlen wcslen #define trex_printf wprintf #else #define TRexChar char #define MAX_CHAR 0xFF #define _TREXC(c) (c) #define trex_strlen strlen #define trex_printf printf #endif #ifndef TREX_API #define TREX_API extern #endif #define TRex_True 1 #define TRex_False 0 typedef unsigned int TRexBool; typedef struct TRex TRex; typedef struct { const TRexChar *begin; int len; } TRexMatch; TREX_API TRex *trex_compile(const TRexChar *pattern,const TRexChar **error); TREX_API void trex_free(TRex *exp); TREX_API TRexBool trex_match(TRex* exp,const TRexChar* text); TREX_API TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end); TREX_API TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end); TREX_API int trex_getsubexpcount(TRex* exp); TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp); #endif allegro5-5.2.10.1/docs/scripts/trex.txt000066400000000000000000000126151473414355200176270ustar00rootroot00000000000000T-REX 1.3 http://tiny-rex.sourceforge.net ---------------------------------------------------------------------- T-Rex a tiny regular expression library Copyright (C) 2003-2006 Alberto Demichelis 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. ---------------------------------------------------------------------- TRex implements the following expressions \ Quote the next metacharacter ^ Match the beginning of the string . Match any character $ Match the end of the string | Alternation () Grouping (creates a capture) [] Character class ==GREEDY CLOSURES== * Match 0 or more times + Match 1 or more times ? Match 1 or 0 times {n} Match exactly n times {n,} Match at least n times {n,m} Match at least n but not more than m times ==ESCAPE CHARACTERS== \t tab (HT, TAB) \n newline (LF, NL) \r return (CR) \f form feed (FF) ==PREDEFINED CLASSES== \l lowercase next char \u uppercase next char \a letters \A non letters \w alphanimeric [0-9a-zA-Z] \W non alphanimeric \s space \S non space \d digits \D non nondigits \x exadecimal digits \X non exadecimal digits \c control charactrs \C non control charactrs \p punctation \P non punctation \b word boundary \B non word boundary ---------------------------------------------------------------------- API DOC ---------------------------------------------------------------------- TRex *trex_compile(const TRexChar *pattern,const TRexChar **error); compiles an expression and returns a pointer to the compiled version. in case of failure returns NULL.The returned object has to be deleted through the function trex_free(). pattern a pointer to a zero terminated string containing the pattern that has to be compiled. error apointer to a string pointer that will be set with an error string in case of failure. ---------------------------------------------------------------------- void trex_free(TRex *exp) deletes a expression structure created with trex_compile() exp the expression structure that has to be deleted ---------------------------------------------------------------------- TRexBool trex_match(TRex* exp,const TRexChar* text) returns TRex_True if the string specified in the parameter text is an exact match of the expression, otherwise returns TRex_False. exp the compiled expression text the string that has to be tested ---------------------------------------------------------------------- TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) searches the first match of the expressin in the string specified in the parameter text. if the match is found returns TRex_True and the sets out_begin to the beginning of the match and out_end at the end of the match; otherwise returns TRex_False. exp the compiled expression text the string that has to be tested out_begin a pointer to a string pointer that will be set with the beginning of the match out_end a pointer to a string pointer that will be set with the end of the match ---------------------------------------------------------------------- TREX_API TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end) searches the first match of the expressin in the string delimited by the parameter text_begin and text_end. if the match is found returns TRex_True and the sets out_begin to the beginning of the match and out_end at the end of the match; otherwise returns TRex_False. exp the compiled expression text_begin a pointer to the beginnning of the string that has to be tested text_end a pointer to the end of the string that has to be tested out_begin a pointer to a string pointer that will be set with the beginning of the match out_end a pointer to a string pointer that will be set with the end of the match ---------------------------------------------------------------------- int trex_getsubexpcount(TRex* exp) returns the number of sub expressions matched by the expression exp the compiled expression --------------------------------------------------------------------- TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *submatch) retrieve the begin and and pointer to the length of the sub expression indexed by n. The result is passed trhough the struct TRexMatch: typedef struct { const TRexChar *begin; int len; } TRexMatch; the function returns TRex_True if n is valid index otherwise TRex_False. exp the compiled expression n the index of the submatch submatch a pointer to structure that will store the result this function works also after a match operation has been performend. allegro5-5.2.10.1/docs/src/000077500000000000000000000000001473414355200151775ustar00rootroot00000000000000allegro5-5.2.10.1/docs/src/autosuggest.js000066400000000000000000001067761473414355200201300ustar00rootroot00000000000000/* Auto-suggest control, modified for Allegro's purposes. * * The original copyright notice follows: * * Auto-suggest control, version 2.4, October 10th 2009. * * (c) 2007-2009 Dmitriy Khudorozhkov (dmitrykhudorozhkov@yahoo.com) * * Latest version download and documentation: * http://www.codeproject.com/KB/scripting/AutoSuggestControl.aspx * * Based on "Auto-complete Control" by zichun: * http://www.codeproject.com/KB/scripting/jsactb.aspx * * This software is provided "as-is", without any express or implied warranty. * In no event will the author 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. */ var autosuggest_url = ""; // Global link to the server-side script, that gives you the suggestion list. // Used for controls that do not define their own server script urls. function autosuggest(id, array, url, onSelect) { var field = document.getElementById(id); var exists = field.autosuggest; if(exists) return exists; // "Public" variables: this.time_out = 0; // autocomplete timeout, in milliseconds (0: autocomplete never times out) this.response_time = 250; // time, in milliseconds, between the last char typed and the actual query this.entry_limit = 10; // number of entries autocomplete will show at a time this.limit_start = false; // should the auto complete be limited to the beginning of keyword? this.match_first = true; // if previous is false, should the exact matches be displayed first? this.restrict_typing = false; // restrict to existing members of array this.full_refresh = false; // should the script re-send the AJAX request after each typed character? this.use_iframe = true; // should the control use an IFrame element to fix suggestion list positioning (MS IE only)? this.use_scroll = true; // should the control use a scroll bar (true) or a up/down arrow-buttons (false)? this.use_mouse = true; // enable mouse support this.no_default = false; // should the control omit selecting the 1st item in a suggestion list? this.start_check = 0; // show widget only after this number of characters is typed in (effective if >1) this.text_delimiter = [";", ","]; // delimiter for multiple autocomplete entries. Set it to empty array ( [] ) for single autocomplete. this.ajax_delimiter = "|"; // character that delimits entries in the string returned by AJAX call this.item_delimiter = ","; // character that delimits key and value for the suggestion item in the string returned by AJAX call this.selectedIndex = -1; // index (zero-based) of the entry last selected this.min_results = 5; // minimum number of results to return // "Private" variables: this.suggest_url = url || (array ? "" : autosuggest_url); // URL the server-side script that gives you the suggestion list this.msie = (document.all && !window.opera); this.displayed = false; this.delim_words = []; this.current_word = 0; this.delim_char = []; this.current = 0; this.total = 0; this.range_up = 0; this.range_down = 0; this.previous = 0; this.timer = 0; this.rebuild = false; this.evsetup = false; this.bool = []; this.rows = []; this.onSelect = onSelect || null; this.cur_x = 0; this.cur_y = 0; this.cur_w = 0; this.cur_h = 0; this.mouse_x = 0; this.mouse_y = 0; this.mouse_on_list = 0; this.caret_moved = false; this.field_id = id; this.field = field; this.lastterm = field.value; this.keywords = [], this.keywords_init = []; this.values = [], this.values_init = []; return this.construct(array || []); }; autosuggest.prototype = { construct: function(array) { function callLater(func, obj, param1, param2) { return function() { func.call(obj, param1 || null, param2 || null) }; } this.field.autosuggest = this; // Initialize the control from JS array, if any: this.bindArray(array); // Create event handlers: this.funcClick = this.mouseClick; this.funcCheck = this.checkKey; this.funcPress = this.keyPress; this.funcHighlight = this.highlightTable; this.funcClear = callLater(this.clearEvents, this); this.funcUp = callLater(this.scroll, this, true, 1); this.funcDown = callLater(this.scroll, this, false, 1); this.funcFocus = callLater(this.focusTable, this); this.funcUnfocus = callLater(this.unfocusTable, this); this.addEvent(this.field, "focus", callLater(this.setupEvents, this)); this.addEvent(window, "resize", callLater(this.reposition, this)); var obj = this; this.addEvent(document, "keypress", function(event) { obj.funcShortcut(obj, event); }); this.addEvent(document, "keydown", function(event) { obj.funcShortcut(obj, event); }); return this; }, funcShortcut: function(obj, event) { event = event || window.event; var s; if("key" in event && typeof event.key != "undefined") { s = event.key; } else { var c = event.charCode || event.keyCode; if(c == 27) { s = "Escape"; } else { s = String.fromCharCode(c); } } switch(s) { case "Escape": obj.field.blur(); break; case "s": case "S": if(!this.evsetup) { event.preventDefault(); obj.field.focus(); break; } } }, bindArray: function(array) { if(!array || !array.length) return; this.suggest_url = ""; this.keywords = [], this.keywords_init = []; this.values = [], this.values_init = []; for(var i = 0, cl = array.length; i < cl; i++) { var item = array[i]; if(item.constructor == Array) { this.keywords[i] = this.keywords_init[i] = item[0]; this.values[i] = this.values_init[i] = item[1]; } else { this.keywords[i] = this.keywords_init[i] = item; this.values[i] = this.values_init[i] = ""; } } }, bindURL: function(url) { if(!url) url = autosuggest_url; this.suggest_url = url; }, setupEvents: function() { if(!this.evsetup) { this.evsetup = true; this.addEvent(document, "keydown", this.funcCheck); this.addEvent(this.field, "blur", this.funcClear); this.addEvent(document, "keypress", this.funcPress); } }, clearEvents: function() { // Removes an event handler: function removeEvent(obj, event_name, func_ref) { if(obj.removeEventListener && !window.opera) { obj.removeEventListener(event_name, func_ref, true); } else if(obj.detachEvent) { obj.detachEvent("on" + event_name, func_ref); } else { obj["on" + event_name] = null; } } var event = window.event; if(event && this.cur_h) { var elem = event.srcElement || event.target; var x = this.mouse_x + (document.documentElement.scrollLeft || document.body.scrollLeft || 0); var y = this.mouse_y + (document.documentElement.scrollTop || document.body.scrollTop || 0); if((elem.id == this.field_id) && (x > this.cur_x && x < (this.cur_x + this.cur_w)) && (y > this.cur_y && y < (this.cur_y + this.cur_h))) { this.field.focus(); return; } } removeEvent(document, "keydown", this.funcCheck); removeEvent(this.field, "blur", this.funcClear); removeEvent(document, "keypress", this.funcPress); this.hide(); this.evsetup = false; }, parse: function(n, plen, re) { if(!n || !n.length) return ""; if(!plen) return n; var tobuild = [], c = 0, p = n.search(re); // No match found because we're serving approximate results if(p < 0) { tobuild[c++] = n; } else { tobuild[c++] = n.substr(0, p); tobuild[c++] = ""; tobuild[c++] = n.substring(p, plen + p); tobuild[c++] = ""; tobuild[c++] = n.substring(plen + p, n.length); } return tobuild.join(""); }, build: function() { if(this.total == 0) { this.displayed = false; return; } this.rows = []; this.current = this.no_default ? -1 : 0; var that = this; this.addEvent(document, "mousemove", function(event) { event = event || window.event; that.mouse_x = event.x; that.mouse_y = event.y; }); var body = document.getElementById("suggest_table_" + this.field_id); if(body) { this.displayed = false; document.body.removeChild(body); var helper = document.getElementById("suggest_helper_" + this.field_id); if(helper) document.body.removeChild(helper); } var bb = document.createElement("div"); bb.id = "suggest_table_" + this.field_id; bb.className = "autosuggest-body"; this.cur_y = this.curPos(this.field, "Top") + this.field.offsetHeight; bb.style.top = this.cur_y + "px"; this.cur_x = this.curPos(this.field, "Left"); bb.style.left = this.cur_x + "px"; this.cur_w = this.field.offsetWidth - (this.msie ? 2 : 6); bb.style.width = this.cur_w + "px"; this.cur_h = 1; bb.style.height = "1px"; var cc = null; if(this.msie && this.use_iframe) { var cc = document.createElement("iframe"); cc.id = "suggest_helper_" + this.field_id; cc.src = "javascript:\"\";"; cc.scrolling = "no"; cc.frameBorder = "no"; } var that = this; var showFull = (this.total > this.entry_limit); if(cc) { document.body.appendChild(cc); cc.style.top = this.cur_y + "px"; cc.style.left = this.cur_x + "px"; cc.style.width = bb.offsetWidth + 2; } document.body.appendChild(bb); var first = true, dispCount = showFull ? this.entry_limit : this.total; var str = [], cn = 0; // cellspacing and cellpadding were not moved to css - IE doesn't understand border-spacing. str[cn++] = ""; bb.innerHTML = str.join(""); var table = bb.firstChild; if(this.use_mouse) { table.onmouseout = this.funcUnfocus; table.onmouseover = this.funcFocus; } var real_height = 0, real_width = 0; function createArrowRow(dir) { var row = table.insertRow(-1); row.className = dir ? "up" : "down"; var cell = row.insertCell(0); real_height += cell.offsetHeight + 1; return cell; } if(!this.use_scroll && showFull) createArrowRow(true).parentNode.className = "up-disabled"; var kl = this.keywords.length, counter = 0, j = 0; // For "parse" call: var t, plen; if(this.text_delimiter.length > 0) { var word = this.delim_words[this.current_word]; t = this.trim(this.addSlashes(word)); plen = this.trim(word).length; } else { var word = this.field.value; t = this.addSlashes(word); plen = word.length; } var re = new RegExp((this.limit_start ? "^" : "") + t, "i"); function addSuggestion(index, _first) { var row = that.rows[j] = table.insertRow(-1); row.className = (_first || (that.previous == index)) ? "selected" : ""; var cell = row.insertCell(0); cell.innerHTML = that.parse(that.keywords[index], plen, re); cell.setAttribute("pos", j++); cell.autosuggest = that; if(that.use_mouse) { that.addEvent(cell, "click", that.funcClick); cell.onmouseover = that.funcHighlight; } return [row.offsetWidth, row.offsetHeight]; } for(var i = 0; i < kl; i++) { if(this.bool[i]) { var dim = addSuggestion(i, (first && !this.no_default && !this.rebuild)); first = false; if(counter <= this.entry_limit) real_height += dim[1] + 1; if(real_width < dim[0]) real_width = dim[0]; if(++counter == this.entry_limit) { ++i; break; } } } var last = i; if(showFull) { if(!this.use_scroll) { var cell = createArrowRow(false); if(this.use_mouse) this.addEvent(cell, "click", this.funcDown); } else { bb.style.height = real_height + "px"; bb.style.overflow = "auto"; bb.style.overflowX = "hidden"; } } this.cur_h = real_height + 1; bb.style.height = this.cur_h + "px"; this.cur_w = ((real_width > bb.offsetWidth) ? real_width : bb.offsetWidth) + (this.msie ? -2 : 2) + 100; bb.style.width = this.cur_w + "px"; if(cc) { cc.style.height = this.cur_h + "px"; cc.style.width = this.cur_w + "px"; } this.range_up = 0; this.range_down = j - 1; this.displayed = true; if(this.use_scroll) { setTimeout(function() { counter = 0; for(var i = last; i < kl; i++) { if(!that.displayed) return; if(that.bool[i]) { addSuggestion(i); if(++counter == that.entry_limit) { ++i; break; } } } last = i; if(j < that.total) setTimeout(arguments.callee, 25); }, 25); } }, remake: function() { this.rows = []; var a = document.getElementById("suggest_table2_" + this.field_id); var k = 0, first = true; function adjustArrow(obj, which, cond, handler) { var r = a.rows[k++]; r.className = which ? (cond ? "up" : "up-disabled") : (cond ? "down" : "down-disabled"); var c = r.firstChild; if(cond && handler && obj.use_mouse) obj.addEvent(c, "click", handler); } if(this.total > this.entry_limit) { var b = (this.range_up > 0); adjustArrow(this, true, b, this.funcUp); } // For "parse" call: var t, plen; if(this.text_delimiter.length > 0) { var word = this.delim_words[this.current_word]; t = this.trim(this.addSlashes(word)); plen = this.trim(word).length; } else { var word = this.field.value; t = this.addSlashes(word); plen = word.length; } var re = new RegExp((this.limit_start ? "^" : "") + t, "i"); var kl = this.keywords.length, j = 0; for(var i = 0; i < kl; i++) { if(this.bool[i]) { if((j >= this.range_up) && (j <= this.range_down)) { var r = this.rows[j] = a.rows[k++]; r.className = ""; var c = r.firstChild; c.innerHTML = this.parse(this.keywords[i], plen, re); c.setAttribute("pos", j); } if(++j > this.range_down) break; } } if(kl > this.entry_limit) { var b = (j < this.total); adjustArrow(this, false, b, this.funcDown); } if(this.msie) { var helper = document.getElementById("suggest_helper_" + this.field_id); if(helper) helper.style.width = a.parentNode.offsetWidth + 2; } }, reposition: function() { if(this.displayed) { this.cur_y = this.curPos(this.field, "Top") + this.field.offsetHeight; this.cur_x = this.curPos(this.field, "Left"); var control = document.getElementById("suggest_table_" + this.field_id); control.style.top = this.cur_y + "px"; control.style.left = this.cur_x + "px"; } }, startTimer: function(on_list) { if(this.time_out > 0) this.timer = setTimeout(function() { this.mouse_on_list = on_list; this.hide(); }, this.time_out); }, stopTimer: function() { if(this.timer) { clearTimeout(this.timer); this.timer = 0; } }, getRow: function(index) { if(typeof(index) == "undefined") index = this.current; return (this.rows[index] || null); }, fixArrows: function(base) { if(this.total <= this.entry_limit) return; var table = base.firstChild, at_start = (this.current == 0), at_end = (this.current == (this.total - 1)); var row = table.rows[0]; row.className = at_start ? "up-disabled" : "up"; row = table.rows[this.entry_limit + 1]; row.className = at_end ? "down-disabled" : "down"; }, scroll: function(direction, times) { if(!this.displayed) return; this.field.focus(); if(this.current == (direction ? 0 : (this.total - 1))) return; if(!direction && (this.current < 0)) { this.current = -1; } else { var t = this.getRow(); if(t && t.style) t.className = ""; } this.current += times * (direction ? -1 : 1); if(direction) { if(this.current < 0) this.current = 0; } else { if(this.current >= this.total) this.current = this.total - 1; if(this.use_scroll && (this.current >= this.rows.length)) this.current = this.rows.length - 1; } var t = this.getRow(), base = document.getElementById("suggest_table_" + this.field_id); if(this.use_scroll) { if(direction) { if(t.offsetTop < base.scrollTop) base.scrollTop = t.offsetTop; } else { if((t.offsetTop + t.offsetHeight) > (base.scrollTop + base.offsetHeight)) { var ndx = this.current - this.entry_limit + 1; if(ndx > 0) base.scrollTop = this.getRow(ndx).offsetTop; } } } else { if(direction) { if(this.current < this.range_up) { this.range_up -= times; if(this.range_up < 0) this.range_up = 0; this.range_down = this.range_up + this.entry_limit - 1; this.remake(); } else this.fixArrows(base); } else { if(this.current > this.range_down) { this.range_down += times; if(this.range_down > (this.total - 1)) this.range_down = this.total - 1; this.range_up = this.range_down - this.entry_limit + 1; this.remake(); } else this.fixArrows(base); } t = this.getRow(); } if(t && t.style) t.className = "selected"; this.stopTimer(); this.startTimer(1); this.field.focus(); }, mouseClick: function(event) { event = event || window.event; var elem = event.srcElement || event.target; if(!elem.id) elem = elem.parentNode; var obj = elem.autosuggest; if(!obj) { var tag = elem.tagName.toLowerCase(); elem = (tag == "tr") ? elem.firstChild : elem.parentNode; obj = elem.autosuggest; } if(!obj || !obj.displayed) return; obj.mouse_on_list = 0; obj.current = parseInt(elem.getAttribute("pos"), 10); obj.choose(); }, focusTable: function() { this.mouse_on_list = 1; }, unfocusTable: function() { this.mouse_on_list = 0; this.stopTimer(); this.startTimer(0) }, highlightTable: function(event) { event = event || window.event; var elem = event.srcElement || event.target; var obj = elem.autosuggest; if(!obj) return; obj.mouse_on_list = 1; var row = obj.getRow(); if(row && row.style) row.className = ""; obj.current = parseInt(elem.getAttribute("pos"), 10); row = obj.getRow(); if(row && row.style) row.className = "selected"; obj.stopTimer(); obj.startTimer(0); }, choose: function() { if(!this.displayed) return; if(this.current < 0) return; this.displayed = false; var kl = this.keywords.length; for(var i = 0, c = 0; i < kl; i++) if(this.bool[i] && (c++ == this.current)) break; this.selectedIndex = i; this.insertWord(this.keywords[i]); if(this.onSelect) this.onSelect(i, this); }, insertWord: function(a) { // Sets the caret position to l in the object function setCaretPos(obj, l) { obj.focus(); if(obj.setSelectionRange) { obj.setSelectionRange(l, l); } else if(obj.createTextRange) { var m = obj.createTextRange(); m.moveStart("character", l); m.collapse(); m.select(); } } if(this.text_delimiter.length > 0) { var str = "", word = this.delim_words[this.current_word], wl = word.length, l = 0; for(var i = 0; i < this.delim_words.length; i++) { if(this.current_word == i) { var prespace = "", postspace = "", gotbreak = false; for(var j = 0; j < wl; ++j) { if(word.charAt(j) != " ") { gotbreak = true; break; } prespace += " "; } for(j = wl - 1; j >= 0; --j) { if(word.charAt(j) != " ") break; postspace += " "; } str += prespace; str += a; l = str.length; if(gotbreak) str += postspace; } else { str += this.delim_words[i]; } if(i != this.delim_words.length - 1) str += this.delim_char[i]; } this.field.value = str; setCaretPos(this.field, l); } else { this.field.value = a; } this.mouse_on_list = 0; this.hide(); }, hide: function() { if(this.mouse_on_list == 0) { this.displayed = false; var base = document.getElementById("suggest_table_" + this.field_id); if(base) { var helper = document.getElementById("suggest_helper_" + this.field_id); if(helper) document.body.removeChild(helper); document.body.removeChild(base); } this.stopTimer(); this.cur_x = 0; this.cur_y = 0; this.cur_w = 0; this.cur_h = 0; this.rows = []; } }, keyPress: function(event) { // On firefox there is no way to distingish pressing shift-8 (asterix) // from pressing 8 during the keyDown event, so we do restrict_typing // whilest handling the keyPress event event = event || window.event; var code = window.event ? event.keyCode : event.charCode; var obj = event.srcElement || event.target; obj = obj.autosuggest; if(obj.restrict_typing && !obj.suggest_url.length && (code >= 32)) { var caret_pos = obj.getCaretEnd(obj.field); var new_term = obj.field.value.substr(0, caret_pos).toLowerCase(); var isDelimiter = false; if(obj.text_delimiter.length > 0) { // check whether the pressed key is a delimiter key var delim_split = ""; for(var j = 0; j < obj.text_delimiter.length; j++) { delim_split += obj.text_delimiter[j]; if(obj.text_delimiter[j] == String.fromCharCode(code)) isDelimiter = true; } // only consider part of term after last delimiter delim_split = obj.addSlashes(delim_split); var lastterm_rx = new RegExp(".*([" + delim_split + "])"); new_term = new_term.replace(lastterm_rx, ''); } var keyw_len = obj.keywords.length; var i = 0; if(isDelimiter) { // pressed key is a delimiter: allow if current term is complete for(i = 0; i < keyw_len; i++) if(obj.keywords[i].toLowerCase() == new_term) break; } else { new_term += String.fromCharCode(code).toLowerCase(); for(i = 0; i < keyw_len; i++) if(obj.keywords[i].toLowerCase().indexOf(new_term) != -1) break; } if(i == keyw_len) { obj.stopEvent(event); return false; } } if(obj.caret_moved) obj.stopEvent(event); return !obj.caret_moved; }, checkKey: function(event) { event = event || window.event; var code = event.keyCode; var obj = event.srcElement || event.target; obj = obj.autosuggest; obj.caret_moved = 0; var term = ""; obj.stopTimer(); switch(code) { // Up arrow: case 38: if(obj.current <= 0) { obj.stopEvent(event); obj.hide(); } else { obj.scroll(true, 1); obj.caret_moved = 1; obj.stopEvent(event); } return false; // Down arrow: case 40: if(!obj.displayed) { obj.timer = setTimeout(function() { obj.preSuggest(-1); }, 25); } else { obj.scroll(false, 1); obj.caret_moved = 1; } return false; // Page up: case 33: if(obj.current == 0) { obj.caret_moved = 0; return false; } obj.scroll(true, (obj.use_scroll || (obj.getRow() == obj.rows[obj.range_up])) ? obj.entry_limit : (obj.current - obj.range_up)); obj.caret_moved = 1; break; // Page down: case 34: if(obj.current == (obj.total - 1)) { obj.caret_moved = 0; return false; } obj.scroll(false, (obj.use_scroll || (obj.getRow() == obj.rows[obj.range_down])) ? obj.entry_limit : (obj.range_down - obj.current)); obj.caret_moved = 1; break; // Home case 36: if(obj.current == 0) { obj.caret_moved = 0; return false; } obj.scroll(true, obj.total); obj.caret_moved = 1; break; // End case 35: if(obj.current == (obj.total - 1)) { obj.caret_moved = 0; return false; } obj.scroll(false, obj.total); obj.caret_moved = 1; break; // Esc: case 27: term = obj.field.value; obj.mouse_on_list = 0; obj.hide(); break; // Enter: case 13: if(obj.displayed) { obj.caret_moved = 1; obj.choose(); return false; } break; // Tab: case 9: if((obj.displayed && (obj.current >= 0)) || obj.timer) { obj.caret_moved = 1; obj.choose(); setTimeout(function() { obj.field.focus(); }, 25); return false; } break; case 16: //shift break; default: obj.caret_moved = 0; obj.timer = setTimeout(function() { obj.preSuggest(code); }, (obj.response_time < 10 ? 10 : obj.response_time)); } if(term.length) setTimeout(function() { obj.field.value = term; }, 25); return true; }, preSuggest: function(kc) { if(!this.timer) return; this.stopTimer(); if(this.displayed && (this.lastterm == this.field.value)) return; this.lastterm = this.field.value; if(kc == 38 || kc == 40 || kc == 13) return; var c = 0; if(this.displayed && (this.current >= 0)) { for(var i = 0; i < this.keywords.length; i++) { if(this.bool[i]) ++c; if(c == this.current) { this.previous = i; break; } } } else { this.previous = -1; } if(!this.field.value.length && (kc != -1)) { this.mouse_on_list = 0; this.hide(); } var ot, t; if(this.text_delimiter.length > 0) { var caret_pos = this.getCaretEnd(this.field); var delim_split = ""; for(var i = 0; i < this.text_delimiter.length; i++) delim_split += this.text_delimiter[i]; delim_split = this.addSlashes(delim_split); var delim_split_rx = new RegExp("([" + delim_split + "])"); c = 0; this.delim_words = []; this.delim_words[0] = ""; for(var i = 0, j = this.field.value.length; i < this.field.value.length; i++, j--) { if(this.field.value.substr(i, j).search(delim_split_rx) == 0) { var ma = this.field.value.substr(i, j).match(delim_split_rx); this.delim_char[c++] = ma[1]; this.delim_words[c] = ""; } else { this.delim_words[c] += this.field.value.charAt(i); } } var l = 0; this.current_word = -1; for(i = 0; i < this.delim_words.length; i++) { if((caret_pos >= l) && (caret_pos <= (l + this.delim_words[i].length))) this.current_word = i; l += this.delim_words[i].length + 1; } ot = this.trim(this.delim_words[this.current_word]); t = this.trim(this.addSlashes(this.delim_words[this.current_word])); } else { ot = this.field.value; t = this.addSlashes(ot); } if(ot.length == 0 && (kc != -1)) { this.mouse_on_list = 0; this.hide(); } else if((ot.length == 1) || this.full_refresh || ((ot.length > 1) && !this.keywords.length) || ((ot.length > 1) && (this.keywords[0].charAt(0).toLowerCase() != ot.charAt(0).toLowerCase()))) { var ot_ = ((ot.length > 1) && !this.full_refresh) ? ot.charAt(0) : ot; if(this.suggest_url.length) { // create xmlhttprequest object: var http = null; if(typeof(XMLHttpRequest) != "undefined") { try { http = new XMLHttpRequest(); } catch (e) { http = null; } } else { try { http = new ActiveXObject("Msxml2.XMLHTTP") ; } catch (e) { try { http = new ActiveXObject("Microsoft.XMLHTTP") ; } catch (e) { http = null; } } } if(http) { // Uncomment for local debugging in Mozilla/Firefox: // try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); } catch (e) { } if(http.overrideMimeType) http.overrideMimeType("text/xml"); http.open("GET", this.suggest_url + ot_, true); var that = this; http.onreadystatechange = function(n) { if(http.readyState == 4) { if((http.status == 200) || (http.status == 0)) { var text = http.responseText; var index1 = text.indexOf(""); var index2 = (index1 == -1) ? text.length : text.indexOf(" lcs) { lcs = table[i+1][j+1]; } } else { table[i+1][j+1] = 0; } } } return lcs; }, // A function to compute the Levenshtein distance between two strings // Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported // Full License can be found at http://creativecommons.org/licenses/by-sa/3.0/legalcode // This code is an unmodified (aside from style) version of the code written by Marco de Wit // and was found at http://stackoverflow.com/a/18514751/745719 levenshtein: (function() { var row2 = []; return function(s1, s2) { if(s1 === s2) { return 0; } else { var s1_len = s1.length, s2_len = s2.length; if(s1_len && s2_len) { var i1 = 0, i2 = 0, a, b, c, c2, row = row2; while(i1 < s1_len) row[i1] = ++i1; while(i2 < s2_len) { c2 = s2.charCodeAt(i2); a = i2; ++i2; b = i2; for(i1 = 0; i1 < s1_len; ++i1) { c = a + (s1.charCodeAt(i1) !== c2 ? 1 : 0); a = row[i1]; b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c); row[i1] = b; } } return b; } else { return s1_len + s2_len; } } }; })(), // Setup an event handler for the given event and DOM element // event_name refers to the event trigger, without the "on", like click or mouseover // func_name refers to the function callback that is invoked when event is triggered addEvent: function(obj, event_name, func_ref) { if(obj.addEventListener && !window.opera) { obj.addEventListener(event_name, func_ref, true); } else if(obj.attachEvent) { obj.attachEvent("on" + event_name, func_ref) } else { obj["on" + event_name] = func_ref; } }, // Stop an event from bubbling up the event DOM stopEvent: function(event) { event = event || window.event; if(event) { if(event.stopPropagation) event.stopPropagation(); if(event.preventDefault) event.preventDefault(); if(typeof(event.cancelBubble) != "undefined") { event.cancelBubble = true; event.returnValue = false; } } return false; }, // Get the end position of the caret in the object. Note that the obj needs to be in focus first. getCaretEnd: function(obj) { if(typeof(obj.selectionEnd) != "undefined") { return obj.selectionEnd; } else if(document.selection && document.selection.createRange) { var M = document.selection.createRange(), Lp; try { Lp = M.duplicate(); Lp.moveToElementText(obj); } catch(e) { Lp = obj.createTextRange(); } Lp.setEndPoint("EndToEnd", M); var rb = Lp.text.length; if(rb > obj.value.length) return -1; return rb; } return -1; }, // Get offset position from the top/left of the screen: curPos: function(obj, what) { var coord = 0; while(obj) { coord += obj["offset" + what]; obj = obj.offsetParent; } return coord; }, // String functions: addSlashes: function(str) { return str.replace(/(["\\\.\|\[\]\^\*\+\?\$\(\)])/g, "\\$1"); }, trim: function(str) { return str.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"); } }; allegro5-5.2.10.1/docs/src/changes-5.0.txt000066400000000000000000004017371473414355200176640ustar00rootroot00000000000000% Allegro changelog for 5.0.x series See `changes._tx` for changes in earlier versions of Allegro. These lists serve as summaries; the full histories are in the git repository. Changes from 5.0.10 to 5.0.11 (January 2015) =========================================== The main developers this time were: SiegeLord and Peter Wang. Core: - Fix OSX backend on OSX 10.10 (lordnoriyuki). Audio addon: - Fix/avoid all sound examples freezing on OSX with the aqueue driver (Elias Pschernig). - Fix a deadlock in Pulseaudio driver. Other: - Fix build warnings. - Improve documentation (syntax highlighting). Changes from 5.0.9 to 5.0.10 (June 2013) ======================================== The main developers this time were: Trent Gamblin, Paul Suntsov, Peter Wang. Core: - Register system interface even if no display driver available on Windows. Displays: - Don't crash in al_create_display if there is no display driver. - Don't crash at shutdown if there is no display driver (Windows). - Don't fail init if both D3D, GL drivers unavailable (Windows). - Run fullscreen toggle on main thread (OS X). - Destroy the backbuffer bitmap when destroying the display (OS X). - Switch to new NSTrackingArea API (OS X). - Check availability of fullscreen button on window frame at run-time (OS X). Graphics: - Add ALLEGRO_SRC_COLOR, ALLEGRO_DEST_COLOR, ALLEGRO_INVERSE_SRC_COLOR, ALLEGRO_INVERSE_DEST_COLOR blending modes (initially by Jon Rafkind and Elias Pschernig). - Let al_destroy_bitmap implicitly untarget the bitmap on the calling thread. - Use memory bitmap drawing when either bitmap is locked (OpenGL). - Add const qualifiers to glUniform*v() functions (Aaron Bolyard). Input: - al_set_mouse_xy on Windows resulted in the mouse getting set to the wrong position in windowed modes. - Scale the user supplied mouse cursor if it's too big (Windows). - Fix mouse warping on OS X. - Fix mouse warping in Linux evdev mouse driver. Audio addon: - pulseaudio: Use smaller buffer size by default, and make it configurable. - pulseaudio: Clean up state transitions. - Fix looping in Ogg Vorbis stream (Todd Cope). - Enable the use of the unpatched DirectX SDK to build Allegro with MinGW. Color addon: - Fix al_color_rgb_to_html blue component (Jeff Bernard). Font addons: - Make al_init_ttf_addon return true for subsequent calls. Primitives addon: - Disallow 3 component vectors for ALLEGRO_PRIM_TEX_COORD. - Check that the vertex declaration is valid before creating it. - Respect filter settings of textures in the D3D backend. Build system: - Do not install most internal header files. - Do not search for and link with unneeded X libraries. Examples: - ex_audio_timer: New example. Other: - Minor fixes. - Various documentation updates. - A lot of code refactoring. Changes from 5.0.8 to 5.0.9 (February 2013) =========================================== The main developers this time were: Trent Gamblin, Elias Pschernig, Peter Wang. Core: - Clean up logging subsystem at shutdown (muhkuh). - Fix a problem with creating a display after Allegro is shut down then re-initialised on X11. - Fix use of clobbered return value from setlocale() on X11. - Fix use of double math functions for float arguments (Nick Trout). Displays: - Fix al_set/get_window position on Windows so getting/setting to the same position continuosly doesn't move the window. (Michael Swiger) - Add al_set_display_icons (plural). Implemented on X11 and Windows. - Made al_get_display_mode return the closest thing to a pixel format possible with the WGL driver (tobing). - Move WGL context destruction out of the message pump thread and into the user/main thread. - Allow command-tab to work in fullscreen window mode on OS X. Graphics: - Avoid null pointer dereference when setting a target bitmap after its video_texture has already been released (D3D). - Make d3d_lock_region fail immediately if _al_d3d_sync_bitmap failed, likely because the device was lost. - Set device_lost flag immediately when d3d_display_thread_proc finds the device is lost. - Sync bitmaps before resizing display to prevent changes being lost after the resize (D3D). - Revert a faulty FBO rebinding optimisation in al_set_target_bitmap. - Fix OpenGL extensions being completely ignored on OS X. - Support stencil buffer on iOS. Input: - Partially fix mouse buttons "sticking" on Mac, e.g. holding the mouse and toggling fullscreen window. Filesystem: - Keep absolute path in ALLEGRO_FS_ENTRYs so that later changes to the working directory do not affect the interpretation of the path. - Set ALLEGRO_FILEMODE_HIDDEN properly on Unix. - Make sure stat mode bits are cleared in default implementation of al_update_fs_entry. - Support Unicode paths on Windows. - Change description of al_get_fs_entry_name about not returning absolute path if created from relative path; no longer true for either the default or Physfs implementations. Audio addons: - Shut down threads properly when when destroying FLAC and modaudio streams. - Fix PulseAudio driver trying to connect to a non-existent server forever. Image I/O addon: - Fixed loading interlaced .png files with libpng. - Use Allegro built-in loaders in preference to OS X loaders for BMP/TGA/PCX. The OS X TGA loader doesn't support alpha and this is also more consistent. - Restored ability of the native OSX image loader to load grayscale pictures. Native dialog addon: - Add al_init_native_dialog_addon and al_shutdown_native_dialog_addon. Build system: - Rename allegro\*-5.0.pc files to allegro\*-5.pc. The old names are deprecated but retained on the 5.0 branch for backwards compatibility. - Only generate and install pkg-config files for libraries that we build. - Install iPhone internals headers (Nick Trout). Examples: - ex_icon2: New example. - speed: Use builtin font. Other: - Documentation updates. - A lot of code refactoring. Changes from 5.0.7 to 5.0.8 (November 2012) =========================================== The main developers this time were: Dennis Busch, Trent Gamblin, Elias Pschernig, Paul Suntsov, Peter Wang. Core: - Added alternate spelling: ALLEGRO_ALIGN_CENTER. Displays: - Rewrite D3D display format listing code, which was broken. This should re-enable multi-sampling and fix ex_depth_mask being slow with D3D. - Fixed a case where changing fullscreen mode in D3D via al_resize_display caused a crash and loss of loaded bitmaps information. - Fixed a case where changing fullscreen mode in OpenGL (on Windows) via al_resize_display cause nothing to be rendered after the mode change. - Fix crashes when resizing a WGL fullscreen window. - Fixed missing/incorrect resize events under Windows. - Fix al_set_new_display_adapter on OS X. - Fix use of invalidated pointers in D3D driver when the first format fails. - Fix bug where setting the mouse cursor had no effect when the mouse was captured (mouse button held down). - Fix windows not having a minimise button when set to windowed state from fullscreen window state. - Respect ALLEGRO_FRAMELESS flag properly when toggling from fullscreen window state to windowed state (Windows). - Don't generate DISPLAY_LOST events when resizing a fullscreen display. - Scale window icon to sizes returned by GetSystemMetrics (Windows). - Fixed ALLEGRO_FULLSCREEN_WINDOW under OS X. - Added al_osx_get_window function (Dennis Gooden). Graphics: - al_draw_pixel was crashing when drawn on sub-bitmaps on OpenGL. - Fix a potential crash when drawing the screen to a bitmap with D3D. - Avoid null pointer dereference when setting a target bitmap after its video_texture has already been released (D3D). - Lock bitmap to prevent slowness when creating a cursor from a non-memory bitmap on Windows. - Conditionally lock bitmap when creating cursor on X11 (previously it did so even if already locked). - Don't use NSOpenGLPFAAccelerated unnecessarily (OS X). Input: - Fix incorrect keyboard modifier flags after leaving and re-entering a window (Windows). - Fixed a bug with mouse enter/leave events for resized windows under OSX (Dennis Gooden). - Temporary fix for delay after mouse warp on OS X. File I/O: - Fix al_fputc on big-endian. Reported by Andreas Rönnquist and Tobias Hansen. - Make al_fputc return value like fputc when out of range. - Fix al_read_directory crash on 64-bit Windows (simast). Image addon: - Don't include native image loader source files in builds with the native image loaders disabled (OSX, iOS). - Added a missing autorelease-pool to the OSX bitmap saving function (sleepywind). - Fix OSX native image loader for loading not-premultiplied RGB data. Previously the data was "de-multiplied", with possibly all information lost. - Fix OSX native image loader for loading bitmaps without an alpha channel. They appeared completely black previously. Font addons: - Add builtin font creation function. - Added ALLEGRO_ALIGN_INTEGER text drawing flag (Todd Cope). - Made TTF addon include padding on the top and left edges of pages (Todd Cope). Audio addon: - Use programmatically generated interpolators. They cover an additional case which was missed and should be slightly more efficient. - Support linear interpolation for 16-bit mixers. - Add cubic interpolation for mixers (off by default). - Fix potential deadlock in stop_voice for OpenAL. - Fix potential deadlock in stop_voice for DirectSound. - Improve buffer filling behaviour for DirectSound, reducing pops and crackles significantly on slower machines. - Increase default buffer size for DirectSound to 8192 samples. - Fix setting the speed of an audio stream after it was attached to the mixer. Native dialogs addon: - Do not unload of rich edit module when closing one text log window while another exists. Reported by URB753. - Use default colours for Windows text log implementation, avoiding problems when the previous custom colours failed, leading to black text on a nearly black background. Build system: - Install pkg-config files when cross-compiling on Unix. Examples: - ex_synth: Add button to save waveform to a file. - ex_multisample: Demonstrate using moving bitmaps. - speed: Avoid poor performance due to needless redraws. - Renamed a5teroids to Cosmic Protector Other: - Many minor bug fixes. - Various documentation updates. Changes from 5.0.6 to 5.0.7 (June 2012) ======================================= The main developers this time were: Trent Gamblin, Elias Pschernig, Peter Wang. Core: - Fix ALLEGRO_STATIC_ASSERT collisions from different files included in the same translation unit. Reported by tobing. - Make al_ref_cstr, al_ref_ustr and al_ref_buffer return const ALLEGRO_USTR* instead of just an ALLEGRO_USTR* (Paul Suntsov). - Make al_ustr_empty_string const correct. - Fix many memory leak/warnings on MacOS X (Pär Arvidsson). - Fix typo preventing get_executable_name from using System V procfs correctly. Reported by Max Savenkov. Displays: - Add ALLEGRO_FRAMELESS as a preferred synonym for the confusing ALLEGRO_NOFRAME flag. - Rename al_toggle_display_flag to al_set_display_flag, retaining the older name for compatibility. - Set WM_NAME for some window managers (X11). Graphics: - Force al_create_bitmap to not create oversized bitmaps, to mitigate integer overflow problems. - Removed initial black frame on all Allegro programs. OpenGL: - Texture should be 'complete' (min/mag and wrap set) before glTexImage2D. - Fixed a bug in al_unlock_bitmap where the pixel alignment mistakenly was used as row length. - Fixed typo in names of some OpenGL extension functions. - Display list of OpenGL extensions in allegro.log also for OpenGL 3.0. Direct3D: - Fixed a bug in the D3D driver where separate alpha blending was being tested for when it shouldn't have been (Max Savenkov). Input: - Monitor /dev/input instead of /dev on Linux for hotplugging joysticks (Jon Rafkind). - Do not permanently change the locale for the X11 keyboard driver. Set LC_CTYPE only, not LC_ALL. Audio addon: - Fix desychronization due to inaccurate sample positions when resampling. Thanks to _Bnu for discovering the issue and Paul Suntsov for devising the correct solution. - Fix linear interpolation across audio stream buffer fragments. - Fix two minor memory leaks in the PulseAudio driver. Image I/O addon: - Improve compatibility of BMP loader. In particular, support bitmaps with V2-V5 headers and certain alpha bit masks. - Fix TGA loader using more memory than necessary. Reported by Max Savenkov. Font addon: - Use user set pixel format for fonts. Native dialogs addon: - Clear mouse state after dialogs or else it gets messed up (OSX). - Fix some warnings in gtk_dialog.c. - Wrap use of NSAlert so it can be run on the main thread with return value. Examples: - Add ex_resample_test. - ex_audio_props: Add bidir button. - ex_joystick_events: Support hotplugging and fix display of 3-axis sticks. - Add test_driver --no-display flag. (Tobias Hansen) Other: - Various documentation updates. - Other minor bug fixes. - Fix whatis entries of man pages. (Tobias Hansen) Changes from 5.0.5 to 5.0.6 (March 2012) ======================================== The main developers this time were: Trent Gamblin, Matthew Leverton, Elias Pschernig, Paul Suntsov, Peter Wang. Core: - Added al_register_assert_handler. Graphics: - Added al_draw_tinted_scaled_rotated_bitmap_region. - Added al_reset_clipping_rectangle convenience function. - Added al_get_parent_bitmap. - Fixed a bug in the OpenGL driver when drawing the backbuffer outside the clipping rectangle of the target bitmap. - Make blitting from backbuffer work when using multisampling on Windows/D3D. Displays: - Set ALLEGRO_MINIMIZED display flag on Windows (Zac Evans). - Don't generate bogus resize events after restoring minimised window on Windows. - Fixed bug on Windows where two SWITCH_IN events were fired when window was minimized/restored (Michael Swiger). - Fixed inverted al_toggle_display_flag(ALLEGRO_NOFRAME) logic under Windows as well as a bug where repeatedly setting the flag to on would make the window grow bigger and bigger (Michael Swiger). - Fixed inverted al_toggle_display_flag(ALLEGRO_NOFRAME) logic in X11. - Prevent a deadlock during display creation on X. - Fallback to the 'old' visual selection method on X instead of crashing if the 'new' visual selection doesn't work. Input: - Use the same logic in set_mouse_xy for FULLSCREEN_WINDOW as was used for FULLSCREEN. (Max OS X) Filesystem: - Added al_fopen_slice. - Added al_set_exe_name which allows overriding Allegro's idea of the path to the current executable. - Make al_get_standard_path(ALLEGRO_TEMP_PATH) treat the value of TMPDIR et al. as a directory name even without a trailing slash. (Unix) - Make stdio al_fopen implementation set proper errno on failure. Audio addons: - Add mixer gain property and functions. - Improve code to check that DLL symbols are loaded in the acodec addon. The old method was hacky and broke under -O2 using GCC 4.6.1. Image I/O addon: - Improved accuracy of un-alpha-premultiplying in the native OSX bitmap loader. Primitives addon: - Added al_draw_filled_pieslice and al_draw_pieslice. - Added al_draw_elliptical_arc. TTF addon: - Added al_load_ttf_font_stretch functions (tobing). - Added ALLEGRO_TTF_NO_AUTOHINT font loading flag to disable the Auto Hinter which is enabled by default in newer version of FreeType (Michał Cichoń). - Clear locked region so pixel borders aren't random garbage that can be seen sometimes with linear filtering on. - Unlock glyph cache page at end of text_length and get_text_dimensions (jmasterx). Examples: - Added new examples: ex_audio_chain, ex_display_events, ex_file_slice. - ex_ogre3d: Make it work under Windows (AMCerasoli). - a5teroids: Support gamepads that report small non-zero values for sticks that are at rest. Other: - Added index to HTML version of the reference manual (Jon Rafkind). - Various documentation updates. - Other minor bug fixes. Changes from 5.0.4 to 5.0.5 (November 2011) =========================================== The main developers this time were: Elias Pschernig and Trent Gamblin. Graphics: - Fixed several instances of windows being positioned wrong on Windows: regular windows, WGL FULLSCREEN_WINDOW, and ALLEGRO_NOFRAME windows. - Don't re-bind the FBO in al_set_target_bitmap if the new target bitmap shares the parent bitmap with the new target bitmap (Paul Suntsov). - Zero out fake refresh rate information from the nvidia proprietary driver on X11 (Peter Wang). - Implemented the ALLEGRO_FULLSCREEN_WINDOW flag for iOS. Input: - Make al_set_mouse_xy work in fullscreen on Windows. - Fixed a race condition in al_init_joystick. - Fixed problem on OS X where having two identical gamepads attached would cause joystick initialization to hang (Thanks to Todd Cope for pointing it out.) - Fixed iphone joystick events (it assumed a call to al_get_joystick but that's not required when using events). TTF fonts: - Save new bitmap flags and bitmap format at time of loading font and use them when creating pages. Primitives addon: - Very thin arcs/pieslices were not drawn due to an overzealous check (Paul Suntsov). Native dialogs addon: - Implemented al_show_native_message_box for iOS. Other: - Use .../Library/Application Support for ALLEGRO_USER_SETTINGS_PATH and ALLEGRO_USER_DATA_PATH on iOS. - Listen for applicationDidBecomeActive and applicationWillResignActive instead of applicationWillEnterForeground and applicationDidEnterBackground on iOS. This makes all of the common situations where you want to pause your game work, such as the lock button. - Fix some memory leaks on iOS. Documentation: - Various documentation updates. - Generate multiple copies of a man page for all the API entries that it documents. Changes from 5.0.3 to 5.0.4 (August 2011) ========================================= The main developers this time were: Trent Gamblin, Matthew Leverton, Elias Pschernig, Jon Rafkind, Paul Suntsov, Peter Wang and torhu. Core: - Restore searching of directories on PATH for DLLs to load on Windows. - Fix crash on shutdown in headless Unix environment (no X11 display). - Change all instances of al_malloc + memset(0) to al_calloc. Graphics: - Save memory in OpenGL case by freeing bitmap memory after uploading a texture. Use a temporary buffer when converting lock buffer back to native texture format. - Don't release or refresh memory or sub-bitmaps when D3D device gets lost/found. - Do not set D3D sub bitmaps to modified when first creating them. This can cause major slowdowns when creating a lot of sub-bitmaps and is likely responsible for slow font performance/startup when using D3D. - Fix incorrect number of display formats in D3D (tobing). - Honor ALLEGRO_VSYNC in the WGL driver. - Make titlebar icons the right size on Windows. - Fix typo causing weird results of al_get_monitor_info on X. - Don't setup FBO for a sub-bitmap whose parent is locked. - Specialise ADD/ONE/INVERSE_ALPHA blend mode software scanline drawers. - Toggle ALLEGRO_VIDEO_BITMAP flag off when creating a memory bitmap (both bits were previously on). - Add null bitmap assertion to al_clone_bitmap. Input: - New system for mapping extended keys in Windows keyboard driver. Mainly for getting the same keycode for numpad keys independently of the state of Num Lock. - More reliable updating of the toggle modifiers in Windows keyboard driver (Num Lock, Caps Lock, and Scroll Lock). Timers: - Fix race conditions when starting timers from different threads. Audio addons: - Don't mix into a global temporary sample buffer, causing noise when two separate mixers are trying to run in parallel. - Make it possible to start/stop an audio stream which is attached to a voice. - ALSA voices could not be resumed after being stopped, because the update threads quit as soon as a voice is stopped. - OpenAL backend did not handle the case where _al_voice_update returns less than a full buffer. - Attempt to load FLAC and Vorbis DLLs only once to avoid Windows popping up too many error windows. Native dialogs addon: - al_show_native_messagebox() on Windows: add UTF-8 support; show heading; show information icon by default. TTF addon: - Reduce memory usage. - Don't make multiple passes over strings when computing text dimensions. Build system: - Make sure static builds on Windows never use DLL_TLS (Zac Evans). - Made compilation possible with different combinations of Xinerama, XF86VidMode, or Randr being present. - cmake: Use find_path HINTS instead of PATHS in our DirectX SDK scripts. - cmake: Search for D3DX9 once instead of multiple times (John-Kim Murphy). - cmake: Find FLAC/Ogg/Vorbis libraries under the names generated by the official MSVC project files. - Include zlib.h explicitly for libpng 1.5. Examples: - Add multisampling to SPEED example. Change examples to use ALLEGRO_SUGGEST for multisampling. - Include the font for speed.app under OSX within the bundle so it can be run by double clicking. - Use default blending/pre-multiplied alpha in ex_blend2. Other: - Various documentation updates. - Fix minor memory leaks. Bindings: - Better way to make the Python wrapper work with both Python 2 and 3. - Include Windows-specific functions in the Python wrapper. Changes from 5.0.2.1 to 5.0.3 (May 2011) ======================================== Input: - Fixed keyboard repeat for extended keys on Windows. Added ALLEGRO_KEY_MENU. (torhu) - Make Delete key in Windows send KEY_CHAR event with unichar code 127 (Peter Wang). Filesystem: - al_remove_filename returned false even if successful (reported by xpolife). Graphics: - On OpenGL ES 1.1, glReadPixels can only read 4 byte pixels (Trent Gamblin). Font addon: - Fix a small memory leak when unregistering a handler with al_register_font_loader (Trent Gamblin). Primitives addon: - Fix assertion failures when drawing al_draw_ellipse, al_draw_arc, al_draw_rounded_rectangle, al_draw_filled_rounded_rectangle at very small scales (reported by Carl Olsson). Native dialogs addon: - gtk: Fix truncated string if the final button contained a non-ASCII character (Peter Wang). Other: - Minor build fixes and documentation updates. Changes from 5.0.2 to 5.0.2.1 (April 2011) ========================================== - Fix regression on Windows where the keyboard state was not updated unless the keyboard event source is registered to an event queue. Changes from 5.0.1 to 5.0.2 (April 2011) ======================================== Input: - Fix inverted mouse wheel on X11. - Make unicode field in KEY_CHAR events zero for Fn, arrow keys, etc. for OS X (jmasterx, Peter Hull). - Support ALLEGRO_KEY_PAD_ENTER and detect left/right Alt and Ctrl keys independently on Windows (torhu, Matthew Leverton). Changes from 5.0.0 to 5.0.1 (March 2011) ======================================== The main developers this time were: Trent Gamblin, Elias Pschernig, Peter Wang. Other contributions noted in-line. Graphics: - Automatically destroy framebuffer objects (FBOs) created for non-memory bitmaps after a while. This solves the problem of running out of resources if you set many different target bitmaps. - Make al_get_opengl_fbo attempt to create an FBO if one doesn't exist. - Avoid very small textures in Direct3D. - Do not sync from memory when first creating/uploading a bitmap (D3D). - Try to fix the problem of the taskbar appearing above fullscreen windows on Windows. - Center the window after toggling fullscreen on Windows. Input: - Support 4-way mouse-wheel and up to 32 mouse buttons in X11. Audio addons: - Avoid buffer overrun while reading from vorbis files. - Added optional support for Tremor in place of libvorbis on any platform. - Do not prefer DirectSound with OpenAL. This can cause problems and also will override user config. - Play silence where needed in DirectSound driver. TTF addon: - Do not hold bitmap drawing when changing target bitmap, which is invalid and caused transformations to be misapplied. - Remove FBO for a cache bitmap once we are no longer adding glyphs to it. Build system: - Force "default" visibility of _al_mangled_main on OS X, otherwise the dynamic linker cannot find the symbol if building with XCode4 (Owen Anderson and Peter Hull). - Generated pkg-config files should take into account LIB_SUFFIX variable (Cristian Morales Vega). - Update allegro_font pkg-config file to not require allegro_primitives. Documentation: - Various documentation updates. - Add copy of DejaVu font licence. Bindings: - Add allegro_main addon to the Python wrapper. Make the wrapper work with Python 3, which has a different string representation. Add parameter type checking for custom types. Changes from 5.0.0 RC5 to 5.0.0 (February 2011) =============================================== Color addon: - Use colour names from CSS. This is the same as the previous list but with all grey/gray alternatives. Documentation: - Minor documentation updates. Changes from 5.0.0 RC4 to 5.0.0 RC5 (February 2011) =================================================== The main developers this time were: Thomas Fjellstrom, Trent Gamblin, Peter Hull, Matthew Leverton and Peter Wang. Other contributions noted in-line. System: - Load allegro5.cfg from the directory containing the executable, not the initial working directory. Graphics: - Make al_get_monitor_info return success code. - Replace al_set_new_display_adaptor(-1) with a named constant ALLEGRO_DEFAULT_DISPLAY_ADAPTER. - Fix numerous bugs in X mode setting and multi monitor related code, and introduce new xrandr code. - Generate ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY when mouse leaves OS X window (Evert Glebbeek). - Hide OS X window during exiting fullscreen window mode, to prevent the hideous misaligned animation from showing. - Fix erroneous assertions in OpenGL backend. - Added a hack which makes OpenGL mode work under Wine for me (Elias Pschernig). - Add support for some al_get_display_options in D3D port. Keyboard: - Don't send KEY_CHAR events for modifier and dead keys (with contributions from torhu). - Don't send KEY_DOWN events for non-physical key events. - osx: Allow unicode entry (single keypresses only). - x11: Set the keycode field in KEY_CHAR events to the code of the last key pressed, as stated in the documentation, even if the char is due to a compose sequence. - x11: Get rid of historic behaviour where the unicode field is always zero when Alt is held down. - Rename ALLEGRO_KEY_EQUALS_PAD to ALLEGRO_KEY_PAD_EQUALS for consistency. Mouse: - Add al_grab_mouse and al_ungrab_mouse. Implemented on X11 and Windows. - Allow the user configure a key binding to toggle mouse grabbing on a window. - Support horizontal mouse wheel on Windows (jmasterx). - Calculate Y position for al_set_mouse_xy correctly in OS X windowed mode (X-G). - Use more appropriate CURSOR_LINK cursor on OS X (X-G). - Assign different button IDs for separate touches on iPhone (Michał Cichoń). - iphone: Remove fake mouse move events as they're unncessary and can cause problems with user input tracking. Filesystem: - Clean up al_get_standard_path(): remove SYSTEM_DATA, SYSTEM_SETTINGS, PROGRAM paths; add RESOURCES and USER_DOCUMENTS paths. Use system API calls if possible. - Implement ALLEGRO_USER_DATA_PATH under Linux. Honor XDG_DATA/CONFIG_HOME environment variables. - Fix al_make_directory on Windows due to problems with calls to stat() with trailing slashes. Native dialogs addon: - Use string arguments to al_create_native_file_dialog() and al_get_native_file_dialog_path() instead of ALLEGRO_PATH. - Enhance the Windows file selector (initial patch by Todd Cope): - Use Windows' folder selector for ALLEGRO_FILECHOOSER_FOLDER. - Implement patterns. - Display the title of the dialog that the user specified. Primitives addon: - Fix changing the D3D blender state without updating the cached state. TTF addon: - Align glyphs in ttf font sheets so as to work around problems with forced S3TC compression with some OpenGL drivers (Elias Pschernig). Examples: - SPEED: add full screen flag, use standard paths for highscores and data. Build system: - Check PulseAudio backend will compile before enabling support. - Give a louder warning if FLAC/Vorbis/DUMB compile tests fail. Other: - Many leaks fixed on OS X. - Minor bug fixes and documentation updates. Changes from 5.0.0 RC3 to 5.0.0 RC4 (December 2010) =================================================== The main developers this time were: Trent Gamblin, Matthew Leverton, Elias Pschernig, Peter Wang. Graphics: - d3d: Don't generate intermediate resize events during modal resize loop. - Optimize D3D9 driver by caching blender state and scissor rectangle so redundant calls to D3D9 functions are avoided (Michał Cichoń). - gl: Use glGenerateMipmapEXT to generate mipmaps when FBOs are used. - x11: Don't restore display mode if another fullscreen display is active. Input: - iphone: Reverse button/axis events that were swapped at some point. File I/O: - Change the way user code implements new ALLEGRO_FILE structures. This adds al_create_file_handle and al_get_file_userdata. - Implement default ungetc behavior - used if the interface does not supply its own. - Add al_fopen_interface. Memfile addon: - Implement ungetc. - Add rw file modes. - Rename header to allegro_memfile.h. - Add documentation. Image I/O addon: - Fix endian issues in TGA and Mac OS X image loaders. Other: - Use _NSGetExecutablePath for al_get_standard_path(ALLEGRO_EXENAME_PATH) on OS X (Jeff Connelly). - Minor bug fixes and documentation updates. Changes from 5.0.0 RC2 to 5.0.0 RC3 (December 2010) =================================================== The main developers this time were: Michał Cichoń, Trent Gamblin, Peter Wang. Graphics: - Honour subbitmap clipping rectangle under OpenGL (Elias Pschernig). - Fix an error in the Direct3D primitives blending. - al_set_new_window_position() did not have an effect for resizable windows on X11. - Fix windows only showing up on first monitor on X11 (Thomas Fjellstrom). - Implement al_get_monitor_info() for iDevices. Input: - Separate character inputs from physical key down events. This removes unichar and modifiers fields from ALLEGRO_EVENT_KEY_DOWN, and replaces ALLEGRO_EVENT_KEY_REPEAT by ALLEGRO_EVENT_KEY_CHAR. We decided this design flaw was better fixed now than later. - Make Mac OS X keyboard driver properly distinguish key down and key repeat events. TTF addon: - Respect ALLEGRO_NO_PREMULTIPLIED_ALPHA flag when loading TTF fonts. Other: - Fix returning a garbage pointer in maybe_load_library_at_cwd (Vadik Mironov). - Remove dependency on dxguid. - Minor compilation fixes and documentation updates. Changes from 5.0.0 RC1 to 5.0.0 RC2 (December 2010) =================================================== The developers this time were: Trent Gamblin, Elias Pschernig and Peter Wang. System: - Add al_is_system_installed and hide al_get_system_driver. - Prevent 'DLL hijacking' security issue on Windows. Graphics: - Change to using premultiplied alpha by default. The new bitmap flag ALLEGRO_NO_PREMULTIPLIED_ALPHA was added. - Change the value of ALLEGRO_VIDEO_BITMAP to non-zero. - Change al_get_opengl_version to return a packed integer. - Made al_get_opengl_version return an OpenGL ES version (if using OpenGL ES) rather than an attempted estimate at a desktop GL version. - Added function al_get_opengl_variant that returns either ALLEGRO_DESKTOP_OPENGL or ALLEGRO_OPENGL_ES. - Make al_have_opengl_extension return bool. - Fix OpenGL graphics mode height value on Windows. - Only try to create one Direct3D display at a time. - Make screensaver activate on Windows Vista and above unless inhibited. - Avoid potential divide-by-zeroes when computing the refresh rate in X11 video modes. Events: - Delete an incorrect mutex destroy in al_unregister_event_source. Input: - Revert the joystick driver used on OS X 10.4 to the pre-hotplugging version, rather than one which contained an earlier attempt at implementing hotplugging. Select the 10.4 or greater joystick driver at runtime. iPhone: - Added two iPhone-specific functions: al_iphone_override_screen_scale and al_iphone_program_has_halted. Image I/O addon: - Made the iPhone and OSX image loaders not try and correct colors to some arbitrary color space, but instead use the values directly from the image. Native dialogs addon: - Tolerate null display in al_show_native_file_dialog on Windows. - Make GTK native dialog implementation only call GTK from a single thread. - Define al_show_native_message_box to be usable without installing Allegro. Primitives addon: - Make primitives addon compilable again without OpenGL. Examples: - ex_ttf: Test the monochrome flag. - Work around problems with MSVC and UTF-8 string literals. ex_utf8 is now not built under MSVC. - Don't use WIN32 executable type on examples that require the console (David Capello). Other: - Minor bug fixes and documentation updates. Changes from 4.9.22 to 5.0.0 RC1 (November 2010) ================================================ The developers this time were: Trent Gamblin, Evert Glebbeek, Elias Pschernig, Paul Suntsov, Peter Wang. Graphics: - Make al_resize_display keep the original resolution (or change back) if it can't set the users request, on Windows. - Do not emit ALLEGRO_DISPLAY_RESIZE events from the Windows and X11 display drivers when using al_resize_display. - [X11] Make al_get_num_display_modes and al_get_display_mode work if the adapter is set to default. Right now there was no way to query the modes of the default monitor. - [X11] Use _NET_WM_STATE_FULLSCREEN hint for "true" fullscreen displays. Enable mouse grabbing in fullscreen modes. - Added ALLEGRO_EVENT_DISPLAY_ORIENTATION and implement it on iOS. - Dennis Busch fixed a problem with displays not showing up on the primary display by default in some dual head setups, on Windows. - Increase the precision of texture coordinate deltas in the software triangle renderer, from floats to doubles. - Remove al_get_frontbuffer(). It wasn't implemented anywhere. - Implement min/mag filter and mipmap flags for Direct3D. Input: - Report correct initial mouse position if a display is created with the mouse pointer inside, or if the mouse routines are installed after a display is created (X11, Windows). - John Murphy fixed improperly mapped axes on the Windows joystick driver. Events: - Do not register user event sources with the destructor system as it cannot work reliably. User event sources must be destroyed manually. Filesystem: - Make al_get_fs_entry_name and al_get_current_directory return strings instead of ALLEGRO_PATH. - Make al_make_directory create parent directories as needed. - Fix al_create_fs_entry to not trim the root path "/" down to the empty string with the stdio backend. Path routines: - Remove al_make_path_absolute and replace it by al_rebase_path. - Remove undocumented behavior of setting a default organization name of "allegro" for all apps. - Correctly return standard paths as directories on OS X. Threads: - Rename al_wait_cond_timed to al_wait_cond_until to match al_wait_cond_until. Config routines: - Add a blank line between sections when writing out a config file. Other core: - Move the Windows event loops back into the same thread as the D3D event loop. It's a requirement of D3D, else you can get crashes as I was when resetting the device (like tabbing away from a fullscreen app). - Add some missing standard entries to the OS X menu bar (the "hide", "hide others" and the window list, mainly). Audio addon: - Automatically stop sample instances which point to a buffer of a sample which is about to be destroyed with al_destroy_sample. - alsa: Resume properly after suspending. Image I/O addon: - Make GDI+ support compile cleanly with the headers that come with MinGW package w32api-3.15. - Speed up PNG and BMP saving, and NSImageFromAllegroBitmap loading. TTF addon: - Add a flag for loading TTFs without anti-aliasing (ALLEGRO_TTF_MONOCHROME). Primitives addon: - Fix several failed sub-bitmap related unit tests on Windows. - Made thick outlined triangles look nicer when the triangles are very thin. - Add a debug-only check for primitives addon initialization to aid in code portability. Examples: - Added example demonstrating the effect of premultiplied alpha. - Make 'F' toggle fullscreen window in SPEED (in-game). - Minor improvements to the a5teroids demo. Documentation: - Many documentation updates. - Add list of contributors and a readme for packagers. - Make make_doc tool build cleanly on MSVC, and work around a problem with recent version of Pandoc on Windows. - Improve styling of PDF output. - Add generated man pages to archives. Bindings: - Implemented array types in the Python wrapper. Changes from 4.9.21 to 4.9.22 (September 2010) ============================================== The developers this time included: Michał Cichoń, Trent Gamblin, Evert Glebbeek, Angelo Mottola, Elias Pschernig, Paul Suntsov and Peter Wang. System: - Allow the X11 port to initialise without an X server connection. Graphics: - Fix many bugs with bitmap locking. - Fix many bugs to do with transformations, flipping and clipping. - Fix many bugs to do with sub-bitmaps as source and destination. - Renamed al\_draw\_[tinted\_]rotated_scaled_bitmap to al\_draw\_[tinted\_]scaled_rotated_bitmap to match the parameter order. - Reimplemented bitmap software rendering routines using newly optimised software triangle renderer, formerly in the primitives addon. - Add pixel_size field to ALLEGRO_LOCKED_REGION. - Fix bugs to do with pixel alignment on OpenGL. - Fix OpenGL pixel transfer of 15 bpp formats, where Allegro does not Allegro does not care whether the unused bit is set or not, but when transferring to OpenGL it will be interpreted as an alpha bit. - Disabled support for drawing a bitmap into itself. - Changed specification of al\_draw_*bitmap to not allow transformation and ignore blending/tinting when the screen itself is being drawn (except when drawn into a memory bitmap). - Allow bitmap regions to be outside the bitmap area in drawing routines. - Added al_add_new_bitmap_flag convenience function. - Added three new bitmaps flags ALLEGRO_MAG_LINEAR, ALLEGRO_MIN_LINEAR, ALLEGRO_MIPMAP. Removed the config settings for linear/anisotropic min/mag filtering. DirectX side not yet updated. - Register destructors for bitmaps, so they will be implicitly destroyed when Allegro is shut down. This was only true for some bitmaps previously. - Don't allocate memory buffers for video bitmaps when using OpenGL. - Make al_get_opengl_extension_list() return NULL if called on a non-GL display. - Fix al_create_display for OpenGL forward compatible contexts. - Add al_set_current_opengl_context as an explicit way to set the OpenGL context. - Rename al_is_opengl_extension_supported to al_have_opengl_extension. - Produce more accurate/correct color when going from less to more bits per component. - Fix al_set_new_window_position() everywhere. - Avoid potential deadlock if resizing window to the same size on X11. - Fixed turning off vsync in X11. - Added al_is_d3d_device_lost function. - Dynamically load dinput and d3d DLLs on Windows. - Replaced PeekMessage with GetMessage in window event loops for the D3D and WGL drivers (David Capello). Input: - Added hotplugging support for joysticks on Linux, Windows and OS X. - Added al_reconfigure_joysticks function. - Merged all joystick devices under a single joystick event source. - Removed al_get_joystick_number. - Add al_is_joystick_installed. - The OS X joystick driver was rewritten; it requires OS X 10.5. The older driver still exists for OS X 10.4 and earlier but is in a semi-updated state with regards to hotplugging. - Allow user to override joystick device paths in the config file (Linux). - Fix iphone touch input and clipping for modes other than w=768,h=1024. - Fixed missing mouse movement messages on IPhone on touch-up/down. Also changed how mouse buttons are reported - always as button 1 now. Config: - Give config iterators proper types instead of void *. - Make al_get_system_config() always return non-NULL if a system driver is installed. Events: - Rename al_event_queue_is_empty to al_is_event_queue_empty (with compatibility define). Timers: - Add al_add_timer_count function. - Rename al_timer_is_started to al_get_timer_started. - Rename al_current_time to al_get_time (with compatibility define). File I/O: - Add al_open_fs_entry to open a file handle from an FS_ENTRY. - Add al_fclearerr. - Set ALLEGRO_FILEMODE_HIDDEN flag on entries for file names beginning with dot (OS X). - Remove al_is_path_present, al_fs_entry_is_directory, al_fs_entry_is_file (all trivial). Primitives addon: - Optimised most of the software rendering routines by a lot. - Triangle drawer was skipping pixels in very thin triangles. - Handle lost d3d devices better. - Fix some bugs found during testing. Image I/O addon: - Fix native image loader on Mac OS X: images that were not 72 dpi would be rescaled to a smaller size. - Added native bitmap saving support for OSX. - Fix jpeg saving when locked region has negative pitch. Native dialogs addon: - Add Windows and OS X text log implementations. - Add ALLEGRO_FILECHOOSER and ALLEGRO_TEXTLOG types instead of conflating them into ALLEGRO_NATIVE_DIALOG. - Fix race condition in al_open_native_text_log. - Rename al_destroy_native_dialog to al_destroy_native_file_dialog. - Rename al_get_native_dialog_event_source to al_get_native_text_log_event_source. - Speed up text log appending by making the reader/writers asynchronous. - Register destructors for file chooser and text log dialogs. - Fix file chooser on Windows returning multiple selections with slashes appended to filenames. If an initial path was specified then the dialog wouldn't open at all; fixed. - Let native dialog functions fail gracefully. Audio addons: - Init destructors even if audio driver fails to install. - Dynamically load dsound DLL on Windows. Font addons: - Added al_shutdown_ttf_addon. - Prevent SIGSEGV for double-closing a file in the TTF addon if it is not a valid font file. - Make al_grab_font_from_bitmap not cause a segmentation fault if the bitmap is garbage. - Some TTF fonts would not render right at small sizes; fixed. - Make al_destroy_font ignore NULL. Tests: - Added a test suite (finally). - Add a shell script to produce test coverage results using lcov. Examples: - Add ex_haiku, an example based on Mark Oates's Haiku game. Mark generously agreed to let us include it as an Allegro example. - Added a new example ex_joystick_hotplugging. - Added a new example ex_filter. - Make ex_fs_window work on MSVC. - Allow a5teroids to run without audio, or if audio data doesn't load. Build system: - Re-added CMake option that allows forced static linking of libFLAC. - Replaced the old iphone xcode project with a cmake iphone toolchain. Documentation: - Many updates to the reference manual. Bindings: - Added a workaround to the Python wrapper for a Mingw bug. Changes from 4.9.20 to 4.9.21 (July 2010) ========================================= The main developers this time were: Trent Gamblin, Matthew Leverton, Elias Pschernig, Paul Suntsov, Peter Wang. Graphics: - Fixed the mis-termed "blend color". There is no more color state. - al_set*_blender functions lose the color parameter. - Added 5 new bitmap drawing functions al_draw_tinted*_bitmap with a color parameter. The parameter is used just like the "blend color" before. - All text drawing functions gain a color parameter and use it like they used the "blend color" before. - Primitive drawing functions previously sometimes (and sometimes not) used the "blend color". Not any longer. - Make the current blending mode thread-local state instead of per-display state. - Add explicit display arguments to functions which require a display, but don't require the rendering context to be current. - Make al_set_target_bitmap change the current display as necessary. al_set_target_bitmap(NULL) releases the rendering context. - Add al_set_target_backbuffer as a convenience. - Remove al_set_current_display. - Give each bitmap its own transformation, i.e. every bitmap has a transformation, which is in effect when that bitmap is the target. - Remove sub-bitmap clip-to-parent restriction on create. Add out-of-bounds blitting support to memory bitmaps. - Merge sub-bitmap and parent bitmap clipping; clip source bitmap to (0,0)-(w,h); fix flipping to/from clipped bitmaps. - Made mouse cursors independent of displays. You may create cursors without a display, and you may use a cursor with any display. - Rename al_{set,get}_current_video_adapter to *new_display_adapter for consistency. - Move the new display video adapter and new window position to thread-local state, like other new display parameters. Make al_store_state also save those parameters with ALLEGRO_STATE_NEW_DISPLAY_PARAMETERS. - Rename al_transform_transform to al_compose_transform. Switched the order of parameters in al_compose_transform and al_copy_transform to match the rest of the transform functions. - Made memory bitmap manipulation without a display possible (again?). - Fixed window resizing in D3D driver. Simplify resize-postponing on Windows. - Make al_create_display abort early when the new_display_adapter is greater than the screen count (X11). - Added ALLEGRO_MINIMIZED flag to the X11 port. - Fixed OpenGL version string parsing (bug #3016654). Other core: - Renamed al_install_timer to al_create_timer, and al_uninstall_timer to al_destroy_timer. - Rename al\_{get,set}\_{appname,orgname} to \*app_name and \*org_name. - Fix assertion failure in al_create_mutex_recursive on Windows (spoofle). Primitives addon: - Made the D3D driver of the primitives addon work with multiple displays. Also made it handle the display being destroyed properly. - Simplified shader recreating on thread destruction when using the primitives addon with D3D. - Avoid double free when shutting down the primitives addon multiple times. - Older Intel cards don't implement DrawIndexedPrimitiveUP correctly. Altered the D3D code to work around that. Audio addon: - Allow setting the DirectSound buffer size via allegro5.cfg. Image addon: - Make GDI+ image loader work with MinGW. Font addon: - Nicolas Martyanoff added al_get_font_descent/ascent functions which query per-font properties. Previously it was necessary to call al_get_text_dimensions (which now just reports the text dimensions as it should). Native dialogs addon: - Add text log window functions (GTK only for now). Documentation: - Many updates to the reference manual. - Improve styling and add Allegro version to HTML pages. - Separated readme_a5.txt into multiple files, and hopefully improve them. Build system: - Remove INSTALL_PREFIX. Windows users can now use CMAKE_INSTALL_PREFIX to set the install path. - Allow the user to place dependencies in a subdirectory "deps", which will be automatically searched. Examples: - Use text log windows in many examples. - Add ex_noframe: test bitmap manipulation without a display. Bindings: - Update Python bindings. Changes from 4.9.19 to 4.9.20 (May 2010) ======================================== The developers this time were: Thomas Fjellstrom, Evert Glebbeek, Matthew Leverton, Milan Mimica, Paul Suntsov, Trent Gamblin, Elias Pschernig, Peter Wang. With significant contributions from Michał Cichoń. Core: - Add al_malloc, al_free, et al. These are now used consistently throughout Allegro and its addons. - Replace al_set_memory_management_functions by a simpler function, al_set_memory_interface. - Renamed some D3D/Windows specific functions to follow the al_{verb}_{stuff} convention. Graphics: - Move image I/O framework to core, i.e. al_load_bitmap, al_save_bitmap and bitmap file type registration. Image codecs remain in allegro_image. - Added a simple display capabilities querying capability to al_get_display_option: ALLEGRO_MAX_BITMAP_SIZE, ALLEGRO_SUPPORT_NPOT_BITMAP, ALLEGRO_CAN_DRAW_INTO_BITMAP, ALLEGRO_SUPPORT_SEPARATE_ALPHA. (OpenGL only for now) - Fix in OpenGL 3.0 context creation. - Make the extensions mechanism compatible with OpenGL version >= 3. Declared symbols needed by OpenGL 3.2 and 3.3 and brought OpenGL extensions up to date. - Fix an assertion in _al_draw_bitmap_region_memory so it does not trigger when source and destination are the same bitmap. - Fix some locking issues by setting GL_PACK_ALIGNMENT and GL_UNPACK_ALIGNMENT before reading/writing pixels. - Partial implementation of ALLEGRO_FULLSCREEN_WINDOW on OS X (Snow Leopard, probably Leopard). - Started X11 fullscreen support (resolution switching). - Fix handling of X11 size hints. - Fixed a deadlock related to fullscreen windows under X11 caused by using a nested lock for a condition variable. - Use _NET_WM_ICON to set icon on X11 instead of XSetWMHints. - Get the iPhone OpenGL version more properly. Only use separate blending on iPhone with OpenGL ES 2.0+. - Release the splash view and windows on iPhone, which makes backgrounding Allegro apps on OS 4.0 work. - Updated iphone port for IPad (only tested in the simulator). Input: - Disabled Raw Input code in Windows. Mouse events now reflect system cursor movements even in fullscreen mode. - Prevent late WM_MOUSELEAVE notifications from overriding mouse state display field (Windows). - Update pollable mouse state with axes events as well as button events on iPhone. Filesystem: - Made the filesystem entry functions work under Windows even if the name passed to al_create_fs_entry has a trailing slash or backslash. Config routines: - Add al_{load,save}_config_file_f. - Reorder al_save_config_file* arguments to match al_save_bitmap and al_save_sample. - Optimise config routines to work well for thousands of keys/sections. Image addon: - Added a GDI+ implementation of the image codecs, which will be used in favour of libjpeg/libpng if Allegro is compiled with MSVC. Then allegro_image will not require JPEG/PNG DLLs at runtime. - Removed format specific image functions. - Fixed bug in native png loader on iphone: was using the source color space instead of the target color space which made it fail whenever they differed (alpha-less paletted pictures). - Add an autorelease pool around iphone native image loading to stop memory leaks. Font addons: - Sever the tie between allegro_font and allegro_image. The user needs to initialise the image addon separately now. - Rename al_load_ttf_font_entry to al_load_ttf_font_f. - Fixed problem with glyph precision after applying transformations in the ttf addon. Primitives addon: - Added al_init_primitives addon function. This is now required. - Removed ALLEGRO_PRIM_COLOR; ALLEGRO_COLOR can now be used where it was required. - v textures coordinates were off for OpenGL non-power-of-two textures. - Free the vertex cache in al_destroy_display on X11. - Added the dummy vertex shader support to D3D driver of the primitives addon. Without this, custom vertices either resulted in warnings or outright crashes on some systems. - Bring D3D driver up to speed a little bit: transformations now work properly with sub-bitmap targets; the half-pixel offset now properly interacts with transformations; al_set_target_bitmap does not clear the transformation; the proper transformation is set at display creation. - Cull the primitives that are completely outside the clipping region. - Scale the numbers of vertices for the curvy primitives with the scale of the current transformation. Audio addon: - Remove driver parameter from al_install_audio. - Rename al_get_depth_size to al_get_audio_depth_size. - Rename al_get_audio_stream_buffer to al_get_audio_stream_fragment. - Many improvements to AQueue driver. Audio codecs: - Add MOD/S3M/XM/IT file support, using the DUMB library. - Revert to a monolithic allegro_acodec addon, i.e. remove separate allegro_flac, allegro_vorbis addons. WAV file support is in allegro_acodec. - Implement DLL loading for FLAC/Vorbis/DUMB on Windows. allegro_acodec will load the DLL at runtime to enable support for that format. If your program does not require said format, you don't need to distribute the DLL. - Remove format-specific loader/saver audio codec functions. - Make acodec loaders have consistent file closing behaviour. - Optimised wave file loading. Examples: - Make SPEED port run acceptably on graphics drivers without FBOs. Documentation: - Added documentation for the public Direct3D specific functions. - Documented ALLEGRO_OPENGL_3_0 and ALLEGRO_OPENGL_FORWARD_COMPATIBLE. Other: - Many bug and documentation fixes. Changes from 4.9.18 to 4.9.19 (April 2010) ========================================== The main developers this time were: Milan Mimica, Trent Gamblin, Paul Suntsov, Peter Wang. Other contributions from: Evert Glebbeek and Shawn Hargreaves. Graphics: - Implemented support for transformations for memory bitmaps. - Transformations now work properly when the target bitmap is a sub-bitmap in OpenGL (still broken in D3D). Also fixed OpenGL bitmap drawing in the same scenario (it used to always revert to software drawing). - Use the memory drawers when the source bitmap is the backbuffer with the rotated/scaled bitmaps. - Make al_put_pixel clip even if the bitmap is locked, which was the reason why software primitives were not clipping. - Added al_put_blended_pixel, the blended version of al_put_pixel. - Sub bitmaps of sub bitmaps must be clipped to the first parent. - Don't clear the transformation when setting the target bitmap in OpenGL. - Implemented ALLEGRO_NOFRAME and ALLEGRO_FULLSCREEN_WINDOW in WGL. - Set the ALLEGRO_DISPLAY->refresh_rate variable for fullscreen modes under D3D. - Make d3d_clear return immediately if the display is in a lost state. - Rewrote the function that reads the OpenGL version so it works for previously unrecognised versions, and future versions. - Check for framebuffer extension on iPhone properly. - Fixed locking bugs on iPhone. allegro_ttf works now. Input: - Removed al_set_mouse_range. - Don't call al_get_mouse_state if the mouse driver isn't installed (Windows). - Send events even when the mouse cursor leaves the window, while any buttons are held down (Windows and Mac OS X; X11 already did this). - Allow mouse presses and accelerometer data simultaneously. (iPhone) File I/O: - Optimise al_fread{16,32}* by using only one call to al_fread each. - Optimise al_fgetc() for stdio backend. Path: - Fix an infinite loop in _find_executable_file when searching for the executable on the PATH (Alan Coopersmith). Primitives addon: - Made the software driver for the primitives addon check for blending properly. Also, fixed two line shaders. - Made the D3D driver thread-safe. The whole addon should be thread-safe now. - The addon now officially supports 3D vertices, even though the software component can't draw them yet. - Changed the way the primitives addon handles the OpenGL state (fixes a few bugs and makes life easier for raw-OpenGL people) Image addon: - Optimised BMP, PCX, TGA loaders. - Fix loading 16-bit BMP files. - Fix loading grayscale TGA images. - Nial Giacomelli fixed a bug where images could be corrupt using the native Apple image loader (iPhone). Audio addon: - Add al_is_audio_installed. - Fix al_attach_sample_instance_to_mixer for int16 mixers. - Implement attaching an INT16 mixer to another INT16 mixer. - Handle conversion when an INT16 mixer is attached to a UINT16 voice. Build system: - Add an option to disable Apple native image loader (iPhone and OS X). - Add ttf addon target to iPhone xcode project. Examples: - Special contribution from Shawn "the Progenitor" Hargreaves. Changes from 4.9.17 to 4.9.18 (March 2010) ========================================== The main developers this time were: Trent Gamblin, Elias Pschernig, Evert Glebbeek, Peter Wang. Other contributions from: Milan Mimica, Paul Suntsov, Peter Hull. Graphics: - Fixed broken drawing into memory bitmaps as access to the global transformation required an active display. Now both transformation and current blending mode are stored in the display but provisions are made for them to also work if the current thread has no display. - Fixed a bunch of clipping problems with OpenGL, especially with sub-bitmaps. - Fix bug in OpenGL FBO setup when the target bitmap is the sub-bitmap of a bitmap with an FBO. - Fixed crash in al_get_num_display_modes under OSX 10.5. - Fixed some problems in _al_convert_to_display_bitmap that caused problems in WGL FS display resize. - Fixed al_set_current_display(NULL) on WGL. - Added subtractive blending. al_set_blender() takes another parameter. - Added ALLEGRO_FULLSCREEN_WINDOW display flag (X11 and D3D for now). - Allow changing ALLEGRO_FULLSCREEN_WINDOW with al_toggle_display_flag. - Figured out how to switch display modes using Carbon on OS X 10.6. - Stop the OpenGL driver on iPhone from changing the currently bound FBO behind our back when locking a bitmap. - Prevent screen flicker at app startup by simulating the splash screen (iPhone). Input: - Added "pressure" field to the mouse event struct and mouse state, which can be used with pressure sensitive pointing devices, i.e. tablets/stylus (currently OS X only). - Report scroll ball "w" position in mouse event struct, on OS X. - Removed OS X 10.1 specific code from mouse driver. We don't support OS X 10.1 any more. - Fix building of Linux joystick driver on some systems. Threads: - Fix a problem when al_join_thread() is called immediately after al_start_thread(). The thread could be joined before the user's thread function starts at all. - Fix a possible deadlock with al_join_thread() on Windows (thanks to Michał Cichoń for the report). - Fix some error messages running threading examples on OS X. Other core: - Added version check to al_install_system. - Rename al_free_path to al_destroy_path for consistency. - Make it possible to have an empty organization name with al_set_org_name(). - Changed implementation of AL_ASSERT to use POSIX-standard assert instead. - Removed al_register_assert_handler. - Fix timer macros which did not parenthesize their arguments. - Make stricmp, strlwr, strupr macros conditionally defined. Audio addon: - Rename al_attach_sample_to_mixer to al_attach_sample_instance_to_mixer. - Fix a premature free() when detaching samples and other audio objects. - Fix mixers attaching to mixers. - Pass correct number of samples to mixer postprocess callback. - AudioQueue code was not compiled even though version requirements may have been met (OS X). Primitives addon: - Make high-level primitives functions thread safe. (note: the DirectX driver is not yet thread safe) - Fix a bug causing crashes on Windows 7 when using the primitives addon and Direct3D (Invalid vertex declarations were being used). - Fixed another issue with primitives drawing to memory bitmaps. - Hopefully fix the bitmap clipping bugs, and make the D3D and OGL/Software outputs to be near-identical again. Image addon: - Added a "native loader" for MacOS X that uses the NSImage bitmap loading functions. In addition to .png and .jpg, this allows us to read a whole zoo of image formats (listed in allegro.log). - Add native support for tif, jpg, gif, png, BMPf, ico, cur, xbm formats to under IPhone. - Fixed an over-zealous ASSERT() that disallowed passing NULL to al_register_bitmap_loader() despite this being an allowed value. - Avoid using a field which is deprecated in libpng 1.4. Color addon: - Make al_color_name_to_rgb return a bool. Native dialogs addon: - Fixed some erratic behaviour and crashes on OS X. Build system: - Set VERSION and SOVERSION properties on targets to give Unix shared libraries proper sonames. e.g. liballegro[_addon].so.4.9, liballegro[_addon].4.9.dylib - Static libraries are now named without version number suffixes to minimise the differences with the shared libraries, which no longer have the versions in their base names. e.g. liballegro[_addon]-static.a, allegro[_addon]-static.lib - Windows import libraries are also named without version suffixes, e.g. liballegro[_addon].a, allegro[_addon].lib - DLLs are named with a short version suffix, not the full version. e.g. allegro-4.9.dll instead of allegro-4.9.18.dll - Add support for Mac OS X frameworks (untested), which are enabled with WANT_FRAMEWORKS and WANT_EMBED. There is one framework per addon. - Search for static OGG/Vorbis libraries built with MSVC named libogg_static.lib, etc. - Updated iPhone XCode project. Examples: - ex_mixer_pp: New example to test mixer postprocessing callbacks. - ex_threads: Make it more visually interesting and test out per-display transformations. - ex_ogre3d: New example demonstrating use of Ogre graphics rendering alongside Allegro (currently GLX only). Commented out in the build system for now. - ex_fs_window: New example to test ALLEGRO_FULLSCREEN_WINDOW flag and al_toggle_display_flag. - ex_blend2: Updated to test subtractive blending, including scaled/rotated blits and the primitives addon. - ex_mouse_events: Show "w" field. - ex_prim: Added possibility to click the mouse to advance screens (for iPhone). - ex_vsync: Display config parameters and warning. - ex_gldepth: Make the textures appear again though we're not sure why they disappeared. Documentation: - Many documentation updates. - Add which header file and which library to link with for each page of the reference manual. - Minor improvements to HTML styling and man page output. Changes from 4.9.16 to 4.9.17 (February 2010) ============================================= The main developers this time were: Trent Gamblin, Elias Pschernig, Evert Glebbeek, Paul Suntsov, Peter Wang. Core: - Removed END_OF_MAIN() everywhere. For MSVC, we pass a linker option through a #pragma. On Mac OS X, we rename main() and call it from a real main() function in the allegro-main addon. The prototype for main() for C++ applications should be "int main(int, char **)", or the code will not compile on OS X. For C, either of the normal ANSI forms is fine. \#define ALLEGRO_NO_MAGIC_MAIN disables the \#pragma or name mangling, so you can write a WinMain() or use al_run_main() yourself. Graphics: - Fixed a bug in the OpenGL driver where al_draw_bitmap() wouldn't handle blitting from the back buffer. - Changing the blending color now works with deferred drawing (Todd Cope). - Avoid some problems with window resizing in Windows/D3D. - Added al_get_d3d_texture_position. - Fixed bug under X11 where al_create_display() would always use the display options from the first al_create_display() call. - Properly implemented osx_get_opengl_pixelformat_attributes(). - Fixed automatic detection of colour depth on OS X. - Fixed al_get_num_display_modes() on Mac OS X 10.6. - Removed al_get_num_display_formats, al_get_display_format_option, al_set_new_display_format functions as they can't be implemented on OSX/iPhone/GPX ports (and were awkward to use). - Replaced al_toggle_window_frame function with a new function al_toggle_display_flags. - al_load_bitmap() and al_convert_mask_to_alpha() no longer reset the current transformation. - Add a minimize button to all non-resizable windows on Windows. - The wgl display switch-in/out vtable entries were swapped (Milan Mimica). Input: - Some keycodes were out of order in src/win/wkeyboard.c - Fixed mouse range after resizing window on Windows. - Fixed (or worked around) a joystick axis detection problem on Mac OS X. - Change timer counts from 'long' to 'int64_t'. File I/O: - Remove `ret_success' arguments from al_fread32be/le. allegro-main addon: - Added an "allegro-main" addon to hold the main() function that is required on Mac OS X. This way the user can opt out of it. Primitives addon: - Added support for sub-bitmap textures in OpenGL driver. - Added support for sub-bitmap textures in D3D driver. Made D3D sub-bitmaps work better with user D3D code. Audio addons: - Changed the _stream suffix to _f in the audio loading functions. - Added the stream versions of loading functions for wav, ogg and flac. - Rename audio I/O functions to al_load_{format}, al_save_{format}, al_load_{format}_f and al_save_{format}_f. - Added al_load_sample_f, al_save_sample_f, al_load_audio_stream_f and the related functions. - Fixed a bug where al_save_sample was improperly handling the extension. - al_drain_audio_stream would hang on an audio stream in the 'playing' state (the default) which wasn't attached to anything. - Fixed a potential deadlock on destroying audio streams by shutting down the audio driver. - Comment out PA_SINK_SUSPENDED check, which breaks the PulseAudio driver, at least on Ubuntu 9.10. - Replace unnecessary uses of `long' in audio interfaces. Image addons: - Fixed return values of al_save_bmp_f and al_save_pcx_f being ignored. - Changed the _stream suffix to _f in the image loading functions. TTF addon: - Drawing TTF fonts no longer resets the current transformation. Build system: - Add the CMake option FLAC_STATIC, required when using MSVC with a static FLAC library. - Link with zlib if linking with PhysicsFS is not enough. - Updated iPhone project files. Documentation: - Many documentation updates. Examples: - ex_display_options: Added mouse support, query current display settings, display error if a mode can't be set. Bindings: - Made the Python wrapper work under OSX. - Added a CMake option to build the Python wrapper. - Added al_run_main() mainly to support the Python wrapper on OSX. Changes from 4.9.15.1 to 4.9.16 (November 2009) =============================================== The main developers this time were: Trent Gamblin and Paul Suntsov. Graphics: - Fixed clipping of the right/bottom edges for the software primitives. - Enable sub-pixel accuracy for rotated blitting in software. - Made the D3D output look closer to the OGL/Software output. - OpenGL driver now respects the 'linear' texture filtering configuration option. Anisotropic is interpreted as linear at this time. - Added deferred bitmap drawing (al_hold_bitmap_drawing). - Made the font addons use deferred bitmap drawing instead of the primitives addon, removing the link between the two addons. - Changed al_transform_vertex to al_transform_coordinates to make the function more versatile. - Transfered transformations from the primitives addon into the core. Added documentation for that, as well as a new example, ex_transform. Transformations work for hardware accelerated bitmap drawing (including fonts) but the software component is not implemented as of yet. Also fixed some bugs inside the code of the transformations. - Increase performance of screen->bitmap blitting in the D3D driver. - Fixed a strange bug with textured primitives (u/v repeat flags were being ignored on occasion). - Added ALLEGRO_VIDEO_BITMAP for consistency. Input: - Work around a memory leak in iPhone OS that occurs when the accelerometer is on during touch input. Other core: - Don't #define true/false/bool macros in C++. Audio addon: - Some minor cleanups to the Audio Queue driver. Changes from 4.9.15 to 4.9.15.1 (October 2009) ============================================== - Fixed a problem building on MinGW (dodgy dinput.h). Changes from 4.9.14 to 4.9.15 (October 2009) ============================================ The main developers this time were: Trent Gamblin, Elias Pschernig, Matthew Leverton, Paul Suntsov, Peter Wang. Core: - Set the initial title of new windows to the app name. - Add al_set/get_event_source_data. - Make locking work on bitmaps that didn't have an FBO prior to the call on iPhone. - Make al_get_opengl_fbo work on iPhone. - Made iPhone port properly choose a visual (so depth buffer creation works). Font addon: - Improved drawing speed for longish strings. The font addon now depends on the primitives addon. Primitives addon: - Made the ribbon drawer handle the case of extremely sharp corners more gracefully. - Make al_draw_pixel use blend color in the D3D driver. - Added POINT_LIST to the primitive types. - Various fixes for the D3D driver: fixed line loop drawing; made the indexed primitives a little faster; added workabouts for people with old/Intel graphics cards. - Fall back to software if given a memory bitmap as a texture. - Removed OpenGL state saving code, it was causing massive slowdown when drawing. Also removed glFlush for the same reason. Audio addon: - Added PulseAudio driver. - Support AudioQueue driver on Mac OS X. - Add al_uninstall_audio exit function. - Added ALLEGRO_EVENT_AUDIO_STREAM_FINISHED event to signify when non-looping streams made with al_load_audio_stream reach the end of the file. - Fixed a deadlock when destroying voices. - Handle underruns in the r/w ALSA updater. - Minor change to the ALSA driver to improve compatibility with PulseAudio. Documentation: - Replaced awk/sh documentation scripts with C programs. Changes from 4.9.13 to 4.9.14 (September 2009) ============================================== The main developers this time were: Trent Gamblin, Elias Pschernig, Paul Suntsov, Peter Wang. Other contributions from: Evert Glebbeek, Matthew Leverton. Ports: - Elias Pschernig and Trent Gamblin started a iPhone port. Graphics: - Added al_get_opengl_texture_size and al_get_opengl_texture_position functions. - Try to take into account GL_PACK_ALIGNMENT, GL_UNPACK_ALIGNMENT when locking OpenGL bitmaps. - Fixed all (hopefully) conversion mistakes in the color conversion macros. - Sped up memory blitting, which was using conversion even with identical formats (in some cases). - Make al_set_current_display(NULL); unset the current display. - Added ALLEGRO_LOCK_READWRITE flag for al_lock_bitmap (in place of 0). - Fixed window titles which contain non-ASCII characters in X11. - Added OES_framebuffer_object extension. Input: - Added a lot more system mouse cursors. - Renamed al_get_cursor_position to al_get_mouse_cursor_position. - Prevent Windows from intercepting ALT for system menus. Filesystem: - Make the path returned by al_get_entry_name() owned by the filesystem entry so the user doesn't need to free it manually. - Renamed the filesystem entry functions, mainly to include "fs_entry" in their names instead of just "entry". - Reordered and renamed ALLEGRO_FS_INTERFACE members. - Make al_read_directory() not return . and .. directory entries. - Renamed al_create_path_for_dir to al_create_path_for_directory. - Added al_set_standard_file_interface, al_set_standard_fs_interface. Events: - Exported ALLEGRO_EVENT_TYPE_IS_USER. Threads: - Added a new function al_run_detached_thread. Other core: - Put prefixes on register_assert_handler, register_trace_handler. - Added functions to return the compiled Allegro version and addon versions. - Added al_ prefix to fixed point routines and document them. - Added al_get_system_config(). - Renamed al_system_driver() to al_get_system_driver(). - Added 64-bit intptr_t detection for Windows. - Added work-around to make OS X port compile in 64 bit mode. Addons: - Renamed addons from a5\_\* to allegro_*. Image addon: - Renamed the IIO addon to "allegro_image". - Renamed \*\_entry functions that take ALLEGRO_FILE * arguments to *_stream. - Fixed off-by-one error in greyscale JPEG loader. Audio addons: - Renamed the kcm_audio addon to "allegro_audio". - Renamed ALLEGRO_STREAM and stream functions to ALLEGRO\_AUDIO\_STREAM and al\_\*audio_stream\*. - Renamed al_stream_from_file to al_load_audio_stream - Added int16 mixing and configurable frequency and depth for default mixer/voice (see configuration file). - Fixed FLAC decoding and added FLAC streaming support. - Changed the function signature of al_get_stream_fragment() to be more straightforward. - Fixed bug in kcm audio that caused data to be deleted that was still used. - Made ALSA audio driver work when the driver does not support mmap (commonly because the ALSA really is PulseAudio). - Removed al_is_channel_conf function. Font addons: - Optimized font loading by converting the mask color on a memory copy instead of have to lock a texture. - Made the ttf addon read from file streams. Primitives addon: - Fixed the direction of the last segment in software line loop, and fixed the offsets in the line drawer. - Fixed the thick ribbon code in the primitives addon, was broken for straight segments. - Various fixes/hacks for the D3D driver of the primitives addon: hack to make the indexed primitives work and a fix for the textured primitives. - Various enhancements to the transformations API: const correctness, transformation inverses and getting the current transformation. - Added support for custom vertex formats. - Flipped the v axis of texture coordinates for primitives. Now (u=0, v=0) correspond to (x=0, y=0) on the texture bitmap. - Added a way to use texture coordinates measured in pixels. Changed ALLEGRO_VERTEX to use them by default. PhysicsFS: - PhysFS readdir didn't prepend the parent directory name to the returned entry's path. - Set execute bit on PhysFS directory entries. Examples: - Made examples report errors using the native dialogs addon if WANT_POPUP_EXAMPLES is enabled in CMake (default). - Added new example ex_draw_bitmap, which simply measures FPS when drawing a bunch of bitmaps (similar to exaccel in A4). Documentation: - Many documentation updates and clarifications. - Fixed up Info and PDF documentation. Bindings: - Added a script to generate a 1:1 Python wrapper (see `python` directory). Changes from 4.9.12 to 4.9.13 (August 2009) =========================================== The main developers this time were: Trent Gamblin, Elias Pschernig, Paul Suntsov, Peter Wang. Other contributions from: Todd Cope, Evert Glebbeek, Michael Harrington, Matthew Leverton. Ports: - Trent Gamblin started a port to the GP2X Wiz handheld console. Graphics: - Some OpenGL bitmap routines were not checking whether the target bitmap was locked. - Scaled bitmap drawer was not setting the blend mode. - Fixed a bug where al_map_rgb followed by al_unmap_rgb would return different values. - Fixed problems with sub-sub-bitmaps. - Fixed window placement on OS X, which did not properly translate the coordinates specified by the user with al_set_new_window_position(). - Made is_wgl_extension_supported() fail gracefuly. - Added ALLEGRO_ALPHA_TEST bitmap flag. - Minor optimizations in some memory blitting routines. Input: - Replaced (ALLEGRO_EVENT_SOURCE *) casting with type-safe functions, namely al_get_keyboard_event_source, al_get_mouse_event_source, al_get_joystick_event_source, al_get_display_event_source, al_get_timer_event_source, etc. - Made it so that users can derive their own structures from ALLEGRO_EVENT_SOURCE. al_create_user_event_source() is replaced by al_init_user_event_source(). - Fixed a problem on Windows where the joystick never regains focus when tabbing away from a window. - Fixed a problem with missing key repeat with broken X.Org drivers. - Implemented ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY, ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY for X11. Image I/O addon: - Changed return type of al_save_bitmap() to bool. - Separated al_add_image_handler into al_register_bitmap_loader, al_register_bitmap_saver, etc. - Made JPEG and PNG loaders handle al_create_bitmap() failing. - Speed up JPEG loading and saving. - Fixed a reinitialisation issue in iio. Audio addons: - Moved basic sample loading/saving routines to kcm_audio from acodec and added file type registration functions. - Moved WAV support into kcm_audio. - Made WAV loader not choke on extra chunks in the wave. - Separated acodec into a5_flac, a5_vorbis addons. You need to initialise them explicitly. Removed sndfile support. - Renamed al\_\*\_oggvorbis to al\_\*\_ogg\_vorbis. - Changed argument order in al_save_sample and al_stream_from_file. - Reordered parameters in al\_attach\_* functions to follow the word order. - Renamed a few streaming functions to refer to fragments/buffers as fragments consistently. - Added missing getters for ALLEGRO_SAMPLE fields. - Fixed mutex locking problems with kcm_audio objects. - Avoid underfilling a stream when it is fed with a short looping stream. Other addons: - Added glyph advance caching for the TTF addon. - Renamed al_register_font_extension to al_register_font_loader. Match the file name extension case insensitively. Documentation: - Lots of documentation updates. - Added a short "Getting started guide" to the reference manual. Examples: - Added another example for kcm_audio streaming: ex_synth. Build system: - Fix pkg-config .pc files generated for static linking. - DLL symbols are now exported by name, not ordinals. Changes from 4.9.11 to 4.9.12 (July 2009) ========================================= - Fixed bugs in Windows keyboard driver (Todd Cope). - Fixed problems with ALLEGRO_MOUSE_STATE buttons on Windows (Milan Mimica). - Fixed problems with PhysicsFS addon DLL on MSVC (Peter Wang). - Set the D3D texture address mode to CLAMP (Todd Cope). - Fixed hang if Allegro was initialized more than once on Windows (Michael Harrington). - Added a CMake option to force the use of DllMain style TLS on Windows, for use with C# bindings (Michael Harrington). - Fixed a bug where drawing circles with a small radius would crash (Elias Pschernig). - Fixed several memory leaks throughout the libraries (Trent Gamblin). - Fixed some compilation warnings on Mac OS X (Evert Glebbeek). - Small documentation updates. Changes from 4.9.10.1 to 4.9.11 (June 2009) =========================================== The main developers this time were: Trent Gamblin, Milan Mimica, Elias Pschernig, Paul Suntsov, Peter Wang. Other contributions from: Christopher Bludau, David Capello, Todd Cope, Evert Glebbeek, Peter Hull. Graphics: - Changed rotation direction in memory blitting routines to match D3D/OpenGL routines. - Made al_set_target_bitmap not create an FBO if the bitmap is locked. - Added explicit FBO handling functions al_get_opengl_fbo and al_remove_opengl_fbo in case we weren't quite clever enough above and the user has to intervene manually. - Added OpenGL 3.1 support and a bunch of new OpenGL extensions. - Fixed al_inhibit_screensaver on Windows - Fixed selection of X pixel formats with WGL if a new bitmap has alpha. - Made X11 icon work regardless of the backbuffer format. Input: - Ditched DirectInput keyboard driver and replaced it with WinAPI. Fixes several issues the old driver had. - Rewrote Windows mouse driver to use WinAPI instad of DirectInput. - Added al_get_joystick_number. Filesystem: - Merged ALLEGRO_FS_HOOK_ENTRY_INTERFACE into ALLEGRO_FS_INTERFACE and made ALLEGRO_FS_INTERFACE public. - Added al_set_fs_interface and al_get_fs_interface. - Made al_opendir take an ALLEGRO_FS_ENTRY. - Removed functions which are obsolete or probably have no use. - Made al_get_standard_path(ALLEGRO_PROGRAM_PATH) return a path with an empty filename. Path routines: - Renamed functions to follow conventions. File I/O: - Fix al_fgets() returning wrong pointer value on success. Primitives addon: - Added support for textured primitives in software. - Introduced ALLEGRO_PRIM_COLOR, removed ALLEGRO_VBUFFER. - Exposed the software line and triangle drawers to the user. - Added rounded rectangles. - Fix an extraneous pixel bug in the triangle drawer. Audio addon: - Change from using generic get/set audio property functions to specific getter/setter functions. - Change return types on many functions to return true on success instead of zero. (Watch out when porting your code, the C compiler won't help.) Native dialogs: - Added a Windows implementation. - Added a title to al_show_native_message_box(). Other addons: - Implemented the filesystem interface for PhysicsFS and demonstrate its use in ex_physfs. - Fixed al_color_html_to_rgb. Examples: - Added an OpenGL pixel shader example. Build system: - Output separate pkg-config .pc files for static linking. Changes from 4.9.10 to 4.9.10.1 (May 2009) ========================================== - Fixed uses of snprintf on MSVC. - Disabled ex_curl on Windows as it requires Winsock. Changes from 4.9.9.1 to 4.9.10 (May 2009) ========================================= The main developers this time were: Trent Gamblin, Evert Glebbeek, Milan Mimica, Elias Pschernig, Peter Wang. Other contributions from: Peter Hull, Paul Suntsov. Graphics: - Renamed al_clear() to al_clear_to_color(). - Renamed al_opengl_version() to al_get_opengl_version(). - Changed the direction of rotation for al_draw_rotated* from counter-clockwise to clockwise. - Added new pixel format ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE which guanrantees component ordering. - Added ALLEGRO_NO_PRESERVE_TEXTURE flag. - Fixed horizontal flipping in plain software blitting routines. - Fixed some blending bugs in the OpenGL driver. - Made OpenGL driver fall back to software rendering if separate alpha blending is requested but not supported. - Added a config option which allows pretending a lower OpenGL version. - Implemented al_get_num_display_formats(), al_get_display_format_option() and al_set_new_display_format() for WGL. - Fixed bug in al_get_display_format_option() with the GLX driver. - Fixed a bug in the D3D driver that made display creation crash if the first scored mode failed. - Made the OpenGL driver prefer the backbuffer format for new bitmaps. - Defer FBO creation to when first setting a bitmap as target bitmap. Input: - Renamed some joystick functions. - Account for caps lock state in OS X keyboard driver. - Made UTF-8 input work on X11. File I/O: - Separated part of fshook API into a distinct file I/O API (actually generic streams). - Make the file I/O API match stdio more closely and account for corner cases. (incomplete) - Made it possible to set a stream vtable on a per-thread basis, which affects al_fopen() for that thread. - Added al_fget_ustr() to read a line conveniently. - Change al_fputs() not to do its own CR insertion. - Add al_fopen_fd() to create an ALLEGRO_FILE from an existing file descriptor. Filesystem: - Changed al_getcwd, al_get_entry_name to return ALLEGRO_PATHs. - Renamed al_get_path to al_get_standard_path, and to return an ALLEGRO_PATH. - Changed al_readdir to return an ALLEGRO_FS_ENTRY. - Added al_path_create_dir. - Removed some filesystem querying functions which take string paths (ALLEGRO_FS_ENTRY versions will do). Config routines: - Added functions to traverse configurations structures. - Change al_save_config_file() return type to bool. - Removed an arbitrary limit on the length of config values. - Renamed configuration files to allegro5.cfg and allegro5rc. String routines: - Allegro 4-era string routines removed. - Added al_ustr_to_buffer(). Other core: - Renamed al_thread_should_stop to al_get_thread_should_stop. - Added a new internal logging mechanism with configurable debug "channels", verbosity levels and output formatting. - Cleaned up ASSERT namespace pollution. Font addons: - Renamed font and TTF addon functions to conform to conventions. - Added al_init_ttf_addon. - Implemented slightly nicer text drawing API: - functions are called "draw_text" instead of "textout" - centre/right alignment handled by a flag instead of functions - functions accepting ALLEGRO_USTR arguments provided - substring support is removed so 'count' arguments not needed in usual case, however ALLEGRO_USTR functions provide similar thing. - Removed al_font_is_compatible_font. - Sped up al_grab_font_from_bitmap() by five times. - ttf: Fixed a possible bug with kerning of unicode code points > 127. Image I/O addon: - Renamed everything in the IIO addon. - Exposed al_load_bmp/al_save_bmp etc. Audio addon: - Renamed al_mixer_set_postprocess_callback. - Added two config options to OSS driver. - Made ALSA read config settings from [alsa] section. Native dialogs: - Added al_show_native_message_box() which works like allegro_message() in A4. Implemented for GTK and OS X. PhysicsFS addon: - Added PhysicsFS addon. Primitives addon: - Removed global state flags. - Removed normals from ALLEGRO_VERTEX. - Removed read/write flags from vertex buffers. Examples: - Added an example that tests al_get_display_format_option(). - Added an example which shows playing a sample directly to a voice. - Added an example for PhysicsFS addon. - Added a (silly) example that loads an image off the network using libcurl. - Added ex_dir which demonstrates the use of al_readdir and al_get_entry_name. Other: - Many bug and documentation fixes. Changes from 4.9.9 to 4.9.9.1 (March 2009) ========================================== - Made it compile and work with MSVC and MinGW 3.4.5. - Enabled SSE instruction set in MSVC. - Fixed X11 XIM keyboard input (partially?). - Fall back on the reference (software) rasterizer in D3D. Changes from 4.9.8 to 4.9.9 (March 2009) ======================================== The main developers this time were: Trent Gamblin, Evert Glebbeek, Milan Mimica, Elias Pschernig, Paul Suntsov, Peter Wang. Other contributions from: Todd Cope, Angelo Mottola, Trezker. Graphics: - Added display options API and scoring, based on AllegroGL, for finer control over display creation. - Added API to query possible display formats (implemented on X, Mac OS X). - Changed the bitmap locking mechanism. The caller can choose a pixel format. - Added support for multisampling. - Simplified the semantics of al_update_display_region(). - Optimised software blitting routines. - Optimised al_map_rgb/al_map_rgba. - Replaced al_draw_rectangle() and al_draw_line() from core library with al_draw_rectangle_ex() and al_draw_line_ex() from the primitives addon. - Implemented al_wait_for_vsync() everywhere except WGL. - Fixed problems with sub-bitmaps with the OpenGL driver. - Fixed bugs in software scaled/rotated blit routines. - Added a new pixel format ALLEGRO_PIXEL_FORMAT_ABGR_F32. Removed ALLEGRO_PIXEL_FORMAT_ANY_15_WITH_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_24_WITH_ALPHA. - Added support for creating OpenGL 3.0 contexts (untested; only WGL/GLX for now). Relevant display flags are ALLEGRO_OPENGL_3_0 and ALLEGRO_OPENGL_FORWARD_COMPATIBLE. - Allow disabling any OpenGL extensions from allegro.cfg to test alternative rendering paths. - Fixed problem with windows only activating on title bar clicks (Windows). - Fixed a minimize/restore bug in D3D (with the help of Christopher Bludau). Input: - Implemented al_set_mouse_xy under X11. - Added ALLEGRO_EVENT_MOUSE_WARPED event for al_set_mouse_xy(). Path routines: - Made al_path_get_drive/filename return the empty string instead of NULL if the drive or filename is missing. - Changed al_path_set_extension/al_path_get_extension to include the leading dot. - Made al_path_get_extension(), al_path_get_basename(), al_path_to_string() return pointers to internal strings. Unicode: - Changed type of ALLEGRO_USTR; now you should use pointers to ALLEGRO_USTRs. - Added UTF-16 conversion routines. Other core: - Added ALLEGRO_GET_EVENT_TYPE for constructing integers for event type IDs. - Renamed configuration function names to conform to conventions. - Removed public MIN/MAX/ABS/MID/SGN/CLAMP/TRUE/FALSE macros. - Replaced AL_PI by ALLEGRO_PI and documented it as part of public API. Audio addons: - Added stream seeking and stream start/end loop points. - Add panning support for kcm_audio (stereo only). Font addons: - Made al_font_grab_font_from_bitmap() accept code point ranges. - Made font routines use new UTF-8 routines; lifted some arbitrary limits. - Fixed artefacts in bitmap font and TTF rendering. Image I/O addon: - Made the capability to load/save images from/to ALLEGRO_FS_ENTRYs public. - Added missing locking to .png save function. Other addons: - Added native_dialog addon, with file selector dialogs. - Fixed many bugs in the primitives addon. - Made hsv/hsl color functions accept angles outside the 0..360° range. - Fixed a bug in al_color_name_to_rgb. Examples: - New programs: ex_audio_props, ex_blend_bench, ex_blend_test, ex_blit, ex_clip, ex_draw, ex_font_justify, ex_gl_depth, ex_logo, ex_multisample, ex_native_filechooser, ex_path_test, ex_rotate, ex_stream_seek, ex_vsync, ex_warp_mouse. (ex_draw demonstrated known bugs currently.) - Updated programs: ex_joystick_events, ex_monitorinfo ex_pixelformat, ex_scale, ex_subbitmap. Build system: - Added pkg-config support. .pc files are generated and installed on Unix. - Allowed gcc to generate SSE instructions on x86 by default. For Pentium 2 (or lower) compatibility you must uncheck a CMake option before building Allegro. Other: - Many other bug fixes. Changes from 4.9.7.1 to 4.9.8 (February 2009) ============================================= The main developers this time were: Thomas Fjellstrom, Trent Gamblin, Evert Glebbeek, Matthew Leverton, Milan Mimica, Elias Pschernig, Paul Suntsov, Peter Wang. General: - Lots of bug fixes. File system hooks: - Rationalised file system hook functions. Failure reasons can be retrieved with al_get_errno(). - Enable large file support on 32-bit systems. - Converted the library and addons to use file system hook functions. Path functions: - Added al_path_clone(), al_path_make_canonical(), al_path_make_absolute(), al_path_set\_extension(), al\_{get,set}\_org_name, al\_{get,set}_app_name} functions. - Made al_path_get_extension() not include the leading "." of the extension, - Add AL_EXENAME_PATH, AL_USER_SETTINGS_PATH, AL_SYSTEM_SETTINGS_PATH enums for al_get_path(). String routines: - Added a new, dynamically allocating UTF-8 string API. This uses bstrlib internally, which is distributed under a BSD licence. Allegro 5 will expect all strings to be either ASCII compatible, or in UTF-8 encoding. - Removed many old Unicode string functions. (Eventually they will all be removed.) Config routines: - Clarified behaviour of al_config_add_comment, al_config_set_value with regards to whitespace and leading comment marks. Graphics: - Bug fixes on Windows and Mac OS X for resizing, switching away, setting full screens, multi-monitor, etc. - Added an al_get_opengl_texture() convenience function. - Added separate alpha blending. - Added ALLEGRO_PIXEL_FORMAT_ANY. - Honour al_set_new_window_position() in X11 port. - Made the X11 port fail to set a full screen mode if the requested resolution cannot be set rather than falling back to a windowed mode. Input: - Added a field to the mouse state struct to indicate the display the mouse is currently on. - Made DirectX enumerate all joysticks/gamepads properly by using a device type new to DirectInput 8. - Fixed a bug in wmouse.c where y was not changed in al_set_mouse_xy. - Support ALLEGRO_EVENT_MOUSE_ENTER/LEAVE_DISPLAY events in Windows. Addons: - Added a primitives addon. - Revamp interface for kcm_audio addon to make simple cases easier. - Added native .wav support and save sample routines to acodec addon. - Added a colors addon. - Added memory file addon and example. TTF addon: - Added al_ttf_get_text_dimensions() function. - Allow specifying the font size more precisely by passing a negative font size. - Guess the filenames of kerning info for Type1 fonts. Documentation: - Added a new documentation system using Pandoc. Now we can generate HTML, man, Info and PDF formats. - Added and fixed lots of documentation. Examples: - Added ex_prim, ex_mouse_focus examples. - Made ex_blend2 more comprehensive. - Updated ex_get_path example. - Made ex_ttf accept the TTF file name on the command line. Build system: - Use official CMAKE_BUILD_TYPE method of selecting which build configuration. This should work better for non-make builds, however, it's no longer possible to build multiple configurations with a single configuration step as we could previously. Removals: - Remove outdated A4 tools. - Remove icodec addon. - SCons build was unmaintained and not working. Changes from 4.9.7 to 4.9.7.1 (December 2008) ============================================= - Scan aintern_dtor.h for export symbols, needed for MSVC. Changes from 4.9.6 to 4.9.7 (December 2008) =========================================== The main developers this time were: Trent Gamblin, Evert Glebbeek, Peter Hull, Milan Mimica, Peter Wang. Graphics: - Fixed a bug where the "display" field of a bitmap was not correctly reset when it was transfered to another display on OS X. - Made al_create_display() respect al_set_new_window_position() on OS X. - Fixed the bug that caused input focus to be lost in OS X when a window was resized. - Made resizable Allegro windows respond properly to the green "+" button at the top of the screen on OS X. - Properly implemented fullscreen resize in WGL. - Made the memory blenders work the same as the hardware ones. - Made al_get_pixel()/al_draw_pixel() handle sub bitmaps in case the bitmap was locked. - In the OpenGL driver, if the bitmap is locked by the user, use memory drawing on the locked region. - Added implementations of al_inhibit_screensaver() for the X and Mac OS X ports. - Added multi-monitor support to Mac OS X port (untested!). - Other fixes. Input: - Made al_get_keyboard_state() return structures with the `display' field correctly set. - Made keyboard event member 'unichar' uppercase when Shift/CapsLock is on, in Windows. - Made mouse cursor show/hide work with Mac OS X full screen. Config routines: - Preserve comment and empty lines in config files when writing. Addons: - Add a simple interface layer for kcm_audio. - Made kcm_audio objects automatically be destroyed when it is shut down. - Renamed functions in kcm_audio to conform better with the rest of the library. - Made the TTF addon aggregate glyph cache bitmaps into larger bitmaps for faster glyph rendering (less source bitmap switching). Examples: - Add an example to test the ALLEGRO_KEYBOARD_STATE `display' field. - Add an example for testing config routines. - Add an example for checking software blending routines against hardware blending. - Add an example for the simple interface for kcm_audio. Changes from 4.9.5 to 4.9.6 (November 2008) =========================================== The core developers this time were: Thomas Fjellstrom, Trent Gamblin, Evert Glebbeek, Peter Hull, Milan Mimica, Jon Rafkind, Peter Wang. Allegro 4.9.6 and onwards are licensed under the zlib licence (see LICENSE.txt). This is a simple permissive free software licence, close in spirit to the 'giftware' licence, but is clearer and more well-known. General: - Added filesystem hook (fshook) and path API functions. - Many minor bug fixes. Graphics: - Added allegro5/a5_opengl.h, which has to be included by programs to use OpenGL specifics. ALLEGRO_EXCLUDE_GLX and ALLEGRO_EXCLUDE_WGL can be #defined to exclude GLX and WGL OpenGL extensions respectively. - Added allegro/a5_direct3d.h, which has to be included by programs to use D3D specifics. - Fixed some drawing from and onto sub-bitmaps. - Fixed blending with the wrong color in case of sub-bitmaps. - Fixed a bug in the D3D driver where the transformation matrix was not reset after drawing a bitmap. - Added draw pixel to OpenGL driver. - Added more OpenGL extensions. - Added function to inhibit screen saver (currently Windows only). Config routines: - Added al_config_create(). - Deleted al_config_set_global(). Made empty section name equivalent to the global section. - Read system wide and home directory config files on Unix (Ryan Patterson). Events: - Added support for injecting user-defined events into event queues. Audio addon: - Made the ALSA driver read the device name from the config file (Ryan Patterson). Examples: - Added ex_subbitmap example. - Added ex_disable_screensaver example. Build system: - Rationalised library names and made CMake and SCons build systems agree on the names. Changes from 4.9.4 to 4.9.5 (October 2008) ========================================== The core developers this time were: Trent Gamblin, Evert Glebbeek, Peter Hull, Milan Mimica, Elias Pschernig, Jon Rafkind, Peter Wang. Graphics: - Added fullscreen support on Mac OS X. - Added support for resizable windows on Mac OS X. - Made frameless windows respond to events on Mac OS X. - Fixed a problem with D3D blending. - Made D3D driver work on systems without hardware vertex processing. - Made WGL driver fail more gracefully. - Implemented sprite flipping for OpenGL drivers (Steven Wallace). - Added al_is_sub_bitmap() function. Input: - Fixed input with multiple windows on Windows. - Fixed keyboard autorepeat events in X11. - Added al_is_keyboard_installed(). - Fixed key shifts on Windows (ported from 4.2). - Fixed mouse button reporting on Mac OS X. - Implemented system mouse cursors on MacOS X. - Fixed mouse cursors with alpha channels on X11. - Some work on Mac OS X joystick support (incomplete). Events: - Simplified internals of events system further. At the same time, this change happens to also allow event queues to grow unboundedly. (You should still avoid letting them get too big, of course.) Audio addons: - Made ALLEGRO_STREAM objects emit events for empty fragments that need to be refilled. - Added a possiblity to drain a stream created by al_stream_from_file(). - Added a function to rewind a stream. - Added gain support to ALLEGRO_STREAM and ALLEGRO_SAMPLE objects. - Made it possible to attach a sample to a mixer that isn't already attached to something. - Fixed Ogg Vorbis loader on big-endian systems. - Made the OpenAL driver the least preferred driver, as it doesn't play stereo samples properly. Image addons: - Added JPEG support to iio addon, using libjpeg. - Fixed TGA loader on big-endian systems. - Fixed image loading in icodec addon. Font addon: - Fixed count-restricted text output functions calculations on non-ASCII strings. - Made al_textout* functions always a 'count' parameter. - Renamed al_font_text_length* to al_font_text_width*. - Harmonised the order of al_font_textout* and al_font_textprintf* arguments. Examples: - Added ex_bitmap_flip example (Steven Wallace). - Added ex_mixer_chain example. - Split ex_events into smaller examples. - Made the demo use ALLEGRO_STREAM to play music. - Build an app bundle from the demo, on Mac OS X. Build system: - Improved detection of external dependencies in CMake build. - Guess compiler locations for MinGW and MSVC (CMake). - Many improvements to scons build, including install support. General: - Many other bug fixes. Changes from 4.9.3 to 4.9.4 (September 2008) ============================================ The core developers this time were: Trent Gamblin, Peter Hull, Milan Mimica, Elias Pschernig and Peter Wang. Ryan Dickie and Jon Rafkind also contributed. General: - Many bug fixes all around. - Added a public threads API. - Added a basic configuration API. - Added al_store_state/al_restore_state functions. - Added al_get_errno/al_set_errno (not used much yet). - Renamed some functions/structures to be more consistent. - Code formatting improvements. - Added more debugging messages. - Removed a lot of A4 code that is no longer used. Graphics: - Added support for some new OpenGL extensions. - Multihead support on Windows (preliminary support on OSX and Linux). - Many enhancements to all drivers. - Merged common parts of WGL and D3D drivers. - Borderless windows, setting window positions and titles. - Fullscreen support on OSX and Linux. - Do not clear bitmaps when they are created. - Improved compile times and DLL sizes by simplifying "memblit" functions. - Added EXPOSE, SWITCH_IN and SWITCH_OUT display events. Build system: - Many bug fixes and enhancements to SCons and CMake build systems. - Support for Turbo C++ 2006. - Support for cross-compiling on Linux to MinGW (CMake). Events: - Filled in a display field for all relevant events. - Added al_wait_for_event_until. Addons: - Added an ImageMagick addon - Added iio (Image IO) addon - Supports BMP, PCX, TGA. - Supports PNG support with libpng. - Added new audio addon, kcm_audio. (The 'audio' addon was taken in a new direction between the 4.9.3 and 4.9.4 releases, but we decided against that, so actually it's actually a continuation of the old audio addon.) - Added audio streaming functionality. - Added OSS, ALSA, DirectSound drivers. - A lot of reorganisation, internally and externally. - Added TTF font addon, using FreeType. - Made all addons use "al_" prefix. Examples: - Lots of new examples. - Wait for keypress in some examples instead of arbitrary delay. - Clean up files when done in some examples. Changes from 4.9.2 to 4.9.3 (April 2008) ======================================== Graphics: - Milan Mimica did lots of work on the OpenGL drivers, such as adding an OpenGL driver for Windows and making the OpenGL code shared between platforms. - Peter Hull added an OpenGL graphics driver for Mac OS X. - Milan Mimica made the OpenGL driver share contexts between displays. - Peter Wang and Milan Mimica made the OpenGL driver work with cards that don't support non-power-of-two (NPOT) textures. - Trent Gamblin added support for NPOT textures in the Direct3D driver. - Trent Gamblin fixed blending in memory drawing functions. - Trent Gamblin added al_draw_pixel() which obeys blending. - Trent Gamblin made al_clear() not affected by blending in D3D. - Milan Mimica added the following functions to the public API: al_opengl_version(), al_is_opengl_extension_supported(), al_get_opengl_proc_address(), al_get_opengl_extension_list(). - Milan Mimica added sub-bitmaps support for memory bitmaps and in the OpenGL display driver. - Milan Mimica made displays keep a list of bitmaps. When destroying a display its bitmaps will be managed properly, e.g. converted to memory bitmaps if necessary. All display bitmaps will be automatically destroyed on exit. - Peter Wang made X window resizing work without GLX 1.3. - Trent Gamblin fixed a bug in the Direct3D driver when windows were minimized (thanks to David McCallum). - Trent Gamblin fixed the coordinates of Direct3D primitives to match OpenGL style. - Peter Hull fixed some logic in bitmap drawing and al_load_bitmap(). Fonts: - Milan Mimica made font drawing faster, by making glyphs sub-bitmaps of a larger glyph sheet. - Milan Mimica and Peter Wang made font loading faster. - Trent Gamblin added versions of text output functions which take as an explicit argument the length of the strings. Audio: - A new audio API implementation, originally by Chris Robinson, was added (currently as an addon only). It has received additional work in the past from Milan Mimica and recently much work from Ryan Dickie. - Ryan Dickie also added an acodec addon, which has loaders for FLAC, Wave and Ogg Vorbis files, using other libraries. Timers: - Ryan Dickie changed the type of timestamps throughout the API from int expressed in milliseconds to double expressed in seconds and improved timer resolution on Windows. - Ryan Dickie added an 'error' field to the timer event, and added error and overhead statistics to exnew_timer. - Trent Gamblin made the Windows timer use QueryPerformanceCounter. - Peter Wang split al_wait_for_event() into two functions, a version that takes a timeout and a version that doesn't. - Trent Gamblin merged the Windows and Unix timer source files. Input: - Peter Wang renamed some joystick and timer functions to adhere to the `al__` convention. - Peter Wang made al_num_joysticks() more lenient if there is no joystick driver installed. Other: - David Capello added support for various different BMPs. - Elias Pschernig fixed compilation of the X port in case the XVidMode extension is unavailable (thanks to Thomas Fjellstrom). - Elias Pschernig added a exnew_timer example. - Trent Gamblin added exnew_multiwin and exnew_drawpixels. - Peter Wang added exnew_timedwait and exnew_scale. - Jon Rafkind and Elias Pschernig updated the SCons build. - Jon Rafkind added a `_s` suffix to static libraries in the SCons build. - Elias Pschernig did some work on cross-compilation with SCons and MinGW. - Milan Mimica made the CMake build work with MSVC project solutions and made the library build with MSVC 8. - Jacod Dawid added a nicer spaceship graphic for a5teroids demo. - Many more bug fixes and documentation updates. Changes from 4.9.1 to 4.9.2 (November 2007) =========================================== *This list is still to be summarised.* - Trent Gamblin made the mouse cursor always hide when the user calls al_hide_mouse_cursor in fullscreen (D3D). - Trent Gamblin fixed some signedness warnings and implemented show/hide_mouse in the display vtable for D3D. - Elias Pschernig made show/hide cursor use the display driver instead of the 4.2 gfx_driver. - Elias Pschernig fixed missing keyboard events in exnew_mouse_events example. - Elias Pschernig wired the X11 mouse driver to the XGLX system driver. - Jon Rafkind made various fixes to get the OSX build to compile - Trent Gamblin added exnew_mouse_events. - Trent Gamblin added exnew_mouse. - Jon Rafkind made the scons build get the library name dynamically. - Jon Rafkind made the scons build link Allegro using -l instead of using the full path. - Trent Gamblin added a note about MINGDIR in readme_a5.txt. - Trent Gamblin removed -lalleg_unsharable from allegro-config.in, since assembly is not used anymore. - Jon Rafkind fixed up allegro-config. - Trent Gamblin added some documentation on ALLEGRO_MSESTATE. - Trent Gamblin listed the examples in readme_a5.txt. - Trent Gamblin improved some inline documentation. - Jon Rafkind removed /lib from install path in unix.scons. - Jon Rafkind added the new demo to the scons build and allowed addons to be built statically or shared. - Trent Gamblin made the glx line drawing function use blending. - Trent Gamblin added cmake instructions to readme_a5.txt. - Elias Pschernig added readme_a5.txt. - Trent Gamblin fixed warnings in the demo. - Trent Gamblin fixed a crash-on-exit bug in tls.c. - Trent Gamblin replaced the old demo with a temporary one. - Peter Wang fixed gcc string warnings. - Peter Wang added some assertions to display_new.c. - Peter Wang merged changes from the 4.2 branch. - Elias Pschernig removed an unnecessary import from the naturaldocs upload script. - Elias Pschernig added a script to automatically upload the naturaldocs generated documentation to the website. - Peter Wang fixed missed renamings from AL_ to ALLEGRO_ in the Linux and X code. - Elias Pschernig merged 4.9-newgfx back to 4.9. - Peter Wang fixed a "ALLEGRO__JOYSTICK" typo. - Trent Gamblin renamed AL_ to ALLEGRO_ in input, events, and timer code. - Elias Pschernig implemented outline flag and blending for draw_rectangle in the GLX driver. - Elias Pschernig added another mysha.pcx for the font example. - Elias Pschernig re-added GLX checked to scons build which went missing in the merge. - Elias Pschernig added icon.xpm which went missing in the merge. - Peter Wang replaced _al_draw_bitmap_region_memory_fast with _al_draw_bitmap_region_memory. - Trent Gamblin made memblit.c compile a little faster in debug mode. - Peter Wang mergedd changes in r7948:10859 on 4.9 branch to 4.9-newgfx branch. - Peter Wang enabled WANT_D3D by default. Only set ALLEGRO_D3D on Windows. - Trent Gamblin made al_acknowledge_resize take the display as a parameter. - Trent Gamblin fixed some warnings and made the MinGW build compilable statically with gcc 4.2.1. - Peter Wang fixed a bug in ALLEGRO_CONVERT_BGR_565_TO_ARGB_4444. - Peter Wang renamed al_memory_management_functions() to al_set_memory_management_functions() and added some extra documenation for it. - Peter Wang removed NaturalDocs markup for Allegro 4.x display functions. - Peter Wang made OpenGL libraries link if building with X11 support. - Peter Wang fixed a signedness warning. - Peter Wang made al_destroy_bitmap return immediately when passed a null pointer instead of segfaulting. - Elias Pschernig made some cosmetic improvements to the code. - Elias Pschernig removed a bad optimization. - Elias Pschernig removed > GLX 1.1 specific code. - Trent Gamblin fixed several of the floating point unmapping functions that were doing integer division. - Elias Pschernig implemented blending in the GLX driver. - Elias Pschernig fixed GLX rotation to use radians and allow negative angles. - Elias Pschernig implemented rotated blitting in the GLX driver. - Jon Rafkind made scons install addons/font. - Jon Rafkind added a scons file for addons. - Jon Rafkind used target_scanner to find makedoc instead of using Depends. - Jon Rafkind forced makedoc to be a dependancy of the docs. - Trent Gamblin made 60hz the default refresh rate of the D3D driver. - Trent Gamblin changed al_create_mouse_cursor to accept ALLEGRO_BITMAP structures. - Trent Gamblin renamed __al_unmap_rgba to al_unmap_rgba_ex in the glx driver. - Trent Gamblin made al_(map|unmap)_rgb(a)_*_ex public. - Trent Gamblin made D3D windows show the resize cursor when resizing windows. - Jon Rafkind added allegro includes for asmdef. - Jon Rafkind erased older build demo target. - Jon Rafkind added the demo to the scons build. - Jon Rafkind made it so assembly files can be built statically. - Jon Rafkind made scons always build asmdef. - Trent Gamblin made al_acknowledge_resize and al_resize_display adjust clipping in the D3D driver. Mad eal_set_current_display - Trent Gamblin used higher compatibility flags to Direct3DCreate9, made D3D driver die more gracefully on unsupported configurations, removed flags from draw_line, and did more error checking. - Trent Gamblin turned al_init macros into an inline function. - Trent Gamblin commented out a TRACE line that was causing the entire log to be overwritten. - Peter Wang fixed an incorrect call to _al_vector_find_and_delete. - Peter Wang made various formatting fixes. - Peter Wang converted CR/LF line endings to LF. - Trent Gamblin added NaturalDocs for the graphics api. - Trent Gamblin fixed an instance where a variable could have been used uninitialized. - Trent Gamblin fixed texture coordinates in the D3D driver. - Trent Gamblin fixed formatting and an improper assertion. - Trent Gamblin removed a redundant call to al_set_target_bitmap. - Trent Gamblin fixed a bug in the DX joystick code that caused it to assert when it shouldn't. - Trent Gamblin made al_create_display call al_flip_display so the window is cleared. - Trent Gamblin made the D3D driver work where render-to-texture is not supported. - Trent Gamblin removed masking support completely. - Elias Pschernig got the font example working with the GLX driver. - Elias Pschernig renamed the font addon in the scons build. - Jon Rafkind made scons build modules in a separate directory. - Jon Rafkind bumped the version to match cmake. - Jon Rafkind fixed esd to be like the other unix modules. - Trent Gamblin changed color map and unmap functions to use the target bitmap. - Trent Gamblin added the font example to the cmake build process. - Elias Pschernig added the font example to the scons build process. - Elias Pschernig removed special handling of "src" dir, and made various cosmetic changes. - Trent Gamblin made cmake install to MINGDIR. - Trent Gamblin added a better font and example for the bitmap font addon. - Trent Gamblin removed unix header from install on other platforms. - Trent Gamblin added a bitmap font addon. - Trent Gamblin fixed a locking bug in the D3D driver. - Elias Pschernig removed masking from the GLX driver. - Trent Gamblin implemented blending for memory bitmaps (very slow unless the blend mode is ALLEGRO_ONE,ALLEGRO_ZERO with a pure white blend color). - Trent Gamblin implemented blending for the D3D driver. - Trent Gamblin added ALLEGRO_PIXEL_FORMAT_ANY_(15|16|24|32)_(WITH_ALPHA|NO_ALPHA) formats, used ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA in locking examples, and ixed some formatting. - Trent Gamblin added al_clone_bitmap which makes an exact copy of the color-data of a bitmap. - Trent Gamblin added a ALLEGRO_KEEP_BITMAP_FORMAT flag that forces Allegro to use the same format as the disk file when loading bitmaps. - Elias Pschernig implemented video bitmap masking for the GLX driver (by converting to alpha textures and drawing with alpha blending). - Elias Pschernig fixed clipping in the GLX driver. - Trent Gamblin removed ALLEGRO_MASK_SOURCE flag in favor of ALLEGRO_USE_MASKING. Mask color is now a bitmap property. Removed ALLEGRO_NO_ALPHA flag and changed the meaning of ALLEGRO_USE_ALPHA to mean do alpha blending or not. Added al_set/get_bitmap_mask_color and removed al_set/get_mask_color. New masking example added (exnew_masking). - Trent Gamblin added proper clipping to al_put_pixel. - Trent Gamblin renamed graphics stuff from AL_ to ALLEGRO_ and removed patterned drawing. - Elias Pschernig implemented clipping for the X11 GLX driver (only for screen so far). - Trent Gamblin removed unused set_bitmap_clip entry from the bitmap vtable. - Trent Gamblin made clipping always enabled and made the clipping functions operate on the current target bitamp. - Trent Gamblin removed src/compat/coblit.c. - Trent Gamblin renamed scroll_display to scroll_screen in display.c - Trent Gamblin Removed commented code from src/display.c. Removed include/allegro/display.h and src/compat/cogfx.c - Elias Pschernig renamed XDUMMY driver to XGLX. - Elias Pschernig made some cosmetic changes. - Elias Pschernig made exblend work over the compatibility screen. - Elias Pschernig implemented upload_compat_screen method in the GLX driver. - Elias Pschernig optimized al_lock_bitmap/al_unlock_bitmap slightly. - Elias Pschernig added a flags parameter to the drawing primitives methods. - Trent Gamblin added flags to primitives in display vtable and renamed draw_filled_rectangle vtable entry to draw_rectangle. - Elias Pschernig implemented AL_SINGLEBUFFER flag and fixed bug with AL_FULLSCREEN in the GLX driver. - Trent Gamblin added a mode parameter to al_set_drawing_pattern. - Trent Gamblin added AL_OUTLINED flag that is the default for primitives. - Trent Gamblin added al_set_drawing_pattern and al_get_drawing_pattern, added a flags parameters to all the primitive drawing functions that can be: AL_FILLED, AL_PATTERNED, and added hline and vline functions for memory bitmaps. - Trent Gamblin ifdefed d3d stuff in win/wnewsys.c. - Trent Gamblin removed d3dx9 library from CMakeLists.txt. - Trent Gamblin ifdefed Direct3D stuff in display.c. - Jon Rafkind made scons read win32 files from cmake file list. - Trent Gamblin added al_wait_for_vsync and made it work with the D3D driver. - Elias Pschernig implemented immediate-resize for al_resize_display, and implemented fullscreen resizing. - Trent Gamblin added al_enable_bitmap_clip and al_is_bitmap_clip_enabled, added al_create_sub_bitmap, and made it work with D3D and memory bitmaps. - Elias Pschernig improved fullscreen handling. - Elias Pschernig added shutdown_system vtable entry to the system driver, and automatically call it on program exit. This allows unsetting fullscreen modes in the X11 driver. - Trent Gamblin added al_set_bitmap_clip and al_get_bitmap_clip, and made them work with D3D and memory bitmaps. - Elias Pschernig added XF86Vidmode fullscreen modes. - Elias Pschernig added xdummy files to cmake files list. - Elias Pschernig made al_resize_display work on non-resizable windows. - Elias Pschernig fixed opengl setup being issued in wrong thread. - Elias Pschernig moved src/misc/colconv.c from windows sources to general sources. - Elias Pschernig uncommented accidentally commented out line. - Elias Pschernig made scons read the list of source files from cmake/FileList.cmake, so there's only one place to add new files. - Trent Gamblin made _al_get_pixel_value faster. - Trent Gamblin made al_unmap_rgba_i use a table instead of relying on al_unmap_rgba_f. - Peter Wang changed #includes to use file names from the root of the include hierarchy, i.e. #include "allegro/internal/foo.h" instead of #include "internal/foo.h" and likewise for allegro/platform/foo.h. - Peter Wang removed some stray CR characters. - Trent Gamblin added al_get_bitmap_width, al_get_bitmap_height, al_get_bitmap_format, and al_get_bitmap_flags. - Trent Gamblin made al_draw_rotated_(scaled_)bitmap only lock the region of the destination is needs to for memory bitmaps. - Trent Gamblin made al_draw_scaled_bitmap use the AL_FLIP_* flags. - Trent Gamblin added an example of resizing a fullscreen display. - Elias Pschernig updated xdummy driver and implemented al_resize_display for it. - Elias Pschernig added another testcase. - Trent Gamblin added al_get_display_width and al_get_display_height, made al_get_display_* work on the current display, and renamed al_notify_resize to al_acknowledge_resize. - Trent Gamblin uncommented everything in cogfx.c (removing the display parameter). - Trent Gamblin made exnew_lockscreen use pitch. - Trent Gamblin fixed scaled conversion macros (4444, 555, 565), added XRGB_8888 pixel format, made windowed mode default, moved get_num_display_modes and get_display_mode into the system vtable. - Trent Gamblin made exnew_lockbitmap use pitch. - Trent Gamblin fixed D3D unlocking bug, and used desktop format in windowed mode if not specified. - Elias Pschernig fixed a bug where events reported the wrong source display under X11. - Elias Pschernig added three simple test cases. - Elias Pschernig fixed al_lock_bitmap and al_unlock_bitmap implementation in the xdummy driver (for now it works in a slow way). - Trent Gamblin made al_notify_resize return success/failure and added al_resize_display to resize the display from code. - Elias Pschernig started implementing lock_region and unlock_region for the xdummy driver. - Elias Pschernig split xdraw.c out of xdisplay.c, used _AL_THREAD instead of pthreads in the xdummy driver, added a lock to the xdummy driver, in order to implement al_destroy_display, used the correct format. - Elias Pschernig fixed a comment typo. - Elias Pschernig fixed a typo in AL_CONVERT_PALETTE_8_TO_ABGR_8888. - Trent Gamblin improved D3D line drawing, added al_get_num_display_modes and al_get_display_mode, and cleaned up & organized some code. - Trent Gamblin removed _al_win_delete_from_vector. - Trent Gamblin added draw_memory_bitmap_region vtable hook to AL_DISPLAY. - Elias Pschernig implemented enough of the xdummy driver to run exnewap (doesn't display correctly yet though). - Elias Pschernig updated scons build files. - Elias Pschernig Removed windows specific includes from exnewapi.c. - Elias Pschernig added missing al_convert_mask_to_alpha prototype. - Peter Wang fixed src/tls.c to compile under Linux (not tested). - Trent Gamblin put TLS support back in for MSVC and UNIX. - Trent Gamblin cleaned up some code, added headers to new source files, grouped thread local variables into one structure (UNIX support is broken for now), and made mask color thread local. - Trent Gamblin added clear, filled rectangle, and line for memory bitmaps. - Trent Gamblin made it so the system driver is no longer hard coded, added switch_out method to display vtable, made the D3D window and system driver code generic. - Trent Gamblin merged 4.9-elias and 4.9-trentg into 4.9-newgfx. - Elias Pschernig adjusted prototype of _al_init to implementation. - Elias Pschernig fixed a bogus cast. - Elias Pschernig fixed typo in al_get_new_diplay_format for non-mingw. - Trent Gamblin made display and bitmap parameters local to the calling thread. - Trent Gamblin added al_draw_rotated_bitmap and al_draw_rotated_scaled_bitmap for memory bitmaps using Allegro's software rotation code as a base. - Trent Gamblin ported a stretch blit fix from 4.2, made al_init call allegro_init, made al_draw_bitmap(_region) much faster on memory bitmaps, and added al_draw_scaled_bitmap for memory bitmaps. - Trent Gamblin renamed AL_LOCKED_RECTANGLE to AL_LOCKED_REGION, and started on memory bitmaps (al_draw_bitmap and al_draw_bitmap region work). - Trent Gamblin made seperate functions for getting/setting display/bitmap parameters, made backbuffer-as-source bitmap work in D3D, and changed parameter ordering of some functions. - Trent Gamblin added al_is_compatible_bitmap removed dependancy on Allegro's 3D math functions from the D3D driver. - Trent Gamblin added al_convert_mask_to_alpha, made put/get_pixel faster if the bitmap is locked ahead of time, and brought back AL_MASK_SOURCE. - Trent Gamblin committed various bugfixes, implemented the RGB mapping/unmapping functions from Bob's API. - Trent Gamblin removed the D3DX library dependancy. - Trent Gamblin committed various bugfixes and got all of the examples working with the D3D driver. - Trent Gamblin fixed some of the compatibility conversions. - Trent Gamblin changed the examples back to autodetecting the graphics driver. - Trent Gamblin made fullscreen mode work with the D3D driver, and non-resizable windows. - Trent Gamblin finished bitmap conversion functions, improved locking, implemented get/put pixel, and made some speed improvements. - Trent Gamblin added a bitmap conversion function. - Trent Gamblin got the demo game running in D3D. - Trent Gamblin removed an unnecessary bitmap copy. - Trent Gamblin added a skeleton D3D driver. - Peter Wang fixed the generation of allegro-config under Mac OS. - Michael Jensen fixed a mistake in the documenation for is_compatible_font. - Peter Wang fixed wrong variable in example code for load_font(); - Trent Gamblin fixed some problems with the cmake build on Windows. - Peter Wang removed the second parameter in a call to _al_event_source_needs_to_generate_event() which was missed earlier. - Peter Wang exposed some internal documentation on destructors, events and event sources to NaturalDocs. - Peter Wang changed al_wait_for_event() so that a timeout value of "0" means to not wait at all. To wait an indefinite amount of time the caller should pass the AL_WAIT_FOREVER constant. - Peter Wang removed the declarations of al_event_source_set_mask and al_event_source_mask which were missed in the previous change. - Peter Wang removed event masking abilities, that is, for the user to prevent an event source from generating particular event types. This was implemented using bitfields which limited the number of event types to 32. Although the limit could be raised event masking was probably not very useful anyway. In all, the functions removed are: al_event_source_mask, al_event_source_set_mask, al_wait_for_specific_event. The al_wait_for_specific_event() API also required event types to be bitfields. - Peter Wang fixed some spelling mistakes in the examples. - Peter Wang bumped the version to 4.9.2. - Peter Wang moved allegro/branches/4.3 to allegro/branches/4.9. - Ryan Patterson clarified the documentation of stop_sample(). - Peter Wang and Trent Gamblin fixed some issues with the CMake build. The allegro-config script was not generated properly and liballeg_unsharable wasn't being installed. - Matthew Leverton changed an instance of long long to LONG_LONG and an LL suffix into a (LONG_LONG) cast, both for MSVC 6. - Matthew Leverton submitted a fix for MSVC 6 regarding MSVC's lack of a \_\_FUNCTION\_\_ macro. - orz, Matthew Leverton, and Peter Wang made the ALLEGRO_USE_C=1 option to work under MinGW and MSVC. - Anthony Cassidy fixed a typo. - Peter Wang removed the 'msvc' target from the fix.sh help message as it should not be used by users any more. Added a comment that it is used by zipup.sh. - Anthony 'Timorg' Cassidy made d_menu_proc fill up its assigned area with the gui_bg_color. Changes from 4.9.0 to 4.9.1 (March 2007) ======================================== *Note that 4.9.1 was called 4.3.1 when it was originally released.* - Added a new mouse and cursor API. The new functions are: al_install_mouse, al_uninstall_mouse, al_get_mouse, al_get_mouse_num_buttons, al_get_mouse_num_axes, al_set_mouse_xy, al_set_mouse_z, al_set_mouse_w, al_set_mouse_axis, al_set_mouse_range, al_get_mouse_state, al_mouse_button_down, al_mouse_state_axis al_create_mouse_cursor, al_destroy_mouse_cursor, al_set_mouse_cursor, al_set_system_mouse_cursor, al_show_mouse_cursor, al_hide_mouse_cursor - Added documentation for some parts of the 4.9 API using the NaturalDocs generation system. The documentation is nowhere near as good as a proper manual, but it's still better than nothing. - Added a commented example demonstating the new API (exnew_events.c). - Added CMake and SCons build systems. These are mainly for use by Allegro developers at present. - Various bug fixes and minor changes. Changes from 4.2 series to 4.9.0 (July 2006) ============================================ *Note that 4.9.0 was called 4.3.0 when it was originally released.* Basically we're just wrapping up what we have in version control up to now. See the commit logs if you want details. This release introduces a few new subsystems. We have an event system, a new keyboard API, a new joystick API, a new timer API, and the start of a new graphics API. All of these are subject to change, as is usual for a WIP. We are maintaining a certain level of source compatibility with the 4.2 API. If it's easy to maintain compatibility then we do it, otherwise compatibility is dropped. Obscure features are more likely to be dropped. This release has had minimal testing on Linux/x86, Windows/x86 (MinGW) and Windows/x86 (MSVC). It seems to work on some Linux/x86-64 machines also. Other ports are broken or untested. The new functions are as follows (in no particular order). No real documentation exists at the moment but interesting header files are: altime.h, display.h, draw.h, events.h, joystick.h, keyboard.h, timer.h. - al_current_time al_rest - al_create_video_bitmap al_create_system_bitmap al_scroll_display al_request_scroll al_poll_scroll al_show_video_bitmap al_request_video_bitmap al_enable_triple_buffer al_create_display al_set_update_method al_destroy_display al_flip_display al_get_buffer al_get_update_method al_enable_vsync al_disable_vsync al_toggle_vsync al_vsync_is_enabled al_blit al_blit_region al_blit_scaled - al_event_source_set_mask al_event_source_mask - al_create_event_queue al_destroy_event_queue al_register_event_source al_unregister_event_source al_event_queue_is_empty al_get_next_event al_peek_next_event al_drop_next_event al_flush_event_queue al_wait_for_event al_wait_for_specific_event - al_install_joystick al_uninstall_joystick al_num_joysticks al_get_joystick al_release_joystick al_joystick_name al_joystick_num_sticks al_joystick_stick_flags al_joystick_stick_name al_joystick_num_axes al_joystick_axis_name al_joystick_button_name al_get_joystick_state - al_install_keyboard al_uninstall_keyboard al_get_keyboard al_set_keyboard_leds al_keycode_to_name al_get_keyboard_state al_key_down - al_install_timer al_uninstall_timer al_start_timer al_stop_timer al_timer_is_started al_timer_get_speed al_timer_set_speed al_timer_get_count al_timer_set_count allegro5-5.2.10.1/docs/src/changes-5.1.txt000066400000000000000000001517311473414355200176610ustar00rootroot00000000000000% Allegro changelog for 5.1.x series See `changes-5.0.txt` for changes in Allegro 5.0.x. These lists serve as summaries; the full histories are in the git repository. Changes from 5.1.13 to 5.1.13.1 (February 2016) ============================================ The main developers this time were: SiegeLord. Image addon: - Fix regression in bitmap loading when compiled under MSVC. Changes from 5.1.12 to 5.1.13 (January 2016) ============================================ The main developers this time were: Julian Smythe, Elias Pschernig and Peter Hull. Graphics: - Add `al_get_opengl_program_object` (SiegeLord). Input: - Fix spurious triggering of the mouse grab key when it wasn't otherwise set (SiegeLord). Android port: - Avoid multiple HALT/RESUME events on Android (Max Savenkov). - Implement `al_get_monitor_info` for Android (Reuben Bell). - Fix Android crash on file access. - Implement ALLEGRO_FULLSCREEN_WINDOW on Android. - Fix crash if display is destroyed while the app is switched out. - Add support for x86_64 Android. - Add `al_android_set_apk_fs_interface`. Linux port: - Allow using OpenGL ES in X11. - Fix the initial display size not being correct sometimes (SiegeLord). - Fix a race condition in the XInput joystick driver (Trent Gamblin). OSX port: - Fix various memory leaks. - Fix `al_set_window_title`. - Fix a lot of decrepid and deprecated code. - Fix single buffer flip display (SiegeLord). Windows port: - Fix Windows UNC path handling. - Fix clipboard nul-termination issues (Trent Gamblin). - Set the window title immediately upon window creation (SiegeLord). Build system: - Define CMAKE_FIND_ROOT_PATH for i686-w64-mingw32 cross compiler (Martijn van Iersel). - Allow building with older CMakes again (SiegeLord). - Do not catche compile tests' failure (Bruce Pascoe). - Add a way to statically link the runtime with MinGW (SiegeLord). - Don't link the MSVC C runtime at all when requesting a static runtime and building a static library (SiegeLord). Documentation: - Add links to the source code of the definitions of the most API entries. - Fix sidebar generation with modern Pandoc (Boris Carvajal). Python: - Fix ordering issue for HAPTIC* structs. - Fix missing ALLEGRO_PRIM_ATTR_NUM. Other: - Add a 'none' debug level to turn off logging entirely in debug builds (SiegeLord). - Reconfigure logging after the configuration files are loaded (SiegeLord). - Fix al_set_new_window_title() off-by-1 (Bruce Pascoe). - Don't call al_get_time() before system is installed (SiegeLord). Audio addon: - Add `al_get_default_voice` and `al_set_default_voice`. - Flush the pulse audio stream rather than draining it, fixing some audio breaks (SiegeLord). - Fill audio stream fragments with silence in the audio addon rather than in the acodec addon, fixing some garbage output (SiegeLord). - Fix possible deadlock when destroying audio streams (SiegeLord). Acodec addon: - Don't read past the audio chunk's end when streaming wav files (SiegeLord). - Turn off allegro_acodec dynamic loading by default, fixing a common footgun (Bruce Pascoe). Image addon: - An enormous amount of work supporting reading of esoteric (and not) BMP format variants (palletted, GIMP-style, etc). New tests were added using the manual bmp suites. Native dialog addon: - Update code to work with modern OSX versions. - Clean up menu handling on OSX. Changes from 5.1.11 to 5.1.12 (September 2015) ============================================== The main developers this time were: Bruce Pascoe, Beoran, Elias Pschernig, SiegeLord, Trent Gamblin. Graphics: - Add `al_set_blend_color` and `al_set_blender`, for additional blending modes. - Add `ALLEGRO_MAXIMIZED` display flag. - Add `al_reparent_bitmap`, `al_get_bitmap_x/y`. This allows changing the offset of a sub-bitmap. - Make `ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA` actually pick a format without an alpha channel. - Add `al_premul_rgba` and `al_premul_rgba_f` convenience functions for dealing with pre-multiplied alpha blending mode. Input: - Fix key auto-repeat on modern X11 versions. - Fix mis-detection of some joysticks on Android. Android port: - Fix a crash when minimizing the app before Allegro has been initialized. iOS port: Linux port: - Add `al_get_x_window_id` (Robert MacGregor) OSX port: - Fix some deprecated API usage. Windows port: - Fix a dangling pointer issue resulting in crashes when resizing on Windows 10. Build system: - Build with multiple processors when using MSVC. - Make XInput2/touch input optional on Linux. Documentation: - Various documentation improvements. - Fix some badly formatted flags (Rodolfo Lam). Other: - Allow injecting Allegro events into event queses using `al_emit_user_event` (Ryan Roden-Corrent) - Add `al_set_new_window_title` and `al_get_new_window_title`. - Add `al_get_clipboard_text`, `al_set_clipboard_text` and `al_clipboard_has_text`. - Add `al_resume_timer` (Ryan Roden-Corrent). - Add `al_get_cpu_count` and `al_get_ram_size`. Audio addon: - Add multiple voice support for the AQueue driver. - Fix a bug when `al_restore_default_mixer` was called multiple times. Color addon: Font addon: - Add `al_draw_glyph`, `al_get_glyph_width`, `al_get_glyph_dimensions` and `al_get_glyph_advance`. These functions are useful when additional control is needed when drawing text. - Add `al_set_fallback_font`. Image addon: - Add `al_register_bitmap_identifier`, `al_identify_bitmap` and `al_identify_bitmap_f`. This allows detecting the bitmap type by looking at the initial few bytes in the file rather than relying solely on the extension. - Allow saving bitmaps with uppercase extensions (Daniel). Native dialog addon: - Fix crashes when creating menus with sub-menus (Todd Cope). Video addon: - Allow using both Ffmpeg and Theora backends simultaneously. - Reduce latency of `al_get_video_frame` for the Theora backend. - Make the Theora backend send the `ALLEGRO_VIDEO_FRAME_SHOW` events. - Rename `al_get_video_width/height` to `al_get_video_scaled_width/height` which now return the aspect corrected size of the video frame. - Rename `al_pause_video/al_is_video_paused` to `al_get/set_video_playing`. - Add `ALLEGRO_EVENT_VIDEO_FINISHED` event. - Remove `ALLEGRO_EVENT_VIDEO_FRAME_ALLOC` event. - Remove `al_get_video_aspect_ratio`. Examples: - New examples: ex_reparent, ex_inject_events, ex_clipboard, ex_cpu, ex_timer_pause. Changes from 5.1.10 to 5.1.11 (June 2015) =========================================== The main developers this time were: SiegeLord, Trent Gamblin. Input: - Rename `al_get_haptic_active` to `al_is_haptic_active` for consistency. - Rename `al_get_num_haptic_effects` to `al_get_max_haptic_effects`. - Implement the missing `al_is_touch_input_haptic` function. - Move the loops parameter of `al_upload_and_play_haptic_effect` after the id to be consistent with `al_play_haptic_effect`. OSX port: - Fix mouse warping in OSX. - Add retina display support to OSX. Windows port: - Fix querying display modes before creating a display. - Make the Windows joystick implementation more fault tolerant. - Initialize display callbacks when creating faux fullscreen (Edgar Reynaldo). Build system: - Fix the conditional compilation of sal.h (Edgar Reynaldo). - Don't look at WinSDK when we're not on MSVC, fixing MinGW builds when MSVC is installed as well. - Fix the static FLAC compile tests on Android and Windows. - Make the OSX frameworks install in the proper location again. - Add `WANT_STATIC_RUNTIME` CMake build option (currently MSVC-only). Documentation: - Various documentation improvements. Other: - Return a valid configuration from `al_get_system_config` before Allegro is installed. This allows you to override the various configuration options without using an on-disk `allegro5.cfg`. - Compile in the logging support in release modes by default. Now logging can be turned on in release builds without recompiling the program by editing the system configuration. - Detect file-overruns when saving configuration files (Bruce Pascoe). Color addon: - When converting from YUV to RGB, clamp the returned values between 0 and 1. Video addon: - Use an enum in place of magic numbers for `al_get_video_position` constants. Changes from 5.1.9 to 5.1.10 (May 2015) =========================================== The main developers this time were: SiegeLord, Elias Pschernig, Trent Gamblin, Polybios. Input: - Add `al_set_mouse_wheel_precision` and `al_get_mouse_wheel_precision`. Graphics: - Added `al_transform_coordinates_3d`. - Added `al_build_camera_transform`. - Make the projection transform a bitmap local state. This removes `al_set_projection_transform` and `al_get_projection_transform`, and replaces them with `al_use_projection_transform` and `al_get_current_projection_transform` with similar semantics to the regular transforms. OSX port: - Improved joystick axis layouts on Mac OS X, and added support for some dpards (Max Savenkov). X11 port: - Fix some memory leaks (ElectricSolstice). - Make the XInput2 check more accurate (we require a specific version). Windows port: - Remove taskbar hiding on Windows. - Fix high precision mice on Windows. - Fix some D3D conflicts with the OpenGL backend. - Remove the prohibition of building OpenGL-only DLLs. - Added LRESULT argument to WindowProc callback, fixing `al_win_add_window_callback` for some event types (Aaron Bolyard). Android port: - Fix some memory leaks. - Make it possible to specify the Android target during building. iOS port: - Add an XCode project to help build Allegro when CMake support fails. - Restore the CMake support. - Makes the examples run on the iOS simulator out of the box. - Various small fixes (Trent Gamblin, jmasterx). - Remove `al_iphone_get_last_shake_time` and a`l_iphone_get_battery_level`. - Hack around iOS not creating mipmaps (jmasterx). - If the supported orientation is `ALLEGRO_DISPLAY_ORIENTATION_UNKNOWN`, default to supporting all orientations. - Get Cosmic Protector to compile again. Build system: - Revamp the detection of DirectX dependencies. Now it should work out of the box for at least MSVC and mingw-w64. - Fix GDIPlus finding script (pkrcel). - Bump the minimum version of CMake to 2.8.5. Documentation: - Many documentation improvements, as always (special thanks to Polybios). - Make the PDF output prettier with better fonts and an up-to-date version number. - Make the Javascript search for online documentation support partial matches. - Make [section] links work in HTML. - Allow the docs to have more than 1024 entries (Allegro is getting huge!). Other: - Make the test driver a little more resistant to failure. - Various fixes to the experimental SDL backend. - Update the CONTRIBUTORS.txt. Audio addon: - Fix deadlock when destroying an audio stream soon after its creation. - Add VOC file support (pkrcel). - Disable processing of the XM zero-speed event. - Disable processing of module loop points if `ALLEGRO_PLAYMODE_ONCE` is set. - Fix a buffer overflow bug. Image addon: - Fix loading of indexed + transparent PNGs with the libpng backend. Dialog addon: - Fix some style issues with the Windows file dialog. - Fix a bug with multiple filenames with the Windows file dialog. - Change the semantics of the patterns in `al_create_native_file_dialog` to support future expansion of the patterns to support both AND and OR style filtering. - Make the GTK file selection dialog look like it's from 2004 (as opposed to mid-1990s). TTF addon: - Fix some warnings. - Make the page size dynamic, allowing for fonts with up to 8192x8192 glyphs by default. Examples: - New examples: ex_camera, ex_projection2. Changes from 5.1.8 to 5.1.9 (January 2015) =========================================== The main developers this time were: Trent Gamblin, SiegeLord, Elias Pschernig. Core: - Fix OSX backend on OSX 10.10 (lordnoriyuki). - Simplify how sub-bitmaps interact with their parent bitmaps. You can now destroy a sub-bitmap at any time (not only before the parent is destroyed). Additionally, when the parent is converted using `al_convert_bitmap`, all the sub-bitmaps are also automatically converted. - Switch to using unicode Win32 (e.g. this fixes using `al_set_window_title` with unicode strings). - Add some Linux WM hints so make Allegro windows work more smoothly (especially with Unity). Filesystem: - Add `al_fprintf` (DanielH and Tobias Scheuer). - Add `al_for_each_fs_entry`, a convenience function that helps enumerating the contents of a directory more easily using a callback function (Beoran). - Fix for `al_get_standard_path` with Unicode (vkensou). Input: - Add X11 touch driver (Ryan Gumbs). - Emulate mouse pressure for backends that don't support pressure. - Added Windows haptics driver, XInput joystick driver (Beoran). - Fix OSX joystick deinitialization. Graphics: - Add block compression pixel formats (ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1/DXT3/DXT5) for compressed video bitmaps. This includes an API to fetch compressed block size (`al_get_pixel_block_width/height/size`) as well as API to load and unload compressed bitmap data without paying a runtime compression cost (`al_lock_bitmap_blocked`). Unfortunately, due to patent concerns this last feature is disabled for OpenGL (if you thinks those concerns don't apply to you, you can enable it by passing `-DWANT_OPENGL_S3TC_LOCKING=1` to cmake). - Make real fullscreen modes work on OS X again. May not be perfect still. (thanks to SDL). Shaders: - Don't clobber the 0'th texture unit in OpenGL and Direct3D. This simplifies working with shaders. Android port: - Bump minimum Android API level from 10 to 12 (aka version 3.1). - Add controller support to the Android port. An accelerometer 'joystick' is still the first joystick. Supports two analog sticks and 10 buttons (A B X Y L1 R1 DPAD_L DPAD_R DPAD_U DPAD_D). Supports hotplugging and theoretically multiple joysticks (needs testing). - Set correct orientation at startup on Android (thanks to Aikei_c). Build system: - Various CMake fixes. Other: - Add Travis and AppVeyor continuous integration support. - Fix a lot of memory leaks. - Many documentation improvements. Audio addon: - Disallow attaching a mixer to itself. - Fix uni- and bi-directional looping of zero-length samples. - Fix/avoid all sound examples freezing on OSX with the aqueue driver. Image addon: - Add functionality to load Direct Draw Surface files (.dds). Only compressed pixel formats are supported (DXT1, DXT3 and DXT5). Dialog addon: - Fix native file dialog default paths on Windows (Edgar Reynaldo). - Fix unintended behaviour in `al_set_menu_item_flags` (Malcolm Harrow). - Fix some bugs with native menus in OSX. Video addon: - Fix for now undefined AVCODEC_MAX_AUDIO_FRAME_SIZE (Dennis Busch). TTF addon: - Fix a crashing bug in the TTF addon. - Make `al_load_ttf_font_stretch` return NULL if invalid width/height are passed. Font addon: - Add multi line text output for the font addon (`al_draw_multiline_text`, `al_draw_multiline_textf` and `al_draw_multiline_ustr`). Primitives addon: - Fix some sharp-angle polyline drawing bugs. Examples: - New examples: ex_compressed, ex_font_multiline. - ex_dir: demonstrate `al_for_each_fs_entry`. - ex_haptic2: demonstrate hotplugging. Changes from 5.1.7 to 5.1.8 (January 2014) ========================================== The main developers this time were: Beoran, SiegeLord, Trent Gamblin, Markus Henschel, Peter Wang. Core: - Allow MSVC to use DLL TLS but disable DLL TLS by default. - Do not include windows.h via allegro.h. - Fix some memory leaks on X11. Graphics: - Spell ALLEGRO_DST_COLOR, ALLEGRO_INVERSE_DST_COLOR with "DEST" (with compatibility defines). - Fix bug which meant ALLEGRO_INVERSE_SRC_COLOR and ALLEGRO_INVERSE_DEST_COLOR never actually worked on D3D. - Fix horizontal and vertical shears which were not composing with translations correctly. - Optimise al_restore_state if saved target display/bitmap are unchanged. - Fix _al_display_settings_sorter ordering of indexes when scores are equal. - Use a minimum 16x16 texture workaround even on desktop OpenGL. - Propagate errors up OpenGL lock bitmap implementations. - Use proxy bitmap when locking writable backbuffer regions on GLES. - Clean up FBO creation during bitmap locking. - Move the half-pixel shift in D3D into the projection matrix. Use the texture dimensions to compute the half-pixel shift. - Fix al_get_d3d_texture_size returning zeros. - Remove ALLEGRO_FORCE_LOCKING flag. - Setup GL viewport and projection in al_acknowledge_resize on Android. - Improve implementation of display options on Android: use the same display setting scoring code as other ports; handle SUGGEST display options properly; map ALLEGRO_COLOR_SIZE to EGL_BUFFER_SIZE attributes. Filesystem: - Add al_ferror and al_ferror. Initial patch by Tobias Scheuer. - Make al_fclose have a return value. - Check al_fclose return value in saving routines. - Make al_fopen_fd not leak a FILE handle in a failure path. - Make al_make_temp_file allocate temporary buffer to match the template. - android: Interpret the path to APK asset as AssetManager doesn't. - android: Correctly return -1 for APK asset file size if it can't be determined. A side-effect is that FreeType (via the TTF addon) can now load TTFs stored compressed in APK assets. - android: Support ungetc on APK file streams. - android: Fix EOF handling in AllegroInputStream. Input: - Initial haptics API, only implemented on Linux to begin with. - Use Linux input API for joystick driver instead of deprecated joystick API. - Use Linux joystick driver on Android if OUYA model detected (Jonathan Lilliemarck). - Use thread for hotplugging joysticks on Linux instead of timerfd (due to Android). - Report unichar in KEY_CHAR events on Android. (Todd Cope) - Added some Android gaming key codes. - iOS touch coordinates need to be multiplied by contentScaleFactor. - Android touch input id 0 was incorrectly treated as invalid. (Max Savenkov) Shaders: - Automatically call OnLostDevice and OnResetDevice on HLSL shaders. - Remove #version specifier from all shaders. Audio addon: - Remove generic audio event source and AudioQueue events. - Don't queue silent fragments at start of new audio streams. - Make stream_read return correct number of filled samples when no data is available (zero). - A DirectSound voice could not be restarted once it has been stopped. - Fix crash when attaching empty stream to dsound voice. - Reset buffer position in stop instead of play in dsound voice. - Fix calculation of current sample position in dsound voice. - Reset audio stream when al_set_audio_stream_playing to false for voice and mixer cases, and make all fragments available for refill. - Emit stream fragment events when a stream is started. - Remove unnecessary reallocation of the channel matrix. - Add al_fill_silence. - Add al_get_audio_stream_played_samples. - Fix deadlock in Pulseaudio driver. Reported by Bluebird. - Let al_set_sample_instance_playing work for unattached instances and sample instances with no data set. Reported by Bluebird. - Enable the use of the unpatched DirectX SDK to build. Audio codec addon: - Fix looping in Ogg Vorbis stream. (Todd Cope) - Seeking in wavs would always have returned success. Image addon: - Fix many problems in Android native image loader, including: supporting ALLEGRO_NO_PREMULTIPLIED_ALPHA, respecting the new bitmap format, working for non-APK assets, not crashing on failure. Native dialogs addon: - Change native menu ids from int to uint16_t due to limitation with Windows. (Matthew Leverton) Primitives addon: - Rename the primitives buffer flags. - Simplify the prim buffer hints. - Simplify the al_create_vertex_buffer API. - Actually implement uninitialized vertex buffers. - Add indexed buffer API. - Polylines with ALLEGRO_LINE_CAP_CLOSED cap style did not draw correctly with thickness == 0. - Take into account the projection matrix when computing the scale of the high level primitives. - Replace enum arguments for al_draw_polyline and al_draw_polygon with integers to reduce chance of ABI issues. TTF addon: - Fix a bug where some glyphs would be blank. - Allow glyph allocation to fail without crashing. Android port: - Separate Allegro library Java code from the original example project for Android (Jonathan Lilliemarck). - Build Allegro library as a JAR. - Rename Java package to org.liballeg.android. - Change how the application shared library is specified. Override the AllegroActivity constructor instead of specifying in AndroidManifest.xml. - Add a method to tell if the user exited main in the Android Java code. - Add a fix for the case of launching another activity from your game on Android and then returning to the game after it finishes. - Refactoring and clean up. iOS port: - Remove al_iphone_get/set_screen_scale as not really needed and confusing. Build system: - Integrate Android port into build system, including building and launching examples for debugging. - Detect OpenGLES/2 libraries on Android. - Let clang use same options as gcc in build system. Python: - Made the C-parser used in the Python API generator understand more type constructs. (Elias Pschernig) Examples: - Make demos and most examples run (somewhat) on Android. - Add touch input support to various examples. - New examples: ex_file, ex_haptic, ex_haptic2, ex_touch_input. - ex_prim: Demonstrate indexed buffers. Other: - More more minor bug fixes and changes. - Documentation updates. - Syntax highlight the C source examples and prototypes in the documentation. Changes from 5.1.6 to 5.1.7 (May 2013) ====================================== The main developers this time were: Peter Wang, Trent Gamblin. Graphics: - Added al_horizontal_shear_transform, al_vertical_shear_transform (Jeff Bernard). - Make al_destroy_bitmap maintain the current display when untargeting the bitmap to be destroyed. - Delete al_create_custom_bitmap. - Delete al_ortho_transform compatibility macro. - Make al_get_d3d_texture_size fail instead of crash if passed a non-D3D bitmap. - Make al_get_opengl_texture_size return success code to match D3D. - Rename al_d3d_set_release/restore_callback to be consistent with existing naming, and pass the display as an argument. - Check availability of fullscreen button on window frame at run-time (OS X). Input: - Fix mouse warping on OS X. - Fix mouse warping in Linux evdev mouse driver. Audio addon: - pulseaudio: Use smaller buffer size by default, and make it configurable. - pulseaudio: Clean up state transitions. Color addon: - Fix al_color_rgb_to_html blue component (Jeff Bernard). - Implement al_color_html_to_rgb and al_color_html more strictly. Primitives addon: - Delete al_draw_polygon_with_holes. - Delete stride-less version of al_draw_polyline*. - Simplify interface of al_triangulate_polygon and al_draw_filled_polygon_with_holes. Video addon: - Make al_seek_video return a result. - Fix crash when unable to open a Ogg video. - Don't scan to end of headers of unknown stream for Ogg video. - Stop reading at end of Ogg video. - Try to account for audio buffers in positioning of Ogg video. - Implement seek to beginning of file (only) in Ogg backend. - Replace deprecated av_find_stream_info() call (Nick Black). Android port: - Fix some Android switch in/out and exit issues. Build system: - Do not install most internal header files. - Do not search for and link with unneeded X libraries. Examples: - ex_audio_timer: New example. - Revise and comment the ex_prim_shader example and shaders (Paul Suntsov). Other: - Various documentation updates. - Minor fixes and much code refactoring. Changes from 5.1.5 to 5.1.6 (March 2013) ======================================== The main developers this time were: Trent Gamblin, Paul Suntsov, Peter Wang. Core: - Fix use of clobbered return value from setlocale() on X11. - Register system interface even if no display driver available on Windows. - Fix use of double math functions for float arguments (Nick Trout). Shaders: - Revamped shader API. The shader API is now part of the core library, and the shader addon removed. - Shaders are now a per-bitmap property, set with al_use_shader. A bitmap without a set shader uses a default shader internally, that allows Allegro drawing functions to work as in non-programmable pipeline mode. - Shader variable setters operate on the shader of the target bitmap. - Rename ALLEGRO_USE_PROGRAMMABLE_PIPELINE to ALLEGRO_PROGRAMMABLE_PIPELINE. - Rename al_link_shader to al_build_shader. - Remove al_set_shader. - Remove the al_set_shader_*_array functions. These functions cannot be easily (or at all) implemented with the D3D backend. - Add al_get_shader_platform and al_get_default_shader_source. - Remove al_get_opengl_program_object, al_set_opengl_program_object, al_get_direct3d_effect, al_set_direct3d_effect. - Remove Cg shader backend. - Add macros for shader variable names (Jon Rafkind). Displays: - Made al_get_display_mode return the closest thing to a pixel format possible with the WGL driver (tobing). - Move WGL context destruction out of the message pump thread and into the user/main thread. - Allow command-tab to work in fullscreen window mode on OS X. - Remove "user_reload" parameter from al_acknowledge_drawing_resume. - Don't crash in al_create_display if there is no display driver. - Don't crash at shutdown if there is no display driver (Windows). - Don't fail init if both D3D, GL drivers unavailable (Windows). - Sync bitmaps before resizing display to prevent changes being lost after the resize (D3D). - Load the D3D9X module during display creation and unload it when the D3D system shuts down. - Run fullscreen toggle on main thread (OS X). - Destroy the backbuffer bitmap when destroying the display (OS X). - Switch to new NSTrackingArea API (OS X). - Set ALLEGRO_NO_PRESERVE_TEXTURE on backbuffer (OpenGL). Graphics: - Let al_destroy_bitmap implicitly untarget the bitmap on the calling thread. - Fix a bug where bitmap locking may change the target bitmap but not restore it back to NULL (OpenGL). - Use memory bitmap drawing when either bitmap is locked (OpenGL). - Fix a crash in D3D destroying sub-bitmaps. - Add const qualifiers to glUniform*v() functions (Aaron Bolyard). Input: - Partially fix mouse buttons "sticking" on Mac, e.g. holding the mouse and toggling fullscreen window. - al_set_mouse_xy on Windows resulted in the mouse getting set to the wrong position in windowed modes - Scale the user supplied mouse cursor if it's too big (Windows). - Add key constants for some Android keys, those that are used in Xperia Play controls. Audio addons: - Fix PulseAudio driver trying to connect to a non-existent server forever. - Avoid memory leaks with audio event source. - Use smaller buffer size for OpenSL. Image addon: - Use Allegro built-in loaders in preference to OS X loaders for BMP/TGA/PCX. The OS X TGA loader doesn't support alpha and this is also more consistent. Font addons: - Make al_init_font_addon return success value. - Make al_init_ttf_addon return true for subsequent calls. Native dialogs addon: - Fix a crash on iOS due to threading/TLS issues geting the display (Nick Trout). Primitives addon: - Speed up al_triangulate_polygon_with_holes. - Speed up drawing of the rounds for polylines. - Add custom vertex attributes to the primitives addon. - Replace vertex shader binary generated by vsa.exe (removed from DirectX SDKs for a while now) by that generated by fxc.exe. - A minor revamp of the HLSL default shader system in the primitives addon. - Fix a few incorrect usages of al_lock_vertex_buffer - Disallow 3 component vectors for ALLEGRO_PRIM_TEX_COORD. - Add a whole bunch of new ALLEGRO_PRIM_STORAGE values. - Primitives addon was ignoring the filter settings of textures in the D3D backend. Android port: - Generate KEY_CHAR on Android. - Add key constants for Android. - Set target bitmap to display backuffer after program is resumed. - Use different functions for OpenGL ES 1 and OpenGL ES 2 on Android. iOS port: - Support stencil buffer on iOS. - Remove unnecessary autorelease pools. There was a crash when using Airplay that goes away without the pools. - Make Airplay work the standard way most apps do unless the Allegro user explicitly creates a display on the second screen. - Don't autorotate displays other than device. - Fix some threading and memory issues. Raspberry Pi port: - Allow for color size, depth and stencil sizes. - Support al_show_mouse_cursor and al_hide_mouse_cursor. Disabled as it sometimes ends up stuck on the screen until reboot. Examples: - New examples: ex_prim_shader, ex_shader_target. Other: - Various documentation updates. - Minor fixes and code refactoring. Changes from 5.1.4 to 5.1.5 (January 2013) ========================================== The main developers this time were: Trent Gamblin, Elias Pschernig, Jon Rafkind, Peter Wang. Ports: - Initial port to Raspberry Pi by Trent Gamblin. Core: - Added an al_register_trace_handler function. - Clean up logging subsystem at shutdown (muhkuh). - Fix a problem with creating a display after Allegro is shut down then re-initialised on X11. Displays: - Fix crashes when resizing a WGL fullscreen window. - Fix use of invalidated pointers in D3D driver when the first format fails. - Fix bug where setting the mouse cursor had no effect when the mouse was captured (mouse button held down). - Fix windows not having a minimise button when set to windowed state from fullscreen window state. - Respect ALLEGRO_FRAMELESS flag properly when toggling from fullscreen window state to windowed state (Windows). - Don't generate DISPLAY_LOST events when resizing a fullscreen display. - Fix al_set/get_window position on Windows so getting/setting to the same position continuosly doesn't move the window. (Michael Swiger) - Rename al_change_display_option to al_set_display_option. - Add al_set_display_icons (plural), implemented for X11 and Windows. - Add ALLEGRO_GTK_TOPLEVEL display flag for X11. - Fix window resizing when using shaders (X11). Graphics: - Avoid null pointer dereference when setting a target bitmap after its video_texture has already been released (D3D). - Make d3d_lock_region fail immediately if _al_d3d_sync_bitmap failed, likely because the device was lost. - Set device_lost flag immediately when d3d_display_thread_proc finds the device is lost. - Fix OpenGL extensions being completely ignored on OS X. - Added a quick hack to fix bitmap locking on desktop OpenGL when using shaders. Config: - Added al_remove_config_key and al_remove_config_section functions. File I/O: - Fix al_read_directory crash on 64-bit Windows (simast). Filesystem: - Keep absolute path in ALLEGRO_FS_ENTRYs so that later changes to the current working directory do not affect the interpretation of the path. - Set ALLEGRO_FILEMODE_HIDDEN properly on Unix. - Make sure stat mode bits are cleared in default implementation of al_update_fs_entry. - Support Unicode paths on Windows. - Change description of al_get_fs_entry_name about not returning absolute path if created from relative path; no longer true for either the default or Physfs implementations. Audio addons: - Fix setting the speed of an audio stream after it was attached to the mixer (Paul Suntsov). - Shut down threads properly when when destroying FLAC and modaudio streams. Font addon: - Avoid making x offset non-integral for ALLEGRO_ALIGN_CENTRE. - Make al_draw_justified_* respect ALLEGRO_ALIGN_INTEGER. TTF addon: - Don't save the projection transform if no display is set. Image addon: - Added a missing autorelease-pool to the OSX bitmap saving function (sleepywind). - Fix OSX native image loader for loading not-premultiplied RGB data. Previously the data was "de-multiplied", with possibly all information lost. - Fix OSX native image loader for loading bitmaps without an alpha channel. They appeared completely black previously. - Fixed loading interlaced .png files with libpng. Native dialogs addon: - Do not unload of rich edit module when closing one text log window while another exists. Reported by URB753. - Use default colours for Windows text log implementation, avoiding problems when the previous custom colours failed, leading to black text on a nearly black background. - Add al_shutdown_native_dialog_addon. - Add native menu support on X11 (requires ALLEGRO_GTK_TOPLEVEL). - Add native menu support on OS X. PhysicsFS addon: - Implement al_change_directory semantics (Todd Cope). Primitives addon: - Fixed textured primitives when using shaders (OpenGL). Shader addon: - Add dynamic loading of d3dx9_xx.dll (Michał Cichoń). - Add dynamic loading of Cg DLLs (Michał Cichoń). - Started implementing default shaders. Only GLSL so far. - Fix null pointer dereference in al_create_shader if backend init fails. Android port: - Fix setting the current display on Android. - Don't set the backbuffer when setting up the OpenGL view. Build system: - Rename allegro\*-5.1.pc files to allegro\*-5.pc. The new names will be available in future 5.0.x releases. - Generate and install allegro_shader pkg-config file. - Only generate and install pkg-config files for libraries that we build. Examples: - ex_icon2: New example. - ex_shader_multitex: New example. - ex_shader: Choose shader platform on command-line; external shader sources. - ex_menu: Various changes. - speed: Avoid poor performance due to needless redraws. Other: - Documentation updates, many thanks to beoran. - A lot of code refactoring. Changes from 5.1.3 to 5.1.4 (October 2012) ========================================== The main developers this time were: Trent Gamblin, Elias Pschernig, Peter Wang. Graphics: - Fixed al_convert_bitmap using the target instead of the source format when converting its data. - Fix a crash in Direct3D in al_set_target_bitmap when switching from a memory target. - Fix a potential crash when drawing the screen to a bitmap with D3D. - WGL shouldn't need to preserve bitmaps. - Update the projection transform when setting up the OpenGL context on X11 (SiegeLord). - Lock bitmap to prevent slowness when creating a cursor from a non-memory bitmap on Windows. - Conditionally lock bitmap when creating cursor on X11 (previously it did so even if already locked). Input: - Make al_install_touch_input fail under Windows if there is no touch device. - Temporary fix for delay after mouse warp on OS X. File I/O: - Fix al_fputc on big-endian. Reported by Andreas Rönnquist and Tobias Hansen. - Make al_fputc return value like fputc when out of range. Image addon: - gdiplus: Only preserve indexed images with KEEP_INDEX flag on. Font addons: - Added ALLEGRO_ALIGN_INTEGER text drawing flag (Todd Cope). - Added a new al_get_font_ranges function. - Made TTF addon include padding on the top and left edges of pages (Todd Cope). Audio addon: - Use programmatically generated interpolators. They cover an additional case which was missed and should be slightly more efficient. - Support linear interpolation for 16-bit mixers. - Add cubic interpolation for mixers (off by default). - Fix potential deadlock in stop_voice for OpenAL. - Fix potential deadlock in stop_voice for DirectSound. - Improve buffer filling behaviour for DirectSound, reducing pops and crackles significantly on slower machines. - Increase default buffer size for DirectSound to 8192 samples. Android port: - Support ALLEGRO_KEYBOARD_STATE. - Fix return type of APK_tell (Todd Cope). - Allow use of OpenGL ES 2 under Android. iOS port: - Make orientation changes work on iOS with SDK 6. Build system: - Rename native dialog library back to allegro_dialog to match 5.0. - Install pkg-config files when cross-compiling on Unix. Python: - Make the Python wrapper also check for the monolith DLL. Examples: - ex_synth: Add button to save waveform to a file. - ex_multisample: Demonstrate using moving bitmaps. - Renamed a5teroids to Cosmic Protector Other: - Minor bug fixes and documentation updates. Changes from 5.1.2 to 5.1.3 (August 2012) ========================================= The main developers this time were: Dennis Busch, Trent Gamblin, Elias Pschernig, Jon Rafkind, Paul Suntsov, Peter Wang. Displays: - Rewrite D3D display format listing code, which was broken. This should re-enable multi-sampling and fix ex_depth_mask being slow with D3D. - Fixed a case where changing fullscreen mode in D3D via al_resize_display caused a crash and loss of loaded bitmaps information. - Fixed a case where changing fullscreen mode in OpenGL (on Windows) via al_resize_display cause nothing to be rendered after the mode change. - Fixed OpenGL (Windows) bitmap preservation between fullscreen mode changes. - Fixed missing/incorrect resize events under Windows. - Fixed ALLEGRO_FULLSCREEN_WINDOW under OS X. - Fix al_set_new_display_adapter on OS X. - Enable fullscreen icon on resizable windows on OS X 10.7 and up. - Added al_osx_get_window function (Dennis Gooden). Graphics: - Rename al_ortho_transform to al_orthographic_transform and give it a more consistent parameter order. - Add al_perspective_transform and al_translate|scale|rotate_transform_3d. - al_draw_pixel was crashing when drawn on sub-bitmaps on OpenGL. - Make ogl_flush_vertex_cache disable GL_TEXTURE_2D state. - Don't use NSOpenGLPFAAccelerated unnecessarily (OS X). Input: - Fix incorrect keyboard modifier flags after leaving and re-entering a window (Windows). - Fixed a bug with mouse enter/leave events for resized windows under OSX (Dennis Gooden). Audio addon: - Add OpenSL ES driver for Android. Font addons: - Add builtin font creation function. - Preserve projection transformation when caching glyphs in the TTF addon. Image addon: - Don't include native image loader source files when the native image loaders are disabled. Primitives addon: - Add vertex buffer API. Native dialogs addon: - Run NSAlert on the main thread (OS X). Android port: - Many bug and compatibility fixes. - Support al_inhibit_screensaver on Android. - Generate SWITCH_IN/OUT events on Android similar to iOS. - Support render state API on Android. - Make al_acknowledge_drawing_resume take a user callback parameter for interdependant textures. - Support building Android port for x86. - Add an ANDROID_APP_NAME CMake variable which will replace all org/liballeg/app and org_liballeg_app with your own app name Build system: - Make the monolith dll under Windows use proper dll exports with MSVC. - Properly include the main addon in the monolith build. - Add Physfs and Cg include directories. Examples: - Added new examples: ex_projection, ex_vertex_buffer. Other: - Documented the allegro_main addon. - Various minor bug fixes and cleanups. Changes from 5.1.1 to 5.1.2 (May 2012) ====================================== The main developers this time were: Thomas Fjellstrom, Trent Gamblin, Elias Pschernig, Peter Wang. Core: - Add userdata to Windows window callbacks and rename the functions (Matthew Leverton). - Fix ALLEGRO_STATIC_ASSERT collisions from different files included in the same translation unit. Reported by tobing. - Make al_ustr_empty_string const correct. - Fix many memory leak/warnings on MacOS X (Pär Arvidsson). Filesystem: - Make stdio al_fopen implementation set proper errno on failure. - Make al_get_standard_path(ALLEGRO_TEMP_PATH) treat environment values as directory names even without a trailing slash on Unix. - Fix typo preventing get_executable_name from using System V procfs correctly. Reported by Max Savenkov. Displays: - Fixed bug on Windows where two SWITCH_IN events were fired when window was minimized/restored (Michael Swiger). - Fixed inverted al_toggle_display_flag(ALLEGRO_NOFRAME) logic under Windows as well as a bug where repeatedly setting the flag to on would make the window grow bigger and bigger (Michael Swiger). - Fixed inverted al_toggle_display_flag(ALLEGRO_NOFRAME) logic in X11. - Rename al_toggle_display_flag to al_set_display_flag, retaining the older name for compatibility. - Add ALLEGRO_FRAMELESS as a preferred synonym for the confusing ALLEGRO_NOFRAME flag. - Set WM_NAME for some window managers (X11). - Disable the idle timer on iOS (screen lock) when entering airplay mode. - Make al_destroy_display handle display disconnection properly. The user will need to clean up then call al_destroy_display after receiving ALLEGRO_EVENT_DISPLAY_DISCONNECTED (iOS). Graphics: - Added al_get_parent_bitmap (Paul Suntsov). - Make blitting from backbuffer work when using multisampling on Windows/D3D. - Redefine pixel format LUMINANCE_8 as SINGLE_CHANNEL_8. - Map SINGLE_CHANNEL_8 to red channel only. Fix some software pixel format conversion bugs previously present with the LUMINANCE_8 format. - Added al_create_custom_bitmap. - Remove ALLEGRO_PRESERVE_TEXTURE flag. The idea is to always preserve textures unless directed otherwise by the user with ALLEGRO_NO_PRESERVE_TEXTURE. - Added al_clear_depth_buffer and al_set_render_state functions. - Force al_create_bitmap to not create oversized bitmaps, to mitigate integer overflow problems. - Removed initial black frame on all Allegro programs. OpenGL: - Fix null pointer dereference if backbuffer creation fails. Reported by Max Savenkov. - Made the ALLEGRO_OPENGL_FORWARD_COMPATIBLE flag work with al_draw_bitmap. - Texture should be 'complete' (min/mag and wrap set) before glTexImage2D. - Restore matrix manipulation code for unlocking backbuffer in GL <1.4 case. - Fixed a bug in al_unlock_bitmap where the pixel alignment mistakenly was used as row length. - Never set the projection when using programmable pipeline mode unless a program object is bound. - Do not preserve bound texture state. - Disable GL_NORMAL_ARRAY in non-programmable pipeline mode. - Fixed typo in names of some OpenGL extension functions. - Display list of OpenGL extensions in allegro.log also for OpenGL 3.0. - Check for OES_texture_npot as well for non-power-of-two support. - Fix loading of some textures on iOS. Direct3D: - Fixed a bug in the D3D driver where separate alpha blending was being tested for when it shouldn't have been (Max Savenkov). - Do not manage depth stencil surface. - Arrange code so that sleep and hibernate work using the release and restore callbacks. - Fix device reset problem in D3D. - Make sub-bitmap restore properly on lost device. Input: - Increase max number of joystick "sticks". Due to analogue buttons being mapped to axes, the number of sticks on a single device may be much higher than expected. - Monitor /dev/input instead of /dev on Linux for hotplugging joysticks (Jon Rafkind). - Do not permanently change the locale for the X11 keyboard driver. Set LC_CTYPE only, not LC_ALL. - Update ALLEGRO_MOUSE_STATE even if mouse emulation event source isn't attached to an event queue (Android and iOS). - Don't report shakes at program start accidentally (iOS). Android port: - Many graphics-related changes (too many to list). - Make Android port always choose a double buffered graphics mode. - Don't force 16-bit mode if no COLOR_SIZE specified. - Go fullscreen (no title/status bar). - Generate ALLEGRO_EVENT_DISPLAY_HALT_DRAWING, RESUME_DRAWING events instead of SWITCH_IN/OUT. - Add an APK file driver for reading assets directly from Android app bundles. - Additions and fixes to accelerometer and orientation code. - Support for volume keys. - Added a dummy mouse driver, enough to get al_get_mouse_state working. - Improve compatibility of touch input emulation driver with iOS touch input emulation. - Add al_android_get_os_version(). - Fix linking problem on Android 2.2 and below. - Update and clean up sample project. Audio addon: - Fix desychronization due to inaccurate sample positions when resampling. Thanks to _Bnu for discovering the issue and Paul Suntsov for devising the correct solution. - Fix linear interpolation across audio stream buffer fragments. - Add stub OpenSL driver (Jon Rafkind). Image addon: - Improved accuracy of un-alpha-premultiplying in the native OSX bitmap loader. - Improve compatibility of BMP loader. In particular, support bitmaps with V2-V5 headers and certain alpha bit masks. - Improve robustness of BMP loader against some corrupt files. - Fix TGA loader using more memory than necessary. Reported by Max Savenkov. - Image loading in Android now works. Font addon: - Use user set pixel format for fonts. TTF addon: - Added ALLEGRO_TTF_NO_AUTOHINT font loading flag to disable the Auto Hinter which is enabled by default in newer version of FreeType (Michał Cichoń). - Unlock glyph cache page at end of text_length and get_text_dimensions (jmasterx). Primitives addon: - Use GL_REPEAT so textures can be tiled again. - Always set the texture due to missing glGetInteger on some GLES 1.0/1.1 devices. Native dialogs addon: - Only call SetMenu from within the window thread (Matthew Leverton). - Clear mouse state after dialogs or else it gets messed up (OSX). - Fix some warnings in gtk_dialog.c. Build system: - Added OSX Framework support for the monolith library. - Make examples build with monolith build. - Add WANT_ANDROID_LEGACY to allow compiling for older Android platforms. Examples: - a5teroids: Added high scores and other improvements. New graphics by Tony Huisman. - Add ex_file_slice. - Add ex_resample_test. - Add ex_depth_mask. - ex_audio_props: Add bidir button. - ex_joystick_events: Support hotplugging and fix display of 3-axis sticks. - ex_polygon: Test al_draw_filled_polygon_with_holes. - ex_get_path: Test al_set_exe_name. - Made the skater demo run from within xcode. - Add test_driver --no-display flag. (Tobias Hansen) - Add test_driver --force-opengl-2.0 option. - Make .png and .tga loading tests to not require a backbuffer with an alpha channel. Other: - Many minor bug fixes. - Many documentation updates. - Fix whatis entries of man pages. (Tobias Hansen) Changes from 5.1.0 to 5.1.1 (February 2012) =========================================== The main developers were: Thomas Fjellstrom, Trent Gamblin, Matthew Leverton, Elias Pschernig, Jon Rafkind, Peter Wang. Ports: - Thomas Fjellstrom started an Android port. Displays, keys and touch events work. Core: - Make al_ref_cstr, al_ref_ustr and al_ref_buffer return const ALLEGRO_USTR* instead of just an ALLEGRO_USTR* (Paul Suntsov). Graphics: - Fixed a bug in the OpenGL driver when drawing the backbuffer outside the clipping rectangle of the target bitmap. Displays: - Fixed a problem with wrong window size when restoring a minimised window, in code that was added to support window constraints (jmasterx). - Set ALLEGRO_MINIMIZED display flag on Windows (Zac Evans). - Prevent a deadlock during display creation on X. - Fallback to the 'old' visual selection method on X instead of crashing if the 'new' visual selection doesn't work. - Implement XEmbed protocol. - Add hot plug display support on iOS (Airplay and wired.) Input: - Use the same logic in set_mouse_xy for FULLSCREEN_WINDOW as was used for FULLSCREEN. (Max OS X) Audio addons: - Add audio recording API with implementations for ALSA, AudioQueue, DirectSound8 and PulseAudio. - Improve code to check that DLL symbols are loaded in the acodec addon. The old method was hacky and broke under -O2 using GCC 4.6.1. (Paul Suntsov) Image addon: - Some initial Android support. - Write libjpeg errors to Allegro log. TTF addon: - Clear locked region so pixel borders aren't random garbage that can be seen sometimes with linear filtering on. Video addon: - Added Ogg Theora/Vorbis backend. - Fixed a few warnings with ffmpeg version 0.7/0.8. Build system: - Add monolith library option. - Detect the new MinGW cross-compiler in Ubuntu. Examples: - Added new examples: ex_record, ex_record_name, ex_display_events. - ex_ogre3d: Make it work under Windows (AMCerasoli). - skater: small bug fixes, mouse support, add missing files for scrollers. - a5teroids: Support gamepads that report small non-zero values for sticks that are at rest. - Added pong example in Python. Other: - Added index to HTML version of the reference manual. - Various documentation updates. - Other minor bug fixes. Changes from 5.0.x to 5.1.0 (November 2011) =========================================== The main developers were: Michał Cichoń, Trent Gamblin, Matthew Leverton, Elias Pschernig, Paul Suntsov, Peter Wang. Core: - Added al_register_assert_handler. - Added API for registering callbacks to intercept window messages on Windows. Graphics: - Added bitmap conversion API: al_convert_bitmap, al_convert_bitmaps, with bitmap flag ALLEGRO_CONVERT_BITMAP and display option ALLEGRO_AUTO_CONVERT_BITMAPS. Automatic bitmap conversion is enabled by default. - Added al_draw_tinted_scaled_rotated_bitmap_region. - Added new ALLEGRO_PIXEL_FORMAT_LUMINANCE_8 format. - Added a new bitmap flag ALLEGRO_KEEP_INDEX. - Separate bitmap loader flags from bitmap flags. This adds three functions: al_load_bitmap_flags, al_load_bitmap_flags_f and al_load_bitmap_font_flags. - Add ALLEGRO_SRC_COLOR, ALLEGRO_DST_COLOR blending modes (Jon Rafkind). - Add ALLEGRO_INVERSE_SRC_COLOR and ALLEGRO_INVERSE_DST_COLOR blending modes. - Made al_compose_transform do a full 3d multiply. - Added al_get_current_inverse_transform, al_ortho_transform, al_get_projection_transform, al_set_projection_transform. - Added al_reset_clipping_rectangle convenience function. - Added al_get_d3d_texture_size. - Added al_d3d_set_release_callback and al_d3d_set_restore_callback for release/restoring user d3d objects. Displays: - Added al_get_display_orientation. - Added a new display option ALLEGRO_SUPPORTED_ORIENTATIONS to specify the supported orientations (default is just portrait as before). - Added al_change_display_option function, initially only for ALLEGRO_SUPPORTED_ORIENTATIONS. - Add two new display events (only implemented on iOS right now). ALLEGRO_EVENT_DISPLAY_HALT_DRAWING tells the app to stop all drawing and ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING tells it it can start drawing again. SWITCH_OUT/IN on iOS were redefined from "going into/out of background" to "going active/inactive". - Added the function al_acknowledge_drawing_halt. - Added window size constraint functions (jmasterx). Input: - Add API related to touch input. The implementation covers iDevices and Windows 7 drivers for touch input. A number of mouse emulation modes are provided. Events: - Add al_pause_event_queue, al_is_event_queue_paused. Filesystem: - Added al_fopen_slice. - Added al_set_exe_name which allows overriding Allegro's idea of the path to the current executable. Audio addon: - Add mixer gain property and functions. - Add a 'global' audio event source, generating some audio events from the Audio Queues driver: AUDIO_ROUTE_CHANGE, AUDIO_INTERRUPTION, AUDIO_END_INTERRUPTION. Native dialogs addon: - Add menus to native dialogs (Windows and GTK). Primitives addon: - Add simple polygon triangulator and polygon drawing routines. - Added al_draw_polyline and al_draw_polyline_ex. - Added al_draw_filled_pieslice and al_draw_pieslice. - Added al_draw_elliptical_arc. TTF addon: - Added al_load_ttf_font_stretch functions (tobing). Shader addon: - Added a shader addon and programmable pipeline support. Video addon: - Added a video player addon, currently using ffmpeg. iOS port: - Added al_iphone_override_screen_scale, al_iphone_get_screen_scale, al_iphone_set_statusbar_orientation, al_iphone_get_last_shake_time, al_iphone_get_battery_level, al_iphone_get_window, al_iphone_get_view. Examples: - Added new example programs: ex_audio_chain, ex_loading_thread, ex_menu, ex_palette, ex_polygon, ex_shader, ex_window_constraints, ex_video. - Added skater demo ported from Allegro 4.4. allegro5-5.2.10.1/docs/src/changes-5.2.txt000066400000000000000000001027761473414355200176670ustar00rootroot00000000000000% Allegro changelog for 5.2.x series These lists serve as summaries; the full histories are in the git repository. Changes from 5.2.10 to 5.2.10.1 (December 2024) =============================================== MacOS - Fix some corner cases in the new keyboard input system (SiegeLord) - Fix version-based conditional compilation (Rhys-T) Packaging - Fix the package script to check for makeinfo, this prevents malformed source achives from being created (as happened in 5.2.10) (SiegeLord) Changes from 5.2.9.1 to 5.2.10 (November 2024) ============================================== Core - Add a compatibility config option, `keyboard_version=xx.yy.zz` as well as the same but with `joystick_version` if it is necessary to restore the old behavior. This enables us to fix bugs with the input system, while providing a mechanism to restore old buggy behavior temporarily (SiegeLord) - Assorted timer improvements (Connor Clark) - Optimize inverse transformations. (SiegeLord) - Fix the handling of the new window title in `ALLEGRO_STATE` (#1562) (Alexandre Martins) - Add `ALLEGRO_TRACE_LEVEL` environment variable. This makes it easier to enable logging on release builds. (SiegeLord) - Add `al_ref_info` to convert `ALLEGRO_USTR_INFO` to `ALLEGRO_USTR` (SiegeLord) - Add `al_get_display_adapter` (#1578) (SiegeLord) - Add `al_get_render_state` (Mark Oates) MacOS - Don't use usage numbers as joystick button ids on OSX. (#1527) (SiegeLord) - Enable deadkey handling on MacOS (SiegeLord). - Map numpad delete to `ALLEGRO_KEY_PAD_DELETE` and the weird ISO section key to `ALLEGRO_KEY_BACKSLASH2` (#1523) (SiegeLord) Windows - Fix key events when using modifiers (#1430, #1504) (SiegeLord) - Fix undesirable deadzone when using analog joysticks (geecab) - Use the correct monitor when restoring fullscreen window when using OpenGL (SiegeLord) - Fix `ALLEGRO_FULLSCREEN_WINDOW` not working in certain conditions (SiegeLord) Linux - Fix joystick initialization when overriding IO (#1572) (Alexandre Martins) - Make sure the bitmap for the initial icon is created as a memory bitmap (#1571) (SiegeLord) Android - Add more joystick buttons (#1482) (Alexandre Martins) - Fix corruption of bitmaps created with the `ALLEGRO_NO_PRESERVE_TEXTURE` flag when the application loses focus (#1492) (Alexandre Martins) - Fix a concurrency issue related to `al_acknowledge_drawing_halt` (Alexandre Martins) - Add `al_android_open_fd` (Alexandre Martins) - Assorted improvements (Alexandre Martins) iPhone: - Fix build (Todd Cope) Audio addon: - Add MacOS support for listing output devices (Aldrik Ramaekers) Acodec addon: - Prefill `ALLEGRO_AUDIO_STREAM`s with data (SiegeLord) - Add OpenMPT support. This is meant to replace DUMB, as DUMB is not maintained. You can use the compatibility config option `acodec_prefer_dumb` to temporarily make DUMB the preferred handler for module files, if Allegro is built with both DUMB and OpenMPT. Some modules may sound different under OpenMPT. (SiegeLord) Native dialog addon: - Add Android support (Alexandre Martins) - Auto-scroll the native textlog on MacOS (SiegeLord) - Fix monospace fonts on MacOS in the native textlog (SiegeLord) - Improve the patterns arg in `al_create_native_file_dialog` (SiegeLord) - Support for multiple pattern sets (Windows/Linux) - Supports for custom pattern set descriptions (Windows/Linux) - Support for MIME types on MacOS - Remove the implicit catch-all pattern on Windows (the "All files *.*"), it was inconsistent with other platforms. - Make MacOS do a better job at extracting the file extension - Improve documentation overall Video addon: - Make `al_is_video_playing` return false before `al_start_video` (SiegeLord) - Make `ALLEGRO_VIDEO` work with the automatic destruction system (SiegeLord) Build system: - Reproducible build support (Andreas Rönnquist) - Fix multiarch install location (Andreas Rönnquist) Examples: - Remove VLAs to improve Visual Studio support (Jeff Linahan, SiegeLord) - Fix opaque black background pixels in explosion sprites in the Shooter demo (tstoeter) Changes from 5.2.9 to 5.2.9.1 (January 2024) ============================================ Linux: - Fix a regression where toggling fullscreen window when menus are used stopped working (SiegeLord) Changes from 5.2.8 to 5.2.9 (November 2023) =========================================== Android: - Fix back button/gesture (alemart) - Implement `al_get_joystick_name` (alemart) - Great many assorted fixes (alemart) Audio: - Add `al_get_mixer_has_attached` and `al_get_voice_has_attached` (TRDario) - Fix `al_set_audio_stream_playmode` return value and interaction with looping audio streams (Cody Licorish) - Send PulseAudio silence if the attached mixer is stopped (SiegeLord) Acodec: - voc memory leak fixes (TRDario) - Fix internal looping for mod files (SiegeLord) Build system: - Add a target for copying examples, letting you build the demo without the examples (SiegeLord). - Improve CMake scripts (Gilad Reich) - Support the newer WebP library which is split into two (SiegeLord). Core: - Add `al_can_set_keyboard_leds` and `al_can_get_mouse_cursor_position` (TRDario) - Allow outputting logs to STDOUT via ALLEGRO_TRACE environment variable (SiegeLord) - Add `al_get_current_shader` (TRDario) - Add `al_get_window_borders` for Windows and Linux (Elias Pschernig + SiegeLord) TTF: - Fixes for `al_get_glyph_width`, `al_get_glyph_al_get_glyph` when interacting with zero-width/zero-height glyphs (Connor Clark) MacOS: - Don't close submenus on click (Todd Cope) - Fix disabling menu items (Todd Cope) - Add support for filtering by file extensions in the native file dialog (Todd Cope) - Textlog improvements (Connor Clark) - Fix improper display boundary for cursors (Connor Clark) - Make `al_get_joystick_name` return the name of the joystick (Todd Cope) - Fix off-by-one error for hat switches (Connor Clark) - Add a workaround for live resizing not working. Enable it via `[osx] allow_live_resize = false` in `allegro5.cfg` and then listen and respect `ALLEGRO_EVENT_DISPLAY_HALT/RESUME_DRAWING` events (#1350) (SiegeLord + Elias Pschernig) Linux: - Fix fullscreen window creation (#1349) (SiegeLord) - Fix some X11 + fullscreen window interaction (#1358) (SiegeLord) - Allow setting higher quality icons (SiegeLord + Trent Gamblin) - Improve `DISPLAY_SWITCH_IN/OUT` events (#1390, #1367) (SiegeLord) - Work on improving Window positioning (Elias Pschernig) - Fix creating an initially maximized window (SiegeLord) - Enable toggling and setting maximized/frameless modes when menus are used (SiegeLord) - Fix popup menu (#1280) (SiegeLord) - Make AltGr (right Alt) toggle the `ALLEGRO_KEYMOD_ALTGR` modifier (SiegeLord) Windows: - Fix drawable area mouse hiding state being out of sync (#1388) (SiegeLord) - Fix some oddities with Shift + Alt on Windows (#1348) - Work on improving Window positioning (SiegeLord) - Make native file dialog respect the initial directory when `ALLEGRO_FILECHOOSER_FOLDER` is set (José Carlos HR) - Fix the client area changing size on Windows when restoring a window (#1433) (SiegeLord) - Fix crashes with menus and Windows (#1381) (SiegeLord) - Fix keyboard modifier keys + char events (#1504, #1430) (SiegeLord) SDL: - Fix touch ids (Sebastian Krzyszkowiak) - Fix `al_get_mouse_state` crash (Elias Pschernig) - Implement `al_create_mouse_cursor` (Connor Clark) - Implement `al_get_monitor_dpi` (Elias Pschernig) Documentation: - Assorted clarifications and improvements (various) Changes from 5.2.7 to 5.2.8 (June 2022) ======================================== The main developers this time were: SiegeLord, Elias Pschernig, Sebastian Krzyszkowiak, Julian Smythe. Build system: - Add a configuration summary. Currently this mostly reports the addon features. - Fix build failure with sanitizers enabled. - Remove `-Wdeclaration-after-statement`, MSVC had support for this for a while now. - Bump minimum CMake version to 3.0. Core: - Add `al_fopen_slice` mode to prevent seek on close (Karl Robillard). - Allow configuring bitmap wrapping via `al_set_new_bitmap_wrap`. Graphics: - Reject creating bitmaps with negative width or height (Peter Hull). - Add a minimal shader implementation for GLSL. Minimal shader supports fewer features, but is faster (Issue #1120). Select it via the `_MINIMAL` suffix to the shader platforms. Emscripten: - Improve emscripten instructions for building demos (Connor Clark). - Fix usage of SDL_Init for emscripten (Issue #1322) (Connor Clark). OSX: - Fix a few thread-related crashes. - Don't use `-flat_namespace` in `LINK_FLAGS` (danielnachun). - Make `al_get/set_window_position` work on Retina displays Windows: - Fix flickering when creating multisampling displays under DirectX. - Fix multisampling selection on Windows with OpenGL. - Fixed a bug which freezes and crashes the window in Windows OpenGL (HerrNamenlos123). - Allow specifying shader model 3_0 for HLSL shaders (Issue #1154). SDL: - Ignore touch events from indirect touch devices. - Use `SDL_PeepEvents` for event handling, to improve performance. - Improve joysticks support (Issue #1326) (Connor Clark). - Fix mouse axis setter (Connor Clark). Linux: - Use `clock_gettime` with `CLOCK_MONOTONIC` instead of `gettimeofday` (check-switch-26). Android: - Update Gradle to 5.0. Audio addon: - Add `ALLEGRO_PLAYMODE_LOOP_ONCE` (Issue #1309). - Add `al_play_audio_stream`, a 'simple' API endpoint for audio stream playback. Acodec addon: - Fix Vorbis/Opus support under MSVC + Clang. - Add audio identification / `al_identify_sample`. - Use regular seeking for Ogg streams. The old one did cross-fades, causing unexpected behavior in certain cases (Issue #1310). - Enable looping for modules. Audio addon: - Allow identifying and listing audio devices via new API: `al_get_num_audio_output_devices`, `al_get_audio_output_device`, `al_get_audio_device_name` (Aldrik Ramaekers). Color addon: - Add linear and oklab color spaces to the color addon. Font addon: - Fix declaration of al_draw_multiline_textf() as a PRINTFUNC (check-switch-26). Image addon: - Prevent RLE data in corrupt `.tga` from overflowing the buffer (Peter Hull). - PCX loader validation (Peter Hull). - Windows BMP - Make more robust to crashing (Peter Hull). - Fix DDS compressed image loading when image dimensions are not multiple of block size (check-switch-26). Native Dialog addon: - Fix native dialogs addon compatibility with older GTK+ versions (Andrew Kravchuk). TTF addon: - Fixed TTF rendering when using transforms (check-switch-26). PhysFS addon: - Fix incorrect error handling in `PHYSFS_close` (j-w-c-b). Video addon: - Allow identifying video files via a magic number, exposed via `al_identify_video` (Issue #1262). - Fix `al_is_video_addon_initalized` (Jayson). Documentation: - Document some reasonable defaults for `al_create_mixer`/`al_create_voice`. - Refactor the audio docs to highlight the simple API better. Misc: - Fix a few data race issues, in an effort to fix ex_threads crashes on Linux. Examples: - Allow exiting from `ex_audio_timer` (BillKek) - Add the Allegro 4 "shooter" demo. - Fix `ex_threads` crash under D3D. - Add `ex_audio_devices`. - Update `ex_palette` to build with Emscripten (Issue #1318). - Improve `ex_stream_seek`. - Improve `ex_windows`. Changes from 5.2.6 to 5.2.7 (March 2021) ======================================== The main developers this time were: SiegeLord, Peter Hull, Elias Pschernig, Aldrik Ramaekers, Andreas Rönnquist. Build system: - Allow generating projects with a suffix (lorry-lee). - Fix build under Clang-CL in Visual Studio. Core: - Avoid some undefined behavior errors. - Return key modifiers in `ALLEGRO_EVENT_KEY_UP` and `ALLEGRO_EVENT_KEY_DOWN`. - Allow calling `al_map_*` color functions before Allegro is initialized. - Allow minimum bitmap size to be something other than 16 on non-Android platforms (controlled via `allegro5.cfg`). - Add `al_get_monitor_refresh_rate` (only implemented on Windows for now). Graphics: - Fix `ALLEGRO_KEEP_INDEX` flag for bitmaps. - Add `ALLEGRO_OPENGL_CORE_PROFILE` display flag. Emscripten: - The experimental Emscripten support (via the SDL backend) is now documented in `README_sdl.txt`. OSX: - Move more Cocoa operations to the main thread. - Explicitly link CoreVideo to fix the static build. Windows: - Issue #1125: Speed up OpenGL extension detection (Tobias Scheuer). - Use Unicode APIs when enumerating joysticks. - Use `WM_DEVICECHANGE` rather than polling to detect joystick hotlugging, reducing input drops and lags (Todd Cope). - Fix joystick polling period. - Restore WinXP compatibility by using slightly older API when loading shared libraries (Julian Smythe). - Fix build with HLSL disabled (Julian Smythe). - Raise DirectInput `MAX_JOYSTICKS` to 32 and `DEVICE_BUFFER_SIZE` to 128. SDL: - Issue #1224: Fix bug in SDL voice driver. Audio addon: - Allows playing sounds in reverse by specifying a negative speed. Acodec addon: - Fix edge-case looping in Ogg Vorbis stream (Cody Licorish) Audio addon: - Use more sensible values for PulseAudio's playback buffer, potentially resolving some crashes and high CPU usage. Native Dialog Addon: - Migrate from GTK2 to GTK3. Sadly, we lose menu icons as GTK3 dropped support for them. TTF addon: - Allow initializing TTF addon before the Font addon. - Shut-down the TTF addon automatically in `al_uninstall_system`. PhysFS addon: - Fix handling of native path separators. - Stop using deprecated PhysFS API. Primitives addon: - Fix segfault in `al_draw_ribbon` when `num_segments > 128` (Rodolfo Borges). - Issue 1215: Correctly handle small scales when determining subdivision level for high level primitives (Robin Heydon). Documentation: - Fix LaTeX errors in the generation of the reference manual PDF. - Add links to examples into the reference manual. - Allow pressing 'S' to focus the search bar in the docs. - Assorted documentation improvements. Misc: - Add a security policy and an associated private security mailing list - allegro-security@lists.liballeg.org. - Add Emscripten-powered examples to https://liballeg.org/examples_demos.html. Examples: - `ex_audio_simple` now displays instructions and supports bidirectional looping. - Add default files to some audio examples. Changes from 5.2.5 to 5.2.6 (February 2020) ========================================== The main developers this time were: SiegeLord, Peter Hull, Karthik Kumar Viswanathan, Elias Pschernig, Sebastian Krzyszkowiak, Doug Thompson, PmProg, RmBeer. Core: - Fix timestamps being clamped to ints on touch inputs with X11. - Fix al_utf8_width argument type mismatch on platforms where `sizeof(int) != 4`. - Fix building for GNU/Linux without GNU extensions enabled - Some refactoring to simplify adding new drivers. Graphics: - Fix for OpenGL version selection and reporting on Windows and X (Edgar Reynaldo). - Report OpenGL version in display options on Android, iOS and Raspberry Pi. - Fix creation of the bitmap depth buffer for non-square bitmaps (Kevin Wellwood). - Fix `ALLEGRO_ALPHA_TEST_VALUE` not being interpreted correctly. - Fix reported bitshifts for `ARGB_4444` and `RGBA_4444` pixel formats. - Fix alpha test with the GLSL version. Android: - Do not build Android examples outside of Android. - Use the cmake toolchain provided by the Android NDK. - Use FLAG_KEEP_SCREEN_ON instead of a wakelock for screensaver inhibition. - Use DisplayListener to listen to orientation changes. - Implement `ALLEGRO_FRAMELESS` on Android. This hides the navigation buttons and the bar on top. Linux: - Fix `al_inhibit_screensaver` function. OSX: - Ensure system calls happen on the main thread. - Make things work on Catalina. Hurd: - Fix pthreads (Andreas Rönnquist). Windows: - Implement Windows version check using non-deprecated functions. - Abstract UNICODE vs ANSI string handling, switch to using UNICODE by default. - Enable debug window for `DEBUGMODE` on Windows. SDL: - Fix requesting GLES profile on GL Allegro. - Add audio recorder implementation. - Don't link with dl, it's unnecessary. Addons: - Add a whole bunch of `al_is_*_initialized` functions (Mark Oates). Acodec addon: - Add MP3 support via the MiniMP3 library. Audio addon: - Allow calling `al_destroy_audio_recorder` on NULL. - Fix some stream garbage audio issues for high playback speeds. Image addon: - Add support for FreeImage library. - Always prefer non-system image loaders. Python wrapper: - Fix a number of bugs (zachs18 and others). Misc: - Add an `.editorconfig` file. - Convert our internal Python scripts to Python 3. Examples: - `ex_draw_bitmap` - Add more options. Changes from 5.2.4 to 5.2.5 (February 2019) ========================================== The main developers this time were: Sebastian Krzyszkowiak, SiegeLord, Elias Pschernig, Bruce Pascoe, Aldrik Ramaekers, Firat Salgur. Core: - Try to identify bitmap format for unknown extensions. - Add some missing OpenGL 4.3 functions. - Add `al_create_thread_with_stacksize` to create threads with a custom stack size. (Aldrik Ramaekers) - Add `al_get_system_id` function, letting you disambiguate platforms at runtime. Graphics: - Add `al_get_monitor_dpi` to query the DPI of a monitor. - Add new API for making blender a bitmap-local state (like transformations), which can simplify some code. See `al_set_bitmap_blender` and the related APIs. Also see the `ex_blend_target` example. - Added `al_transpose_transform`. This is useful for rotation transformations. - Rework internal GLES support for better portability. - Don't force POT bitmaps on GLES. - Fix repeated bitmap locking on OpenGL. Android: - Various documentation and other improvements (Christian Mauduit). - Fix OpenGL version reporting after display creation. iOS: - Fix OpenGL version reporting after display creation. Linux: - Improve linux joystick detections. - Fix a number of memory leaks/crashes in the audio addon when using pulseaudio/alsa. (Julian Smythe) - Fix compilation with Mesa 18.2.5 and later. - Fix OpenGL version reporting after display creation (Edgar Reynaldo). - Fix requesting specific OpenGL versions via display options (Edgar Reynaldo). OSX: - Make `al_get_monitor_info` return the correct values for Retina displays. - Fix vsync on OSX 10.14+. RaspberryPi: - Fix OpenGL version reporting after display creation. Windows: - Fix toggling of menu checkboxes by id. - Fix `al_draw_indexed_primitive` while using Direct3D. - Fix crash when passing `NULL` display to `al_show_native_file_dialog` while using `ALLEGRO_FILECHOOSER_FOLDER`. - Fix OpenGL version reporting after display creation (Edgar Reynaldo). - Fix requesting specific OpenGL versions via display options (Edgar Reynaldo). SDL: - Sebastian Krzyszkowiak has spent a lot of effort to making the SDL backend usable as a nearly fully featured Allegro backend. You can use it on platforms native Allegro implementations do not support (such as emscripten, etc.). Addons: - Better logging when failing to load a resource. - Fix a memory leak when destroying a mixer with attached streams. - Fix a memory leak in the audio destroying a mixer with attached streams. Acodec addon: - Allow modules to loop properly when the user hasn't specified loop points. (Todd Cope) Audio addon: - Better support for big endian. (Douglas Mencken) TTF addon: - Added support of HarfBuzz in FreeType (Arves100). Documentation: - Source links now point to the correct commit on GitHub. - General improvements and clarifications. Examples: - Add `ex_blend_target`. Changes from 5.2.3 to 5.2.4 (February 2018) ========================================== The main developers this time were: Sebastian Krzyszkowiak, Elias Pschernig, SiegeLord Core: - Fix errors when reading/writing 0 byte buffers (Bruce Pascoe). - Re-initialize TLS when Allegro is installed (Issue #865). - Add `al_transform_coordinates_4d`. - Don't initialize the trace mutex multiple times (Issue #874). - Fix 3D (non-projection) transforms with `al_hold_bitmap_drawing`. Raspberry Pi port: - Fix compilation on RPI. Android port: - Remove limit on the working directory length. - Fix `ALLEGRO_MAXIMIZED` flag. - Fix build with older Android NDKs. - Remove `glClear` hack for Android 2.1. Linux port: - Make compositor bypass configurable in X11, and bypass only when fullscreen by default. OSX port: - Fix a few OSX retina scaling issues (Issue #851). Audio addon: - Fix ALSA lag. - Add an option to use the desktop window when initializing DirectSound (Issue #877). Font addon: - Add support for bmfont format. Native dialog addon: - Resize the display on Windows when hiding/showing the menu (Issue #860). - Detect when `al_popup_menu` fails to actually work under GTK (Issue #808). - Don't clear the top-level menu when destroying the popup menu. Build system: - Don't link in libm on MSVC for DUMB (Issue #847). - Don't use the LOCATION property (Issue #847). - Don't use SYSTEM for DirectX includes. - Add hints for mingw-w64 path locations for DirectX includes/libs. Python binding: - Fix the Python code-generation scripts to run under Python 2. Lua binding: - Add script to generate LuaJIT C API for Allegro 5 (BQ). Documentation: - Many improvements (Andreas Rönnquist, others) Examples: - Add a texture to the skybox in `ex_camera`. Changes from 5.2.2 to 5.2.3 (October 2017) ========================================== The main developers this time were: Elias Pschernig, SiegeLord, Sebastian Krzyszkowiak, Vitaliy V. Tokarev, Simon Naarmann, Bruno Félix Rezende Ribeiro, Trent Gamblin). Core: - Add `al_path_ustr` (Bruce Pascoe). - Handle NULL sections more gracefully with the config API. - Add missing `glStencilMaskSeparate prototype` (Aaron Bolyard). - Add `al_clear_keyboard_state`. - Don't add blank lines before config sections when writing them out. - Fix `fs_stdio_read_directory` appending an extra slash. - Fix `al_set_window_constraints` when the flag ALLEGRO_MAXIMIZED is set. - Fix `al_set_clipping_rectangle` when out-of-bounds (Bruce Pascoe). - Enable blocked locking of S3TC formats unconditionally. Raspberry Pi port: - Set default file interface when attempting to read /boot/config.txt. Android port: - Replace the old build system that used deprecated tools with a new Gradle-based system. - Work around crashes on some Androids when an FBO is bound during `egl_SwapBuffers`. - Fix LocalRef leak when opening files using APK interface. - Remove -Wno-psabi switches from Toolchain-android.cmake. Linux port: - Make three finger salute and LED toggle configurable. - Fix KEY_CHAR events under X11 with compose key enabled. - Fix clearing the `ALLEGRO_MAXIMIZED` flag under X11. - Add `al_x_set_initial_icon`. - Free wm_hints in `set_initial_icon`. - Read Allegro system config from ~/.allegro5rc on Unix. Windows port: - Make bitmap contents persist again after device loss. - Add large file support for MSVC. - Only test cooperative lavel if device is known to be lost. - Don't leak the `D3DEffect` when attaching multiple sources. - Fix `al_get_monitor_info` (Tobias Scheuer). OSX port: - Various fixes for OSX 10.6. - Fix some Bluetooth mice on OS X (Tom Bass). - Fixed deprecation warning when starting OSX console app (Tom Bass). - Fix OSX magic main with the LTO switch (Evert Glebbeek). Audio addon: - Allow setting the buffer size for ALSA. - Don't apply gain twice for sample instances and streams when pan is not `ALLEGRO_PAN_NONE`. - Disallow attaching mixers with different channel configurations. - Add `al_set_sample_instance_channel_matrix` and `al_set_audio_stream_channel_matrix`. - Don't free the extra pointer in DirectSound if voice fails to play for some reason. - Add `al_lock_sample_id` and `al_unlock_sample_id`. - For OpenAL, detach from buffers before deleting. - Return true when seeking mod audio streams. Acodec addon: - Free audio stream buffer in flac_stream_close. - Add DUMB 2.0 support. Color addon: - Add XYZ, xyY, Lab and LCH color spaces. - Remove "purwablue" named color, add "rebeccablue". Native dialog addon: - Improve save dialogs under GTK driver. - Improved path behavior in GTK native file dialog ([bk]door.maus). - Enable `ALLEGRO_FILECHOOSER_FOLDER` On Linux (Todd Cope). - Use unique ids to identify menu items internally, fixing their event sources. - Make the native message box return 2 on Windows when cancel is pressed. Image addon: - Set compression level to `Z_DEFAULT_COMPRESSION` in png saver by default. - Make PNG, JPEG compression level configurable. - Make PNG gamma value configurable. - Add WebP support with libwebp. Video addon: - Allow calling `al_init_video_addon` after `al_shutdown_video_addon` was called. Build system: - Detect and link optional FreeType dependencies. - Add a CMake option to prefer static dependencies. - Fix SDL platform build. Python binding: - Fix some corrupted regexps in the generation script (verderten). Documentation: - Lots of improvements as usual (Edgar Reynaldo, Mark Oates, twobit). Examples: - Fix various issues with `ex_curl`. - Fix memory leak in `ex_audio_simple` (Rm Beer). Changes from 5.2.1.1 to 5.2.2 (December 2016) ======================================= The main developers this time were: Trent Gamblin, SiegeLord, Elias Pschernig. Core: - Don't accumulate time in the timer while it is stopped. - Use dynamic OpenGL ES checks, so binaries produced on newer platforms don't crash on older ones. - Destabilize the OpenGL extensions API (BREAKING CHANGE!). Raspberry Pi port: - Add various optimizations. - Fix `al_set_mouse_xy` under X. Android port: - Fix buffer overrun and memory leak in the clipboard support. - Add WANT_GLES3 to disable some of the newer features on platforms where they aren't supported. - Fix build in Android versions below 3.1. - Fix a crash when activity is destroyed/paused. - Allow building for android mips, arm64 and mips64. - Add `al_android_get_jni_env` and `al_android_get_activity` utility functions. - Update manifest files for newer Android versions. Windows port: - Handle keyboard input properly when Ctrl is pressed (Tobias Scheuer). Hurd port: - Define a fallback PATH_MAX (Andreas Rönnquist). OSX port: - Clear window to black when going in/out of fullscreen. - Fix window centering when going out of FULLSCREEN_WINDOW mode. - Fix OSX 10.12 build. - Allow 32 bit builds on OSX (MarcusCalhoun-Lopez). Build system: - Fix issues with building on GCC6 on Windows. - Fix source directory littering while configuring the Android build. Python binding: - Add support Python 3 (Gabriel Queiroz). Documentation: - Document the behavior of `al_set_target_bitmap` with respect to transformations (Edgar Reynaldo). - Fix typo in `al_use_transform` docs (Ryan Roden-Corrent). Examples: - Add kerning to the `al_get_glyph` example in ex_ttf. - Various fixes in ex_camera (Erich Erstu). Changes from 5.2.1 to 5.2.1.1 (August 2016) ======================================= The main developers this time were: Trent Gamblin, SiegeLord. Core: - Enforce backwards compatibility in the version check, rather than erroneously allowing forwards compatiblity. - Temporarily remove new extensions in ALLEGRO_OGL_EXT_LIST as that broke ABI compatibility. OSX port: - Temporarily revert changes in joystick detection, as it did not interact well with some joysticks. Windows port: - Fix the clear display to black right away to avoid an ugly white flash change. Changes from 5.2.0 to 5.2.1 (July 2016) ======================================= The main developers this time were: Elias Pschernig, Trent Gamblin, SiegeLord, Ryan Roden-Corrent, Boris Carvajal and Peter Hull. Core: - Optimize bitmap holding a bit (Bruce Pascoe). - Add `al_get/set_depth/samples` (OpenGL only for now). - Optimize destruction performance when you have thousands of objects (e.g. sub-bitmaps). - Use low floating point precision for the OpenGL fragment shaders, which helps performance a lot on mobile platforms. - Don't stop and join the timer thread when stopping the last timer (prevents unnecessary delay in this situation on some platforms). - Add `al_backup_dirty_bitmap` and `al_backup_dirty_bitmaps` to more finely control when bitmap context backup is performed. Android port: - Fix Android app issues when woken up during sleep. - Specify the Android toolchain file on the command line now. ANDROID_NDK_TOOLCHAIN_ROOT now has to be specified in an environment variable. OSX port: - Improve joystick enumeration (Todd Cope). - Make `al_set_new_window_title` work correctly. - Don't send duplicate mouse move events. - Fix mouse warping behavior. - Exit fullscreen mode if ALLEGRO_FULLSCREEN_WINDOW is set when destroying a display (otherwise if you destroy and recreate display without terminating the program, a white window kicks around). iOS port: - Make it compile again. - Don't backup textures as it is unnecessary. - Update minimum iOS to version to 6.1. - Disable the native png loader in favor of libpng, as it is broken on Apple's end. - Create library when creating the archive. Windows port: - Fix the D3D target bitmap bug. - Clear display to black right away to avoid an ugly white flash. Raspberry Pi port: - Fix system cursor support. Linux port: - Make `al_set_new_window_title` work correctly. Build system: - Use PROJECT_SOURCE_DIR and PROJECT_BINARY_DIR instead of CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR. This lets you use Allegro as a sub-project in your CMake project. - Fix GDIPlus finding in cmake-gui (Bruce Pascoe). - Add .gitignore and ignore build/ dir (Mark Oates). - Fix building examples with non-Allegro dependencies with the monolith build. Documentation: - Various documentation updates (Daniel Johnson and others). Other: - Add more `#include` statements in Allegro headers, so it's easier to use them in isolation (Jordan Woehr). - Allow marking tests as being hardware only. - Prefix some private Allegro macros and types to not pollute the namespace. - Make set_shader_uniform api const-correct (Bruce Pascoe). Audio addon: - Adjust loop end position when calling `al_set_sample_instance_length`. Acodec addon: - Allow file-backed audio streams to be restarted after they finish. - Add Opus codec support. Image addon: - Fail gracefully if not built with PNG/JPG loaders. Native dialog addon: Font addon: - Make `al_get_text_dimensions` and `al_get_glyph_dimensions` return exact bounding boxes (koro). - Add `ALLEGRO_GLYPH` structure and `al_get_glyph`, allowing for some additional optimization when drawing fonts. Examples: - Add more controls to `ex_audio_props`. - Add an example of using Enet with Allegro. Changes from 5.1.13.1 to 5.2.0 (April 2016) ============================================ The main developers this time were: SiegeLord, Polybios, Mark Oates, Elias Pschernig and Jonathan Seeley. Core: - Add `al_is_event_source_registered` (koro). - Make destructors log messages more meaningful. - Mouse emulation API for touch devices is now unstable. - Rename `al_convert_bitmaps` to `al_convert_memory_bitmaps`. Input: - Haptic API is now unstable. Android port: - Fixed bogus display destruction on Android which previously caused zombie states. OSX port: - Fix OSX mouse state position scaling. - Fix other various scaling issues. - Make toggling ALLEGRO_FRAMELESS work. - Fix an issue where fullscreen windows would occasionally leave empty space for the titlebar. - Fix incorrect debug assert in the audio addon. Windows port: - Make Allegro apps DPI-aware by default, which means that they won't be scaled by the OS. - Fix compilation for the CPU detection code on some compilers. - Don't sync the D3D bitmap when locking with WRITE_ONLY. - Remove dsound.dll runtime loading. - Don't link xinput and d3dx9 libraries (they are still required at runtime though if you're using the relevant features). - Fix a bug where al_wait_for_event_timed can block despite 0 timeout (Aldo Nunez). Build system: - Install PDB files when building with MSVC. Documentation: - Fix source links for API entries with multi-line prototypes. - Make the readme look prettier on GitHub. - Tons of assorted documentation improvements, especially for the audio addon. Other: - Add a stability system where some unstable APIs need to be opted into by defining `ALLEGRO_UNSTABLE` before including Allegro headers. Audio addon: - Fix sporadic deadlocks - Recorder API is now unstable. Native dialog addon: - `al_toggle_menu_item_flags` is now unstable. TTF addon: - Add an option to pre-cache the glyphs, useful for platforms where the current algorithm is buggy (typically some Android devices). Video addon: - Temporarily remove FFmpeg backend, as it was too buggy, didn't build and was too hard to fix. Examples: - Make `ex_vsync` less likely cause a seizure. - Make `ex_draw_bitmap` and `ex_touch_input` switch in/out on Android. - Add documentation to `ex_bitmap` (Daniel Johnson). - Improve `ex_logo` text entry experience. allegro5-5.2.10.1/docs/src/custom_header.html000066400000000000000000000001751473414355200207120ustar00rootroot00000000000000 allegro5-5.2.10.1/docs/src/pandoc.css000066400000000000000000000076051473414355200171650ustar00rootroot00000000000000/* We use this style sheet for HTML documents generated with Pandoc. */ body { background-color: #fcfcfc; padding-left: 0.1em; color: #222; font-family: sans-serif; } pre { border: 1px solid #ddd; background-color: #f3f3f8; padding: 0.6em; padding-left: 0.8em; -moz-border-radius: 5px; -webkit-border-radius: 5px; } blockquote { border: 1px solid #ddd; background-color: #fff8e0; padding: 0.6em; padding-left: 0.8em; -moz-border-radius: 5px; -webkit-border-radius: 5px; } blockquote p { padding: 0; margin: 0; } blockquote p em:first-child { font-style: normal; font-weight: bold; color: #400000; } code { font-family: monospace; } h1, h2, h3, h4, h5 { color: #348; margin-top: 2.5em; border-top: 1px solid #eee; padding-top: 0.8em; } h1 { font-size: 130%; } h2 { font-size: 110%; } h3 { font-size: 95%; } h4 { font-size: 90%; font-style: italic; } h5 { font-size: 90%; font-style: italic; } h1.title { font-size: 200%; font-weight: bold; margin-top: 0; padding-top: 0.2em; padding-bottom: 0.2em; text-align: left; border: none; } a { text-decoration: none; color: #348; } dl dt { font-weight: bold; } dt code { font-weight: bold; } dd p { margin-top: 0; } ul { padding-left: 1.5em; } table { background-color: #f8f8fa; border-top: 1px solid #e0e0e0; border-bottom: 1px solid #e0e0e0; } table th { font-weight: bold; border-bottom: 1px solid #e0e0e0; padding: 0.5em; } /* Side bar */ div.sidebar { background-color: #f0f0fa; border: solid 1px #e0e0ea; float: left; width: 150px; margin-right: 1em; line-height: 110%; -moz-border-radius: 5px; -webkit-border-radius: 5px; } div.sidebar ul { list-style-type: none; padding: 0; margin-left: 0.5em; font-size: small; } div.sidebar ul a:hover { background: #fffff0; } div.searchbox { margin-left: 5px; margin-right: 5px; margin-bottom: 0.8em; font-size: small; } /* font-size isn't inherited (at least not in Firefox and Chrome) */ input#q { font-size: small; width: 85%; } /* Body of page */ div.content { margin-left: 165px; max-width: 50em; line-height: 135%; } div#TOC { display: table; border: 1px solid #ddd; background-color: #f3f3fa; padding-right: 1em; -moz-border-radius: 5px; -webkit-border-radius: 5px; } div#TOC ul { padding-left: 1em; list-style-type: none; } p.timestamp { margin-top: 3em; border-top: solid 1px #eee; padding: 0.7em; padding-left: 0.3em; color: #999; text-align: left; } /* Below is the autosuggest.css from autosuggest.js version 2.4. */ .autosuggest-body { position: absolute; border: 1px solid black; z-index: 100; font-size: small; } .autosuggest-body iframe { display: block; position: absolute; z-index: 999; filter: alpha(opacity=0); } .autosuggest-body table { width: 100%; background-color: #f3f3fa; } .autosuggest-body tr { cursor: hand; cursor: pointer; color: black; text-align: left; } .autosuggest-body tr.up { height: 10px; background: #656291 url("arrow-up.gif") center center no-repeat; } .autosuggest-body tr.down { height: 10px; background: #656291 url("arrow-down.gif") center center no-repeat; } .autosuggest-body tr.up-disabled { height: 10px; background: #656291 url("arrow-up-d.gif") center center no-repeat; cursor: default; } .autosuggest-body tr.down-disabled { height: 10px; background: #656291 url("arrow-down-d.gif") center center no-repeat; cursor: default; } .autosuggest-body tr.selected { background-color: #D6D7E7; color: red; } .autosuggest-body td { white-space: nowrap; } .autosuggest-body span.match { font-weight: bold; } allegro5-5.2.10.1/docs/src/refman/000077500000000000000000000000001473414355200164475ustar00rootroot00000000000000allegro5-5.2.10.1/docs/src/refman/acodec.txt000066400000000000000000000024451473414355200204330ustar00rootroot00000000000000# Audio codecs addon These functions are declared in the following header file. Link with allegro_acodec. ~~~~c #include ~~~~ ## API: al_init_acodec_addon This function registers all the known audio file type handlers for [al_load_sample], [al_save_sample], [al_load_audio_stream], etc. Depending on what libraries are available, the full set of recognised extensions is: .wav, .flac, .ogg, .opus, .it, .mod, .s3m, .xm, .voc. *Limitations:* - Saving is only supported for wav files. - The wav file loader currently only supports 8/16 bit little endian PCM files. 16 bits are used when saving wav files. Use flac files if more precision is required. - Module files (.it, .mod, .s3m, .xm) are often composed with streaming in mind, and sometimes cannot be easily rendered into a finite length sample. Therefore they cannot be loaded with [al_load_sample]/[al_load_sample_f] and must be streamed with [al_load_audio_stream] or [al_load_audio_stream_f]. - .voc file streaming is unimplemented. Return true on success. ## API: al_is_acodec_addon_initialized Returns true if the acodec addon is initialized, otherwise returns false. Since: 5.2.6 ## API: al_get_allegro_acodec_version Returns the (compiled) version of the addon, in the same format as [al_get_allegro_version]. allegro5-5.2.10.1/docs/src/refman/allegro_version.tex.cmake000066400000000000000000000000221473414355200234340ustar00rootroot00000000000000@ALLEGRO_VERSION@ allegro5-5.2.10.1/docs/src/refman/audio.txt000066400000000000000000001710441473414355200203200ustar00rootroot00000000000000# Audio addon These functions are declared in the following header file. Link with allegro_audio. ~~~~c #include ~~~~ ## Basic Audio In order to just play some sounds (called samples in Allegro) and background music, here's how to quick start with Allegro's audio addon: Call [al_reserve_samples] with the number of samples you'd like to be able to play simultaneously (don't forget to call [al_install_audio] beforehand). If these succeed, you can now call [al_play_sample], with data obtained by [al_load_sample], for example (don't forget to [initialize the acodec addon][al_init_acodec_addon]). In order to stop samples, you can use the [ALLEGRO_SAMPLE_ID] that al_play_sample returns. If you want to play large audio files (e.g. background music) without loading the whole file at once you can use [al_play_audio_stream] (after calling [al_reserve_samples]). This will load and play an `ALLEGRO_AUDIO_STREAM`. Note that the basic API only supports one such audio stream playing at once. ### API: ALLEGRO_SAMPLE_ID An ALLEGRO_SAMPLE_ID represents a sample being played via [al_play_sample]. It can be used to later stop the sample with [al_stop_sample]. The underlying ALLEGRO_SAMPLE_INSTANCE can be extracted using [al_lock_sample_id]. ### API: al_install_audio Install the audio subsystem. Returns true on success, false on failure. > Note: most users will call [al_reserve_samples] and [al_init_acodec_addon] after this. See also: [al_reserve_samples], [al_uninstall_audio], [al_is_audio_installed], [al_init_acodec_addon] ### API: al_uninstall_audio Uninstalls the audio subsystem. See also: [al_install_audio] ### API: al_is_audio_installed Returns true if [al_install_audio] was called previously and returned successfully. ### API: al_reserve_samples Reserves a number of sample instances, attaching them to the default mixer. If no default mixer is set when this function is called, then it will create one and attach it to the default voice. If no default voice has been set, it, too, will be created. If you call this function a second time with a smaller number of samples, then the excess internal sample instances will be destroyed causing some sounds to stop and some instances returned by [al_lock_sample_id] to be invalidated. This diagram illustrates the structures that are set up: sample instance 1 / sample instance 2 default voice <-- default mixer <--- . \ . sample instance N Returns true on success, false on error. [al_install_audio] must have been called first. See also: [al_set_default_mixer], [al_play_sample] ### API: al_play_sample Plays a sample on one of the sample instances created by [al_reserve_samples]. Returns true on success, false on failure. Playback may fail because all the reserved sample instances are currently used. Parameters: * gain - relative volume at which the sample is played; 1.0 is normal. * pan - 0.0 is centred, -1.0 is left, 1.0 is right, or ALLEGRO_AUDIO_PAN_NONE. * speed - relative speed at which the sample is played; 1.0 is normal. * loop - ALLEGRO_PLAYMODE_ONCE, ALLEGRO_PLAYMODE_LOOP, or ALLEGRO_PLAYMODE_BIDIR * ret_id - if non-NULL the variable which this points to will be assigned an id representing the sample being played. If [al_play_sample] returns `false`, then the contents of ret_id are invalid and must not be used as argument to other functions. See also: [al_load_sample], [ALLEGRO_PLAYMODE], [ALLEGRO_AUDIO_PAN_NONE], [ALLEGRO_SAMPLE_ID], [al_stop_sample], [al_stop_samples], [al_lock_sample_id]. ### API: al_stop_sample Stop the sample started by [al_play_sample]. See also: [al_stop_samples] ### API: al_stop_samples Stop all samples started by [al_play_sample]. See also: [al_stop_sample] ### API: al_lock_sample_id Locks a [ALLEGRO_SAMPLE_ID], returning the underlying [ALLEGRO_SAMPLE_INSTANCE]. This allows you to adjust the various properties of the instance (such as volume, pan, etc) while the sound is playing. This function will return `NULL` if the sound corresponding to the id is no longer playing. While locked, `ALLEGRO_SAMPLE_ID` will be unavailable to additional calls to [al_play_sample], even if the sound stops while locked. To put the `ALLEGRO_SAMPLE_ID` back into the pool for reuse, make sure to call `al_unlock_sample_id` when you're done with the instance. See also: [al_play_sample], [al_unlock_sample_id] Since: 5.2.3 > *[Unstable API]:* New API. ### API: al_unlock_sample_id Unlocks a [ALLEGRO_SAMPLE_ID], allowing future calls to [al_play_sample] to reuse it if possible. Note that after the id is unlocked, the [ALLEGRO_SAMPLE_INSTANCE] that was previously returned by [al_lock_sample_id] will possibly be playing a different sound, so you should only use it after locking the id again. See also: [al_play_sample], [al_lock_sample_id] Since: 5.2.3 > *[Unstable API]:* New API. ### API: al_play_audio_stream Loads and plays an audio file, streaming from disk as it is needed. This API can only play one audio stream at a time. This requires a default mixer to be set, which is typically done via [al_reserve_samples], but can also be done via [al_set_default_mixer]. Returns the stream on success, NULL on failure. You must not destroy the returned stream, it will be automatically destroyed when the addon is shut down. > *Note:* the allegro_audio library does not support any audio file formats by default. You must use the allegro_acodec addon, or register your own format handler. See also: [al_play_audio_stream_f], [al_load_audio_stream] Since: 5.2.8 > *[Unstable API]:* New API. ### API: al_play_audio_stream_f Loads and plays an audio file from [ALLEGRO_FILE] stream, streaming it is needed. This API can only play one audio stream at a time. This requires a default mixer to be set, which is typically done via [al_reserve_samples], but can also be done via [al_set_default_mixer]. The file type is determined by the passed 'ident' parameter, which is a file name extension including the leading dot. Returns the stream on success, NULL on failure. You must not destroy the returned stream, it will be automatically destroyed when the addon is shut down. On success the file should be considered owned by the audio stream, and will be closed when the audio stream is destroyed. On failure the file will be closed. > *Note:* the allegro_audio library does not support any audio file formats by default. You must use the allegro_acodec addon, or register your own format handler. See also: [al_play_audio_stream], [al_load_audio_stream_f] Since: 5.2.8 > *[Unstable API]:* New API. ## Samples ### API: ALLEGRO_SAMPLE An ALLEGRO_SAMPLE object stores the data necessary for playing pre-defined digital audio. It holds a user-specified PCM data buffer and information about its format (data length, depth, frequency, channel configuration). You can have the same ALLEGRO_SAMPLE playing multiple times simultaneously. See also: [ALLEGRO_SAMPLE_INSTANCE] ### API: al_create_sample Create a sample data structure from the supplied buffer. If `free_buf` is true then the buffer will be freed with [al_free] when the sample data structure is destroyed. For portability (especially Windows), the buffer should have been allocated with [al_malloc]. Otherwise you should free the sample data yourself. A sample that is referred to by the `samples` parameter refers to a sequence channel intensities. E.g. if you're making a stereo sample with the `samples` set to 4, then the layout of the data in `buf` will be: ~~~~ LRLRLRLR ~~~~ Where L and R are the intensities for the left and right channels respectively. A single sample, then, refers to the LR pair in this example. To allocate a buffer of the correct size, you can use something like this: ~~~~c int sample_size = al_get_channel_count(chan_conf) * al_get_audio_depth_size(depth); int bytes = samples * sample_size; void *buffer = al_malloc(bytes); ~~~~ See also: [al_destroy_sample], [ALLEGRO_AUDIO_DEPTH], [ALLEGRO_CHANNEL_CONF] ### API: al_load_sample Loads a few different audio file formats based on their extension. Note that this stores the entire file in memory at once, which may be time consuming. To read the file as it is needed, use [al_load_audio_stream] or [al_play_audio_stream]. Returns the sample on success, NULL on failure. > *Note:* the allegro_audio library does not support any audio file formats by default. You must use the allegro_acodec addon, or register your own format handler. See also: [al_register_sample_loader], [al_init_acodec_addon] ### API: al_load_sample_f Loads an audio file from an [ALLEGRO_FILE] stream into an [ALLEGRO_SAMPLE]. The file type is determined by the passed 'ident' parameter, which is a file name extension including the leading dot. Note that this stores the entire file in memory at once, which may be time consuming. To read the file as it is needed, use [al_load_audio_stream_f] or [al_play_audio_stream_f]. Returns the sample on success, NULL on failure. The file remains open afterwards. > *Note:* the allegro_audio library does not support any audio file formats by default. You must use the allegro_acodec addon, or register your own format handler. See also: [al_register_sample_loader_f], [al_init_acodec_addon] ### API: al_save_sample Writes a sample into a file. Currently, wav is the only supported format, and the extension must be ".wav". Returns true on success, false on error. > *Note:* the allegro_audio library does not support any audio file formats by default. You must use the allegro_acodec addon, or register your own format handler. See also: [al_save_sample_f], [al_register_sample_saver], [al_init_acodec_addon] ### API: al_save_sample_f Writes a sample into a [ALLEGRO_FILE] filestream. Currently, wav is the only supported format, and the extension must be ".wav". Returns true on success, false on error. The file remains open afterwards. > *Note:* the allegro_audio library does not support any audio file formats by default. You must use the allegro_acodec addon, or register your own format handler. See also: [al_save_sample], [al_register_sample_saver_f], [al_init_acodec_addon] ### API: al_destroy_sample Free the sample data structure. If it was created with the `free_buf` parameter set to true, then the buffer will be freed with [al_free]. This function will stop any sample instances which may be playing the buffer referenced by the [ALLEGRO_SAMPLE]. See also: [al_destroy_sample_instance], [al_stop_sample], [al_stop_samples] ### API: al_get_sample_channels Return the channel configuration of the sample. See also: [ALLEGRO_CHANNEL_CONF], [al_get_sample_depth], [al_get_sample_frequency], [al_get_sample_length], [al_get_sample_data] ### API: al_get_sample_depth Return the audio depth of the sample. See also: [ALLEGRO_AUDIO_DEPTH], [al_get_sample_channels], [al_get_sample_frequency], [al_get_sample_length], [al_get_sample_data] ### API: al_get_sample_frequency Return the frequency (in Hz) of the sample. See also: [al_get_sample_channels], [al_get_sample_depth], [al_get_sample_length], [al_get_sample_data] ### API: al_get_sample_length Return the length of the sample in sample values. See also: [al_get_sample_channels], [al_get_sample_depth], [al_get_sample_frequency], [al_get_sample_data] ### API: al_get_sample_data Return a pointer to the raw sample data. See also: [al_get_sample_channels], [al_get_sample_depth], [al_get_sample_frequency], [al_get_sample_length] ## Advanced Audio For more fine-grained control over audio output, here's a short description of the basic concepts: Voices represent audio devices on the system. Basically, every audio output chain that you want to be heard needs to end up in a voice. As voices are on the hardware/driver side of things, there is only limited control over their parameters (frequency, sample format, channel configuration). The number of available voices is limited as well. Typically, you will only use one voice and attach a mixer to it. Calling [al_reserve_samples] will do this for you by setting up a default voice and mixer; it can also be achieved by calling [al_restore_default_mixer]. Although you *can* attach sample instances and audio streams directly to a voice without using a mixer, it is, as of now, not recommended. In contrast to mixers, you can only attach a single object to a voice anyway. Mixers mix several sample instances and/or audio streams into a single output buffer, converting sample data with differing formats according to their output parameters (frequency, depth, channels) in the process. In order to play several samples/streams at once reliably, you will need at least one mixer. A mixer that is not (indirectly) attached to a voice will remain silent. For most use cases, one (default) mixer attached to a single voice will be sufficient. You may attach mixers to other mixers in order to create complex audio chains. Samples ([ALLEGRO_SAMPLE]) just represent "passive" buffers for sample data in memory. In order to play a sample, a sample instance ([ALLEGRO_SAMPLE_INSTANCE]) needs to be created and attached to a mixer (or voice). Sample instances control *how* the underlying samples are played. Several playback parameters (position, speed, gain, pan, playmode, playing/paused) can be adjusted. Particularly, multiple instances may be created from the same sample, e.g. with different parameters. Audio streams ([ALLEGRO_AUDIO_STREAM]) are similar to sample instances insofar as they respond to the same playback parameters and have to be attached to mixers or voices. A single audio stream can only be played once simultaneously. For example, consider the following configuration of the audio system. ~~~~c ALLEGRO_VOICE* voice = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); ALLEGRO_MIXER* mixer_1 = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); ALLEGRO_MIXER* mixer_2 = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); /* Load a stream, the stream starts in a playing state and just needs * to be attached to actually output sound. */ ALLEGRO_AUDIO_STREAM* stream = al_load_audio_stream("music.ogg", 4, 2048); /* The sample needs sample instances to output sound. */ ALLEGRO_SAMPLE* sample = al_load_sample("sound.wav") ALLEGRO_SAMPLE_INSTANCE* instance_1 = al_create_sample_instance(sample); ALLEGRO_SAMPLE_INSTANCE* instance_2 = al_create_sample_instance(sample); /* Attach everything up (see diagram). */ al_attach_mixer_to_voice(mixer_1, voice); al_attach_mixer_to_mixer(mixer_2, mixer_1); al_attach_audio_stream_to_mixer(stream, mixer_1); al_attach_sample_instance_to_mixer(instance_1, mixer_2); al_attach_sample_instance_to_mixer(instance_2, mixer_2); /* Play two copies of the sound simultaneously. */ al_set_sample_instance_playing(instance_1, true); al_set_sample_instance_playing(instance_2, true); ~~~~ ![*An example configuration of the audio system to play music and a sound.*](images/audio.png) Since we have two mixers, with the sample instances connected to a different mixer than the audio stream, you can control the volume of all the instances independently from the music by setting the gain of the mixer / stream. Having two sample instances lets you play two copies of the sample simultaneously. With this in mind, another look at [al_reserve_samples] and [al_play_sample] is due: What the former does internally is to create a specified number of sample instances that are "empty" at first, i.e. with no sample data set. When al_play_sample is called, it'll use one of these internal sample instances that is not currently playing to play the requested sample. All of these sample instances will be attached to the default mixer, which can be changed via [al_set_default_mixer]. ## Sample instances ### API: ALLEGRO_SAMPLE_INSTANCE An ALLEGRO_SAMPLE_INSTANCE object represents a playable instance of a predefined sound effect. It holds information about how the effect should be played: These playback parameters consist of the looping mode, loop start/end points, playing position, speed, gain, pan and the playmode. Whether a sample instance is currently playing or paused is also one of its properties. An instance uses the data from an [ALLEGRO_SAMPLE] object. Multiple instances may be created from the same ALLEGRO_SAMPLE. An ALLEGRO_SAMPLE must not be destroyed while there are instances which reference it. To actually produce audio output, an ALLEGRO_SAMPLE_INSTANCE must be attached to an [ALLEGRO_MIXER] which eventually reaches an [ALLEGRO_VOICE] object. See also: [ALLEGRO_SAMPLE] ### API: al_create_sample_instance Creates a sample instance, using the supplied sample data. The instance must be attached to a mixer (or voice) in order to actually produce output. The argument may be NULL. You can then set the sample data later with [al_set_sample]. See also: [al_destroy_sample_instance] ### API: al_destroy_sample_instance Detaches the sample instance from anything it may be attached to and frees it (the sample data, i.e. its ALLEGRO_SAMPLE, is *not* freed!). See also: [al_create_sample_instance] ### API: al_play_sample_instance Play the sample instance. Returns true on success, false on failure. See also: [al_stop_sample_instance] ### API: al_stop_sample_instance Stop an sample instance playing. See also: [al_play_sample_instance] ### API: al_get_sample_instance_channels Return the channel configuration of the sample instance's sample data. See also: [ALLEGRO_CHANNEL_CONF]. ### API: al_get_sample_instance_depth Return the audio depth of the sample instance's sample data. See also: [ALLEGRO_AUDIO_DEPTH]. ### API: al_get_sample_instance_frequency Return the frequency (in Hz) of the sample instance's sample data. ### API: al_get_sample_instance_length Return the length of the sample instance in sample values. This property may differ from the length of the instance's sample data. See also: [al_set_sample_instance_length], [al_get_sample_instance_time] ### API: al_set_sample_instance_length Set the length of the sample instance in sample values. This can be used to play only parts of the underlying sample. Be careful not to exceed the actual length of the sample data, though. Return true on success, false on failure. Will fail if the sample instance is currently playing. See also: [al_get_sample_instance_length] ### API: al_get_sample_instance_position Get the playback position of a sample instance. See also: [al_set_sample_instance_position] ### API: al_set_sample_instance_position Set the playback position of a sample instance. Returns true on success, false on failure. See also: [al_get_sample_instance_position] ### API: al_get_sample_instance_speed Return the relative playback speed of the sample instance. See also: [al_set_sample_instance_speed] ### API: al_set_sample_instance_speed Set the relative playback speed of the sample instance. 1.0 means normal speed. Return true on success, false on failure. Will fail if the sample instance is attached directly to a voice. See also: [al_get_sample_instance_speed] ### API: al_get_sample_instance_gain Return the playback gain of the sample instance. See also: [al_set_sample_instance_gain] ### API: al_set_sample_instance_gain Set the playback gain of the sample instance. Returns true on success, false on failure. Will fail if the sample instance is attached directly to a voice. See also: [al_get_sample_instance_gain] ### API: al_get_sample_instance_pan Get the pan value of the sample instance. See also: [al_set_sample_instance_pan]. ### API: al_set_sample_instance_pan Set the pan value on a sample instance. A value of -1.0 means to play the sample only through the left speaker; +1.0 means only through the right speaker; 0.0 means the sample is centre balanced. A special value [ALLEGRO_AUDIO_PAN_NONE] disables panning and plays the sample at its original level. This will be louder than a pan value of 0.0. > Note: panning samples with more than two channels doesn't work yet. Returns true on success, false on failure. Will fail if the sample instance is attached directly to a voice. See also: [al_get_sample_instance_pan], [ALLEGRO_AUDIO_PAN_NONE] ### API: al_get_sample_instance_time Return the length of the sample instance in seconds, assuming a playback speed of 1.0. See also: [al_get_sample_instance_length] ### API: al_get_sample_instance_playmode Return the playback mode of the sample instance. See also: [ALLEGRO_PLAYMODE], [al_set_sample_instance_playmode] ### API: al_set_sample_instance_playmode Set the playback mode of the sample instance. Returns true on success, false on failure. See also: [ALLEGRO_PLAYMODE], [al_get_sample_instance_playmode] ### API: al_get_sample_instance_playing Return true if the sample instance is in the playing state. This may be true even if the instance is not attached to anything. See also: [al_set_sample_instance_playing] ### API: al_set_sample_instance_playing Change whether the sample instance is playing. The instance does not need to be attached to anything (since: 5.1.8). Returns true on success, false on failure. See also: [al_get_sample_instance_playing] ### API: al_get_sample_instance_attached Return whether the sample instance is attached to something. See also: [al_attach_sample_instance_to_mixer], [al_attach_sample_instance_to_voice], [al_detach_sample_instance] ### API: al_detach_sample_instance Detach the sample instance from whatever it's attached to, if anything. Returns true on success. See also: [al_attach_sample_instance_to_mixer], [al_attach_sample_instance_to_voice], [al_get_sample_instance_attached] ### API: al_get_sample Return the sample data that the sample instance plays. Note this returns a pointer to an internal structure, *not* the [ALLEGRO_SAMPLE] that you may have passed to [al_set_sample]. However, the sample buffer of the returned ALLEGRO_SAMPLE will be the same as the one that was used to create the sample (passed to [al_create_sample]). You can use [al_get_sample_data] on the return value to retrieve and compare it. See also: [al_set_sample] ### API: al_set_sample Change the sample data that a sample instance plays. This can be quite an involved process. First, the sample is stopped if it is not already. Next, if data is NULL, the sample is detached from its parent (if any). If data is not NULL, the sample may be detached and reattached to its parent (if any). This is not necessary if the old sample data and new sample data have the same frequency, depth and channel configuration. Reattaching may not always succeed. On success, the sample remains stopped. The playback position and loop end points are reset to their default values. The loop mode remains unchanged. Returns true on success, false on failure. On failure, the sample will be stopped and detached from its parent. See also: [al_get_sample] ### API: al_set_sample_instance_channel_matrix Set the matrix used to mix the channels coming from this instance into the mixer it is attached to. Normally Allegro derives the values of this matrix from the gain and pan settings, as well as the channel configurations of this instance and the mixer it is attached to, but this allows you override that default value. Note that if you do set gain or pan of this instance or the mixer it is attached to, you'll need to call this function again. The matrix has mixer channel rows and sample channel columns, and is row major. For example, if you have a stereo sample instance and want to mix it to a 5.1 mixer you could use this code: ~~~~c float matrix[] = { 0.5, 0.0, /* Half left to front left */ 0.0, 0.5, /* Half right to front right */ 0.5, 0.0, /* Half left to rear left */ 0.0, 0.5, /* Half right to rear right */ 0.1, 0.1, /* Mix left and right for center */ 0.1, 0.1, /* Mix left and right for center */ }; al_set_sample_instance_channel_matrix(instance, matrix); ~~~~ Returns true on success, false on failure (e.g. if this is not attached to a mixer). Since: 5.2.3 > *[Unstable API]:* New API. ## Audio streams ### API: ALLEGRO_AUDIO_STREAM An ALLEGRO_AUDIO_STREAM object is used to stream generated audio to the sound device, in real-time. This is done by reading from a buffer, which is split into a number of fragments. Whenever a fragment has finished playing, the user can refill it with new data. As with [ALLEGRO_SAMPLE_INSTANCE] objects, streams store information necessary for playback, so you may not play the same stream multiple times simultaneously. Streams also need to be attached to an [ALLEGRO_MIXER], which, eventually, reaches an [ALLEGRO_VOICE] object. While playing, you must periodically fill fragments with new audio data. To know when a new fragment is ready to be filled, you can either directly check with [al_get_available_audio_stream_fragments], or listen to events from the stream. You can register an audio stream event source to an event queue; see [al_get_audio_stream_event_source]. An [ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT] event is generated whenever a new fragment is ready. When you receive an event, use [al_get_audio_stream_fragment] to obtain a pointer to the fragment to be filled. The size and format are determined by the parameters passed to [al_create_audio_stream]. If you're late with supplying new data, the stream will be silent until new data is provided. You must call [al_drain_audio_stream] when you're finished with supplying data to the stream. It is often a good idea to prefill the audio stream with data before [ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT] events arrive. Here is a snippet that will fill the stream buffers with silence: ~~~~c ALLEGRO_AUDIO_STREAM *stream = al_create_audio_stream(num_buffers, samples_per_buffer, freq, depth, channel_conf); void *buf; while ((buf = al_get_audio_stream_fragment(stream))) { al_fill_silence(buf, samples_per_buffer, depth, channel_conf); al_set_audio_stream_fragment(stream, buf); } ~~~~ If the stream is created by [al_load_audio_stream] or [al_play_audio_stream] then it will also generate an [ALLEGRO_EVENT_AUDIO_STREAM_FINISHED] event if it reaches the end of the file and is not set to loop. ### API: al_create_audio_stream Creates an [ALLEGRO_AUDIO_STREAM]. The stream will be set to play by default. It will feed audio data from a buffer, which is split into a number of fragments. Parameters: * fragment_count - How many fragments to use for the audio stream. Usually only two fragments are required - splitting the audio buffer in two halves. But it means that the only time when new data can be supplied is whenever one half has finished playing. When using many fragments, you usually will use fewer samples for one, so there always will be (small) fragments available to be filled with new data. * frag_samples - The size of a fragment in samples. See note and explanation below. * freq - The frequency, in Hertz. * depth - Must be one of the values listed for [ALLEGRO_AUDIO_DEPTH]. * chan_conf - Must be one of the values listed for [ALLEGRO_CHANNEL_CONF]. A sample that is referred to by the *frag_samples* parameter refers to a sequence channel intensities. E.g. if you're making a stereo stream with the *frag_samples* set to 4, then the layout of the data in the fragment will be: ~~~~ LRLRLRLR ~~~~ Where L and R are the intensities for the left and right channels respectively. A single sample, then, refers to the LR pair in this example. The choice of *fragment_count*, *frag_samples* and *freq* directly influences the audio delay. The delay in seconds can be expressed as: delay = fragment_count * frag_samples / freq This is only the delay due to Allegro's streaming, there may be additional delay caused by sound drivers and/or hardware. > *Note:* If you know the fragment size in bytes, you can get the size in samples > like this: > > sample_size = al_get_channel_count(chan_conf) * al_get_audio_depth_size(depth); > samples = bytes_per_fragment / sample_size; > > The size of the complete buffer is: > > buffer_size = bytes_per_fragment * fragment_count > *Note:* Unlike many Allegro objects, audio streams are not implicitly destroyed when Allegro is shut down. You must destroy them manually with [al_destroy_audio_stream] before the audio system is shut down. ### API: al_load_audio_stream Loads an audio file from disk as it is needed. Unlike regular streams, the one returned by this function need not be fed by the user; the library will automatically read more of the file as it is needed. The stream will contain *buffer_count* buffers with *samples* samples. The audio stream will start in the playing state. It should be attached to a voice or mixer to generate any output. See [ALLEGRO_AUDIO_STREAM] for more details. Returns the stream on success, NULL on failure. > *Note:* the allegro_audio library does not support any audio file formats by default. You must use the allegro_acodec addon, or register your own format handler. See also: [al_load_audio_stream_f], [al_register_audio_stream_loader], [al_init_acodec_addon] ### API: al_load_audio_stream_f Loads an audio file from [ALLEGRO_FILE] stream as it is needed. Unlike regular streams, the one returned by this function need not be fed by the user; the library will automatically read more of the file as it is needed. The stream will contain *buffer_count* buffers with *samples* samples. The file type is determined by the passed 'ident' parameter, which is a file name extension including the leading dot. The audio stream will start in the playing state. It should be attached to a voice or mixer to generate any output. See [ALLEGRO_AUDIO_STREAM] for more details. Returns the stream on success, NULL on failure. On success the file should be considered owned by the audio stream, and will be closed when the audio stream is destroyed. On failure the file will be closed. > *Note:* the allegro_audio library does not support any audio file formats by default. You must use the allegro_acodec addon, or register your own format handler. See also: [al_load_audio_stream], [al_register_audio_stream_loader_f], [al_init_acodec_addon] ### API: al_destroy_audio_stream Destroy an audio stream which was created with [al_create_audio_stream] or [al_load_audio_stream]. > *Note:* If the stream is still attached to a mixer or voice, [al_detach_audio_stream] is automatically called on it first. See also: [al_drain_audio_stream]. ### API: al_get_audio_stream_event_source Retrieve the associated event source. See [al_get_audio_stream_fragment] for a description of the [ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT] event that audio streams emit. ### API: al_drain_audio_stream You should call this to finalise an audio stream that you will no longer be feeding, to wait for all pending buffers to finish playing. The stream's playing state will change to false. See also: [al_destroy_audio_stream] ### API: al_rewind_audio_stream Set the streaming file playing position to the beginning. Returns true on success. Currently this can only be called on streams created with [al_load_audio_stream], [al_play_audio_stream], [al_load_audio_stream_f] or [al_play_audio_stream_f]. ### API: al_get_audio_stream_frequency Return the stream frequency (in Hz). ### API: al_get_audio_stream_channels Return the stream channel configuration. See also: [ALLEGRO_CHANNEL_CONF]. ### API: al_get_audio_stream_depth Return the stream audio depth. See also: [ALLEGRO_AUDIO_DEPTH]. ### API: al_get_audio_stream_length Return the stream length in samples. ### API: al_get_audio_stream_speed Return the relative playback speed of the stream. See also: [al_set_audio_stream_speed]. ### API: al_set_audio_stream_speed Set the relative playback speed of the stream. 1.0 means normal speed. Return true on success, false on failure. Will fail if the audio stream is attached directly to a voice. See also: [al_get_audio_stream_speed]. ### API: al_get_audio_stream_gain Return the playback gain of the stream. See also: [al_set_audio_stream_gain]. ### API: al_set_audio_stream_gain Set the playback gain of the stream. Returns true on success, false on failure. Will fail if the audio stream is attached directly to a voice. See also: [al_get_audio_stream_gain]. ### API: al_get_audio_stream_pan Get the pan value of the stream. See also: [al_set_audio_stream_pan]. ### API: al_set_audio_stream_pan Set the pan value on an audio stream. A value of -1.0 means to play the stream only through the left speaker; +1.0 means only through the right speaker; 0.0 means the sample is centre balanced. A special value [ALLEGRO_AUDIO_PAN_NONE] disables panning and plays the stream at its original level. This will be louder than a pan value of 0.0. Returns true on success, false on failure. Will fail if the audio stream is attached directly to a voice. See also: [al_get_audio_stream_pan], [ALLEGRO_AUDIO_PAN_NONE] ### API: al_get_audio_stream_playing Return true if the stream is playing. See also: [al_set_audio_stream_playing]. ### API: al_set_audio_stream_playing Change whether the stream is playing. Returns true on success, false on failure. See also: [al_get_audio_stream_playing] ### API: al_get_audio_stream_playmode Return the playback mode of the stream. See also: [ALLEGRO_PLAYMODE], [al_set_audio_stream_playmode]. ### API: al_set_audio_stream_playmode Set the playback mode of the stream. Returns true on success, false on failure. See also: [ALLEGRO_PLAYMODE], [al_get_audio_stream_playmode]. ### API: al_get_audio_stream_attached Return whether the stream is attached to something. See also: [al_attach_audio_stream_to_mixer], [al_attach_audio_stream_to_voice], [al_detach_audio_stream]. ### API: al_detach_audio_stream Detach the stream from whatever it's attached to, if anything. See also: [al_attach_audio_stream_to_mixer], [al_attach_audio_stream_to_voice], [al_get_audio_stream_attached]. ### API: al_get_audio_stream_played_samples Get the number of samples consumed by the parent since the audio stream was started. Since: 5.1.8 ### API: al_get_audio_stream_fragment When using Allegro's audio streaming, you will use this function to continuously provide new sample data to a stream. If the stream is ready for new data, the function will return the address of an internal buffer to be filled with audio data. The length and format of the buffer are specified with [al_create_audio_stream] or can be queried with the various functions described here. Once the buffer is filled, you must signal this to Allegro by passing the buffer to [al_set_audio_stream_fragment]. If the stream is not ready for new data, the function will return NULL. > *Note:* If you listen to events from the stream, an [ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT] event will be generated whenever a new fragment is ready. However, getting an event is *not* a guarantee that [al_get_audio_stream_fragment] will not return NULL, so you still must check for it. See also: [al_set_audio_stream_fragment], [al_get_audio_stream_event_source], [al_get_audio_stream_frequency], [al_get_audio_stream_channels], [al_get_audio_stream_depth], [al_get_audio_stream_length] ### API: al_set_audio_stream_fragment This function needs to be called for every successful call of [al_get_audio_stream_fragment] to indicate that the buffer (pointed to by `val`) is filled with new data. See also: [al_get_audio_stream_fragment] ### API: al_get_audio_stream_fragments Returns the number of fragments this stream uses. This is the same value as passed to [al_create_audio_stream] when a new stream is created. See also: [al_get_available_audio_stream_fragments] ### API: al_get_available_audio_stream_fragments Returns the number of available fragments in the stream, that is, fragments which are not currently filled with data for playback. See also: [al_get_audio_stream_fragment], [al_get_audio_stream_fragments] ### API: al_seek_audio_stream_secs Set the streaming file playing position to time. Returns true on success. Currently this can only be called on streams created with [al_load_audio_stream], [al_play_audio_stream], [al_load_audio_stream_f] or [al_play_audio_stream_f]. See also: [al_get_audio_stream_position_secs], [al_get_audio_stream_length_secs] ### API: al_get_audio_stream_position_secs Return the position of the stream in seconds. Currently this can only be called on streams created with [al_load_audio_stream], [al_play_audio_stream], [al_load_audio_stream_f] or [al_play_audio_stream_f]. See also: [al_get_audio_stream_length_secs] ### API: al_get_audio_stream_length_secs Return the length of the stream in seconds, if known. Otherwise returns zero. Currently this can only be called on streams created with [al_load_audio_stream], [al_play_audio_stream], [al_load_audio_stream_f] or [al_play_audio_stream_f]. See also: [al_get_audio_stream_position_secs] ### API: al_set_audio_stream_loop_secs Sets the loop points for the stream in seconds. Currently this can only be called on streams created with [al_load_audio_stream], [al_play_audio_stream], [al_load_audio_stream_f] or [al_play_audio_stream_f]. ### API: al_set_audio_stream_channel_matrix Like [al_set_sample_instance_channel_matrix] but for streams. Since: 5.2.3 > *[Unstable API]:* New API. ## Advanced audio file I/O ### API: al_register_sample_loader Register a handler for [al_load_sample]. The given function will be used to handle the loading of sample files with the given extension. The extension should include the leading dot ('.') character. It will be matched case-insensitively. The `loader` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. See also: [al_register_sample_loader_f], [al_register_sample_saver] ### API: al_register_sample_loader_f Register a handler for [al_load_sample_f]. The given function will be used to handle the loading of sample files with the given extension. The extension should include the leading dot ('.') character. It will be matched case-insensitively. The `loader` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. See also: [al_register_sample_loader] ### API: al_register_sample_saver Register a handler for [al_save_sample]. The given function will be used to handle the saving of sample files with the given extension. The extension should include the leading dot ('.') character. It will be matched case-insensitively. The `saver` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. See also: [al_register_sample_saver_f], [al_register_sample_loader] ### API: al_register_sample_saver_f Register a handler for [al_save_sample_f]. The given function will be used to handle the saving of sample files with the given extension. The extension should include the leading dot ('.') character. It will be matched case-insensitively. The `saver` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. See also: [al_register_sample_saver] ### API: al_register_audio_stream_loader Register a handler for [al_load_audio_stream] and [al_play_audio_stream]. The given function will be used to open streams from files with the given extension. The extension should include the leading dot ('.') character. It will be matched case-insensitively. The `stream_loader` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. See also: [al_register_audio_stream_loader_f] ### API: al_register_audio_stream_loader_f Register a handler for [al_load_audio_stream_f] and [al_play_audio_stream_f]. The given function will be used to open streams from files with the given extension. The extension should include the leading dot ('.') character. It will be matched case-insensitively. The `stream_loader` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. See also: [al_register_audio_stream_loader] ### API: al_register_sample_identifier Register an identify handler for [al_identify_sample]. The given function will be used to detect files for the given extension. It will be called with a single argument of type [ALLEGRO_FILE] which is a file handle opened for reading and located at the first byte of the file. The handler should try to read as few bytes as possible to safely determine if the given file contents correspond to the type with the extension and return true in that case, false otherwise. The file handle must not be closed but there is no need to reset it to the beginning. The extension should include the leading dot ('.') character. It will be matched case-insensitively. The `identifier` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. Since: 5.2.8 See also: [al_identify_bitmap] ### API: al_identify_sample This works exactly as [al_identify_sample_f] but you specify the filename of the file for which to detect the type and not a file handle. The extension, if any, of the passed filename is not taken into account - only the file contents. Since: 5.2.8 See also: [al_init_acodec_addon], [al_identify_sample_f], [al_register_sample_identifier] ### API: al_identify_sample_f Tries to guess the audio file type of the open ALLEGRO_FILE by reading the first few bytes. By default Allegro cannot recognize any file types, but calling [al_init_acodec_addon] will add detection of the types it can read. You can also use [al_register_sample_identifier] to add identification for custom file types. Returns a pointer to a static string with a file extension for the type, including the leading dot. For example ".wav" or ".ogg". Returns NULL if the audio type cannot be determined. Since: 5.2.8 See also: [al_init_acodec_addon], [al_identify_sample], [al_register_sample_identifier] ## Audio recording Allegro's audio recording routines give you real-time access to raw, uncompressed audio input streams. Since Allegro hides all of the platform specific implementation details with its own buffering, it will add a small amount of latency. However, for most applications that small overhead will not adversely affect performance. Recording is supported by the ALSA, AudioQueue, DirectSound8, and PulseAudio drivers. Enumerating or choosing other recording devices is not yet supported. ### API: ALLEGRO_AUDIO_RECORDER An opaque datatype that represents a recording device. Since: 5.1.1 > *[Unstable API]:* The API may need a slight redesign. ### API: ALLEGRO_AUDIO_RECORDER_EVENT Structure that holds the audio recorder event data. Every event type will contain: * .source: pointer to the audio recorder The following will be available depending on the event type: * .buffer: pointer to buffer containing the audio samples * .samples: number of samples (not bytes) that are available Since 5.1.1 See also: [al_get_audio_recorder_event] > *[Unstable API]:* The API may need a slight redesign. ### API: al_create_audio_recorder Creates an audio recorder using the system's default recording device. (So if the returned device does not work, try updating the system's default recording device.) Allegro will internally buffer several seconds of captured audio with minimal latency. (XXX: These settings need to be exposed via config or API calls.) Audio will be copied out of that private buffer into a fragment buffer of the size specified by the samples parameter. Whenever a new fragment is ready an event will be generated. The total size of the fragment buffer is fragment_count * samples * bytes_per_sample. It is treated as a circular, never ending buffer. If you do not process the information fast enough, it will be overrun. Because of that, even if you only ever need to process one small fragment at a time, you should still use a large enough value for fragment_count to hold a few seconds of audio. frequency is the number of samples per second to record. Common values are: * 8000 - telephone quality speech * 11025 * 22050 * 44100 - CD quality music (if 16-bit, stereo) For maximum compatibility, use a depth of ALLEGRO_AUDIO_DEPTH_UINT8 or ALLEGRO_AUDIO_DEPTH_INT16, and a single (mono) channel. The recorder will not record until you start it with [al_start_audio_recorder]. On failure, returns NULL. Since: 5.1.1 > *[Unstable API]:* The API may need a slight redesign. ### API: al_start_audio_recorder Begin recording into the fragment buffer. Once a complete fragment has been captured (as specified in [al_create_audio_recorder]), an [ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT] event will be triggered. Returns true if it was able to begin recording. Since: 5.1.1 > *[Unstable API]:* The API may need a slight redesign. ### API: al_stop_audio_recorder Stop capturing audio data. Note that the audio recorder is still active and consuming resources, so if you are finished recording you should destroy it with [al_destroy_audio_recorder]. You may still receive a few events after you call this function as the device flushes the buffer. If you restart the recorder, it will begin recording at the beginning of the next fragment buffer. Since: 5.1.1 > *[Unstable API]:* The API may need a slight redesign. ### API: al_is_audio_recorder_recording Returns true if the audio recorder is currently capturing data and generating events. Since: 5.1.1 > *[Unstable API]:* The API may need a slight redesign. ### API: al_get_audio_recorder_event Returns the event as an [ALLEGRO_AUDIO_RECORDER_EVENT]. Since: 5.1.1 > *[Unstable API]:* The API may need a slight redesign. ### API: al_get_audio_recorder_event_source Returns the event source for the recorder that generates the various recording events. Since: 5.1.1 > *[Unstable API]:* The API may need a slight redesign. ### API: al_destroy_audio_recorder Destroys the audio recorder and frees all resources associated with it. It is safe to destroy a recorder that is recording. You may receive events after the recorder has been destroyed. They must be ignored, as the fragment buffer will no longer be valid. Since: 5.1.1 > *[Unstable API]:* The API may need a slight redesign. ## Audio devices ### API: ALLEGRO_AUDIO_DEVICE An opaque datatype that represents an audio device. ### API: al_get_num_audio_output_devices Get the number of available audio output devices on the system. Since: 5.2.8 return -1 for unsupported drivers. ### API: al_get_audio_output_device Get the output audio device of the specified index. Since: 5.2.8 ### API: al_get_audio_device_name Get the user friendly display name of the device. Since: 5.2.8 ## Voices ### API: ALLEGRO_VOICE A voice represents an audio device on the system, which may be a real device, or an abstract device provided by the operating system. To play back audio, you would attach a mixer, sample instance or audio stream to a voice. See also: [ALLEGRO_MIXER], [ALLEGRO_SAMPLE], [ALLEGRO_AUDIO_STREAM] ### API: al_create_voice Creates a voice structure and allocates a voice from the digital sound driver. The passed frequency (in Hz), sample format and channel configuration are used as a hint to what kind of data will be sent to the voice. However, the underlying sound driver is free to use non-matching values. For example, it may be the native format of the sound hardware. If a mixer is attached to the voice, the mixer will handle the conversion of all its input streams to the voice format and care does not have to be taken for this. However if you access the voice directly, make sure to not rely on the parameters passed to this function, but instead query the returned voice for the actual settings. Reasonable default arguments are: ~~~~c al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2) ~~~~ See also: [al_destroy_voice] ### API: al_destroy_voice Destroys the voice and deallocates it from the digital driver. Does nothing if the voice is NULL. See also: [al_create_voice] ### API: al_detach_voice Detaches the mixer, sample instance or audio stream from the voice. See also: [al_attach_mixer_to_voice], [al_attach_sample_instance_to_voice], [al_attach_audio_stream_to_voice] ### API: al_attach_audio_stream_to_voice Attaches an audio stream to a voice. The same rules as [al_attach_sample_instance_to_voice] apply. This may fail if the driver can't create a voice with the buffer count and buffer size the stream uses. An audio stream attached directly to a voice has a number of limitations: The audio stream plays immediately and cannot be stopped. The stream position, speed, gain and panning cannot be changed. At this time, we don't recommend attaching audio streams directly to voices. Use a mixer inbetween. Returns true on success, false on failure. See also: [al_detach_voice], [al_voice_has_attachments] ### API: al_attach_mixer_to_voice Attaches a mixer to a voice. It must have the same frequency and channel configuration, but the depth may be different. Returns true on success, false on failure. See also: [al_detach_voice], [al_voice_has_attachments] ### API: al_attach_sample_instance_to_voice Attaches a sample instance to a voice, and allows it to play. The instance's gain and loop mode will be ignored, and it must have the same frequency, channel configuration and depth (including signed-ness) as the voice. This function may fail if the selected driver doesn't support preloading sample data. At this time, we don't recommend attaching sample instances directly to voices. Use a mixer inbetween. Returns true on success, false on failure. See also: [al_detach_voice], [al_voice_has_attachments] ### API: al_get_voice_frequency Return the frequency of the voice (in Hz), e.g. 44100. ### API: al_get_voice_channels Return the channel configuration of the voice. See also: [ALLEGRO_CHANNEL_CONF]. ### API: al_get_voice_depth Return the audio depth of the voice. See also: [ALLEGRO_AUDIO_DEPTH]. ### API: al_get_voice_playing Return true if the voice is currently playing. See also: [al_set_voice_playing] ### API: al_set_voice_playing Change whether a voice is playing or not. This can only work if the voice has a non-streaming object attached to it, e.g. a sample instance. On success the voice's current sample position is reset. Returns true on success, false on failure. See also: [al_get_voice_playing] ### API: al_get_voice_position When the voice has a non-streaming object attached to it, e.g. a sample, returns the voice's current sample position. Otherwise, returns zero. See also: [al_set_voice_position]. ### API: al_set_voice_position Set the voice position. This can only work if the voice has a non-streaming object attached to it, e.g. a sample instance. Returns true on success, false on failure. See also: [al_get_voice_position]. ### API: al_voice_has_attachments Returns true if the voice has something attached to it. See also: [al_attach_mixer_to_voice], [al_attach_sample_instance_to_voice], [al_attach_audio_stream_to_voice] Since: 5.2.9 ## Mixers ### API: ALLEGRO_MIXER A mixer mixes together attached streams into a single buffer. In the process, it converts channel configurations, sample frequencies and audio depths of the attached sample instances and audio streams accordingly. You can control the quality of this conversion using ALLEGRO_MIXER_QUALITY. When going from mono to stereo (and above), the mixer reduces the volume of both channels by `sqrt(2)`. When going from stereo (and above) to mono, the mixer reduces the volume of the left and right channels by `sqrt(2)` before adding them to the center channel (if present). ### API: ALLEGRO_MIXER_QUALITY * ALLEGRO_MIXER_QUALITY_POINT - point sampling * ALLEGRO_MIXER_QUALITY_LINEAR - linear interpolation * ALLEGRO_MIXER_QUALITY_CUBIC - cubic interpolation (since: 5.0.8, 5.1.4) ### API: al_create_mixer Creates a mixer to attach sample instances, audio streams, or other mixers to. It will mix into a buffer at the requested frequency (in Hz) and channel count. The only supported audio depths are ALLEGRO_AUDIO_DEPTH_FLOAT32 and ALLEGRO_AUDIO_DEPTH_INT16 (not yet complete). To actually produce any output, the mixer will have to be attached to a voice using [al_attach_mixer_to_voice]. Reasonable default arguments are: ~~~~c al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2) ~~~~ Returns true on success, false on error. See also: [al_destroy_mixer], [ALLEGRO_AUDIO_DEPTH], [ALLEGRO_CHANNEL_CONF] ### API: al_destroy_mixer Destroys the mixer. See also: [al_create_mixer] ### API: al_get_default_mixer Return the default mixer, or NULL if one has not been set. Although different configurations of mixers and voices can be used, in most cases a single mixer attached to a voice is what you want. The default mixer is used by [al_play_sample]. See also: [al_reserve_samples], [al_play_sample], [al_set_default_mixer], [al_restore_default_mixer] ### API: al_set_default_mixer Sets the default mixer. All samples started with [al_play_sample] will be stopped and all sample instances returned by [al_lock_sample_id] will be invalidated. If you are using your own mixer, this should be called before [al_reserve_samples]. Returns true on success, false on error. See also: [al_reserve_samples], [al_play_sample], [al_get_default_mixer], [al_restore_default_mixer] ### API: al_restore_default_mixer Restores Allegro's default mixer and attaches it to the default voice. If the default mixer hasn't been created before, it will be created. If the default voice hasn't been set via [al_set_default_voice] or created before, it will also be created. All samples started with [al_play_sample] will be stopped and all sample instances returned by [al_lock_sample_id] will be invalidated. Returns true on success, false on error. See also: [al_get_default_mixer], [al_set_default_mixer], [al_reserve_samples]. ### API: al_get_default_voice Returns the default voice or NULL if there is none. Since: 5.1.13 See also: [al_get_default_mixer] ### API: al_set_default_voice You can call this before calling al_restore_default_mixer to provide the voice which should be used. Any previous voice will be destroyed. You can also pass NULL to destroy the current default voice. Since: 5.1.13 See also: [al_get_default_mixer] ### API: al_attach_mixer_to_mixer Attaches the mixer passed as the first argument onto the mixer passed as the second argument. The first mixer (that is going to be attached) must not already be attached to anything. Both mixers must use the same frequency, audio depth and channel configuration. Returns true on success, false on error. It is invalid to attach a mixer to itself. See also: [al_detach_mixer]. ### API: al_attach_sample_instance_to_mixer Attach a sample instance to a mixer. The instance must not already be attached to anything. Returns true on success, false on failure. See also: [al_detach_sample_instance]. ### API: al_attach_audio_stream_to_mixer Attach an audio stream to a mixer. The stream must not already be attached to anything. Returns true on success, false on failure. See also: [al_detach_audio_stream]. ### API: al_get_mixer_frequency Return the mixer frequency (in Hz). See also: [al_set_mixer_frequency] ### API: al_set_mixer_frequency Set the mixer frequency (in Hz). This will only work if the mixer is not attached to anything. Returns true on success, false on failure. See also: [al_get_mixer_frequency] ### API: al_get_mixer_channels Return the mixer channel configuration. See also: [ALLEGRO_CHANNEL_CONF]. ### API: al_get_mixer_depth Return the mixer audio depth. See also: [ALLEGRO_AUDIO_DEPTH]. ### API: al_get_mixer_gain Return the mixer gain (amplification factor). The default is 1.0. Since: 5.0.6, 5.1.0 See also: [al_set_mixer_gain]. ### API: al_set_mixer_gain Set the mixer gain (amplification factor). Returns true on success, false on failure. Since: 5.0.6, 5.1.0 See also: [al_get_mixer_gain] ### API: al_get_mixer_quality Return the mixer quality. See also: [ALLEGRO_MIXER_QUALITY], [al_set_mixer_quality] ### API: al_set_mixer_quality Set the mixer quality. This can only succeed if the mixer does not have anything attached to it. Returns true on success, false on failure. See also: [ALLEGRO_MIXER_QUALITY], [al_get_mixer_quality] ### API: al_get_mixer_playing Return true if the mixer is playing. See also: [al_set_mixer_playing]. ### API: al_set_mixer_playing Change whether the mixer is playing. Returns true on success, false on failure. See also: [al_get_mixer_playing]. ### API: al_get_mixer_attached Return true if the mixer is attached to something. See also: [al_mixer_has_attachments], [al_attach_sample_instance_to_mixer], [al_attach_audio_stream_to_mixer], [al_attach_mixer_to_mixer], [al_detach_mixer] ### API: al_mixer_has_attachments Returns true if the mixer has something attached to it. See also: [al_get_mixer_attached], [al_attach_sample_instance_to_mixer], [al_attach_audio_stream_to_mixer], [al_attach_mixer_to_mixer], [al_detach_mixer] Since: 5.2.9 ### API: al_detach_mixer Detach the mixer from whatever it is attached to, if anything. See also: [al_attach_mixer_to_mixer]. ### API: al_set_mixer_postprocess_callback Sets a post-processing filter function that's called after the attached streams have been mixed. The buffer's format will be whatever the mixer was created with. The sample count and user-data pointer is also passed. > *Note:* The callback is called from a dedicated audio thread. ## Miscelaneous ### API: ALLEGRO_AUDIO_DEPTH Sample depth and type as well as signedness. Mixers only use 32-bit signed float (-1..+1), or 16-bit signed integers. Signedness is determined by an "unsigned" bit-flag applied to the depth value. * ALLEGRO_AUDIO_DEPTH_INT8 * ALLEGRO_AUDIO_DEPTH_INT16 * ALLEGRO_AUDIO_DEPTH_INT24 * ALLEGRO_AUDIO_DEPTH_FLOAT32 * ALLEGRO_AUDIO_DEPTH_UNSIGNED For convenience: * ALLEGRO_AUDIO_DEPTH_UINT8 * ALLEGRO_AUDIO_DEPTH_UINT16 * ALLEGRO_AUDIO_DEPTH_UINT24 ### API: ALLEGRO_AUDIO_PAN_NONE A special value for the pan property of sample instances and audio streams. Use this value to disable panning on sample instances and audio streams, and play them without attentuation implied by panning support. ALLEGRO_AUDIO_PAN_NONE is different from a pan value of 0.0 (centered) because, when panning is enabled, we try to maintain a constant sound power level as a sample is panned from left to right. A sound coming out of one speaker should sound as loud as it does when split over two speakers. As a consequence, a sample with pan value 0.0 will be 3 dB softer than the original level. (Please correct us if this is wrong.) ### API: ALLEGRO_CHANNEL_CONF Speaker configuration (mono, stereo, 2.1, etc). * ALLEGRO_CHANNEL_CONF_1 * ALLEGRO_CHANNEL_CONF_2 * ALLEGRO_CHANNEL_CONF_3 * ALLEGRO_CHANNEL_CONF_4 * ALLEGRO_CHANNEL_CONF_5_1 * ALLEGRO_CHANNEL_CONF_6_1 * ALLEGRO_CHANNEL_CONF_7_1 ### API: ALLEGRO_PLAYMODE Sample and stream playback mode. * ALLEGRO_PLAYMODE_ONCE - the sample/stream is played from start to finish an then it stops. * ALLEGRO_PLAYMODE_LOOP - the sample/stream is played from start to finish (or between the two loop points). When it reaches the end, it restarts from the beginning. * ALLEGRO_PLAYMODE_LOOP_ONCE - just like ALLEGRO_PLAYMODE_ONCE, but respects the loop end point. * ALLEGRO_PLAYMODE_BIDIR - the sample is played from start to finish (or between the two loop points). When it reaches the end, it reverses the playback direction and plays until it reaches the beginning when it reverses the direction back to normal. This is mode is rarely supported for streams. ### API: ALLEGRO_AUDIO_EVENT_TYPE Events sent by [al_get_audio_stream_event_source] or [al_get_audio_recorder_event_source]. #### ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT Sent when a stream fragment is ready to be filled in. See [al_get_audio_stream_fragment]. #### ALLEGRO_EVENT_AUDIO_STREAM_FINISHED Sent when a stream is finished. #### ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT Sent after a user-specified number of samples have been recorded. Convert this to [ALLEGRO_AUDIO_RECORDER_EVENT] via [al_get_audio_recorder_event]. You must always check the values for the buffer and samples as they are not guaranteed to be exactly what was originally specified. Since: 5.1.1 > *[Unstable API]:* The API may need a slight redesign. ### API: al_get_allegro_audio_version Returns the (compiled) version of the addon, in the same format as [al_get_allegro_version]. ### API: al_get_audio_depth_size Return the size of a sample, in bytes, for the given format. The format is one of the values listed under [ALLEGRO_AUDIO_DEPTH]. ### API: al_get_channel_count Return the number of channels for the given channel configuration, which is one of the values listed under [ALLEGRO_CHANNEL_CONF]. ### API: al_fill_silence Fill a buffer with silence, for the given format and channel configuration. The buffer must have enough space for the given number of samples, and be properly aligned. Since: 5.1.8 allegro5-5.2.10.1/docs/src/refman/color.txt000066400000000000000000000345221473414355200203340ustar00rootroot00000000000000# Color addon These functions are declared in the following header file. Link with allegro_color. ~~~~c #include ~~~~ When converting between certain color spaces, RGB colors are implicitly assumed to mean sRGB. sRGB is a standard which maps RGB colors to absolute colors. sRGB is very close to RGB values on a monitor which has a gamma value of 2.2. For example when the red component of a color is 0.5, the monitor will use a brightness of pow(0.5, 2.2) or about 22% - and not 50%. The reason is that human eyes can distinguish better between dark colors than between bright colors, and so if a pixel of the monitor is lit up to 22% of its maximum power it already will appear at half brightness to a human eye. sRGB improves upon simple gamma correction by taking differences between the three color channels into account as well. In general, most monitors nowadays try to be close to the sRGB specification. And so if in an Allegro game you display something with color al_map_rgb_f(0.5, 0.5, 0,5) then it will appear at about half brightness (even though the actual brightness output of the monitor will be less than half). ## API: al_color_cmyk Return an [ALLEGRO_COLOR] structure from CMYK values (cyan, magenta, yellow, black). See also: [al_color_cmyk_to_rgb], [al_color_rgb_to_cmyk] ## API: al_color_cmyk_to_rgb Convert CMYK values to RGB values. See also: [al_color_cmyk], [al_color_rgb_to_cmyk] ## API: al_color_hsl Return an [ALLEGRO_COLOR] structure from HSL (hue, saturation, lightness) values. Parameters: * hue - Color hue angle in the range 0..360 * saturation - Color saturation in the range 0..1 * lightness - Color lightness in the range 0..1 See also: [al_color_hsl_to_rgb], [al_color_hsv] ## API: al_color_hsl_to_rgb Convert values in HSL color model to RGB color model. Parameters: * hue - Color hue angle in the range 0..360 * saturation - Color saturation in the range 0..1 * lightness - Color lightness in the range 0..1 * red, green, blue - returned RGB values in the range 0..1 See also: [al_color_rgb_to_hsl], [al_color_hsl], [al_color_hsv_to_rgb] ## API: al_color_hsv Return an [ALLEGRO_COLOR] structure from HSV (hue, saturation, value) values. Parameters: * hue - Color hue angle in the range 0..360 * saturation - Color saturation in the range 0..1 * value - Color value in the range 0..1 See also: [al_color_hsv_to_rgb], [al_color_hsl] ## API: al_color_hsv_to_rgb Convert values in HSV color model to RGB color model. Parameters: * hue - Color hue angle in the range 0..360 * saturation - Color saturation in the range 0..1 * value - Color value in the range 0..1 * red, green, blue - returned RGB values in the range 0..1 See also: [al_color_rgb_to_hsv], [al_color_hsv], [al_color_hsl_to_rgb] ## API: al_color_html Interprets an HTML-style hex number (e.g. #00faff) as a color. The accepted format is the same as [al_color_html_to_rgb]. Returns the interpreted color, or `al_map_rgba(0, 0, 0, 0)` if the string could not be parsed. > *Note*: the behaviour on invalid strings is different from Allegro 5.0.x. See also: [al_color_html_to_rgb], [al_color_rgb_to_html] ## API: al_color_html_to_rgb Interprets an HTML-style hex number (e.g. #00faff) as a color. The only accepted formats are "#RRGGBB" and "RRGGBB" where R, G, B are hexadecimal digits [0-9A-Fa-f]. Returns true on success, false on failure. On failure all components are set to zero. > *Note*: the behaviour on invalid strings is different from Allegro 5.0.x. See also: [al_color_html], [al_color_rgb_to_html] ## API: al_color_rgb_to_html Create an HTML-style string representation of an [ALLEGRO_COLOR], e.g. #00faff. Parameters: * red, green, blue - The color components in the range 0..1. * string - A pointer to a buffer of at least 8 bytes, into which the result will be written (including the NUL terminator). Example: ~~~~c char html[8]; al_color_rgb_to_html(1, 0, 0, html); ~~~~ Now html will contain "#ff0000". See also: [al_color_html], [al_color_html_to_rgb] ## API: al_color_name Return an [ALLEGRO_COLOR] with the given name. If the color is not found then black is returned. See [al_color_name_to_rgb] for the list of names. ## API: al_color_name_to_rgb Parameters: * name - The (lowercase) name of the color. * r, g, b - If one of the recognized color names below is passed, the corresponding RGB values in the range 0..1 are written. The 148 recognized names are: > aliceblue, antiquewhite, aqua, aquamarine, azure, beige, bisque, black, blanchedalmond, blue, blueviolet, brown, burlywood, cadetblue, chartreuse, chocolate, coral, cornflowerblue, cornsilk, crimson, cyan, darkblue, darkcyan, darkgoldenrod, darkgray, darkgreen, darkkhaki, darkmagenta, darkolivegreen, darkorange, darkorchid, darkred, darksalmon, darkseagreen, darkslateblue, darkslategray, darkturquoise, darkviolet, deeppink, deepskyblue, dimgray, dodgerblue, firebrick, floralwhite, forestgreen, fuchsia, gainsboro, ghostwhite, goldenrod, gold, gray, green, greenyellow, honeydew, hotpink, indianred, indigo, ivory, khaki, lavenderblush, lavender, lawngreen, lemonchiffon, lightblue, lightcoral, lightcyan, lightgoldenrodyellow, lightgreen, lightgrey, lightpink, lightsalmon, lightseagreen, lightskyblue, lightslategray, lightsteelblue, lightyellow, lime, limegreen, linen, magenta, maroon, mediumaquamarine, mediumblue, mediumorchid, mediumpurple, mediumseagreen, mediumslateblue, mediumspringgreen, mediumturquoise, mediumvioletred, midnightblue, mintcream, mistyrose, moccasin, avajowhite, navy, oldlace, olive, olivedrab, orange, orangered, orchid, palegoldenrod, palegreen, paleturquoise, palevioletred, papayawhip, peachpuff, peru, pink, plum, powderblue, purple, rebeccapurple, red, rosybrown, royalblue, saddlebrown, salmon, sandybrown, seagreen, seashell, sienna, silver, skyblue, slateblue, slategray, snow, springgreen, steelblue, tan, teal, thistle, tomato, turquoise, violet, wheat, white, whitesmoke, yellow, yellowgreen They are taken from CSS: Note that these 9 colors have two names and so there are only 139 distinct colors: aqua = cyan, darkgray = darkgrey, darkslategray = darkslategrey, dimgray = dimgrey, fuchsia = purple, gray = grey, lightgray = lightgrey, lightslategray = lightslategrey, slategray = slategrey Returns: true if a name from the list above was passed, else false. See also: [al_color_name] ## API: al_color_rgb_to_cmyk Each RGB color can be represented in CMYK with a K component of 0 with the following formula: C = 1 - R M = 1 - G Y = 1 - B K = 0 This function will instead find the representation with the maximal value for K and minimal color components. See also: [al_color_cmyk], [al_color_cmyk_to_rgb] ## API: al_color_rgb_to_hsl Given an RGB triplet with components in the range 0..1, return the hue in degrees from 0..360 and saturation and lightness in the range 0..1. See also: [al_color_hsl_to_rgb], [al_color_hsl] ## API: al_color_rgb_to_hsv Given an RGB triplet with components in the range 0..1, return the hue in degrees from 0..360 and saturation and value in the range 0..1. See also: [al_color_hsv_to_rgb], [al_color_hsv] ## API: al_color_rgb_to_name Given an RGB triplet with components in the range 0..1, find a color name describing it approximately. See also: [al_color_name_to_rgb], [al_color_name] ## API: al_color_rgb_to_xyz Convert RGB values to XYZ color space. Since: 5.2.3 See also: [al_color_xyz], [al_color_xyz_to_rgb] ## API: al_color_xyz Return an [ALLEGRO_COLOR] structure from XYZ values. The CIE 1931 XYZ color space consists of three components in the range 0..1. The Y component corresponds to luminance and the X and Z components define the color. RGB components are always assumed to be in sRGB space. > *Note:* > > The XYZ color space can represent more colors than are > visible in sRGB and therefore conversion may result in RGB values > outside of the 0..1 range. You can check for that case with > [al_is_color_valid]. Since: 5.2.3 See also: [al_color_xyz_to_rgb], [al_color_rgb_to_xyz] ## API: al_color_xyz_to_rgb Convert XYZ color values to RGB color space. Since: 5.2.3 See also: [al_color_xyz], [al_color_rgb_to_xyz] ## API: al_color_rgb_to_xyy Convert RGB values to xyY color space. Since: 5.2.3 See also: [al_color_xyy], [al_color_xyy_to_rgb] ## API: al_color_xyy Return an [ALLEGRO_COLOR] structure from xyY values. The Y component in the xyY color space is the same as the Y in XYZ. However the x and y values are computed from XYZ like this: ~~~~c x = X / (X + Y + Z) y = Y / (X + Y + Z) ~~~~ Since: 5.2.3 See also: [al_color_xyy_to_rgb], [al_color_rgb_to_xyy] ## API: al_color_xyy_to_rgb Convert xyY color values to RGB color space. Since: 5.2.3 See also: [al_color_xyy], [al_color_rgb_to_xyy] ## API: al_color_rgb_to_lab Convert RGB values to L\*a\*b\* color space. Since: 5.2.3 See also: [al_color_lab], [al_color_lab_to_rgb] ## API: al_color_lab Return an [ALLEGRO_COLOR] structure from CIE L\*a\*b\* values. The L\* component corresponds to luminance from 0..1. The a\* and b\* components are in the range -1..+1. > *Note:* > > The L\*a\*b\* color space can represent more colors than are > visible in sRGB and therefore conversion may result in RGB values > outside of the 0..1 range. You can check for that case with > [al_is_color_valid]. > *Note:* > > In some literature the range of L* is 0 to 100 and a* and b* are from > -100 to +100. In that case divide all components by 100 before passing > them to this function. Since: 5.2.3 See also: [al_color_lab_to_rgb], [al_color_rgb_to_lab] ## API: al_color_lab_to_rgb Convert CIE L\*a\*b\* color values to RGB color space. Since: 5.2.3 See also: [al_color_lab], [al_color_rgb_to_lab] ## API: al_color_rgb_to_lch Convert RGB values to CIE LCH color space. Since: 5.2.3 See also: [al_color_lch], [al_color_lch_to_rgb] ## API: al_color_lch Return an [ALLEGRO_COLOR] structure from CIE LCH values. LCH colors are very similar to HSL, with the same meaning of L and H and C corresponding to S. However LCH is more visually uniform. Furthermore, this function expects the angle for H in radians and not in degree. The CIE LCH color space is a cylindrical representation of the L\*a\*b\* color space. The L component is the same and C and H are computed like this: ~~~~c C = sqrt(a * a + b * b) H = atan2(b, a) ~~~~ Since: 5.2.3 See also: [al_color_lch_to_rgb], [al_color_rgb_to_lch] ## API: al_color_lch_to_rgb Convert CIE LCH color values to RGB color space. Since: 5.2.3 See also: [al_color_lch], [al_color_rgb_to_lch] ## API: al_color_distance_ciede2000 This function computes the CIEDE2000 color difference between two RGB colors. This is a visually uniform color difference, unlike for example the RGB distance. When using the RGB distance (Euklidean distance between two RGB triplets) there can be color pairs with the same distance, where the colors of one pair appear to be almost the same color, while the colors of the other pair look quite different. This is improved by using the L\*a\*b\* color space which was designed with perceptual uniformity in mind. However it still is not completely uniform. The CIEDE2000 formula contains some additional transformations to fix that. The returned color distance is roughly in the range 0 (identical color) to 1 (completely different color) - but values greater than one are possible. > Note: This function uses [al_color_lab] internally which > defines the L component to be in the range 0..1 (and not 0..100 as is > sometimes seen). Since: 5.2.3 ## API: al_color_rgb_to_yuv Convert RGB values to YUV color space. See also: [al_color_yuv], [al_color_yuv_to_rgb] ## API: al_color_yuv Return an [ALLEGRO_COLOR] structure from YUV values. See also: [al_color_yuv_to_rgb], [al_color_rgb_to_yuv] ## API: al_color_yuv_to_rgb Convert YUV color values to RGB color space. See also: [al_color_yuv], [al_color_rgb_to_yuv] ## API: al_get_allegro_color_version Returns the (compiled) version of the addon, in the same format as [al_get_allegro_version]. ## API: al_is_color_valid Checks if all components of the color are between 0 and 1. Some of the color conversions in this addon support color spaces with more colors than can be represented in sRGB and when converted to RGB will result in invalid color components outside the 0..1 range. Since: 5.2.3 ## API: al_color_rgb_to_oklab Convert RGB values to the Oklab color space. Since: 5.2.8 See also: [al_color_oklab], [al_color_oklab_to_rgb] ## API: al_color_oklab Return an [ALLEGRO_COLOR] structure from Oklab values. The L component corresponds to luminance from 0..1. The a and b components are in the range -1..+1. > *Note:* > > The Oklab color space can represent more colors than are > visible in sRGB and therefore conversion may result in RGB values > outside of the 0..1 range. You can check for that case with > [al_is_color_valid]. Since: 5.2.8 See also: [al_color_oklab_to_rgb], [al_color_rgb_to_oklab] ## API: al_color_oklab_to_rgb Convert Oklab color values to RGB. Since: 5.2.8 See also: [al_color_oklab], [al_color_rgb_to_oklab] ## API: al_color_rgb_to_linear Convert gamma corrected sRGB values (i.e. normal RGB) to linear sRGB space. Since: 5.2.8 See also: [al_color_linear], [al_color_linear_to_rgb] ## API: al_color_linear Return an [ALLEGRO_COLOR] structure from linear sRGB values. Allegro RGB values are assumed to be sRGB. The sRGB standard is in wide use by various display devices. It accounts for a standard gamma correction applied to RGB colors before they get displayed. Gamma correction means if for example we have a medium gray color specified with al_map_rgb_f(0.5,0.5,0.5) then we do not want the monitor to set the pixel to exactly half the physical maximum intensity, but instead to an intensity that appears to be half as bright as the maximum to the person looking at it. In this case that would be closer to 21% of maximum intensity rather than to 50% intensity. For some applications it may be useful to specify a color in linear sRGB components, in which case you can use this function. For example: ~~~~c ALLEGRO_COLOR gray = al_color_linear(0.216, 0.216, 0.216); char html[8]; al_color_rgb_to_html(gray.r, gray.g, gray.b, html); // "#808080" ~~~~ Since: 5.2.8 See also: [al_color_linear_to_rgb], [al_color_rgb_to_linear] ## API: al_color_linear_to_rgb Convert linear sRGB color values to gamma corrected (i.e. normal) RGB values. Since: 5.2.8 See also: [al_color_linera], [al_color_rgb_to_linear] allegro5-5.2.10.1/docs/src/refman/config.txt000066400000000000000000000156211473414355200204620ustar00rootroot00000000000000# Configuration files These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ Allegro supports reading and writing of configuration files with a simple, INI file-like format. A configuration file consists of key-value pairs separated by newlines. Keys are separated from values by an equals sign (`=`). All whitespace before the key, after the value and immediately adjacent to the equals sign is ignored. Keys and values may have whitespace characters within them. Keys do not need to be unique, but all but the last one are ignored. The hash (`#`) character is used a comment when it is the first non-whitespace character on the line. All characters following that character are ignored to the end of the line. The hash character anywhere else on the line has no special significance. Key-value pairs can be optionally grouped into sections, which are declared by surrounding a section name with square brackets (`[` and `]`) on a single line. Whitespace before the opening bracket is ignored. All characters after the trailing bracket are also ignored. All key-value pairs that follow a section declaration belong to the last declared section. Key-value pairs that don't follow any section declarations belong to the global section. Sections do not nest. Here is an example configuration file: ~~~ini ## Monster description monster name = Allegro Developer [weapon 0] damage = 443 [weapon 1] damage = 503 ~~~~ It can then be accessed like this (make sure to check for errors in an actual program): ~~~~c ALLEGRO_CONFIG* cfg = al_load_config_file("test.cfg"); printf("%s\n", al_get_config_value(cfg, "", "monster name")); /* Prints: Allegro Developer */ printf("%s\n", al_get_config_value(cfg, "weapon 0", "damage")); /* Prints: 443 */ printf("%s\n", al_get_config_value(cfg, "weapon 1", "damage")); /* Prints: 503 */ al_destroy_config(cfg); ~~~~ ## API: ALLEGRO_CONFIG An abstract configuration structure. ## API: ALLEGRO_CONFIG_SECTION An opaque structure used for iterating across sections in a configuration structure. See also: [al_get_first_config_section], [al_get_next_config_section] ## API: ALLEGRO_CONFIG_ENTRY An opaque structure used for iterating across entries in a configuration section. See also: [al_get_first_config_entry], [al_get_next_config_entry] ## API: al_create_config Create an empty configuration structure. See also: [al_load_config_file], [al_destroy_config] ## API: al_destroy_config Free the resources used by a configuration structure. Does nothing if passed NULL. See also: [al_create_config], [al_load_config_file] ## API: al_load_config_file Read a configuration file from disk. Returns NULL on error. The configuration structure should be destroyed with [al_destroy_config]. See also: [al_load_config_file_f], [al_save_config_file] ## API: al_load_config_file_f Read a configuration file from an already open file. Returns NULL on error. The configuration structure should be destroyed with [al_destroy_config]. The file remains open afterwards. See also: [al_load_config_file] ## API: al_save_config_file Write out a configuration file to disk. Returns true on success, false on error. See also: [al_save_config_file_f], [al_load_config_file] ## API: al_save_config_file_f Write out a configuration file to an already open file. Returns true on success, false on error. The file remains open afterwards. See also: [al_save_config_file] ## API: al_add_config_section Add a section to a configuration structure with the given name. If the section already exists then nothing happens. ## API: al_remove_config_section Remove a section of a configuration. Returns true if the section was removed, or false if the section did not exist. Since: 5.1.5 ## API: al_add_config_comment Add a comment in a section of a configuration. If the section doesn't yet exist, it will be created. The section can be NULL or "" for the global section. The comment may or may not begin with a hash character. Any newlines in the comment string will be replaced by space characters. See also: [al_add_config_section] ## API: al_get_config_value Gets a pointer to an internal character buffer that will only remain valid as long as the ALLEGRO_CONFIG structure is not destroyed. Copy the value if you need a copy. The section can be NULL or "" for the global section. Returns NULL if the section or key do not exist. See also: [al_set_config_value] ## API: al_set_config_value Set a value in a section of a configuration. If the section doesn't yet exist, it will be created. If a value already existed for the given key, it will be overwritten. The section can be NULL or "" for the global section. For consistency with the on-disk format of config files, any leading and trailing whitespace will be stripped from the value. If you have significant whitespace you wish to preserve, you should add your own quote characters and remove them when reading the values back in. See also: [al_get_config_value] ## API: al_remove_config_key Remove a key and its associated value in a section of a configuration. Returns true if the entry was removed, or false if the entry did not exist. Since: 5.1.5 ## API: al_get_first_config_section Returns the name of the first section in the given config file. Usually this will return an empty string for the global section, even it contains no values. The `iterator` parameter will receive an opaque iterator which is used by [al_get_next_config_section] to iterate over the remaining sections. The returned string and the iterator are only valid as long as no change is made to the passed ALLEGRO_CONFIG. See also: [al_get_next_config_section] ## API: al_get_next_config_section Returns the name of the next section in the given config file or NULL if there are no more sections. The `iterator` must have been obtained with [al_get_first_config_section] first. See also: [al_get_first_config_section] ## API: al_get_first_config_entry Returns the name of the first key in the given section in the given config or NULL if the section is empty. The `iterator` works like the one for [al_get_first_config_section]. The returned string and the iterator are only valid as long as no change is made to the passed [ALLEGRO_CONFIG]. See also: [al_get_next_config_entry] ## API: al_get_next_config_entry Returns the next key for the iterator obtained by [al_get_first_config_entry]. The `iterator` works like the one for [al_get_next_config_section]. ## API: al_merge_config Merge two configuration structures, and return the result as a new configuration. Values in configuration 'cfg2' override those in 'cfg1'. Neither of the input configuration structures are modified. Comments from 'cfg2' are not retained. See also: [al_merge_config_into] ## API: al_merge_config_into Merge one configuration structure into another. Values in configuration 'add' override those in 'master'. 'master' is modified. Comments from 'add' are not retained. See also: [al_merge_config] allegro5-5.2.10.1/docs/src/refman/direct3d.txt000066400000000000000000000052261473414355200207160ustar00rootroot00000000000000# Direct3D integration These functions are declared in the following header file: ~~~~c #include ~~~~ ## API: al_get_d3d_device Returns the Direct3D device of the display. The return value is undefined if the display was not created with the Direct3D flag. *Returns:* A pointer to the Direct3D device. ## API: al_get_d3d_system_texture Returns the system texture (stored with the D3DPOOL_SYSTEMMEM flags). This texture is used for the render-to-texture feature set. *Returns:* A pointer to the Direct3D system texture. ## API: al_get_d3d_video_texture Returns the video texture (stored with the D3DPOOL_DEFAULT or D3DPOOL_MANAGED flags depending on whether render-to-texture is enabled or disabled respectively). *Returns:* A pointer to the Direct3D video texture. ## API: al_have_d3d_non_pow2_texture_support Returns whether the Direct3D device supports textures whose dimensions are not powers of two. *Returns:* True if device supports NPOT textures, false otherwise. ## API: al_have_d3d_non_square_texture_support Returns whether the Direct3D device supports textures that are not square. *Returns:* True if the Direct3D device supports non-square textures, false otherwise. ## API: al_get_d3d_texture_size Retrieves the size of the Direct3D texture used for the bitmap. Returns true on success, false on failure. Zero width and height are returned if the bitmap is not a Direct3D bitmap. Since: 5.1.0 See also: [al_get_d3d_texture_position] ## API: al_get_d3d_texture_position Returns the u/v coordinates for the top/left corner of the bitmap within the used texture, in pixels. *Parameters:* * bitmap - ALLEGRO_BITMAP to examine * u - Will hold the returned u coordinate * v - Will hold the returned v coordinate See also: [al_get_d3d_texture_size] ## API: al_is_d3d_device_lost Returns a boolean indicating whether or not the Direct3D device belonging to the given display is in a lost state. *Parameters:* * display - The display that the device you wish to check is attached to ## API: al_set_d3d_device_release_callback The callback will be called whenever a D3D device is reset (minimize, toggle fullscreen window, etc). In the callback you should release any d3d resources you have created yourself. The callback receives the affected display as a parameter. Pass NULL to disable the callback. Since: 5.1.0 ## API: al_set_d3d_device_restore_callback The callback will be called whenever a D3D device that has been reset is restored. In the callback you should restore any d3d resources you have created yourself. The callback receives the affected display as a parameter. Pass NULL to disable the callback. Since: 5.1.0 allegro5-5.2.10.1/docs/src/refman/display.txt000066400000000000000000000726231473414355200206670ustar00rootroot00000000000000# Displays These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ All drawing operations end up being visible on a display which is the same as a window in windowed environments. Thus, before anything is displayed, a display needs to be created. Before creating a display with [al_create_display], flags and options can be set with [al_set_new_display_flags] and [al_set_new_display_option]. For example, you can enable the use of shaders or choose between the OpenGL and Direct3D backends (on platforms that support both) with [al_set_new_display_flags]. Display options are rather optional settings that do not affect Allegro itself, e.g. they allow you to specify whether you want a depth buffer or enable multisampling. The actual properties of a display that has been successfully created can be queried via [al_get_display_option], [al_get_display_flags], [al_get_display_width] etc. Note that you can query some additional read-only properties such as the maximum allowed bitmap (i.e. texture) size via [al_get_display_option]. Each display has a backbuffer associated to it which is the default target for any drawing operations. In order to make visible what has been drawn previously, you have to to call [al_flip_display]. Note that it is generally advisable to redraw the whole screen (or [clear][al_clear_to_color] it in advance) to avoid artefacts of uninitialised memory becoming visible with some drivers. You don't have to use Allegro's drawing routines, however: since creating a display implies the creation of an OpenGL context or Direct3D device respectively, you can use these APIs directly if you prefer to do so. Allegro provides integration for both (see the OpenGL / Direct3D sections), so you can retrieve the underlying textures of [ALLEGRO_BITMAP]s, for example. In order to write a well-behaved application, it is necessary to remember that displays will also inform you about important [events][ALLEGRO_EVENT_DISPLAY_EXPOSE] via their [event sources][al_get_display_event_source]. ## Display creation ### API: ALLEGRO_DISPLAY An opaque type representing an open display or window. ### API: al_create_display Create a display, or window, with the specified dimensions. The parameters of the display are determined by the last calls to al_set_new_display\_\*. Default parameters are used if none are set explicitly. Creating a new display will automatically make it the active one, with the backbuffer selected for drawing. Returns NULL on error. Each display that uses OpenGL as a backend has a distinct OpenGL rendering context associated with it. See [al_set_target_bitmap] for the discussion about rendering contexts. See also: [al_set_new_display_flags], [al_set_new_display_option], [al_set_new_display_refresh_rate], [al_set_new_display_adapter], [al_set_new_window_title] [al_set_window_position] ### API: al_destroy_display Destroy a display. If the target bitmap of the calling thread is tied to the display, then it implies a call to "al_set_target_bitmap(NULL);" before the display is destroyed. That special case notwithstanding, you should make sure no threads are currently targeting a bitmap which is tied to the display before you destroy it. See also: [al_set_target_bitmap] ### API: al_get_new_display_flags Get the display flags to be used when creating new displays on the calling thread. See also: [al_set_new_display_flags], [al_set_display_flag] ### API: al_set_new_display_flags Sets various flags to be used when creating new displays on the calling thread. flags is a bitfield containing any reasonable combination of the following: ALLEGRO_WINDOWED : Prefer a windowed mode. Under multi-head X (not XRandR/TwinView), the use of more than one adapter is impossible due to bugs in X and GLX. [al_create_display] will fail if more than one adapter is attempted to be used. ALLEGRO_FULLSCREEN_WINDOW : Make the window span the entire screen. Unlike ALLEGRO_FULLSCREEN this will never attempt to modify the screen resolution. Instead the pixel dimensions of the created display will be the same as the desktop. The passed width and height are only used if the window is switched out of fullscreen mode later but will be ignored initially. Under Windows and X11 a fullscreen display created with this flag will behave differently from one created with the ALLEGRO_FULLSCREEN flag - even if the ALLEGRO_FULLSCREEN display is passed the desktop dimensions. The exact difference is platform dependent, but some things which may be different is how alt-tab works, how fast you can toggle between fullscreen/windowed mode or how additional monitors behave while your display is in fullscreen mode. Additionally under X, the use of more than one adapter in multi-head mode or with true Xinerama enabled is impossible due to bugs in X/GLX, creation will fail if more than one adapter is attempted to be used. ALLEGRO_FULLSCREEN : Prefer a fullscreen mode. Under X the use of more than one FULLSCREEN display when using multi-head X, or true Xinerama is not possible due to bugs in X and GLX, display creation will fail if more than one adapter is attempted to be used. > *Note:* Prefer using ALLEGRO_FULLSCREEN_WINDOW as it typically provides a better user experience as the monitor doesn't change resolution and switching away from your game via Alt-Tab works smoothly. ALLEGRO_FULLSCREEN is typically less well supported compared to ALLEGRO_FULLSCREEN_WINDOW. ALLEGRO_RESIZABLE : The display is resizable (only applicable if combined with ALLEGRO_WINDOWED). ALLEGRO_MAXIMIZED : The display window will be maximized (only applicable if combined with ALLEGRO_RESIZABLE). Since: 5.1.12 ALLEGRO_OPENGL : Require the driver to provide an initialized OpenGL context after returning successfully. ALLEGRO_OPENGL_3_0 : Require the driver to provide an initialized OpenGL context compatible with OpenGL version 3.0. ALLEGRO_OPENGL_FORWARD_COMPATIBLE : If this flag is set, the OpenGL context created with ALLEGRO_OPENGL_3_0 will be forward compatible *only*, meaning that all of the OpenGL API declared deprecated in OpenGL 3.0 will not be supported. Currently, a display created with this flag will *not* be compatible with Allegro drawing routines; the display option ALLEGRO_COMPATIBLE_DISPLAY will be set to false. ALLEGRO_OPENGL_ES_PROFILE : Used together with ALLEGRO_OPENGL, requests that the OpenGL context uses the OpenGL ES profile. A specific version can be requested with [al_set_new_display_option]. Note: Currently this is only supported by the X11/GLX driver. Since: 5.1.13 ALLEGRO_OPENGL_CORE_PROFILE : Used together with ALLEGRO_OPENGL, requests that the OpenGL context uses the OpenGL Core profile. A specific version can be requested with [al_set_new_display_option]. Note: Currently this is only supported by the X11/GLX driver. Since: 5.2.7 ALLEGRO_DIRECT3D : Require the driver to do rendering with Direct3D and provide a Direct3D device. ALLEGRO_PROGRAMMABLE_PIPELINE : Require a programmable graphics pipeline. This flag is required to use [ALLEGRO_SHADER] objects. Since: 5.1.6 ALLEGRO_FRAMELESS : Try to create a window without a frame (i.e. no border or titlebar). This usually does nothing for fullscreen modes, and even in windowed modes it depends on the underlying platform whether it is supported or not. Since: 5.0.7, 5.1.2 ALLEGRO_NOFRAME : Original name for ALLEGRO_FRAMELESS. This works with older versions of Allegro. ALLEGRO_GENERATE_EXPOSE_EVENTS : Let the display generate expose events. ALLEGRO_GTK_TOPLEVEL : Create a GTK toplevel window for the display, on X. This flag is conditionally defined by the native dialog addon. You must call [al_init_native_dialog_addon] for it to succeed. ALLEGRO_GTK_TOPLEVEL is incompatible with ALLEGRO_FULLSCREEN. Since: 5.1.5 ALLEGRO_DRAG_AND_DROP : If a display is created with the ALLEGRO_DRAG_AND_DROP flag it will generate ALLEGRO_EVENT_DROP events when files or text are dropped over the display. > *[Unstable API]:* This is an experimental feature and currently only works for the X11 backend. Since: 5.2.9 0 can be used for default values. See also: [al_set_new_display_option], [al_get_display_option], [al_set_display_option] ### API: al_get_new_display_option Retrieve an extra display setting which was previously set with [al_set_new_display_option]. ### API: al_set_new_display_option Set an extra display option, to be used when creating new displays on the calling thread. Display options differ from display flags, and specify some details of the context to be created within the window itself. These mainly have no effect on Allegro itself, but you may want to specify them, for example if you want to use multisampling. The 'importance' parameter can be either: * ALLEGRO_REQUIRE - The display will not be created if the setting can not be met. * ALLEGRO_SUGGEST - If the setting is not available, the display will be created anyway with a setting as close as possible to the requested one. You can query the actual value used in that case by calling [al_get_display_option] after the display has been created. * ALLEGRO_DONTCARE - If you added a display option with one of the above two settings before, it will be removed again. Else this does nothing. The supported options are: ALLEGRO_COLOR_SIZE : This can be used to ask for a specific bit depth. For example to force a 16-bit framebuffer set this to 16. ALLEGRO_RED_SIZE, ALLEGRO_GREEN_SIZE, ALLEGRO_BLUE_SIZE, ALLEGRO_ALPHA_SIZE : Individual color component size in bits. ALLEGRO_RED_SHIFT, ALLEGRO_GREEN_SHIFT, ALLEGRO_BLUE_SHIFT, ALLEGRO_ALPHA_SHIFT : Together with the previous settings these can be used to specify the exact pixel layout the display should use. Normally there is no reason to use these. ALLEGRO_ACC_RED_SIZE, ALLEGRO_ACC_GREEN_SIZE, ALLEGRO_ACC_BLUE_SIZE, ALLEGRO_ACC_ALPHA_SIZE : This can be used to define the required accumulation buffer size. ALLEGRO_STEREO : Whether the display is a stereo display. ALLEGRO_AUX_BUFFERS : Number of auxiliary buffers the display should have. ALLEGRO_DEPTH_SIZE : How many depth buffer (z-buffer) bits to use. ALLEGRO_STENCIL_SIZE : How many bits to use for the stencil buffer. ALLEGRO_SAMPLE_BUFFERS : Whether to use multisampling (1) or not (0). ALLEGRO_SAMPLES : If the above is 1, the number of samples to use per pixel. Else 0. ALLEGRO_RENDER_METHOD: : 0 if hardware acceleration is not used with this display. ALLEGRO_FLOAT_COLOR : Whether to use floating point color components. ALLEGRO_FLOAT_DEPTH : Whether to use a floating point depth buffer. ALLEGRO_SINGLE_BUFFER : Whether the display uses a single buffer (1) or another update method (0). ALLEGRO_SWAP_METHOD : If the above is 0, this is set to 1 to indicate the display is using a copying method to make the next buffer in the flip chain available, or to 2 to indicate a flipping or other method. ALLEGRO_COMPATIBLE_DISPLAY : Indicates if Allegro's graphics functions can use this display. If you request a display not useable by Allegro, you can still use for example OpenGL to draw graphics. ALLEGRO_UPDATE_DISPLAY_REGION : Set to 1 if the display is capable of updating just a region, and 0 if calling [al_update_display_region] is equivalent to [al_flip_display]. ALLEGRO_VSYNC : Set to 1 to tell the driver to wait for vsync in [al_flip_display], or to 2 to force vsync off. The default of 0 means that Allegro does not try to modify the vsync behavior so it may be on or off. Note that even in the case of 1 or 2 it is possible to override the vsync behavior in the graphics driver so you should not rely on it. ALLEGRO_MAX_BITMAP_SIZE : When queried this returns the maximum size (width as well as height) a bitmap can have for this display. Calls to [al_create_bitmap] or [al_load_bitmap] for bitmaps larger than this size will fail. It does not apply to memory bitmaps which always can have arbitrary size (but are slow for drawing). ALLEGRO_SUPPORT_NPOT_BITMAP : Set to 1 if textures used for bitmaps on this display can have a size which is not a power of two. This is mostly useful if you use Allegro to load textures as otherwise only power-of-two textures will be used internally as bitmap storage. ALLEGRO_CAN_DRAW_INTO_BITMAP : Set to 1 if you can use [al_set_target_bitmap] on bitmaps of this display to draw into them. If this is not the case software emulation will be used when drawing into display bitmaps (which can be very slow). ALLEGRO_SUPPORT_SEPARATE_ALPHA : This is set to 1 if the [al_set_separate_blender] function is supported. Otherwise the alpha parameters will be ignored. ALLEGRO_AUTO_CONVERT_BITMAPS : This is on by default. It causes any existing memory bitmaps with the ALLEGRO_CONVERT_BITMAP flag to be converted to a display bitmap of the newly created display with the option set. Since: 5.1.0 ALLEGRO_SUPPORTED_ORIENTATIONS : This is a bit-combination of the orientations supported by the application. The orientations are the same as for [al_get_display_orientation] with the additional possibilities: * ALLEGRO_DISPLAY_ORIENTATION_PORTRAIT * ALLEGRO_DISPLAY_ORIENTATION_LANDSCAPE * ALLEGRO_DISPLAY_ORIENTATION_ALL PORTRAIT means only the two portrait orientations are supported, LANDSCAPE means only the two landscape orientations and ALL allows all four orientations. When the orientation changes between a portrait and a landscape orientation the display needs to be resized. This is done by sending an [ALLEGRO_EVENT_DISPLAY_RESIZE] message which should be handled by calling [al_acknowledge_resize]. Since: 5.1.0 ALLEGRO_OPENGL_MAJOR_VERSION : Request a specific OpenGL major version. Since: 5.1.13 ALLEGRO_OPENGL_MINOR_VERSION : Request a specific OpenGL minor version. Since: 5.1.13 ALLEGRO_DEFAULT_SHADER_PLATFORM : Specify the shader platform to use for the default shader. See [ALLEGRO_SHADER_PLATFORM]. The default is ALLEGRO_SHADER_AUTO. Since: 5.2.8 See also: [al_set_new_display_flags], [al_get_display_option] ### API: al_reset_new_display_options This undoes any previous call to [al_set_new_display_option] on the calling thread. ### API: al_get_new_window_position Get the position where new non-fullscreen displays created by the calling thread will be placed. See also: [al_set_new_window_position] ### API: al_set_new_window_position Sets where the top left pixel of the client area of newly created windows (non-fullscreen) will be on screen, for displays created by the calling thread. Negative values are allowed on some multihead systems. To reset to the default behaviour, pass (INT_MAX, INT_MAX). See also: [al_get_new_window_position] ### API: al_get_new_display_refresh_rate Get the requested refresh rate to be used when creating new displays on the calling thread. See also: [al_set_new_display_refresh_rate] ### API: al_set_new_display_refresh_rate Sets the refresh rate to use when creating new displays on the calling thread. If the refresh rate is not available, [al_create_display] will fail. A list of modes with refresh rates can be found with [al_get_num_display_modes] and [al_get_display_mode]. The default setting is zero (don't care). See also: [al_get_new_display_refresh_rate] ### API: al_get_new_display_adapter Gets the video adapter index where new displays will be created by the calling thread, if previously set with [al_set_new_display_adapter]. Otherwise returns `ALLEGRO_DEFAULT_DISPLAY_ADAPTER`. See also: [al_set_new_display_adapter] ### API: al_set_new_display_adapter Sets the adapter to use for new displays created by the calling thread. The adapter has a monitor attached to it. Information about the monitor can be gotten using [al_get_num_video_adapters] and [al_get_monitor_info]. To return to the default behaviour, pass `ALLEGRO_DEFAULT_DISPLAY_ADAPTER`. See also: [al_get_num_video_adapters], [al_get_monitor_info] ## Display operations ### API: al_get_display_event_source Retrieve the associated event source. See the [documentation on events][ALLEGRO_EVENT_DISPLAY_EXPOSE] for a list of the events displays will generate. ### API: al_get_backbuffer Return a special bitmap representing the back-buffer of the display. Care should be taken when using the backbuffer bitmap (and its sub-bitmaps) as the source bitmap (e.g as the bitmap argument to [al_draw_bitmap]). Only untransformed operations are hardware accelerated. These consist of [al_draw_bitmap] and [al_draw_bitmap_region] when the current transformation is the identity. If the transformation is not the identity, or some other drawing operation is used, the call will be routed through the memory bitmap routines, which are slow. If you need those operations to be accelerated, then first copy a region of the backbuffer into a temporary bitmap (via the [al_draw_bitmap] and [al_draw_bitmap_region]), and then use that temporary bitmap as the source bitmap. ### API: al_flip_display Copies or updates the front and back buffers so that what has been drawn previously on the currently selected display becomes visible on screen. Pointers to the special back buffer bitmap remain valid and retain their semantics as the back buffer, although the contents may have changed. > *Note:* If not using the ALLEGRO_SINGLE_BUFFER option, you typically want to redraw every pixel of the backbuffer bitmap to avoid uninitialized memory artifacts. Several display options change how this function behaves: - With ALLEGRO_SINGLE_BUFFER, no flipping is done. You still have to call this function to display graphics, depending on how the used graphics system works. - The ALLEGRO_SWAP_METHOD option may have additional information about what kind of operation is used internally to flip the front and back buffers. - If ALLEGRO_VSYNC is 1, this function will force waiting for vsync. If ALLEGRO_VSYNC is 2, this function will not wait for vsync. With many drivers the vsync behavior is controlled by the user and not the application, and ALLEGRO_VSYNC will not be set; in this case [al_flip_display] will wait for vsync depending on the settings set in the system's graphics preferences. See also: [al_set_new_display_flags], [al_set_new_display_option] ### API: al_update_display_region Does the same as [al_flip_display], but tries to update only the specified region. With many drivers this is not possible, but for some it can improve performance. If this is not supported, this function falls back to the behavior of [al_flip_display]. You can query the support for this function using `al_get_display_option(display, ALLEGRO_UPDATE_DISPLAY_REGION)`. See also: [al_flip_display], [al_get_display_option] ### API: al_wait_for_vsync Wait for the beginning of a vertical retrace. Some driver/card/monitor combinations may not be capable of this. Note how [al_flip_display] usually already waits for the vertical retrace, so unless you are doing something special, there is no reason to call this function. Returns false if not possible, true if successful. See also: [al_flip_display] ## Display size and position ### API: al_get_display_width Gets the width of the display. This is like SCREEN_W in Allegro 4.x. See also: [al_get_display_height] ### API: al_get_display_height Gets the height of the display. This is like SCREEN_H in Allegro 4.x. See also: [al_get_display_width] ### API: al_resize_display Resize the display. Returns true on success, or false on error. This works on both fullscreen and windowed displays, regardless of the ALLEGRO_RESIZABLE flag. Adjusts the clipping rectangle to the full size of the backbuffer. See also: [al_acknowledge_resize] ### API: al_acknowledge_resize When the user receives a [resize event][ALLEGRO_EVENT_DISPLAY_RESIZE] from a resizable display, if they wish the display to be resized they must call this function to let the graphics driver know that it can now resize the display. Returns true on success. Adjusts the clipping rectangle to the full size of the backbuffer. This also resets the backbuffers projection transform to default orthographic transform (see [al_use_projection_transform]). Note that a resize event may be outdated by the time you acknowledge it; there could be further resize events generated in the meantime. See also: [al_resize_display], [ALLEGRO_EVENT] ### API: al_get_window_position Gets the position of a non-fullscreen display. See also: [al_set_window_position], [al_get_window_borders] ### API: al_set_window_position Sets the position on screen of a non-fullscreen display. See also: [al_get_window_position], [al_get_window_borders] ### API: al_get_window_borders If that information is available returns TRUE and fills in the size of the window borders. You can pass NULL for borders you do not want to retrieve. If the border information is not available returns FALSE. > *[Unstable API]:* This is an experimental feature and currently only partially works on X11 and Windows. The meaning of the upper border may change when menus are present. See also: [al_set_window_position], [al_get_window_position] Since: 5.2.9 ### API: al_get_window_constraints Gets the constraints for a non-fullscreen resizable display. Since: 5.1.0 See also: [al_set_window_constraints] ### API: al_set_window_constraints Constrains a non-fullscreen resizable display. The constraints are a hint only, and are not necessarily respected by the window environment. A value of 0 for any of the parameters indicates no constraint for that parameter. The constraints will be applied to a display only after the [al_apply_window_constraints] function call. Since: 5.1.0 See also: [al_apply_window_constraints], [al_get_window_constraints] ### API: al_apply_window_constraints Enable or disable previously set constraints by [al_set_window_constraints] function. If enabled, the specified display will be automatically resized to new sizes to conform constraints in next cases: * The specified display is resizable, not maximized and is not in fullscreen mode. * If the appropriate current display size (width or height) is less than the value of constraint. Applied to minimum constraints. * If the appropriate current display size (width or height) is greater than the value of constraint. Applied to maximum constraints. Constrains are not applied when a display is toggle from windowed to maximized or fullscreen modes. When a display is toggle from maximized/fullscreen to windowed mode, then the display may be resized as described above. The later case is also possible when a user drags the maximized display via mouse. If disabled, the specified display will stop using constraints. See also: [al_get_window_constraints], [al_set_window_constraints] ### API: al_get_display_adapter Returns which adapter the window is currently placed on. Returns -1 if there was an error in determining the adapter. Since: 5.2.10 ## Display settings ### API: al_get_display_flags Gets the flags of the display. In addition to the flags set for the display at creation time with [al_set_new_display_flags] it can also have the ALLEGRO_MINIMIZED flag set, indicating that the window is currently minimized. This flag is very platform-dependent as even a minimized application may still render a preview version so normally you should not care whether it is minimized or not. See also: [al_set_new_display_flags], [al_set_display_flag] ### API: al_set_display_flag Enable or disable one of the display flags. The flags are the same as for [al_set_new_display_flags]. The only flags that can be changed after creation are: - ALLEGRO_FULLSCREEN_WINDOW - ALLEGRO_FRAMELESS - ALLEGRO_MAXIMIZED Returns true if the driver supports toggling the specified flag else false. You can use [al_get_display_flags] to query whether the given display property actually changed. Since: 5.0.7, 5.1.2 See also: [al_set_new_display_flags], [al_get_display_flags] ### API: al_get_display_option Return an extra display setting of the display. See also: [al_set_new_display_option] ### API: al_set_display_option Change an option that was previously set for a display. After displays are created, they take on the options set with [al_set_new_display_option]. Calling [al_set_new_display_option] subsequently only changes options for newly created displays, and doesn't touch the options of already created displays. [al_set_display_option] allows changing some of these values. Not all display options can be changed or changing them will have no effect. Changing options other than those listed below is undefined. * ALLEGRO_SUPPORTED_ORIENTATIONS - This can be changed to allow new or restrict previously enabled orientations of the screen/device. See [al_set_new_display_option] for more information on this option. Since: 5.1.5 See also: [al_set_new_display_option] ### API: al_get_display_format Gets the pixel format of the display. See also: [ALLEGRO_PIXEL_FORMAT] ### API: al_get_display_orientation Return the display orientation, which can be one of the following: - ALLEGRO_DISPLAY_ORIENTATION_UNKNOWN - ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES - ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES - ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES - ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES - ALLEGRO_DISPLAY_ORIENTATION_FACE_UP - ALLEGRO_DISPLAY_ORIENTATION_FACE_DOWN Since: 5.1.0 ### API: al_get_display_refresh_rate Gets the refresh rate of the display. See also: [al_set_new_display_refresh_rate] ### API: al_set_window_title Set the title on a display. See also: [al_set_display_icon], [al_set_display_icons] ### API: al_set_new_window_title Set the title that will be used when a new display is created. Allegro uses a static buffer of [ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE] to store this, so the length of the titme you set must be less than this. See also: [al_set_window_title], [al_get_new_window_title], [al_create_display], [ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE] Since: 5.1.12 ### API: ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE This is the maximum size of the title that can be set with [al_set_new_window_title]. See also: [al_set_new_window_title] Since: 5.1.12 ### API: al_get_new_window_title Returns the title that will be used when a new display is created. This returns the value that [al_set_window_title] was called with. If that function wasn't called yet, the value of [al_get_app_name] is returned as a default. The current implementation returns a pointer to a static buffer of which you should make a copy if you want to modify it. See also: [al_set_window_title], [al_set_new_window_title], [al_create_display] Since: 5.1.12 ### API: al_set_display_icon Changes the icon associated with the display (window). Same as [al_set_display_icons] with one icon. See also: [al_set_display_icons], [al_set_window_title] ### API: al_set_display_icons Changes the icons associated with the display (window). Multiple icons can be provided for use in different contexts, e.g. window frame, taskbar, alt-tab popup. The number of icons must be at least one. > *Note:* If the underlying OS requires an icon of a size not provided then one of the bitmaps will be scaled up or down to the required size. The choice of bitmap is implementation dependent. Since: 5.0.9, 5.1.5 See also: [al_set_display_icon], [al_set_window_title] ## Drawing halts ### API: al_acknowledge_drawing_halt Call this in response to the [ALLEGRO_EVENT_DISPLAY_HALT_DRAWING] event. This is currently necessary for Android and iOS as you are not allowed to draw to your display while it is not being shown. If you do not call this function to let the operating system know that you have stopped drawing or if you call it to late the application likely will be considered misbehaving and get terminated. Since: 5.1.0 See also: [ALLEGRO_EVENT_DISPLAY_HALT_DRAWING] ### API: al_acknowledge_drawing_resume Call this in response to the [ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING] event. Since: 5.1.1 See also: [ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING] ## Screensaver ### API: al_inhibit_screensaver This function allows the user to stop the system screensaver from starting up if true is passed, or resets the system back to the default state (the state at program start) if false is passed. It returns true if the state was set successfully, otherwise false. ## Clipboard With the clipboard API of Allegro, text can be copied from and to the clipboard. Currentlly, only UTF8 encoded text is supported. It currently works on Linux, Windows, OSX, Android and IOS. ### API: al_get_clipboard_text This function returns a pointer to a string, allocated with [al_malloc] with the text contents of the clipboard if available. If no text is available on the clipboard then this function returns NULL. You must call [al_free] on the returned pointer when you don't need it anymore. Beware that text on the clipboard on Windows may be in Windows format, that is, it may have carriage return newline combinations for the line endings instead of regular newlines for the line endings on Linux or OSX. Since: 5.1.12 See also: [al_set_clipboard_text], [al_clipboard_has_text] ### API: al_set_clipboard_text This function pastes the text given as an argument to the clipboard. Since: 5.1.12 See also: [al_get_clipboard_text], [al_clipboard_has_text] ### API: al_clipboard_has_text This function returns true if and only if the clipboard has text available. Since: 5.1.12 See also: [al_set_clipboard_text], [al_get_clipboard_text] allegro5-5.2.10.1/docs/src/refman/events.txt000066400000000000000000000721131473414355200205200ustar00rootroot00000000000000# Event system and events These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ Events are generated by event sources. Most notably, each of the input subsystems provides an event source, but also timers, displays, and audio streams will generate events. Event sources are registered to event queues which aggregate events from multiple sources. A single event source can also be registered to multiple event queues. Event queues can then be queried for events. In particular, it is possible to wait until events become available in order to save CPU time. You can combine this with [timers][ALLEGRO_TIMER] to make your main-loop run at a specific speed without wasting CPU time or missing events. In addition to the predefined event types, Allegro also allows for user-defined events that can be generated by user-defined event sources. The appropriate reaction to an event is determined by examining the fields of the [ALLEGRO_EVENT] union according to the event type. In addition to the events sent by Allegro core, there's also events send by the addons, see [ALLEGRO_AUDIO_EVENT_TYPE] and [ALLEGRO_VIDEO_EVENT_TYPE]. ## API: ALLEGRO_EVENT An ALLEGRO_EVENT is a union of all builtin event structures, i.e. it is an object large enough to hold the data of any event type. All events have the following fields in common: type (ALLEGRO_EVENT_TYPE) : Indicates the type of event. any.source (ALLEGRO_EVENT_SOURCE *) : The event source which generated the event. any.timestamp (double) : When the event was generated. By examining the `type` field you can then access type-specific fields. The `any.source` field tells you which event source generated that particular event. The `any.timestamp` field tells you when the event was generated. The time is referenced to the same starting point as [al_get_time]. Each event is of one of the following types, with the usable fields given. ### ALLEGRO_EVENT_JOYSTICK_AXIS A joystick axis value changed. joystick.id (ALLEGRO_JOYSTICK *) : The joystick which generated the event. This is not the same as the event source `joystick.source`. joystick.stick (int) : The stick number, counting from zero. Axes on a joystick are grouped into "sticks". joystick.axis (int) : The axis number on the stick, counting from zero. joystick.pos (float) : The axis position, from -1.0 to +1.0. ### ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN A joystick button was pressed. joystick.id (ALLEGRO_JOYSTICK *) : The joystick which generated the event. joystick.button (int) : The button which was pressed, counting from zero. ### ALLEGRO_EVENT_JOYSTICK_BUTTON_UP A joystick button was released. joystick.id (ALLEGRO_JOYSTICK *) : The joystick which generated the event. joystick.button (int) : The button which was released, counting from zero. ### ALLEGRO_EVENT_JOYSTICK_CONFIGURATION A joystick was plugged in or unplugged. See [al_reconfigure_joysticks] for details. ### ALLEGRO_EVENT_KEY_DOWN A keyboard key was pressed. keyboard.keycode (int) : The code corresponding to the physical key which was pressed. See the [Key codes] section for the list of ALLEGRO\_KEY\_\* constants. keyboard.display (ALLEGRO_DISPLAY *) : The display which had keyboard focus when the event occurred. > *Note:* this event is about the physical keys being pressed on the keyboard. Look for ALLEGRO_EVENT_KEY_CHAR events for character input. ### ALLEGRO_EVENT_KEY_UP A keyboard key was released. keyboard.keycode (int) : The code corresponding to the physical key which was released. See the [Key codes] section for the list of ALLEGRO\_KEY\_\* constants. keyboard.display (ALLEGRO_DISPLAY *) : The display which had keyboard focus when the event occurred. ### ALLEGRO_EVENT_KEY_CHAR A character was typed on the keyboard, or a character was auto-repeated. keyboard.keycode (int) : The code corresponding to the physical key which was last pressed. See the [Key codes] section for the list of ALLEGRO\_KEY\_\* constants. keyboard.unichar (int) : A Unicode code point (character). This *may* be zero or negative if the event was generated for a non-visible "character", such as an arrow or Function key. In that case you can act upon the `keycode` field. Some special keys will set the `unichar` field to their standard ASCII values: Tab=9, Return=13, Escape=27. In addition if you press the Control key together with A to Z the `unichar` field will have the values 1 to 26. For example Ctrl-A will set `unichar` to 1 and Ctrl-H will set it to 8. As of Allegro 5.0.2 there are some inconsistencies in the treatment of Backspace (8 or 127) and Delete (127 or 0) keys on different platforms. These can be worked around by checking the `keycode` field. keyboard.modifiers (unsigned) : This is a bitfield of the modifier keys which were pressed when the event occurred. See "Keyboard modifier flags" for the constants. keyboard.repeat (bool) : Indicates if this is a repeated character. keyboard.display (ALLEGRO_DISPLAY *) : The display which had keyboard focus when the event occurred. > *Note*: in many input methods, characters are *not* entered one-for-one with physical key presses. Multiple key presses can combine to generate a single character, e.g. apostrophe + e may produce 'é'. Fewer key presses can also generate more characters, e.g. macro sequences expanding to common phrases. ### ALLEGRO_EVENT_MOUSE_AXES One or more mouse axis values changed. mouse.x (int) : x-coordinate mouse.y (int) : y-coordinate mouse.z (int) : z-coordinate. This usually means the vertical axis of a mouse wheel, where up is positive and down is negative. mouse.w (int) : w-coordinate. This usually means the horizontal axis of a mouse wheel. mouse.dx (int) : Change in the x-coordinate value since the previous ALLEGRO_EVENT_MOUSE_AXES event. mouse.dy (int) : Change in the y-coordinate value since the previous ALLEGRO_EVENT_MOUSE_AXES event. mouse.dz (int) : Change in the z-coordinate value since the previous ALLEGRO_EVENT_MOUSE_AXES event. mouse.dw (int) : Change in the w-coordinate value since the previous ALLEGRO_EVENT_MOUSE_AXES event. mouse.pressure (float) : Pressure, ranging from `0.0` to `1.0`. mouse.display (ALLEGRO_DISPLAY *) : The display which had mouse focus. > *Note:* Calling [al_set_mouse_xy] also will result in a change of axis values, but such a change is reported with [ALLEGRO_EVENT_MOUSE_WARPED] events instead which are identical except for their type. > *Note:* currently mouse.display may be NULL if an event is generated in response to [al_set_mouse_axis]. ### ALLEGRO_EVENT_MOUSE_BUTTON_DOWN A mouse button was pressed. mouse.x (int) : x-coordinate mouse.y (int) : y-coordinate mouse.z (int) : z-coordinate mouse.w (int) : w-coordinate mouse.button (unsigned) : The mouse button which was pressed, numbering from 1. As a convenience, the constants ALLEGRO_MOUSE_BUTTON_LEFT, ALLEGRO_MOUSE_BUTTON_RIGHT, ALLEGRO_MOUSE_BUTTON_MIDDLE are provided. However, depending on the hardware there may be more or fewer mouse buttons. You can check [al_get_mouse_num_buttons] if you want to be sure. mouse.pressure (float) : Pressure, ranging from `0.0` to `1.0`. mouse.display (ALLEGRO_DISPLAY *) : The display which had mouse focus. ### ALLEGRO_EVENT_MOUSE_BUTTON_UP A mouse button was released. mouse.x (int) : x-coordinate mouse.y (int) : y-coordinate mouse.z (int) : z-coordinate mouse.w (int) : w-coordinate mouse.button (unsigned) : The mouse button which was released, numbering from 1. As a convenience, the constants ALLEGRO_MOUSE_BUTTON_LEFT, ALLEGRO_MOUSE_BUTTON_RIGHT, ALLEGRO_MOUSE_BUTTON_MIDDLE are provided. However, depending on the hardware there may be more or fewer mouse buttons. You can check [al_get_mouse_num_buttons] if you want to be sure. mouse.pressure (float) : Pressure, ranging from `0.0` to `1.0`. mouse.display (ALLEGRO_DISPLAY *) : The display which had mouse focus. ### ALLEGRO_EVENT_MOUSE_WARPED [al_set_mouse_xy] was called to move the mouse. This event is identical to ALLEGRO_EVENT_MOUSE_AXES otherwise. ### ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY The mouse cursor entered a window opened by the program. mouse.x (int) : x-coordinate mouse.y (int) : y-coordinate mouse.z (int) : z-coordinate mouse.w (int) : w-coordinate mouse.display (ALLEGRO_DISPLAY *) : The display which had mouse focus. ### ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY The mouse cursor left the boundaries of a window opened by the program. mouse.x (int) : x-coordinate mouse.y (int) : y-coordinate mouse.z (int) : z-coordinate mouse.w (int) : w-coordinate mouse.display (ALLEGRO_DISPLAY *) : The display which had mouse focus. ### ALLEGRO_EVENT_TOUCH_BEGIN The touch input device registered a new touch. touch.display (ALLEGRO_DISPLAY) : The display which was touched. touch.id (int) : An identifier for this touch. If supported by the device it will stay the same for events from the same finger until the touch ends. touch.x (float) : The x coordinate of the touch in pixels. touch.y (float) : The y coordinate of the touch in pixels. touch.dx (float) : Movement speed in pixels in x direction. touch.dy (float) : Movement speed in pixels in y direction. touch.primary (bool) : Whether this is the only/first touch or an additional touch. Since: 5.1.0 ### ALLEGRO_EVENT_TOUCH_END A touch ended. Has the same fields as [ALLEGRO_EVENT_TOUCH_BEGIN]. Since: 5.1.0 ### ALLEGRO_EVENT_TOUCH_MOVE The position of a touch changed. Has the same fields as [ALLEGRO_EVENT_TOUCH_BEGIN]. Since: 5.1.0 ### ALLEGRO_EVENT_TOUCH_CANCEL A touch was cancelled. This is device specific but could for example mean that a finger moved off the border of the device or moved so fast that it could not be tracked any longer. Has the same fields as [ALLEGRO_EVENT_TOUCH_BEGIN]. Since: 5.1.0 ### ALLEGRO_EVENT_TIMER A [timer][ALLEGRO_TIMER] counter incremented. timer.source (ALLEGRO_TIMER *) : The timer which generated the event. timer.count (int64_t) : The timer count value. ### ALLEGRO_EVENT_DISPLAY_EXPOSE The display (or a portion thereof) has become visible. display.source (ALLEGRO_DISPLAY *) : The display which was exposed. display.x (int) : The X position of the top-left corner of the rectangle which was exposed. display.y (int) : The Y position of the top-left corner of the rectangle which was exposed. display.width (int) : The width of the rectangle which was exposed. display.height (int) : The height of the rectangle which was exposed. > *Note:* The display needs to be created with ALLEGRO_GENERATE_EXPOSE_EVENTS flag for these events to be generated. ### ALLEGRO_EVENT_DISPLAY_RESIZE The window has been resized. display.source (ALLEGRO_DISPLAY *) : The display which was resized. display.x (int) : The X position of the top-left corner of the display. display.y (int) : The Y position of the top-left corner of the display. display.width (int) : The new width of the display. display.height (int) : The new height of the display. You should normally respond to these events by calling [al_acknowledge_resize]. Note that further resize events may be generated by the time you process the event, so these fields may hold outdated information. ### ALLEGRO_EVENT_DISPLAY_CLOSE The close button of the window has been pressed. display.source (ALLEGRO_DISPLAY *) : The display which was closed. ### ALLEGRO_EVENT_DISPLAY_LOST When using Direct3D, displays can enter a "lost" state. In that state, drawing calls are ignored, and upon entering the state, bitmap's pixel data can become undefined. Allegro does its best to preserve the correct contents of bitmaps (see the ALLEGRO_NO_PRESERVE_TEXTURE flag) and restore them when the device is "found" (see [ALLEGRO_EVENT_DISPLAY_FOUND]). However, this is not 100% fool proof (see discussion in [al_create_bitmap]'s documentation). > *Note:* This event merely means that the display was lost, that is, DirectX suddenly lost the contents of all video bitmaps. In particular, you can keep calling drawing functions -- they just most likely won't do anything. If Allegro's restoration of the bitmaps works well for you then no further action is required when you receive this event. display.source (ALLEGRO_DISPLAY *) : The display which was lost. ### ALLEGRO_EVENT_DISPLAY_FOUND Generated when a lost device is restored to operating state. See [ALLEGRO_EVENT_DISPLAY_LOST]. display.source (ALLEGRO_DISPLAY *) : The display which was found. ### ALLEGRO_EVENT_DISPLAY_SWITCH_OUT The window is no longer active, that is the user might have clicked into another window or "tabbed" away. In response to this event you might want to call [al_clear_keyboard_state] (possibly passing display.source as its argument) in order to prevent Allegro's keyboard state from getting out of sync. display.source (ALLEGRO_DISPLAY *) : The display which was switched out of. ### ALLEGRO_EVENT_DISPLAY_SWITCH_IN The window is the active one again. display.source (ALLEGRO_DISPLAY *) : The display which was switched into. ### ALLEGRO_EVENT_DISPLAY_ORIENTATION Generated when the rotation or orientation of a display changes. display.source (ALLEGRO_DISPLAY *) : The display which generated the event. event.display.orientation : Contains one of the following values: - ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES - ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES - ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES - ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES - ALLEGRO_DISPLAY_ORIENTATION_FACE_UP - ALLEGRO_DISPLAY_ORIENTATION_FACE_DOWN ### ALLEGRO_EVENT_DISPLAY_HALT_DRAWING When a display receives this event it should stop doing any drawing and then call [al_acknowledge_drawing_halt] immediately. This is currently only relevant for Android and iOS. It will be sent when the application is switched to background mode, in addition to [ALLEGRO_EVENT_DISPLAY_SWITCH_OUT]. The latter may also be sent in situations where the application is not active but still should continue drawing, for example when a popup is displayed in front of it. > *Note:* This event means that the next time you call a drawing function, your program will crash. So you *must* stop drawing and you *must* immediately reply with [al_acknowledge_drawing_halt]. Allegro sends this event because it cannot handle this automatically. Your program might be doing the drawing in a different thread from the event handling, in which case the drawing thread needs to be signaled to stop drawing before acknowledging this event. > *Note:* Mobile devices usually never quit an application, so to prevent the battery from draining while your application is halted it can be a good idea to call [al_stop_timer] on all your timers, otherwise they will keep generating events. If you are using audio, you can also stop all audio voices (or pass NULL to [al_set_default_voice] if you use the default mixer), otherwise Allegro will keep streaming silence to the voice even if the stream or mixer are stopped or detached. Since: 5.1.0 See also: [ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING] ### ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING When a display receives this event, it may resume drawing again, and it must call [al_acknowledge_drawing_resume] immediately. This is currently only relevant for Android and iOS. The event will be sent when an application returns from background mode and is allowed to draw to the display again, in addition to [ALLEGRO_EVENT_DISPLAY_SWITCH_IN]. The latter event may also be sent in a situation where the application is already active, for example when a popup in front of it closes. > *Note:* Unlike [ALLEGRO_EVENT_DISPLAY_FOUND] it is not necessary to reload any bitmaps when you receive this event. Since: 5.1.0 See also: [ALLEGRO_EVENT_DISPLAY_HALT_DRAWING] ### ALLEGRO_EVENT_DISPLAY_CONNECTED This event is sent when a physical display is connected to the device Allegro runs on. Currently, on most platforms, Allegro supports only a single physical display. However, on iOS, a secondary physical display is supported. display.source (ALLEGRO_DISPLAY *) : The display which was connected. Since: 5.1.1 ### ALLEGRO_EVENT_DISPLAY_DISCONNECTED This event is sent when a physical display is disconnected from the device Allegro runs on. Currently, on most platforms, Allegro supports only a single physical display. However, on iOS, a secondary physical display is supported. display.source (ALLEGRO_DISPLAY *) : The display which was disconnected. ### ALLEGRO_EVENT_DROP If a display is created with the ALLEGRO_DRAG_AND_DROP flag it will generate ALLEGRO_EVENT_DROP events when files or text are dropped over the display. drop.x (int) : X coordinate that something is being dragged to drop.y (int) : Y coordinate that something is being dragged to drop.text (char *) : the filename or text that was dropped - this will be NULL while the item is being dragged and only set at the final drop. > *Note*: if the *text* field is not NULL ownership transfers to the event receiver and it must eventually be freed with al_free. drop.is_file (bool) : if text is not NULL whether the text is a filename or just plain text. drop.row (int) : if there is multiple files or multiple rows of text this will number them, starting with 0. drop.is_complete (bool) : indicates that this event will be the last one sent for the drag&drop action. If *is_complete* is set before receiving an event where *text* was not NULL it means the user aborted the drag&drop. Since: 5.2.9 > *[Unstable API]:* This is an experimental feature and currently only works for the X11 backend. ## API: ALLEGRO_USER_EVENT An event structure that can be emitted by user event sources. These are the public fields: - ALLEGRO_EVENT_SOURCE *source; - intptr_t data1; - intptr_t data2; - intptr_t data3; - intptr_t data4; Like all other event types this structure is a part of the ALLEGRO_EVENT union. To access the fields in an ALLEGRO_EVENT variable `ev`, you would use: - ev.user.source - ev.user.data1 - ev.user.data2 - ev.user.data3 - ev.user.data4 To create a new user event you would do this: ~~~~c ALLEGRO_EVENT_SOURCE my_event_source; ALLEGRO_EVENT my_event; float some_var; al_init_user_event_source(&my_event_source); my_event.user.type = ALLEGRO_GET_EVENT_TYPE('M','I','N','E'); my_event.user.data1 = 1; my_event.user.data2 = &some_var; al_emit_user_event(&my_event_source, &my_event, NULL); ~~~~ Event type identifiers for user events are assigned by the user. Please see the documentation for [ALLEGRO_GET_EVENT_TYPE] for the rules you should follow when assigning identifiers. See also: [al_emit_user_event], [ALLEGRO_GET_EVENT_TYPE], [al_init_user_event_source] ## API: ALLEGRO_EVENT_QUEUE An event queue holds events that have been generated by event sources that are registered with the queue. Events are stored in the order they are generated. Access is in a strictly FIFO (first-in-first-out) order. See also: [al_create_event_queue], [al_destroy_event_queue] ## API: ALLEGRO_EVENT_SOURCE An event source is any object which can generate events. For example, an ALLEGRO_DISPLAY can generate events, and you can get the ALLEGRO_EVENT_SOURCE pointer from an ALLEGRO_DISPLAY with [al_get_display_event_source]. You may create your own "user" event sources that emit custom events. See also: [ALLEGRO_EVENT], [al_init_user_event_source], [al_emit_user_event] ## API: ALLEGRO_EVENT_TYPE An integer used to distinguish between different types of events. See also: [ALLEGRO_EVENT], [ALLEGRO_GET_EVENT_TYPE], [ALLEGRO_EVENT_TYPE_IS_USER] ## API: ALLEGRO_GET_EVENT_TYPE Make an event type identifier, which is a 32-bit integer. Usually, but not necessarily, this will be made from four 8-bit character codes, for example: ~~~~c #define MY_EVENT_TYPE ALLEGRO_GET_EVENT_TYPE('M','I','N','E') ~~~~ IDs less than 1024 are reserved for Allegro or its addons. Don't use anything lower than `ALLEGRO_GET_EVENT_TYPE(0, 0, 4, 0)`. You should try to make your IDs unique so they don't clash with any 3rd party code you may be using. Be creative. Numbering from 1024 is not creative. If you need multiple identifiers, you could define them like this: ~~~~c #define BASE_EVENT ALLEGRO_GET_EVENT_TYPE('M','I','N','E') #define BARK_EVENT (BASE_EVENT + 0) #define MEOW_EVENT (BASE_EVENT + 1) #define SQUAWK_EVENT (BASE_EVENT + 2) /* Alternatively */ enum { BARK_EVENT = ALLEGRO_GET_EVENT_TYPE('M','I','N','E'), MEOW_EVENT, SQUAWK_EVENT }; ~~~~ See also: [ALLEGRO_EVENT], [ALLEGRO_USER_EVENT], [ALLEGRO_EVENT_TYPE_IS_USER] ## API: ALLEGRO_EVENT_TYPE_IS_USER A macro which evaluates to true if the event type is not a builtin event type, i.e. one of those described in [ALLEGRO_EVENT_TYPE]. ## API: al_create_event_queue Create a new, empty event queue, returning a pointer to the newly created object if successful. Returns NULL on error. See also: [al_register_event_source], [al_destroy_event_queue], [ALLEGRO_EVENT_QUEUE] ## API: al_destroy_event_queue Destroy the event queue specified. All event sources currently registered with the queue will be automatically unregistered before the queue is destroyed. This function does nothing if `queue` is NULL. (since 5.2.9) See also: [al_create_event_queue], [ALLEGRO_EVENT_QUEUE] ## API: al_register_event_source Register the event source with the event queue specified. An event source may be registered with any number of event queues simultaneously, or none. Trying to register an event source with the same event queue more than once does nothing. See also: [al_unregister_event_source], [ALLEGRO_EVENT_SOURCE] ## API: al_unregister_event_source Unregister an event source with an event queue. If the event source is not actually registered with the event queue, nothing happens. If the queue had any events in it which originated from the event source, they will no longer be in the queue after this call. See also: [al_register_event_source] ## API: al_is_event_source_registered Return true if the event source is registered. See also: [al_register_event_source] Since: 5.2.0 ## API: al_pause_event_queue Pause or resume accepting new events into the event queue (to resume, pass false for `pause`). Events already in the queue are unaffected. While a queue is paused, any events which would be entered into the queue are simply ignored. This is an alternative to unregistering then re-registering all event sources from the event queue, if you just need to prevent events piling up in the queue for a while. See also: [al_is_event_queue_paused] Since: 5.1.0 ## API: al_is_event_queue_paused Return true if the event queue is paused. See also: [al_pause_event_queue] Since: 5.1.0 ## API: al_is_event_queue_empty Return true if the event queue specified is currently empty. See also: [al_get_next_event], [al_peek_next_event] ## API: al_get_next_event Take the next event out of the event queue specified, and copy the contents into `ret_event`, returning true. The original event will be removed from the queue. If the event queue is empty, return false and the contents of `ret_event` are unspecified. See also: [ALLEGRO_EVENT], [al_peek_next_event], [al_wait_for_event] ## API: al_peek_next_event Copy the contents of the next event in the event queue specified into `ret_event` and return true. The original event packet will remain at the head of the queue. If the event queue is actually empty, this function returns false and the contents of `ret_event` are unspecified. See also: [ALLEGRO_EVENT], [al_get_next_event], [al_drop_next_event] ## API: al_drop_next_event Drop (remove) the next event from the queue. If the queue is empty, nothing happens. Returns true if an event was dropped. See also: [al_flush_event_queue], [al_is_event_queue_empty] ## API: al_flush_event_queue Drops all events, if any, from the queue. See also: [al_drop_next_event], [al_is_event_queue_empty] ## API: al_wait_for_event Wait until the event queue specified is non-empty. If `ret_event` is not NULL, the first event in the queue will be copied into `ret_event` and removed from the queue. If `ret_event` is NULL the first event is left at the head of the queue. See also: [ALLEGRO_EVENT], [al_wait_for_event_timed], [al_wait_for_event_until], [al_get_next_event] ## API: al_wait_for_event_timed Wait until the event queue specified is non-empty. If `ret_event` is not NULL, the first event in the queue will be copied into `ret_event` and removed from the queue. If `ret_event` is NULL the first event is left at the head of the queue. `secs` determines approximately how many seconds to wait. If the call times out, false is returned. Otherwise, if an event ocurred, true is returned. For compatibility with all platforms, `secs` must be 2,147,483.647 seconds or less. See also: [ALLEGRO_EVENT], [al_wait_for_event], [al_wait_for_event_until] ## API: al_wait_for_event_until Wait until the event queue specified is non-empty. If `ret_event` is not NULL, the first event in the queue will be copied into `ret_event` and removed from the queue. If `ret_event` is NULL the first event is left at the head of the queue. `timeout` determines how long to wait. If the call times out, false is returned. Otherwise, if an event ocurred, true is returned. For compatibility with all platforms, `timeout` must be 2,147,483.647 seconds or less. See also: [ALLEGRO_EVENT], [ALLEGRO_TIMEOUT], [al_init_timeout], [al_wait_for_event], [al_wait_for_event_timed] ## API: al_init_user_event_source Initialise an event source for emitting user events. The space for the event source must already have been allocated. One possible way of creating custom event sources is to derive other structures with ALLEGRO_EVENT_SOURCE at the head, e.g. ~~~~c typedef struct THING THING; struct THING { ALLEGRO_EVENT_SOURCE event_source; int field1; int field2; /* etc. */ }; THING *create_thing(void) { THING *thing = malloc(sizeof(THING)); if (thing) { al_init_user_event_source(&thing->event_source); thing->field1 = 0; thing->field2 = 0; } return thing; } ~~~~ The advantage here is that the THING pointer will be the same as the ALLEGRO_EVENT_SOURCE pointer. Events emitted by the event source will have the event source pointer as the `source` field, from which you can get a pointer to a THING by a simple cast (after ensuring checking the event is of the correct type). However, it is only one technique and you are not obliged to use it. The user event source will never be destroyed automatically. You must destroy it manually with [al_destroy_user_event_source]. See also: [ALLEGRO_EVENT_SOURCE], [al_destroy_user_event_source], [al_emit_user_event], [ALLEGRO_USER_EVENT] ## API: al_destroy_user_event_source Destroy an event source initialised with [al_init_user_event_source]. This does not free the memory, as that was user allocated to begin with. See also: [ALLEGRO_EVENT_SOURCE] ## API: al_emit_user_event Emit an event from a user event source. The event source must have been initialised with [al_init_user_event_source]. Returns `false` if the event source isn't registered with any queues, hence the event wouldn't have been delivered into any queues. Events are *copied* in and out of event queues, so after this function returns the memory pointed to by `event` may be freed or reused. Some fields of the event being passed in may be modified by the function. Reference counting will be performed if `dtor` is not NULL. Whenever a copy of the event is made, the reference count increases. You need to call [al_unref_user_event] to decrease the reference count once you are done with a user event that you have received from [al_get_next_event], [al_peek_next_event], [al_wait_for_event], etc. Once the reference count drops to zero `dtor` will be called with a copy of the event as an argument. It should free the resources associated with the event, but *not* the event itself (since it is just a copy). If `dtor` is NULL then reference counting will not be performed. It is safe, but unnecessary, to call [al_unref_user_event] on non-reference counted user events. You can use al_emit_user_event to emit both user and non-user events from your user event source. Note that emitting input events will not update the corresponding input device states. For example, you may emit an event of type [ALLEGRO_EVENT_KEY_DOWN], but it will not update the [ALLEGRO_KEYBOARD_STATE] returned by [al_get_keyboard_state]. See also: [ALLEGRO_USER_EVENT], [al_unref_user_event] ## API: al_unref_user_event Decrease the reference count of a user-defined event. This must be called on any user event that you get from [al_get_next_event], [al_peek_next_event], [al_wait_for_event], etc. which is reference counted. This function does nothing if the event is not reference counted. See also: [al_emit_user_event], [ALLEGRO_USER_EVENT] ## API: al_get_event_source_data Returns the abstract user data associated with the event source. If no data was previously set, returns NULL. See also: [al_set_event_source_data] ## API: al_set_event_source_data Assign the abstract user data to the event source. Allegro does not use the data internally for anything; it is simply meant as a convenient way to associate your own data or objects with events. See also: [al_get_event_source_data] allegro5-5.2.10.1/docs/src/refman/file.txt000066400000000000000000000371511473414355200201360ustar00rootroot00000000000000# File I/O These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: ALLEGRO_FILE An opaque object representing an open file. This could be a real file on disk or a virtual file. ## API: ALLEGRO_FILE_INTERFACE A structure containing function pointers to handle a type of "file", real or virtual. See the full discussion in [al_set_new_file_interface]. The fields are: ~~~~c void* (*fi_fopen)(const char *path, const char *mode); bool (*fi_fclose)(ALLEGRO_FILE *f); size_t (*fi_fread)(ALLEGRO_FILE *f, void *ptr, size_t size); size_t (*fi_fwrite)(ALLEGRO_FILE *f, const void *ptr, size_t size); bool (*fi_fflush)(ALLEGRO_FILE *f); int64_t (*fi_ftell)(ALLEGRO_FILE *f); bool (*fi_fseek)(ALLEGRO_FILE *f, int64_t offset, int whence); bool (*fi_feof)(ALLEGRO_FILE *f); int (*fi_ferror)(ALLEGRO_FILE *f); const char * (*fi_ferrmsg)(ALLEGRO_FILE *f); void (*fi_fclearerr)(ALLEGRO_FILE *f); int (*fi_fungetc)(ALLEGRO_FILE *f, int c); off_t (*fi_fsize)(ALLEGRO_FILE *f); ~~~~ The fi_open function must allocate memory for whatever userdata structure it needs. The pointer to that memory must be returned; it will then be associated with the file. The other functions can access that data by calling [al_get_file_userdata] on the file handle. If fi_open returns NULL then [al_fopen] will also return NULL. The fi_fclose function must clean up and free the userdata, but Allegro will free the [ALLEGRO_FILE] handle. If fi_fungetc is NULL, then Allegro's default implementation of a 16 char long buffer will be used. ## API: ALLEGRO_SEEK * ALLEGRO_SEEK_SET - seek relative to beginning of file * ALLEGRO_SEEK_CUR - seek relative to current file position * ALLEGRO_SEEK_END - seek relative to end of file See also: [al_fseek] ## API: al_fopen Creates and opens a file (real or virtual) given the path and mode. The current file interface is used to open the file. Parameters: * path - path to the file to open * mode - access mode to open the file in ("r", "w", etc.) Depending on the stream type and the mode string, files may be opened in "text" mode. The handling of newlines is particularly important. For example, using the default stdio-based streams on DOS and Windows platforms, where the native end-of-line terminators are CR+LF sequences, a call to [al_fgetc] may return just one character ('\\n') where there were two bytes (CR+LF) in the file. When writing out '\\n', two bytes would be written instead. (As an aside, '\\n' is not defined to be equal to LF either.) Newline translations can be useful for text files but is disastrous for binary files. To avoid this behaviour you need to open file streams in binary mode by using a mode argument containing a "b", e.g. "rb", "wb". Returns a file handle on success, or NULL on error. See also: [al_set_new_file_interface], [al_fclose]. ## API: al_fopen_interface Opens a file using the specified interface, instead of the interface set with [al_set_new_file_interface]. See also: [al_fopen] ## API: al_fopen_slice Opens a slice (subset) of an already open random access file as if it were a stand alone file. While the slice is open, the parent file handle must not be used in any way. The slice is opened at the current location of the parent file, up through `initial_size` bytes. The `initial_size` may be any non-negative integer that will not exceed the bounds of the parent file. Seeking with `ALLEGRO_SEEK_SET` will be relative to this starting location. `ALLEGRO_SEEK_END` will be relative to the starting location plus the size of the slice. The mode can be any combination of: * r: read access * w: write access * e: expandable * s: seek to the end of the slice upon [al_close] (this is the default behavior) * n: disable the seeking behavior of "s". For example, a mode of "rw" indicates the file can be read and written. (Note that this is slightly different from the stdio modes.) Keep in mind that the parent file must support random access and be open in normal write mode (not append) for the slice to work in a well defined way. If the slice is marked as expandable, then reads and writes can happen after the initial end point, and the slice will grow accordingly. Otherwise, all activity is restricted to the initial size of the slice. A slice must be closed with [al_fclose]. The parent file will then be positioned immediately after the end of the slice. This behavior can be disabled by setting the "n" mode. Since: 5.0.6, 5.1.0 See also: [al_fopen] ## API: al_fclose Close the given file, writing any buffered output data (if any). Returns true on success, false on failure. errno is set to indicate the error. ## API: al_fread Read 'size' bytes into the buffer pointed to by 'ptr', from the given file. Returns the number of bytes actually read. If an error occurs, or the end-of-file is reached, the return value is a short byte count (or zero). al_fread() does not distinguish between EOF and other errors. Use [al_feof] and [al_ferror] to determine which occurred. See also: [al_fgetc], [al_fread16be], [al_fread16le], [al_fread32be], [al_fread32le] ## API: al_fwrite Write 'size' bytes from the buffer pointed to by 'ptr' into the given file. Returns the number of bytes actually written. If an error occurs, the return value is a short byte count (or zero). See also: [al_fputc], [al_fputs], [al_fwrite16be], [al_fwrite16le], [al_fwrite32be], [al_fwrite32le] ## API: al_fflush Flush any pending writes to the given file. Returns true on success, false otherwise. errno is set to indicate the error. See also: [al_get_errno] ## API: al_ftell Returns the current position in the given file, or -1 on error. errno is set to indicate the error. On some platforms this function may not support large files. See also: [al_fseek], [al_get_errno] ## API: al_fseek Set the current position of the given file to a position relative to that specified by 'whence', plus 'offset' number of bytes. 'whence' can be: * ALLEGRO_SEEK_SET - seek relative to beginning of file * ALLEGRO_SEEK_CUR - seek relative to current file position * ALLEGRO_SEEK_END - seek relative to end of file Returns true on success, false on failure. errno is set to indicate the error. After a successful seek, the end-of-file indicator is cleared and all pushback bytes are forgotten. On some platforms this function may not support large files. See also: [al_ftell], [al_get_errno] ## API: al_feof Returns true if the end-of-file indicator has been set on the file, i.e. we have attempted to read *past* the end of the file. This does *not* return true if we simply are at the end of the file. The following code correctly reads two bytes, even when the file contains exactly two bytes: ~~~~c int b1 = al_fgetc(f); int b2 = al_fgetc(f); if (al_feof(f)) { /* At least one byte was unsuccessfully read. */ report_error(); } ~~~~ See also: [al_ferror], [al_fclearerr] ## API: al_ferror Returns non-zero if the error indicator is set on the given file, i.e. there was some sort of previous error. The error code may be system or file interface specific. See also: [al_feof], [al_fclearerr], [al_ferrmsg] ## API: al_ferrmsg Return a message string with details about the last error that occurred on the given file handle. The returned string is empty if there was no error, or if the file interface does not provide more information. See also: [al_fclearerr], [al_ferror] ## API: al_fclearerr Clear the error indicator for the given file. The standard I/O backend also clears the end-of-file indicator, and other backends *should* try to do this. However, they may not if it would require too much effort (e.g. PhysicsFS backend), so your code should not rely on it if you need your code to be portable to other backends. See also: [al_ferror], [al_feof] ## API: al_fungetc Ungets a single byte from a file. Pushed-back bytes are not written to the file, only made available for subsequent reads, in reverse order. The number of pushbacks depends on the backend. The standard I/O backend only guarantees a single pushback; this depends on the libc implementation. For backends that follow the standard behavior, the pushback buffer will be cleared after any seeking or writing; also calls to [al_fseek] and [al_ftell] are relative to the number of pushbacks. If a pushback causes the position to become negative, the behavior of [al_fseek] and [al_ftell] are undefined. See also: [al_fgetc], [al_get_errno] ## API: al_fsize Return the size of the file, if it can be determined, or -1 otherwise. ## API: al_fgetc Read and return next byte in the given file. Returns EOF on end of file or if an error occurred. See also: [al_fungetc] ## API: al_fputc Write a single byte to the given file. The byte written is the value of c cast to an unsigned char. Parameters: * c - byte value to write * f - file to write to Returns the written byte (cast back to an int) on success, or EOF on error. ## API: al_fprintf Writes to a file with stdio "printf"-like formatting. Returns the number of bytes written, or a negative number on error. See also: [al_vfprintf] ## API: al_vfprintf Like al_fprintf but takes a va_list. Useful for creating your own variations of formatted printing. Returns the number of bytes written, or a negative number on error. See also: [al_fprintf] ## API: al_fread16le Reads a 16-bit word in little-endian format (LSB first). On success, returns the 16-bit word. On failure, returns EOF (-1). Since -1 is also a valid return value, use [al_feof] to check if the end of the file was reached prematurely, or [al_ferror] to check if an error occurred. See also: [al_fread16be] ## API: al_fread16be Reads a 16-bit word in big-endian format (MSB first). On success, returns the 16-bit word. On failure, returns EOF (-1). Since -1 is also a valid return value, use [al_feof] to check if the end of the file was reached prematurely, or [al_ferror] to check if an error occurred. See also: [al_fread16le] ## API: al_fwrite16le Writes a 16-bit word in little-endian format (LSB first). Returns the number of bytes written: 2 on success, less than 2 on an error. See also: [al_fwrite16be] ## API: al_fwrite16be Writes a 16-bit word in big-endian format (MSB first). Returns the number of bytes written: 2 on success, less than 2 on an error. See also: [al_fwrite16le] ## API: al_fread32le Reads a 32-bit word in little-endian format (LSB first). On success, returns the 32-bit word. On failure, returns EOF (-1). Since -1 is also a valid return value, use [al_feof] to check if the end of the file was reached prematurely, or [al_ferror] to check if an error occurred. See also: [al_fread32be] ## API: al_fread32be Read a 32-bit word in big-endian format (MSB first). On success, returns the 32-bit word. On failure, returns EOF (-1). Since -1 is also a valid return value, use [al_feof] to check if the end of the file was reached prematurely, or [al_ferror] to check if an error occurred. See also: [al_fread32le] ## API: al_fwrite32le Writes a 32-bit word in little-endian format (LSB first). Returns the number of bytes written: 4 on success, less than 4 on an error. See also: [al_fwrite32be] ## API: al_fwrite32be Writes a 32-bit word in big-endian format (MSB first). Returns the number of bytes written: 4 on success, less than 4 on an error. See also: [al_fwrite32le] ## API: al_fgets Read a string of bytes terminated with a newline or end-of-file into the buffer given. The line terminator(s), if any, are included in the returned string. A maximum of max-1 bytes are read, with one byte being reserved for a NUL terminator. Parameters: * f - file to read from * buf - buffer to fill * max - maximum size of buffer Returns the pointer to buf on success. Returns NULL if an error occurred or if the end of file was reached without reading any bytes. See [al_fopen] about translations of end-of-line characters. See also: [al_fget_ustr] ## API: al_fget_ustr Read a string of bytes terminated with a newline or end-of-file. The line terminator(s), if any, are included in the returned string. On success returns a pointer to a new ALLEGRO_USTR structure. This must be freed eventually with [al_ustr_free]. Returns NULL if an error occurred or if the end of file was reached without reading any bytes. See [al_fopen] about translations of end-of-line characters. See also: [al_fgetc], [al_fgets] ## API: al_fputs Writes a string to file. Apart from the return value, this is equivalent to: ~~~~c al_fwrite(f, p, strlen(p)); ~~~~ Parameters: * f - file handle to write to * p - string to write Returns a non-negative integer on success, EOF on error. Note: depending on the stream type and the mode passed to [al_fopen], newline characters in the string may or may not be automatically translated to native end-of-line sequences, e.g. CR/LF instead of LF. See also: [al_fwrite] ## Standard I/O specific routines ### API: al_fopen_fd Create an [ALLEGRO_FILE] object that operates on an open file descriptor using stdio routines. See the documentation of fdopen() for a description of the 'mode' argument. Returns an ALLEGRO_FILE object on success or NULL on an error. On an error, the Allegro errno will be set and the file descriptor will not be closed. The file descriptor will be closed by [al_fclose] so you should not call close() on it. See also: [al_fopen] ### API: al_make_temp_file Make a temporary randomly named file given a filename 'template'. 'template' is a string giving the format of the generated filename and should include one or more capital Xs. The Xs are replaced with random alphanumeric characters, produced using a simple pseudo-random number generator only. There should be no path separators. If 'ret_path' is not NULL, the address it points to will be set to point to a new path structure with the name of the temporary file. Returns the opened [ALLEGRO_FILE] on success, NULL on failure. ## Alternative file streams By default, the Allegro file I/O routines use the C library I/O routines, hence work with files on the local filesystem, but can be overridden so that you can read and write to other streams. For example, you can work with blocks of memory or sub-files inside .zip files. There are two ways to get an [ALLEGRO_FILE] that doesn't use stdio. An addon library may provide a function that returns a new ALLEGRO_FILE directly, after which, all al_f* calls on that object will use overridden functions for that type of stream. Alternatively, [al_set_new_file_interface] changes which function will handle the following [al_fopen] calls for the current thread. ### API: al_set_new_file_interface Set the [ALLEGRO_FILE_INTERFACE] table for the calling thread. This will change the handler for later calls to [al_fopen]. See also: [al_set_standard_file_interface], [al_store_state], [al_restore_state]. ### API: al_set_standard_file_interface Set the [ALLEGRO_FILE_INTERFACE] table to the default, for the calling thread. This will change the handler for later calls to [al_fopen]. See also: [al_set_new_file_interface] ### API: al_get_new_file_interface Return a pointer to the [ALLEGRO_FILE_INTERFACE] table in effect for the calling thread. See also: [al_store_state], [al_restore_state]. ### API: al_create_file_handle Creates an empty, opened file handle with some abstract user data. This allows custom interfaces to extend the [ALLEGRO_FILE] struct with their own data. You should close the handle with the standard [al_fclose] function when you are finished with it. See also: [al_fopen], [al_fclose], [al_set_new_file_interface] ### API: al_get_file_userdata Returns a pointer to the custom userdata that is attached to the file handle. This is intended to be used by functions that extend [ALLEGRO_FILE_INTERFACE]. allegro5-5.2.10.1/docs/src/refman/fixed.txt000066400000000000000000000326231473414355200203150ustar00rootroot00000000000000# Fixed point math routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: al_fixed A fixed point number. Allegro provides some routines for working with fixed point numbers, and defines the type `al_fixed` to be a signed 32-bit integer. The high word is used for the integer part and the low word for the fraction, giving a range of -32768 to 32767 and an accuracy of about four or five decimal places. Fixed point numbers can be assigned, compared, added, subtracted, negated and shifted (for multiplying or dividing by powers of two) using the normal integer operators, but you should take care to use the appropriate conversion routines when mixing fixed point with integer or floating point values. Writing `fixed_point_1 + fixed_point_2` is OK, but `fixed_point + integer` is not. The only advantage of fixed point math routines is that you don't require a floating point coprocessor to use them. This was great in the time period of i386 and i486 machines, but stopped being so useful with the coming of the Pentium class of processors. From Pentium onwards, CPUs have increased their strength in floating point operations, equaling or even surpassing integer math performance. However, many embedded processors have no FPUs so fixed point maths can still be useful there. Depending on the type of operations your program may need, using floating point types may be faster than fixed types if you are targeting a specific machine class. ## API: al_itofix Converts an integer to fixed point. This is the same thing as x<<16. Remember that overflows (trying to convert an integer greater than 32767) and underflows (trying to convert an integer lesser than -32768) are not detected even in debug builds! The values simply "wrap around". Example: ~~~~c al_fixed number; /* This conversion is OK. */ number = al_itofix(100); assert(al_fixtoi(number) == 100); number = al_itofix(64000); /* This check will fail in debug builds. */ assert(al_fixtoi(number) == 64000); ~~~~ Return value: Returns the value of the integer converted to fixed point ignoring overflows. See also: [al_fixtoi], [al_ftofix], [al_fixtof]. ## API: al_fixtoi Converts fixed point to integer, rounding as required to the nearest integer. Example: ~~~~c int result; /* This will put 33 into `result'. */ result = al_fixtoi(al_itofix(100) / 3); /* But this will round up to 17. */ result = al_fixtoi(al_itofix(100) / 6); ~~~~ See also: [al_itofix], [al_ftofix], [al_fixtof], [al_fixfloor], [al_fixceil]. ## API: al_fixfloor Returns the greatest integer not greater than x. That is, it rounds towards negative infinity. Example: ~~~~c int result; /* This will put 33 into `result'. */ result = al_fixfloor(al_itofix(100) / 3); /* And this will round down to 16. */ result = al_fixfloor(al_itofix(100) / 6); ~~~~ See also: [al_fixtoi], [al_fixceil]. ## API: al_fixceil Returns the smallest integer not less than x. That is, it rounds towards positive infinity. Example: ~~~~c int result; /* This will put 34 into `result'. */ result = al_fixceil(al_itofix(100) / 3); /* This will round up to 17. */ result = al_fixceil(al_itofix(100) / 6); ~~~~ See also: [al_fixtoi], [al_fixfloor]. ## API: al_ftofix Converts a floating point value to fixed point. Unlike [al_itofix], this function clamps values which could overflow the type conversion, setting Allegro's errno to ERANGE in the process if this happens. Example: ~~~~c al_fixed number; number = al_itofix(-40000); assert(al_fixfloor(number) == -32768); number = al_itofix(64000); assert(al_fixfloor(number) == 32767); assert(!al_get_errno()); /* This will fail. */ ~~~~ Return value: Returns the value of the floating point value converted to fixed point clamping overflows (and setting Allegro's errno). See also: [al_fixtof], [al_itofix], [al_fixtoi], [al_get_errno] ## API: al_fixtof Converts fixed point to floating point. Example: ~~~~c float result; /* This will put 33.33333 into `result'. */ result = al_fixtof(al_itofix(100) / 3); /* This will put 16.66666 into `result'. */ result = al_fixtof(al_itofix(100) / 6); ~~~~ See also: [al_ftofix], [al_itofix], [al_fixtoi]. ## API: al_fixmul A fixed point value can be multiplied or divided by an integer with the normal `*` and `/` operators. To multiply two fixed point values, though, you must use this function. If an overflow occurs, Allegro's errno will be set and the maximum possible value will be returned, but errno is not cleared if the operation is successful. This means that if you are going to test for overflow you should call `al_set_errno(0)` before calling [al_fixmul]. Example: ~~~~c al_fixed result; /* This will put 30000 into `result'. */ result = al_fixmul(al_itofix(10), al_itofix(3000)); /* But this overflows, and sets errno. */ result = al_fixmul(al_itofix(100), al_itofix(3000)); assert(!al_get_errno()); ~~~~ Return value: Returns the clamped result of multiplying `x` by `y`, setting Allegro's errno to ERANGE if there was an overflow. See also: [al_fixadd], [al_fixsub], [al_fixdiv], [al_get_errno]. ## API: al_fixdiv A fixed point value can be divided by an integer with the normal `/` operator. To divide two fixed point values, though, you must use this function. If a division by zero occurs, Allegro's errno will be set and the maximum possible value will be returned, but errno is not cleared if the operation is successful. This means that if you are going to test for division by zero you should call `al_set_errno(0)` before calling [al_fixdiv]. Example: ~~~~c al_fixed result; /* This will put 0.06060 `result'. */ result = al_fixdiv(al_itofix(2), al_itofix(33)); /* This will put 0 into `result'. */ result = al_fixdiv(0, al_itofix(-30)); /* Sets errno and puts -32768 into `result'. */ result = al_fixdiv(al_itofix(-100), al_itofix(0)); assert(!al_get_errno()); /* This will fail. */ ~~~~ Return value: Returns the result of dividing `x` by `y`. If `y` is zero, returns the maximum possible fixed point value and sets Allegro's errno to ERANGE. See also: [al_fixadd], [al_fixsub], [al_fixmul], [al_get_errno]. ## API: al_fixadd Although fixed point numbers can be added with the normal `+` integer operator, that doesn't provide any protection against overflow. If overflow is a problem, you should use this function instead. It is slower than using integer operators, but if an overflow occurs it will set Allegro's errno and clamp the result, rather than just letting it wrap. Example: ~~~~c al_fixed result; /* This will put 5035 into `result'. */ result = al_fixadd(al_itofix(5000), al_itofix(35)); /* Sets errno and puts -32768 into `result'. */ result = al_fixadd(al_itofix(-31000), al_itofix(-3000)); assert(!al_get_errno()); /* This will fail. */ ~~~~ Return value: Returns the clamped result of adding `x` to `y`, setting Allegro's errno to ERANGE if there was an overflow. See also: [al_fixsub], [al_fixmul], [al_fixdiv]. ## API: al_fixsub Although fixed point numbers can be subtracted with the normal `-` integer operator, that doesn't provide any protection against overflow. If overflow is a problem, you should use this function instead. It is slower than using integer operators, but if an overflow occurs it will set Allegro's errno and clamp the result, rather than just letting it wrap. Example: ~~~~c al_fixed result; /* This will put 4965 into `result'. */ result = al_fixsub(al_itofix(5000), al_itofix(35)); /* Sets errno and puts -32768 into `result'. */ result = al_fixsub(al_itofix(-31000), al_itofix(3000)); assert(!al_get_errno()); /* This will fail. */ ~~~~ Return value: Returns the clamped result of subtracting `y` from `x`, setting Allegro's errno to ERANGE if there was an overflow. See also: [al_fixadd], [al_fixmul], [al_fixdiv], [al_get_errno]. ## Fixed point trig The fixed point square root, sin, cos, tan, inverse sin, and inverse cos functions are implemented using lookup tables, which are very fast but not particularly accurate. At the moment the inverse tan uses an iterative search on the tan table, so it is a lot slower than the others. On machines with good floating point processors using these functions could be slower Always profile your code. Angles are represented in a binary format with 256 equal to a full circle, 64 being a right angle and so on. This has the advantage that a simple bitwise 'and' can be used to keep the angle within the range zero to a full circle. ### API: al_fixtorad_r This constant gives a ratio which can be used to convert a fixed point number in binary angle format to a fixed point number in radians. Example: ~~~~c al_fixed rad_angle, binary_angle; /* Set the binary angle to 90 degrees. */ binary_angle = 64; /* Now convert to radians (about 1.57). */ rad_angle = al_fixmul(binary_angle, al_fixtorad_r); ~~~~ See also: [al_fixmul], [al_radtofix_r]. ### API: al_radtofix_r This constant gives a ratio which can be used to convert a fixed point number in radians to a fixed point number in binary angle format. Example: ~~~~ al_fixed rad_angle, binary_angle; ... binary_angle = al_fixmul(rad_angle, radtofix_r); ~~~~ See also: [al_fixmul], [al_fixtorad_r]. ### API: al_fixsin This function finds the sine of a value using a lookup table. The input value must be a fixed point binary angle. Example: ~~~~c al_fixed angle; int result; /* Set the binary angle to 90 degrees. */ angle = al_itofix(64); /* The sine of 90 degrees is one. */ result = al_fixtoi(al_fixsin(angle)); assert(result == 1); ~~~~ Return value: Returns the sine of a fixed point binary format angle as a fixed point value. ### API: al_fixcos This function finds the cosine of a value using a lookup table. The input value must be a fixed point binary angle. Example: ~~~~c al_fixed angle; float result; /* Set the binary angle to 45 degrees. */ angle = al_itofix(32); /* The cosine of 45 degrees is about 0.7071. */ result = al_fixtof(al_fixcos(angle)); assert(result > 0.7 && result < 0.71); ~~~~ Return value: Returns the cosine of a fixed point binary format angle as a fixed point value. ### API: al_fixtan This function finds the tangent of a value using a lookup table. The input value must be a fixed point binary angle. Example: ~~~~c al_fixed angle, res_a, res_b; float dif; angle = al_itofix(37); /* Prove that tan(angle) == sin(angle) / cos(angle). */ res_a = al_fixdiv(al_fixsin(angle), al_fixcos(angle)); res_b = al_fixtan(angle); dif = al_fixtof(al_fixsub(res_a, res_b)); printf("Precision error: %f\n", dif); ~~~~ Return value: Returns the tangent of a fixed point binary format angle as a fixed point value. ### API: al_fixasin This function finds the inverse sine of a value using a lookup table. The input value must be a fixed point value. The inverse sine is defined only in the domain from -1 to 1. Outside of this input range, the function will set Allegro's errno to EDOM and return zero. Example: ~~~~c float angle; al_fixed val; /* Sets `val' to a right binary angle (64). */ val = al_fixasin(al_itofix(1)); /* Sets `angle' to 0.2405. */ angle = al_fixtof(al_fixmul(al_fixasin(al_ftofix(0.238)), al_fixtorad_r)); /* This will trigger the assert. */ val = al_fixasin(al_ftofix(-1.09)); assert(!al_get_errno()); ~~~~ Return value: Returns the inverse sine of a fixed point value, measured as fixed point binary format angle, or zero if the input was out of the range. All return values of this function will be in the range -64 to 64. ### API: al_fixacos This function finds the inverse cosine of a value using a lookup table. The input must be a fixed point value. The inverse cosine is defined only in the domain from -1 to 1. Outside of this input range, the function will set Allegro's errno to EDOM and return zero. Example: ~~~~c al_fixed result; /* Sets result to binary angle 128. */ result = al_fixacos(al_itofix(-1)); ~~~~ Return value: Returns the inverse sine of a fixed point value, measured as fixed point binary format angle, or zero if the input was out of range. All return values of this function will be in the range 0 to 128. ### API: al_fixatan This function finds the inverse tangent of a value using a lookup table. The input must be a fixed point value. The inverse tangent is the value whose tangent is `x`. Example: ~~~~c al_fixed result; /* Sets result to binary angle 13. */ result = al_fixatan(al_ftofix(0.326)); ~~~~ Return value: Returns the inverse tangent of a fixed point value, measured as a fixed point binary format angle. ### API: al_fixatan2 This is a fixed point version of the libc atan2() routine. It computes the arc tangent of `y / x`, but the signs of both arguments are used to determine the quadrant of the result, and `x` is permitted to be zero. This function is useful to convert Cartesian coordinates to polar coordinates. Example: ~~~~c al_fixed result; /* Sets `result' to binary angle 64. */ result = al_fixatan2(al_itofix(1), 0); /* Sets `result' to binary angle -109. */ result = al_fixatan2(al_itofix(-1), al_itofix(-2)); /* Fails the assert. */ result = al_fixatan2(0, 0); assert(!al_get_errno()); ~~~~ Return value: Returns the arc tangent of `y / x` in fixed point binary format angle, from -128 to 128. If both `x` and `y` are zero, returns zero and sets Allegro's errno to EDOM. ### API: al_fixsqrt This finds out the non negative square root of `x`. If `x` is negative, Allegro's errno is set to EDOM and the function returns zero. ### API: al_fixhypot Fixed point hypotenuse (returns the square root of `x*x + y*y`). This should be better than calculating the formula yourself manually, since the error is much smaller. allegro5-5.2.10.1/docs/src/refman/font.txt000066400000000000000000000665131473414355200201710ustar00rootroot00000000000000# Font addons These functions are declared in the following header file. Link with allegro_font. ~~~~c #include ~~~~ ## General font routines ### API: ALLEGRO_FONT A handle identifying any kind of font. Usually you will create it with [al_load_font] which supports loading all kinds of TrueType fonts supported by the FreeType library. If you instead pass the filename of a bitmap file, it will be loaded with [al_load_bitmap] and a font in Allegro's bitmap font format will be created from it with [al_grab_font_from_bitmap]. ### API: ALLEGRO_GLYPH A structure containing the properties of a character in a font. ~~~~c typedef struct ALLEGRO_GLYPH { ALLEGRO_BITMAP *bitmap; // the bitmap the character is on int x; // the x position of the glyph on bitmap int y; // the y position of the glyph on bitmap int w; // the width of the glyph in pixels int h; // the height of the glyph in pixels int kerning; // pixels of kerning (see below) int offset_x; // x offset to draw the glyph at int offset_y; // y offset to draw the glyph at int advance; // number of pixels to advance after this character } ALLEGRO_GLYPH; ~~~~ bitmap may be a sub-bitmap in the case of color fonts. Bitmap can also be NULL in which case nothing should be drawn (sometimes true for whitespace characters in TTF fonts). kerning should be added to the x position you draw to if you want your text kerned and depends on which codepoints [al_get_glyph] was called with. Glyphs are tightly packed onto the bitmap, so you need to add offset_x and offset_y to your draw position for the text to look right. advance is the number of pixels to add to your x position to advance to the next character in a string and includes kerning. Since: 5.2.1 > *[Unstable API]:* This API is new and subject to refinement. See also: [al_get_glyph] ### API: al_init_font_addon Initialise the font addon. Note that if you intend to load bitmap fonts, you will need to initialise allegro_image separately (unless you are using another library to load images). Similarly, if you wish to load truetype-fonts, do not forget to also call [al_init_ttf_addon]. Returns true on success, false on failure. On the 5.0 branch, this function has no return value. You may wish to avoid checking the return value if your code needs to be compatible with Allegro 5.0. Currently, the function will never return false. See also: [al_init_image_addon], [al_init_ttf_addon], [al_shutdown_font_addon] ### API: al_is_font_addon_initialized Returns true if the font addon is initialized, otherwise returns false. Since: 5.2.6 See also: [al_init_font_addon], [al_shutdown_font_addon] ### API: al_shutdown_font_addon Shut down the font addon. This is done automatically at program exit, but can be called any time the user wishes as well. See also: [al_init_font_addon] ### API: al_load_font Loads a font from disk. This will use [al_load_bitmap_font_flags] if you pass the name of a known bitmap format, or else [al_load_ttf_font]. The flags parameter is passed through to either of those functions. Bitmap and TTF fonts are also affected by the current [bitmap flags][al_set_new_bitmap_flags] at the time the font is loaded. See also: [al_destroy_font], [al_init_font_addon], [al_register_font_loader], [al_load_bitmap_font_flags], [al_load_ttf_font] ### API: al_destroy_font Frees the memory being used by a font structure. Does nothing if passed NULL. See also: [al_load_font] ### API: al_register_font_loader Informs Allegro of a new font file type, telling it how to load files of this format. The `extension` should include the leading dot ('.') character. It will be matched case-insensitively. The `load_font` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. See also: [al_init_font_addon] ### API: al_get_font_line_height Returns the usual height of a line of text in the specified font. For bitmap fonts this is simply the height of all glyph bitmaps. For truetype fonts it is whatever the font file specifies. In particular, some special glyphs may be higher than the height returned here. If the X is the position you specify to draw text, the meaning of ascent and descent and the line height is like in the figure below. X------------------------ /\ | | / \ | | /____\ ascent | / \ | | / \ | height ---------------- | | | descent | | | ------------------------- See also: [al_get_text_width], [al_get_text_dimensions] ### API: al_get_font_ascent Returns the ascent of the specified font. See also: [al_get_font_descent], [al_get_font_line_height] ### API: al_get_font_descent Returns the descent of the specified font. See also: [al_get_font_ascent], [al_get_font_line_height] ### API: al_get_text_width Calculates the length of a string in a particular font, in pixels. See also: [al_get_ustr_width], [al_get_font_line_height], [al_get_text_dimensions] ### API: al_get_ustr_width Like [al_get_text_width] but expects an ALLEGRO_USTR. See also: [al_get_text_width], [al_get_ustr_dimensions] ### API: al_draw_text Writes the NUL-terminated string `text` onto the target bitmap at position `x`, `y`, using the specified `font`. The `flags` parameter can be 0 or one of the following flags: - ALLEGRO_ALIGN_LEFT - Draw the text left-aligned (same as 0). - ALLEGRO_ALIGN_CENTRE - Draw the text centered around the given position. - ALLEGRO_ALIGN_RIGHT - Draw the text right-aligned to the given position. It can also be combined with this flag: - ALLEGRO_ALIGN_INTEGER - Always draw text aligned to an integer pixel position. This was formerly the default behaviour. Since: 5.0.8, 5.1.4 This function does not support newline characters (`\n`), but you can use [al_draw_multiline_text] for multi line text output. See also: [al_draw_ustr], [al_draw_textf], [al_draw_justified_text], [al_draw_multiline_text]. ### API: al_draw_ustr Like [al_draw_text], except the text is passed as an ALLEGRO_USTR instead of a NUL-terminated char array. See also: [al_draw_text], [al_draw_justified_ustr], [al_draw_multiline_ustr] ### API: al_draw_justified_text Like [al_draw_text], but justifies the string to the region x1-x2. The `diff` parameter is the maximum amount of horizontal space to allow between words. If justisfying the text would exceed `diff` pixels, or the string contains less than two words, then the string will be drawn left aligned. The `flags` parameter can be 0 or one of the following flags: - ALLEGRO_ALIGN_INTEGER - Draw text aligned to integer pixel positions. Since: 5.0.8, 5.1.5 See also: [al_draw_justified_textf], [al_draw_justified_ustr] ### API: al_draw_justified_ustr Like [al_draw_justified_text], except the text is passed as an ALLEGRO_USTR instead of a NUL-terminated char array. See also: [al_draw_justified_text], [al_draw_justified_textf]. ### API: al_draw_textf Formatted text output, using a printf() style format string. All parameters have the same meaning as with [al_draw_text] otherwise. See also: [al_draw_text], [al_draw_ustr] ### API: al_draw_justified_textf Formatted text output, using a printf() style format string. All parameters have the same meaning as with [al_draw_justified_text] otherwise. See also: [al_draw_justified_text], [al_draw_justified_ustr]. ### API: al_get_text_dimensions Sometimes, the [al_get_text_width] and [al_get_font_line_height] functions are not enough for exact text placement, so this function returns some additional information. Returned variables (all in pixels): - x, y - Offset to upper left corner of bounding box. - w, h - Dimensions of bounding box. Note that glyphs may go to the left and upwards of the X, in which case x and y will have negative values. See also: [al_get_text_width], [al_get_font_line_height], [al_get_ustr_dimensions] ### API: al_get_ustr_dimensions Like [al_get_text_dimensions], except the text is passed as an ALLEGRO_USTR instead of a NUL-terminated char array. See also: [al_get_text_dimensions] ### API: al_get_allegro_font_version Returns the (compiled) version of the addon, in the same format as [al_get_allegro_version]. ### API: al_get_font_ranges Gets information about all glyphs contained in a font, as a list of ranges. Ranges have the same format as with [al_grab_font_from_bitmap]. `ranges_count` is the maximum number of ranges that will be returned. `ranges` should be an array with room for `ranges_count` * 2 elements. The even integers are the first unicode point in a range, the odd integers the last unicode point in a range. Returns the number of ranges contained in the font (even if it is bigger than `ranges_count`). Since: 5.1.4 See also: [al_grab_font_from_bitmap] ### API: al_set_fallback_font Sets a font which is used instead if a character is not present. Can be chained, but make sure there is no loop as that would crash the application! Pass NULL to remove a fallback font again. Since: 5.1.12 See also: [al_get_fallback_font], [al_draw_glyph], [al_draw_text] ### API: al_get_fallback_font Retrieves the fallback font for this font or NULL. Since: 5.1.12 See also: [al_set_fallback_font] ## Per glyph text handling For some applications Allegro's text drawing functions may not be sufficient. For example, you would like to give a different color to every letter in a word, or use different a font for a drop cap. That is why Allegro supports drawing and getting the dimensions of the individual glyphs of a font. A glyph is a particular visual representation of a letter, character or symbol in a specific font. And it's also possible to get the kerning to use between two glyphs. These per glyph functions have less overhead than Allegro's per string text drawing and dimensioning functions. So, with these functions you can write your own efficient and precise custom text drawing functions. ### API: al_draw_glyph Draws the glyph that corresponds with `codepoint` in the given `color` using the given `font`. If `font` does not have such a glyph, nothing will be drawn. To draw a string as left to right horizontal text you will need to use [al_get_glyph_advance] to determine the position of each glyph. For drawing strings in other directions, such as top to down, use [al_get_glyph_dimensions] to determine the size and position of each glyph. If you have to draw many glyphs at the same time, use [al_hold_bitmap_drawing] with true as the parameter, before drawing the glyphs, and then call [al_hold_bitmap_drawing] again with false as a parameter when done drawing the glyphs to further enhance performance. Since: 5.1.12 See also: [al_get_glyph_width], [al_get_glyph_dimensions], [al_get_glyph_advance]. ### API: al_get_glyph_width This function returns the width in pixels of the glyph that corresponds with `codepoint` in the font `font`. Returns zero if the font does not have such a glyph. Since: 5.1.12 See also: [al_draw_glyph], [al_get_glyph_dimensions], [al_get_glyph_advance]. ### API: al_get_glyph_dimensions Sometimes, the [al_get_glyph_width] or [al_get_glyph_advance] functions are not enough for exact glyph placement, so this function returns some additional information, particularly if you want to draw the font vertically. The function itself returns true if the character was present in `font` and false if the character was not present in `font`. Returned variables (all in pixel): - bbx, bby - Offset to upper left corner of bounding box. - bbw, bbh - Dimensions of bounding box. These values are the same as [al_get_text_dimensions] would return for a string of a single character equal to the glyph passed to this function. Note that glyphs may go to the left and upwards of the X, in which case x and y will have negative values. If you want to draw a string verticallly, for Japanese or as a game effect, then you should leave bby + bbh space between the glyphs in the y direction for a regular placement. If you want to draw a string horizontally in an extra compact way, then you should leave bbx + bbw space between the glyphs in the x direction for a compact placement. In the figure below is an example of what bbx and bby may be like for a `2` glyph, and a `g` glyph of the same font compared to the result of al_get_glyph_width(). al_get_glyph_width() al_get_glyph_width() __|___ __|__ / \ / \ bbx bbw bbx bbw <-->+<------>+ <-->+<----->+ X baseline ^ | | ^ | | bby | | | bby | | | v | | | | | +---+--------+ | | | ^ | ***** | | | | | |* ** | v | | bbh | | ** | bbh +---+-------+ | | ** | ^ | ***** | v |********| | |* *| +---+--------+ | | ***** | | | *| | | * *| v | **** | +---+-------+ Since: 5.1.12 See also: [al_draw_glyph], [al_get_glyph_width], [al_get_glyph_advance]. ### API: al_get_glyph_advance This function returns by how much the x position should be advanced for left to right text drawing when the glyph that corresponds to codepoint1 has been drawn, and the glyph that corresponds to codepoint2 will be the next to be drawn. This takes into consideration the horizontal advance width of the glyph that corresponds with codepoint1 as well as the kerning between the glyphs of codepoint1 and codepoint2. Kerning is the process of adjusting the spacing between glyphs in a font, to obtain a more visually pleasing result. Kerning adjusts the space between two individual glyphs with an offset determined by the author of the font. If you pass ALLEGRO_NO_KERNING as codepoint1 then al_get_glyph_advance will return 0. this can be useful when drawing the first character of a string in a loop. Pass ALLEGRO_NO_KERNING as codepoint2 to get the horizontal advance width of the glyph that corresponds to codepoint1 without taking any kerning into consideration. This can be used, for example, when drawing the last character of a string in a loop. This function will return zero if the glyph of codepoint1 is not present in the `font`. If the glyph of codepoint2 is not present in the font, the horizontal advance width of the glyph that corresponds to codepoint1 without taking any kerning into consideration is returned. When drawing a string one glyph at the time from the left to the right with kerning, the x position of the glyph should be incremented by the result of [al_get_glyph_advance] applied to the previous glyph drawn and the next glyph to draw. Note that the return value of this function is a recommended advance for optimal readability for left to right text determined by the author of the font. However, if you like, you may want to draw the glyphs of the font narrower or wider to each other than what [al_get_glyph_advance] returns for style or effect. In the figure below is an example of what the result of al_get_glyph_advance may be like for two glypphs `A` and `l` of the same font that has kerning for the "Al" pair, without and with the ALLEGRO_NO_KERNING flag. al_get_glyph_advance(font, 'A', 'l') ___|___ / \ ------------- /\ -| / \ | /____\ | / \ | / \ \_ ------------- al_get_glyph_advance(font, 'A', ALLEGRO_NO_KERNING) ____|____ / \ --------------- /\ -| / \ | /____\ | / \ | / \ \_ --------------- Since: 5.1.12 See also: [al_draw_glyph], [al_get_glyph_width], [al_get_glyph_dimensions]. ## Multiline text drawing ### API: al_draw_multiline_text Like [al_draw_text], but this function supports drawing multiple lines of text. It will break `text` in lines based on its contents and the `max_width` parameter. The lines are then layed out vertically depending on the `line_height` parameter and drawn each as if [al_draw_text] was called on them. A newline `\n` in the `text` will cause a "hard" line break after its occurrence in the string. The text after a hard break is placed on a new line. Carriage return `\r` is not supported, will not cause a line break, and will likely be drawn as a square or a space depending on the font. The `max_width` parameter controls the maximum desired width of the lines. This function will try to introduce a "soft" line break after the longest possible series of words that will fit in `max_length` when drawn with the given `font`. A "soft" line break can occur either on a space or tab (`\t`) character. However, it is possible that `max_width` is too small, or the words in `text` are too long to fit `max_width` when drawn with `font`. In that case, the word that is too wide will simply be drawn completely on a line by itself. If you don't want the text that overflows `max_width` to be visible, then use [al_set_clipping_rectangle] to clip it off and hide it. The lines `text` was split into will each be drawn using the `font`, `x`, `color` and `flags` parameters, vertically starting at `y` and with a distance of `line_height` between them. If `line_height` is zero (`0`), the value returned by calling [al_get_font_line_height] on `font` will be used as a default instead. The `flags` ALLEGRO_ALIGN_LEFT, ALLEGRO_ALIGN_CENTRE, ALLEGRO_ALIGN_RIGHT and ALLEGRO_ALIGN_INTEGER will be honoured by this function. If you want to calculate the size of what this function will draw without actually drawing it, or if you need a complex and/or custom layout, you can use [al_do_multiline_text]. Since: 5.1.9 See also: [al_do_multiline_text], [al_draw_multiline_ustr], [al_draw_multiline_textf] ### API: al_draw_multiline_ustr Like [al_draw_multiline_text], except the text is passed as an ALLEGRO_USTR instead of a NUL-terminated char array. Since: 5.1.9 See also: [al_draw_multiline_text], [al_draw_multiline_textf], [al_do_multiline_text] ### API: al_draw_multiline_textf Formatted text output, using a printf() style format string. All parameters have the same meaning as with [al_draw_multiline_text] otherwise. Since: 5.1.9 See also: [al_draw_multiline_text], [al_draw_multiline_ustr], [al_do_multiline_text] ### API: al_do_multiline_text This function processes the `text` and splits it into lines as [al_draw_multiline_text] would, and then calls the callback `cb` once for every line. This is useful for custom drawing of multiline text, or for calculating the size of multiline text ahead of time. See the documentation on [al_draw_multiline_text] for an explanation of the splitting algorithm. For every line that this function splits `text` into the callback `cb` will be called once with the following parameters: - `line_num` - the number of the line starting from zero and counting up - `line` - a pointer to the beginning character of the line (see below) - `size` - the size of the line (0 for empty lines) - `extra` - the same pointer that was passed to al_do_multiline_text Note that `line` is *not* guaranteed to be a NUL-terminated string, but will merely point to a character within `text` or to an empty string in case of an empty line. If you need a NUL-terminated string, you will have to copy `line` to a buffer and NUL-terminate it yourself. You will also have to make your own copy if you need the contents of `line` after `cb` has returned, as `line` is *not* guaranteed to be valid after that. If the callback `cb` returns false, al_do_multiline_text will stop immediately, otherwise it will continue on to the next line. Since: 5.1.9 See also: [al_draw_multiline_text] ### API: al_do_multiline_ustr Like [al_do_multiline_text], but using ALLEGRO_USTR instead of a NUL-terminated char array for text. Since: 5.1.9 See also: [al_draw_multiline_ustr] ## Bitmap fonts ### API: al_grab_font_from_bitmap Creates a new font from an Allegro bitmap. You can delete the bitmap after the function returns as the font will contain a copy for itself. Parameters: - bmp: The bitmap with the glyphs drawn onto it - n: Number of unicode ranges in the bitmap. - ranges: 'n' pairs of first and last unicode point to map glyphs to for each range. The bitmap format is as in the following example, which contains three glyphs for 1, 2 and 3. ............. . 1 .222.333. . 1 . 2. 3. . 1 .222.333. . 1 .2 . 3. . 1 .222.333. ............. In the above illustration, the dot is for pixels having the background color. It is determined by the color of the top left pixel in the bitmap. There should be a border of at least 1 pixel with this color to the bitmap edge and between all glyphs. Each glyph is inside a rectangle of pixels not containing the background color. The height of all glyph rectangles should be the same, but the width can vary. The placement of the rectangles does not matter, except that glyphs are scanned from left to right and top to bottom to match them to the specified unicode codepoints. The glyphs will simply be drawn using [al_draw_bitmap], so usually you will want the rectangles filled with full transparency and the glyphs drawn in opaque white. Examples: ~~~~c int ranges[] = {32, 126}; al_grab_font_from_bitmap(bitmap, 1, ranges) int ranges[] = { 0x0020, 0x007F, /* ASCII */ 0x00A1, 0x00FF, /* Latin 1 */ 0x0100, 0x017F, /* Extended-A */ 0x20AC, 0x20AC}; /* Euro */ al_grab_font_from_bitmap(bitmap, 4, ranges) ~~~~ The first example will grab glyphs for the 95 standard printable ASCII characters, beginning with the space character (32) and ending with the tilde character (126). The second example will map the first 96 glyphs found in the bitmap to ASCII range, the next 95 glyphs to Latin 1, the next 128 glyphs to Extended-A, and the last glyph to the Euro character. (This is just the characters found in the Allegro 4 font.) See also: [al_load_bitmap], [al_grab_font_from_bitmap] ### API: al_load_bitmap_font Load a bitmap font from a file. This is done by first calling [al_load_bitmap_flags] and then [al_grab_font_from_bitmap]. If you wanted to load an old A4 font, for example, it would be better to load the bitmap yourself in order to call [al_convert_mask_to_alpha] on it before passing it to [al_grab_font_from_bitmap]. See also: [al_load_bitmap_font_flags], [al_load_font], [al_load_bitmap_flags] ### API: al_load_bitmap_font_flags Like [al_load_bitmap_font] but additionally takes a flags parameter which is a bitfield containing a combination of the following: ALLEGRO_NO_PREMULTIPLIED_ALPHA : The same meaning as for [al_load_bitmap_flags]. See also: [al_load_bitmap_font], [al_load_bitmap_flags] ### API: al_create_builtin_font Creates a monochrome bitmap font (8x8 pixels per character). This font is primarily intended to be used for displaying information in environments or during early runtime states where no external font data is available or loaded (e.g. for debugging). The builtin font contains the following unicode character ranges: 0x0020 to 0x007F (ASCII) 0x00A1 to 0x00FF (Latin 1) 0x0100 to 0x017F (Extended A) 0x20AC to 0x20AC (euro currency symbol) Returns NULL on an error. The font memory must be freed the same way as for any other font, using [al_destroy_font]. Since: 5.0.8, 5.1.3 See also: [al_load_bitmap_font], [al_destroy_font] ## TTF fonts These functions are declared in the following header file. Link with allegro_ttf. ~~~~c #include ~~~~ ### API: al_init_ttf_addon Call this after [al_init_font_addon] to make [al_load_font] recognize ".ttf" and other formats supported by [al_load_ttf_font]. Returns true on success, false on failure. ### API: al_is_ttf_addon_initialized Returns true if the TTF addon is initialized, otherwise returns false. Since: 5.2.6 See also: [al_init_ttf_addon], [al_shutdown_ttf_addon] ### API: al_shutdown_ttf_addon Unloads the ttf addon again. You normally don't need to call this. ### API: al_load_ttf_font Loads a TrueType font from a file using the FreeType library. Quoting from the FreeType FAQ this means support for many different font formats: *TrueType, OpenType, Type1, CID, CFF, Windows FON/FNT, X11 PCF, and others* The `size` parameter determines the size the font will be rendered at, specified in pixels. The standard font size is measured in *units per EM*, if you instead want to specify the size as the total height of glyphs in pixels, pass it as a negative value. > *Note:* If you want to display text at multiple sizes, load the font multiple times with different size parameters. The following flags are supported: * ALLEGRO_TTF_NO_KERNING - Do not use any kerning even if the font file supports it. * ALLEGRO_TTF_MONOCHROME - Load as a monochrome font (which means no anti-aliasing of the font is done). * ALLEGRO_TTF_NO_AUTOHINT - Disable the Auto Hinter which is enabled by default in newer versions of FreeType. Since: 5.0.6, 5.1.2 See also: [al_init_ttf_addon], [al_load_ttf_font_f] ### API: al_load_ttf_font_f Like [al_load_ttf_font], but the font is read from the file handle. The filename is only used to find possible additional files next to a font file. > *Note:* The file handle is owned by the returned ALLEGRO_FONT object and must not be freed by the caller, as FreeType expects to be able to read from it at a later time. ### API: al_load_ttf_font_stretch Like [al_load_ttf_font], except it takes separate width and height parameters instead of a single size parameter. If the height is a positive value, and the width zero or positive, then font will be stretched according to those parameters. The width must not be negative if the height is positive. As with [al_load_ttf_font], the height may be a negative value to specify the total height in pixels. Then the width must also be a negative value, or zero. Returns `NULL` if the height is positive while width is negative, or if the height is negative while the width is positive. Since: 5.0.6, 5.1.0 See also: [al_load_ttf_font], [al_load_ttf_font_stretch_f] ### API: al_load_ttf_font_stretch_f Like [al_load_ttf_font_stretch], but the font is read from the file handle. The filename is only used to find possible additional files next to a font file. > *Note:* The file handle is owned by the returned ALLEGRO_FONT object and must not be freed by the caller, as FreeType expects to be able to read from it at a later time. Since: 5.0.6, 5.1.0 See also: [al_load_ttf_font_stretch] ### API: al_get_allegro_ttf_version Returns the (compiled) version of the addon, in the same format as [al_get_allegro_version]. ### API: al_get_glyph Gets all the information about a glyph, including the bitmap, needed to draw it yourself. prev_codepoint is the codepoint in the string before the one you want to draw and is used for kerning. codepoint is the character you want to get info about. You should clear the 'glyph' structure to 0 with memset before passing it to this function for future compatibility. Since: 5.2.1 > *[Unstable API]:* This API is new and subject to refinement. See also: [ALLEGRO_GLYPH] allegro5-5.2.10.1/docs/src/refman/fshook.txt000066400000000000000000000254321473414355200205070ustar00rootroot00000000000000# File system routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ These functions allow access to the filesystem. This can either be the real filesystem like your harddrive, or a virtual filesystem like a .zip archive (or whatever else you or an addon makes it do). ## API: ALLEGRO_FS_ENTRY Opaque filesystem entry object. Represents a file or a directory (check with [al_get_fs_entry_mode]). There are no user accessible member variables. ## API: ALLEGRO_FILE_MODE Filesystem modes/types * ALLEGRO_FILEMODE_READ - Readable * ALLEGRO_FILEMODE_WRITE - Writable * ALLEGRO_FILEMODE_EXECUTE - Executable * ALLEGRO_FILEMODE_HIDDEN - Hidden * ALLEGRO_FILEMODE_ISFILE - Regular file * ALLEGRO_FILEMODE_ISDIR - Directory ## API: al_create_fs_entry Creates an [ALLEGRO_FS_ENTRY] object pointing to path on the filesystem. 'path' can be a file or a directory and must not be NULL. ## API: al_destroy_fs_entry Destroys a fs entry handle. The file or directory represented by it is not destroyed. If the entry was opened, it is closed before being destroyed. Does nothing if passed NULL. ## API: al_get_fs_entry_name Returns the entry's filename path. Note that the filesystem encoding may not be known and the conversion to UTF-8 could in very rare cases cause this to return an invalid path. Therefore it's always safest to access the file over its [ALLEGRO_FS_ENTRY] and not the path. On success returns a read only string which you must not modify or destroy. Returns NULL on failure. > Note: prior to 5.1.5 it was written: "... the path will not be an absolute path if the entry wasn't created from an absolute path". This is no longer true. ## API: al_update_fs_entry Updates file status information for a filesystem entry. File status information is automatically updated when the entry is created, however you may update it again with this function, e.g. in case it changed. Returns true on success, false on failure. Fills in errno to indicate the error. See also: [al_get_errno], [al_get_fs_entry_atime], [al_get_fs_entry_ctime], [al_get_fs_entry_mode] ## API: al_get_fs_entry_mode Returns the entry's mode flags, i.e. permissions and whether the entry refers to a file or directory. See also: [al_get_errno], [ALLEGRO_FILE_MODE] ## API: al_get_fs_entry_atime Returns the time in seconds since the epoch since the entry was last accessed. Warning: some filesystems either don't support this flag, or people turn it off to increase performance. It may not be valid in all circumstances. See also: [al_get_fs_entry_ctime], [al_get_fs_entry_mtime], [al_update_fs_entry] ## API: al_get_fs_entry_ctime Returns the time in seconds since the epoch this entry was created on the filesystem. See also: [al_get_fs_entry_atime], [al_get_fs_entry_mtime], [al_update_fs_entry] ## API: al_get_fs_entry_mtime Returns the time in seconds since the epoch since the entry was last modified. See also: [al_get_fs_entry_atime], [al_get_fs_entry_ctime], [al_update_fs_entry] ## API: al_get_fs_entry_size Returns the size, in bytes, of the given entry. May not return anything sensible for a directory entry. See also: [al_update_fs_entry] ## API: al_fs_entry_exists Check if the given entry exists on in the filesystem. Returns true if it does exist or false if it doesn't exist, or an error occurred. Error is indicated in Allegro's errno. See also: [al_filename_exists] ## API: al_remove_fs_entry Delete this filesystem entry from the filesystem. Only files and empty directories may be deleted. Returns true on success, and false on failure, error is indicated in Allegro's errno. See also: [al_filename_exists] ## API: al_filename_exists Check if the path exists on the filesystem, without creating an [ALLEGRO_FS_ENTRY] object explicitly. See also: [al_fs_entry_exists] ## API: al_remove_filename Delete the given path from the filesystem, which may be a file or an empty directory. This is the same as [al_remove_fs_entry], except it expects the path as a string. Returns true on success, and false on failure. Allegro's errno is filled in to indicate the error. See also: [al_remove_fs_entry] ## Directory functions ### API: al_open_directory Opens a directory entry object. You must call this before using [al_read_directory] on an entry and you must call [al_close_directory] when you no longer need it. Returns true on success. See also: [al_read_directory], [al_close_directory] ### API: al_read_directory Reads the next directory item and returns a filesystem entry for it. Returns NULL if there are no more entries or if an error occurs. Call [al_destroy_fs_entry] on the returned entry when you are done with it. This function will ignore any files or directories named `.` or `..` which may exist on certain platforms and may signify the current and the parent directory. See also: [al_open_directory], [al_close_directory] ### API: al_close_directory Closes a previously opened directory entry object. Returns true on success, false on failure and fills in Allegro's errno to indicate the error. See also: [al_open_directory], [al_read_directory] ### API: al_get_current_directory Returns the path to the current working directory, or NULL on failure. The returned path is dynamically allocated and must be destroyed with [al_free]. Allegro's errno is filled in to indicate the error if there is a failure. This function may not be implemented on some (virtual) filesystems. See also: [al_get_errno], [al_free] ### API: al_change_directory Changes the current working directory to 'path'. Returns true on success, false on error. ### API: al_make_directory Creates a new directory on the filesystem. This function also creates any parent directories as needed. Returns true on success (including if the directory already exists), otherwise returns false on error. Fills in Allegro's errno to indicate the error. See also: [al_get_errno] ### API: al_open_fs_entry Open an [ALLEGRO_FILE] handle to a filesystem entry, for the given access mode. This is like calling [al_fopen] with the name of the filesystem entry, but uses the appropriate file interface, not whatever was set with the latest call to [al_set_new_file_interface]. Returns the handle on success, NULL on error. See also: [al_fopen] ### API: ALLEGRO_FOR_EACH_FS_ENTRY_RESULT Return values for the callbacks of [al_for_each_fs_entry] and for that function itself. * ALLEGRO_FOR_EACH_FS_ENTRY_ERROR - An error ocurred. * ALLEGRO_FOR_EACH_FS_ENTRY_OK - Continue normally and recurse into directories. * ALLEGRO_FOR_EACH_FS_ENTRY_SKIP - Continue but do NOT recusively descend. * ALLEGRO_FOR_EACH_FS_ENTRY_STOP - Stop iterating and return. See also: [al_for_each_fs_entry] Since: 5.1.9 ### API: al_for_each_fs_entry This function takes the [ALLEGRO_FS_ENTRY] `dir`, which should represent a directory, and looks for any other file system entries that are in it. This function will then call the callback function `callback` once for every filesystem entry in the directory `dir`. The callback `callback` must be of type `int callback(ALLEGRO_FS_ENTRY * entry, void * extra)`. The `callback` will be called with a pointer to an [ALLEGRO_FS_ENTRY] that matches one file or directory in `dir`, and the pointer passed in the `extra` parameter to [al_for_each_fs_entry]. When `callback` returns `ALLEGRO_FOR_EACH_FS_ENTRY_STOP` or `ALLEGRO_FOR_EACH_FS_ENTRY_ERROR`, iteration will stop immediately and [al_for_each_fs_entry] will return the value the `callback` returned. When `callback` returns `ALLEGRO_FOR_EACH_FS_ENTRY_OK` iteration will continue normally, and if the [ALLEGRO_FS_ENTRY] parameter of `callback` is a directory, [al_for_each_fs_entry] will call itself on that directory. Therefore the function will recusively descend into that directory. However, when `callback` returns `ALLEGRO_FOR_EACH_FS_ENTRY_SKIP` iteration will continue, but [al_for_each_fs_entry] will NOT recurse into the [ALLEGRO_FS_ENTRY] parameter of `callback` even if it is a directory. This function will skip any files or directories named `.` or `..` which may exist on certain platforms and may signify the current and the parent directory. The `callback` will not be called for files or directories with such a name. Returns ALLEGRO_FOR_EACH_FS_ENTRY_OK if successful, or ALLEGRO_FOR_EACH_FS_ENTRY_ERROR if something went wrong in processing the directory. In that case it will use [al_set_errno] to indicate the type of error which occurred. This function returns ALLEGRO_FOR_EACH_FS_ENTRY_STOP in case iteration was stopped by making `callback` return that value. In this case, [al_set_errno] will not be used. See also: [ALLEGRO_FOR_EACH_FS_ENTRY_RESULT] Since: 5.1.9 ## Alternative filesystem functions By default, Allegro uses platform specific filesystem functions for things like directory access. However if for example the files of your game are not in the local filesystem but inside some file archive, you can provide your own set of functions (or use an addon which does this for you, for example our physfs addon allows access to the most common archive formats). ### API: ALLEGRO_FS_INTERFACE The available functions you can provide for a filesystem. They are: ~~~ ALLEGRO_FS_ENTRY * fs_create_entry (const char *path); void fs_destroy_entry (ALLEGRO_FS_ENTRY *e); const char * fs_entry_name (ALLEGRO_FS_ENTRY *e); bool fs_update_entry (ALLEGRO_FS_ENTRY *e); uint32_t fs_entry_mode (ALLEGRO_FS_ENTRY *e); time_t fs_entry_atime (ALLEGRO_FS_ENTRY *e); time_t fs_entry_mtime (ALLEGRO_FS_ENTRY *e); time_t fs_entry_ctime (ALLEGRO_FS_ENTRY *e); off_t fs_entry_size (ALLEGRO_FS_ENTRY *e); bool fs_entry_exists (ALLEGRO_FS_ENTRY *e); bool fs_remove_entry (ALLEGRO_FS_ENTRY *e); bool fs_open_directory (ALLEGRO_FS_ENTRY *e); ALLEGRO_FS_ENTRY * fs_read_directory (ALLEGRO_FS_ENTRY *e); bool fs_close_directory(ALLEGRO_FS_ENTRY *e); bool fs_filename_exists(const char *path); bool fs_remove_filename(const char *path); char * fs_get_current_directory(void); bool fs_change_directory(const char *path); bool fs_make_directory(const char *path); ALLEGRO_FILE * fs_open_file(ALLEGRO_FS_ENTRY *e); ~~~ ### API: al_set_fs_interface Set the [ALLEGRO_FS_INTERFACE] table for the calling thread. See also: [al_set_standard_fs_interface], [al_store_state], [al_restore_state]. ### API: al_set_standard_fs_interface Return the [ALLEGRO_FS_INTERFACE] table to the default, for the calling thread. See also: [al_set_fs_interface]. ### API: al_get_fs_interface Return a pointer to the [ALLEGRO_FS_INTERFACE] table in effect for the calling thread. See also: [al_store_state], [al_restore_state]. allegro5-5.2.10.1/docs/src/refman/fullscreen_mode.txt000066400000000000000000000027731473414355200223670ustar00rootroot00000000000000# Fullscreen modes These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: ALLEGRO_DISPLAY_MODE Used for fullscreen mode queries. Contains information about a supported fullscreen modes. ~~~~c typedef struct ALLEGRO_DISPLAY_MODE { int width; // Screen width int height; // Screen height int format; // The pixel format of the mode int refresh_rate; // The refresh rate of the mode } ALLEGRO_DISPLAY_MODE; ~~~~ The `refresh_rate` may be zero if unknown. For an explanation of what `format` means, see [ALLEGRO_PIXEL_FORMAT]. See also: [al_get_display_mode] ## API: al_get_display_mode Retrieves a fullscreen mode. Display parameters should not be changed between a call of [al_get_num_display_modes] and [al_get_display_mode]. index must be between 0 and the number returned from al_get_num_display_modes-1. mode must be an allocated ALLEGRO_DISPLAY_MODE structure. This function will return NULL on failure, and the mode parameter that was passed in on success. See also: [ALLEGRO_DISPLAY_MODE], [al_get_num_display_modes] ## API: al_get_num_display_modes Get the number of available fullscreen display modes for the current set of display parameters. This will use the values set with [al_set_new_display_refresh_rate], and [al_set_new_display_flags] to find the number of modes that match. Settings the new display parameters to zero will give a list of all modes for the default driver. See also: [al_get_display_mode] allegro5-5.2.10.1/docs/src/refman/getting_started.txt000066400000000000000000000172321473414355200224040ustar00rootroot00000000000000# Getting started guide ## Introduction Welcome to Allegro 5! This short guide should point you at the parts of the API that you'll want to know about first. It's not a tutorial, as there isn't much discussion, only links into the manual. The rest you'll have to discover for yourself. Read the examples, and ask questions at [Allegro.cc]. There is an unofficial tutorial at [the wiki]. Be aware that, being on the wiki, it may be a little out of date, but the changes should be minor. Hopefully more will sprout when things stabilise, as they did for earlier versions of Allegro. ## Structure of the library and its addons Allegro 5.0 is divided into a core library and multiple addons. The addons are bundled together and built at the same time as the core, but they are distinct and kept in separate libraries. The core doesn't depend on anything in the addons, but addons may depend on the core and other addons and additional third party libraries. Here are the addons and their dependencies: allegro_main -> allegro allegro_image -> allegro allegro_primitives -> allegro allegro_color -> allegro allegro_font -> allegro allegro_ttf -> allegro_font -> allegro allegro_audio -> allegro allegro_acodec -> allegro_audio -> allegro allegro_video -> allegro_audio -> allegro allegro_memfile -> allegro allegro_physfs -> allegro allegro_native_dialog -> allegro The header file for the core library is `allegro5/allegro.h`. The header files for the addons are named `allegro5/allegro_image.h`, `allegro5/allegro_font.h`, etc. The allegro_main addon does not have a header file. ## The main function For the purposes of cross-platform compatibility Allegro puts some requirements on your main function. First, you must include the core header (`allegro5/allegro.h`) in the same file as your main function. Second, if your main function is inside a C++ file, then it must have this signature: `int main(int argc, char **argv)`. Third, if you're using C/C++ then you need to link with the allegro_main addon when building your program. ## Initialisation Before using Allegro you must call [al_init]. Some addons have their own initialisation, e.g. [al_init_image_addon], [al_init_font_addon], [al_init_ttf_addon]. To receive input, you need to initialise some subsystems like [al_install_keyboard], [al_install_mouse], [al_install_joystick]. ## Opening a window [al_create_display] will open a window and return an [ALLEGRO_DISPLAY]. To clear the display, call [al_clear_to_color]. Use [al_map_rgba] or [al_map_rgba_f] to obtain an [ALLEGRO_COLOR] parameter. Drawing operations are performed on a backbuffer. To make the operations visible, call [al_flip_display]. ## Display an image To load an image from disk, you need to have initialised the image I/O addon with [al_init_image_addon]. Then use [al_load_bitmap], which returns an [ALLEGRO_BITMAP]. Use [al_draw_bitmap], [al_draw_scaled_bitmap] or [al_draw_scaled_rotated_bitmap] to draw the image to the backbuffer. Remember to call [al_flip_display]. ## Changing the drawing target Notice that [al_clear_to_color] and [al_draw_bitmap] didn't take destination parameters: the destination is implicit. Allegro remembers the current "target bitmap" for the current thread. To change the target bitmap, call [al_set_target_bitmap]. The backbuffer of the display is also a bitmap. You can get it with [al_get_backbuffer] and then restore it as the target bitmap. Other bitmaps can be created with [al_create_bitmap], with options which can be adjusted with [al_set_new_bitmap_flags] and [al_set_new_bitmap_format]. ## Event queues and input Input comes from multiple sources: keyboard, mouse, joystick, timers, etc. Event queues aggregate events from all these sources, then you can query the queue for events. Create an event queue with [al_create_event_queue], then tell input sources to place new events into that queue using [al_register_event_source]. The usual input event sources can be retrieved with [al_get_keyboard_event_source], [al_get_mouse_event_source] and [al_get_joystick_event_source]. Events can be retrieved with [al_wait_for_event] or [al_get_next_event]. Check the event type and other fields of [ALLEGRO_EVENT] to react to the input. Displays are also event sources, which emit events when they are resized. You'll need to set the ALLEGRO_RESIZABLE flag with [al_set_new_display_flags] before creating the display, then register the display with an event queue. When you get a resize event, call [al_acknowledge_resize]. Timers are event sources which "tick" periodically, causing an event to be inserted into the queues that the timer is registered with. Create some with [al_create_timer]. [al_get_time] and [al_rest] are more direct ways to deal with time. ## Displaying some text To display some text, initialise the image and font addons with [al_init_image_addon] and [al_init_font_addon], then load a bitmap font with [al_load_font]. Use [al_draw_text] or [al_draw_textf]. For TrueType fonts, you'll need to initialise the TTF font addon with [al_init_ttf_addon] and load a TTF font with [al_load_ttf_font]. ## Drawing primitives The primitives addon provides some handy routines to draw lines ([al_draw_line]), rectangles ([al_draw_rectangle]), circles ([al_draw_circle]), etc. ## Blending To draw translucent or tinted images or primitives, change the blender state with [al_set_blender]. As with [al_set_target_bitmap], this changes Allegro's internal state (for the current thread). Often you'll want to save some part of the state and restore it later. The functions [al_store_state] and [al_restore_state] provide a convenient way to do that. ## Sound Use [al_install_audio] to initialize sound. To load any sample formats, you will need to initialise the acodec addon with [al_init_acodec_addon]. After that, you can simply use [al_reserve_samples] and pass the number of sound effects typically playing at the same time. Then load your sound effects with [al_load_sample] and play them with [al_play_sample]. To stream large pieces of music from disk, you can use [al_load_audio_stream] so the whole piece will not have to be pre-loaded into memory. If the above sounds too simple and you can't help but think about clipping and latency issues, don't worry. Allegro gives you full control over how much or little you want its sound system to do. The [al_reserve_samples] function mentioned above only sets up a default mixer and a number of sample instances but you don't need to use it. Instead, to get a "direct connection" to the sound system you would use an [ALLEGRO_VOICE] (but depending on the platform only one such voice is guaranteed to be available and it might require a specific format of audio data). Therefore all sound can be first routed through an [ALLEGRO_MIXER] which is connected to such a voice (or another mixer) and will mix together all sample data fed to it. You can then directly stream real-time sample data to a mixer or a voice using an [ALLEGRO_AUDIO_STREAM] or play complete sounds using an [ALLEGRO_SAMPLE_INSTANCE]. The latter simply points to an [ALLEGRO_SAMPLE] and will stream it for you. ## Unstable API Some of Allegro's API is marked as unstable, which means that in future versions of Allegro it may change or even be removed entirely! If you want to experiment with the unstable API, define `ALLEGRO_UNSTABLE` macro before including Allegro's headers. Note that when you define that macro, the version check performed by [al_install_system] and [al_init] becomes more scrict. See documentation of those functions for details. ## Not the end There's a heap of stuff we haven't even mentioned yet. Enjoy! [Allegro.cc]: http://www.allegro.cc/forums/ [the wiki]: http://wiki.allegro.cc/ allegro5-5.2.10.1/docs/src/refman/graphics.txt000066400000000000000000002117651473414355200210240ustar00rootroot00000000000000# Graphics routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## Colors ### API: ALLEGRO_COLOR An ALLEGRO_COLOR structure describes a color in a device independent way. Use [al_map_rgb] et al. and [al_unmap_rgb] et al. to translate from and to various color representations. ### API: al_map_rgb Convert r, g, b (ranging from 0-255) into an [ALLEGRO_COLOR], using 255 for alpha. This function can be called before Allegro is initialized. See also: [al_map_rgba], [al_map_rgba_f], [al_map_rgb_f] ### API: al_map_rgb_f Convert r, g, b, (ranging from 0.0f-1.0f) into an [ALLEGRO_COLOR], using 1.0f for alpha. This function can be called before Allegro is initialized. See also: [al_map_rgba], [al_map_rgb], [al_map_rgba_f] ### API: al_map_rgba Convert r, g, b, a (ranging from 0-255) into an [ALLEGRO_COLOR]. This function can be called before Allegro is initialized. See also: [al_map_rgb], [al_premul_rgba], [al_map_rgb_f] ### API: al_premul_rgba This is a shortcut for [al_map_rgba]\(r * a / 255, g * a / 255, b * a / 255, a). By default Allegro uses pre-multiplied alpha for transparent blending of bitmaps and primitives (see [al_load_bitmap_flags] for a discussion of that feature). This means that if you want to tint a bitmap or primitive to be transparent you need to multiply the color components by the alpha components when you pass them to this function. For example: ~~~~c int r = 255; int g = 0; int b = 0; int a = 127; ALLEGRO_COLOR c = al_premul_rgba(r, g, b, a); /* Draw the bitmap tinted red and half-transparent. */ al_draw_tinted_bitmap(bmp, c, 0, 0, 0); ~~~~ This function can be called before Allegro is initialized. Since: 5.1.12 See also: [al_map_rgba], [al_premul_rgba_f] ### API: al_map_rgba_f Convert r, g, b, a (ranging from 0.0f-1.0f) into an [ALLEGRO_COLOR]. This function can be called before Allegro is initialized. See also: [al_map_rgba], [al_premul_rgba_f], [al_map_rgb_f] ### API: al_premul_rgba_f This is a shortcut for [al_map_rgba_f]\(r * a, g * a, b * a, a). By default Allegro uses pre-multiplied alpha for transparent blending of bitmaps and primitives (see [al_load_bitmap_flags] for a discussion of that feature). This means that if you want to tint a bitmap or primitive to be transparent you need to multiply the color components by the alpha components when you pass them to this function. For example: ~~~~c float r = 1; float g = 0; float b = 0; float a = 0.5; ALLEGRO_COLOR c = al_premul_rgba_f(r, g, b, a); /* Draw the bitmap tinted red and half-transparent. */ al_draw_tinted_bitmap(bmp, c, 0, 0, 0); ~~~~ This function can be called before Allegro is initialized. Since: 5.1.12 See also: [al_map_rgba_f], [al_premul_rgba] ### API: al_unmap_rgb Retrieves components of an ALLEGRO_COLOR, ignoring alpha. Components will range from 0-255. This function can be called before Allegro is initialized. See also: [al_unmap_rgba], [al_unmap_rgba_f], [al_unmap_rgb_f] ### API: al_unmap_rgb_f Retrieves components of an [ALLEGRO_COLOR], ignoring alpha. Components will range from 0.0f-1.0f. This function can be called before Allegro is initialized. See also: [al_unmap_rgba], [al_unmap_rgb], [al_unmap_rgba_f] ### API: al_unmap_rgba Retrieves components of an [ALLEGRO_COLOR]. Components will range from 0-255. This function can be called before Allegro is initialized. See also: [al_unmap_rgb], [al_unmap_rgba_f], [al_unmap_rgb_f] ### API: al_unmap_rgba_f Retrieves components of an [ALLEGRO_COLOR]. Components will range from 0.0f-1.0f. This function can be called before Allegro is initialized. See also: [al_unmap_rgba], [al_unmap_rgb], [al_unmap_rgb_f] ## Locking and pixel formats ### API: ALLEGRO_LOCKED_REGION Users who wish to manually edit or read from a bitmap are required to lock it first. The ALLEGRO_LOCKED_REGION structure represents the locked region of the bitmap. This call will work with any bitmap, including memory bitmaps. ~~~~c typedef struct ALLEGRO_LOCKED_REGION { void *data; int format; int pitch; int pixel_size; } ALLEGRO_LOCKED_REGION; ~~~~ - *data* points to the leftmost pixel of the first row (row 0) of the locked region. For blocked formats, this points to the leftmost block of the first row of blocks. - *format* indicates the pixel format of the data. - *pitch* gives the size in bytes of a single row (also known as the stride). The pitch may be greater than `width * pixel_size` due to padding; this is not uncommon. It is also *not* uncommon for the pitch to be negative (the bitmap may be upside down). For blocked formats, 'row' refers to the row of blocks, not of pixels. - *pixel_size* is the number of bytes used to represent a single block of pixels for the pixel format of this locked region. For most formats (and historically, this used to be true for all formats), this is just the size of a single pixel, but for blocked pixel formats this value is different. See also: [al_lock_bitmap], [al_lock_bitmap_region], [al_unlock_bitmap], [ALLEGRO_PIXEL_FORMAT] ### API: ALLEGRO_PIXEL_FORMAT Pixel formats. Each pixel format specifies the exact size and bit layout of a pixel in memory. Components are specified from high bits to low bits, so for example a fully opaque red pixel in ARGB_8888 format is 0xFFFF0000. > *Note:* > > The pixel format is independent of endianness. That is, in the above > example you can always get the red component with > > ~~~~c > (pixel & 0x00ff0000) >> 16 > ~~~~ > > But you can *not* rely on this code: > > ~~~~c > *(pixel + 2) > ~~~~ > > It will return the red component on little endian systems, but the > green component on big endian systems. Also note that Allegro's naming is different from OpenGL naming here, where a format of GL_RGBA8 merely defines the component order and the exact layout including endianness treatment is specified separately. Usually GL_RGBA8 will correspond to ALLEGRO_PIXEL_ABGR_8888 though on little endian systems, so care must be taken (note the reversal of RGBA <-> ABGR). The only exception to this ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE which will always have the components as 4 bytes corresponding to red, green, blue and alpha, in this order, independent of the endianness. Some of the pixel formats represent compressed bitmap formats. Compressed bitmaps take up less space in the GPU memory than bitmaps with regular (uncompressed) pixel formats. This smaller footprint means that you can load more resources into GPU memory, and they will be drawn somewhat faster. The compression is lossy, however, so it is not appropriate for all graphical styles: it tends to work best for images with smooth color gradations. It is possible to compress bitmaps at runtime by passing the appropriate bitmap format in `al_set_new_bitmap_format` and then creating, loading, cloning or converting a non-compressed bitmap. This, however, is not recommended as the compression quality differs between different GPU drivers. It is recommended to compress these bitmaps ahead of time using external tools and then load them compressed. Unlike regular pixel formats, compressed pixel formats are not laid out in memory one pixel row at a time. Instead, the bitmap is subdivided into rectangular blocks of pixels that are then laid out in block rows. This means that regular locking functions cannot use compressed pixel formats as the destination format. Instead, you can use the blocked versions of the bitmap locking functions which do support these formats. It is not recommended to use compressed bitmaps as target bitmaps, as that operation cannot be hardware accelerated. Due to proprietary algorithms used, it is typically impossible to create compressed memory bitmaps. * ALLEGRO_PIXEL_FORMAT_ANY - Let the driver choose a format. This is the default format at program start. * ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA - Let the driver choose a format without alpha. * ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA - Let the driver choose a format with alpha. * ALLEGRO_PIXEL_FORMAT_ANY_15_NO_ALPHA - Let the driver choose a 15 bit format without alpha. * ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA - Let the driver choose a 16 bit format without alpha. * ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA - Let the driver choose a 16 bit format with alpha. * ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA - Let the driver choose a 24 bit format without alpha. * ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA - Let the driver choose a 32 bit format without alpha. * ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA - Let the driver choose a 32 bit format with alpha. * ALLEGRO_PIXEL_FORMAT_ARGB_8888 - 32 bit * ALLEGRO_PIXEL_FORMAT_RGBA_8888 - 32 bit * ALLEGRO_PIXEL_FORMAT_ARGB_4444 - 16 bit * ALLEGRO_PIXEL_FORMAT_RGB_888 - 24 bit * ALLEGRO_PIXEL_FORMAT_RGB_565 - 16 bit * ALLEGRO_PIXEL_FORMAT_RGB_555 - 15 bit * ALLEGRO_PIXEL_FORMAT_RGBA_5551 - 16 bit * ALLEGRO_PIXEL_FORMAT_ARGB_1555 - 16 bit * ALLEGRO_PIXEL_FORMAT_ABGR_8888 - 32 bit * ALLEGRO_PIXEL_FORMAT_XBGR_8888 - 32 bit * ALLEGRO_PIXEL_FORMAT_BGR_888 - 24 bit * ALLEGRO_PIXEL_FORMAT_BGR_565 - 16 bit * ALLEGRO_PIXEL_FORMAT_BGR_555 - 15 bit * ALLEGRO_PIXEL_FORMAT_RGBX_8888 - 32 bit * ALLEGRO_PIXEL_FORMAT_XRGB_8888 - 32 bit * ALLEGRO_PIXEL_FORMAT_ABGR_F32 - 128 bit * ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE - Like the version without _LE, but the component order is guaranteed to be red, green, blue, alpha. This only makes a difference on big endian systems, on little endian it is just an alias. * ALLEGRO_PIXEL_FORMAT_RGBA_4444 - 16bit * ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 - A single 8-bit channel. A pixel value maps onto the red channel when displayed, but it is undefined how it maps onto green, blue and alpha channels. When drawing to bitmaps of this format, only the red channel is taken into account. Allegro may have to use fallback methods to render to bitmaps of this format. This pixel format is mainly intended for storing the color indices of an indexed (paletted) image, usually in conjunction with a pixel shader that maps indices to RGBA values. Since 5.1.2. * ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1 - Compressed using the DXT1 compression algorithm. Each 4x4 pixel block is encoded in 64 bytes, resulting in 6-8x compression ratio. Only a single bit of alpha per pixel is supported. Since 5.1.9. * ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3 - Compressed using the DXT3 compression algorithm. Each 4x4 pixel block is encoded in 128 bytes, resulting in 4x compression ratio. This format supports sharp alpha transitions. Since 5.1.9. * ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5 - Compressed using the DXT5 compression algorithm. Each 4x4 pixel block is encoded in 128 bytes, resulting in 4x compression ratio. This format supports smooth alpha transitions. Since 5.1.9. See also: [al_set_new_bitmap_format], [al_get_bitmap_format] ### API: al_get_pixel_size Return the number of bytes that a pixel of the given format occupies. For blocked pixel formats (e.g. compressed formats), this returns 0. See also: [ALLEGRO_PIXEL_FORMAT], [al_get_pixel_format_bits] ### API: al_get_pixel_format_bits Return the number of bits that a pixel of the given format occupies. For blocked pixel formats (e.g. compressed formats), this returns 0. See also: [ALLEGRO_PIXEL_FORMAT], [al_get_pixel_size] ### API: al_get_pixel_block_size Return the number of bytes that a block of pixels with this format occupies. Since: 5.1.9. See also: [ALLEGRO_PIXEL_FORMAT], [al_get_pixel_block_width], [al_get_pixel_block_height] ### API: al_get_pixel_block_width Return the width of the the pixel block for this format. Since: 5.1.9. See also: [ALLEGRO_PIXEL_FORMAT], [al_get_pixel_block_size], [al_get_pixel_block_height] ### API: al_get_pixel_block_height Return the height of the the pixel block for this format. Since: 5.1.9. See also: [ALLEGRO_PIXEL_FORMAT], [al_get_pixel_block_size], [al_get_pixel_block_width] ### API: al_lock_bitmap Lock an entire bitmap for reading or writing. If the bitmap is a display bitmap it will be updated from system memory after the bitmap is unlocked (unless locked read only). Returns NULL if the bitmap cannot be locked, e.g. the bitmap was locked previously and not unlocked. This function also returns NULL if the `format` is a compressed format. Flags are: * ALLEGRO_LOCK_READONLY - The locked region will not be written to. This can be faster if the bitmap is a video texture, as it can be discarded after the lock instead of uploaded back to the card. * ALLEGRO_LOCK_WRITEONLY - The locked region will not be read from. This can be faster if the bitmap is a video texture, as no data need to be read from the video card. You are required to fill in all pixels before unlocking the bitmap again, so be careful when using this flag. * ALLEGRO_LOCK_READWRITE - The locked region can be written to and read from. Use this flag if a partial number of pixels need to be written to, even if reading is not needed. `format` indicates the pixel format that the returned buffer will be in. To lock in the same format as the bitmap stores its data internally, call with `al_get_bitmap_format(bitmap)` as the format or use ALLEGRO_PIXEL_FORMAT_ANY. Locking in the native format will usually be faster. If the bitmap format is compressed, using ALLEGRO_PIXEL_FORMAT_ANY will choose an implementation defined non-compressed format. On some platforms, Allegro automatically backs up the contents of video bitmaps because they may be occasionally lost (see discussion in [al_create_bitmap]'s documentation). If you're completely recreating the bitmap contents often (e.g. every frame) then you will get much better performance by creating the target bitmap with ALLEGRO_NO_PRESERVE_TEXTURE flag. > *Note:* While a bitmap is locked, you can not use any drawing operations on it (with the sole exception of [al_put_pixel] and [al_put_blended_pixel]). See also: [ALLEGRO_LOCKED_REGION], [ALLEGRO_PIXEL_FORMAT], [al_unlock_bitmap], [al_lock_bitmap_region], [al_lock_bitmap_blocked], [al_lock_bitmap_region_blocked] ### API: al_lock_bitmap_region Like [al_lock_bitmap], but only locks a specific area of the bitmap. If the bitmap is a video bitmap, only that area of the texture will be updated when it is unlocked. Locking only the region you indend to modify will be faster than locking the whole bitmap. > *Note:* Using the ALLEGRO_LOCK_WRITEONLY with a blocked pixel format (i.e. formats for which [al_get_pixel_block_width] or [al_get_pixel_block_height] do not return 1) requires you to have the region be aligned to the block width for optimal performance. If it is not, then the function will have to lock the region with the ALLEGRO_LOCK_READWRITE instead in order to pad this region with valid data. See also: [ALLEGRO_LOCKED_REGION], [ALLEGRO_PIXEL_FORMAT], [al_unlock_bitmap] ### API: al_unlock_bitmap Unlock a previously locked bitmap or bitmap region. If the bitmap is a video bitmap, the texture will be updated to match the system memory copy (unless it was locked read only). See also: [al_lock_bitmap], [al_lock_bitmap_region], [al_lock_bitmap_blocked], [al_lock_bitmap_region_blocked] ### API: al_lock_bitmap_blocked Like [al_lock_bitmap], but allows locking bitmaps with a blocked pixel format (i.e. a format for which [al_get_pixel_block_width] or [al_get_pixel_block_height] do not return 1) in that format. To that end, this function also does not allow format conversion. For bitmap formats with a block size of 1, this function is identical to calling `al_lock_bitmap(bmp, al_get_bitmap_format(bmp), flags)`. > *Note:* Currently there are no drawing functions that work when the bitmap is locked with a compressed format. [al_get_pixel] will also not work. Since: 5.1.9 See also: [al_lock_bitmap], [al_lock_bitmap_region_blocked] ### API: al_lock_bitmap_region_blocked Like [al_lock_bitmap_blocked], but allows locking a sub-region, for performance. Unlike [al_lock_bitmap_region] the region specified in terms of blocks and not pixels. Since: 5.1.9 See also: [al_lock_bitmap_region], [al_lock_bitmap_blocked] ## Bitmap creation ### API: ALLEGRO_BITMAP Abstract type representing a bitmap (2D image). ### API: al_create_bitmap Creates a new bitmap using the bitmap format and flags for the current thread. Blitting between bitmaps of differing formats, or blitting between memory bitmaps and display bitmaps may be slow. Unless you set the ALLEGRO_MEMORY_BITMAP flag, the bitmap is created for the current display. Blitting to another display may be slow. If a display bitmap is created, there may be limitations on the allowed dimensions. For example a DirectX or OpenGL backend usually has a maximum allowed texture size - so if bitmap creation fails for very large dimensions, you may want to re-try with a smaller bitmap. Some platforms also dictate a minimum texture size, which is relevant if you plan to use this bitmap with the primitives addon. If you try to create a bitmap smaller than this, this call will not fail but the returned bitmap will be a section of a larger bitmap with the minimum size. The minimum size that will work on all platforms is 32 by 32. There is an experimental switch to turns this padding off by editing the system configuration (see `min_bitmap_size` key in [al_get_system_config]). Some platforms do not directly support display bitmaps whose dimensions are not powers of two. Allegro handles this by creating a larger bitmap that has dimensions that are powers of two and then returning a section of that bitmap with the dimensions you requested. This can be relevant if you plan to use this bitmap with the primitives addon but shouldn't be an issue otherwise. If you create a bitmap without ALLEGRO_MEMORY_BITMAP set but there is no current display, a temporary memory bitmap will be created instead. You can later convert all such bitmap to video bitmap and assign to a display by calling [al_convert_memory_bitmaps]. On some platforms the contents of video bitmaps may be lost when your application loses focus. Allegro has an internal mechanism to restore the contents of these video bitmaps, but it is not foolproof (sometimes bitmap contents can get lost permanently) and has performance implications. If you are using a bitmap as an intermediate buffer this mechanism may be wasteful. In this case, if you do not want Allegro to manage the bitmap contents for you, you can disable this mechanism by creating the bitmap with the ALLEGRO_NO_PRESERVE_TEXTURE flag. The bitmap contents are lost when you get the ALLEGRO_EVENT_DISPLAY_LOST and ALLEGRO_EVENT_DISPLAY_HALT_DRAWING and a should be restored when you get the ALLEGRO_EVENT_DISPLAY_FOUND and when you call [al_acknowledge_drawing_resume] (after ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING event). You can use those events to implement your own bitmap content restoration mechanism if Allegro's does not work well enough for you (for example, you can reload them all from disk). *Note*: The contents of a newly created bitmap are undefined - you need to clear the bitmap or make sure all pixels get overwritten before drawing it. When you are done with using the bitmap you must call [al_destroy_bitmap] on it to free any resources allocated for it. See also: [al_set_new_bitmap_format], [al_set_new_bitmap_flags], [al_clone_bitmap], [al_create_sub_bitmap], [al_convert_memory_bitmaps], [al_destroy_bitmap] ### API: al_create_sub_bitmap Creates a sub-bitmap of the parent, at the specified coordinates and of the specified size. A sub-bitmap is a bitmap that shares drawing memory with a pre-existing (parent) bitmap, but possibly with a different size and clipping settings. The sub-bitmap may originate off or extend past the parent bitmap. See the discussion in [al_get_backbuffer] about using sub-bitmaps of the backbuffer. The parent bitmap's clipping rectangles are ignored. If a sub-bitmap was not or cannot be created then NULL is returned. When you are done with using the sub-bitmap you must call [al_destroy_bitmap] on it to free any resources allocated for it. Note that destroying parents of sub-bitmaps will not destroy the sub-bitmaps; instead the sub-bitmaps become invalid and should no longer be used for drawing - they still must be destroyed with [al_destroy_bitmap] however. It does not matter whether you destroy a sub-bitmap before or after its parent otherwise. See also: [al_create_bitmap] ### API: al_clone_bitmap Create a new bitmap with [al_create_bitmap], and copy the pixel data from the old bitmap across. The newly created bitmap will be created with the current new bitmap flags, and not the ones that were used to create the original bitmap. If the new bitmap is a memory bitmap, its projection bitmap is reset to be orthographic. See also: [al_create_bitmap], [al_set_new_bitmap_format], [al_set_new_bitmap_flags], [al_convert_bitmap] ### API: al_convert_bitmap Converts the bitmap to the current bitmap flags and format. The bitmap will be as if it was created anew with [al_create_bitmap] but retain its contents. All of this bitmap's sub-bitmaps are also converted. If the new bitmap type is memory, then the bitmap's projection bitmap is reset to be orthographic. If this bitmap is a sub-bitmap, then it, its parent and all the sibling sub-bitmaps are also converted. Since: 5.1.0 See also: [al_create_bitmap], [al_set_new_bitmap_format], [al_set_new_bitmap_flags], [al_clone_bitmap] ### API: al_convert_memory_bitmaps If you create a bitmap when there is no current display (for example because you have not called [al_create_display] in the current thread) and are using the ALLEGRO_CONVERT_BITMAP bitmap flag (which is set by default) then the bitmap will be created successfully, but as a memory bitmap. This function converts all such bitmaps to proper video bitmaps belonging to the current display. Note that video bitmaps get automatically converted back to memory bitmaps when the last display is destroyed. This operation will preserve all bitmap flags except ALLEGRO_VIDEO_BITMAP and ALLEGRO_MEMORY_BITMAP. Since: 5.2.0 See also: [al_convert_bitmap], [al_create_bitmap] ### API: al_destroy_bitmap Destroys the given bitmap, freeing all resources used by it. This function does nothing if the bitmap argument is NULL. As a convenience, if the calling thread is currently targeting the bitmap then the bitmap will be untargeted first. The new target bitmap is unspecified. (since: 5.0.10, 5.1.6) Otherwise, it is an error to destroy a bitmap while it (or a sub-bitmap) is the target bitmap of any thread. See also: [al_create_bitmap] ### API: al_get_new_bitmap_flags Returns the flags used for newly created bitmaps. See also: [al_set_new_bitmap_flags] ### API: al_get_new_bitmap_format Returns the format used for newly created bitmaps. See also: [ALLEGRO_PIXEL_FORMAT], [al_set_new_bitmap_format] ### API: al_set_new_bitmap_flags Sets the flags to use for newly created bitmaps. Valid flags are: ALLEGRO_MEMORY_BITMAP : Create a bitmap residing in system memory. Operations on, and with, memory bitmaps will not be hardware accelerated. However, direct pixel access can be relatively quick compared to video bitmaps, which depend on the display driver in use. *Note*: Allegro's software rendering routines are currently somewhat unoptimised. *Note:* Combining ALLEGRO_VIDEO_BITMAP and ALLEGRO_MEMORY_BITMAP flags is invalid. ALLEGRO_VIDEO_BITMAP : Creates a bitmap that resides in the video card memory. These types of bitmaps receive the greatest benefit from hardware acceleration. *Note*: Creating a video bitmap will fail if there is no current display or the current display driver cannot create the bitmap. The latter will happen if for example the format or dimensions are not supported. *Note:* Bitmaps created with this flag will be converted to memory bitmaps when the last display is destroyed. In most cases it is therefore easier to use the ALLEGRO_CONVERT_BITMAP flag instead. *Note:* Combining ALLEGRO_VIDEO_BITMAP and ALLEGRO_MEMORY_BITMAP flags is invalid. ALLEGRO_CONVERT_BITMAP : This is the default. It will try to create a video bitmap and if that fails create a memory bitmap. Bitmaps created with this flag when there is no active display will be converted to video bitmaps next time a display is created. They also will remain video bitmaps if the last display is destroyed and then another is created again. Since 5.1.0. *Note:* You can combine this flag with ALLEGRO_MEMORY_BITMAP or ALLEGRO_VIDEO_BITMAP to force the initial type (and fail in the latter case if no video bitmap can be created) - but usually neither of those combinations is very useful. You can use the display option ALLEGRO_AUTO_CONVERT_BITMAPS to control which displays will try to auto-convert bitmaps. ALLEGRO_FORCE_LOCKING : Does nothing since 5.1.8. Kept for backwards compatibility only. ALLEGRO_NO_PRESERVE_TEXTURE : Normally, every effort is taken to preserve the contents of bitmaps, since some platforms may forget them. This can take extra processing time. If you know it doesn't matter if a bitmap keeps its pixel data, for example when it's a temporary buffer, use this flag to tell Allegro not to attempt to preserve its contents. ALLEGRO_ALPHA_TEST : This is a driver hint only. It tells the graphics driver to do alpha testing instead of alpha blending on bitmaps created with this flag. Alpha testing is usually faster and preferred if your bitmaps have only one level of alpha (0). This flag is currently not widely implemented (i.e., only for memory bitmaps). ALLEGRO_MIN_LINEAR : When drawing a scaled down version of the bitmap, use linear filtering. This usually looks better. You can also combine it with the MIPMAP flag for even better quality. ALLEGRO_MAG_LINEAR : When drawing a magnified version of a bitmap, use linear filtering. This will cause the picture to get blurry instead of creating a big rectangle for each pixel. It depends on how you want things to look like whether you want to use this or not. ALLEGRO_MIPMAP : This can only be used for bitmaps whose width and height is a power of two. In that case, it will generate mipmaps and use them when drawing scaled down versions. For example if the bitmap is 64x64, then extra bitmaps of sizes 32x32, 16x16, 8x8, 4x4, 2x2 and 1x1 will be created always containing a scaled down version of the original. See also: [al_get_new_bitmap_flags], [al_get_bitmap_flags] ### API: al_add_new_bitmap_flag A convenience function which does the same as ~~~~c al_set_new_bitmap_flags(al_get_new_bitmap_flags() | flag); ~~~~ See also: [al_set_new_bitmap_flags], [al_get_new_bitmap_flags], [al_get_bitmap_flags] ### API: al_set_new_bitmap_format Sets the pixel format ([ALLEGRO_PIXEL_FORMAT]) for newly created bitmaps. The default format is 0 and means the display driver will choose the best format. See also: [ALLEGRO_PIXEL_FORMAT], [al_get_new_bitmap_format], [al_get_bitmap_format] ### API: al_set_new_bitmap_depth Sets the depthbuffer depth used by newly created bitmaps (on the current thread) if they are used with [al_set_target_bitmap]. 0 means no depth-buffer will be created when drawing into the bitmap, which is the default. Since: 5.2.1 > *[Unstable API]:* This is an experimental feature and currently only works for the OpenGL backend. ### API: al_get_new_bitmap_depth Returns the value currently set with [al_set_new_bitmap_depth] on the current thread or 0 if none was set. Since: 5.2.1 > *[Unstable API]:* This is an experimental feature and currently only works for the OpenGL backend. ### API: al_set_new_bitmap_samples Sets the multi-sampling samples used by newly created bitmaps (on the current thread) if they are used with [al_set_target_bitmap]. 0 means multi-sampling will not be used when drawing into the bitmap, which is the default. 1 means multi-sampling will be used but only using a single sample per pixel (so usually there will be no visual difference to not using multi-sampling at all). > *Note:* Some platforms have restrictions on when the multi-sampling buffer for a bitmap is realized, i.e. down-scaled back to the actual bitmap dimensions. This may only happen after a call to [al_set_target_bitmap]. So for example: al_set_target_bitmap(multisample); al_clear_to_color(blue); al_draw_line(0, 0, 100, 100, red, 1); al_lock_bitmap(multisample, ...) // ERROR: the contents of the bitmap will be undefined al_set_target_bitmap(backbuffer); al_lock_bitmap(multisample, ...) // CORRECT: at this point, the bitmap contents are updated and // there will be an anti-aliased line in it. Since: 5.2.1 > *[Unstable API]:* This is an experimental feature and currently only works for the OpenGL backend. ### API: al_get_new_bitmap_samples Returns the value currently set with [al_set_new_bitmap_samples] on the current thread or 0 if none was set. Since: 5.2.1 > *[Unstable API]:* This is an experimental feature and currently only works for the OpenGL backend. ### API: al_set_new_bitmap_wrap Sets the texture wrapping settings for newly created bitmaps (on the current thread). Typically you take advantage of this feature either via the primitives addon (see [al_draw_prim] and others) or via custom shaders (see [ALLEGRO_SHADER]). > *Note:* In the context of custom shaders, Direct3D and OpenGL have different granularities for controlling this setting. Direct3D sets wrapping setting for each sampler separately, while OpenGL sets it per-texture. This interacts particularly poorly with the primitives addon which (for backwards compatibility) alters the wrapping setting. To minimize this issue, use a wrapping setting that's not ALLEGRO_BITMAP_WRAP_DEFAULT. Since: 5.2.8 > *[Unstable API]:* This is an experimental feature. See also: [ALLEGRO_BITMAP_WRAP] ### API: al_get_new_bitmap_wrap Returns the value currently set with [al_set_new_bitmap_wrap] on the current thread. Since: 5.2.8 > *[Unstable API]:* This is an experimental feature. See also: [ALLEGRO_BITMAP_WRAP] ### API: ALLEGRO_BITMAP_WRAP Controls the how the pixel color is determined from a texture querying the texture coordinates are outside the usual bounds. * ALLEGRO_BITMAP_WRAP_DEFAULT - The default behavior. This corresponds to ALLEGRO_BITMAP_WRAP_REPEAT when using the primitives addon and ALLEGRO_BITMAP_WRAP_CLAMP otherwise. * ALLEGRO_BITMAP_WRAP_REPEAT - The texture coordinates get shifted to the opposite edge that they go past. * ALLEGRO_BITMAP_WRAP_CLAMP - The texture coordinates get clamped to the edges that they go past. * ALLEGRO_BITMAP_WRAP_MIRROR - The texture coordinates get mirrored across the edges that they go past. ## Bitmap properties ### API: al_get_bitmap_flags Return the flags used to create the bitmap. See also: [al_set_new_bitmap_flags] ### API: al_get_bitmap_format Returns the pixel format of a bitmap. See also: [ALLEGRO_PIXEL_FORMAT], [al_set_new_bitmap_flags] ### API: al_get_bitmap_height Returns the height of a bitmap in pixels. ### API: al_get_bitmap_width Returns the width of a bitmap in pixels. ### API: al_get_bitmap_depth Return the depthbuffer depth used by this bitmap if it is used with [al_set_target_bitmap]. Since: 5.2.1 > *[Unstable API]:* This is an experimental feature and currently only works for the OpenGL backend. ### API: al_get_bitmap_samples Return the multi-sampling samples used by this bitmap if it is used with [al_set_target_bitmap]. Since: 5.2.1 > *[Unstable API]:* This is an experimental feature and currently only works for the OpenGL backend. ### API: al_get_pixel Get a pixel's color value from the specified bitmap. This operation is slow on non-memory bitmaps. Consider locking the bitmap if you are going to use this function multiple times on the same bitmap. See also: [ALLEGRO_COLOR], [al_put_pixel], [al_lock_bitmap] ### API: al_is_bitmap_locked Returns whether or not a bitmap is already locked. See also: [al_lock_bitmap], [al_lock_bitmap_region], [al_unlock_bitmap] ### API: al_is_compatible_bitmap D3D and OpenGL allow sharing a texture in a way so it can be used for multiple windows. Each [ALLEGRO_BITMAP] created with [al_create_bitmap] however is usually tied to a single ALLEGRO_DISPLAY. This function can be used to know if the bitmap is compatible with the given display, even if it is a different display to the one it was created with. It returns true if the bitmap is compatible (things like a cached texture version can be used) and false otherwise (blitting in the current display will be slow). The only time this function is useful is if you are using multiple windows and need accelerated blitting of the same bitmaps to both. Returns true if the bitmap is compatible with the current display, false otherwise. If there is no current display, false is returned. ### API: al_is_sub_bitmap Returns true if the specified bitmap is a sub-bitmap, false otherwise. See also: [al_create_sub_bitmap], [al_get_parent_bitmap] ### API: al_get_parent_bitmap Returns the bitmap this bitmap is a sub-bitmap of. Returns NULL if this bitmap is not a sub-bitmap. This function always returns the real bitmap, and never a sub-bitmap. This might NOT match what was passed to [al_create_sub_bitmap]. Consider this code, for instance: ~~~~c ALLEGRO_BITMAP* a = al_create_bitmap(512, 512); ALLEGRO_BITMAP* b = al_create_sub_bitmap(a, 128, 128, 256, 256); ALLEGRO_BITMAP* c = al_create_sub_bitmap(b, 64, 64, 128, 128); ASSERT(al_get_parent_bitmap(b) == a && al_get_parent_bitmap(c) == a); ~~~~ The assertion will pass because only `a` is a real bitmap, and both `b` and `c` are its sub-bitmaps. Since: 5.0.6, 5.1.2 See also: [al_create_sub_bitmap], [al_is_sub_bitmap] ### API: al_get_bitmap_x For a sub-bitmap, return it's x position within the parent. See also: [al_create_sub_bitmap], [al_get_parent_bitmap], [al_get_bitmap_y] Since: 5.1.12 ### API: al_get_bitmap_y For a sub-bitmap, return it's y position within the parent. See also: [al_create_sub_bitmap], [al_get_parent_bitmap], [al_get_bitmap_x] Since: 5.1.12 ### API: al_reparent_bitmap For a sub-bitmap, changes the parent, position and size. This is the same as destroying the bitmap and re-creating it with [al_create_sub_bitmap] - except the bitmap pointer stays the same. This has many uses, for example an animation player could return a single bitmap which can just be re-parented to different animation frames without having to re-draw the contents. Or a sprite atlas could re-arrange its sprites without having to invalidate all existing bitmaps. See also: [al_create_sub_bitmap], [al_get_parent_bitmap] Since: 5.1.12 ### API: al_get_bitmap_blender Returns the current blender being used by the target bitmap. You can pass NULL for values you are not interested in. Since: 5.2.5 > *[Unstable API]:* New API. See also: [al_set_bitmap_blender], [al_get_separate_bitmap_blender] ### API: al_get_separate_bitmap_blender Returns the current blender being used by the target bitmap. You can pass NULL for values you are not interested in. Since: 5.2.5 > *[Unstable API]:* New API. See also: [al_set_separate_bitmap_blender], [al_get_bitmap_blender] ### API: al_get_bitmap_blend_color Returns the color currently used for constant color blending on the target bitmap. Since: 5.2.5 > *[Unstable API]:* New API. See also: [al_set_bitmap_blend_color] ### API: al_set_bitmap_blender Sets the function to use for blending when rendering to the target bitmap. If no blender is set for a given bitmap at draw time, the values set for [al_set_blender]/[al_set_separate_blender] are used instead. To use separate functions for chroma (RGB) and alpha channels, use [al_set_separate_bitmap_blender]. See [al_set_blender] for more information about how blending works. See also: [al_set_separate_bitmap_blender], [al_reset_bitmap_blender] Since: 5.2.5 > *[Unstable API]:* New API. ### API: al_set_separate_bitmap_blender Like [al_set_bitmap_blender], but allows specifying a separate blending operation for the alpha channel. This is useful if your target bitmap also has an alpha channel and the two alpha channels need to be combined in a different way than the color components. Since: 5.2.5 > *[Unstable API]:* New API. See also: [al_set_bitmap_blender], [al_reset_bitmap_blender] ### API: al_set_bitmap_blend_color Sets the color to use for `ALLEGRO_CONST_COLOR` or `ALLEGRO_INVERSE_CONST_COLOR` blend operations. Since: 5.2.5 > *[Unstable API]:* New API. See also: [al_set_bitmap_blender], [al_reset_bitmap_blender] ### API: al_reset_bitmap_blender Resets the blender for this bitmap to the default. After resetting the bitmap blender, the values set for [al_set_bitmap_blender]/[al_set_separate_bitmap_blender] will be used instead. Since: 5.2.5 > *[Unstable API]:* New API. See also: [al_set_bitmap_blender] ## Drawing operations All drawing operations draw to the current "target bitmap" of the current thread. Initially, the target bitmap will be the backbuffer of the last display created in a thread. ### API: al_clear_to_color Clear the complete target bitmap, but confined by the clipping rectangle. See also: [ALLEGRO_COLOR], [al_set_clipping_rectangle], [al_clear_depth_buffer] ### API: al_clear_depth_buffer Clear the depth buffer (confined by the clipping rectangle) to the given value. A depth buffer is only available if it was requested with [al_set_new_display_option] and the requirement could be met by the [al_create_display] call creating the current display. Operations involving the depth buffer are also affected by [al_set_render_state]. For example, if `ALLEGRO_DEPTH_FUNCTION` is set to `ALLEGRO_RENDER_LESS` then depth buffer value of 1 represents infinite distance, and thus is a good value to use when clearing the depth buffer. Since: 5.1.2 See also: [al_clear_to_color], [al_set_clipping_rectangle], [al_set_render_state], [al_set_new_display_option] ### API: al_draw_bitmap Draws an unscaled, unrotated bitmap at the given position to the current target bitmap (see [al_set_target_bitmap]). `flags` can be a combination of: * ALLEGRO_FLIP_HORIZONTAL - flip the bitmap about the y-axis * ALLEGRO_FLIP_VERTICAL - flip the bitmap about the x-axis > *Note:* The current target bitmap must be a different bitmap. Drawing a bitmap to itself (or to a sub-bitmap of itself) or drawing a sub-bitmap to its parent (or another sub-bitmap of its parent) are not currently supported. To copy part of a bitmap into the same bitmap simply use a temporary bitmap instead. > *Note:* The backbuffer (or a sub-bitmap thereof) can not be transformed, blended or tinted. If you need to draw the backbuffer draw it to a temporary bitmap first with no active transformation (except translation). Blending and tinting settings/parameters will be ignored. This does not apply when drawing into a memory bitmap. See also: [al_draw_bitmap_region], [al_draw_scaled_bitmap], [al_draw_rotated_bitmap], [al_draw_scaled_rotated_bitmap] ### API: al_draw_tinted_bitmap Like [al_draw_bitmap] but multiplies all colors in the bitmap with the given color. For example: ~~~~c al_draw_tinted_bitmap(bitmap, al_map_rgba_f(0.5, 0.5, 0.5, 0.5), x, y, 0); ~~~~ The above will draw the bitmap 50% transparently (r/g/b values need to be pre-multiplied with the alpha component with the default blend mode). ~~~~c al_draw_tinted_bitmap(bitmap, al_map_rgba_f(1, 0, 0, 1), x, y, 0); ~~~~ The above will only draw the red component of the bitmap. See [al_draw_bitmap] for a note on restrictions on which bitmaps can be drawn where. See also: [al_draw_bitmap] ### API: al_draw_bitmap_region Draws a region of the given bitmap to the target bitmap. * sx - source x * sy - source y * sw - source width (width of region to blit) * sh - source height (height of region to blit) * dx - destination x * dy - destination y * flags - same as for [al_draw_bitmap] See [al_draw_bitmap] for a note on restrictions on which bitmaps can be drawn where. See also: [al_draw_bitmap], [al_draw_scaled_bitmap], [al_draw_rotated_bitmap], [al_draw_scaled_rotated_bitmap] ### API: al_draw_tinted_bitmap_region Like [al_draw_bitmap_region] but multiplies all colors in the bitmap with the given color. See [al_draw_bitmap] for a note on restrictions on which bitmaps can be drawn where. See also: [al_draw_tinted_bitmap] ### API: al_draw_pixel Draws a single pixel at x, y. This function, unlike [al_put_pixel], does blending and, unlike [al_put_blended_pixel], respects the transformations (that is, the pixel's position is transformed, but its size is unaffected - it remains a pixel). This function can be slow if called often; if you need to draw a lot of pixels consider using [al_draw_prim] with ALLEGRO_PRIM_POINT_LIST from the primitives addon. * x - destination x * y - destination y * color - color of the pixel > *Note:* This function may not draw exactly where you expect it to. See the pixel-precise output section on the primitives addon documentation for details on how to control exactly where the pixel is drawn. See also: [ALLEGRO_COLOR], [al_put_pixel] ### API: al_draw_rotated_bitmap Draws a rotated version of the given bitmap to the target bitmap. The bitmap is rotated by 'angle' radians clockwise. The point at cx/cy relative to the upper left corner of the bitmap will be drawn at dx/dy and the bitmap is rotated around this point. If cx,cy is 0,0 the bitmap will rotate around its upper left corner. * cx - center x (relative to the bitmap) * cy - center y (relative to the bitmap) * dx - destination x * dy - destination y * angle - angle by which to rotate (radians) * flags - same as for [al_draw_bitmap] Example ~~~~c float w = al_get_bitmap_width(bitmap); float h = al_get_bitmap_height(bitmap); al_draw_rotated_bitmap(bitmap, w / 2, h / 2, x, y, ALLEGRO_PI / 2, 0); ~~~~ The above code draws the bitmap centered on x/y and rotates it 90° clockwise. See [al_draw_bitmap] for a note on restrictions on which bitmaps can be drawn where. See also: [al_draw_bitmap], [al_draw_bitmap_region], [al_draw_scaled_bitmap], [al_draw_scaled_rotated_bitmap] ### API: al_draw_tinted_rotated_bitmap Like [al_draw_rotated_bitmap] but multiplies all colors in the bitmap with the given color. See [al_draw_bitmap] for a note on restrictions on which bitmaps can be drawn where. See also: [al_draw_tinted_bitmap] ### API: al_draw_scaled_rotated_bitmap Like [al_draw_rotated_bitmap], but can also scale the bitmap. The point at cx/cy in the bitmap will be drawn at dx/dy and the bitmap is rotated and scaled around this point. * cx - center x * cy - center y * dx - destination x * dy - destination y * xscale - how much to scale on the x-axis (e.g. 2 for twice the size) * yscale - how much to scale on the y-axis * angle - angle by which to rotate (radians) * flags - same as for [al_draw_bitmap] See [al_draw_bitmap] for a note on restrictions on which bitmaps can be drawn where. See also: [al_draw_bitmap], [al_draw_bitmap_region], [al_draw_scaled_bitmap], [al_draw_rotated_bitmap] ### API: al_draw_tinted_scaled_rotated_bitmap Like [al_draw_scaled_rotated_bitmap] but multiplies all colors in the bitmap with the given color. See [al_draw_bitmap] for a note on restrictions on which bitmaps can be drawn where. See also: [al_draw_tinted_bitmap] ### API: al_draw_tinted_scaled_rotated_bitmap_region Like [al_draw_tinted_scaled_rotated_bitmap] but you specify an area within the bitmap to be drawn. You can get the same effect with a sub bitmap: ~~~~c al_draw_tinted_scaled_rotated_bitmap(bitmap, sx, sy, sw, sh, tint, cx, cy, dx, dy, xscale, yscale, angle, flags); /* This draws the same: */ sub_bitmap = al_create_sub_bitmap(bitmap, sx, sy, sw, sh); al_draw_tinted_scaled_rotated_bitmap(sub_bitmap, tint, cx, cy, dx, dy, xscale, yscale, angle, flags); ~~~~ See [al_draw_bitmap] for a note on restrictions on which bitmaps can be drawn where. Since: 5.0.6, 5.1.0 See also: [al_draw_tinted_bitmap] ### API: al_draw_scaled_bitmap Draws a scaled version of the given bitmap to the target bitmap. * sx - source x * sy - source y * sw - source width * sh - source height * dx - destination x * dy - destination y * dw - destination width * dh - destination height * flags - same as for [al_draw_bitmap] See [al_draw_bitmap] for a note on restrictions on which bitmaps can be drawn where. See also: [al_draw_bitmap], [al_draw_bitmap_region], [al_draw_rotated_bitmap], [al_draw_scaled_rotated_bitmap], ### API: al_draw_tinted_scaled_bitmap Like [al_draw_scaled_bitmap] but multiplies all colors in the bitmap with the given color. See [al_draw_bitmap] for a note on restrictions on which bitmaps can be drawn where. See also: [al_draw_tinted_bitmap] ### API: al_get_target_bitmap Return the target bitmap of the calling thread. See also: [al_set_target_bitmap] ### API: al_put_pixel Draw a single pixel on the target bitmap. This operation is slow on non-memory bitmaps. Consider locking the bitmap if you are going to use this function multiple times on the same bitmap. This function is not affected by the transformations or the color blenders. See also: [ALLEGRO_COLOR], [al_get_pixel], [al_put_blended_pixel], [al_lock_bitmap] ### API: al_put_blended_pixel Like [al_put_pixel], but the pixel color is blended using the current blenders before being drawn. See also: [ALLEGRO_COLOR], [al_put_pixel] ## Target bitmap ### API: al_set_target_bitmap This function selects the bitmap to which all subsequent drawing operations in the calling thread will draw to. To return to drawing to a display, set the backbuffer of the display as the target bitmap, using [al_get_backbuffer]. As a convenience, you may also use [al_set_target_backbuffer]. Each allegro bitmap maintains two transformation matrices associated with it for drawing onto the bitmap. There is a view matrix and a projection matrix. When you call al_set_target_bitmap, these will be made current for the bitmap, affecting global OpenGL and DirectX states depending on the driver in use. Each video bitmap is tied to a display. When a video bitmap is set to as the target bitmap, the display that the bitmap belongs to is automatically made "current" for the calling thread (if it is not current already). Then drawing other bitmaps which are tied to the same display can be hardware accelerated. A single display cannot be current for multiple threads simultaneously. If you need to release a display, so it is not current for the calling thread, call `al_set_target_bitmap(NULL);` Setting a memory bitmap as the target bitmap will not change which display is current for the calling thread. On some platforms, Allegro automatically backs up the contents of video bitmaps because they may be occasionally lost (see discussion in [al_create_bitmap]'s documentation). If you're completely recreating the bitmap contents often (e.g. every frame) then you will get much better performance by creating the target bitmap with ALLEGRO_NO_PRESERVE_TEXTURE flag. OpenGL note: Framebuffer objects (FBOs) allow OpenGL to directly draw to a bitmap, which is very fast. When using an OpenGL display, if all of the following conditions are met an FBO will be created for use with the bitmap: * The GL_EXT_framebuffer_object OpenGL extension is available. * The bitmap is not a memory bitmap. * The bitmap is not currently locked. In Allegro 5.0.0, you had to be careful as an FBO would be kept around until the bitmap is destroyed or you explicitly called [al_remove_opengl_fbo] on the bitmap, wasting resources. In newer versions, FBOs will be freed automatically when the bitmap is no longer the target bitmap, *unless* you have called [al_get_opengl_fbo] to retrieve the FBO id. In the following example, no FBO will be created: ~~~~c lock = al_lock_bitmap(bitmap); al_set_target_bitmap(bitmap); al_put_pixel(x, y, color); al_unlock_bitmap(bitmap); ~~~~ The above allows using [al_put_pixel] on a locked bitmap without creating an FBO. In this example an FBO is created however: ~~~~c al_set_target_bitmap(bitmap); al_draw_line(x1, y1, x2, y2, color, 0); ~~~~ An OpenGL command will be used to directly draw the line into the bitmap's associated texture. See also: [al_get_target_bitmap], [al_set_target_backbuffer] ### API: al_set_target_backbuffer Same as `al_set_target_bitmap(al_get_backbuffer(display));` See also: [al_set_target_bitmap], [al_get_backbuffer] ### API: al_get_current_display Return the display that is "current" for the calling thread, or NULL if there is none. See also: [al_set_target_bitmap] ## Blending modes ### API: al_get_blender Returns the active blender for the current thread. You can pass NULL for values you are not interested in. See also: [al_set_blender], [al_get_separate_blender] ### API: al_get_separate_blender Returns the active blender for the current thread. You can pass NULL for values you are not interested in. See also: [al_set_separate_blender], [al_get_blender] ### API: al_get_blend_color Returns the color currently used for constant color blending (white by default). See also: [al_set_blend_color], [al_set_blender] Since: 5.1.12 ### API: al_set_blender Sets the function to use for blending for the current thread. Blending means, the source and destination colors are combined in drawing operations. Assume the source color (e.g. color of a rectangle to draw, or pixel of a bitmap to draw) is given as its red/green/blue/alpha components (if the bitmap has no alpha it always is assumed to be fully opaque, so 255 for 8-bit or 1.0 for floating point): *s = s.r, s.g, s.b, s.a*. And this color is drawn to a destination, which already has a color: *d = d.r, d.g, d.b, d.a*. The conceptional formula used by Allegro to draw any pixel then depends on the `op` parameter: * ALLEGRO_ADD r = d.r * df.r + s.r * sf.r g = d.g * df.g + s.g * sf.g b = d.b * df.b + s.b * sf.b a = d.a * df.a + s.a * sf.a * ALLEGRO_DEST_MINUS_SRC r = d.r * df.r - s.r * sf.r g = d.g * df.g - s.g * sf.g b = d.b * df.b - s.b * sf.b a = d.a * df.a - s.a * sf.a * ALLEGRO_SRC_MINUS_DEST r = s.r * sf.r - d.r * df.r g = s.g * sf.g - d.g * df.g b = s.b * sf.b - d.b * df.b a = s.a * sf.a - d.a * df.a Valid values for the factors `sf` and `df` passed to this function are as follows, where `s` is the source color, `d` the destination color and `cc` the color set with [al_set_blend_color] (white by default) * ALLEGRO_ZERO f = 0, 0, 0, 0 * ALLEGRO_ONE f = 1, 1, 1, 1 * ALLEGRO_ALPHA f = s.a, s.a, s.a, s.a * ALLEGRO_INVERSE_ALPHA f = 1 - s.a, 1 - s.a, 1 - s.a, 1 - s.a * ALLEGRO_SRC_COLOR (since: 5.0.10, 5.1.0) f = s.r, s.g, s.b, s.a * ALLEGRO_DEST_COLOR (since: 5.0.10, 5.1.8) f = d.r, d.g, d.b, d.a * ALLEGRO_INVERSE_SRC_COLOR (since: 5.0.10, 5.1.0) f = 1 - s.r, 1 - s.g, 1 - s.b, 1 - s.a * ALLEGRO_INVERSE_DEST_COLOR (since: 5.0.10, 5.1.8) f = 1 - d.r, 1 - d.g, 1 - d.b, 1 - d.a * ALLEGRO_CONST_COLOR (since: 5.1.12, not supported on OpenGLES 1.0) f = cc.r, cc.g, cc.b, cc.a * ALLEGRO_INVERSE_CONST_COLOR (since: 5.1.12, not supported on OpenGLES 1.0) f = 1 - cc.r, 1 - cc.g, 1 - cc.b, 1 - cc.a Blending examples: So for example, to restore the default of using premultiplied alpha blending, you would use: ~~~~c al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); ~~~~ As formula: r = d.r * (1 - s.a) + s.r * 1 g = d.g * (1 - s.a) + s.g * 1 b = d.b * (1 - s.a) + s.b * 1 a = d.a * (1 - s.a) + s.a * 1 If you are using non-pre-multiplied alpha, you could use ~~~~c al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); ~~~~ Additive blending would be achieved with ~~~~c al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); ~~~~ Copying the source to the destination (including alpha) unmodified ~~~~c al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); ~~~~ Multiplying source and destination components ~~~~c al_set_blender(ALLEGRO_ADD, ALLEGRO_DEST_COLOR, ALLEGRO_ZERO) ~~~~ Tinting the source (like [al_draw_tinted_bitmap]) ~~~~c al_set_blender(ALLEGRO_ADD, ALLEGRO_CONST_COLOR, ALLEGRO_ONE); al_set_blend_color(al_map_rgb(0, 96, 255)); /* nice Chrysler blue */ ~~~~ Averaging source and destination pixels ~~~~c al_set_blender(ALLEGRO_ADD, ALLEGRO_CONST_COLOR, ALLEGRO_CONST_COLOR); al_set_blend_color(al_map_rgba_f(0.5, 0.5, 0.5, 0.5)); ~~~~ As formula: r = d.r * 0 + s.r * d.r g = d.g * 0 + s.g * d.g b = d.b * 0 + s.b * d.b a = d.a * 0 + s.a * d.a See also: [al_set_separate_blender], [al_set_blend_color], [al_get_blender] ### API: al_set_separate_blender Like [al_set_blender], but allows specifying a separate blending operation for the alpha channel. This is useful if your target bitmap also has an alpha channel and the two alpha channels need to be combined in a different way than the color components. See also: [al_set_blender], [al_get_blender], [al_get_separate_blender] ### API: al_set_blend_color Sets the color to use for blending when using the ALLEGRO_CONST_COLOR or ALLEGRO_INVERSE_CONST_COLOR blend functions. See [al_set_blender] for more information. See also: [al_set_blender], [al_get_blend_color] Since: 5.1.12 ## Clipping ### API: al_get_clipping_rectangle Gets the clipping rectangle of the target bitmap. See also: [al_set_clipping_rectangle] ### API: al_set_clipping_rectangle Set the region of the target bitmap or display that pixels get clipped to. The default is to clip pixels to the entire bitmap. See also: [al_get_clipping_rectangle], [al_reset_clipping_rectangle] ### API: al_reset_clipping_rectangle Equivalent to calling `al_set_clipping_rectangle(0, 0, w, h)' where *w* and *h* are the width and height of the target bitmap respectively. Does nothing if there is no target bitmap. See also: [al_set_clipping_rectangle] Since: 5.0.6, 5.1.0 ## Graphics utility functions ### API: al_convert_mask_to_alpha Convert the given mask color to an alpha channel in the bitmap. Can be used to convert older 4.2-style bitmaps with magic pink to alpha-ready bitmaps. See also: [ALLEGRO_COLOR] ## Deferred drawing ### API: al_hold_bitmap_drawing Enables or disables deferred bitmap drawing. This allows for efficient drawing of many bitmaps that share a parent bitmap, such as sub-bitmaps from a tilesheet or simply identical bitmaps. Drawing bitmaps that do not share a parent is less efficient, so it is advisable to stagger bitmap drawing calls such that the parent bitmap is the same for large number of those calls. While deferred bitmap drawing is enabled, the only functions that can be used are the bitmap drawing functions and font drawing functions. Changing the state such as the blending modes will result in undefined behaviour. One exception to this rule are the non-projection transformations. It is possible to set a new transformation while the drawing is held. No drawing is guaranteed to take place until you disable the hold. Thus, the idiom of this function's usage is to enable the deferred bitmap drawing, draw as many bitmaps as possible, taking care to stagger bitmaps that share parent bitmaps, and then disable deferred drawing. As mentioned above, this function also works with bitmap and truetype fonts, so if multiple lines of text need to be drawn, this function can speed things up. See also: [al_is_bitmap_drawing_held] ### API: al_is_bitmap_drawing_held Returns whether the deferred bitmap drawing mode is turned on or off. See also: [al_hold_bitmap_drawing] ## Image I/O ### API: al_register_bitmap_loader Register a handler for [al_load_bitmap]. The given function will be used to handle the loading of bitmaps files with the given extension. The extension should include the leading dot ('.') character. It will be matched case-insensitively. The `loader` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. See also: [al_register_bitmap_saver], [al_register_bitmap_loader_f] ### API: al_register_bitmap_saver Register a handler for [al_save_bitmap]. The given function will be used to handle the saving of bitmaps files with the given extension. The extension should include the leading dot ('.') character. It will be matched case-insensitively. The `saver` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. See also: [al_register_bitmap_loader], [al_register_bitmap_saver_f] ### API: al_register_bitmap_loader_f Register a handler for [al_load_bitmap_f]. The given function will be used to handle the loading of bitmaps files with the given extension. The extension should include the leading dot ('.') character. It will be matched case-insensitively. The `fs_loader` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. See also: [al_register_bitmap_loader] ### API: al_register_bitmap_saver_f Register a handler for [al_save_bitmap_f]. The given function will be used to handle the saving of bitmaps files with the given extension. The extension should include the leading dot ('.') character. It will be matched case-insensitively. The `saver_f` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. See also: [al_register_bitmap_saver] ### API: al_load_bitmap Loads an image file into a new [ALLEGRO_BITMAP]. The file type is determined by [al_identify_bitmap], using the extension as a fallback in case identification is not possible. Returns NULL on error. This is the same as calling [al_load_bitmap_flags] with a flags parameter of 0. > *Note:* the core Allegro library does not support any image file formats by default. You must use the allegro_image addon, or register your own format handler. See also: [al_load_bitmap_flags], [al_load_bitmap_f], [al_register_bitmap_loader], [al_set_new_bitmap_format], [al_set_new_bitmap_flags], [al_init_image_addon] ### API: al_load_bitmap_flags Loads an image file into a new [ALLEGRO_BITMAP]. The file type is determined by [al_identify_bitmap], using the extension as a fallback in case identification is not possible. Returns NULL on error. The flags parameter may be a combination of the following constants: ALLEGRO_NO_PREMULTIPLIED_ALPHA : By default, Allegro pre-multiplies the alpha channel of an image with the images color data when it loads it. Typically that would look something like this: ~~~~c r = get_float_byte(); g = get_float_byte(); b = get_float_byte(); a = get_float_byte(); r = r * a; g = g * a; b = b * a; set_image_pixel(x, y, r, g, b, a); ~~~~ The reason for this can be seen in the Allegro example ex_premulalpha, ie, using pre-multiplied alpha gives more accurate color results in some cases. To use alpha blending with images loaded with pre-multiplied alpha, you would use the default blending mode, which is set with al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA). The ALLEGRO_NO_PREMULTIPLIED_ALPHA flag being set will ensure that images are not loaded with alpha pre-multiplied, but are loaded with color values direct from the image. That looks like this: ~~~~c r = get_float_byte(); g = get_float_byte(); b = get_float_byte(); a = get_float_byte(); set_image_pixel(x, y, r, g, b, a); ~~~~ To draw such an image using regular alpha blending, you would use al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) to set the correct blender. This has some caveats. First, as mentioned above, drawing such an image can result in less accurate color blending (when drawing an image with linear filtering on, the edges will be darker than they should be). Second, the behaviour is somewhat confusing, which is explained in the example below. ~~~~c // Load and create bitmaps with an alpha channel al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA); // Load some bitmap with alpha in it bmp = al_load_bitmap("some_alpha_bitmap.png"); // We will draw to this buffer and then draw this buffer to the screen tmp_buffer = al_create_bitmap(SCREEN_W, SCREEN_H); // Set the buffer as the target and clear it al_set_target_bitmap(tmp_buffer); al_clear_to_color(al_map_rgba_f(0, 0, 0, 1)); // Draw the bitmap to the temporary buffer al_draw_bitmap(bmp, 0, 0, 0); // Finally, draw the buffer to the screen // The output will look incorrect (may take close inspection // depending on the bitmap -- it may also be very obvious) al_set_target_bitmap(al_get_backbuffer(display)); al_draw_bitmap(tmp_buffer, 0, 0, 0); ~~~~ To explain further, if you have a pixel with 0.5 alpha, and you're using (ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) for blending, the formula is: a = da * dst + sa * src Expands to: result_a = dst_a * (1-0.5) + 0.5 * 0.5 So if you draw the image to the temporary buffer, it is blended once resulting in 0.75 alpha, then drawn again to the screen, blended in the same way, resulting in a pixel has 0.1875 as an alpha value. ALLEGRO_KEEP_INDEX : Load the palette indices of 8-bit .bmp and .pcx files instead of the rgb colors. Since 5.1.0. ALLEGRO_KEEP_BITMAP_FORMAT : Force the resulting [ALLEGRO_BITMAP] to use the same format as the file. *This is not yet honoured.* > *Note:* the core Allegro library does not support any image file formats by default. You must use the allegro_image addon, or register your own format handler. Since: 5.1.0 See also: [al_load_bitmap] ### API: al_load_bitmap_f Loads an image from an [ALLEGRO_FILE] stream into a new [ALLEGRO_BITMAP]. The file type is determined by [al_identify_bitmap_f]. If identification is not possible, the passed 'ident' parameter, which is a file name extension including the leading dot, is used as a fallback, if it is not NULL. This is the same as calling [al_load_bitmap_flags_f] with 0 for the flags parameter. Returns NULL on error. The file remains open afterwards. > *Note:* the core Allegro library does not support any image file formats by default. You must use the allegro_image addon, or register your own format handler. See also: [al_load_bitmap_flags_f], [al_load_bitmap], [al_register_bitmap_loader_f], [al_init_image_addon] ### API: al_load_bitmap_flags_f Loads an image from an [ALLEGRO_FILE] stream into a new [ALLEGRO_BITMAP]. The file type is determined by [al_identify_bitmap_f]. If identification is not possible, the passed 'ident' parameter, which is a file name extension including the leading dot, is used as a fallback, if it is not NULL. The flags parameter is the same as for [al_load_bitmap_flags]. Returns NULL on error. The file remains open afterwards. > *Note:* the core Allegro library does not support any image file formats by default. You must use the allegro_image addon, or register your own format handler. Since: 5.1.0 See also: [al_load_bitmap_f], [al_load_bitmap_flags] ### API: al_save_bitmap Saves an [ALLEGRO_BITMAP] to an image file. The file type is determined by the extension. Returns true on success, false on error. > *Note:* the core Allegro library does not support any image file formats by default. You must use the allegro_image addon, or register your own format handler. See also: [al_save_bitmap_f], [al_register_bitmap_saver], [al_init_image_addon] ### API: al_save_bitmap_f Saves an [ALLEGRO_BITMAP] to an [ALLEGRO_FILE] stream. The file type is determined by the passed 'ident' parameter, which is a file name extension including the leading dot. Returns true on success, false on error. The file remains open afterwards. > *Note:* the core Allegro library does not support any image file formats by default. You must use the allegro_image addon, or register your own format handler. See also: [al_save_bitmap], [al_register_bitmap_saver_f], [al_init_image_addon] ### API: al_register_bitmap_identifier Register an identify handler for [al_identify_bitmap]. The given function will be used to detect files for the given extension. It will be called with a single argument of type [ALLEGRO_FILE] which is a file handle opened for reading and located at the first byte of the file. The handler should try to read as few bytes as possible to safely determine if the given file contents correspond to the type with the extension and return true in that case, false otherwise. The file handle must not be closed but there is no need to reset it to the beginning. The extension should include the leading dot ('.') character. It will be matched case-insensitively. The `identifier` argument may be NULL to unregister an entry. Returns true on success, false on error. Returns false if unregistering an entry that doesn't exist. Since: 5.1.12 See also: [al_identify_bitmap] ### API: al_identify_bitmap This works exactly as [al_identify_bitmap_f] but you specify the filename of the file for which to detect the type and not a file handle. The extension, if any, of the passed filename is not taken into account - only the file contents. Since: 5.1.12 See also: [al_init_image_addon], [al_identify_bitmap_f], [al_register_bitmap_identifier] ### API: al_identify_bitmap_f Tries to guess the bitmap file type of the open ALLEGRO_FILE by reading the first few bytes. By default Allegro cannot recognize any file types, but calling [al_init_image_addon] will add detection of (some of) the types it can read. You can also use [al_register_bitmap_identifier] to add identification for custom file types. Returns a pointer to a static string with a file extension for the type, including the leading dot. For example ".png" or ".jpg". Returns NULL if the bitmap type cannot be determined. Since: 5.1.12 See also: [al_init_image_addon], [al_identify_bitmap], [al_register_bitmap_identifier] ## Render State ### API: ALLEGRO_RENDER_STATE Possible render states which can be set with [al_set_render_state]: ALLEGRO_ALPHA_TEST : If this is set to 1, the values of ALLEGRO_ALPHA_FUNCTION and ALLEGRO_ALPHA_TEST_VALUE define a comparison function which is performed on the alpha component of each pixel. Only if it evaluates to true the pixel is written. Otherwise no subsequent processing (like depth test or blending) is performed. This can be very useful, for example if a depth buffer is used but you do not want fully transparent pixels to modify it. ALLEGRO_ALPHA_FUNCTION : One of [ALLEGRO_RENDER_FUNCTION], only used when ALLEGRO_ALPHA_TEST is 1. ALLEGRO_ALPHA_TEST_VALUE : Only used when ALLEGRO_ALPHA_TEST is 1. Should be a value of 0 - 255. ALLEGRO_WRITE_MASK : This determines how the framebuffer and depthbuffer are updated whenever a pixel is written (in case alpha and/or depth testing is enabled: after all such enabled tests succeed). Depth values are only written if ALLEGRO_DEPTH_TEST is 1, in addition to the write mask flag being set. ALLEGRO_DEPTH_TEST : If this is set to 1, compare the depth value of any newly written pixels with the depth value already in the buffer, according to ALLEGRO_DEPTH_FUNCTION. Allegro primitives with no explicit z coordinate will write a value of 0 into the depth buffer. ALLEGRO_DEPTH_FUNCTION : One of [ALLEGRO_RENDER_FUNCTION], only used when ALLEGRO_DEPTH_TEST is 1. Since: 5.1.2 See also: [al_set_render_state], [ALLEGRO_RENDER_FUNCTION], [ALLEGRO_WRITE_MASK_FLAGS] ### API: ALLEGRO_RENDER_FUNCTION Possible functions are: - ALLEGRO_RENDER_NEVER - ALLEGRO_RENDER_ALWAYS - ALLEGRO_RENDER_LESS - ALLEGRO_RENDER_EQUAL - ALLEGRO_RENDER_LESS_EQUAL - ALLEGRO_RENDER_GREATER - ALLEGRO_RENDER_NOT_EQUAL - ALLEGRO_RENDER_GREATER_EQUAL Since: 5.1.2 See also: [al_set_render_state] ### API: ALLEGRO_WRITE_MASK_FLAGS Each enabled bit means the corresponding value is written, a disabled bit means it is not. - ALLEGRO_MASK_RED - ALLEGRO_MASK_GREEN - ALLEGRO_MASK_BLUE - ALLEGRO_MASK_ALPHA - ALLEGRO_MASK_DEPTH - ALLEGRO_MASK_RGB - Same as RED | GREEN | BLUE. - ALLEGRO_MASK_RGBA - Same as RGB | ALPHA. Since: 5.1.2 See also: [al_set_render_state] ### API: al_get_render_state Returns one of several render attributes; see [ALLEGRO_RENDER_STATE] for details. This function will return -1 when there is no current display. Since: 5.2.10 See also: [al_set_render_state], [ALLEGRO_RENDER_STATE], [ALLEGRO_RENDER_FUNCTION], [ALLEGRO_WRITE_MASK_FLAGS] ### API: al_set_render_state Set one of several render attributes; see [ALLEGRO_RENDER_STATE] for details. This function does nothing if the target bitmap is a memory bitmap. Since: 5.1.2 See also: [al_get_render_state], [ALLEGRO_RENDER_STATE], [ALLEGRO_RENDER_FUNCTION], [ALLEGRO_WRITE_MASK_FLAGS] ### API: al_backup_dirty_bitmap On some platforms, notably Windows Direct3D and Android, textures may be lost at any time for events such as display resize or switching out of the app. On those platforms, bitmaps created without the ALLEGRO_NO_PRESERVE_TEXTURE flag automatically get backed up to system memory every time al_flip_display is called. This function gives you more control over when your bitmaps get backed up. By calling this function after modifying a bitmap, you can make sure the bitmap is backed up right away instead of during the next flip. Since: 5.2.1 > *[Unstable API]:* This API is new and subject to refinement. See also: [al_backup_dirty_bitmaps], [al_create_bitmap] ### API: al_backup_dirty_bitmaps Backs up all of a display's bitmaps to system memory. Since: 5.2.1 > *[Unstable API]:* This API is new and subject to refinement. See also: [al_backup_dirty_bitmap] allegro5-5.2.10.1/docs/src/refman/haptic.txt000066400000000000000000000724351473414355200204730ustar00rootroot00000000000000# Haptic routines Haptic functions support force feedback and vibration on input devices. These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ Currently force feedback is fully supported on Linux and on Windows for DirectInput compatible devices. There is also minimal support for Android. It is not yet supported on OSX, iOS, or on Windows for XInput compatible devices. ## API: ALLEGRO_HAPTIC This is an abstract data type representing a haptic device that supports force feedback or vibration. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. See also: [al_get_haptic_from_joystick] ## API: ALLEGRO_HAPTIC_CONSTANTS This enum contains flags that are used to define haptic effects and capabilities. If the flag is set in the return value of [al_get_haptic_capabilities], it means the device supports the given effect. The value of these flags should be set into a [ALLEGRO_HAPTIC_EFFECT] struct to determine what kind of haptic effect should be played. * ALLEGRO_HAPTIC_RUMBLE - simple vibration effects * ALLEGRO_HAPTIC_PERIODIC - periodic, wave-form effects * ALLEGRO_HAPTIC_CONSTANT - constant effects * ALLEGRO_HAPTIC_SPRING - spring effects * ALLEGRO_HAPTIC_FRICTION - friction effects * ALLEGRO_HAPTIC_DAMPER - damper effects * ALLEGRO_HAPTIC_INERTIA - inertia effects * ALLEGRO_HAPTIC_RAMP - ramp effects * ALLEGRO_HAPTIC_SQUARE - square wave periodic effect * ALLEGRO_HAPTIC_TRIANGLE - triangle wave periodic effect * ALLEGRO_HAPTIC_SINE - sine wave periodic effect * ALLEGRO_HAPTIC_SAW_UP - upwards saw wave periodic effect * ALLEGRO_HAPTIC_SAW_DOWN - downwards saw wave periodic effect * ALLEGRO_HAPTIC_CUSTOM - custom wave periodic effect * ALLEGRO_HAPTIC_GAIN - the haptic device supports gain setting * ALLEGRO_HAPTIC_ANGLE - the haptic device supports angle coordinates * ALLEGRO_HAPTIC_RADIUS - the haptic device supports radius coordinates * ALLEGRO_HAPTIC_AZIMUTH - the haptic device supports azimuth coordinates * ALLEGRO_HAPTIC_AUTOCENTER Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. See also: [al_get_haptic_capabilities], [ALLEGRO_HAPTIC_EFFECT] ## API: ALLEGRO_HAPTIC_EFFECT This struct models a particular haptic or vibration effect. It needs to be filled in correctly and uploaded to a haptic device before the device can play it back. *Fields:* type : The type of the haptic effect. May be one of the ALLEGRO_HAPTIC_CONSTANTS constants between or equal to ALLEGRO_HAPTIC_RUMBLE and ALLEGRO_HAPTIC_RAMP. * If `type` is set to ALLEGRO_HAPTIC_RUMBLE, then the effect is a simple "rumble" or vibration effect that shakes the device. In some cases, such as on a mobile platform, the whole device may shake. * If `type` is set to ALLEGRO_HAPTIC_PERIODIC, the effect is a shake or vibration of which the intensity is a periodic wave form. * If `type` is set to ALLEGRO_HAPTIC_CONSTANT, the effect is a constant pressure, motion or push-back in a certain direction of the axes of the device. * If `type` is set to ALLEGRO_HAPTIC_SPRING, the effect is a springy kind of resistance against motion of the axes of the haptic device. * If `type` is set to ALLEGRO_HAPTIC_FRICTION, the effect is a friction kind of resistance against motion of the axes of the haptic device. * If `type` is set to ALLEGRO_HAPTIC_DAMPER, the effect is a damper kind of resistance against motion of the axes of the haptic device. * If `type` is set to ALLEGRO_HAPTIC_INERTIA, the effect causes inertia or slowness of motions on the axes of the haptic device. * If `type` is set to ALLEGRO_HAPTIC_RAMP, the effect causes a pressure or push-back that ramps up or down depending on the position of the axis. direction : The direction of location in 3D space where the effect should be played. Allegro haptic devices model directions in 3D space using spherical coordinates. However, the haptic device may not support localized effects, or may not support all coordinate components. In Allegro's coordinate system, the value in `direction.angle` determines the planar angle between the effect and the direction of the user who holds the device, expressed in radians. This angle increases clockwise away from the user. So, an effect with an angle 0.0 takes place in the direction of the user of the haptic device, an angle of π/2 is to the left of the user, an angle of π means the direction away from the user, and an angle of 3π/2 means to the right of the user. If [al_get_haptic_capabilities] has the flag ALLEGRO_HAPTIC_ANGLE set, then setting `direction.angle` is supported. Otherwise, it is unsupported, and you should set it to 0. The value in `direction.radius` is a relative value between 0.0 and 1.0 that determines the relative distance from the center of the haptic device at which the effect will play back. A value of 0 means that the effect should play back at the center of the device. A value of 1.0 means that the effect should play back away from the center as far as is possible. If [al_get_haptic_capabilities] has the flag ALLEGRO_HAPTIC_RADIUS set, then setting `direction.radius` is supported. Otherwise, it is unsupported, and you should set it to 0. The value in `direction.azimuth` determines the elevation angle between the effect and the plane in which the user is holding the device, expressed in radians. An effect with an azimuth 0.0 plays back in the plane in which the user is holding the device, an azimuth +π/2 means the effect plays back vertically above the user plane, and an azimuth -π/2 means the effect plays back vertically below the user plane. If [al_get_haptic_capabilities] has the flag ALLEGRO_HAPTIC_AZIMUTH set, then setting `direction.azimuth` is supported. Otherwise, it is unsupported, and you should set it to 0. replay : Determines how the effect should be played back. `replay.length` is the duration in seconds of the effect, and `replay.delay` is the time in seconds that the effect playback should be delayed when playback is started with [al_play_haptic_effect]. data : Determines in detail the parameters of the haptic effect to play back. If `type` is set to ALLEGRO_HAPTIC_RUMBLE, then `data.rumble.strong_magnitude` must be set to a relative magnitude between 0.0 and 1.0 to determine how intensely the "large" rumble motor of the haptic device will vibrate, and `data.rumble.weak_magnitude` must be set to relative magnitude between 0.0 and 1.0 to determine how intensely the "weak" ruble motor of the haptic device will vibrate. Not all devices have a "weak" motor, in which case the value set in `data.rumble.weak_magnitude` will be ignored. If `type` is set to ALLEGRO_HAPTIC_PERIODIC, then data.periodic.waveform must be set to one of ALLEGRO_HAPTIC_SQUARE, ALLEGRO_HAPTIC_TRIANGLE, ALLEGRO_HAPTIC_SINE, ALLEGRO_HAPTIC_SAW_UP, ALLEGRO_HAPTIC_SAW_DOWN, ALLEGRO_HAPTIC_CUSTOM. This will then determine the wave form of the vibration effect that will be played on the haptic device. In these cases, `data.periodic.period` must be set to the period in seconds of the wave form. The field `data.periodic.magnitude` must be set to the relative magnitude of intensity between -1.0 and 1.0 at which the wave form of the vibration will be played back. The field `data.periodic.offset` must be filled in with the offset from origin in seconds of the wave form of vibration, and the field `data.periodic.phase` is the phase of the wave form of vibration in seconds. If `data.periodic.waveform` is set to ALLEGRO_HAPTIC_CUSTOM, then `data.periodic.custom_data` must point to an array of `data.periodic.custom_len` doubles, each with values between -1.0 and 1.0. This value array will determine the shape of the wave form of the haptic effect. ALLEGRO_HAPTIC_CUSTOM is not supported on some platforms, so use [al_get_haptic_capabilities] to check if it's available. If it isn't, you may want to play back a non-custom wave effect as a substitute instead. If `type` is set to ALLEGRO_HAPTIC_CONSTANT, then `data.constant.level` must be set to a relative intensity value between 0.0 and 1.0 to determine the intensity of the effect. If `type` is set to any of ALLEGRO_HAPTIC_SPRING, ALLEGRO_HAPTIC_FRICTION, ALLEGRO_HAPTIC_DAMPER, ALLEGRO_HAPTIC_INERTIA, ALLEGRO_HAPTIC_RAMP, then the `data.condition` struct should be filled in. To explain this better, it's best to keep in mind that these kinds of effects are most useful for steering-wheel kind of devices, where resistance or inertia should be applied when turning the device's wheel a certain distance to the left or right. The field `data.condition.right_saturation` must be filled in with a relative magnitude between -1.0 and 1.0 to determine the intensity of resistance or inertia on the "right" side of the axis. Likewise, `data.condition.left_saturation` must be filled in with a relative magnitude between -1.0 and 1.0 to determine the intensity of resistance or inertia on the "left" side of the axis. The field `data.condition.deadband` must be filled in with a relative value between 0.0 and 1.0 to determine the relative width of the "dead band" of the haptic effect. As long as the axis of the haptic device remains in the "dead band" area, the effect will not be applied. A value of 0.0 means there is no dead band, and a value of 1.0 means it applied over the whole range of the axis in question. The field `data.condition.center` must be filled in with a relative value between -1.0 and 1.0 to determine the relative position of the "center" of the effect around which the dead band is centered. It should be set to 0.0 in case the center should not be shifted. The field `data.condition.right_coef` and `data.condition.right_left_coef` must be filled in with a relative coefficient, that will determine how quickly the effect ramps up on the right and left side. If set to 1.0, then the effect will be immediately at full intensity when outside of the dead band. If set to 0.0 the effect will not be felt at all. If `type` is set to ALLEGRO_HAPTIC_RAMP, then `data.ramp.start_level` should be set to a relative magnitude value between -1.0 and 1.0 to determine the initial intensity of the haptic effect. The field `data.ramp.end_level` should be set to a relative magnitude value between -1.0 and 1.0 to determine the final intensity of the haptic effect at the end of playback. If `type` is set to any of ALLEGRO_HAPTIC_PERIODIC, ALLEGRO_HAPTIC_CONSTANT, ALLEGRO_HAPTIC_RAMP, then `data.envelope` determines the "envelope" of the effect. That is, it determines the duration and intensity for the ramp-up attack or "fade in" and the ramp-down or "fade out" of the effect. In these cases the field `data.envelope.attack_level` must be set to a relative value between 0.0 and 1.0 that determines the intensity the effect should have when it starts playing (after `replay.delay` seconds have passed since the playback was started). The field `data.envelope.attack_length` must be set to the time in seconds that the effect should ramp up to the maximum intensity as set by the other parameters. If `data.envelope.attack_length` is 0, then the effect will play immediately at full intensity. The field `data.envelope.fade_level` must be set to a relative value between 0.0 and 1.0 that determines the intensity the effect should have when it stops playing after `replay.length + replay.delay` seconds have passed since the playback of the effect started. The field `data.envelope.fade_length` must be set to the time in seconds that the effect should fade out before it finishes playing. If `data.envelope.fade_length` is 0, then the effect will not fade out. If you don't want to use an envelope, then set all four fields of `data.envelope` to 0.0. The effect will then play back at full intensity throughout its playback. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: ALLEGRO_HAPTIC_EFFECT_ID This struct is used as a handle to control playback of a haptic effect and should be considered opaque. Its implementation is visible merely to allow allocation by the users of the Allegro library. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_install_haptic Installs the haptic (force feedback) device subsystem. This must be called before using any other haptic-related functions. Returns true if the haptics subsystem could be initialized correctly, false in case of error. For portability you should first open a display before calling [al_install_haptic]. On some platforms, such as DirectInput under Windows, [al_install_haptic] will only work if at least one active display is available. This display must stay available until [al_uninstall_haptic] is called. If you need to close and reopen your active display for example, then you should call [al_uninstall_haptic] before closing the display, and [al_install_haptic] after opening it again. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_uninstall_haptic Uninstalls the haptic device subsystem. This is useful since on some platforms haptic effects are bound to the active display. If you need to close and reopen your active display for example, then you should call [al_uninstall_haptic] before closing the display, and [al_install_haptic] after opening it again. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_is_haptic_installed Returns true if the haptic device subsystem is installed, false if not. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_is_mouse_haptic Returns true if the mouse has haptic capabilities, false if not. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_is_keyboard_haptic Returns true if the keyboard has haptic capabilities, false if not. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_is_display_haptic Returns true if the display has haptic capabilities, false if not. This mainly concerns force feedback that shakes a hand held device, such as a phone or a tablet. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_is_joystick_haptic Returns true if the joystick has haptic capabilities, false if not. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_is_touch_input_haptic Returns true if the touch input device has haptic capabilities, false if not. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_get_haptic_from_mouse If the mouse has haptic capabilities, returns the associated haptic device handle. Otherwise returns NULL. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_get_haptic_from_keyboard If the keyboard has haptic capabilities, returns the associated haptic device handle. Otherwise returns NULL. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_get_haptic_from_display If the display has haptic capabilities, returns the associated haptic device handle. Otherwise returns NULL. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_get_haptic_from_joystick If the joystick has haptic capabilities, returns the associated haptic device handle. Otherwise returns NULL. It's necessary to call this again every time the joystick configuration changes, such as through hot plugging. In that case, the old haptic device must be released using [al_release_haptic]. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_get_haptic_from_touch_input If the touch input device has haptic capabilities, returns the associated haptic device handle. Otherwise returns NULL. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_release_haptic Releases the haptic device and its resources when it's not needed anymore. Should also be used in case the joystick configuration changed, such as when a joystick is hot plugged. This function also automatically releases all haptic effects that are still uploaded to the device and that have not been released manually using [al_release_haptic_effect]. Returns true on success or false if the haptic device couldn't be released for any reason, such as NULL being passed, the device not being active or failure in the driver. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_is_haptic_active Returns true if the haptic device can currently be used, false if not. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_get_haptic_capabilities Returns an integer with or'ed values from [ALLEGRO_HAPTIC_CONSTANTS], which, if set, indicate that the haptic device supports the given feature. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_is_haptic_capable Returns true if the haptic device supports the feature indicated by the query parameter, false if the feature is not supported. The query parameter must be one of the values of [ALLEGRO_HAPTIC_CONSTANTS]. Since: 5.1.9 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. See also: [al_get_haptic_capabilities] ## API: al_set_haptic_gain Sets the gain of the haptic device if supported. Gain is much like volume for sound, it is as if every effect's intensity is multiplied by it. Gain is a value between 0.0 and 1.0. Returns true if set successfully, false if not. Only works if [al_get_haptic_capabilities] returns a value that has [ALLEGRO_HAPTIC_GAIN][ALLEGRO_HAPTIC_CONSTANTS] set. If not, this function returns false, and all effects will be played without any gain influence. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_get_haptic_gain Returns the current gain of the device. Gain is much like volume for sound, it is as if every effect's intensity is multiplied by it. Gain is a value between 0.0 and 1.0. Only works correctly if [al_get_haptic_capabilities] returns a value that has [ALLEGRO_HAPTIC_GAIN][ALLEGRO_HAPTIC_CONSTANTS] set. If this is not set, this function will simply return 1.0 and all effects will be played without any gain influence. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_set_haptic_autocenter Turns on or off the automatic centering feature of the haptic device if supported. Depending on the device automatic centering may ensure that the axes of the device are centered again automatically after playing a haptic effect. The intensity parameter should be passed with a value between 0.0 and 1.0. The value 0.0 means automatic centering is disabled, and 1.0 means full strength automatic centering. Any value in between those two extremes will result in partial automatic centering. Some platforms do not support partial automatic centering. If that is the case, a value of less than 0.5 will turn it off, while a value equal to or higher to 0.5 will turn it on. Returns true if set successfully, false if not. Can only work if [al_get_haptic_capabilities] returns a value that has [ALLEGRO_HAPTIC_AUTOCENTER][ALLEGRO_HAPTIC_CONSTANTS] set. If not, this function returns false. Since: 5.1.9 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_get_haptic_autocenter Returns the current automatic centering intensity of the device. Depending on the device automatic centering may ensure that the axes of the device are centered again automatically after playing a haptic effect. The return value can be between 0.0 and 1.0. The value 0.0 means automatic centering is disabled, and 1.0 means automatic centering is enabled at full strength. Any value in between those two extremes means partial automatic centering is enabled. Some platforms do not support partial automatic centering. If that is the case, a value of less than 0.5 means it is turned off, while a value equal to or higher to 0.5 means it is turned on. Can only work if [al_get_haptic_capabilities] returns a value that has [ALLEGRO_HAPTIC_AUTOCENTER][ALLEGRO_HAPTIC_CONSTANTS] set. If not, this function returns 0.0. Since: 5.1.9 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_get_max_haptic_effects Returns the maximum amount of haptic effects that can be uploaded to the device. This depends on the operating system, driver, platform and the device itself. This may return a value as low as 1. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_is_haptic_effect_ok Returns true if the haptic device can play the haptic effect as given, false if not. The haptic effect must have been filled in completely and correctly. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_upload_haptic_effect Uploads the haptic effect to the device. The haptic effect must have been filled in completely and correctly. You must also pass in a pointer to a user allocated [ALLEGRO_HAPTIC_EFFECT_ID]. This `id` can be used to control playback of the effect. Returns true if the effect was successfully uploaded, false if not. The function [al_get_max_haptic_effects] returns how many effects can be uploaded to the device at the same time. The same haptic effect can be uploaded several times, as long as care is taken to pass in a different [ALLEGRO_HAPTIC_EFFECT_ID]. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_play_haptic_effect Plays back a previously uploaded haptic effect. The play_id must be a valid [ALLEGRO_HAPTIC_EFFECT_ID] obtained from [al_upload_haptic_effect], [al_upload_and_play_haptic_effect] or [al_rumble_haptic]. The haptic effect will be played back loop times in sequence. If loop is less than or equal to 1, then the effect will be played once only. This function returns immediately and doesn't wait for the playback to finish. It returns true if the playback was started successfully or false if not. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_upload_and_play_haptic_effect Uploads the haptic effect to the device and starts playback immediately. Returns true if the upload and playback were successful, false if either failed. In case false is returned, the haptic effect will be automatically released as if [al_release_haptic_effect] had been called, so there is no need to call it again manually in this case. However, if true is returned, it is necessary to call [al_release_haptic_effect] when the effect isn't needed anymore, to prevent the amount of available effects on the haptic devicefrom running out. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. See also: [al_upload_haptic_effect], [al_play_haptic_effect] ## API: al_stop_haptic_effect Stops playing a previously uploaded haptic effect. The play_id must be a valid [ALLEGRO_HAPTIC_EFFECT_ID] obtained from [al_upload_haptic_effect], [al_upload_and_play_haptic_effect] or [al_rumble_haptic]. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_is_haptic_effect_playing Returns true if the haptic effect is currently playing. Returns false if the effect has been stopped or if it has already finished playing, or if it has not been played yet. The play_id must be a valid [ALLEGRO_HAPTIC_EFFECT_ID] obtained from [al_upload_haptic_effect], [al_upload_and_play_haptic_effect] or [al_rumble_haptic]. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_get_haptic_effect_duration Returns the estimated duration in seconds of a single loop of the given haptic effect. The effect's `effect.replay` must have been filled in correctly before using this function. Since: 5.1.9 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_release_haptic_effect Releases a previously uploaded haptic effect from the device it has been uploaded to, allowing for other effects to be uploaded. The play_id must be a valid [ALLEGRO_HAPTIC_EFFECT_ID] obtained from [al_upload_haptic_effect], [al_upload_and_play_haptic_effect] or [al_rumble_haptic]. This function is called automatically when you call [al_release_haptic] on a [ALLEGRO_HAPTIC] for all effects that are still uploaded to the device. Therefore this function is most useful if you want to upload and release haptic effects dynamically, for example as a way to circumvent the limit imposed by [al_get_max_haptic_effects]. Returns true on success, false if the effect couldn't be released for any reason such as when NULL is passed, the effect is not active or failure to release the effect by the driver. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. ## API: al_rumble_haptic Uploads a simple rumble effect to the haptic device and starts playback immediately. The parameter `intensity` is a relative magnitude between 0.0 and 1.0 that determines the intensity of the rumble effect. The `duration` determines the duration of the effect in seconds. You must also pass in a pointer to a user allocated [ALLEGRO_HAPTIC_EFFECT_ID]. It it is stored a reference to be used to control playback of the effect. Returns true if the rumble effect was successfully uploaded and started, false if not. In case false is returned, the rumble effect will be automatically released as if [al_release_haptic_effect] had been called, so there is no need to call it again manually in this case. However, if true is returned, it is necessary to call [al_release_haptic_effect] when the effect isn't needed anymore, to prevent the amount of available effects on the haptic device from running out. Since: 5.1.8 > *[Unstable API]:* Perhaps could be simplified due to limited support for all the exposed features across all of the platforms. Awaiting feedback from users. allegro5-5.2.10.1/docs/src/refman/image.txt000066400000000000000000000030321473414355200202700ustar00rootroot00000000000000# Image I/O addon These functions are declared in the following header file. Link with allegro_image. ~~~~c #include ~~~~ Some of the format handlers define configuration options for specifying things like compression level or gamma handling. Refer to [al_get_system_config] for their documentation. ## API: al_init_image_addon Initializes the image addon. This registers bitmap format handlers for [al_load_bitmap], [al_load_bitmap_f], [al_save_bitmap], [al_save_bitmap_f]. The following types are built into the Allegro image addon and guaranteed to be available: BMP, DDS, PCX, TGA. Every platform also supports JPEG and PNG via external dependencies. Other formats may be available depending on the operating system and installed libraries, but are not guaranteed and should not be assumed to be universally available. The DDS format is only supported to load from, and only if the DDS file contains textures compressed in the DXT1, DXT3 and DXT5 formats. Note that when loading a DDS file, the created bitmap will always be a video bitmap and will have the pixel format matching the format in the file. ## API: al_is_image_addon_initialized Returns true if the image addon is initialized, otherwise returns false. Since: 5.2.6 ## API: al_shutdown_image_addon Shut down the image addon. This is done automatically at program exit, but can be called any time the user wishes as well. ## API: al_get_allegro_image_version Returns the (compiled) version of the addon, in the same format as [al_get_allegro_version]. allegro5-5.2.10.1/docs/src/refman/images/000077500000000000000000000000001473414355200177145ustar00rootroot00000000000000allegro5-5.2.10.1/docs/src/refman/images/LINE_CAP.png000066400000000000000000000517501473414355200216440ustar00rootroot00000000000000PNG  IHDRlZsBIT|d pHYs$$yNtEXtSoftwarewww.inkscape.org< IDATxw\UwBH bY T(Uz* (T\){o!JBzHdǹiwN>'9ss>swDDDDDDUvDDDDD2r!"""""PBDDDDDʅ$B I*"""""U.DDDDD$\H"TDr!"""""PBDDDDDʅ$B I*"""""U.DDDDD$\H"TDr!"""""PBDDDDDʅ$B I*"""""U.DDDDD$\H"TDr!"""""PBDDDDDʅ$B I*"""""U.DDDDD$\H"TDT]bZ@S}Y E.tEf`[`C`sEE{-pqk|+:f03ݽ} ``Q.𜻷xu`AtG"}?(b1@]lw_Rľrw} X;ǏpXP{b)}^t?v`~1_sK`K¹> |qw]ľϮ\\ݗp#3q&98kIl0"Cѱ9[Jv]w(04Ԍb>ڽ6,-? ؑ^N.f/dyu-hwX1}f)-ܽW}@ ױ}*pQE" زc~cR/DmsvAE@Z|~{>",T7aQآV8q-Du%΀=^'<|cEgNl\ec<6+ | Z5@_2};sym\Dc";ڕE.pb^><;[.vṣcRy|ci}UB,3Ak[dk |x΍ZDuF H2 i) C=~735;ߤmW‡GG-j57phf7Y{f-=B4x_e Fz}_o RZ`]`wft9%ϵ{;ev{3bXM|ٝf6*2z],5o:`t!I8Ѓq6b/1fv6?2n/b__df^\=7#~-` ߪn M6J.p'8n%9К1"!TE8'vn%T8!^=c `{`h}5 sAUi$5ǵ{.lM4 &nM,iBe61@H̜_/}?BsgBMfwKAz3EuN3ymCُ< $\F>WwLAdy*_ vFWliwЅEeby+(Eim{'0*7c; pw&< m#Y9X7!S lP1Ǣnpsmsvj,jʹϩŪ ۮ%u/ynk՝l۝6y]l,ja>z2w_k^9C|NsܢcQѹV=1.w?ǹ<"4 |]`˶ p9XW>OˢpSV3LvC\-{&37L_j0=> -pN69 f7w<1!gmK$kq]Qn|~D\aPZJ!%|ݧyǞ:̾RlyenBImGwIAt/r6U>3]R;(Gshriw~y,=?W..%if;y -+q ݈9mO)&W,ic2f68_)d_w8'igңoG677FbOp 06εmGhq8_MfPx)$]]q*pEF3H㮸Vp*Do`f`|Omehf B2{^,geu+hq,uxŹ{m[taf# ^B3.RY̬'pp6mo ;#c@QOvwa*;_׍_ @B:U>~~47ǟ2?iM8o%Nc8Zʼ.LMD4עo\۬ދxCʜM![(o}}$׶y+7zXhJ=oҶ/@^/%9}`4+aUPL-"st)K=삮]ÈcOҚmK=~5:X[U>3]&̼V 2j-M駟̵tJ3P17pSUsamqD¬;}2/ʿ=/7¬ LدAfCk<1FazSKrM-aΞBj%xL'w-)̿Kius|(!wLY[ef,ps.-M*rnfǑtyR P|r>[m%w̮&L&VYF9֋ msw_df?@3s'3`_~C={Wլs?m[Lbo3[>h?,_.brվf:bѱ< Rtf/8\d#Ii5 U.ҰCTȬsm{oxw.E8;$wFN&4مEƎ5Ƣ[&)ޔ@Cov(bۛkHQp}EP2 \^m =^sȹUN!̄Sjfwa*͸qj{#gEXGfv9Kwoj}u}ƨaQ> w$T75OѲ%x*[w2K'{g=ea3k Lh00xJ\560!<ݛl[(b{`o-fvCT>#>vt30_tb&_ or0+>G J[~E;6(f|ߢVy*E_ i% , "t>!K0Šwv0haK=k'ru\늁ݭ%V,|?Vf< h{Tw78&9 PڷH7B" fcƯ8ªl"u{\{yKOEU.:mEsϖr=((1w7/}Be;G3'dĵ39a/Ϲe3SyKdoo :lK \Bhɮ`fפ8h%ۑo'L5^ `fƹAe 6G*! =yt7$ %8e;+zƉCGԂTELEi΋4įy;fWکXT̉sh3jZ^S/R7v.!%ayI0S[ٙo|uuW~$az۳k>ƄP:Egg IADsa2 qSUZuSo{l :lkf6Փ/=5)R:l|JΎ0o2(+<>e[FZ:cߢEFΎV=.O?=u ͱ=lT|~hB #׹) f*h; {W%2KD6Nm3+砝o!_m\|ӣo-8~oǞ*ep)SU."'=nfR] y8 =<.+ޒSŪg[^Ǟ>=UTGViإ36kj Үoנ~p /3m$mz1Nyb?4e f60EvF҅q[ƞl$x3ۢ׌{\$;ϚVDo[^3"{#2s'UwtvnMF.@q0-o&ucOɬt~4ٞo& S ~`^G.= ^:굈g)ifs#ѷ}i{3osyZb\X2n,v^QvDZJDN=Y+|c61}K-"+6 Pz^6B:-סhbOb5`fצg7OG#8̶-,_$L9xWq9j뗱w$W+׹Bh;vW :\ϐ9&G(c'EEEHi9^c&m-Fˏ=\lEchu?.eE2kc)#s~^Kl[ X;(^g]ffQ)RV.27ՄEYmTm&ٕmQR3rxk@oq=%T1>"0/6s 7ә+ݽ.=~kfNaI6ݍl}6m+0M6f5{S:afm,ԔfEw6f ݽs-~~rFѿ4QKnΊ"f6Q,7UH⑦|ѬaǿǞ* ڶC"{ah{3pxgv'2œο׀ Xf"rf3XXclfV6Bwyv;:]!6fSF+?ifwzd,3ۋ1pm~nn%O>&'+$(nQY_ 3 oH:(t\MERgC_~0o6P7aG205,QO^ܪ{"N"ڏYɎ}pq[)Xr F ׁތb=ym߳"yu~]K cw_V{&ȣlDlY+~\_}*w~Dm-Nwu"qE6!0໘ upI2mSrK nWasS ݢϫxMvwM}:O30m7$o!S`YF-̙\?u.αf%ki7]s}*pZ~6~i%} bc|,Ehm~^~3r GpL>jwK<C>s}Ul,*&>@>B ֮\2J*a~fإ[0F/w]zovtE}Tsy}Ћ2aѷ=Fم:3 <퟉+ez/rm*f.rK0/pzUwCXxyz ws 9vH )uY6޽ w&ҍY$"4f\^9TӂClw߃0mμC[GXTs<Zp_T3oioI\4fa-BfvMBk]wyٵ!~Cvѽ[}=QG< "t?tY+h:-y!aW7ˆf(x5H7>W"|'- =aI Yv gZtX$EVXN623m'ʅ Y>2ݚ'+EH"s!"""""PBDDDDDʅ$B I*"""""U.DDDDD$\H"TDr!"""""PBDDDDDʅ$B I*"""""U.DDDDD$\H"TDr!"""""PBDDDDDʅ$B I*"""""U.DDDDD$\H"TDr!"""""PBDDDDDʅ$B I*"""""U.DmvDDDD*"̶3{lô#"""$U.D. x2LDDD$\t[ľ~ ff_OH""""1wO m`;`#`$0hF_/KS+Hl4:0tx 06hj*cNFxoL"5ux#>xxoJ"娷D= X fO-iQ$-=rQoSZv4OuuDefl9~86f9Skj!n-Hm[`JV.m_c UޗN{p_RESo)`E+ *+88-]U֯v?oNCڿH]ý_T,iyMPcoTk,_֨]Bn/Hmp8P?wC_Κ[[JTkڪKWׇٗ#j_e~G?o![ vো@BFuN2V.mDb\{ ѧyMj&̓y8=)̢m <.Rz; J7hl(-a6uU59f*8mH7KrQoksin3;}l-7Fӈ7/uAE WoշӶ'CTjh OLh]RnBVo,aL]XZa6'LC]KTsz ^DVoNkl2يƄιUl5 c꠮%pF7IGW.BEd优C@__~=U/$Vfb[5W&F9u#ᕓ+V")VMXǼ/p}a(tYpކɠuqfJ"Kc}V,*b aʑ˧ôhOe.#x.2! WXobM~`ny s*]Fy~kf/HoqM_:7V8sj`Ql3?ofV"]孌|~}E;-nȊ8l>cmZ0F T\y}8C>5915܄UCk8xU"Ӗ2yaS$aqsa/(*%TwV.!bZ2;b*aRR63~|d W[uDx&*uRQNVjvWc< BT(E$!T$"xgJiU.Y,/ ?h:5U]@SW+6cVj7As. SeE^ev{/^EbZQ;ހX~i!\gf)*%2)ʠ YK;'0heYR,]J̀}~FQqɗJV{\xJ]cf.HRr7 %tgR(*%E84/vkVѱs|^ˊJIf8}jrHD<&2^oz2.I;z#%>{")*%=QwV.,OA >hy:JIlg-mrȱC}<ܻRRհ4Os|͸K\@6*RRh5!ND<Иd? J^+f(i3.$;+/bqeuo/|<2QlӲ$)j4D`T ^6[(*%yhї;:f"/,DnTTJ L Efx̮VTJz\4R-(ĝԜӽ%`G(*58CJ f x}qxdaz[g :EQ)TS̝͍'eQP}2=2?~0ԑJIOJ+|zwטqFQ)!jXqCXLXso[xTۉYz-w{n3J #N|"&D葥1%kֱ=:Qtol]~a|fKG+~=Nr@?C[%WQm=HrVMJ 㵳ʮb1JIl֙,{9Z vRNv;:߾Dٿ]ˬ=Gö ţ 8~2EmWel ܧt2|zۜuT Oh޹oÒg*#fvʻHºl ;ԯrS W+g6%-b^;f:_Q)pVg Q&ﰵC\"Qo.k+y;:^\VO 8m\-f/'F_ GWgg<2Q_(*%m4B;=[a 9x\{|x~t\4\wP όS3pӧ5gt9ĸ;~컿Fj8gökQptjj߾յ ԑJ}[^Qzq&ye=gPhC-k3B EQ)i}78Xʡj ~0[翝H) 1xJQ).MtBKZ}hi k8j9b> I{8Z 7kr./\&ܨR\nDOKs[ Gɯ.f} ðJ}!=NʽO8?LsB p K}kLuf)uaRl _OtBb8p p';2U$&E#`o.es tx|~*udl ׵u[n.̈́ܽkF}HQo/ko-efO]*/,=ـ>(ZY yE+aAb8]zz l&^WåEoTÞc,4ӡ;uܽ9Hmpł&͟[ -ν۰{ fvPy~ E|9W{)Rҫ\dۖqXR&72`i <kYsZW 0$DXoБ֯.pR&-w7\ajMtO_8vR oK >\ΤwNwΊpZ4'MAewj9pe'@՛{;Fyok@V1v:8* {VuY9 zKrPoC:ccod0kNފbb&)x})HmpDw1Ãh&̀uRBml?kdEʹY˻_Vzh^kEQ)ɪM?ZA참!79<הR91ppR>4ͲV7YO.#aQ8c'WTJճ*qg's0Eyr|Toջ>~ 8si ,4B/ƿ.V|fN^̨+z\,X/&PTJic53hΊ^SEQ))[ϭ\D' 5% |8)*%DHKSTJ0AkO xv7l4 {"D]}z|"U{LT$w8Ʋz0u JXS88KQ)0K.K*LJJf"$@Q))I\dN7&i% ޘvA0/*.KU9ش˒1. j?~CXĮ{p?vAw]~Adכn0=S=$63W3#BԠ>p>'7xlfc.[9~ z(3?ȴ #=_빈R]4f&IM"b|1$@Q)YmBX|RR'(*%GJ]ҫ+f3[ J*KJF%O~ iDz3a\]%DGCQ)*6*u?vAuDnIDSTJ27rRVTJi72RR+*%JTZ*#*xvag(*u.ʹ˒EdQT">$88[Q)ɈR;](*%0 i%?(*%P 3ۅ㭄Q.fe*#*50RR:fy(HE%Dټ7xp+*XTG~BT(zTjpR"TO\rM&DifS.QTj}B%o HڜZniʖJkfPYDQL2`fPTJ2TNTj3BT:3[#HbQ먜Z}V=qQT\i%MdR$ TfV^iDQK.KUJQ)v 㛥]%*T[m+f+![ G_.fB+ĔEd?vAgR?!LQ QQ.t*w0TFT&E$I<EŢR3!3VQ)QFzOODQiF\ęٚ~i%J*l]BT i%ˀӁ)*%5pRQQ̬R!\tv#D6L, x9Haf{Rk]EJݞvA0QJhWTJڈRPQ' 縢R`Eu%*KzTjM/fvUBeI T+!*.3?3ʒ$ݯR**%QTB9~}IքJ~ȣR**%QTb`˒Edf!FCeIR 3ۑԱT(}pV J*(*%Φ2R/b$]bQS)' Ofz&Hq*CJRRJRR:B"zTjs¬Rט #ksIfvRz.JEM, PTJVafn*%*upRQQ_)*%QTR`Ӵ˒9YT(C $}~K#J]LH, x#H`fRR̬Rzp+*Ճ)U(*!*$kMf3[Q)ɈRIH8ZxT,wov 6ef6,Hs3OJ}=$07JIF=$`)¤dfb$ۧ], D.WTJ2l'BRRW)*ճr03,RfRTJV2 JJw]TfVJh#y4HPQ iDŢwRRF*$ pRgPQ;T%TLQTZ` oj]TRzTjK(*uz.VT*9衢\i%+JVQ)Ɉ*M, PTJVE.#vFZ. f :^ QQk**=\RRgD&lD&UBsiDz J=J**U"ŢzhMPTJ*P4q%ERTJ2ՄsRRٟh)$`;*z.z(*uմ˒EdѪI, XBJdٖJRR*0*K:E E/E.K,   KeD^'*z#QTJQ'QQG i7P,RZ*!*73*a\$o!,w6?*>!*WED' [JL0(*u.x.2!iSE/gfkfԹTo4IBJE.>vY00FJIJovY0^QrQ!lBTjݴ˒w J)*%+EQ5.K^'*uw!J}8ʉJO]bQ&JXTp;F\rM@Q)i'JmʈJn1JW"eRWQYQ쏊J J%$ PQsQ^i%+s 3ېž[eI7To4IBl+¬RJIEĨ_vAzU.*}_Dp]9l?8JJFUJQ)D*BDQ)j*U Q i$MEU0w0JW7RRĢRSQORPTJܽϡrR;ϮQ)\&l"!*tKR}`0/ >FnD.]?/.6"tvY5#jy,S˟?ФJ]lvY5ã u\iƴ(3 .K֨=/8 '犓&Vث*(*u109tʠ~2 5O[cjxmuzJԸҙUѰlP8۫b~>/wwР,J}0Tn8<4Yx*Oϫk/p/ ~OTz(*sk i87ma~44wwk!Sjj s4K8_6,23m@^~K٥2?jR.* MIDAT6'NjLuU<NJgfÀӀ#[ &ضYI޷G3i]Z@lMBC~i#; &>a |T_>ԟƽ94./dJTXT8ZP}T6s0cm'GvC _;kc:p-p= ޒo#=AOJU4XD[x#Zu0b0e\3&1=Wt_ݙ'JT]h=&S\/uoULMAMx{:෧HӢRሉj4B5ˆXw@`Tb9/=*IU*ԘZ8i=dPGVgT/&dZ^N2Kaf$ N-*vpǻ 7w慨pdz(UtLQs\-(*= RJm8~.И'̷V]deLNӸ:)Qk2@M 2NX6Ģ-M.w6H VFRUnX,i ߁ۋezH 3C43D6*Uݝݷ &Dy+yKᰉ!>9ckmx SpBTtsTjp5\ gLgdzY L#8+,O:ط_{dp>=/߂W~E%Xn04%O6՝ͱيŋX4?XAWs(` |ﯕX<6|mA/+&FϘʵf֭%}ؚu[lbbql8*ٽƽv>tywr}?NV,13T,|_GPo[%Yִr!m.5?|of0;O 4| s-mD +_v]6 g/SބybP+>ď]m4V)J!!*TA;u9{p\e\6iӴMSh&M[(ꔛB, S= :::L Hp88 xf(rY/eAFЂ)I4) M&?޳Ͷ䲛ML7{{?={}y1( .T@T39'5r8SE%>c\̶RMۑ{n4KҧsLmAԙTG;6H⑏;\m.7fr9J]R}<*r(F+Z.&U*5ƧBiANSyޱ<[J5ɤBBgfO|R^ J2ngf%~,V*u,R&h;wb~+ɑ̒fvn*9x4s63KJ=:qi~չ㫁 .DJ݈K=95dT7qȰT+}i[;aT۵]]I4fJ0Ro|;-8\sw%9R_aT9G<4 .$T/瑖*o^M_iʀlOVd0UJ`Į۝b62^a(U}tk7 f/V͂d/%؜b/e;EBefpRHKz B3gf138kTz>p .dBY>_Qgl<R )-/3=.n`bu0k^ =a!2T@ҀK^3\Y^~4%T 2TD^ : Ϋ X[Gc\L3MKz]ǽ0d|* ̈́SXTR=;UGVSSBKIk]dxA%Wh /n!,'̠(k]dxf֒*uoe ̋ЌP xH2b\Ȅ3F3lhu 侲f}4=.,?lW\J4 rTT*~ bi[TJc#fCHT{7uP?x[ f=3U Jzcw.pi D20ǁuf̮/z}*,Nr|`wwꇻ|E; T`býcE2{% ksAft$'Y] kj]pRQH'pʤ lĞ$e;pۻƾOMwn\V]: 1.7ɂUG%}IJvCi6RU7K{p] Kџٝ9Rp![C]4B| $f?PkZc.^JmqNnS7`=lc$4*AC6G`2YZb6f~"S-qj>oq cG3/ ç)Xa{+ qũKy߶1i/f:¹ujTpTB hnq6`nϊ>+ ׌ߋ4P;x/|/>hsUQW W_=L'a>^S˷BM$|5{+Sc< W%gnN)]?Cߛ\;$љEw=GUjU Au f'A[ \gyf3nXH~XCAfdr;&m渃E== f&)(hxޒtf+6_|{kYpT^GB*pp<#0\gGTJ>6|;4R=,intc`86 =ɎM ,'`Q#ׁMӚ ߛ[CTrdx +14]L .$L@%0W E:'w"*Z{ՃFdw:nAlcfv$Td||on}wo6OJ9r`1n|zq)1M(""y/qَHfυH1ׁr wSn> E""\9f*V ""OBk.DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$ .DDDDD$s#|αIENDB`allegro5-5.2.10.1/docs/src/refman/images/LINE_CAP.svg000066400000000000000000000300251473414355200216470ustar00rootroot00000000000000 image/svg+xml NONE SQUARE ROUND TRIANGLE allegro5-5.2.10.1/docs/src/refman/images/LINE_JOIN.png000066400000000000000000000370251473414355200217770ustar00rootroot00000000000000PNG  IHDRlZsBIT|d pHYs$$yNtEXtSoftwarewww.inkscape.org< IDATxw^{/ 6c BH#q @~ zo`H%@=tLL16.YծFis]ՎfY7ow?=Y XN87TxTtqtݛA8 e{~U{g~ye]c2p=+ݴ{paQA4`bݱ <{ǬN;vX!\t{~_lTqE/ts'^=ݹ畹}c96 xQ>glſ?^wfb}.ߪ<U.?-$\آ]yȏ<Ģgfީ}xp!4MۀQqGza&Ofvt;3;c*nY x.̶zmkOQ_#mX> x~X6ՎQoD9>O`#`_lpjfC8yt.vMk cR^'`x[&1DŽnfy- wW%>qEjpsWB Af} b$(3)T;2M-/Lr'puvmN΅$MsmW`.Ⴗ[f#gqEkOo"v}'~tz |p}_O-y |;ۓ;Rc mMǟX6τOcvN_q+u!#뮓 ⱨEџ+i=XβضپwNn4uF_z${j,j\7'mZKl}6^ =¿bQ `XTۍccyϽ{"D y{3ng,*C=;i,g:_ jcQE5bcO*XwIuE߫s,jlwc5ܞp}XT7fE͈4jwff(ڹ7/9ݗ!|jfqлo䭖oPc?0@{hw̬p@()à݁yK-{JIqB9 =\:̾50#YMGt]'=sB/ٍ5Z5[էc/U1 ח L^\E3pە;<=KxIr"أ6aFA]\g(viFaVc/+-F>}9MkV~&T̶$Lp?1ً ъǣۘg+I4~ v'B b2W=B[$l"a&;cvyѨK 湥dRyw=TowԽ ƍr.c/OU͌CJF *-&ŞL9x{oŅ/' +8 x'[uYA[^ڮKqI-O8o /N$wY72i!sImJHrCou.?wڨ7Xw@03(d#i|k*.I(.zsψ}oI3WlmB@wv2 \|uGccTxyƖo􊐃1ħu=$\*{Vgƙne>cImLv!6!0x'rf(f%8/zZ7#q3Ǝmd  Ӟw'Mhpdt\žUt+(N ;Vғ ?0Mߢx=֌OY $816$fҙ椓\~'a$Q%Y⮒ 2h䐻/ug2¸{om@^^|?C]xw%Ä 5prwb3;ہCl[/`9Q~un˜N_2P, k^ߵ;zPL*mB 3{:MWKrU\D&_4l9=_*5-oqrR4(^DiaS>r:uؽ&wrIq=nqG {׻GؤԆ=;/ Z"}EZ ^mfc8eߦ? } 3۞8YLݯz8.n~!|0s7,}͜I w:ޕ;(lQ7tS 4Gz) Kq&z{y3 `fcq훉H;?tjKmO#^k$XS1Cn٢] 3E 4쵶}-*3?W~=_ֶ薻?BIN5իmzz<}ľ*ې;+."Q3[7[Uv%tASm:XT"4ypwSACTx/7F_Ş^>B)ɯbbϓI^+aXlR*KtsJm+e ^B5R%WnJeq*̇>U|_<.KS*g 2iET)eE-!>P{M+rKG uifVjQQn*ݱl2Iy8ULpd*Gosvt,wjXg#7N/̠)$VBagwz9=^s)7Sv|҃?Y4 B!>ayf30tf T3({!skSwnoʠM~olVBhew0 3ݟ)01uLlfROl2ӓ?#=1~)w|WN[=ö4w.%D0Nݾj&=* VQ޳,ڮ )3hf%0DQj]<= V{^SY(sHww3)%.aAEff}@z~mP5FL^ZJ]*=W̆{ Q5rtE}R98/Y6F:sbO}zw̾IX} AXe &1Z]*+ ²1]3ބǐ::Ϸ?Z4:N< أ}/y3Υ/@VH&^swMI .3ؑ9x(am3vJkwe 7!g!rѝkf;>gVLt)t@MO ET N %M%:}l`owI/4ߙY3>UςG?ׅGvwoakޱ _fR~e\.۞͝_?]&w8/N';wV¿)Us.whz6s!u2߷e=ˀl׷1w}lhB"9ul)G]nZg>oAH= b?3m? K*lW]o@mƖَ >Pa8<E ,ޕ@s}0m=w?쀞7^d1ՄA}go٘k@!T(c.a<)t׀Oߣ1N+3+~O)uawͬzAu!<=FkRAO~$qJIq?L( Rlsu$5tWk.zi 5lXmISawR6ȉH* Nj¬RiV)iTQRbɯ ifv}&R\0;y/ Y+0;g{"aw{)K$5f]))KiwR~pLq")swRJI(swRUTJ ZGKWTJISt9;mQ Q#P FJ4cHЋ]4{(*%͢{.ĝ<`?wRx[ !ҥ*q'(!*uC !%3{pi{!qqG !Rf+ĝjfvmZctV $&WYMD:twכ٥ff%Rl%Z_Smff04{HDR=)Nb9aôZXBX?8-' $ ,ǖ^̾·OX7ViNBQ) N $2X먌pߙEVѰ N6ɰ_ĝ$ڪ $ QK9 QJIhȞ: N:fi~uĝ؏4iwoR+*%i0w87j **%Yj1;>O }3H.cwCGY7FrofgirѴ]K#CY7FzhwR7{(HhwRO}v .%,b cf?~u;ᄕpײn.X\d9;egRTJXLqVY7FC N-p E\f6 xlZ ¬RJI4Rw^# NJI2YN?Ũn4q'18E$h`$!*u}0H0= 8;S**%]jAIsn4ĝ%KY7DSt~k-ŁRgɯFhAImgfЬ# q'5x7Y7FR NjWBo>f֚ucDϢ9 >0NY<*# O@Rҵ f J}$HaC3 CJ} H4Lq7hҫl#lL8ok7:Y7F_ BmhfY7F+`=B1r{?p6.sgf'y( 88\JI b 5{$)13mqSUJ 3eݖ^JI(0< /κ!8l:!skc3H0] Ä;uC1D~C5 xݝuCy5L,+~a}hԍJIQu(*%q~ !FƄEJ 2*BT7JI".Jat!*uuc10*u<+E JaBMEd%3CTuBTJIMS\0*otgO3,Ed9JģR#2nNp{n4EuST\E6ʺ1 #OTQόHRRg^,*50ums]֞cfyW"5t=qQ$Gnƴ#IDATa`JIA4vtY%J*1h&?QÀ_+*%QTjafWJޛRjhw{Rh K49EEE"*+R?$*]8REu%p3'*uRR6$?Q**%qԩ4TjBTBEVF&?Q8E$ےq JIA: .붤@Q)YmI8zR䮸(0 9<4H0l¬RJJf Doκ!rpߛuC$[Euo$DRk(*%qwB|$$Tk2!*73q[A'*uRRJKG>efg+*ջ"$Du[R0E&Rɺ-)XDqVf/$%9JJJ-Ϻ1r8WQާWQT,f"JLʸ)iMU_Y7DG:  J)*%ʨԏOTjw/H6Օ(*5|E7<K(*!pJٕJIAZ0ި٣RRjY7FEff6P,IzUE\:ZmIRQn4F J5{$)1Mw!*&Y`eTjymIRD-. 죄_Ny"swc af_ 坔qSҠ̾IU*/Q="!Q;縢R9իbQ]qJ4]5K8wJIE+*u*QhԖYJS﹈3q.Y%J*l !*ےEJIA: pmIYRTJ l+9ԫyJ凊.Y%s Q˲n43ۉpwےQn4E$Ϣԏ Q7' wf_ XTWz¬RR?,Œݯ$GQ)fbIRJN>R7)*%QT,`*JEP,jARG**%QTL`ǬےEdJI0*K`RIESTJvN QQ[n43CqVF~mI\`wu[R.Yh(*%yè/ ʎ:R¬RWdiJIaTV9@ XT̮STJ bQOTϊJ JInuJOGUT*깨33@J}9붤`)rRR䝙M#Hɺ-)X 6s|ZmIu[R"gQR+n4E+*.RwfB9>붤 `hFp;n4(*'p$JLJ=uCbQ .:E$)~EX;MUTJ bQBO]RX:D>RUQER_̺-)PTJV~&JCJfY%J*l[9imI˄EY7hBf)غY%{Gk"J=NUJQ)VFMCT>BDQ)ryUT E5!wؘDdfטYƕH bQhzJ J$?Q-(FFg^THoGJTs䢨iY%'R^4IJԯeݖ(*%aT 7JIARY7Q 38|D#*df_%DeݖJIL:8cR#D~@.R!DN6!Y7&+%9*5l8FȾX6/$Z{  ndRZa0o8ρ%&}yv-4)`fJ s!rAgF^:0& 6X_w:ˀGi=׆/..;ا fݐLۏ-Bk}lmƒxj~f5~Y#GvڲnHwZc#`!_ & 1mˬ@w^!*''ۦto`y5pȺ8<6/{CS`fÀnGNo5/l76ydX+ok#3 p`0%& ~h+'dΠ><M?Y,Zᱬ!`8x2Uf?&- K?_̶nϺR?[ &~t_^^g ϶p+psI72#*.a ߟ}+ "x})8!>2?l=7 Zx8vo|ޣaq'dܽn_s^m0?l;6 m-,_ks97xDEѿ~4zpc8|:a²yz\WeI@E1M2m>&[o, ? ”AnA{xP`ܔߣT\HCX.lt|8aNΰVg_]#hj洨xi[˺62|a5^]>>1Z-Da iu64dk n$.,{7wEC(O(χo=N" r|4zm3)5Sb?T,,}``.w2lciW$' +_i`>`ccos[u }^!Յ}>pPtmT+RMW_]G< o*w_J  V!mBmćGsޅgâ*F=.cstJcE*#oO{U;p\0cن8[*.$3ۧ?.ᕐ=9pӭDկ\f9N]׬| !< F.w8pwZO υyKXs3 e{In~פ(Hc>{߄+clof'Ye6&2|zLqpʆvL OXE5[z5̖Sk:}7OTw |g|XD=^8fC Xؚ.RL k@4=(}x.Oj0e }YfKzG/G?W8<]\uӀ Wt*l9Yg>SծfA'fgRgl}f<7rKqJxth9L돌ZtG35"*.$!cQ8^n3jCGИ6ul:f{й"S-?}["A)9oz#8Tg .E l{-z:q\oFsZnȢWdbA}U6^FWt$ l_uX..G#̐&R%[ H"m2+<&gM3֦Rq!(킰*qB/GK&>HF[i)p}7ߟ{s\fT>zgs;ѴݑD: f\ffEc5,׼?{_=ׅ͘ۺ s]xI݌.a~ *16qBWI|x^ǁx3TVUNŅdb+#ԈN*E:Jn%uܹqV>gef k*}l*~'[,>I؞Du"AlBg $4xKM V xozWٵf^ DkBmY3~ؚI$9>ݼBq-R&ƞyNqbkx]b9z̎k S9QCm#5=HooU$׹{O=[E.*[1FFmYF, "uP&oNc;ڀ J})UJŅde|5RnF_͢ߨQD4o ̎jDq􄺏DMsCpf oDwY }j0bA0?eVڽK t7aqt0]ݒt?5f65=&B2sctgk? jrnCZaϵ݁k{?"Upbh\m\oYVNjrtKn֠X0|at{Ǯz$kfSsT\Hf90*09x&C+k.ӟNaMlfWٺ5=*.$cOG  [PX ^v@n //cֲuq1GPvvT`пm+,4hw%e'Gm> ~8Z0&qr')a3;Q) 熁6]8ˆTB]@1*,T)Rsx#9ew[WyuH87^y,ŦT9U?5Λ&ip^6Zvir9β7o6t- m)\9~3 8xvYefÁtK cy_ V]Pf/^UX@(,n;f>Xښ2q͋~;Vtϭj$Dmpr3P^> æ:{> `aZ=>u?pm5vHmm5KWsᢹH:xej?U\HkaƑ”Ý KoZ0tk[z* l+wrG'[2#*.z~-Ջ, 90نv` !0p)fg~: >[7~2p/W m mG>,:G/7EJDE1/|xd7ރýoWރ-auIT͛ -~ x& nKcݫ\Ņ4{1m-FW# n1*.ziCq%V||(CWOٵl_T\>[_Jof,!,K8v[AEa!卡[pxkYg~e5;i⢕QFo7aM٨6&Ylr}y36ʁYu,hYAUqCɕi1o8i#2!}'pW7mފ83 lu;66`dh+kĿ7PZ<\Yz+l4qn$C[ d)rg%w_Xa '|hF ׀WGit05!ڽDO^9p~ image/svg+xml NONE BEVEL ROUND MITER 4 allegro5-5.2.10.1/docs/src/refman/images/audio.png000066400000000000000000001770511473414355200215360ustar00rootroot00000000000000PNG  IHDRXYIsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxwx{=ҁBBЋ"9B=|4A:P @6uꚄvI6ﺸpgޙyv6{f`)]=Y DDDDD18~"""""ODDDDd C?c'""""2p DDDDD18~"""""OOD\\,X'bXx1ܹX=/^Ă PRRX w^[[b~ק\џ-Zcǎ=p˗/c(((xUѣbn˖-ˑ;ǩSiÆ Xt)9ߕ^Cƍ˭+((̙3@e@zz:fϞfӦM/ann+#""GU5 V3fظq#LLLIII֭&Oȧ^ӧѶmۧ~ʬ]FFF;vlu(**R3g@DU>~z222.]?W_ŢE+++&&&رcԩ!C[|-޽СڴiS8v Ѽyst]NDו&!!hԨu:|0LMMooo]{FcǎK.8~8]#Facc@4h稨|>3rϜ9sss4k @DD4i vyyyعs' T*6III AZZ<==sLMll,KKK1gΜAڵ8|0|}} ;VXX^y`())СCw'NԩS*wsrrp)<쳸~:v [[[9z篿 .}qw^iӦѣGsCDDTcj_~g[WWWyG+ҦM)**ҵYdJ.]dȐ!baa!n}iibll,ݻw>}WED$**Jȯ*""Ν:uȘ1c@JJJ_ׯG,,,d˖-۷OwlKKKT4i899رccǎbjj*[n^dVpq2rHiժJoFȑ#$2bquu޽{KIIʕ+LZj%=8;;ܺuKi׮lRڴi#{}HzzT*;vH>}XFGll3gxxxH^^ˠAR &ݻw333Ynn?[l[[[Y|xyyIPPH~tmRRRK.(CVZDEE>|Xo߾2|pHii=?"""CO]dd4h@H``߿\7niٲӧH֬Y#"eA[Rիu8p@j\zUDD֬Y#r1] Νk׊deeɉ'^z-]OZN>ǧ~*k]|Gbii)#F

'OڵkoW^v,,,pixyygN8u}@nn.Y/qI"%%VVV077'>>|84 ԩWhh(rrrb ]VԞEEE}36666vvvX~=O???3~!4iR9 yJٳgjj4DEEa~ fIIIaXv-BBBpm$%%Gnn.BCC_#++ trϜ9={=@aa!DFFFzmtmΟ?777ԪU [nVń uBٳ1cޘp4kL`ĉz .Ĉ#0dh+=DDD5C?=6k֬qq2L8&&&0aN<ݻ̙3Bkbb"ѤI\~W_U83Ϡk׮ѸqcԫW#F@jj*LLLP\\pcϞ=x|r9@ـ^JHLLĭ[ aÆo߾Xd `Ϟ=xޅ]_~%ZjnݺUzO> ;;;lR,<<ź ~ L>™PZZ>}sEƍe˖wE@@_/~pvvPG&,, ФIܹs?^3g[N9{,T*pUdggw3sL~bŊrT8|0:s1urJ@voYd)--;;;ڵ^w}Wlmm%==]׽f۶mzm^{5yDDdѢEbll,999o ={={Vo޼YȥKDDd@t(..E+Z\]Kݺu%>>^@~r?--MԩSHDZV y饗 >\DpFu֒!7oޔ޽{Z xzzʙ3gHEV޽{El_EGG]t\rELLLdܹR\\,2a 1c4iD}㏢R$55UD.HppӧqҩS'E~KElL>瞈Ȑ1c.J%ɬYtp͚5bdd$*Z7(iٲn?>>>[_ZZ*Gbkk+^^^"VVV'ĉM6z3gٷoӥK7""=zɓ'{֭u늹XYYIZ+.))Illl… J [/AAARAj 2D7CQMy )((@BBj5<==alYf|2XYYU &dee[7a"&&k׆o'"HLLF+-- IIIhڴ#V;w ;;>+;;n݂gUZZ8Ro]޽acc["777oބCFII bccagg3(q ԫWO]$8;;ᑏEDDd(Сj*KJ[o7T"""=mQGT\\.T5EGG#33~z )]U";;hڴ޼DDDT=18v!""""2p DDDDD18~"""""ODDDDd C?c'""""2p DDDDD1UAGݻ. JDD"Oh֬:t9DDDdxٲe q5dff*]~*f…Crr2֮]t9DDDd۷o#99 "Xb!`'BVX ;w &&F0U!WFIIuJJ ,Y`EDDDd/";;[o`֭$[DDD`'"Znynn.;@EDDDd(۷;V*"""2 DU@HH*])h4X~* 88X .J7deeaǎFDDDC?²pI 00899Gall.>DDDv% 88x Əޞ#Q SA~"""""ODDDDd C?QJoooK!"""ODDDDd C?|l5 rw2s}EpuDDDdffbԩشiQ}W9.϶hpeDO_aq 6<6@fn>7ހJR<""O:gΜȑ#k s6'&ȾTea{9,DǪUPvmK#""z ؼy3ƏB4ƠeU)£0gfdA aw"" K.̙3j1!#ޝПt*}NNNصkڴitYDDD_-^3g΄J1A:YK"4ŘGBV.R 5ƍ1f3yV针Rh~9~...8z(.B 5ԉ'Э[7q}1e =RL^EDaaaU,""r8-K QF/OLX6g{"::/%U4i_JCTYbkc`maM6aŊJDDDT0۶mСCage] g%"0acch8;;+] 3gc0=F:@֍_~Yr0 .D||ør1֭ ~6j#~DOZرJDDD5` gs+\ Qq-,, WCDD5CEBBl,_ErjNM}.\7j:~w!@^)jk 3$&&͛HOOW$"". .ZU_û)b- }:ܴ}0mPJsJ]^zZvإ޲ o #7vV.wvVtvP_{gp%> Zx-)ʡ":1Z{~` ~؋!T%BW zlTf~9h[u6V:JF.0VMz;=Yh&L.b-jņ}=f ~k)ħiwtj]n}\R*v>{ynپ3%QZE#OW[[Pxq?^Yuǿ~؋εB]ǰ=pDS/wbsh|k5 :E:2pr\kܼyiiiJCDD5C.•KsS4J9|243ĸbvF6}^!7`j??3C^ I?."V|JDD$OKII8)\`Kuj͇΢Dckc?4uKw_C="co}f`霱z!XWGĀ-ŏ!<f&إ""~$YYϚhZ ~0V1{x z%ܸy?pTłkˆx}d/]g[|0iJJ]3:;lj*~j# G]<R6.-.*Z.c3-Q/? 'Wo2)9Hӿ 1޽+MMa1=FEXJZc}o= uFew3s3zprAV!']05Q c_e(-y()-E ]Z?kwc׉H{N]VD}q||Wmw2sPߥ׷19 KKK@IRfb~fddKKKhEtw-myo=4rG3/wo-|bpGO{m{svį?sa LǬ662 };aʠgզ~$\;lknu'A(a'}SYYynđ{wi_F*N]p}v^:Mz?(; DD~HJRs 2rָ }ϜQ_F(RJ„N8mU&9fgyuxO4t{;fӳ=6:n6G3oy lsQ IqMӫ=>+Gh銀*6Ͽ}+~0{DOq~C#0&j_7@߿?:4n'G|+BFW01ѦL8 | r5v{_!.wbhSl;uNbBPG4c]î:] *c{E1%""e@{E;)]=%e CJaZq/W4Nf>>"W\_϶ԽgmFj5T*,3?;!'6.:+&{kߦ^x_'|Q<[Mm{ Ӯ Jˆ|>T9651ƺ&aɶP|(n;ctSVs-lp>]o.ۊR`c7f+]&,}̪*EГrJL4 Ab霱Jcp2s󑒑[Ks Qדacc-LM+1ѓWt>>>}/@׮]u3ԪO(&""zkJiӦ8p5D-5+CàRзo_r"":u*jժ8u9Nr bt=R7kkkk̞=🵻uL"tsAh#F{xxc+""'3g<==V"((*F`` |||FFF_•QM_XZZ/,ܰw2p|<~={xuׯ333+#""bq!C ;OY_m@Ii%U{qIx'ήIV4""" 5w}OOOVRj-OSW#OSg}zҭa证aaX$z%:\IH;^y:xyy)Xџk:`͚5022!D/ڄcχZJRJ""2 5؈#7@Dow`CJDT-agkXYZbzjڴ)lmmHJDD"HY˖-̙3QZZ;􇩉eUIR3?BL"0|@l=͚5SB"" uV7hůF=ZJETz*t32rpuuխwqqA֭٭~9{,8XY=BNP j\,a/>AvꫯF02 U= ';;SLƍ~\ tkpeDO_AQ168o6DV?~< w7-Z~""Bvq @n6zm c=Y9(Rrmڴ)ST*4jԈSsQO*((G}e˖!==`oc:5GаDZ BqIӪ6lQFm۶z-,,%%""z( t_X`6oތXrsS>hZuPv27PRPTDDDHTAT^^^|0=ODDDDd C?c'""""2p DDDDD18~"""""ODDDDd C?c'""""2p DDDDD18~"""""ODDDDd C?c'""""2p DDDDDDD.9rµkא,䠤DXXX pss6l֭[SNPD""'JDD֭[{ҥK 333t ѣtIDDD C?WAAV\˗#22REۖ?pm;[3XؘǨj#/ki}K(-j5zYf!((H᪉w T)Fŋ#88ڎ5)F l05Q+\%㑙]m}0EeZnya WHDDBv¬Y h oA}` O.=SןCHN-=<~ғSbӦM]_=ѧ•=}%n90?oJtyDDDtΜ9#G"..6f1vO5^jz>VAj*Ԯ][҈C?6oތǣm[cahPA鲈ۑ  $$}Z-\ҥK1j(O*Я/OCC.]tYDDD;5ŋ1sLT*|nO}%Uyb FBV.R 5ƍ1fV,c.(..۱pqqѣGtYDDDb诡N8nݺ;D&Ǿ1EXXlmm.鯁1j(a DDߍD&.K/tIDDDb证&MׯcX^/!֬LipژaӦMXb%=5̶m0tP8YintIDǟ.b-Att4.Hwk|̙3;=Qb@/?_V"""= 5… vJCdp0&ؾ};BCC.H7||^o4ٓCD0o,iѥ… qQMo:ɓt=E y&ӕ.j0c '… Eߣ!;[|M]m0_bq4sE *m(|C7޲tl}q72QXXFu0#4PƬ[LQϴϺؙعRrPŠ>~01QWZgE Jշ'7ܸ#aok/&axLKOČTo,^yA8|"'%VZS=w; g[ofj G{ <Ӿ^YM 7z4HNNcODD40W}k+\{_qh"na:{╉ ,-L`Q-us?ڏ; W;4s`cxӃX^/̞AƬ)(FL|JZ|a_LG[ݺ"Lv_g]{4wFlB9`#+Laa) -Cի\1C '0aX X[ƾ1g}~6lِC1do_q`oC?_vwj -w̜oUЫ~=7o"--Mrc7pGuGbƴN^qIslĎ7e\k, {bXsxilk]R^^t@6}}ngj0tF>efmGȡj014 =GЗQޟ56$Jǟ.۷w{~=|1?`ÎH,[}[j#Ĝ@ꅍˇ-`KcԠSUy]l'&&";;EEE055VDDD•C>cęx{ftiW/Zls'fC7~3^l¢D^Iy~PΆ ;;[ኈb7`Z02RDr`զڿ,-L0_#|9Vi%jK*\oanӯbnP_.5#`K]{?'4s_E ݽew-Rxg7q6`c]vW_)d9DDT{˃VYħc7^+ ǮػC1.(%>~;S =*| fҰbY|D^Ϳ\Kc[w43-bޫ.}ȁMp|^PTl>}'B=>{c'1vVXlȔ j:wg6 Z5uս;?ix5G*7:6($""RC?U9+ GCZغ_|vkžX.@lBFbgTw]¢kw[ɺ9y()".z|Mqq֦,D>t1 - řЮ;N;iyxW6EEz*:MOX`yUɼDD~fee###Ajq?+[w]9zZ[)FȡQ0w RRPR=kG{CYz D7fr6 us7AָG$΅ ueJ[6qЮ;6|?TׯO=1/oE)0߇o@_77vOٌKQw̵ܠ&',[Z .))Ws""'} ,--=V%?tbRv@nT~n盡N-+7ߵa/-A S((,A; Ò!5G`x}jG,_s?z+t~ocۯn.y0{kذ!bccq-6 >U]tM, O #z'$fbs<Ӿ>\ʺDVa^]uZaM\`fj K!h:&G6ua6Bd,ZyRV}zbX)6G`p}9C'oDa.hܰ2v,Yu=Qx{:M 7k;c5|8:[ћ8^ N=KAD*=0YocDKx6GnR*I}dlrH?޽{{*>.1f1I% ӅaʂQع }Qޭ= Ю;O{/allgᆪ6&TH P" J>BUD: "HWzɨ IDAT%J|pͥC>kue;Yg>{7kXesҩMߏ'u'hغ x&Nס X['OQkuŋ^uS{"4kXמm9{3 a/2V.|l }Gg_l|^k3j2}79DGO^݅W_DDfX )+NN5F)R22I$9%RΙxJ;nĒ72394̙'+Vf_Ԋ% ;q-[` >-_%T:/ykH([,WpqUDDDrJH@@gΜa"IA^zg-psd#)5T;,(Q¨8""R̩;vdڴi,JѪYEs/tF`L&nnnFFbLs?f͚Wƕ;VeP$/9Mquueܹf 5:Sj>HʕIdF)\ -ZXW22s*ŀdbԨQL|iDjnL&:t>c`*)T#GŦmgYiY+4i҄ndl]GDD*ń cǎ7Wmp"'L} D߾QlYS+ƍB ;#R}}WR3x衇\666LDD;bٙ?W]s N$Rt,\eŅaÆYd"""*Nٳ'R?;22$R ee{hO{E߰P4dƿs݋bQF<쳸Z~ߋ<*CBB#Fov2L~ bp2w%5w2_ޞӭ[e˖nݺK_n_~aќ;w}yDVl\ _.3W 4`Ĉ9L&W9EDS闛JMM孷bڴi\t V>k`8؛ N);.] ,\'Uѿ6lx'''ׯOɒ%+""rWTHQaooOjhܸ1-Z=&2ePj7*rbbb߿gr9"##IJJ"))T23޿,899DRߟJ*QZ5[[[|}}TʾZ*rϮ\牎&>>^Rdf<==GxDDS\Ill, $%%Lzz:dffb3tP9gflmmqrr<<<""RFٳپ};k6:pF"22nݺѲeK*Udt$BAYa>-ZFU :~˗c6 00]Sn]lmjHb͚5уDضmj2:&L`ҤI[GGG\]]iѢ;vy׭#""RK;rZ"::WWWOj֬ip2) , 7fǎyGGGJ(L.]1Hbct)^bcci׮888hz1IJeq/_bЧO7oODDD &|J֭񸍍=x{{3{l @lluϛL&*VoF`` EDD -^zq{^#rڶmˠApvv SL*/{96oLZZuϩ˽ZjCv} F)0T%͞=y-̏?˳|rʕ+ǖ-[[./&1J䩵k2rHl6~ʕ>ݻӾ}{8#d4lؐݻwVDD*RSS/Xl?3G^-zs888XWqsscƌ[ʕ+w^7nK/c@KT2d!!!XWyWhѢnnnF͜9͛w^ƏOVV'OAܹӠ"""OsIt~~~deeqY|}}=z4_}'((R%$$|id6mb;v ̸q8q"TDD$i_… IKKSҫW/\]] N'EM ?@HH{aX,1HHF}v/^L~#c=ѣG5/""EJÇSF ݉H"\r'Eʕ5kf`B{$_̙3~KĤIشiիWĉjՊ#Glt<\~sTPsαyf6mjt$뤦2i$y222 d֬Ylh"""M_ܪUh׮+WرcZS {2l0vލd'?h"""L{$͝;G}T_ uuV&M3gΤN:FGg}0uTJ*ep2i_ĵx/EZJXv-3fŅ0jժot4+KKMMח˗/s!Wnt$|q)ڵkSLt'N#~._LFTXX"k֬aƌZG}%""b~uZ_3Ĉ#طomڴ… 2.]it<)4GrULL e˖ƆfF), _|/" xxx0ydFat4)f4/j޼ydffҹsg~)>|]reFIN0:#*͛hm~oӓ˗SV-fΜit4)&4Grͮ]ˋH퍎$RDGG3zh~ڷo̙3)WDD(Hk74H_&|||Xt)~-^^^\:1+\IٲeaΝԯ_H"##Y~=رc=zxHHH ++"98;;SD \]])_8"ER> YYYh$*rW?x`lmm N#w?W\[j*mt"kS!ڰb njt+~c|<#;_~ KOFh\>kɔ)S0:/w᧟~".. PV-Z|9/^V5o7:HYpӈ\/wLkN ,`h N"R66&t ֭[9wDDT͟?L:uDR#whΝSR)j :"#""4""*r͛hmfݺulZ"Mhf;JLL FGblt)޽{CFǑo>/|7nz?vwTy:5:$_3E 4 .{cnepq#>wjO41'G;Jy:뎿fͦpV=x*A&tjYTfqp,<+ʣ}yY6m; bkkÜowk]ΥzӘ>oe \{ojRto_ OBjZ~*O\Q4Att4EDJֵxin9rj ߔqW`4]fڤ=?u<ֿKz/w_isҟKo wpJֲ|%5^YWwP:ːwV3mRg L9?wcI:dOZ_mITFPiPKf#0yu) /c_W[iTZl<ń܈o=q)RM'6m;U#X0&uоUekPcS ?H:w~ J^;牍J*FGbL_n)33ŋS?~@/ܝcؾ<DŽ0uv&7׼טf7,V`~Lŀ0\~bĿ~eZk78O$:>^YNp7m߲`4}ї^jXs0-m]=w|]u1++eqw5ZVM]j0N9p1Ώ.Wӳcu\͵őfՊ1GniʕDGGSF 4h`t $$$`oƫqWwS'ӌL,gt$f֢]:6=j[ ?'G3;ysxƥpQVaS[@M]?_l;`HNu&--V9&چARع/&ձ<ߛVsw<1>R9~*6Wϝ}B@VVIII'L_nIk^ ݍ -=#Oxz8ѾUeat,-=lyO'b37y= >WwQ UkҴA9]gm_WPp^coo{SzWϾGZƒ s-:ϝ{(Sޕ+WTEP#7? 4:ܥkn_rRun~s7l~f k.]q:z3:+xq0H$wZ|b2Gta^~::бYtOWھLl]kccw9gddafe;U͛-ϼ^%X6[ǎoxqnv_}fCմ}JO.W*"b,~ŋFv([7B䶯I; W ݑg?R KwMHJԧ\ɠCSsS3G~T7zp6\+s>:!1m`7L]. 4e\R-3D$xO76mPr~-;KOR#7p ϾGl\X#wG~~n Xz#s6t^ mKLZ򝝯̼EH~М~ǏuV޽q\+Iv/6&uIp?tMZz&6,[˦+{[eҫmU (p1s%5C*k_.޸geeۆhpOM&} \I_X.vS7;*U(gow`l<7R +t+ڿ='''nuHR믱X,:J%#nnngbt۲X,^UakmsO@p?fIvŐ|բLiƼ:Oi7-TߝO݁{#: &{xݱmbg"17!#nx>7Gy鶯;NlycnhAs=ޟ/"F2Y,c>+kȐ!̝; &oG{H03bt"%=#Q gQ=wMLJ\d<.U"W-y/!1 /^AAAVD$iArHNNfɒ%L&ltO-[` QR|<;5J%omrljԨO\/"b~#))P*UR0αXΞn(, f)nyLr%Y1ʚMԩSJI_rE-?0aaa|^|ё$t}*u|oy̍v}u_ z W-􋈑4_"""PvvvDEEat$?ݺufUo}8"E7___f̘dTR4ih"Ri~3gYYYCСK lat"hժuYRJIDD_6|@S{;;;o=\DS|!f3m۶>^LSmٲ#G =Q`t"kgʦu}www\]] N&"ŝJW 4[· ܚ7?8q5:H@sbkkK^+W7A_HOO',Z0aJb|8"EJv1//'++]{uu%;;;ʖ-kp:~~Gbcc vFǑ<ɻ dƟ;ŀWXY˧TEk#=-[$2&O/%;[+ܯ{#׿d21zhbŊJp+f~G򘍍 ,txёD b7*L:wLƍU^;;;ӉM[`tIK~~~̝;[[[&~YvIPJNI ?Gʕ6l9OOO+"J1wmjϐ!C N"}|X,Fk-;dt$BJjm믿nշ08HN*؁سgt8Fĉʦ1oёD +7_םÃ7|%KZU&J16{l i:o6F_+!++X"ֱXB}gwߵ. PJ L("rc&Ţ;Lʕ+Gtt4۶maÆFG͚5QFI+pj/hQZt?/#1) *oe}lٲ#"J1/йsg8zqذa'22 O'} h"J +lْ1ch=lٲԭ[I^D`b \mB͛g^:tWiu8mt4C$&Χs[v'''yƍWXQ_D <Cӧ\gŌ; .Ьay?Ռ`6k@DfgrBBBxsL籵f͚/_ި""wL1cFm۶Z8R@%&&2af͚EBB>. ^^Ӹ^Y]Hqb2֟d}!zC{Z0`uq )Tf͚0| dt).\;Ò%K8wq6 /U+j%/Jy: %9%t8u6c>~[p_\uhggGÆ ֭5jq[[[*UDʕq)>>ȸx"ǎc֭Ѝ Ύ(<<<$"0fMfLJST)^gΜ_~9r7LpKHH͚5#88ƍcgg_EDrFs璕EnTE l~466ٳg `˖-L<__3ի7ndҤItOOO g%44OOOBBBx饗矉3݈=իWȑ#,_:GDna͚5ۗK.xZj>|ؠTEKtt4dϞ=ޣG,Yb=&++#GsN6o̦M8|p1[[[VJpp5k*E֭[iҤ eʔ!"";NHѡCV\yެ_jժhZh/"TVhonعs'9A֋ j%)T1c0uT^x}-$''DdduϙL&F͔)S HVt]tCrJ.\pWS 322طo6mbͬ[+1vvvԩSf͚BVtoBKOOߟ/w^m8#R͚5~+Weri#֭[Gpp0up7ofdgg8&00zЬY3jԨq˕DDrJӻwoիǮ]#"Q~}v (Y$aaanȘrضmӀ͛7_wQFFr\899XD*"k׮?aرF[ ((֭Kݺug}.] B7*R<$%%gϞ' uֵ^j%"^zGDJ\smπ.zС\3;k'"ԪU OOO"##FH!/Ŏ;;v ---196kԨ%i"믿*""E/]tK.k.Rk׮%**e˖l2J(<`hڴ)^^^F G/b(WQQQlٲƍIDF~]3ڧkCYb;v$((#G臷H!/->>۷rπ2eаaC봠 J,"I{9s0tP~rwwM6ig޽{7_g=BBBhѢF G/B!--ӧOS\9#=HA{]*E_|#hݺ5W6:~)ٺuӀM6qǸҸqcR͛7ݠ"r3S\3dHQcJi&N:իMg@hh(+V4m/2N:EJpvv&::#}H֥B7mIOOq 1FB>}TED$g3 99ݻw[/ЬY3<==|"EFBʕ UVFG~)Jng)A4@{."`lْõH/EYLL ۶m1-(5551>>>4hzаaC2/r4vUED+S ]tN `߾}O֭[Gttt)AvvvԩSǺTh˖-)]oCPH!w|}}ȑ#TZH" 4/ݵ)A> ў֥BCBB_܄F %KOӦMUED $00G}m۬μypssQFO5koCP/MCQDD(rss˱g@ff&GqFN>cLPPE6D = ΎHJ,it$%#r"##;wd۶mddd8zBzt? /͛GVVzRbϏ>}ЧOسgB`DEEFXX...ԭ[7Dž~JQBv8pe˖ѩS'H.HHȑ#9 =tPcp" 885kX$R۷oQFx{{ёD$honرciii9ͱq H{ k7>#*"""'Ǟ)))ڵiڵkʱg3ճ^>Egggqss\rTR 6lH&Mptt4:9͛O8ABB)))O֟QjU7nLpp0fq^>Y|9SY"ΎFѥKHr匎t, 7ofoӦMcǎT{AlRxq#.lErUzj&i$]Nы'vDy"Ɔ-[Oӭ[B˗:u*f"<<MW' <+VWi]\qpqVVɸBzJ2 8C\<~6}h/jfڵkرci۶s_DD| s… ]}`K|jųb*ቝ3NZFD2RIM'L8'Cٲ'ZsrrgϞ<ԯ_?_W`ƌ={IhZTkZ{G6 EÕ4=͆EQү\VV-^}UW`Kٿd_AVF: 4^[n'O歷b޼y_}UkR#Tm׍UPpI+|l`8h׮:M6׿ҿn:ƌc]*7ƇЬw })R}^ʔ)S]W_}/ŋԼ-͞=I҈ܷXv--_ <|grllm٥/x 'R$GcWctҒ1L <{/Ϧ uONNgaX,b64Zř,˼~'.: /̄ 5x̙3 4͛7چ6L¯ND̴Tv.u˗7/bsNȱc0L1/L3D+q9#ixxx0m4uWۗClGW󅦘5-@T_l';+-ZpB ɳtRN\\n>{#jvkH&EV2bо}{̙nb駟2~xVNoO!Is qgYpl/<|'899kq_r%{&99Zތ媗ε "E g`ĞOח+VPn|'saXpW<'| "q5KL҅hXr%ժU3:u=z4_|u{9^;򓤧$ӰaC-[kwT,XaG88kC(+|5ḻ?ҢE<lƎ-4~|lV R%D9OXlM41:UJJ }_~ =>K=%R]8rEu#L8UT_bŊ}ۖ 裏MBx*"Ca_ ;v,~)f{z|:WyD 4<~WWW~w40tuʕ+qd) oW;W D依-[M6p_e_bݺu###aﵥDKrN<<3!'Odذalٲe1`*",\?ׯ_sݰ?3>|Z<9;3ZwZ?WΛF~HII^Ǩ\9;G'zO'|QQQ :Bђ"/.lfҤIYs]_v-gَ*="ϕd21aN|JcmkKI'6nHXX=^#55 J="T7? V~ײX,*H1L&'O&&&0tRvgܜw [oEff]ĉ|Y IDATwh⛹QD_9I&gl2݋oY<>6^GDVͨ־;W\;e- ,ٳQW):jcwYYYyPD˃OO^CDG3b2:mqqqwu?m4zy~"yՁNO5/$))鎿6!!o FWE$8{ހX,,Yٳgs5ϖ-[p@D_`%%9Yf>|۷Sݑ=YH1٘?ٽ{]XX)))Tx%%0zؿn::DVVVΜ9>;'\=まCt)گ&NZS$.wtU{^Bキ"Ŋ( ) HZ$)&Xn a͛73w|9RQQ={(..nq7orx*TxXyʫ\tI555lٲP *Kx !QQQ\zA9@g7:*TPpzۗPM #TP4 P̷?224 mmپITB?6}#!<< -TP-z7ƍP]]]gsQQQo UPh޹ᔕ$V_ u ŋ)))ٳTWWoYO q5΀|Ȩsh޹ *#;Krr24IrJnPyd>22A2Ct :(OWSʱװ4tHbJ;RNm]gl]Z[Ӳ̶2.΍tJ 1֣ W<;;ȍ1!655!FZ4ĭO˹Qe%˜}7y ƒ7ۢk%?^uDCTF} DKa`]Q`X JoQS]Cȑx))ZӢgtJ('梩s+kx @rL&هUscV|kΆfeYRg#DmR㫮S]g'{:WVK0h#юܹsceemtt4V>~t8NŹ{?oL8RiV-l#.W^ܣp\R孤?dɤ]Ъbc]\Geok ѡIj#,}WZI ,yynw3V:QY.K/c/LØ|=hKLCްJE(_i6d%i,{ _Pw}z׌#ge⊑6.&raE+{;{˭h(#'Go1NYrPc+=sPn"tn[Z+?䃞Jii)*l AxL9brVhh*Z̠~ݹ_' 3_}WѭWrr\0R HܘV駬0ogd2iÐi3 ȶiYЇ"зT,LqXchPQ\)CTIX]UEut|c&\L™ ׯ%EYhD؁>eYGfYei >|?Xz4ahȌ n$F9٪,-o5x4#N2fT7}iީ'_Hwr/[ QnڀV>ٰ\$'O'`:4// @Čcd'Y嫮"h-y:N3:KtIVJOJJ#;GbЭi;-o}[V9cG'=_+xk>3?dҘû1=sΧקJkYkuUg?}M l:ΛIۗߢߜ2/eS62ϐ_۹S~A9Km5-s{ߡ8"sLոL֭XmXAzVD!gFpSowe*pe2̙AtA ]g0o֨cCs\zugp]\Q^Ȝ}>uz3jF1."CJw>?3{LczPDu{fL&Y&o ĩKoh}.n۪=:SgcNjUV现֏Vu=>$;7:އ\8vϛۂV Q(OUo?j"!cfI^[!iTth2sHb K]uqbu(~=$dy&@ G".ɵa$crS^]hHsOϡ>2Ef3+&Qw j>-= 펶&W]Wخe't KEL̥tY%QLl$|rԵ̳}cF44>s.:Ʀ2Vt.6_XD6ğ<\o_Z]ĕ܏$V6gھщ kSUQ%0sdPUY]^Jeyx +gaE>ݺ>srU-Csx7ꮌ}qOe3n. TSXxx.|c`_c*m*"//mcF=Rî5x n}(}v7GS'7ZN4 a/7jjtywRqE9{ߡ Y{>lشhˑ7*RzT8~m ?H\}0s7/dY >@J&!Dۊs~(6=@ ka`e˝|] !c9 omS2t" Mz~5&͜taTFض59魏,-!bf8;c>;Ow$B SIvqEy(r^!.Zz] Wbh[;[zKܹT|Z"3ΐw+<\?f~N|av hHڒEbF=+9Dµ n? έqikCa/]1{+t%h;3G56&hꨳ3[ːw۳4-DSp;\LZ8>YVׄi':tűרgiq~ }QzTZZ 4_{WUxݺNysxUtT&RrQUk#bB(jk 8wRGB 7/m\AbIH9zXQ/q3RLaKR-m"=t\PQ\Iy2dEr3sDe?b x'o4:SUd5d,g +m4R}x*%}2BZhIoɃRXX冾 :;r"i!5,"vf\f -8)dGaNoXZXNlNomɺNT~eb)z3wWה)R5y6V(֟Iq4SKA@sG}|q?GI BFl$ T뻲fчv5\8Ł5 7g17ѕ v|ZGɽ{k!f7%i71kx־س\-g}@tMq^q1@$796CoZ)^א1n;)uڿfK]ꢲHyM}Fc,Pt{K m>}ctx= յul#ߝ_a`eKS>O6tjp @ϰB*[?zrp[{ޮ3Eq'Pp_^X*uʃRb1"> PnTUVpcFZ kfAȆضlD筏t_s1%3NbTiVi?FUeܨ,+%-"niMID6~_֭8܋ e'8{8vK0vUJ=sK^q,'D؁]+I eZxiƑbkWze (}z/'Vh|4" h KƐ ~ aӧy޸k e#^Jsi9n -^acI ,׏Ƈ́O Mĸsub4r4tZ$R_F~uM&>Wf`iJ*+xyB\)HB4[ ;!vXK*X7K[QZIE{/sF֙!GKWA;ɬQSWyfKQXBMM '׆y\&`S:㾐h 4u5פJVm}MJ g12֛V}r c89+B3ݿyWȽ_$ K*,ֆ?fmg Ґ =:kgJg'{l8'p8Gx 6JUF\)ebJZOq?:+/I\7M IDATߴs#ܷC=-g~VfHNo}0A}E@}70G" i7m|+i}n]CΘ4sPtM Y\/TSckXޯ}V˵,-mܨ,+UnTW׿R]VVw$JY2gckSY(ciu>'梮%bN" 5ΘY] Q  ]KK+w# Z̺:+ޗƠkEϗ[+O]8ʩqˋ^vC]T}MޓXh2 gc*&i'wH+nbbk[F)%LbXaފKw%DۊHK AF\ WCq?@^}KJs,+{.&$?E6ŭi oQ}vL f4>d,,ʸ'mD[!Ԑ٥h>RKYըih퇓d ӈ;c6_2drrn"3>Kp,=>d,殍"բoi'}\cQaOY3;g~Va:BX|GLwbR_/;U}ZcѰjwP^THܽp@@Ȇ ~V}h'G̐[5QclJQf\9[@ފZdQ&Cu5j"u̙!VAei aI4%6>w~L66R9NчvLT5u,ZJ\^F/dqs J35}GK6>@Z| ;U^sNaN]zK ]Y q\^+kaܕSg(ex= +&ݏ:[^&ÿy^ݲ"qfT7:@wK=sKJsڍk܏ǣp{1`z斄W5h4E>wp_fq{XŽP,=H8B3}nȾKWɶGlD8BԐ| ݶS'7-zPx@ `T~ǎHtV_gu 7"E~}j%r^$T2˵@LpmF6%v;e(ijoL@ r1:uH} s֎);D2>s.^HĕڀCط{ǎݰkՁ=n]mM$\:R욻zIQصR1CEr.Yf_Je֌N~]f }ZIsC۾5:>}?}FLqLs7dVA"7 3orcFu$; E@nTV*YXXp]S =W yoPMeYjQb.$7Jm*M1ɏ+mcNir{+,nLGSGkvcwg8C.ݨ qn}28+a3$)@L8}eUWUQxOq ֍/e̟+^pjyI ߹kYSߐ߹A.xei eRЭ20b؏ܘjjo-QYмSO"9f|h{q Y%#{sLVpPS#?$]>nlŒ{΁ +Oh*29[ûi\ [DۊO$WRvP cc5<^讖@ `袿KC[~Kg~灦-ǽͫ1Aa~{ Z,ۂCWI?&͝];׹i%~'gzXgt{ ݽ)#bf.!cfQD3)ɈKvM.PV_C\^F-x 0nUB6H{8i{a _]T)M].^ڀ%ǭw&jPakX3JVqV–WƇ8u@($=& .ƤK öZG^{{--^%N⃎(n;bxě).rj\M?#.J=6wTT `cP% PYZ"kpOR;r"ǿ˥JXLE XyKʕI^ywbRï>m&!61#n"{sdf.Yclo}ɀ`zdWV HY'ɪd@ zf CR6}Jei 'Lց;MbI?pY ݺc Wљ˕*?|-3~>MuLhީL%P.=ԛ)Ժ<oD S9| 3,mcSr&r}* (w.&mii55̙Ari7k1svre뚚K>}CcbMqQL!L1d=&7"wwI.ٔ؇D2+|a;wDI۔p@8+9_a) 0C2HS$J~HM_ʎ:^i4"o]7EO5,< _dGFZz%W.Nũ5ފV}^kŁ.skLߛvdh6=7C抵2g xuN_" 5(vi?Cs],SAWȵ %Nb٫-QW;d%(a" s1}KB6,*aW|jȀ0$qH8s3L6d֩ i,dѰj['8x./|Ī-TSîuGVBr7Ooر;z8uk N)u0oF9?]o_; Z<Y]yei mس\Z~Ya&\hֱaY<o9hTهCQf߶LJ_I ۀvk8Lǩ,իk0eIN|)\$|"n}0 ra"l:\{RjkOĞMط77EGOy0uv߹DAxI/I}k:]in3uK~D"%-,=~ .!')AnRG}p'ExʲRMdUEQ|CJazȾ\d嵽}!׷͕WiLov߹+k3bv:gaŴC Z%ǿH3oߨI|~3Hu zc![>i&Όs+FPƭG,rI 2rcۢIUā=#>fwƢte`eYCĠc`mu}tO+&m: [Wmdkoņ?Q/qOY\9 2[O|-C#N/'/`ۚI~1J Vp:(?ZZa]2CgϞ#G׳9o&~Y%Ybn#""n>BS;&UVBνB K10yfi=8B,uTb WTaX;DVJ;Ҫba5g;:R/ b1(*Na 22Fꩫ]WWUQx?| l_ R,+֡-MEMu5E)+ѩ\+*+XeBei 7n@^ 'cƌa׮]y4CϋJQf:%ٙ蘚7妡T+)H0˸$eܧ8'm# gf`wl3ѷiX9I CCC6n܈P(d Qn ^L  B,RW'0֗f,zik8kѓ)E(=NlR 044^&/t;N?=;"QWԍ)ah}SP50vToA oi.r2%8::J~@]k.\8+j"&,NWEXa`mO^tMMsDb&PĄ-ZJ̅dZ |_4o;~8UlƆ϶}N#zq ?)'F(K.hjjr/ey$-`#iDN<¢ LڤصKEs hkk+MPz4& YJsk`,bbuGeR/-/uAqA٭*k5HX{܂VUTY [[[RSSVUQ7 t?c̥A yONeY)AR |o_.>"u5\423;<%$(V[[NK?ĉ9y$;֫'@D-SU<;EsCCCU@ĉYx1;֫'@(aƿ ]}zCyaXYIYu&y̬IrVil*Tf-KH ԫGHױOݹ?VOJ 9 LuU}}}ƏOMu5XƨBCqv&[W#ׯtz~JrieBΞ@[[[u=uJIpppnT>ѪP̡?R[^^,3ꘛ7ٳDn[#W\ /bڷoOfۭͤ:̞=/D\^dPsv~STWWWO?`ݬ@*b*T_^<jkk,Ό; N3 *=i\Y NS1dڴiCaƽTPqJ0qɈ@2d7|???Rof ʎQBѦMZT4o޼Qc4e *^,|EtWWWv}}& }%K 8޽PR-swaرR@KKK45/(D"~W۾?ݨg3j*v$ӛ"АЀdI=ȬYwTy*T`DI}2uT}...ݻwg„ TpwT{*T`[ñeԨ5*3 wԩS(dW4hU?%;&I&ai)*) e,|O>LJ~)BgHnR"?+SȤmod̈:?=Pis g~@o- ڵȨa::/]ooo3̓*k OAE;)*M6R<'''.%lZUV*^*KKX ҥ ٤cee -;O?sPi(LOc" @ZW ~*:::l۶ ===NoYM3j*ϨfɤĜ3gΔ~е_'˗/췉;qǬBgCo^ulllxd[XXH|?|64vn*T46OBFl46ӟ.nnnOm޼ytqqٙ{v"JZqzK*T,ݜ͓{xx4(VCٳ'\&j6L`dPɩ,-ac9[eڴnZƷY#>|8!!!Dg3`hƠB eg~]̌KeP(Chkk7:~___\]]9x gpV.;#xz E3nVBţW_}t ^^^M>yׯyyy\p#{Pm'$]{)l~y0/P%Ʀm 2P IDAT9r$DG rVLܰp`*T<3GaB?2ce2<}}} AQǏgaeάcqh U/sm{_T455C .$,]?je3opPBӑp{fLQf:|r+|VVViWUU1m4֬Y@1/3drԵu9R MM5ܘ;w5ͭn=4XaرDEEϻ0Ψk*TW(+c×AYBuU5~~~|G2vLMMi׮"ѳ_+Bnn.#>#&*T<2?k]v|rwk… ;w.y1h޹?=,*/ȾѹtA1uT444m5kϓ6J())aƌ^l\M#<U /U cS!1n\2r+++Zn\?L8`I~3TkP&MbĈrB&4sK/ q̜ᑩPߤ$7+pqO+wޡK.27o.*$4ZL6[n`eΘϺeO5(*>?^ +9O@8@+UVg @νg8u_pP"RŵM+$۵kǴiӰk? 999|lڴ2B!^魏m  R7B6@@>}2e;@ G.IxbKx-. eDÙ-\GE,йsg&Z\fϞ͆ (..<6ۑ JrH8{=I8}*q%?m#{w XL`` K.ɓTVJѓ7swE#iğ+***Ν;rYB .>>>tLv4_KVV ܹsHHII!%%B)--E,7Ux*444BGGccc찵 ///455 XYY;ʺ *C8r{]m#ӆYwfel9̍3(VDxC:y>bbb8}4.]2?8222$33SR&988?ϏZjQv999QF Uv 2339}4gϞh4ry:Ĺs̟W^%++tk GGGJ*O*Uf͚|xk%...xyy퍧'elKFF $$$իW$&&2qDQZZ #OOOMvWL!\r?3<<⭷*ۇlذXtڵK_prrbժU4mڴߥի2%Tzz:G5pB+Eoۛ JttyAGů ˖-bŊ+W?\lr"7-no>+&)ƢE,@ZhA~~>O=uaܹVL)rٵkM4K.I~̃==<<8q"AAAVN*%O?ի毯\‡~hD""ӼysN (W (INNfȐ!ٓ,+cr}qQ*Ud?h *VHrh۶-rR)T@gΜ)͛-qѠAh֬P0ڵkYh ͂#B2ƌCdd$uN:~kRi^cԩF*T믿W^VJ&"bԭ[HVj/..;;;*Wlt"w<9B T6laÆVH&ZK~Px̘1 DDVbE:TNNwsORm߾PΞ=kfggWdp1/avMZZu8q ㈈i+WU'/^̎;2d]v̙3w ȝưahӦ g78bN&efƌ?1MHHoJ6'`x{{ĉIZx1}ʕweʔ)֎$e 999xyyBPPݺu7ٙ_K''Nv\%>>q1i$ݭG1L <[;1*KCo2sLHJJwwwǼ⋬XGGG+'=2224h66I-%ի "88QDToȑ|'jՊ?:uX;uꫯ2w\Zlɶm۰v,)\"""wN:Ν;iڴ)7ov$"?u2w\yᇭIPKZO9p...֎$R_\tIw䮢_DDJd888`gggTRf:55?~K$ 23 >P~W+%*>>'|6mڐcꪂ_:+99-[EXX&L 77ڱ X`s| O&**ڑDnHEX>|1cƐǢEPU֬YÕ+WhӦ 4kڑDnH}K)6oތ;M4v)YbO=qD~)ƌC߾} v)0aӦMqDuRiٲe|믓mHR˜L&ϟOxwIoS/""R׮]y1LL8[;0fbРA$''ӳgOFiH"H{n w}GzGJLڴiu(%LyEDndli28p5b*a֟vDJ*uREܹsiҤ C !==Jna2;w. 6dԨQTKi_DDʜDlmmdd#\t3dHOOh4Z;m_DDʜcDz~6mʅ pwwv$\2K,a…Z;m>""RfT˸GRbEEب)SpILmϼyزe Q*EDD+55UBժU;w.]vv, >O?͞={ػwH>"""ʎ;h֬gϞݧ6l{! իW2G-%)FSRF k8r:t3g2yduے2IE _DDDDnrv ""rM||< رc?~$RRRHKK#//E,8::쌫+~~~Ԯ]`BBBhժ֎({XYTT~-k׮СCϒCccHR;.++gqAiذuSZUgRusȺEZz:.^&9raN?E~~>t҅#Gr[9E*ED䎹z*3gd\x7wW:unGwOʕSS)2طW̮֯¸qٳJY_DDUV1rHSO K6a٩З-55+ֱp$&̸׵kW>jժetRb̐!CXhA6iZX9ȝ?4xw=z4S/""&""G}ӧO3Gzoy)ɩ̞5U?d2_mhRJbxb @vv6u΄i?ڵ3 L%%95jn:ub_DDnYf1byOO\G||=~J*j*BCCKJ[޽>1DDnh̙ >İOҨa*EnR%o>9Oǎ_KJ 9~8;wv"}:iii{xL&5jĮ]dΝԨQ-[о}{9B:u8x > ueǎaÆ"'`͚5tޝdoΜ9sxꩧ~aGVGl۶~ѣGsyz3gh޼9{O>a̙Ͼ}0L4o///xIKKёp^{59BBB#..O>{{{Zh%Khذa̱̝;7x\<䓤Ş={X|9'O6wKrwwG֖~gv̙3݂޽;[Dr5 O%+')=:un˽ --{qS ߼dgg[ۿ?M4 ?ڵ ///xyW4iիWϏU:ի 3[\X\N^^5@XիWB^,1ԭ[V^MPPaaa "eД)S^x㈔:/<{-[͛GJ0Z|6m"""/-/ToذP6 L4'Oһwoyz 98sgΜN:7;66OOBv]Ԯ]x ޺uy ]Tm6u)>llt/r^L&ƍG~~#I ݻעuڶ gV+Wp4h`/}vsמwy-[3̛7)Sa\bpxWWW,uڕG)zz<6o3̜90UF@@Ν8uطop)X"eМ9sHLLQ4j\qDJGMرkZ;P*oADDDn,c2, 唔Ν;իWYl#F(?d";;???݉ܝsά^Gb4yټy3/"K,aȐ!gϞ ^uHMMeoV~a4ygؿ?s9`Ν;K/Ddd$ӧOwA""edb xQ+)<HzPfbѢEw}̟?uQ|y`jЅ ₧'QQQlڴ|@/_NTT:ubÆ OesGLxs:yq[t-+jC5ޞ*`J*lmm .TCA?NrJ6n3<ۢE ] (p! tS/"ǚ5kة;Lo>bbbFJҥKbŊՋW^yG-̸qT 6SҶ苔%ќ9s77Wjհv2#YTܹsVN#%MJ~8z(III4iҤq1|p9Bff&o˖-4iPtAĹs爋#11Q妩3wwB oyM=h"~ѓtڞJ-L&v ֣a{||fU-]IM ycn]qswvio X[Q(9wݍ! -OHRRRiH#hO< w INmpqq.O'a! ,urO4nRxWGzPޱ֛-x*T*tnO/~+lܰg3 =>%'`ۺ7h޼&UV IKK#''{{{+@yEDPҭ ~^OPfLeyys'%9qWbFF&...ׯ˸_5/78 &N2  1cuqrr$3Ϳ0uۖ,kv;ظVgFy,tL& W6kTeUEMCΖMۯYYle7͜3E?߽KB||*["dees>u>H""r !++|]"zL,ߗGnnkgú56|- Y}y<`W o j1䍉ę8},uԲ<')7̐OLҵ=F3g֗3~ Z YWظa+ oXΜZ5˖xڶѷ_/v؋g9+%=trvOeV{*7hTvvOQ]D>""r NNNL&lpi>j 2б blM6$lgۜ6i?zLsycB/$nK~NNh/^ޘh֖M7ϝi623ҩs[suUtԆ?BlJn@6-i߱5;EX(ի֭Ehf)Ao#*Lx9#h4fڶoeQH4AjuKg>19geezŢZ C?oo?ԫ;yyFf}ߒF=pәm 6oڗ_z fC,DXP֬Pnب>^^]ݻ"عM+ˮ\.#f$RҨ{ܒ`j*֎î$&$ хf}ߏR^*1ϲO 5ѓEӦ;_.Ŀ5o`+ӠyR[nplA'u28ȍ'EDDnIڵYv-gbbZ˪EHh"߽#7k/[e.7o"_x\453 /0kݦ%s?琛[=ޞMxg؛*ml :v$O?<LOf}`_3_+8w{7'&3y|"((0k /\rZ-Jfxzzӏ :ank+y m0 *U*XcE|0ۖv6AE*d2Y;gРAk& _gǷm_M5==+p/77d[XD1tҗL+<==^:׷v4)ty(""]vyச(Wv~g\\oʕ+ּr9AFF&UTӳ`6?O+r=*EDRZ5Μ9ɓxa({,~)?.]ycj`qw(܊}~aÆm*f[ֽ{wfϞ*KN]ѤiS }l @HHlWޅK[sN^qert;h>9 *_cgg+mڴv4)!)-""e˖qJwvRLRm۶5mHR¨[f0:t(~iDJ$V@n}||JJ"" 2///D_Z;HÂedgFժU#r3T /̏|+')}]dɢ0 ׼= $R/""ۨQ^:GL+"߇3>#;;: ժUr2)iTČ33K.\dD"Gܾh^Z5LJ"""Ջ_&gH"%^8L~777YSkcȭS/""ؼy^:㓏qDJ̫df^M6tټVZ/֩à +֎$R"w9y"y *htR",,.XY_B{EnI^^¾_`8::w7n`rJ)Tmӷo_>cL&S&DnR,^{m6mgggƏoVEd2Y;.gfĈFzF4rY;]x{9|777Əo fiРJi_DDҥK߿?YYYԮSwcUvn{N'%%___~m|}{RreBCCխG1""RlO>}8}4NN>>#w~DDHPPAAA呐@jj*dddCnn.yyy ֬YCnn.'??_fakk#...RKHåKcժUtڑD%Hw^cVN$"w~2࣏>"%%HKKb"T􋈈rlٲb[RR .N T􋈈r+W$==b[VVfͲR"T􋈈rӦM#55/kD"r).r˗={N$"֠_DD/HHH(rhdw8X~Rl޼y\DDDX%9*EDDJcǎq|}}ѣ/gɌ3TD~R***ߜ8q+VЭ[7*UĔ)S8vK.%77IEL&!DDDDD_DDDDS/""""Rʩ)T􋈈 :wl("r)T􋈈r*EDDDDJ9/""""Rʩ_DDDDS/""""Rʩ)T􋈈_R/""""Rʩ)T􋈈r_DDDDSKH)_DDDDS/""""Rʩ)#4OH٥_DDDDS/""""Rʩ)4OHpBʗ/O^EDZEDDʸѣGi"RT􋈈a.\ ..f͚Y;#;k)YjԮ]n:=]v˼?66ǏӱcGtvMhh(HBB:t\|kҸqcF?]|9{ca4ѣuVϟX~=}oooҥ I&:tzФI~7N8APPyyyԮ]{ &0gFI exzzm6*Uģ>JFF+W4?υ gĈ)L"""Rl `ѣÇ iŦ\SƍM!!!˗/L&)77ԱcGӽk~L֭M?yǎkR5kM˖-3o 3?.66TBs=g7L&ԩSMwEft 0L&i&i޽&doM...+W:d5}s\|dggg3gd2Əo xgyT^=Snnͼ"7OH1bǎ|wSn]"##ر#K,~cܹx{{`gg?޽{h4Y}DDy[BB`0зo_vX"?S2p@IJJd21yd >|CDž 0P^=N>Mvv6/`ڴi٩ױHqQ/""Rz-߿?ᆪqxxxf4h@ӦM-G^^:t ?//sdbc8y$ 6`ʕggg1)))k0ŋDEEi&III^SN1j(`_~I-Z*NNNkD:u[.F'OꫯҵkW>ȍ)FZݻwC8q"P0@7((cG)_< ""sAŊiҤo>&66\x_sA Cx'!!3fлwoqww'##3fRrerssԩ=+W/#88;;;N8Axx87ndڴih"""Ť[nԭ[ӧӢE lBϞ=Yp!cǎŅ˗/[<ŋ 6 (f͚8::y1{%44m .\]]ͅ&O?`ܮaŊlݺ"""رc_}DEE/кukF# .QF;q;{B#"r_DDx{{`<LyYt<;v`ɒ%DGGӫW/;v,P'==dΞ=ˠA(ؿBBBSmۖsiRRR:t({?m4z-j*5kf>ݝ//666ر(O0h ~wj֬iqz1w\ ="""dԩl܇___> z)Uر\:\<< image/svg+xml ALLEGRO_AUDIO_STREAM ALLEGRO_MIXER ALLEGRO_MIXER ALLEGRO_VOICE ALLEGRO_SAMPLE_INSTANCE ALLEGRO_SAMPLE Speakers / headphones sound.wav music.ogg ALLEGRO_SAMPLE_INSTANCE allegro5-5.2.10.1/docs/src/refman/images/primitives1.png000066400000000000000000000372721473414355200227110ustar00rootroot00000000000000PNG  IHDR|sRGB pHYsss"tIME .0> IDATxg|Te_f&^' EPJ(RHtފU"PBҤI/HB 'e~0)fr>Nr9|sfLEO' ' @~ ?@~ ?O ?O' ' @~ ?@~ ?O ?O' ' @~ @~ ?Dc߬d{챱i׮]Ν0QQQG֭[ڵU3glڴ)&&ںnݺ pqqQN9􀀀:,۷o߱cGNN3<ӫW/FClٲe˖juEGGkڠ_~_9?wݻ_բE>}TP~~~xxUHHHpp3D VXWI&F rss*|||k׮]NCݻrto5mTRu-77W!ſpBv&N_rU``Oʩk45k6h@VH&M+^I4Ξ=;22;vؙ3g>y ΣG^bŜ9s Ν;|(V^~Ğ={YfժU Xoֹs>tM6͘1C!ŷ0`vZ)SRRR.^cF3tЌ bccRSSǍwӧ3TNլYqƦ%EEE:tPk֬Q:v("W\Qf<("C;{%-Z\rqq!::ZO;vlٲEOKKիOҥKqqqݺu3-h4;w޹sN[1a9rDDڵkGO۷oСiIncbbGGGe?**}hxJkDrʥ$%%(C96m3xxx(7nٷoߺuFg0f׮]3 (((XtӦMU+Wjڃ[k׮ sO "RR ORRR2`/RQzj~ m۶:u.o_fUPǟ>}zե/ R~zUٳ+_xpBV+ >L:n;vo4h׮];== :p]QaoKi&O`wywJ+{zzիW/^X~+VʃViiifu K.;wAV|JVz#G~YYY~-?ѣG ,WZecc3ogvqq4iRrr.Y$777))ID>lS G0###njcn…<| PF۷]Vӽ;f{g_~t K@@޽{s1CZ]bb߿ %رc\޴iS|royZjUC󹹹-_\QſHێ;P)Sq5g%?%%iӦGjԨWZ04lcccyPxSnxnnnpp0q(/_jUV߬RQ'rrrzGզR5??~YfnnnO=ѣGԩS/SN.]Rl'OrJ֭ʹgvZN\]]===׭[(lR56jԨ]v)K,>}bҥݻӧOm۶`Ŋ?SQQQvN}6lPKӧOEz[#G<_~}HHHCCC? ̙aÆ}{ƍZv֬Y욁G從Я_0?6s |齌%\tiҥҥիNJOdյk &t:9|pxxx``믿^SIIɲeڶmhXRr尰+VoGoժՌ3^{yyۑغuk#""|ġ /6 }ݷo_ll,<;vx}s>;}ŋvڼy+WSb5kVzaf6o|5SƍSRR&MTPP0o;qDNWVH[[r-dСC"2cƌ gΜ)"iIAAm)*WԩS 裏Dm۶w999"2t o-QFݗZ58883&33UVHPNO[l{^x4۩S'O6k֬z=k֬С2A77ڵk+/_k߾}*...**J988T^}ԨQ}`80c /N#Dd۶ms8ƏbŊF)vQvm%<Μ9SO)WsΞ={׫}zdd[l+6lذf͚=WB`4tܦMfonFDԩ};p˗/ǏNLLlҤa{^reſ[^^^;v4%<@~zN>dzjݺuMOJJU˗/裏ի7z?">>*880۰a[+]JLL\|yxxxڵ=jZ|7OEGGרQ4[TTdggg3=8ʕ+*JD֭[׫W޽{wnQTTVM޿'Ϛ5˰>G? ._KP{FFi6 Ӧٓ'Oz{{Z;*!|Ȱ$==t'~٦MSrrMFQzzիW M:uLoU{2)QEGG׫Wʊ R˗/:::СC?GDD?>$$}"rܹ={nݺrʑ!!!qqq_}Cxxc?W^yjutt_tRêqY[[Ϙ1CD&LЭ[7WW_/,}]TTs@~z{?5JDUuO?ܹs5j1cƅ 6mk.___fGG,=\k###}}}[lYQ_^zꕱŋGQQooo_v*vO'  d>\]]\[h2XY^{p ƟO' Ox.f\= 33u)ڄj@~꽲DfGNT`V8~@~x8~Nc>!!dԨQ 69rüZ9'X7;|ÿO'  @~ ?p/?t_UTT7xzz_~~W2DXŶ47PWпx[ TO'(?>m49q℈=LJ0sׯ_;v\pADNh"5 #V(">>>>>>YYYYYY*`]IIaeoo߶m[1z* ?=^-ZP}PX4___v_Jc@~ ?Ow~V[t >I]'RV=7Aڎ OBuId%)IMWVgyq0}@Ks̩^z=L>+@~ypKGu:ۮtU ?O'O' @~eIHHTBvgJ'FKbWM-Jc,8{r˿j|[.Ph/{9'IIIYdIBBU>00044wݽ{wqq1|p8Kշo_y饗?>uTgg{k׮]v~<>?rJZ-"٫W~WCBB@~;{WZhT*N3,:uj6m<<</Z3>}ZJRT})Heee/C 0 JٳA):|pNNN(KJ&N8i$+++^_z!KĉSNupph޼yn ROO'7uȔ"">] D,769VD2], 8qr)WܹsΝ&LhԨQݻtOk4%KN:u111w۠iӦ/?\9vU.>.~5ɸvNՉ'N81^xᣏ>b8 8-[j#MS$=^ڌ*!e޵A6JnUâ+յ"{߾qݺuڵ+OOg~į]@s^1om/mFumfDm:emcv]aʢGw Ħ\]] zm@~Pe'VVV-[''#P[.] CM>>>-<4ibxK-Lw^5jԂ D4E ?ȑ#?>iҤ.]4)1G@IDATk֌&'(KFFƔ)S<<< ''*U<) wƟp\1IzLWO' @~ @~ ?O ?O'O' @~ dhrss7mtѤUvܹUV4WTTm۶}j_,??iҤD}Dd˦-ʬs8h6'(*Kt#TrZ}VnBBB6?m޼/8p`6mJ/Vipng酊RൎɎ+"Z"+]!oh/""nnnܪHffRJdG.::_o޼[VEDjݗɻKj)wjJ꯾zݗJחBΝ֭}v''2lҤɱc-Z4devA77?ȋ~Iynf2dHHHȸqsȩ-""JEdŊ ,عs'ŌSxWߞ={VZƖC]h`0V)F{q6mŋ,X?3ڵkg{]v^ZvxVXXTx嚟?޹s瀀m۶yxxP,ŵkڷos:uP!0N7,m$?ѷx\*HDD)֊QmYe""Wӭm%ԩӿe(19?IlҖVDzj%ww *!Pf:xm-t|Z&KI6=?UwCN(j S҈'KC_u䟇‹PF~ I fE':]0N'}O>QC("?.(t*5ww7xʼ.W>@~ ]{t06aNF  ?IwRxXӔޮo[DD_, $g{?ovuq-.O8Mrv=Ь""r%{+27XDD&miU8w nwϧ-FQnK֖mzk/M%g?QDDlĥ6mD%ݸt'nrs Tǧ$HZqjE$""kavצsu`O"nO٭k8f͚2^w[{Yn)e_DF]J#@~0p#+;0Qy._W+qz-\'"RpN .ok[hѢE2^oOVaTv*vO9{8EDDĭ}*J4EegcWOlD#"V|<,? ?}q"︤-UzoӞ ?݉KGqh ݮW}A?tӍ-(Snyr@~ PqgNb|nſe#tr1My~Ϝ9su//GS$gJq$~&*E3VK7jSɁG !!!***!!ťAAAA @~*k޼;F>|ܹsTQ>{E$)0hHeVWAbbbkrrrZEfD_֮]lٲ__Zj߿CCCEdѢEqošzz̙I]vmB}1x3gjm۶ll߾~7n\͚5~2669aVW۶m׬YO:u-3g|||*v={믿޻w LX?.`xpwT$ҍV5cѾ}}Μ9\(;F:tزeV}嫾Ldm8WtME/"vEI;ŝ>}O*##?tww}vZD."//H榊r\{)v3&ק?AoٲED䧇6qĘ✜_5""";;_.O)5~6>ɤ$[b{H n-ݢԭ2ӏ?XRYYYTHǹ~'^}NߒXZ^%͔o8IOovԩ"bmmmSN/f㓒k׮ .hڪU6k֬FYTb(qo2X I5bk1/K#$uqZatctҞ={Ν;ШQƍS-<ɖ֩=$=%?JD$wD7kš4UQ#9nY҇ήcǎ;v*V`jOn<̪0^>#kf7Ó} >HxTnevk]._ο$6>[}m9J ?Ŷ:Sy)R} !EVȩry%wȋ;HLt7\#*'.'%v7/dMd=//oT +X6,xJ ӓ;) mt)I3E}_)#RN7KR=i'/c ?+x?Yƅ)r$L5%+~ZzKaNJ4/d4ODB[@~;NWc{_ĉ؛-$> dĿ)9DH 9Z K%wUnUV'ZQq`O""V2zf(h-^*rb%r/K毢/|;,ޗSdmdJ쑚rYu> XV_fLRRRB>>'Oefz~ԩSXիW8pӦMmoTΜ9ӳgϘ eϯ\rrrZ6G=i$r^^^M4XkkkOOϦMR@dO"q`2o#OcǎС- ?֭[+rPo̙#ܪUBCCϝ;Gs%111~a]\\h3f+ 0-zׯ_vm ?=FZ;jժo nĉsss @~zZlVM;իWoٲeٶ4sh}EEE͛7oĉ~~~TPw{˫[nHHڵki-7oNMM6mڤ8qښ*3uG)**Og͚ES[NKK;w܏?{sS VZ矿[իWX[ly7_xۯ&P˗/:88x{{>}ޞ`t:[IIDGGWR:*3ZjʕfΜIx`I{Ue˖yyy> tI֨QaÆ7oXg}6))ɓ666P!ikM81;;{޼y?۷'<r}m۶͘1cʕjբXNk׮#GL8qҤIaaa P+WKmjԨQ*U3sL+++ ?HEO' ' @~ ?@~ ?O ?O' ' @~ ?@~ ?O ?O' ' @~ @~ ?O ?Of%HIENDB`allegro5-5.2.10.1/docs/src/refman/images/primitives1.svg000066400000000000000000000775671473414355200227370ustar00rootroot00000000000000 image/svg+xml x y 0 1 2 3 0 1 2 3 (0.5, 0.5) x y 0 1 2 3 0 1 2 3 allegro5-5.2.10.1/docs/src/refman/images/primitives2.png000066400000000000000000000623151473414355200227060ustar00rootroot00000000000000PNG  IHDR}isRGB pHYsss"tIMEY2 IDATxw|SO6^Жhe]YRhd\YEp\Q(׉R "*^ZFeZ{ifiC I_=眜s|ϐ L """""DDDDDĢXT """""DDDDDĢXT """""DDDDDĢXT """""DDDDDĢXT """""DDDDDĢXT """"""DDDDDĢXT """"""DDDDDĢXT """"""DDDDDĢXT """"""DDDDDĢXT """""bQADDDDDĢXT """""bQADDDDDĢXT """""bQADDDDDĢXT """""l҇tضm<\}b}a~:<==ѽ{w : Zo:#G/k.:u 2 :ts=z19T#R^zg SCǏGll,^ gggoGB`r,dժU(((жm[&dggc8~8aÆ! ɩPGT*aȐ!D" +:NץK(nZݺuJ%d@ >^YTX`/H Lݷ[ Lv wآXp~zA JR裏BXX􀲲OOO駟fQGGG]v˗텅ŋ; ԁ4oNNN3kZx{{cǎe͛775Vt-[Ŀoc&b׮]3f \\\/B29Tcz)c#""pM\|INT OOOA*cjj֭زe ;ѷo_j HHH@YY8q~~~tܶ-[ //>,QC.\@TT>s1!ի___~ .]ARl\v|C̙38qy^1}t[ bBPNN ТE ?hӦ 1c 0IuHKK0y \rr2L֭[^cBj@㥗^ A0|p&>rssvZlڴ :tܹsg1ITmJ )NT矇3{m믿̝;ɰ6e8p-[;w"<<_|f͚$A.=9oW]UF644666زe r9Rh&$$0R,jڵx-FjMp )FRgkװ}vxyy1)5k.^x)}zp]`ҤIL}jOf;99jP54w\_}Zhڴqx ɩwԾH˗!y+c(11j-Zddׯ_Gqq1x5c&55YYYhժuu """"Gr'""""bܝVO55N 慈HER^B !TS.^q""eeeP*&7H$""Oqqqڵ+.]ԩS~1jԨM x^ӂn!㳠"99 Zhzd4HMMEhh(\]]Q~}_J]uEFFbL]}aA ;vMڿ{c˖-IP^^z쉳goaÆ~4Z-;d>}U҃KIIիW RT8ydm۶!88l}_cǎXlmU*~7 >CGvmŌᗞ?R? FqeZ`B4GTWhwHLLoml1e 8Cek"99֭͛7/fH۔pT*̙3zagĉ2d0sLQ}VќS?O>0X~=k>8Vx>+r\Űx}[eh; I:6_]~>(*.?k QհQS ^ޙ7::?1cϯܹs1|;v EEE;v,&Mj5kzÇ'|+WYfL=4{ヒ~a„ hѢEwmltR :k֬AHHѭ[7lذ66:5Z4HII?͛?dܻヒE!))ɤ݅t`#8s :tp19Nt2wppȏVJtI'MP(&Ɵ=P Dp! dU򽽱{ڴ?ıcǠP(֭[c޼yݻ=PThѢ<<>;w8;;#00sAXX޽{#99zؽ{7D/є8ǖ{xx+oKKK3)*j f@8V1ŗT0ZW˚;v 8,\B Jiii8x lmm1|w,.1yd,X}5kXPԂbuj~R\pEp GmPWYRr'N|p׫Θ1#GDƍUQQXXh Wr III=W͛Hq#(dU0r?11gϞ^7nH >ʝ$!ˑd<ĿM T5k*mnAG{qD3=D?|xDg 2'>*+ZEV"”)S0b7}0`=zƪUXT܍/TyTL  `dg8mi*^ < g&'DWD$%!^1uuEUĚ$@֬U섉2y矿%&&"44mڴM`oo?ĉyӵGqŶ)DD5Ѯ];ˌWG~~> ^]vA6m ̚5F?l9 mڴ1RΝ;ѲeG+GzpjYEy%vb¢ "qw%K-bbkA^p!(J;vLnRRR#++ w6pppm﷨2e \իW֭[ .`ʔ)$W{ǗLgRW:R&5 = C;x &L;vl@:w+V :mJYYIQwQ5jT6DDѣGX4n5k֠gϞy~c}:>#߿ވE{DDտT6tPHUTE=~W\GNç~ɓ'C.?X_Jd2p> htj4H$ +<ػw/rrr`KYqQ>}:O.x;=Gf""ޑXT """""RB5rг)ADDDDĢ>%.@Qe֒d ~U},5QǩD%Y+"""37 *+)*o.yyȘ7>Vel,2C?>֜eː1o/HMEƼyȊ E{s7<>ٜ """"/)[K@nqpJQ^TInWuh33Z+VlX 7oFUڣp=p۷bMDq'+ccx{ezzũ1]^37s&Iכ:349r!!\nݕ+QE"͡ζg ڝj_lÂN]vq2\^<1QTJ%"#qkWn\QTdeƈH '("""\*0+`ϛᇸsegW9^(+CƜ99r$WvE_e _eˆXTԮl%5ؕP?ki\ӫK 7o6;}Í7nDqR[m8 ';;Vz|-r}7ڵkΝ;s8= \wGpCud"Pss7"Ǚ@# VkNRDgFcTFпTTX櫕-o AU44 EEbb"bj5,+ o=J$%¦}Nž*ڟMHOaY{w+))p=IvhFGJ`;zRS8;׮]Ȫt<~>/#Tw^&F] *ޓsbbbpuNtL8VS}9.;>PE:- -~yXpGh+6}a~~hQE/L8Vݖ;؄xs/m^/ OS"3pb$6+xG}#1[2Rx\V Spo)_$'0wkm $\y@]ܽ,>$bG>?WLv]\://l|}=f̀;W?vS##Wx|i`#4p z4͘~0kخ z4Əaի&K͚㏙45~VAjooRT*QΜj SΡwo #FBޢbc!o⎯ZzE=~wvWb y&L*=,>^QQ&'K 'OwU!""'j9ED)"O>˗ID @mғ"(CDD􈰧\O|\ݎ=PR[AADDDDd=DDDDDĢXT """""zDj,xps`.XT԰zy """" oS^ZK.}7q)0Ek3DkSOR` ue !""SQ @rYh?Hdȧ.?d貲ğ֔h!TSPINՕ+"":=DDDDDĢjgW O5<Lh߽|UG=_8W*S&L0yms X,Aم Ҹ81XehZϜiҦMO,[Nu̘ZUk ~"\rRwށiS~iXTX.[SG*6[T"**ʬ}߾};wI[Ν1bĈZE&LբBcG':NJx{jQ!Tw̩26dXVEEYBB jYǴi """nTW aogɆ+%OVqaɒ%fsέ6w |!Z"ۄ p8\w/J탢M nl:9jR''~t99p;f͌!!CHIt} $ Vs%DDDĢnV_E͋ .]Ú$cQUEoKmeFEd>صm+XNNf_]N/8gRaSoNt󟈈j_ """""5<<n%Kf6jH1J wn}7o.X킃!usMqJa߽;\x< nZG_||QȧIp4*btY17on5󟈈XTXD}' @DDDDTSADDDDD,*E """"OԮ"p"l<|Uƞj8u5 """""bQADDDDD!s*A}i&:u hԨ3gёsذa>7oAٳ'fϞ ///&ȂDS~a˖-qU̟?O<JKK9ñb "<<Xlڵk4&.vvvXz5/`ŊHNNɓ+WrnQ-^7nm_Xl233h"&.7nlmmm3g:ub 8< xl6uT8886.}* $)S:7FNl\  E^JObv\YBnV߫6]e{*++JB`` ADdAA'={ٳh֬xZ޽{CprL.<-'6| 7 Scujb7n"##:_ǧ~]v!44lQdz*` [׆lL8-[4|H8w6mSbq1%FeeP rKJ'ITGbi):ulK.eQ(}ᇘ?>.]ٳgصkqDF}s AR_m◝l~!M1?ax8DȪh4A_ZlzM4A-X+yf >ǏǪU|T*ß| v 4(xwtw=w~^̞=CE=Ľ_~?sqFddd`ƌ_ԩSѾ}{Qy ̙3?hٻ{{{cǎun+/1y* J h8fcc:Nd֧nxZOx饗h"z?l'a~ Dmƍg}777Qya쎍O?EA܋&;v`ׯV^z\ !%m_%Kcǎ5))I ˭"Vgggt }u.\+Wbƌ3f]Whi~D\E~B޳F>v]pUĺs( k33gĂ*믿0tPt[nB`RzQzjL:#F5k .e?\p!"3<:`prrbR駟0qD 2֭L&E\W;os!"ѺukܹDDd9HNN /`׿e2m۶x9LjZáT*ၩSsww_$յ8A.''lO&""q)JYYMi4&.ػw/Y)DD) """""-Psg.ng[@҇QUSADDDDD,*E """""T`y ҥKVgzz:S rUĚb`XT<~iV޽{ȜZZ?uݸqEcb.XT"a U5޼LVxNSSSqQ6OOO4mڴbիWM._ FR֭[ťbMHH@aa=s*ѩSZSɓ&mj7o4kzz:Laoo|mɉ+""""(zZ,dgg٤Yfknn.S;;;FRiXVP(L[l/7 +?XyyŐ!Cڏ=Ze{m D``I[ii),X{e9U(f1󢋵iӦf=e APPW:DDD,*/PXQMDDDDD,*jX5ha1*޽;\]]S y6bԫW/xzzrCDDĢg-:wlq6nܘ90L&虜EDDDßEö *#悈EE @q,c.XT """""bQADDDDD,**dggcڵHKKc23OE5> x:1DDwR~}# mڴAxx8ѣGpsCDĢ1@Dt/Ç5 qqqXx11h cD1<,^Xlذ2 PTT͛7㥗^/[ojL """s=6nHRz㸳gbݻ7ի#GbժU<EaÆaƍJJ+67 B/8q"d/9tOE{^퀢tqj{ ;h+VkG}oCq'xi~0JN]j''N@Trq;,X(H$`"C9sXx1Э[7DDD_ "bQuzYdZ%)2uV[dв"\%w7t,tå~_Fa.c-8 cUnhz{{W{vҤI֥*%%%ػw/݋9s}Tt:iZZrrr"VJ+WMq&%%AZs̩kYT<0b,\^L8V6΋(g} 8Ia'swN-2Uiqh(i }4ݡى:N^ 7toέlO,3 hժ~4'DTl(\T<:WZ-JKK$T*HR( ZPPH$(UVHbbyWkۡCDDD}/tAӡDINX0Ͻضy藇';ŐӳCDg*0&[Dh,A< sW>ֱx]Wq&d]s*辴 87;bG>&LGpp0f͚%X켑t1 4mY+k?pEQWruu5bРA-#sGsADt"22+VN0dXT<&ѽ ӧ#..QQQ C׮]ADĢz^zL ""$='MDDDDD,*j si|OǮ/:6dQADDDDĢH$́KU  D"""",*: w)ox@ڤvcw?C戈Dj8u^`]Vt1 t dEAz-zi/!@2b-9-8ˮ6""=ՐQhx,Q[Gϟ]LY+Qxh1P^z H?bҋ4qǩ+0T Q] zJNiW +W 7^zW ߘ hR7""""uHF͙p'/ ܿb>ùr1oDDDDւ?UayZNDcRbII{)9^ܩ kc ~@٭\*  +xD 1'o告m~Lʀ-.t.0\zpN[<:i%G+bpxa,Y1 ( h2+Ʒ~oP';L!s̝;פs1bģRJT o5UTS1Wh^^YhAL:cTmWͧ@[q\h3Qʒ ~(*.d@@Cqtx(gp 4:k (W"_ouY$CR||Յۆ/4U]6&-j &I0 """u@F@i%/C@.8dsV^+$|o~Vox@p /9PjŰ@ўlNك {>Ӱ<+ CPz P0"N$ @\[ULlCH^yÊ_z-*=wRr4m筂 áb[Appݯz%s1~7 EP Kx=p0Un$jݧn24w;BDDdx6=twPI/bIV0oDDDD,*N~\Ԅ"'bϊś؊aW =TwI!""bQ-1<ZG);tϣ ńbʭ`g]aLq57}\xL jmxln%WYh _u<5ˣ޾3,>Z4+&>oJ5 V>iZ상:"""D9 T7Oe """"Dw%7ܻKXeeW{7^c.XTՐ~,Pr "":oܛh\XuHdH(\xL jc#˲m t{Mݛ2I"؃9 ""bQ߿NBƍrnyW1qDKgTOޏxbH7CO]Ks!66x"ǡHOOǐ!CZ-*vlk%}Odg5ŚbUnww( \ ص0\Z/see9r$ "0^)22ݺumǒW.ep?54flaRPWZ`shhq*/Bz@\У{AբeKv=6EƍsNXskaXnqxf;a/{ {; Xp3\^H?b҉COovvvLC ßrrr+`ѢE *qk#|K?pssCpp0 pZ뱨(݋/B wwQV]n8@e/I~{JEgPXW}N/k@%Qcݯ݊G"!%b܋,:`L6έoESm6lܸ'NL&wE$fUmT"XOGA' ( ZfNYNG` IDATbCC\Q?g7|rպ:s;G;@_h0Sf4"ts,=Q\.[ݝwF XhͭxC ;69|=̀CUB;BA U_Y I-/>T#N(n @v2MDSQPP֭[^%KLvSqn۪PEb; <4d;!X}OGw!9Y MAGǐ: 8s N})ۦ85W`mhN;uSipC!ck)&v':w :|^ADk [Ekuwgz={7njlWO&NUVsnKD^EӞ{mzϟ';ŐӳLEF۠/ypC7>\+:EfA:W O>Сbbb ==111hժU\KģW^@ҕt l:WG/i7+O4 j:Ö3LX? 1+lh\-5)*ƍq1|&۔ &&ҥ EDT<`̘1fN:C;ùFhU"F_֞Y=I{Ӕi}O1R8c&N$*CGw!A1cFQF᧟~b,@4]t)lmm<̞=sNOͧd4qobYxXPḲ/em@='NrҶm[4jyyy("=;I&[r)ȥ o(9TeStsœ87T2))2ErM(V*PҴI~B[BOȣ9'srwN'#9Rt:tV?"44ƃ@BEid9SG#mlRnx#M7#nndZyN:f/a=ܖToX_wz~=JSm%Pg!f/xRGZ${M])x_H}Y׵N-ٳD*&Hظӂxs|@ +e=7H_QHdj@<ӂЂ:sII1'JˤBE#c%Uu&Jz@мN5g!TudT>@ Tl1sH;z0`ǟ&TЂ:cObGv|z^uM/R2_f @h,I7eH #;.KEz%Oqf/u*wn+<4ԵziT5_c@0`LE _҈ɓM_cicSbvSVMQөM5ѦW.SөM?=E_ TT~4famPz%{i,̲: `bp?)e??,DZhr+//2f)4>k?O'׷g65)] ֞>t$i˔1_llx>.;yLWZ꜂IW=]Gh|Vk?CO}%AQMمn_@Ea=UO?ݻnZ󤓛{뷯{hwqE\TuyʪS~7`azh:r뤑~(}[rHsFcCSL2Gv~}({ҋ#{Ks'Wwzzym/=moSgS;4y,~@}>5kWɞ.^%~FEj Tm?BٳtdZ0FIRBTnJ3Oa*<#˓.Sk;rԼ=j T)ϣ = Hnfl0ӧ[^J؞cuI%Ό;uRbRL]gxW)zҜ F⑁ҝKQͿ4?@SO1yA _ľBE#4.+# :T-;Wڞ)^ 8Rzao-5g|Wxja@Zy !mAirE]=XOz0[^ԕRbK1rI΋&15уo*-hw㪓ZR` ^Uj{;-6`/_ݨi TU UR}U-  1#PHx uc|M/̤@_( Go2_5'ow&Rޫ?s&E;0zQ *za&㖎Ӂ$,s=6$]{SV,j^u+"-븩II8=}e׾xz=QJL.+IZ2,>x6hWNK_j:,]~7w,/_ _Pe=c="w$i: F0ۤZ1q²M[kyi?$W3oM[맥ӈW۬_2c|zϽOcbO:*Gyd.1#!r}){`{Rvn/7F~l֝uvǏ?Olѣ5k,Y6Y~"BCCM2wj1}V='fZ=r L0{.wȐ!eҮ7heox5ZOdܴ~[-Us_rh=-س@^k^G˗/WJw$)j`]? hSNVݬsu|q=S'|XwHV~#K|7wi3MϛEޣ^>sa}lW_|MGBјi~UoGn]t#(A*,L[pJכ7o:h%^WiDiƌ?G}T;LQҥ/_*#Icݭ[7-_\=R{o4 }k6NN 1 PhnmDaGCCRܵ%b:%)\QrXD6Kk-qY-VO{@eR3INŦh4U:  %I/}IMr̢v1֖4fɘӷC[.X4|R>J4e)3Z`F3T3g3IR\?)rr㬎(%Ia0ͺqVi[jzsTVZ^{kɵRL#o*:D8= / ~IZt)ϓ% ,RR?h\z޷U׶HרQ4 HbLj$6IYx׍zu>c(Sripɞ"%Nfx40e`PI*#G)6u@0VRRzQg|?F.u+K/ T4Cu.h<@-ʥKy G*P?id ,vzKBZHw@m6fRC/#_X ^@Aԕ)#T1)v~&^5G4D)Kw64zFO̓ҷUҡ)5U}nRR>ҡi.Ro TK+0]dktL7^L]ҷJo4Y!}3N6+^*Y>BE*-s9AkG*t"-cW.C pi["mQR:)Pf uXʯNeiJ*H_5Q~D*;6+$.)4QE,Rx3/GRh:,!R%]/2ڒ 1}r}kIeIerr- PkHK)m><.U:$_Tq$7{Wܹ ;8b GNnRۚ޷V6r Չe8:!A2Tˈ҉5yQWIşHo*fx"zo{bl ؄Im:BvoTa͜93`^ǎuW[߿#6yoҖ6U?zed "-s,3R#nmcu2[S^t.Z.X~:RRh+ RUor4ݸ>b*vL iFʟ+2RސʏIΰJy{sΟI%koIik@Wޮ-:Z6MRw_#)utrw)itQS[\e"w ߴiSZ5x8bp*HƑO8B!;:UF 3+ޙ$2wTT{bӿ YʮpfH֊ur_Mwq߯!I%y敶tсTɞh8;8RaYp;RH2)_Y#E:$ozhc8zaqJSURفVRHE ҷJnFVt#*QeIa+(SZ"`EPͺ3plir[1iZRe~tttS;)㨃$u=TeؚHWmJ8WWgNG?,sv^jmr[y3qU{>Ry2Oۖfo3Oj2fi\IjX9rWm1.Չ?|qdU2>>SA4 Ԯw[7ي~lz}R@!IQ G*Wa —wInuIi[g㛶Oi6P@CÑ w'㔒g?N9Yq";0Pؓ G*j`D)0;vk m%ohl+)&cٵ[`"6%7fuon6Bj=?*J>]||k+ (w<#ĵKiP|i7W;BE;YfV6,DjN?Z)fq150s)~@s%Ts Pqns  PQť[_H.ne\N1T8p@_~\.:vLY, ?-9K9柷;"!wW-//Ok׮ѣGնm[C45T?~\Çג%KO0ASN 5Y-IӖI>/pLLo4s֢̀Ehcpݻ߯_~Y\sN6o,}Aj͗Ƽtm')t@ZU:ThFulH`Fz/^'xBvZh;wj޽45Tkھ}.\n`T2;CEHWD-ݑ%%6ec3Yb-ZSj„ KzAgUNEm!n6ҥ-~jpIr?6 &tbysHt2c5J(HБއzƨ2oşCGH43gt;W\W^yEvR4f :x<曧Oг_]V5< eH)hP\Iº{ tݻ}j޼z)M6M7nTrrcj: wUAA_]VZ_/wd=kӯ?O(M5{J $O4}5JQAqN__|Nۺuk 0 9R#ϧ?Xsѐ!Cԯ_?k6l8~8o^,Xpzi _l\`P!B€}ùl(77Wn[_4f͞=[=nݪ_-_\8=+IJV{S9:z(NX1F%-rM]gD5Z{]nJ>XSݝW)SY|X uٳgP ؼyu&Iz5l0I+??_PӦgEt֩X;vT\\YIi_Jvg|I:^$E}޳gBBB[RHvV}.Txx7|߯K23M۱c"##hZ?e)n:9T[)5^X7fn[C>OOH2ތ+rJ_^?=zf͚'jʔ)3gʕ+5o<ӯkܸq馛L]gNN222tqtʔ)ɩr33տ?O_bZ9RѪU+IS[nE_yf"[6l#ȑ#Ϻ)Қ}PJjxIw}c*$iܸWL6Fa#fVYi>Tt>yV\m 7vu\wr:_h}3gdvѣZ6lV\5kdԌiayr8WDD:H2ޅ>Xiz DBƎ+Ţ'jǎ*))̙3b [CHV˙o-Q!) ѽ+өS>Syy[o)))IIPGL=={ٳ5zh-ZH***R5{lY, RGX4VLiriC.im|WI66 0-Zhɒ%ջwo5iDjӦΝH*$oW߾}gڵ'¿qAv6hHݻwO?޽{Lv@JNN6UM hZhaS@Cg@@8{^Fs +BŞ={YVZZg}6`SO=%Cs!rG:t($ĸK_ԧO09N͝;t#ݮ4Tc*zNw^=5 뮻N_}$i˖-NS1C\Լysу5 #Gj5&~_h bРA $ƞ~2l*""Bg`_0ݡ &hڶmbccYZ{wtkׯ *+ 2Dwfɓ'#Gf;IDAT8tGy5 8gNSӦM#PO#w  o T3FW^ye:uzB6'=sTAAAegg+33SvQl"66V}80z5h ӟ ` ڸq֬Y0Pcǎ_:(PѫW/Iի3F[?̚H޽}N4iN8~&@0,l'wyG˖-?04Fe͘1C&MR||9ӧzN׮]4w\}'F*\.3h„ jӦ kpN[lƏngǟrssplR۷od ΚULL<$iǎJJJ1pAsuJLLTII{9OVTRR{@?!hTm۶ҥ.]ʚg:|n*NCG4i4c *̞=[}>{(**_|˗駟վ}{*y^}Zn&Mɓ'k4jAi6lt]wZ۲ev$r-zdXh {P@@@@BBBB*****PPPP T T T T@@@@BBBB***˕߼;IENDB`allegro5-5.2.10.1/docs/src/refman/images/primitives2.svg000066400000000000000000002075051473414355200227230ustar00rootroot00000000000000 image/svg+xml x y 0 2 4 6 0 2 4 6 x y 0 2 4 6 0 2 4 6 allegro5-5.2.10.1/docs/src/refman/inc.a.txt000066400000000000000000000041771473414355200202110ustar00rootroot00000000000000
allegro5-5.2.10.1/docs/src/refman/inc.z.txt000066400000000000000000000000071473414355200202260ustar00rootroot00000000000000
allegro5-5.2.10.1/docs/src/refman/index.txt000066400000000000000000000027431473414355200203250ustar00rootroot00000000000000% Allegro 5 reference manual * [Getting started guide](getting_started.html) Core API === * [Configuration files](config.html) * [Displays](display.html) * [Events](events.html) * [File I/O](file.html) * [Filesystem](fshook.html) * [Fixed point math](fixed.html) * [Fullscreen modes](fullscreen_mode.html) * [Graphics routines](graphics.html) * [Haptic routines](haptic.html) * [Joystick routines](joystick.html) * [Keyboard routines](keyboard.html) * [Memory management](memory.html) * [Monitors](monitor.html) * [Mouse routines](mouse.html) * [Path structures](path.html) * [Shader](shader.html) * [State](state.html) * [System routines](system.html) * [Threads](threads.html) * [Time](time.html) * [Timer](timer.html) * [Touch input](touch.html) * [Transformations](transformations.html) * [UTF-8 string routines](utf8.html) * [Miscellaneous](misc.html) * [Platform-specific](platform.html) * [Direct3D integration](direct3d.html) * [OpenGL integration](opengl.html) Addons ====== * [Audio addon](audio.html) * [Audio codecs](acodec.html) * [Color addon](color.html) * [Font addons](font.html) * [Image I/O addon](image.html) * [Main addon](main.html) * [Memfile addon](memfile.html) * [Native dialogs addon](native_dialog.html) * [PhysicsFS addon](physfs.html) * [Primitives addon](primitives.html) * [Video streaming addon](video.html) allegro5-5.2.10.1/docs/src/refman/joystick.txt000066400000000000000000000142731473414355200210560ustar00rootroot00000000000000# Joystick routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ On Windows there are two joystick drivers, a DirectInput one and an Xinput one. If support for XInput was compiled in, then it can be enabled by calling al_set_config_value(al_get_system_config(), "joystick", "driver", "xinput") before calling al_install_joystick, or by setting the same option in the allegro5.cfg configuration file. The Xinput and DirectInput drivers are mutually exclusive. The haptics subsystem will use the same driver as the joystick system does. ## API: ALLEGRO_JOYSTICK This is an abstract data type representing a physical joystick. See also: [al_get_joystick] ## API: ALLEGRO_JOYSTICK_STATE This is a structure that is used to hold a "snapshot" of a joystick's axes and buttons at a particular instant. All fields public and read-only. ~~~~c struct { float axis[num_axes]; // -1.0 to 1.0 } stick[num_sticks]; int button[num_buttons]; // 0 to 32767 ~~~~ See also: [al_get_joystick_state] ## API: ALLEGRO_JOYFLAGS * ALLEGRO_JOYFLAG_DIGITAL - the stick provides digital input * ALLEGRO_JOYFLAG_ANALOGUE - the stick provides analogue input (this enum is a holdover from the old API and may be removed) See also: [al_get_joystick_stick_flags] ## API: al_install_joystick Install a joystick driver, returning true if successful. If a joystick driver was already installed, returns true immediately. See also: [al_uninstall_joystick] ## API: al_uninstall_joystick Uninstalls the active joystick driver. All outstanding [ALLEGRO_JOYSTICK] structures are invalidated. If no joystick driver was active, this function does nothing. This function is automatically called when Allegro is shut down. See also: [al_install_joystick] ## API: al_is_joystick_installed Returns true if [al_install_joystick] was called successfully. ## API: al_reconfigure_joysticks Allegro is able to cope with users connecting and disconnected joystick devices on-the-fly. On existing platforms, the joystick event source will generate an event of type `ALLEGRO_EVENT_JOYSTICK_CONFIGURATION` when a device is plugged in or unplugged. In response, you should call [al_reconfigure_joysticks]. Afterwards, the number returned by [al_get_num_joysticks] may be different, and the handles returned by [al_get_joystick] may be different or be ordered differently. All [ALLEGRO_JOYSTICK] handles remain valid, but handles for disconnected devices become inactive: their states will no longer update, and [al_get_joystick] will not return the handle. Handles for devices which remain connected will continue to represent the same devices. Previously inactive handles may become active again, being reused to represent newly connected devices. Returns true if the joystick configuration changed, otherwise returns false. It is possible that on some systems, Allegro won't be able to generate `ALLEGRO_EVENT_JOYSTICK_CONFIGURATION` events. If your game has an input configuration screen or similar, you may wish to call [al_reconfigure_joysticks] when entering that screen. See also: [al_get_joystick_event_source], [ALLEGRO_EVENT] ## API: al_get_num_joysticks Return the number of joysticks currently on the system (or potentially on the system). This number can change after [al_reconfigure_joysticks] is called, in order to support hotplugging. Returns 0 if there is no joystick driver installed. See also: [al_get_joystick], [al_get_joystick_active] ## API: al_get_joystick Get a handle for a joystick on the system. The number may be from 0 to [al_get_num_joysticks]-1. If successful a pointer to a joystick object is returned, which represents a physical device. Otherwise NULL is returned. The handle and the index are only incidentally linked. After [al_reconfigure_joysticks] is called, [al_get_joystick] may return handles in a different order, and handles which represent disconnected devices will not be returned. See also: [al_get_num_joysticks], [al_reconfigure_joysticks], [al_get_joystick_active] ## API: al_release_joystick This function currently does nothing. See also: [al_get_joystick] ## API: al_get_joystick_active Return if the joystick handle is "active", i.e. in the current configuration, the handle represents some physical device plugged into the system. [al_get_joystick] returns active handles. After reconfiguration, active handles may become inactive, and vice versa. See also: [al_reconfigure_joysticks] ## API: al_get_joystick_name Return the name of the given joystick. See also: [al_get_joystick_stick_name], [al_get_joystick_axis_name], [al_get_joystick_button_name] ## API: al_get_joystick_stick_name Return the name of the given "stick". If the stick doesn't exist, NULL is returned. See also: [al_get_joystick_axis_name], [al_get_joystick_num_sticks] ## API: al_get_joystick_axis_name Return the name of the given axis. If the axis doesn't exist, NULL is returned. Indices begin from 0. See also: [al_get_joystick_stick_name], [al_get_joystick_num_axes] ## API: al_get_joystick_button_name Return the name of the given button. If the button doesn't exist, NULL is returned. Indices begin from 0. See also: [al_get_joystick_stick_name], [al_get_joystick_axis_name], [al_get_joystick_num_buttons] ## API: al_get_joystick_stick_flags Return the flags of the given "stick". If the stick doesn't exist, NULL is returned. Indices begin from 0. See also: [ALLEGRO_JOYFLAGS] ## API: al_get_joystick_num_sticks Return the number of "sticks" on the given joystick. A stick has one or more axes. See also: [al_get_joystick_num_axes], [al_get_joystick_num_buttons] ## API: al_get_joystick_num_axes Return the number of axes on the given "stick". If the stick doesn't exist, 0 is returned. See also: [al_get_joystick_num_sticks] ## API: al_get_joystick_num_buttons Return the number of buttons on the joystick. See also: [al_get_joystick_num_sticks] ## API: al_get_joystick_state Get the current joystick state. See also: [ALLEGRO_JOYSTICK_STATE], [al_get_joystick_num_buttons], [al_get_joystick_num_axes] ## API: al_get_joystick_event_source Returns the global joystick event source. All [joystick events][ALLEGRO_EVENT_JOYSTICK_AXIS] are generated by this event source. allegro5-5.2.10.1/docs/src/refman/keyboard.txt000066400000000000000000000142551473414355200210170ustar00rootroot00000000000000# Keyboard routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: ALLEGRO_KEYBOARD_STATE This is a structure that is used to hold a "snapshot" of a keyboard's state at a particular instant. It contains the following publically readable fields: * display - points to the display that had keyboard focus at the time the state was saved. If no display was focused, this points to NULL. You cannot read the state of keys directly. Use the function [al_key_down]. ## Key codes The constant ALLEGRO_KEY_MAX is always one higher than the highest key code. So if you want to use the key code as array index you can do something like this: ~~~~c bool pressed_keys[ALLEGRO_KEY_MAX]; //... pressed_keys[key_code] = true; ~~~~ These are the list of key codes used by Allegro, which are returned in the event.keyboard.keycode field of the ALLEGRO_EVENT_KEY_DOWN and ALLEGRO_EVENT_KEY_UP events and which you can pass to [al_key_down]: ALLEGRO_KEY_A ... ALLEGRO_KEY_Z ALLEGRO_KEY_0 ... ALLEGRO_KEY_9 ALLEGRO_KEY_PAD_0 ... ALLEGRO_KEY_PAD_9 ALLEGRO_KEY_F1 ... ALLEGRO_KEY_F12 ALLEGRO_KEY_ESCAPE ALLEGRO_KEY_TILDE ALLEGRO_KEY_MINUS ALLEGRO_KEY_EQUALS ALLEGRO_KEY_BACKSPACE ALLEGRO_KEY_TAB ALLEGRO_KEY_OPENBRACE ALLEGRO_KEY_CLOSEBRACE ALLEGRO_KEY_ENTER ALLEGRO_KEY_SEMICOLON ALLEGRO_KEY_QUOTE ALLEGRO_KEY_BACKSLASH ALLEGRO_KEY_BACKSLASH2 ALLEGRO_KEY_COMMA ALLEGRO_KEY_FULLSTOP ALLEGRO_KEY_SLASH ALLEGRO_KEY_SPACE ALLEGRO_KEY_INSERT ALLEGRO_KEY_DELETE ALLEGRO_KEY_HOME ALLEGRO_KEY_END ALLEGRO_KEY_PGUP ALLEGRO_KEY_PGDN ALLEGRO_KEY_LEFT ALLEGRO_KEY_RIGHT ALLEGRO_KEY_UP ALLEGRO_KEY_DOWN ALLEGRO_KEY_PAD_SLASH ALLEGRO_KEY_PAD_ASTERISK ALLEGRO_KEY_PAD_MINUS ALLEGRO_KEY_PAD_PLUS ALLEGRO_KEY_PAD_DELETE ALLEGRO_KEY_PAD_ENTER ALLEGRO_KEY_PRINTSCREEN ALLEGRO_KEY_PAUSE ALLEGRO_KEY_ABNT_C1 ALLEGRO_KEY_YEN ALLEGRO_KEY_KANA ALLEGRO_KEY_CONVERT ALLEGRO_KEY_NOCONVERT ALLEGRO_KEY_AT ALLEGRO_KEY_CIRCUMFLEX ALLEGRO_KEY_COLON2 ALLEGRO_KEY_KANJI ALLEGRO_KEY_LSHIFT ALLEGRO_KEY_RSHIFT ALLEGRO_KEY_LCTRL ALLEGRO_KEY_RCTRL ALLEGRO_KEY_ALT ALLEGRO_KEY_ALTGR ALLEGRO_KEY_LWIN ALLEGRO_KEY_RWIN ALLEGRO_KEY_MENU ALLEGRO_KEY_SCROLLLOCK ALLEGRO_KEY_NUMLOCK ALLEGRO_KEY_CAPSLOCK ALLEGRO_KEY_PAD_EQUALS ALLEGRO_KEY_BACKQUOTE ALLEGRO_KEY_SEMICOLON2 ALLEGRO_KEY_COMMAND /* Since: 5.1.1 */ /* Android only for now */ ALLEGRO_KEY_BACK /* Since: 5.1.2 */ /* Android only for now */ ALLEGRO_KEY_VOLUME_UP ALLEGRO_KEY_VOLUME_DOWN /* Since: 5.1.6 */ /* Android only for now */ ALLEGRO_KEY_SEARCH ALLEGRO_KEY_DPAD_CENTER ALLEGRO_KEY_BUTTON_X ALLEGRO_KEY_BUTTON_Y ALLEGRO_KEY_DPAD_UP ALLEGRO_KEY_DPAD_DOWN ALLEGRO_KEY_DPAD_LEFT ALLEGRO_KEY_DPAD_RIGHT ALLEGRO_KEY_SELECT ALLEGRO_KEY_START ALLEGRO_KEY_L1 ALLEGRO_KEY_R1 ## Keyboard modifier flags ALLEGRO_KEYMOD_SHIFT ALLEGRO_KEYMOD_CTRL ALLEGRO_KEYMOD_ALT ALLEGRO_KEYMOD_LWIN ALLEGRO_KEYMOD_RWIN ALLEGRO_KEYMOD_MENU ALLEGRO_KEYMOD_ALTGR ALLEGRO_KEYMOD_COMMAND ALLEGRO_KEYMOD_SCROLLLOCK ALLEGRO_KEYMOD_NUMLOCK ALLEGRO_KEYMOD_CAPSLOCK ALLEGRO_KEYMOD_INALTSEQ ALLEGRO_KEYMOD_ACCENT1 ALLEGRO_KEYMOD_ACCENT2 ALLEGRO_KEYMOD_ACCENT3 ALLEGRO_KEYMOD_ACCENT4 The event field 'keyboard.modifiers' is a bitfield composed of these constants. These indicate the modifier keys which were pressed at the time a character was typed. ## API: al_install_keyboard Install a keyboard driver. Returns true if successful. If a driver was already installed, nothing happens and true is returned. See also: [al_uninstall_keyboard], [al_is_keyboard_installed] ## API: al_is_keyboard_installed Returns true if [al_install_keyboard] was called successfully. ## API: al_uninstall_keyboard Uninstalls the active keyboard driver, if any. This will automatically unregister the keyboard event source with any event queues. This function is automatically called when Allegro is shut down. See also: [al_install_keyboard] ## API: al_get_keyboard_state Save the state of the keyboard specified at the time the function is called into the structure pointed to by *ret_state*. See also: [al_key_down], [al_clear_keyboard_state], [ALLEGRO_KEYBOARD_STATE] ## API: al_clear_keyboard_state Clear the state of the keyboard, emitting [ALLEGRO_EVENT_KEY_UP] for each currently pressed key. The given display is regarded as the one which had the keyboard focus when the event occurred. In case display is NULL no event is emitted. For most keyboard drivers Allegro maintains its own state of the keyboard, which might get out of sync with the real one. This function is intended to remedy such situation by resetting Allegro's keyboard state to a known default (no key pressed). This is particularly useful in response to [ALLEGRO_EVENT_DISPLAY_SWITCH_OUT] events. See also: [al_get_keyboard_state], [ALLEGRO_KEYBOARD_STATE] Since: 5.2.3 > *[Unstable API]:* This is a new feature and the exact semantics are still being decided upon. ## API: al_key_down Return true if the key specified was held down in the state specified. See also: [ALLEGRO_KEYBOARD_STATE] ## API: al_keycode_to_name Converts the given keycode to a description of the key. ## API: al_can_set_keyboard_leds Returns true if setting the keyboard LED indicators is available. Since: 5.2.9 See also: [al_set_keyboard_leds] ## API: al_set_keyboard_leds Overrides the state of the keyboard LED indicators. Set `leds` to a combination of the keyboard modifier flags to enable the corresponding LED indicators (`ALLEGRO_KEYMOD_NUMLOCK`, `ALLEGRO_KEYMOD_CAPSLOCK` and `ALLEGRO_KEYMOD_SCROLLLOCK` are supported) or to -1 to return to default behavior. False is returned if the current keyboard driver cannot set LED indicators. See also: [al_can_set_keyboard_leds] ## API: al_get_keyboard_event_source Retrieve the keyboard event source. All [keyboard events][ALLEGRO_EVENT_KEY_DOWN] are generated by this event source. Returns NULL if the keyboard subsystem was not installed. allegro5-5.2.10.1/docs/src/refman/latex.template000066400000000000000000000133621473414355200213260ustar00rootroot00000000000000%% This template is a modified version of the default pandoc latex template. %% Changes are marked with double-%% comments. %% Most of it was "inspired" by the Memoir manual. $if(legacy-header)$ $legacy-header$ $else$ %% Replacement for the book document class. \documentclass[a4paper]{memoir} %% The default layout looks too wasteful to me. \usepackage[a4paper,hmargin=2.6cm,top=2.4cm,bottom=3cm,footskip=1cm,centering]{geometry} %% ToC down to subsections \settocdepth{subsection} %% Numbering down to subsections as well \setsecnumdepth{subsection} %% Choose a nice looking chapter style. \chapterstyle{ell} %\chapterstyle{ger} %% Choose a nice font. \usepackage[T1]{fontenc} %\usepackage{mathpazo} % roman=Palatino %\usepackage{mathptmx} % roman=Times %\usepackage{newcent} % roman=New Century Schoolbook \usepackage{lmodern} % sansserif=Latin Modern Sans \usepackage{charter} % roman=Charter \usepackage{inconsolata} % typewriter=Inconsolata % TODO: I don't like the sans serif fonts much. %% Does this help with overlongs? \midsloppy %% The long identifiers make justified text look quite ugly. \raggedright %% In definition lists, start the description on the next line. \usepackage{enumitem} \setdescription{style=nextline} \usepackage{amssymb,amsmath} $if(xetex)$ \usepackage{ifxetex} \ifxetex \usepackage{fontspec,xltxtra,xunicode} \defaultfontfeatures{Mapping=tex-text,Scale=MatchLowercase} \else \usepackage[mathletters]{ucs} \usepackage[utf8x]{inputenc} \fi $else$ \usepackage[mathletters]{ucs} \usepackage[utf8x]{inputenc} $endif$ $if(lhs)$ \usepackage{listings} \lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{} $endif$ $endif$ %% Use `Verbatim' environments so we can offset them slightly. \usepackage{fancyvrb} \fvset{xleftmargin=8pt} $if(fancy-enums)$ % Redefine labelwidth for lists; otherwise, the enumerate package will cause % markers to extend beyond the left margin. \makeatletter\AtBeginDocument{% \renewcommand{\@listi} {\setlength{\labelwidth}{4em}} }\makeatother \usepackage{enumerate} $endif$ $if(tables)$ \usepackage{array} % This is needed because raggedright in table elements redefines \\: \newcommand{\PreserveBackslash}[1]{\let\temp=\\#1\let\\=\temp} \let\PBS=\PreserveBackslash $endif$ $if(strikeout)$ \usepackage[normalem]{ulem} $endif$ $if(subscript)$ \newcommand{\textsubscr}[1]{\ensuremath{_{\scriptsize\textrm{#1}}}} $endif$ $if(url)$ \usepackage{url} $endif$ $if(graphics)$ \usepackage{graphicx} % We will generate all images so they have a width \maxwidth. This means % that they will get their normal width if they fit onto the page, but % are scaled down if they would overflow the margins. \makeatletter \def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth \else\Gin@nat@width\fi} \makeatother \let\Oldincludegraphics\includegraphics \renewcommand{\includegraphics}[1]{\Oldincludegraphics[width=\maxwidth]{#1}} $endif$ \usepackage[breaklinks=true,unicode=true]{hyperref} %% Nice coloured links. \usepackage{color} \definecolor{linkcolor}{rgb}{0.2,0.2,0.45} \hypersetup{ colorlinks=true, linkcolor=linkcolor, citecolor=linkcolor, filecolor=linkcolor, urlcolor=linkcolor } \setlength{\parindent}{0pt} \setlength{\parskip}{6pt plus 2pt minus 1pt} $if(numbersections)$ $else$ \setcounter{secnumdepth}{0} $endif$ $if(verbatim-in-note)$ \VerbatimFootnotes % allows verbatim text in footnotes $endif$ $for(header-includes)$ $header-includes$ $endfor$ $if(title)$ \title{$title$} $endif$ $if(author)$ \author{$for(author)$$author$$sep$\\$endfor$} $endif$ $if(date)$ \date{$date$} $endif$ \begin{document} %% Make a nice title page. \frontmatter \pagestyle{empty} % no page numbers, etc. \vspace*{\fill} \begin{center} \HUGE\textsf{The Allegro 5 Library}\par \end{center} \begin{center} \HUGE\textsf{Reference Manual}\par \end{center} \begin{center} \vspace*{10pt} \LARGE\textsf{Version \input{allegro_version.tex}}\par \end{center} \begin{center} \vspace*{\fill} \LARGE{\textcopyright{} 2008 --- 2015} \end{center} \cleardoublepage \pagestyle{ruled} %% Fiddle with the spacing in table of contents. \setlength\cftsectionindent{1.5em} \setlength\cftsubsectionindent{1.5em} \setlength\cftchapternumwidth{2em} \setlength\cftsectionnumwidth{3.7em} \setlength\cftsubsectionnumwidth{4.7em} %% For syntax highlighting \DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}} \newenvironment{Shaded}{}{} \newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{{#1}}} \newcommand{\ImportTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{{#1}}} \newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}} \newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}} \newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{{#1}}} \newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}} \newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}} \newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}} \newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}} \newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}} \newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}} \newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{{#1}}}} \newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{{#1}}} \newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}} \newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{{#1}}} \newcommand{\RegionMarkerTok}[1]{{#1}} \newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}} \newcommand{\NormalTok}[1]{{#1}} $for(include-before)$ $include-before$ $endfor$ $if(toc)$ \tableofcontents $endif$ %% This enables page numbers, etc. \mainmatter $body$ $for(include-after)$ $include-after$ $endfor$ \end{document} %% vim: set ft=tex et: allegro5-5.2.10.1/docs/src/refman/main.txt000066400000000000000000000016101473414355200201320ustar00rootroot00000000000000# Main addon The `main` addon has no public API, but contains functionality to enable programs using Allegro to build and run without platform-specific changes. On platforms that require this functionality (e.g. OSX) this addon contains a C `main` function that invokes [al_run_main] with the user's own `main` function, where the user's `main` function has had its name mangled to something else. The file that defines the user `main` function must include the header file `allegro5/allegro.h`; that header performs the name mangling using some macros. If the user `main` function is defined in C++, then it must have the following signature for this addon to work: ~~~~c int main(int argc, char **argv) ~~~~ This addon does nothing on platforms that don't require its functionality, but you should keep it in mind in case you need to port to platforms that do require it. Link with allegro_main. allegro5-5.2.10.1/docs/src/refman/memfile.txt000066400000000000000000000017761473414355200206410ustar00rootroot00000000000000# Memfile interface The memfile interface allows you to treat a fixed block of contiguous memory as a file that can be used with Allegro's I/O functions. These functions are declared in the following header file. Link with allegro_memfile. ~~~~c #include ~~~~ ## API: al_open_memfile Returns a file handle to the block of memory. All read and write operations act upon the memory directly, so it must not be freed while the file remains open. The mode can be any combination of "r" (readable) and "w" (writable). Regardless of the mode, the file always opens at position 0. The file size is fixed and cannot be expanded. The file is always read from/written to in binary mode, which means that no newline translation is performed. It should be closed with [al_fclose]. After the file is closed, you are responsible for freeing the memory (if needed). ## API: al_get_allegro_memfile_version Returns the (compiled) version of the addon, in the same format as [al_get_allegro_version]. allegro5-5.2.10.1/docs/src/refman/memory.txt000066400000000000000000000053571473414355200205320ustar00rootroot00000000000000# Memory management routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: al_malloc Like malloc() in the C standard library, but the implementation may be overridden. This is a macro. See also: [al_free], [al_realloc], [al_calloc], [al_malloc_with_context], [al_set_memory_interface] ## API: al_free Like free() in the C standard library, but the implementation may be overridden. Additionally, on Windows, a memory block allocated by one DLL must be freed from the same DLL. In the few places where an Allegro function returns a pointer that must be freed, you must use [al_free] for portability to Windows. This is a macro. See also: [al_malloc], [al_free_with_context] ## API: al_realloc Like realloc() in the C standard library, but the implementation may be overridden. This is a macro. See also: [al_malloc], [al_realloc_with_context] ## API: al_calloc Like calloc() in the C standard library, but the implementation may be overridden. This is a macro. See also: [al_malloc], [al_calloc_with_context] ## API: al_malloc_with_context This calls malloc() from the Allegro library (this matters on Windows), unless overridden with [al_set_memory_interface], Generally you should use the [al_malloc] macro. ## API: al_free_with_context This calls free() from the Allegro library (this matters on Windows), unless overridden with [al_set_memory_interface]. Generally you should use the [al_free] macro. ## API: al_realloc_with_context This calls realloc() from the Allegro library (this matters on Windows), unless overridden with [al_set_memory_interface], Generally you should use the [al_realloc] macro. ## API: al_calloc_with_context This calls calloc() from the Allegro library (this matters on Windows), unless overridden with [al_set_memory_interface], Generally you should use the [al_calloc] macro. ## API: ALLEGRO_MEMORY_INTERFACE This structure has the following fields. ~~~~c void *(*mi_malloc)(size_t n, int line, const char *file, const char *func); void (*mi_free)(void *ptr, int line, const char *file, const char *func); void *(*mi_realloc)(void *ptr, size_t n, int line, const char *file, const char *func); void *(*mi_calloc)(size_t count, size_t n, int line, const char *file, const char *func); ~~~~ See also: [al_set_memory_interface] ## API: al_set_memory_interface Override the memory management functions with implementations of [al_malloc_with_context], [al_free_with_context], [al_realloc_with_context] and [al_calloc_with_context]. The context arguments may be used for debugging. The new functions should be thread safe. If the pointer is NULL, the default behaviour will be restored. See also: [ALLEGRO_MEMORY_INTERFACE] allegro5-5.2.10.1/docs/src/refman/misc.txt000066400000000000000000000013701473414355200201440ustar00rootroot00000000000000# Miscellaneous routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: ALLEGRO_PI C99 compilers have no predefined value like M_PI for the constant π, but you can use this one instead. ## API: al_run_main This function is useful in cases where you don't have a main() function but want to run Allegro (mostly useful in a wrapper library). Under Windows and Linux this is no problem because you simply can call [al_install_system]. But some other system (like OSX) don't allow calling [al_install_system] in the main thread. al_run_main will know what to do in that case. The passed argc and argv will simply be passed on to user_main and the return value of user_main will be returned. allegro5-5.2.10.1/docs/src/refman/monitor.txt000066400000000000000000000035241473414355200207030ustar00rootroot00000000000000# Monitors These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: ALLEGRO_MONITOR_INFO Describes a monitor's size and position relative to other monitors. x1, y1 will be 0, 0 on the primary display. Other monitors can have negative values if they are to the left or above the primary display. x2, y2 are the coordinates one beyond the bottom right pixel, so that x2-x1 gives the width and y2-y1 gives the height of the display. ~~~~c typedef struct ALLEGRO_MONITOR_INFO { int x1; int y1; int x2; int y2; } ALLEGRO_MONITOR_INFO; ~~~~ See also: [al_get_monitor_info] ## API: al_get_monitor_info Get information about a monitor's position on the desktop. adapter is a number from 0 to al_get_num_video_adapters()-1. On Windows, use [al_set_new_display_flags] to switch between Direct3D and OpenGL backends, which will often have different adapters available. Returns `true` on success, `false` on failure. See also: [ALLEGRO_MONITOR_INFO], [al_get_num_video_adapters] ## API: al_get_monitor_dpi Get the dots per inch of a monitor attached to the display adapter. Since: 5.2.5 See also: [al_get_num_video_adapters] ## API: al_get_num_video_adapters Get the number of video "adapters" attached to the computer. Each video card attached to the computer counts as one or more adapters. An adapter is thus really a video port that can have a monitor connected to it. On Windows, use [al_set_new_display_flags] to switch between Direct3D and OpenGL backends, which will often have different adapters available. See also: [al_get_monitor_info] ## API: al_get_monitor_refresh_rate Returns the current refresh rate of a monitor attached to the display adapter. Since: 5.2.6 > *[Unstable API]:* This is an experimental feature and currently only works on Windows. See also: [al_get_monitor_info] allegro5-5.2.10.1/docs/src/refman/mouse.txt000066400000000000000000000222431473414355200203430ustar00rootroot00000000000000# Mouse routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: ALLEGRO_MOUSE_STATE Public fields (read only): * x - mouse x position * y - mouse y position * w, z - mouse wheel position (2D 'ball') * buttons - mouse buttons bitfield The zeroth bit is set if the primary mouse button is held down, the first bit is set if the secondary mouse button is held down, and so on. * pressure - pressure, ranging from `0.0` to `1.0` See also: [al_get_mouse_state], [al_get_mouse_state_axis], [al_mouse_button_down] ## Mouse button constants Unlike other indexes, the first mouse button is numbered 1 when returned in the event.mouse.button field of ALLEGRO_EVENT_MOUSE_BUTTON_UP and ALLEGRO_EVENT_MOUSE_BUTTON_DOWN events. As a convenience, the following ALLEGRO_MOUSE_BUTTON constants are provided below. However, depending on the hardware there may be more or fewer mouse buttons. You can check [al_get_mouse_num_buttons] if you want to be sure. ~~~~c typedef enum ALLEGRO_MOUSE_BUTTON { ALLEGRO_MOUSE_BUTTON_LEFT = 1, ALLEGRO_MOUSE_BUTTON_RIGHT = 2, ALLEGRO_MOUSE_BUTTON_MIDDLE = 3 } ALLEGRO_MOUSE_BUTTON; ~~~~ Since: 5.2.10 See also: [al_get_mouse_num_buttons], [al_mouse_button_down] ## API: al_install_mouse Install a mouse driver. Returns true if successful. If a driver was already installed, nothing happens and true is returned. ## API: al_is_mouse_installed Returns true if [al_install_mouse] was called successfully. ## API: al_uninstall_mouse Uninstalls the active mouse driver, if any. This will automatically unregister the mouse event source with any event queues. This function is automatically called when Allegro is shut down. ## API: al_get_mouse_num_axes Return the number of axes on the mouse. The first axis is 0. See also: [al_get_mouse_num_buttons] ## API: al_get_mouse_num_buttons Return the number of buttons on the mouse. The first button is 1. See also: [al_get_mouse_num_axes] ## API: al_get_mouse_state Save the state of the mouse specified at the time the function is called into the given structure. Example: ~~~~c ALLEGRO_MOUSE_STATE state; al_get_mouse_state(&state); if (state.buttons & 1) { /* Primary (e.g. left) mouse button is held. */ printf("Mouse position: (%d, %d)\n", state.x, state.y); } if (state.buttons & 2) { /* Secondary (e.g. right) mouse button is held. */ } if (state.buttons & 4) { /* Tertiary (e.g. middle) mouse button is held. */ } ~~~~ See also: [ALLEGRO_MOUSE_STATE], [al_get_mouse_state_axis], [al_mouse_button_down] ## API: al_get_mouse_state_axis Extract the mouse axis value from the saved state. The axes are numbered from 0, in this order: x-axis, y-axis, z-axis, w-axis. See also: [ALLEGRO_MOUSE_STATE], [al_get_mouse_state], [al_mouse_button_down] ## API: al_mouse_button_down Return true if the mouse button specified was held down in the state specified. Unlike most things, the first mouse button is numbered 1. As a convenience, the constants ALLEGRO_MOUSE_BUTTON_LEFT, ALLEGRO_MOUSE_BUTTON_RIGHT, ALLEGRO_MOUSE_BUTTON_MIDDLE are provided. However, depending on the hardware there may be more or fewer mouse buttons. You can check [al_get_mouse_num_buttons] if you want to be sure. See also: [ALLEGRO_MOUSE_STATE], [al_get_mouse_state], [al_get_mouse_state_axis] ## API: al_set_mouse_xy Try to position the mouse at the given coordinates on the given display. The mouse movement resulting from a successful move will generate an [ALLEGRO_EVENT_MOUSE_WARPED] event. Returns true on success, false on failure. See also: [al_set_mouse_z], [al_set_mouse_w] ## API: al_set_mouse_z Set the mouse wheel position to the given value. Returns true on success, false on failure. See also: [al_set_mouse_w] ## API: al_set_mouse_w Set the second mouse wheel position to the given value. Returns true on success, false on failure. See also: [al_set_mouse_z] ## API: al_set_mouse_axis Set the given mouse axis to the given value. The axis number must not be 0 or 1, which are the X and Y axes. Use [al_set_mouse_xy] for that. Returns true on success, false on failure. See also: [al_set_mouse_xy], [al_set_mouse_z], [al_set_mouse_w] ## API: al_get_mouse_event_source Retrieve the mouse event source. All [mouse events][ALLEGRO_EVENT_MOUSE_AXES] are generated by this event source. Returns NULL if the mouse subsystem was not installed. ## API: al_set_mouse_wheel_precision Sets the precision of the mouse wheel (the z and w coordinates). This precision manifests itself as a multiplier on the `dz` and `dw` fields in mouse events. It also affects the `z` and `w` fields of events and [ALLEGRO_MOUSE_STATE], but not in a simple way if you alter the precision often, so it is suggested to reset those axes to 0 when you change precision. Setting this to a high value allows you to detect small changes in those two axes for some high precision mice. A flexible way of using this precision is to set it to a high value (120 is likely sufficient for most, if not all, mice) and use a floating point `dz` and `dw` like so: ~~~~c al_set_mouse_wheel_precision(120); ALLEGRO_EVENT event; al_wait_for_event(event_queue, &event); if (event.type == ALLEGRO_EVENT_MOUSE_AXES) { double dz = (double)event.mouse.dz / al_get_mouse_wheel_precision(); /* Use dz in some way... */ } ~~~~ Precision is set to 1 by default. It is impossible to set it to a lower precision than that. Since: 5.1.10 See also: [al_get_mouse_wheel_precision] ## API: al_get_mouse_wheel_precision Gets the precision of the mouse wheel (the z and w coordinates). Since: 5.1.10 See also: [al_set_mouse_wheel_precision] ## Mouse cursors ### API: al_create_mouse_cursor Create a mouse cursor from the bitmap provided. `x_focus` and `y_focus` describe the bit of the cursor that will represent the actual mouse position. Returns a pointer to the cursor on success, or NULL on failure. See also: [al_set_mouse_cursor], [al_destroy_mouse_cursor] ### API: al_destroy_mouse_cursor Free the memory used by the given cursor. Has no effect if `cursor` is NULL. See also: [al_create_mouse_cursor] ### API: al_set_mouse_cursor Set the given mouse cursor to be the current mouse cursor for the given display. If the cursor is currently 'shown' (as opposed to 'hidden') the change is immediately visible. Returns true on success, false on failure. See also: [al_set_system_mouse_cursor], [al_show_mouse_cursor], [al_hide_mouse_cursor] ### API: al_set_system_mouse_cursor Set the given system mouse cursor to be the current mouse cursor for the given display. If the cursor is currently 'shown' (as opposed to 'hidden') the change is immediately visible. If the cursor doesn't exist on the current platform another cursor will be silently be substituted. The cursors are: * ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT * ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW * ALLEGRO_SYSTEM_MOUSE_CURSOR_BUSY * ALLEGRO_SYSTEM_MOUSE_CURSOR_QUESTION * ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT * ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE * ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N * ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_W * ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_S * ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E * ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW * ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_SW * ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_SE * ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE * ALLEGRO_SYSTEM_MOUSE_CURSOR_PROGRESS * ALLEGRO_SYSTEM_MOUSE_CURSOR_PRECISION * ALLEGRO_SYSTEM_MOUSE_CURSOR_LINK * ALLEGRO_SYSTEM_MOUSE_CURSOR_ALT_SELECT * ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE Returns true on success, false on failure. See also: [al_set_mouse_cursor], [al_show_mouse_cursor], [al_hide_mouse_cursor] ### API: al_can_get_mouse_cursor_position Returns true if getting the global mouse cursor position is available. Since: 5.2.9 See also: [al_get_mouse_cursor_position] ### API: al_get_mouse_cursor_position On platforms where this information is available, this function returns the global location of the mouse cursor, relative to the desktop. You should not normally use this function, as the information is not useful except for special scenarios as moving a window. Returns true on success, false on failure. See also: [al_can_get_mouse_cursor_position] ### API: al_hide_mouse_cursor Hide the mouse cursor in the given display. This has no effect on what the current mouse cursor looks like; it just makes it disappear. Returns true on success (or if the cursor already was hidden), false otherwise. See also: [al_show_mouse_cursor] ### API: al_show_mouse_cursor Make a mouse cursor visible in the given display. Returns true if a mouse cursor is shown as a result of the call (or one already was visible), false otherwise. See also: [al_hide_mouse_cursor] ### API: al_grab_mouse Confine the mouse cursor to the given display. The mouse cursor can only be confined to one display at a time. Returns true if successful, otherwise returns false. Do not assume that the cursor will remain confined until you call [al_ungrab_mouse]. It may lose the confined status at any time for other reasons. > *Note:* not yet implemented on Mac OS X. See also: [al_ungrab_mouse] ### API: al_ungrab_mouse Stop confining the mouse cursor to any display belonging to the program. > *Note:* not yet implemented on Mac OS X. See also: [al_grab_mouse] allegro5-5.2.10.1/docs/src/refman/native_dialog.txt000066400000000000000000000527431473414355200220300ustar00rootroot00000000000000# Native dialogs support These functions are declared in the following header file. Link with allegro_dialog. ~~~~c #include ~~~~ ## API: ALLEGRO_FILECHOOSER Opaque handle to a native file dialog. ## API: ALLEGRO_TEXTLOG Opaque handle to a text log window. ## API: al_init_native_dialog_addon Initialise the native dialog addon. Returns true on success, false on error. Since: 5.0.9, 5.1.0 > *Note:* Prior to Allegro 5.1.0 native dialog functions could be called without explicit initialisation, but that is now deprecated. Future functionality may require explicit initialisation. An exception is [al_show_native_message_box], which may be useful to show an error message if Allegro fails to initialise. See also: [al_shutdown_native_dialog_addon] ## API: al_is_native_dialog_addon_initialized Returns true if the native dialog addon is initialized, otherwise returns false. Since: 5.2.6 ## API: al_shutdown_native_dialog_addon Shut down the native dialog addon. Since: 5.0.9, 5.1.5 See also: [al_init_native_dialog_addon] ## API: al_create_native_file_dialog Creates a new native file dialog. You should only have one such dialog opened at a time. Parameters: - `initial_path`: The initial search path and filename. Can be NULL. To start with a blank file name the string should end with a directory separator (this should be the common case). - `title`: Title of the dialog. - `patterns`: A string containing newline separated sets of patterns to match. A pattern is either a shell-style glob pattern (e.g. `"*.txt"`) or a MIME type (e.g. `"image/png"`). Not all platforms support both (and some don't even support globs), so a portable solution is to specify a MIME type and simple style globs which Allegro will pick from to match what the platform supports (e.g. do `"image/png;*.png"`). Multiple patterns are separated using a semicolon. If the platform does not provide support for patterns, this parameter is ignored. Here are some example patterns: - `"*.txt"` -- defines a single filter, matching `*.txt` files. - `"*.txt;*.md"` -- like above, but matching two types of files. - `"Text files (*.txt, *.md) *.txt;*.md"` -- like above, but with a custom description (separated from the patterns using a space). - `"Text files *.txt\nPNG images image/png;*.png"` -- defines two filters, with the second filter using a MIME type and extension at the same time. > *Note:* Windows does not support MIME types. Android supports only MIME > types. Instead of file patterns, MacOS supports extensions, so matching > based on filename beyond file type does not work. Allegro will parse your > file pattern to try to extract the file extension. MacOS also supports > MIME types, which behave more predictably. MacOS does not support detailed > descriptions or multiple pattern sets, Allegro will strip the detailed > descriptions and concatenate all patterns into one list. - `mode`: 0, or a combination of the following flags: ALLEGRO_FILECHOOSER_FILE_MUST_EXIST : If supported by the native dialog, it will not allow entering new names, but just allow existing files to be selected. Else it is ignored. ALLEGRO_FILECHOOSER_SAVE : If the native dialog system has a different dialog for saving (for example one which allows creating new directories), it is used. Else it is ignored. ALLEGRO_FILECHOOSER_FOLDER : If there is support for a separate dialog to select a folder instead of a file, it will be used. ALLEGRO_FILECHOOSER_PICTURES : If a different dialog is available for selecting pictures, it is used. Else it is ignored. ALLEGRO_FILECHOOSER_SHOW_HIDDEN : If the platform supports it, also hidden files will be shown. ALLEGRO_FILECHOOSER_MULTIPLE : If supported, allow selecting multiple files. Returns: A handle to the dialog which you can pass to [al_show_native_file_dialog] to display it, and from which you then can query the results using [al_get_native_file_dialog_count] and [al_get_native_file_dialog_path]. When you are done, call [al_destroy_native_file_dialog] on it. If a dialog window could not be created then this function returns NULL. ## API: al_show_native_file_dialog Show the dialog window. The display may be NULL, otherwise the given display is treated as the parent if possible. This function blocks the calling thread until it returns, so you may want to spawn a thread with [al_create_thread] and call it from inside that thread. Returns true on success, false on failure. > *Note:* On Android, [ALLEGRO_EVENT_DISPLAY_HALT_DRAWING] and [ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING] need to be handled before this function returns. This means that you must call it from a different thread. ## API: al_get_native_file_dialog_count Returns the number of files selected, or 0 if the dialog was cancelled. ## API: al_get_native_file_dialog_path Returns one of the selected paths with index `i`. The index should range from `0` to the return value of [al_get_native_file_dialog_count] `-1`. > *Note:* On Android, this function returns a content:// Universal Resource Identifier instead of a file path due to the constraints of Scoped Storage. Selected files may be accessed using [al_android_open_fd]. ## API: al_destroy_native_file_dialog Frees up all resources used by the file dialog. ## API: al_show_native_message_box Show a native GUI message box. This can be used for example to display an error message if creation of an initial display fails. The display may be NULL, otherwise the given display is treated as the parent if possible. The message box will have a single "OK" button and use the style informative dialog boxes usually have on the native system. If the `buttons` parameter is not NULL, you can instead specify the button text in a string, with buttons separated by a vertical bar (|). > *Note:* The `buttons` parameter is currently unimplemented on Windows. The flags available are: ALLEGRO_MESSAGEBOX_WARN : The message is a warning. This may cause a different icon (or other effects). ALLEGRO_MESSAGEBOX_ERROR : The message is an error. ALLEGRO_MESSAGEBOX_QUESTION : The message is a question. ALLEGRO_MESSAGEBOX_OK_CANCEL : Display a cancel button alongside the "OK" button. Ignored if `buttons` is not NULL. ALLEGRO_MESSAGEBOX_YES_NO : Display Yes/No buttons instead of the "OK" button. Ignored if `buttons` is not NULL. [al_show_native_message_box] may be called without Allegro being installed. This is useful to report an error during initialisation of Allegro itself. Returns: - 0 if the dialog window was closed without activating a button. - 1 if the OK or Yes button was pressed. - 2 if the Cancel or No button was pressed. If `buttons` is not NULL, the number of the pressed button is returned, starting with 1. All of the remaining parameters must not be NULL. If a message box could not be created then this returns 0, as if the window was dismissed without activating a button. Example: ~~~~c int button = al_show_native_message_box( display, "Warning", "Are you sure?", "If you click yes then you are confirming that \"Yes\" " "is your response to the query which you have " "generated by the action you took to open this " "message box.", NULL, ALLEGRO_MESSAGEBOX_YES_NO ); ~~~~ ## API: al_open_native_text_log Opens a window to which you can append log messages with [al_append_native_text_log]. This can be useful for debugging if you don't want to depend on a console being available. Use [al_close_native_text_log] to close the window again. The flags available are: ALLEGRO_TEXTLOG_NO_CLOSE : Prevent the window from having a close button. Otherwise, if the close button is pressed, an event is generated; see [al_get_native_text_log_event_source]. ALLEGRO_TEXTLOG_MONOSPACE : Use a monospace font to display the text. Returns NULL if there was an error opening the window, or if text log windows are not implemented on the platform. > *Note:* On Android, logs can be viewed using logcat. See also: [al_append_native_text_log], [al_close_native_text_log] ## API: al_close_native_text_log Closes a message log window opened with [al_open_native_text_log] earlier. Does nothing if passed NULL. See also: [al_open_native_text_log] ## API: al_append_native_text_log Appends a line of text to the message log window and scrolls to the bottom (if the line would not be visible otherwise). This works like printf. A line is continued until you add a newline character. If the window is NULL then this function will fall back to calling printf. This makes it convenient to support logging to a window or a terminal. ## API: al_get_native_text_log_event_source Get an event source for a text log window. The possible events are: ALLEGRO_EVENT_NATIVE_DIALOG_CLOSE : The window was requested to be closed, either by pressing the close button or pressing Escape on the keyboard. The user.data1 field will hold a pointer to the [ALLEGRO_TEXTLOG] which generated the event. The user.data2 field will be 1 if the event was generated as a result of a key press; otherwise it will be zero. ## API: al_get_allegro_native_dialog_version Returns the (compiled) version of the addon, in the same format as [al_get_allegro_version]. ## Menus Menus are implemented on Windows, X and OS X. Menus on X are implemented with GTK, and have a special requirement: you must set the ALLEGRO_GTK_TOPLEVEL display flag prior to creating the display which will have menus attached. A menu can be attached to a single display window or popped up as a context menu. If you wish to use the same menu on multiple displays or use a sub-menu as a context menu, you must make a copy via [al_clone_menu] or [al_clone_menu_for_popup]. Top level items in a non-popup menu must have at least one sub-item, or the behavior is undefined. Each menu item can be given an ID of any 16-bit integer greater than zero. When a user clicks on a menu item, an event will be generated only if it has an ID. This ID should be unique per menu; if you duplicate IDs, then there will be no way for you to determine exactly which item generated the event. There are many functions that take `pos` as a parameter used for locating a particular menu item. In those cases, it represents one of two things: an ID or a zero-based index. Any value greater than zero will always be treated as an ID. Anything else (including zero) will be considered an index based on the absolute value. In other words, 0 is the first menu item, -1 is the second menu item, -2 is the third menu item, and so on. The event type is `ALLEGRO_EVENT_MENU_CLICK`. It contains three fields: ~~~~c event.user.data1 = id; event.user.data2 = (intptr_t) display; event.user.data3 = (intptr_t) menu; ~~~~ The `display` and `menu` may be NULL if it was not possible to tell exactly which item generated the event. A basic example: ~~~~c #define FILE_EXIT_ID 1 ALLEGRO_MENU *menu = al_create_menu(); ALLEGRO_MENU *file_menu = al_create_menu(); al_append_menu_item(file_menu, "Exit", FILE_EXIT_ID, 0, NULL, NULL); al_append_menu_item(menu, "File", 0, 0, NULL, file_menu); al_set_display_menu(display, menu); al_register_event_source(queue, al_get_default_menu_event_source()); al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_MENU_CLICK) { if (event.user.data1 == FILE_EXIT_ID) { exit_program(); } } ~~~~ Because there is no "DISPLAY_DESTROYED" event, you must call al_set_display_menu(display, NULL) before destroying any display with a menu attached, to avoid leaking resources. ### API: ALLEGRO_MENU An opaque data type that represents a menu that contains menu items. Each of the menu items may optionally include a sub-menu. ### API: ALLEGRO_MENU_INFO A structure that defines how to create a complete menu system. For standard menu items, the following format is used: { caption, id, flags, icon } For special items, these macros are helpful: ~~~~c ALLEGRO_START_OF_MENU(caption, id) ALLEGRO_MENU_SEPARATOR ALLEGRO_END_OF_MENU ~~~~ A well-defined menu will begin with `ALLEGRO_START_OF_MENU`, contain one or more menu items, and end with `ALLEGRO_END_OF_MENU`. A menu may contain sub-menus. An example: ~~~~c ALLEGRO_MENU_INFO menu_info[] = { ALLEGRO_START_OF_MENU("&File", 1), { "&Open", 2, 0, NULL }, ALLEGRO_START_OF_MENU("Open &Recent...", 3), { "Recent 1", 4, 0, NULL }, { "Recent 2", 5, 0, NULL }, ALLEGRO_END_OF_MENU, ALLEGRO_MENU_SEPARATOR, { "E&xit", 6, 0, NULL }, ALLEGRO_END_OF_MENU, ALLEGRO_START_OF_MENU("&Help", 7), {"&About", 8, 0, NULL }, ALLEGRO_END_OF_MENU, ALLEGRO_END_OF_MENU }; ALLEGRO_MENU *menu = al_build_menu(menu_info); ~~~~ If you prefer, you can build the menu without the structure by using [al_create_menu] and [al_insert_menu_item]. See also: [al_build_menu] ### API: al_create_menu Creates a menu container that can hold menu items. Returns `NULL` on failure. Since: 5.1.0 See also: [al_create_popup_menu], [al_build_menu] ### API: al_create_popup_menu Creates a menu container for popup menus. Only the root (outermost) menu should be created with this function. Sub menus of popups should be created with [al_create_menu]. Returns `NULL` on failure. Since: 5.1.0 See also: [al_create_menu], [al_build_menu] ### API: al_build_menu Builds a menu based on the specifications of a sequence of `ALLEGRO_MENU_INFO` elements. Returns a pointer to the root `ALLEGRO_MENU`, or `NULL` on failure. To gain access to the other menus and items, you will need to search for them using [al_find_menu_item]. Since: 5.1.0 See also: [ALLEGRO_MENU_INFO], [al_create_menu], [al_create_popup_menu] ### API: al_append_menu_item Appends a menu item to the end of the menu. See [al_insert_menu_item] for more information. Since: 5.1.0 See also: [al_insert_menu_item], [al_remove_menu_item] ### API: al_insert_menu_item Inserts a menu item at the spot specified. See the introductory text for a detailed explanation of how the `pos` parameter is interpreted. The `parent` menu can be a popup menu or a regular menu. To underline one character in the `title`, prefix it with an ampersand. The `flags` can be any combination of: ALLEGRO_MENU_ITEM_DISABLED : The item is "grayed out" and cannot be selected. ALLEGRO_MENU_ITEM_CHECKBOX : The item is a check box. This flag can only be set at the time the menu is created. If a check box is clicked, it will automatically be toggled. ALLEGRO_MENU_ITEM_CHECKED : The item is checked. If set, ALLEGRO_MENU_ITEM_CHECKBOX will automatically be set as well. The `icon` is not yet supported. The `submenu` parameter indicates that this item contains a child menu. The child menu must have previously been created with `al_create_menu`, and not be associated with any other menu. Returns `true` on success. Since: 5.1.0 See also: [al_append_menu_item], [al_remove_menu_item] ### API: al_remove_menu_item Removes the specified item from the menu and destroys it. If the item contains a sub-menu, it too is destroyed. Any references to it are invalidated. If you want to preserve that sub-menu, you should first make a copy with [al_clone_menu]. This is safe to call on a menu that is currently being displayed. Returns `true` if an item was removed. Since: 5.1.0 See also: [al_append_menu_item], [al_insert_menu_item], [al_destroy_menu] ### API: al_clone_menu Makes a copy of a menu so that it can be reused on another display. The menu being cloned can be anything: a regular menu, a popup menu, or a sub-menu. Returns the cloned menu. Since: 5.1.0 See also: [al_clone_menu_for_popup] ### API: al_clone_menu_for_popup Exactly like [al_clone_menu], except that the copy is for a popup menu. Since: 5.1.0 See also: [al_clone_menu] ### API: al_destroy_menu Destroys an entire menu, including its sub-menus. Any references to it or a sub-menu are no longer valid. It is safe to call this on a menu that is currently being displayed. Since: 5.1.0 See also: [al_remove_menu_item] ### API: al_get_menu_item_caption Returns the caption associated with the menu item. It is valid as long as the caption is not modified. Returns `NULL` if the item was not found. Since: 5.1.0 See also: [al_set_menu_item_caption] ### API: al_set_menu_item_caption Updates the menu item caption with the new `caption`. This will invalidate any previous calls to [al_get_menu_item_caption]. Since: 5.1.0 See also: [al_get_menu_item_caption] ### API: al_get_menu_item_flags Returns the currently set flags. See [al_insert_menu_item] for a description of the available flags. Returns -1 if the item was not found. Since: 5.1.0 See also: [al_set_menu_item_flags], [al_toggle_menu_item_flags] ### API: al_set_menu_item_flags Updates the menu item's flags. See [al_insert_menu_item] for a description of the available flags. Since: 5.1.0 See also: [al_get_menu_item_flags], [al_toggle_menu_item_flags] ### API: al_toggle_menu_item_flags Toggles the specified menu item's flags. See [al_insert_menu_item] for a description of the available flags. Returns a bitfield of only the specified flags that are set after the toggle. A flag that was not toggled will not be returned, even if it is set. Returns -1 if the id is invalid. Since: 5.1.0 > *[Unstable API]:* Redundant with `al_get/set_menu_item_flags`. See also: [al_get_menu_item_flags], [al_set_menu_item_flags] ### API: al_get_menu_item_icon Returns the icon associated with the menu. It is safe to draw to the returned bitmap, but you must call [al_set_menu_item_icon] in order for the changes to be applied. Returns `NULL` if the item was not found or if it has no icon. Since: 5.1.0 See also: [al_set_menu_item_icon] ### API: al_set_menu_item_icon Sets the icon for the specified menu item. The menu assumes ownership of the `ALLEGRO_BITMAP` and may invalidate the pointer, so you must clone it if you wish to continue using it. If a video bitmap is passed, it will automatically be converted to a memory bitmap, so it is preferable to pass a memory bitmap. Since: 5.1.0 See also: [al_get_menu_item_icon], [al_clone_bitmap] ### API: al_find_menu Searches in the `haystack` menu for any submenu with the given `id`. (Note that this only represents a literal ID, and cannot be used as an index.) Returns the menu, if found. Otherwise returns `NULL`. Since: 5.1.0 See also: [al_find_menu_item] ### API: al_find_menu_item Searches in the `haystack` menu for an item with the given `id`. (Note that this only represents a literal ID, and cannot be used as an index.) If `menu` and `index` are not `NULL`, they will be set as the parent menu containing the item and the zero-based (positive) index of the item. (If the menu item was not found, then their values are undefined.) Returns true if the menu item was found. Since: 5.1.0 See also: [al_find_menu] ### API: al_get_default_menu_event_source Returns the default event source used for menu clicks. If a menu was not given its own event source via [al_enable_menu_event_source], then it will use this default source. Since: 5.1.0 See also: [al_register_event_source], [al_enable_menu_event_source], [al_disable_menu_event_source] ### API: al_enable_menu_event_source Enables a unique event source for this menu. It and all of its sub-menus will use this event source. (It is safe to call this multiple times on the same menu.) Returns the event source. Since: 5.1.0 See also: [al_register_event_source], [al_get_default_menu_event_source], [al_disable_menu_event_source] ### API: al_disable_menu_event_source Disables a unique event source for the menu, causing it to use the default event source. Since: 5.1.0 See also: [al_get_default_menu_event_source], [al_enable_menu_event_source] ### API: al_get_display_menu Returns the menu associated with the `display`, or `NULL` if it does not have a menu. Since: 5.1.0 See also: [al_set_display_menu] ### API: al_set_display_menu Associates the `menu` with the `display` and shows it. If there was a previous menu associated with the display, it will be destroyed. If you don't want that to happen, you should first remove the menu with [al_remove_display_menu]. If the menu is already attached to a display, it will not be attached to the new display. If `menu` is `NULL`, the current menu will still be destroyed. > *Note:* Attaching a menu may cause the window as available to your application to be resized! You should listen for a resize event, check how much space was lost, and resize the window accordingly if you want to maintain your window's prior size. Returns true if successful. Since: 5.1.0 See also: [al_create_menu], [al_remove_display_menu] ### API: al_popup_menu Displays a context menu next to the mouse cursor. The menu must have been created with [al_create_popup_menu]. It generates events just like a regular display menu does. It is possible that the menu will be canceled without any selection being made. The `display` parameter indicates which window the menu is associated with (when you process the menu click event), but does not actually affect where the menu is located on the screen. Returns `true` if the context menu was displayed. > *Note:* On Linux this function will fail if any of the mouse keys are held down. I.e. it will only reliably work if you handle it in `ALLEGRO_MOUSE_BUTTON_UP` events and even then only if that event corresponds to the final mouse button that was pressed. Since: 5.1.0 See also: [al_create_popup_menu] ### API: al_remove_display_menu Detaches the menu associated with the display and returns it. The menu can then be used on a different display. If you simply want to destroy the active menu, you can call [al_set_display_menu] with a `NULL` menu. Since: 5.1.0 See also: [al_set_display_menu] allegro5-5.2.10.1/docs/src/refman/opengl.txt000066400000000000000000000145221473414355200205000ustar00rootroot00000000000000# OpenGL integration These functions are declared in the following header file: ~~~~c #include ~~~~ ## API: al_get_opengl_extension_list Returns the list of OpenGL extensions supported by Allegro, for the given display. Allegro will keep information about all extensions it knows about in a structure returned by `al_get_opengl_extension_list`. For example: ~~~~c if (al_get_opengl_extension_list()->ALLEGRO_GL_ARB_multitexture) { //use it } ~~~~ The extension will be set to true if available for the given display and false otherwise. This means to use the definitions and functions from an OpenGL extension, all you need to do is to check for it as above at run time, after acquiring the OpenGL display from Allegro. Under Windows, this will also work with WGL extensions, and under Unix with GLX extensions. In case you want to manually check for extensions and load function pointers yourself (say, in case the Allegro developers did not include it yet), you can use the [al_have_opengl_extension] and [al_get_opengl_proc_address] functions instead. > *Note:* the exact extensions exposed depend on how Allegro was compiled. It is recommended to use [al_have_opengl_extension] and [al_get_opengl_proc_address] for the most stable experience. ## API: al_get_opengl_proc_address Helper to get the address of an OpenGL symbol Example: How to get the function _glMultiTexCoord3fARB_ that comes with ARB's Multitexture extension: ~~~~c // define the type of the function ALLEGRO_DEFINE_PROC_TYPE(void, MULTI_TEX_FUNC, (GLenum, GLfloat, GLfloat, GLfloat)); // declare the function pointer MULTI_TEX_FUNC glMultiTexCoord3fARB; // get the address of the function glMultiTexCoord3fARB = (MULTI_TEX_FUNC) al_get_opengl_proc_address( "glMultiTexCoord3fARB"); ~~~~ If _glMultiTexCoord3fARB_ is not NULL then it can be used as if it has been defined in the OpenGL core library. > *Note:* Under Windows, OpenGL functions may need a special calling convention, so it's best to always use the ALLEGRO_DEFINE_PROC_TYPE macro when declaring function pointer types for OpenGL functions. Parameters: name - The name of the symbol you want to link to. *Return value:* A pointer to the symbol if available or NULL otherwise. ## API: al_get_opengl_texture Returns the OpenGL texture id internally used by the given bitmap if it uses one, else 0. Example: ~~~~c bitmap = al_load_bitmap("my_texture.png"); texture = al_get_opengl_texture(bitmap); if (texture != 0) glBindTexture(GL_TEXTURE_2D, texture); ~~~~ ## API: al_get_opengl_texture_size Retrieves the size of the texture used for the bitmap. This can be different from the bitmap size if OpenGL only supports power-of-two sizes or if it is a sub-bitmap. Returns true on success, false on failure. Zero width and height are returned if the bitmap is not an OpenGL bitmap. See also: [al_get_opengl_texture_position] ## API: al_get_opengl_texture_position Returns the u/v coordinates for the top/left corner of the bitmap within the used texture, in pixels. See also: [al_get_opengl_texture_size] ## API: al_get_opengl_program_object Returns the OpenGL program object associated with this shader, if the platform is `ALLEGRO_SHADER_GLSL`. Otherwise, returns 0. ## API: al_get_opengl_fbo Returns the OpenGL FBO id internally used by the given bitmap if it uses one, otherwise returns zero. No attempt will be made to create an FBO if the bitmap is not owned by the current display. The FBO returned by this function will only be freed when the bitmap is destroyed, or if you call [al_remove_opengl_fbo] on the bitmap. > *Note:* In Allegro 5.0.0 this function only returned an FBO which had previously been created by calling [al_set_target_bitmap]. It would not attempt to create an FBO itself. This has since been changed. See also: [al_remove_opengl_fbo], [al_set_target_bitmap] ## API: al_remove_opengl_fbo Explicitly free an OpenGL FBO created for a bitmap, if it has one. Usually you do not need to worry about freeing FBOs, unless you use [al_get_opengl_fbo]. See also: [al_get_opengl_fbo], [al_set_target_bitmap] ## API: al_have_opengl_extension This function is a helper to determine whether an OpenGL extension is available on the given display or not. Example: ~~~~c bool packedpixels = al_have_opengl_extension("GL_EXT_packed_pixels"); ~~~~ If _packedpixels_ is true then you can safely use the constants related to the packed pixels extension. Returns true if the extension is available; false otherwise. ## API: al_get_opengl_version Returns the OpenGL or OpenGL ES version number of the client (the computer the program is running on), for the current display. "1.0" is returned as 0x01000000, "1.2.1" is returned as 0x01020100, and "1.2.2" as 0x01020200, etc. A valid OpenGL context must exist for this function to work, which means you may *not* call it before [al_create_display]. See also: [al_get_opengl_variant] ## API: al_get_opengl_variant Returns the variant or type of OpenGL used on the running platform. This function can be called before creating a display or setting properties for new displays. Possible values are: ALLEGRO_DESKTOP_OPENGL : Regular OpenGL as seen on desktop/laptop computers. ALLEGRO_OPENGL_ES : Trimmed down version of OpenGL used on many small consumer electronic devices such as handheld (and sometimes full size) consoles. See also: [al_get_opengl_version] ## API: al_set_current_opengl_context Make the OpenGL context associated with the given display current for the calling thread. If there is a current target bitmap which belongs to a different OpenGL context, the target bitmap will be changed to NULL. Normally you do not need to use this function, as the context will be made current when you call [al_set_target_bitmap] or [al_set_target_backbuffer]. You might need it if you created an OpenGL "forward compatible" context. Then [al_get_backbuffer] only returns NULL, so it would not work to pass that to [al_set_target_bitmap]. ## OpenGL configuration You can disable the detection of any OpenGL extension by Allegro with a section like this in allegro5.cfg: ~~~~ini [opengl_disabled_extensions] GL_ARB_texture_non_power_of_two=0 GL_EXT_framebuffer_object=0 ~~~~ Any extension which appears in the section is treated as not available (it does not matter if you set it to 0 or any other value). allegro5-5.2.10.1/docs/src/refman/path.txt000066400000000000000000000172421473414355200201520ustar00rootroot00000000000000# Path structures These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ We define a path as an optional *drive*, followed by zero or more *directory components*, followed by an optional *filename*. The filename may be broken up into a *basename* and an *extension*, where the basename includes the start of the filename up to, but not including, the last dot (.) character. If no dot character exists the basename is the whole filename. The extension is everything from the last dot character to the end of the filename. ## API: al_create_path Create a path structure from a string. The last component, if it is followed by a directory separator and is neither "." nor "..", is treated as the last directory name in the path. Otherwise the last component is treated as the filename. The string may be NULL for an empty path. See also: [al_create_path_for_directory], [al_destroy_path] ## API: al_create_path_for_directory This is the same as [al_create_path], but interprets the passed string as a directory path. The filename component of the returned path will always be empty. See also: [al_create_path], [al_destroy_path] ## API: al_destroy_path Free a path structure. Does nothing if passed NULL. See also: [al_create_path], [al_create_path_for_directory] ## API: al_clone_path Clones an ALLEGRO_PATH structure. Returns NULL on failure. See also: [al_destroy_path] ## API: al_join_paths Concatenate two path structures. The first path structure is modified. If 'tail' is an absolute path, this function does nothing. If 'tail' is a relative path, all of its directory components will be appended to 'path'. tail's filename will also overwrite path's filename, even if it is just the empty string. Tail's drive is ignored. Returns true if 'tail' was a relative path and so concatenated to 'path', otherwise returns false. See also: [al_rebase_path] ## API: al_rebase_path Concatenate two path structures, modifying the second path structure. If *tail* is an absolute path, this function does nothing. Otherwise, the drive and path components in *head* are inserted at the start of *tail*. For example, if *head* is "/anchor/" and *tail* is "data/file.ext", then after the call *tail* becomes "/anchor/data/file.ext". See also: [al_join_paths] ## API: al_get_path_drive Return the drive letter on a path, or the empty string if there is none. The "drive letter" is only used on Windows, and is usually a string like "c:", but may be something like "\\\\Computer Name" in the case of UNC (Uniform Naming Convention) syntax. ## API: al_get_path_num_components Return the number of directory components in a path. The directory components do not include the final part of a path (the filename). See also: [al_get_path_component] ## API: al_get_path_component Return the i'th directory component of a path, counting from zero. If the index is negative then count from the right, i.e. -1 refers to the last path component. It is an error to pass an index which is out of bounds. See also: [al_get_path_num_components], [al_get_path_tail] ## API: al_get_path_tail Returns the last directory component, or NULL if there are no directory components. ## API: al_get_path_filename Return the filename part of the path, or the empty string if there is none. The returned pointer is valid only until the filename part of the path is modified in any way, or until the path is destroyed. See also: [al_get_path_basename], [al_get_path_extension], [al_get_path_component] ## API: al_get_path_basename Return the basename, i.e. filename with the extension removed. If the filename doesn't have an extension, the whole filename is the basename. If there is no filename part then the empty string is returned. The returned pointer is valid only until the filename part of the path is modified in any way, or until the path is destroyed. See also: [al_get_path_filename], [al_get_path_extension] ## API: al_get_path_extension Return a pointer to the start of the extension of the filename, i.e. everything from the final dot ('.') character onwards. If no dot exists, returns an empty string. The returned pointer is valid only until the filename part of the path is modified in any way, or until the path is destroyed. See also: [al_get_path_filename], [al_get_path_basename] ## API: al_set_path_drive Set the drive string on a path. The drive may be NULL, which is equivalent to setting the drive string to the empty string. See also: [al_get_path_drive] ## API: al_append_path_component Append a directory component. See also: [al_insert_path_component] ## API: al_insert_path_component Insert a directory component at index i. If the index is negative then count from the right, i.e. -1 refers to the last path component. It is an error to pass an index i which is not within these bounds: 0 <= i <= al_get_path_num_components(path). See also: [al_append_path_component], [al_replace_path_component], [al_remove_path_component] ## API: al_replace_path_component Replace the i'th directory component by another string. If the index is negative then count from the right, i.e. -1 refers to the last path component. It is an error to pass an index which is out of bounds. See also: [al_insert_path_component], [al_remove_path_component] ## API: al_remove_path_component Delete the i'th directory component. If the index is negative then count from the right, i.e. -1 refers to the last path component. It is an error to pass an index which is out of bounds. See also: [al_insert_path_component], [al_replace_path_component], [al_drop_path_tail] ## API: al_drop_path_tail Remove the last directory component, if any. See also: [al_remove_path_component] ## API: al_set_path_filename Set the optional filename part of the path. The filename may be NULL, which is equivalent to setting the filename to the empty string. See also: [al_set_path_extension], [al_get_path_filename] ## API: al_set_path_extension Replaces the extension of the path with the given one, i.e. replaces everything from the final dot ('.') character onwards, including the dot. If the filename of the path has no extension, the given one is appended. Usually the new extension you supply should include a leading dot. Returns false if the path contains no filename part, i.e. the filename part is the empty string. See also: [al_set_path_filename], [al_get_path_extension] ## API: al_path_cstr Convert a path to its string representation, i.e. optional drive, followed by directory components separated by 'delim', followed by an optional filename. To use the current native path separator, use ALLEGRO_NATIVE_PATH_SEP for 'delim'. The returned pointer is valid only until the path is modified in any way, or until the path is destroyed. This returns a null-terminated string. If you need an ALLEGRO_USTR instead, use [al_path_ustr]. See also: [al_path_ustr] ## API: al_path_ustr Convert a path to its string representation, i.e. optional drive, followed by directory components separated by 'delim', followed by an optional filename. To use the current native path separator, use ALLEGRO_NATIVE_PATH_SEP for 'delim'. The returned pointer is valid only until the path is modified in any way, or until the path is destroyed. This returns an ALLEGRO_USTR. If you need a null-terminated string instead, use [al_path_cstr]. Since: 5.2.3 See also: [al_path_cstr] ## API: al_make_path_canonical Removes any leading '..' directory components in absolute paths. Removes all '.' directory components. Note that this does *not* collapse "x/../y" sections into "y". This is by design. If "/foo" on your system is a symlink to "/bar/baz", then "/foo/../quux" is actually "/bar/quux", not "/quux" as a naive removal of ".." components would give you. allegro5-5.2.10.1/docs/src/refman/physfs.txt000066400000000000000000000033521473414355200205270ustar00rootroot00000000000000# PhysicsFS integration PhysicsFS is a library to provide abstract access to various archives. See for more information. This addon makes it possible to read and write files (on disk or inside archives) using PhysicsFS, through Allegro's file I/O API. For example, that means you can use the Image I/O addon to load images from .zip files. You must set up PhysicsFS through its own API. When you want to open an ALLEGRO_FILE using PhysicsFS, first call [al_set_physfs_file_interface], then [al_fopen] or another function that calls [al_fopen]. These functions are declared in the following header file. Link with allegro_physfs. ~~~~c #include ~~~~ ## API: al_set_physfs_file_interface This function sets *both* the [ALLEGRO_FILE_INTERFACE] and [ALLEGRO_FS_INTERFACE] for the calling thread. Subsequent calls to [al_fopen] on the calling thread will be handled by PHYSFS_open(). Operations on the files returned by [al_fopen] will then be performed through PhysicsFS. Calls to the Allegro filesystem functions, such as [al_read_directory] or [al_create_fs_entry], on the calling thread will be diverted to PhysicsFS. To remember and restore another file I/O backend, you can use [al_store_state]/[al_restore_state]. > *Note:* due to an oversight, this function differs from [al_set_new_file_interface] and [al_set_standard_file_interface] which only alter the current [ALLEGRO_FILE_INTERFACE]. > *Note:* PhysFS does not support the text-mode reading and writing, which means that Windows-style newlines will not be preserved. See also: [al_set_new_file_interface]. ## API: al_get_allegro_physfs_version Returns the (compiled) version of the addon, in the same format as [al_get_allegro_version]. allegro5-5.2.10.1/docs/src/refman/platform.txt000066400000000000000000000135111473414355200210350ustar00rootroot00000000000000# Platform-specific functions ## Windows These functions are declared in the following header file: ~~~~c #include ~~~~ ### API: al_get_win_window_handle Returns the handle to the window that the passed display is using. ### API: al_win_add_window_callback The specified callback function will intercept the window's message before Allegro processes it. If the callback function consumes the event, then it should return true. In that case, Allegro will not do anything with the event. Optionally, you may use `result` to customize what Allegro will return return in response to this event. By default, Allegro returns `TRUE`. The `userdata` pointer can be used to supply additional context to the callback function. The callbacks are executed in the same order they were added. Returns true if the callback was added. Since: 5.1.2 ### API: al_win_remove_window_callback Removes the callback that was previously registered with [al_win_add_window_callback]. The `userdata` pointer must be the same as what was used during the registration of the callback. Returns true if the callback was removed. Since: 5.1.2 ## Mac OS X These functions are declared in the following header file: ~~~~c #include ~~~~ ### API: al_osx_get_window Retrieves the NSWindow handle associated with the Allegro display. Since: 5.0.8, 5.1.3 ## iPhone These functions are declared in the following header file: ~~~~c #include ~~~~ ### API: al_iphone_set_statusbar_orientation Sets the orientation of the status bar, which can be one of the following: - ALLEGRO_IPHONE_STATUSBAR_ORIENTATION_PORTRAIT - ALLEGRO_IPHONE_STATUSBAR_ORIENTATION_PORTRAIT_UPSIDE_DOWN - ALLEGRO_IPHONE_STATUSBAR_ORIENTATION_LANDSCAPE_RIGHT - ALLEGRO_IPHONE_STATUSBAR_ORIENTATION_LANDSCAPE_LEFT Since: 5.1.0 ### API: al_iphone_get_view Retrieves the UIView* (EAGLView*) associated with the Allegro display. Since: 5.1.0 ### API: al_iphone_get_window Retrieves the UIWindow* associated with the Allegro display. Since: 5.1.0 ## Android These functions are declared in the following header file: ~~~~c #include ~~~~ ### API: al_android_set_apk_file_interface This function will set up a custom [ALLEGRO_FILE_INTERFACE] that makes all future calls of [al_fopen] read from the applicatons's APK file. > *Note:* Currently, access to the APK file after calling this function is read only. Since: 5.1.2 ### API: al_android_set_apk_fs_interface This function will set up a custom [ALLEGRO_FS_INTERFACE] which allows working within the APK filesystem. The filesystem root is your assets directory and there is read-only access to all files within. > *Note:* Some things like querying file size or attributes are not supported by this. You can always use the PhysFS addon to open the APK file (it is just a regular .zip file) and get more complete information. Since: 5.1.13 ### API: al_android_get_os_version Returns a pointer to a static buffer that contains the version string of the Android platform that the calling Allegro program is running on. Since: 5.1.2 ### API: al_android_get_jni_env Returns the Android JNI environment used by Allegro to call into Java. As a convenience this function provides it to the user so there is no need to obtain it yourself. For example if you have a Java method "void send(String message)" in your activity class, you could call it like this from C code: ~~~~c JNIEnv * env = al_android_get_jni_env(); jclass class_id = (* env)->GetObjectClass(env, al_android_get_activity()); jmethodID method_id = (* env)->GetMethodID(env, class_id, "send", "(Ljava/lang/String;)V"); jstring jdata = (* env)->NewStringUTF(env, "Hello Java!"); (* env)->CallVoidMethod(env, al_android_get_activity(), method_id, jdata); (* env)->DeleteLocalRef(env, jdata); ~~~~ Since: 5.2.2 > *[Unstable API]:* This API is new and subject to refinement. ### API: al_android_get_activity Returns the Java Android activity used by Allegro. This is the same object created by Android from the class you specify in your manifest and either an instance of AllegroActivity or a derived class. Since: 5.2.2 > *[Unstable API]:* This API is new and subject to refinement. ### API: al_android_open_fd Opens a file descriptor to access data under a Universal Resource Identifier (URI). This function accepts content:// and file:// URI schemes. You are responsible for closing the returned file descriptor. The file `mode` can be `"r"`, `"w"`, `"rw"`, `"wt"`, `"wa"` or `"rwt"`. The exact implementation of these modes differ depending on the underlying content provider. For example, `"w"` may or may not truncate. Returns a file descriptor on success or a negative value on an error. On an error, the Allegro errno is set. > *Note:* Remember to add to your manifest file the relevant permissions to your app. Example: ~~~~c const char *content_uri = "content://..."; int fd = al_android_open_fd(content_uri, "r"); if (fd >= 0) { ALLEGRO_FILE *f = al_fopen_fd(fd, "r"); if (f != NULL) { do_something_with(f); al_fclose(f); } else { handle_error(al_get_errno()); close(fd); } } else { handle_error(al_get_errno()); } ~~~~ Since: 5.2.10 See also: [al_fopen_fd], [al_get_errno] > *[Unstable API]:* This API is new and subject to refinement. ## X11 These functions are declared in the following header file: ~~~~c #include ~~~~ ### API: al_get_x_window_id Retrieves the XID associated with the Allegro display. Since: 5.1.12 ### API: al_x_set_initial_icon On some window managers (notably Ubuntu's Unity) al_set_display_icon doesn't work and you need to use a .desktop file. But with this function you can set an icon before calling al_create_display. This works by setting the icon before XMapWindow. Since: 5.2.3 > *[Unstable API]:* New API. allegro5-5.2.10.1/docs/src/refman/primitives.txt000066400000000000000000001277011473414355200214130ustar00rootroot00000000000000# Primitives addon These functions are declared in the following header file. Link with allegro_primitives. ~~~~c #include ~~~~ ## General ### API: al_get_allegro_primitives_version Returns the (compiled) version of the addon, in the same format as [al_get_allegro_version]. ### API: al_init_primitives_addon Initializes the primitives addon. *Returns:* True on success, false on failure. See also: [al_shutdown_primitives_addon] ### API: al_is_primitives_addon_initialized Returns true if the primitives addon is initialized, otherwise returns false. Since: 5.2.6 See also: [al_init_primitives_addon], [al_shutdown_primitives_addon] ### API: al_shutdown_primitives_addon Shut down the primitives addon. This is done automatically at program exit, but can be called any time the user wishes as well. See also: [al_init_primitives_addon] ## High level drawing routines High level drawing routines encompass the most common usage of this addon: to draw geometric primitives, both smooth (variations on the circle theme) and piecewise linear. Outlined primitives support the concept of thickness with two distinct modes of output: hairline lines and thick lines. Hairline lines are specifically designed to be exactly a pixel wide, and are commonly used for drawing outlined figures that need to be a pixel wide. Hairline thickness is designated as thickness less than or equal to 0. Unfortunately, the exact rasterization rules for drawing these hairline lines vary from one video card to another, and sometimes leave gaps where the lines meet. If that matters to you, then you should use thick lines. In many cases, having a thickness of 1 will produce 1 pixel wide lines that look better than hairline lines. Obviously, hairline lines cannot replicate thicknesses greater than 1. Thick lines grow symmetrically around the generating shape as thickness is increased. ### Pixel-precise output While normally you should not be too concerned with which pixels are displayed when the high level primitives are drawn, it is nevertheless possible to control that precisely by carefully picking the coordinates at which you draw those primitives. To be able to do that, however, it is critical to understand how GPU cards convert shapes to pixels. Pixels are not the smallest unit that can be addressed by the GPU. Because the GPU deals with floating point coordinates, it can in fact assign different coordinates to different parts of a single pixel. To a GPU, thus, a screen is composed of a grid of squares that have width and length of 1. The top left corner of the top left pixel is located at (0, 0). Therefore, the center of that pixel is at (0.5, 0.5). The basic rule that determines which pixels are associated with which shape is then as follows: a pixel is treated to belong to a shape if the pixel's center is located in that shape. The figure below illustrates the above concepts: ![*Diagram showing a how pixel output is calculated by the GPU given the mathematical description of several shapes.*](images/primitives1.png) This figure depicts three shapes drawn at the top left of the screen: an orange and green rectangles and a purple circle. On the left are the mathematical descriptions of pixels on the screen and the shapes to be drawn. On the right is the screen output. Only a single pixel has its center inside the circle, and therefore only a single pixel is drawn on the screen. Similarly, two pixels are drawn for the orange rectangle. Since there are no pixels that have their centers inside the green rectangle, the output image has no green pixels. Here is a more practical example. The image below shows the output of this code: ~~~~c /* blue vertical line */ al_draw_line(0.5, 0, 0.5, 6, color_blue, 1); /* red horizontal line */ al_draw_line(2, 1, 6, 1, color_red, 2); /* green filled rectangle */ al_draw_filled_rectangle(3, 4, 5, 5, color_green); /* purple outlined rectangle */ al_draw_rectangle(2.5, 3.5, 5.5, 5.5, color_purple, 1); ~~~~ ![*Diagram showing a practical example of pixel output resulting from the invocation of several primitives addon functions.*](images/primitives2.png) It can be seen that lines are generated by making a rectangle based on the dashed line between the two endpoints. The thickness causes the rectangle to grow symmetrically about that generating line, as can be seen by comparing the red and blue lines. Note that to get proper pixel coverage, the coordinates passed to the `al_draw_line` had to be offset by 0.5 in the appropriate dimensions. Filled rectangles are generated by making a rectangle between the endpoints passed to the `al_draw_filled_rectangle`. Outlined rectangles are generated by symmetrically expanding an outline of a rectangle. With a thickness of 1, as depicted in the diagram, this means that an offset of 0.5 is needed for both sets of endpoint coordinates to exactly line up with the pixels of the display raster. The above rules only apply when multisampling is turned off. When multisampling is turned on, the area of a pixel that is covered by a shape is taken into account when choosing what color to draw there. This also means that shapes no longer have to contain the pixel's center to affect its color. For example, the green rectangle in the first diagram may in fact be drawn as two (or one) semi-transparent pixels. The advantages of multisampling is that slanted shapes will look smoother because they will not have jagged edges. A disadvantage of multisampling is that it may make vertical and horizontal edges blurry. While the exact rules for multisampling are unspecified, and may vary from GPU to GPU, it is usually safe to assume that as long as a pixel is either completely covered by a shape or completely not covered, then the shape edges will be sharp. The offsets used in the second diagram were chosen so that this is the case: if you use those offsets, your shapes (if they are oriented the same way as they are on the diagram) should look the same whether multisampling is turned on or off. ### API: al_draw_line Draws a line segment between two points. *Parameters:* * x1, y1, x2, y2 - Start and end points of the line * color - Color of the line * thickness - Thickness of the line, pass `<= 0` to draw hairline lines See also: [al_draw_soft_line] ### API: al_draw_triangle Draws an outlined triangle. *Parameters:* * x1, y1, x2, y2, x3, y3 - Three points of the triangle * color - Color of the triangle * thickness - Thickness of the lines, pass `<= 0` to draw hairline lines See also: [al_draw_filled_triangle], [al_draw_soft_triangle] ### API: al_draw_filled_triangle Draws a filled triangle. *Parameters:* * x1, y1, x2, y2, x3, y3 - Three points of the triangle * color - Color of the triangle See also: [al_draw_triangle] ### API: al_draw_rectangle Draws an outlined rectangle. *Parameters:* * x1, y1, x2, y2 - Upper left and lower right points of the rectangle * color - Color of the rectangle * thickness - Thickness of the lines, pass `<= 0` to draw hairline lines See also: [al_draw_filled_rectangle], [al_draw_rounded_rectangle] ### API: al_draw_filled_rectangle Draws a filled rectangle. *Parameters:* * x1, y1, x2, y2 - Upper left and lower right points of the rectangle * color - Color of the rectangle See also: [al_draw_rectangle], [al_draw_filled_rounded_rectangle] ### API: al_draw_rounded_rectangle Draws an outlined rounded rectangle. *Parameters:* * x1, y1, x2, y2 - Upper left and lower right points of the rectangle * color - Color of the rectangle * rx, ry - The radii of the round * thickness - Thickness of the lines, pass `<= 0` to draw hairline lines See also: [al_draw_filled_rounded_rectangle], [al_draw_rectangle] ### API: al_draw_filled_rounded_rectangle Draws an filled rounded rectangle. *Parameters:* * x1, y1, x2, y2 - Upper left and lower right points of the rectangle * color - Color of the rectangle * rx, ry - The radii of the round See also: [al_draw_rounded_rectangle], [al_draw_filled_rectangle] ### API: al_calculate_arc When `thickness <= 0` this function computes positions of `num_points` regularly spaced points on an elliptical arc. When `thickness > 0` this function computes two sets of points, obtained as follows: the first set is obtained by taking the points computed in the `thickness <= 0` case and shifting them by `thickness / 2` outward, in a direction perpendicular to the arc curve. The second set is the same, but shifted `thickness / 2` inward relative to the arc. The two sets of points are interleaved in the destination buffer (i.e. the first pair of points will be collinear with the arc center, the first point of the pair will be farther from the center than the second point; the next pair will also be collinear, but at a different angle and so on). The destination buffer `dest` is interpreted as a set of regularly spaced pairs of floats, each pair holding the coordinates of the corresponding point on the arc. The two floats in the pair are adjacent, and the distance (in bytes) between the addresses of the first float in two successive pairs is `stride`. For example, if you have a tightly packed array of floats with no spaces between pairs, then `stride` will be exactly `2 * sizeof(float)`. Example with `thickness <= 0`: ~~~~c const int num_points = 4; float points[num_points][2]; al_calculate_arc(&points[0][0], 2 * sizeof(float), 0, 0, 10, 10, 0, ALLEGRO_PI / 2, 0, num_points); assert((int)points[0][0] == 10); assert((int)points[0][1] == 0); assert((int)points[num_points - 1][0] == 0); assert((int)points[num_points - 1][1] == 10); ~~~~ Example with `thickness > 0`: ~~~~c const int num_points = 4; float points[num_points * 2][2]; al_calculate_arc(&points[0][0], 2 * sizeof(float), 0, 0, 10, 10, 0, ALLEGRO_PI / 2, 2, num_points); assert((int)points[0][0] == 11); assert((int)points[0][1] == 0); assert((int)points[1][0] == 9); assert((int)points[1][1] == 0); assert((int)points[(num_points - 1) * 2][0] == 0); assert((int)points[(num_points - 1) * 2][1] == 11); assert((int)points[(num_points - 1) * 2 + 1][0] == 0); assert((int)points[(num_points - 1) * 2 + 1][1] == 9); ~~~~ *Parameters:* * dest - The destination buffer * stride - Distance (in bytes) between starts of successive pairs of points * cx, cy - Center of the arc * rx, ry - Radii of the arc * start_theta - The initial angle from which the arc is calculated in radians * delta_theta - Angular span of the arc in radians (pass a negative number to switch direction) * thickness - Thickness of the arc * num_points - The number of points to calculate See also: [al_draw_arc], [al_calculate_spline], [al_calculate_ribbon] ### API: al_draw_pieslice Draws a pieslice (outlined circular sector). *Parameters:* * cx, cy - Center of the pieslice * r - Radius of the pieslice * color - Color of the pieslice * start_theta - The initial angle from which the pieslice is drawn in radians * delta_theta - Angular span of the pieslice in radians (pass a negative number to switch direction) * thickness - Thickness of the circle, pass `<= 0` to draw hairline pieslice Since: 5.0.6, 5.1.0 See also: [al_draw_filled_pieslice] ### API: al_draw_filled_pieslice Draws a filled pieslice (filled circular sector). *Parameters:* * cx, cy - Center of the pieslice * r - Radius of the pieslice * color - Color of the pieslice * start_theta - The initial angle from which the pieslice is drawn in radians * delta_theta - Angular span of the pieslice in radians (pass a negative number to switch direction) Since: 5.0.6, 5.1.0 See also: [al_draw_pieslice] ### API: al_draw_ellipse Draws an outlined ellipse. *Parameters:* * cx, cy - Center of the ellipse * rx, ry - Radii of the ellipse * color - Color of the ellipse * thickness - Thickness of the ellipse, pass `<= 0` to draw a hairline ellipse See also: [al_draw_filled_ellipse], [al_draw_circle] ### API: al_draw_filled_ellipse Draws a filled ellipse. *Parameters:* * cx, cy - Center of the ellipse * rx, ry - Radii of the ellipse * color - Color of the ellipse See also: [al_draw_ellipse], [al_draw_filled_circle] ### API: al_draw_circle Draws an outlined circle. *Parameters:* * cx, cy - Center of the circle * r - Radius of the circle * color - Color of the circle * thickness - Thickness of the circle, pass `<= 0` to draw a hairline circle See also: [al_draw_filled_circle], [al_draw_ellipse] ### API: al_draw_filled_circle Draws a filled circle. *Parameters:* * cx, cy - Center of the circle * r - Radius of the circle * color - Color of the circle See also: [al_draw_circle], [al_draw_filled_ellipse] ### API: al_draw_arc Draws an arc. *Parameters:* * cx, cy - Center of the arc * r - Radius of the arc * color - Color of the arc * start_theta - The initial angle from which the arc is calculated in radians * delta_theta - Angular span of the arc in radians (pass a negative number to switch direction) * thickness - Thickness of the arc, pass `<= 0` to draw hairline arc See also: [al_calculate_arc], [al_draw_elliptical_arc] ### API: al_draw_elliptical_arc Draws an elliptical arc. *Parameters:* * cx, cy - Center of the arc * rx, ry - Radii of the arc * color - Color of the arc * start_theta - The initial angle from which the arc is calculated in radians * delta_theta - Angular span of the arc in radians (pass a negative number to switch direction) * thickness - Thickness of the arc, pass `<= 0` to draw hairline arc Since: 5.0.6, 5.1.0 See also: [al_calculate_arc], [al_draw_arc] ### API: al_calculate_spline Calculates a Bézier spline given 4 control points. If `thickness <= 0`, then `num_segments` of points are required in the destination, otherwise twice as many are needed. The destination buffer should consist of regularly spaced (by distance of stride bytes) doublets of floats, corresponding to x and y coordinates of the vertices. *Parameters:* * dest - The destination buffer * stride - Distance (in bytes) between starts of successive pairs of coordinates * points - An array of 4 pairs of coordinates of the 4 control points * thickness - Thickness of the spline ribbon * num_segments - The number of points to calculate See also: [al_draw_spline], [al_calculate_arc], [al_calculate_ribbon] ### API: al_draw_spline Draws a Bézier spline given 4 control points. *Parameters:* * points - An array of 4 pairs of coordinates of the 4 control points * color - Color of the spline * thickness - Thickness of the spline, pass `<= 0` to draw a hairline spline See also: [al_calculate_spline] ### API: al_calculate_ribbon Calculates a ribbon given an array of points. The ribbon will go through all of the passed points. If `thickness <= 0`, then `num_segments` of points are required in the destination buffer, otherwise twice as many are needed. The destination and the points buffer should consist of regularly spaced doublets of floats, corresponding to x and y coordinates of the vertices. *Parameters:* * dest - Pointer to the destination buffer * dest_stride - Distance (in bytes) between starts of successive pairs of coordinates in the destination buffer * points - An array of pairs of coordinates for each point * points_stride - Distance (in bytes) between starts of successive pairs of coordinates in the points buffer * thickness - Thickness of the spline ribbon * num_segments - The number of points to calculate See also: [al_draw_ribbon], [al_calculate_arc], [al_calculate_spline] ### API: al_draw_ribbon Draws a ribbon given an array of points. The ribbon will go through all of the passed points. The points buffer should consist of regularly spaced doublets of floats, corresponding to x and y coordinates of the vertices. *Parameters:* * points - An array of coordinate pairs (x and y) for each point * points_stride - Distance (in bytes) between starts of successive pairs of coordinates in the points buffer * color - Color of the spline * thickness - Thickness of the spline, pass `<= 0` to draw hairline spline * num_segments - The number of segments See also: [al_calculate_ribbon] ## Low level drawing routines Low level drawing routines allow for more advanced usage of the addon, allowing you to pass arbitrary sequences of vertices to draw to the screen. These routines also support using textures on the primitives with the following restrictions: For maximum portability, you should only use textures that have dimensions that are a power of two, as not every videocard supports textures of different sizes completely. This warning is relaxed, however, if the texture coordinates never exit the boundaries of a single bitmap (i.e. you are not having the texture repeat/tile). As long as that is the case, any texture can be used safely. Sub-bitmaps work as textures, but cannot be tiled. Some platforms also dictate a minimum texture size, which means that textures smaller than that size will not tile properly. The minimum size that will work on all platforms is 32 by 32. A note about pixel coordinates. In OpenGL the texture coordinate (0, 0) refers to the top left corner of the pixel. This confuses some drivers, because due to rounding errors the actual pixel sampled might be the pixel to the top and/or left of the (0, 0) pixel. To make this error less likely it is advisable to offset the texture coordinates you pass to the al_draw_prim by (0.5, 0.5) if you need precise pixel control. E.g. to refer to pixel (5, 10) you'd set the u and v to 5.5 and 10.5 respectively. See also: [Pixel-precise output] ### API: al_draw_prim Draws a subset of the passed vertex array. *Parameters:* * texture - Texture to use, pass NULL to use only color shaded primitves * vtxs - Pointer to an array of vertices * decl - Pointer to a [vertex declaration][al_create_vertex_decl]. If set to NULL, the vertices are assumed to be of the [ALLEGRO_VERTEX] type * start - Start index of the subset of the vertex array to draw * end - One past the last index of the subset of the vertex array to draw * type - A member of the [ALLEGRO_PRIM_TYPE] enumeration, specifying what kind of primitive to draw *Returns:* Number of primitives drawn For example to draw a textured triangle you could use: ~~~~c ALLEGRO_COLOR white = al_map_rgb_f(1, 1, 1); ALLEGRO_VERTEX v[] = { {.x = 128, .y = 0, .z = 0, .color = white, .u = 128, .v = 0}, {.x = 0, .y = 256, .z = 0, .color = white, .u = 0, .v = 256}, {.x = 256, .y = 256, .z = 0, .color = white, .u = 256, .v = 256}}; al_draw_prim(v, NULL, texture, 0, 3, ALLEGRO_PRIM_TRIANGLE_LIST); ~~~~ See also: [ALLEGRO_VERTEX], [ALLEGRO_PRIM_TYPE], [ALLEGRO_VERTEX_DECL], [al_draw_indexed_prim] ### API: al_draw_indexed_prim Draws a subset of the passed vertex array. This function uses an index array to specify which vertices to use. *Parameters:* * texture - Texture to use, pass NULL to use only color shaded primitves * vtxs - Pointer to an array of vertices * decl - Pointer to a vertex declaration. If set to NULL, the vtxs are assumed to be of the ALLEGRO_VERTEX type * indices - An array of indices into the vertex array * num_vtx - Number of indices from the indices array you want to draw * type - A member of the [ALLEGRO_PRIM_TYPE] enumeration, specifying what kind of primitive to draw *Returns:* Number of primitives drawn See also: [ALLEGRO_VERTEX], [ALLEGRO_PRIM_TYPE], [ALLEGRO_VERTEX_DECL], [al_draw_prim] ### API: al_draw_vertex_buffer Draws a subset of the passed vertex buffer. The vertex buffer must not be locked. Additionally, to draw onto memory bitmaps or with memory bitmap textures the vertex buffer must support reading (i.e. it must be created with the `ALLEGRO_PRIM_BUFFER_READWRITE`). *Parameters:* * vertex_buffer - Vertex buffer to draw * texture - Texture to use, pass NULL to use only color shaded primitves * start - Start index of the subset of the vertex buffer to draw * end - One past the last index of the subset of the vertex buffer to draw * type - A member of the [ALLEGRO_PRIM_TYPE] enumeration, specifying what kind of primitive to draw *Returns:* Number of primitives drawn Since: 5.1.3 See also: [ALLEGRO_VERTEX_BUFFER], [ALLEGRO_PRIM_TYPE] ### API: al_draw_indexed_buffer Draws a subset of the passed vertex buffer. This function uses an index buffer to specify which vertices to use. Both buffers must not be locked. Additionally, to draw onto memory bitmaps or with memory bitmap textures both buffers must support reading (i.e. they must be created with the `ALLEGRO_PRIM_BUFFER_READWRITE`). *Parameters:* * vertex_buffer - Vertex buffer to draw * texture - Texture to use, pass NULL to use only color shaded primitves * index_buffer - Index buffer to use * start - Start index of the subset of the index buffer to draw * end - One past the last index of the subset of the index buffer to draw * type - A member of the [ALLEGRO_PRIM_TYPE] enumeration, specifying what kind of primitive to draw. Note that ALLEGRO_PRIM_LINE_LOOP and ALLEGRO_PRIM_POINT_LIST are not supported. *Returns:* Number of primitives drawn Since: 5.1.8 See also: [ALLEGRO_VERTEX_BUFFER], [ALLEGRO_INDEX_BUFFER], [ALLEGRO_PRIM_TYPE] ### API: al_draw_soft_triangle Draws a triangle using the software rasterizer and user supplied pixel functions. For help in understanding what these functions do, see the implementation of the various shading routines in addons/primitives/tri_soft.c. The triangle is drawn in two segments, from top to bottom. The segments are deliniated by the vertically middle vertex of the triangle. One of the two segments may be absent if two vertices are horizontally collinear. *Parameters:* * v1, v2, v3 - The three vertices of the triangle * state - A pointer to a user supplied struct, this struct will be passed to all the pixel functions * init - Called once per call before any drawing is done. The three points passed to it may be altered by clipping. * first - Called twice per call, once per triangle segment. It is passed 4 parameters, the first two are the coordinates of the initial pixel drawn in the segment. The second two are the left minor and the left major steps, respectively. They represent the sizes of two steps taken by the rasterizer as it walks on the left side of the triangle. From then on, each step will either be classified as a minor or a major step, corresponding to the above values. * step - Called once per scanline. The last parameter is set to 1 if the step is a minor step, and 0 if it is a major step. * draw - Called once per scanline. The function is expected to draw the scanline starting with a point specified by the first two parameters (corresponding to x and y values) going to the right until it reaches the value of the third parameter (the x value of the end point). All coordinates are inclusive. See also: [al_draw_triangle] ### API: al_draw_soft_line Draws a line using the software rasterizer and user supplied pixel functions. For help in understanding what these functions do, see the implementation of the various shading routines in addons/primitives/line_soft.c. The line is drawn top to bottom. *Parameters:* * v1, v2 - The two vertices of the line * state - A pointer to a user supplied struct, this struct will be passed to all the pixel functions * first - Called before drawing the first pixel of the line. It is passed the coordinates of this pixel, as well as the two vertices above. The passed vertices may have been altered by clipping. * step - Called once per pixel. The second parameter is set to 1 if the step is a minor step, and 0 if this step is a major step. Minor steps are taken only either in x or y directions. Major steps are taken in both directions diagonally. In all cases, the absolute value of the change in coordinate is at most 1 in either direction. * draw - Called once per pixel. The function is expected to draw the pixel at the coordinates passed to it. See also: [al_draw_line] ## Custom vertex declaration routines ### API: al_create_vertex_decl Creates a vertex declaration, which describes a custom vertex format. *Parameters:* * elements - An array of [ALLEGRO_VERTEX_ELEMENT] structures. * stride - Size of the custom vertex structure *Returns:* Newly created vertex declaration. See also: [ALLEGRO_VERTEX_ELEMENT], [ALLEGRO_VERTEX_DECL], [al_destroy_vertex_decl] ### API: al_destroy_vertex_decl Destroys a vertex declaration. *Parameters:* * decl - Vertex declaration to destroy See also: [ALLEGRO_VERTEX_ELEMENT], [ALLEGRO_VERTEX_DECL], [al_create_vertex_decl] ## Vertex buffer routines ### API: al_create_vertex_buffer Creates a vertex buffer. Can return NULL if the buffer could not be created (e.g. the system only supports write-only buffers). > *Note:* > > This is an advanced feature, often unsupported on lower-end video cards. > Be extra mindful of this function failing and make arrangements for > fallback drawing functionality or a nice error message for users with > such lower-end cards. *Parameters:* * decl - Vertex type that this buffer will hold. NULL implies that this buffer will hold [ALLEGRO_VERTEX] vertices * initial_data - Memory buffer to copy from to initialize the vertex buffer. Can be `NULL`, in which case the buffer is uninitialized. * num_vertices - Number of vertices the buffer will hold * flags - A combination of the [ALLEGRO_PRIM_BUFFER_FLAGS] flags specifying how this buffer will be created. Passing 0 is the same as passing `ALLEGRO_PRIM_BUFFER_STATIC`. Since: 5.1.3 See also: [ALLEGRO_VERTEX_BUFFER], [al_destroy_vertex_buffer] ### API: al_destroy_vertex_buffer Destroys a vertex buffer. Does nothing if passed NULL. Since: 5.1.3 See also: [ALLEGRO_VERTEX_BUFFER], [al_create_vertex_buffer] ### API: al_lock_vertex_buffer Locks a vertex buffer so you can access its data. Will return NULL if the parameters are invalid, if reading is requested from a write only buffer, or if the buffer is already locked. *Parameters:* * buffer - Vertex buffer to lock * offset - Vertex index of the start of the locked range * length - How many vertices to lock * flags - ALLEGRO_LOCK_READONLY, ALLEGRO_LOCK_WRITEONLY or ALLEGRO_LOCK_READWRITE Since: 5.1.3 See also: [ALLEGRO_VERTEX_BUFFER], [al_unlock_vertex_buffer] ### API: al_unlock_vertex_buffer Unlocks a previously locked vertex buffer. Since: 5.1.3 See also: [ALLEGRO_VERTEX_BUFFER], [al_lock_vertex_buffer] ### API: al_get_vertex_buffer_size Returns the size of the vertex buffer Since: 5.1.8 See also: [ALLEGRO_VERTEX_BUFFER] ## Index buffer routines ### API: al_create_index_buffer Creates a index buffer. Can return NULL if the buffer could not be created (e.g. the system only supports write-only buffers). > *Note:* > > This is an advanced feature, often unsupported on lower-end video cards. > Be extra mindful of this function failing and make arrangements for > fallback drawing functionality or a nice error message for users with > such lower-end cards. *Parameters:* * index_size - Size of the index in bytes. Supported sizes are 2 for short integers and 4 for integers * initial_data - Memory buffer to copy from to initialize the index buffer. Can be `NULL`, in which case the buffer is uninitialized. * num_indices - Number of indices the buffer will hold * flags - A combination of the [ALLEGRO_PRIM_BUFFER_FLAGS] flags specifying how this buffer will be created. Passing 0 is the same as passing `ALLEGRO_PRIM_BUFFER_STATIC`. Since: 5.1.8 See also: [ALLEGRO_INDEX_BUFFER], [al_destroy_index_buffer] ### API: al_destroy_index_buffer Destroys a index buffer. Does nothing if passed NULL. Since: 5.1.8 See also: [ALLEGRO_INDEX_BUFFER], [al_create_index_buffer] ### API: al_lock_index_buffer Locks a index buffer so you can access its data. Will return NULL if the parameters are invalid, if reading is requested from a write only buffer and if the buffer is already locked. *Parameters:* * buffer - Index buffer to lock * offset - Element index of the start of the locked range * length - How many indices to lock * flags - ALLEGRO_LOCK_READONLY, ALLEGRO_LOCK_WRITEONLY or ALLEGRO_LOCK_READWRITE Since: 5.1.8 See also: [ALLEGRO_INDEX_BUFFER], [al_unlock_index_buffer] ### API: al_unlock_index_buffer Unlocks a previously locked index buffer. Since: 5.1.8 See also: [ALLEGRO_INDEX_BUFFER], [al_lock_index_buffer] ### API: al_get_index_buffer_size Returns the size of the index buffer Since: 5.1.8 See also: [ALLEGRO_INDEX_BUFFER] ## Polygon routines ### API: al_draw_polyline Draw a series of line segments. * vertices - Interleaved array of (x, y) vertex coordinates * vertex_stride - the number of bytes between pairs of vertices (the stride) * vertex_count - Number of vertices in the array * join_style - Member of [ALLEGRO_LINE_JOIN] specifying how to render the joins between line segments * cap_style - Member of [ALLEGRO_LINE_CAP] specifying how to render the end caps * color - Color of the line * thickness - Thickness of the line, pass `<= 0` to draw hairline lines * miter_limit - Parameter for miter join style The stride is normally `2 * sizeof(float)` but may be more if the vertex coordinates are in an array of some structure type, e.g. ~~~~c struct VertexInfo { float x; float y; int id; }; void my_draw(struct VertexInfo verts[], int vertex_count, ALLEGRO_COLOR c) { al_draw_polyline((float *)verts, sizeof(VertexInfo), vertex_count, ALLEGRO_LINE_JOIN_NONE, ALLEGRO_LINE_CAP_NONE, c, 1.0, 1.0); } ~~~~ The stride may also be negative if the vertices are stored in reverse order. Since: 5.1.0 See also: [al_draw_polygon], [ALLEGRO_LINE_JOIN], [ALLEGRO_LINE_CAP] ### API: al_draw_polygon Draw an unfilled polygon. This is the same as passing `ALLEGRO_LINE_CAP_CLOSED` to [al_draw_polyline]. * vertex - Interleaved array of (x, y) vertex coordinates * vertex_count - Number of vertices in the array * join_style - Member of [ALLEGRO_LINE_JOIN] specifying how to render the joins between line segments * color - Color of the line * thickness - Thickness of the line, pass `<= 0` to draw hairline lines * miter_limit - Parameter for miter join style Since: 5.1.0 See also: [al_draw_filled_polygon], [al_draw_polyline], [ALLEGRO_LINE_JOIN] ### API: al_draw_filled_polygon Draw a filled, simple polygon. Simple means it does not have to be convex but must not be self-overlapping. * vertices - Interleaved array of (x, y) vertex coordinates * vertex_count - Number of vertices in the array * color - Color of the filled polygon When the y-axis is facing downwards (the usual), the coordinates must be ordered anti-clockwise. Since: 5.1.0 See also: [al_draw_polygon], [al_draw_filled_polygon_with_holes] ### API: al_draw_filled_polygon_with_holes Draws a filled simple polygon with zero or more other simple polygons subtracted from it - the holes. The holes cannot touch or intersect with the outline of the filled polygon. * vertices - Interleaved array of (x, y) vertex coordinates for each of the polygons, including holes. * vertex_counts - Number of vertices for each polygon. The number of vertices in the filled polygon is given by vertex_counts[0] and must be at least three. Subsequent elements indicate the number of vertices in each hole. The array must be terminated with an element with value zero. * color - Color of the filled polygon When the y-axis is facing downwards (the usual) the filled polygon coordinates must be ordered anti-clockwise. All hole vertices must use the opposite order (clockwise with y down). All hole vertices must be inside the main polygon and no hole may overlap the main polygon. For example: ~~~~c float vertices[] = { 0, 0, // filled polygon, upper left corner 0, 100, // filled polygon, lower left corner 100, 100, // filled polygon, lower right corner 100, 0, // filled polygon, upper right corner 10, 10, // hole, upper left 90, 10, // hole, upper right 90, 90 // hole, lower right }; int vertex_counts[] = { 4, // number of vertices for filled polygon 3, // number of vertices for hole 0 // terminator }; ~~~~ There are 7 vertices: four for an outer square from (0, 0) to (100, 100) in anti-clockwise order, and three more for an inner triangle in clockwise order. The outer main polygon uses vertices 0 to 3 (inclusive) and the hole uses vertices 4 to 6 (inclusive). Since: 5.1.0 See also: [al_draw_filled_polygon], [al_draw_filled_polygon_with_holes], [al_triangulate_polygon] ### API: al_triangulate_polygon Divides a simple polygon into triangles, with zero or more other simple polygons subtracted from it - the holes. The holes cannot touch or intersect with the outline of the main polygon. Simple means the polygon does not have to be convex but must not be self-overlapping. *Parameters:* * vertices - Interleaved array of (x, y) vertex coordinates for each of the polygons, including holes. * vertex_stride - distance (in bytes) between successive pairs of vertices in the array. * vertex_counts - Number of vertices for each polygon. The number of vertices in the main polygon is given by vertex_counts[0] and must be at least three. Subsequent elements indicate the number of vertices in each hole. The array must be terminated with an element with value zero. * emit_triangle - a function to be called for every set of three points that form a triangle. The function is passed the indices of the points in `vertices` and `userdata`. * userdata - arbitrary data to be passed to emit_triangle. Since: 5.1.0 See also: [al_draw_filled_polygon_with_holes] ## Structures and types ### API: ALLEGRO_VERTEX Defines the generic vertex type, with a 3D position, color and texture coordinates for a single texture. Note that at this time, the software driver for this addon cannot render 3D primitives. If you want a 2D only primitive, set z to 0. Note that you must initialize all members of this struct when you're using it. One exception to this rule are the u and v variables which can be left uninitialized when you are not using textures. *Fields:* * x, y, z - Position of the vertex (float) * u, v - Texture coordinates measured in pixels (float) * color - [ALLEGRO_COLOR] structure, storing the color of the vertex See also: [ALLEGRO_PRIM_ATTR] ### API: ALLEGRO_VERTEX_DECL A vertex declaration. This opaque structure is responsible for describing the format and layout of a user defined custom vertex. It is created and destroyed by specialized functions. See also: [al_create_vertex_decl], [al_destroy_vertex_decl], [ALLEGRO_VERTEX_ELEMENT] ### API: ALLEGRO_VERTEX_ELEMENT A small structure describing a certain element of a vertex. E.g. the position of the vertex, or its color. These structures are used by the [al_create_vertex_decl] function to create the vertex declaration. For that they generally occur in an array. The last element of such an array should have the attribute field equal to 0, to signify that it is the end of the array. Here is an example code that would create a declaration describing the [ALLEGRO_VERTEX] structure (passing this as vertex declaration to al_draw_prim would be identical to passing NULL): ~~~~c /* On compilers without the offsetof keyword you need to obtain the * offset with sizeof and make sure to account for packing. */ ALLEGRO_VERTEX_ELEMENT elems[] = { {ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_3, offsetof(ALLEGRO_VERTEX, x)}, {ALLEGRO_PRIM_TEX_COORD_PIXEL, ALLEGRO_PRIM_FLOAT_2, offsetof(ALLEGRO_VERTEX, u)}, {ALLEGRO_PRIM_COLOR_ATTR, 0, offsetof(ALLEGRO_VERTEX, color)}, {0, 0, 0} }; ALLEGRO_VERTEX_DECL* decl = al_create_vertex_decl(elems, sizeof(ALLEGRO_VERTEX)); ~~~~ *Fields:* * attribute - A member of the [ALLEGRO_PRIM_ATTR] enumeration, specifying what this attribute signifies * storage - A member of the [ALLEGRO_PRIM_STORAGE] enumeration, specifying how this attribute is stored * offset - Offset in bytes from the beginning of the custom vertex structure. The C function offsetof is very useful here. See also: [al_create_vertex_decl], [ALLEGRO_VERTEX_DECL], [ALLEGRO_PRIM_ATTR], [ALLEGRO_PRIM_STORAGE] ### API: ALLEGRO_PRIM_TYPE Enumerates the types of primitives this addon can draw. * ALLEGRO_PRIM_POINT_LIST - A list of points, each vertex defines a point * ALLEGRO_PRIM_LINE_LIST - A list of lines, sequential pairs of vertices define disjointed lines * ALLEGRO_PRIM_LINE_STRIP - A strip of lines, sequential vertices define a strip of lines * ALLEGRO_PRIM_LINE_LOOP - Like a line strip, except at the end the first and the last vertices are also connected by a line * ALLEGRO_PRIM_TRIANGLE_LIST - A list of triangles, sequential triplets of vertices define disjointed triangles * ALLEGRO_PRIM_TRIANGLE_STRIP - A strip of triangles, sequential vertices define a strip of triangles * ALLEGRO_PRIM_TRIANGLE_FAN - A fan of triangles, all triangles share the first vertex ### API: ALLEGRO_PRIM_ATTR Enumerates the types of vertex attributes that a custom vertex may have. * ALLEGRO_PRIM_POSITION - Position information, can be stored only in ALLEGRO_PRIM_SHORT_2, ALLEGRO_PRIM_FLOAT_2 and ALLEGRO_PRIM_FLOAT_3. * ALLEGRO_PRIM_COLOR_ATTR - Color information, stored in an [ALLEGRO_COLOR]. The storage field of ALLEGRO_VERTEX_ELEMENT is ignored * ALLEGRO_PRIM_TEX_COORD - Texture coordinate information, can be stored only in ALLEGRO_PRIM_FLOAT_2 and ALLEGRO_PRIM_SHORT_2. These coordinates are normalized by the width and height of the texture, meaning that the bottom-right corner has texture coordinates of (1, 1). * ALLEGRO_PRIM_TEX_COORD_PIXEL - Texture coordinate information, can be stored only in ALLEGRO_PRIM_FLOAT_2 and ALLEGRO_PRIM_SHORT_2. These coordinates are measured in pixels. * ALLEGRO_PRIM_USER_ATTR - A user specified attribute. You can use any storage for this attribute. You may have at most ALLEGRO_PRIM_MAX_USER_ATTR (currently 10) of these that you can specify by adding an index to the value of ALLEGRO_PRIM_USER_ATTR, e.g. the first user attribute is `ALLEGRO_PRIM_USER_ATTR + 0`, the second is `ALLEGRO_PRIM_USER_ATTR + 1` and so on. To access these custom attributes from GLSL shaders you need to declare attributes that follow this nomenclature: `al_user_attr_#` where # is the index of the attribute. For example to have a position and a normal vector for each vertex you could declare it like this: ~~~~c ALLEGRO_VERTEX_ELEMENT elements[3] = { {ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_3, 0}, {ALLEGRO_PRIM_USER_ATTR + 0, ALLEGRO_PRIM_FLOAT_3, 12}, {0, 0, 0}}; ~~~~ And then in your vertex shader access it like this: ~~~~c attribute vec3 al_pos; // ALLEGRO_PRIM_POSITION attribute vec3 al_user_attr_0; // ALLEGRO_PRIM_USER_ATTR + 0 varying float light; const vec3 light_direction = vec3(0, 0, 1); void main() { light = dot(al_user_attr_0, light_direction); gl_Position = al_pos; } ~~~~ To access these custom attributes from HLSL you need to declare a parameter with the following semantics: `TEXCOORD{# + 2}` where # is the index of the attribute. E.g. the first attribute can be accessed via `TEXCOORD2`, second via `TEXCOORD3` and so on. Since: 5.1.6 See also: [ALLEGRO_VERTEX_DECL], [ALLEGRO_PRIM_STORAGE], [al_attach_shader_source] ### API: ALLEGRO_PRIM_STORAGE Enumerates the types of storage an attribute of a custom vertex may be stored in. Many of these can only be used for ALLEGRO_PRIM_USER_ATTR attributes and can only be accessed via shaders. Usually no matter what the storage is specified the attribute gets converted to single precision floating point when the shader is run. Despite that, it may be advantageous to use more dense storage formats (e.g. ALLEGRO_PRIM_NORMALIZED_UBYTE_4 instead of ALLEGRO_PRIM_FLOAT_4) when bandwidth (amount of memory sent to the GPU) is an issue but precision is not. * ALLEGRO_PRIM_FLOAT_1 - A single float Since: 5.1.6 * ALLEGRO_PRIM_FLOAT_2 - A doublet of floats * ALLEGRO_PRIM_FLOAT_3 - A triplet of floats * ALLEGRO_PRIM_FLOAT_4 - A quad of floats Since: 5.1.6 * ALLEGRO_PRIM_SHORT_2 - A doublet of shorts * ALLEGRO_PRIM_SHORT_4 - A quad of shorts Since: 5.1.6 * ALLEGRO_PRIM_UBYTE_4 - A quad of unsigned bytes Since: 5.1.6 * ALLEGRO_PRIM_NORMALIZED_SHORT_2 - A doublet of shorts. Before being sent to the shader, each component is divided by 32767. Each component of the resultant float doublet ranges between -1.0 and 1.0 Since: 5.1.6 * ALLEGRO_PRIM_NORMALIZED_SHORT_4 - A quad of shorts. Before being sent to the shader, each component is divided by 32767. Each component of the resultant float quad ranges between -1.0 and 1.0 Since: 5.1.6 * ALLEGRO_PRIM_NORMALIZED_UBYTE_4 - A quad of unsigned bytes. Before being sent to the shader, each component is divided by 255. Each component of the resultant float quad ranges between 0.0 and 1.0 Since: 5.1.6 * ALLEGRO_PRIM_NORMALIZED_USHORT_2 - A doublet of unsigned shorts. Before being sent to the shader, each component is divided by 65535. Each component of the resultant float doublet ranges between 0.0 and 1.0 Since: 5.1.6 * ALLEGRO_PRIM_NORMALIZED_USHORT_4 - A quad of unsigned shorts. Before being sent to the shader, each component is divided by 65535. Each component of the resultant float quad ranges between 0.0 and 1.0 Since: 5.1.6 * ALLEGRO_PRIM_HALF_FLOAT_2 - A doublet of half-precision floats. Note that this storage format is not supported on all platforms. [al_create_vertex_decl] will return NULL if you use it on those platforms Since: 5.1.6 * ALLEGRO_PRIM_HALF_FLOAT_4 - A quad of half-precision floats. Note that this storage format is not supported on all platforms. [al_create_vertex_decl] will return NULL if you use it on those platforms. Since: 5.1.6 See also: [ALLEGRO_PRIM_ATTR] ### API: ALLEGRO_VERTEX_CACHE_SIZE Defines the size of the transformation vertex cache for the software renderer. If you pass less than this many vertices to the primitive rendering functions you will get a speed boost. This also defines the size of the cache vertex buffer, used for the high-level primitives. This corresponds to the maximum number of line segments that will be used to form them. ### API: ALLEGRO_PRIM_QUALITY Controls the quality of the approximation of curved primitives (e.g. circles). Curved primitives are drawn by approximating them with a sequence of line segments. By default, this roughly corresponds to error of less than half of a pixel. ### API: ALLEGRO_LINE_JOIN * ALLEGRO_LINE_JOIN_NONE * ALLEGRO_LINE_JOIN_BEVEL * ALLEGRO_LINE_JOIN_ROUND * ALLEGRO_LINE_JOIN_MITER ![*ALLEGRO_LINE_JOIN styles*](images/LINE_JOIN.png) See the picture for the difference. The maximum miter length (relative to the line width) can be specified as parameter to the polygon functions. Since: 5.1.0 See also: [al_draw_polygon] ### API: ALLEGRO_LINE_CAP * ALLEGRO_LINE_CAP_NONE * ALLEGRO_LINE_CAP_SQUARE * ALLEGRO_LINE_CAP_ROUND * ALLEGRO_LINE_CAP_TRIANGLE * ALLEGRO_LINE_CAP_CLOSED ![*ALLEGRO_LINE_CAP styles*](images/LINE_CAP.png) See the picture for the difference. ALLEGRO_LINE_CAP_CLOSED is different from the others - it causes the polygon to have no caps. (And the [ALLEGRO_LINE_JOIN] style will determine how the vertex looks.) Since: 5.1.0 See also: [al_draw_polygon] ### API: ALLEGRO_VERTEX_BUFFER A GPU vertex buffer that you can use to store vertices on the GPU instead of uploading them afresh during every drawing operation. Since: 5.1.3 See also: [al_create_vertex_buffer], [al_destroy_vertex_buffer] ### API: ALLEGRO_INDEX_BUFFER A GPU index buffer that you can use to store indices of vertices in a vertex buffer on the GPU instead of uploading them afresh during every drawing operation. Since: 5.1.8 See also: [al_create_index_buffer], [al_destroy_index_buffer] ### API: ALLEGRO_PRIM_BUFFER_FLAGS Flags to specify how to create a vertex or an index buffer. * ALLEGRO_PRIM_BUFFER_STREAM - Hints to the driver that the buffer is written to often, but used only a few times per frame * ALLEGRO_PRIM_BUFFER_STATIC - Hints to the driver that the buffer is written to once and is used often * ALLEGRO_PRIM_BUFFER_DYNAMIC - Hints to the driver that the buffer is written to often and is used often * ALLEGRO_PRIM_BUFFER_READWRITE - Specifies that you want to be able read from this buffer. By default this is disabled for performance. Some platforms (like OpenGL ES) do not support reading from vertex buffers, so if you pass this flag to `al_create_vertex_buffer` or `al_create_index_buffer` the call will fail. Since: 5.1.3 See also: [al_create_vertex_buffer], [al_create_index_buffer] allegro5-5.2.10.1/docs/src/refman/shader.txt000066400000000000000000000321361473414355200204630ustar00rootroot00000000000000# Shader routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: ALLEGRO_SHADER An [ALLEGRO_SHADER] is a program that runs on the GPU. It combines both a vertex and a pixel shader. (In OpenGL terms, an [ALLEGRO_SHADER] is actually a *program* which has one or more *shaders* attached. This can be confusing.) The source code for the underlying vertex or pixel shader can be provided either as GLSL or HLSL, depending on the value of [ALLEGRO_SHADER_PLATFORM] used when creating it. Since: 5.1.0 ## API: ALLEGRO_SHADER_TYPE Used with [al_attach_shader_source] and [al_attach_shader_source_file] to specify how to interpret the attached source. ALLEGRO_VERTEX_SHADER : A vertex shader is executed for each vertex it is used with. The program will output exactly one vertex at a time. When Allegro's graphics are being used then in addition to all vertices of primitives from the primitives addon, each drawn bitmap also consists of four vertices. ALLEGRO_PIXEL_SHADER : A pixel shader is executed for each pixel it is used with. The program will output exactly one pixel at a time - either in the backbuffer or in the current target bitmap. With Allegro's builtin graphics this means the shader is for example called for each destination pixel of the output of an [al_draw_bitmap] call. A more accurate term for pixel shader would be fragment shader since one final pixel in the target bitmap is not necessarily composed of only a single output but of multiple fragments (for example when multi-sampling is being used). Since: 5.1.0 ## API: ALLEGRO_SHADER_PLATFORM The underlying platform which the [ALLEGRO_SHADER] is built on top of, which dictates the language used to program the shader. * ALLEGRO_SHADER_AUTO - Pick a platform automatically given the current display flags. * ALLEGRO_SHADER_GLSL - OpenGL Shading Language * ALLEGRO_SHADER_HLSL - High Level Shader Language (for Direct3D) * ALLEGRO_SHADER_AUTO_MINIMAL - Like ALLEGRO_SHADER_AUTO, but pick a more minimal implementation that may not support alpha testing. * ALLEGRO_SHADER_GLSL_MINIMAL - Minimal GLSL shader. * ALLEGRO_SHADER_HLSL_MINIMAL - Minimal HLSL shader. * ALLEGRO_SHADER_HLSL_SM_3_0 - HLSL shader using shader model 3_0. Since: 5.1.0 ## API: al_create_shader Create a shader object. The platform argument is one of the [ALLEGRO_SHADER_PLATFORM] values, and specifies the type of shader object to create, and which language is used to program the shader. The shader platform must be compatible with the type of display that you will use the shader with. For example, you cannot create and use a HLSL shader on an OpenGL display, nor a GLSL shader on a Direct3D display. The ALLEGRO_SHADER_AUTO value automatically chooses the appropriate platform for the display currently targeted by the calling thread; there must be such a display. It will create a GLSL shader for an OpenGL display, and a HLSL shader for a Direct3D display. Returns the shader object on success. Otherwise, returns NULL. Since: 5.1.0 See also: [al_attach_shader_source], [al_attach_shader_source_file], [al_build_shader], [al_use_shader], [al_destroy_shader], [al_get_shader_platform] ## API: al_attach_shader_source Attaches the shader's source code to the shader object and compiles it. Passing NULL deletes the underlying (OpenGL or DirectX) shader. See also [al_attach_shader_source_file] if you prefer to obtain your shader source from an external file. If you do not use ALLEGRO_PROGRAMMABLE_PIPELINE Allegro's graphics functions will not use any shader specific functions themselves. In case of a system with no fixed function pipeline (like OpenGL ES 2 or OpenGL 3 or 4) this means Allegro's drawing functions cannot be used. TODO: Is ALLEGRO_PROGRAMMABLE_PIPELINE set automatically in this case? When ALLEGRO_PROGRAMMABLE_PIPELINE is used the following shader uniforms are provided by Allegro and can be accessed in your shaders: al_projview_matrix : matrix for Allegro's orthographic projection multiplied by the [al_use_transform] matrix. The type is `mat4` in GLSL, and `float4x4` in HLSL. al_use_tex : whether or not to use the bound texture. The type is `bool` in both GLSL and HLSL. al_tex : the texture if one is bound. The type is `sampler2D` in GLSL and `texture` in HLSL. al_use_tex_matrix : whether or not to use a texture matrix (used by the primitives addon). The type is `bool` in both GLSL and HLSL. al_tex_matrix : the texture matrix (used by the primitives addon). Your shader should multiply the texture coordinates by this matrix. The type is `mat4` in GLSL, and `float4x4` in HLSL. With GLSL alpha testing is done in the shader and uses these additional uniforms: al_alpha_test : Whether to do any alpha testing. If false, the shader should render the pixel, otherwise it should interpret the values of `al_alpha_func` and `al_alpha_test_val`. al_alpha_func : The alpha testing function used. One of the [ALLEGRO_RENDER_FUNCTION] values. The default is ALLEGRO_RENDER_ALWAYS which means all pixels (even completely transparent ones) are rendered. The type is `int`. See [ALLEGRO_RENDER_STATE]. al_alpha_test_val : If alpha testing is not ALLEGRO_RENDER_NEVER or ALLEGRO_RENDER_ALWAYS the alpha value to compare to for alpha testing. The type is `float`. For GLSL shaders the vertex attributes are passed using the following variables: al_pos : vertex position attribute. Type is `vec4`. al_texcoord : vertex texture coordinate attribute. Type is `vec2`. al_color : vertex color attribute. Type is `vec4`. al_user_attr_0 : The vertex attribute declared as ALLEGRO_PRIM_USER_ATTR al_user_attr_1, ..., al_user_attr_9 : The vertex attribute declared as ALLEGRO_PRIM_USER_ATTR + X where X is an integer from 1 to 9 For HLSL shaders the vertex attributes are passed using the following semantics: POSITION0 : vertex position attribute. Type is `float4`. TEXCOORD0 : vertex texture coordinate attribute. Type is `float2`. TEXCOORD1 : vertex color attribute. Type is `float4`. Also, each shader variable has a corresponding macro name that can be used when defining the shaders using string literals. Don't use these macros with the other shader functions as that will lead to undefined behavior. * ALLEGRO_SHADER_VAR_PROJVIEW_MATRIX for "al_projview_matrix" * ALLEGRO_SHADER_VAR_POS for "al_pos" * ALLEGRO_SHADER_VAR_COLOR for "al_color" * ALLEGRO_SHADER_VAR_TEXCOORD for "al_texcoord" * ALLEGRO_SHADER_VAR_USE_TEX for "al_use_tex" * ALLEGRO_SHADER_VAR_TEX for "al_tex" * ALLEGRO_SHADER_VAR_USE_TEX_MATRIX for "al_use_tex_matrix" * ALLEGRO_SHADER_VAR_TEX_MATRIX for "al_tex_matrix" * ALLEGRO_SHADER_VAR_ALPHA_FUNCTION for "al_alpha_func" * ALLEGRO_SHADER_VAR_ALPHA_TEST_VALUE for "al_alpha_test_val" Examine the output of [al_get_default_shader_source] for an example of how to use the above uniforms and attributes. Returns true on success and false on error, in which case the error log is updated. The error log can be retrieved with [al_get_shader_log]. Since: 5.1.0 See also: [al_attach_shader_source_file], [al_build_shader], [al_get_default_shader_source], [al_get_shader_log], [ALLEGRO_PRIM_ATTR] ## API: al_attach_shader_source_file Like [al_attach_shader_source] but reads the source code for the shader from the named file. Returns true on success and false on error, in which case the error log is updated. The error log can be retrieved with [al_get_shader_log]. Since: 5.1.0 See also: [al_attach_shader_source], [al_build_shader], [al_get_shader_log] ## API: al_build_shader This is required before the shader can be used with [al_use_shader]. It should be called after successfully attaching the pixel and/or vertex shaders with [al_attach_shader_source] or [al_attach_shader_source_file]. Returns true on success and false on error, in which case the error log is updated. The error log can be retrieved with [al_get_shader_log]. > *Note:* If you are using the ALLEGRO_PROGRAMMABLE_PIPELINE flag, then you must specify both a pixel and a vertex shader sources for anything to be rendered. Since: 5.1.6 See also: [al_use_shader], [al_get_shader_log] ## API: al_get_shader_log Return a read-only string containing the information log for a shader program. The log is updated by certain functions, such as [al_attach_shader_source] or [al_build_shader] when there is an error. This function never returns NULL. Since: 5.1.0 See also: [al_attach_shader_source], [al_attach_shader_source_file], [al_build_shader] ## API: al_get_shader_platform Returns the platform the shader was created with (either ALLEGRO_SHADER_HLSL or ALLEGRO_SHADER_GLSL). Since: 5.1.6 See also: [al_create_shader] ## API: al_use_shader Uses the shader for subsequent drawing operations on the current target bitmap. Pass NULL to stop using any shader on the current target bitmap. Returns true on success. Otherwise returns false, e.g. because the shader is incompatible with the target bitmap. Since: 5.1.6 See also: [al_destroy_shader], [al_set_shader_sampler], [al_set_shader_matrix], [al_set_shader_int], [al_set_shader_float], [al_set_shader_bool], [al_set_shader_int_vector], [al_set_shader_float_vector], [al_get_current_shader] ## API: al_get_current_shader Return the shader of the target bitmap, or NULL if one isn't being used. Since: 5.2.9 See also: [al_use_shader] ## API: al_destroy_shader Destroy a shader. Any bitmaps which currently use the shader will implicitly stop using the shader. In multi-threaded programs, be careful that no such bitmaps are being accessed by other threads at the time. As a convenience, if the target bitmap of the calling thread is using the shader then the shader is implicitly unused before being destroyed. This function does nothing if the shader argument is NULL. Since: 5.1.0 See also: [al_create_shader] ## API: al_set_shader_sampler Sets a texture sampler uniform and texture unit of the current target bitmap's shader. The given bitmap must be a video bitmap. Different samplers should use different units. The bitmap passed to Allegro's drawing functions uses the 0th unit, so if you're planning on using the `al_tex` variable in your pixel shader as well as another sampler, set the other sampler to use a unit different from 0. With the primitives addon, it is possible to free up the 0th unit by passing `NULL` as the texture argument to the relevant drawing functions. In this case, you may set a sampler to use the 0th unit and thus not use `al_tex` (the `al_use_tex` variable will be set to `false`). Returns true on success. Otherwise returns false, e.g. if the uniform by that name does not exist in the shader. Since: 5.1.0 See also: [al_use_shader] ## API: al_set_shader_matrix Sets a matrix uniform of the current target bitmap's shader. Returns true on success. Otherwise returns false, e.g. if the uniform by that name does not exist in the shader. Since: 5.1.0 See also: [al_use_shader] ## API: al_set_shader_int Sets an integer uniform of the current target bitmap's shader. Returns true on success. Otherwise returns false, e.g. if the uniform by that name does not exist in the shader. Since: 5.1.0 See also: [al_use_shader] ## API: al_set_shader_float Sets a float uniform of the target bitmap's shader. Returns true on success. Otherwise returns false, e.g. if the uniform by that name does not exist in the shader. Since: 5.1.0 See also: [al_use_shader] ## API: al_set_shader_bool Sets a boolean uniform of the target bitmap's shader. Returns true on success. Otherwise returns false, e.g. if the uniform by that name does not exist in the shader. Since: 5.1.6 See also: [al_use_shader] ## API: al_set_shader_int_vector Sets an integer vector array uniform of the current target bitmap's shader. The 'num_components' parameter can take one of the values 1, 2, 3 or 4. If it is 1 then an array of 'num_elems' integer elements is added. Otherwise each added array element is assumed to be a vector with 2, 3 or 4 components in it. For example, if you have a GLSL uniform declared as `uniform ivec3 flowers[4]` or an HLSL uniform declared as `uniform int3 flowers[4]`, then you'd use this function from your code like so: ~~~~c int flowers[4][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {2, 5, 7} }; al_set_shader_int_vector("flowers", 3, (int*)flowers, 4); ~~~~ Returns true on success. Otherwise returns false, e.g. if the uniform by that name does not exist in the shader. Since: 5.1.0 See also: [al_set_shader_float_vector], [al_use_shader] ## API: al_set_shader_float_vector Same as [al_set_shader_int_vector] except all values are float instead of int. Since: 5.1.0 See also: [al_set_shader_int_vector], [al_use_shader] ## API: al_get_default_shader_source Returns a string containing the source code to Allegro's default vertex or pixel shader appropriate for the passed platform. The ALLEGRO_SHADER_AUTO value means GLSL is used if OpenGL is being used otherwise HLSL. ALLEGRO_SHADER_AUTO requires that there is a current display set on the calling thread. This function can return NULL if Allegro was built without support for shaders of the selected platform. Since: 5.1.6 See also: [al_attach_shader_source] allegro5-5.2.10.1/docs/src/refman/state.txt000066400000000000000000000052401473414355200203310ustar00rootroot00000000000000# State These functions are declared in the main Allegro header file: #include ## API: ALLEGRO_STATE Opaque type which is passed to [al_store_state]/[al_restore_state]. The various state kept internally by Allegro can be displayed like this: global active system driver current config per thread new bitmap params new display params active file interface errno current blending mode current display deferred drawing current target bitmap current transformation current projection transformation current clipping rectangle bitmap locking current shader In general, the only real global state is the active system driver. All other global state is per-thread, so if your application has multiple separate threads they never will interfere with each other. (Except if there are objects accessed by multiple threads of course. Usually you want to minimize that though and for the remaining cases use synchronization primitives described in the threads section or events described in the events section to control inter-thread communication.) ## API: ALLEGRO_STATE_FLAGS Flags which can be passed to [al_store_state]/[al_restore_state] as bit combinations. See [al_store_state] for the list of flags. ## API: al_restore_state Restores part of the state of the current thread from the given [ALLEGRO_STATE] object. See also: [al_store_state], [ALLEGRO_STATE_FLAGS] ## API: al_store_state Stores part of the state of the current thread in the given [ALLEGRO_STATE] object. The flags parameter can take any bit-combination of these flags: * ALLEGRO_STATE_NEW_DISPLAY_PARAMETERS - new_display_format, new_display_refresh_rate, new_display_flags * ALLEGRO_STATE_NEW_BITMAP_PARAMETERS - new_bitmap_format, new_bitmap_flags * ALLEGRO_STATE_DISPLAY - current_display * ALLEGRO_STATE_TARGET_BITMAP - target_bitmap * ALLEGRO_STATE_BLENDER - blender * ALLEGRO_STATE_TRANSFORM - current_transformation * ALLEGRO_STATE_PROJECTION_TRANSFORM - current_projection_transformation * ALLEGRO_STATE_NEW_FILE_INTERFACE - new_file_interface * ALLEGRO_STATE_BITMAP - same as ALLEGRO_STATE_NEW_BITMAP_PARAMETERS and ALLEGRO_STATE_TARGET_BITMAP * ALLEGRO_STATE_ALL - all of the above See also: [al_restore_state], [ALLEGRO_STATE] ## API: al_get_errno Some Allegro functions will set an error number as well as returning an error code. Call this function to retrieve the last error number set for the calling thread. ## API: al_set_errno Set the error number for the calling thread. allegro5-5.2.10.1/docs/src/refman/system.txt000066400000000000000000000254601473414355200205430ustar00rootroot00000000000000# System routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: al_install_system Initialize the Allegro system. No other Allegro functions can be called before this (with one or two exceptions). The version field should always be set to ALLEGRO_VERSION_INT. If atexit_ptr is non-NULL, and if hasn't been done already, [al_uninstall_system] will be registered as an atexit function. Returns true if Allegro was successfully initialized by this function call (or already was initialized previously), false if Allegro cannot be used. A common reason for this function to fail is when the version of Allegro you compiled your game against is not compatible with the version of the shared libraries that were found on the system. The version compatibility check works as follows. Let A = xa.ya.za.* be the version of Allegro you compiled with, and B = xb.yb.zb.* be the version of Allegro found in the system shared library. If you defined `ALLEGRO_UNSTABLE` before including Allegro headers, then version A is compatible with B only if xa.ya.za = xb.yb.zb. Otherwise, A is compatible with B only if xa.ya = xb.yb. See also: [al_init] ## API: al_init Like [al_install_system], but automatically passes in the version and uses the atexit function visible in the current binary. > Note: It is typically wrong to call al_init anywhere except the final game binary. In particular, do not call it inside a shared library unless you know what you're doing. In those cases, it is better to call al_install_system either with a `NULL` atexit_ptr, or with a pointer to atexit provided by the user of this shared library. See also: [al_install_system] ## API: al_uninstall_system Closes down the Allegro system. > Note: al_uninstall_system() can be called without a corresponding [al_install_system] call, e.g. from atexit(). ## API: al_is_system_installed Returns true if Allegro is initialized, otherwise returns false. ## API: al_get_allegro_version Returns the (compiled) version of the Allegro library, packed into a single integer as groups of 8 bits in the form `(major << 24) | (minor << 16) | (revision << 8) | release`. You can use code like this to extract them: ~~~~c uint32_t version = al_get_allegro_version(); int major = version >> 24; int minor = (version >> 16) & 255; int revision = (version >> 8) & 255; int release = version & 255; ~~~~ The `release` number is 0 for an unofficial version and 1 or greater for an official release. For example "5.0.2[1]" would be the (first) official 5.0.2 release while "5.0.2[0]" would be a compile of a version from the "5.0.2" branch before the official release. ## API: al_get_standard_path Gets a system path, depending on the `id` parameter. Some of these paths may be affected by the organization and application name, so be sure to set those before calling this function. The paths are not guaranteed to be unique (e.g., SETTINGS and DATA may be the same on some platforms), so you should be sure your filenames are unique if you need to avoid naming collisions. Also, a returned path may not actually exist on the file system. ALLEGRO_RESOURCES_PATH : If you bundle data in a location relative to your executable, then you should use this path to locate that data. On most platforms, this is the directory that contains the executable file. If called from an OS X app bundle, then this will point to the internal resource directory (/Contents/Resources). To maintain consistency, if you put your resources into a directory called "data" beneath the executable on some other platform (like Windows), then you should also create a directory called "data" under the OS X app bundle's resource folder. You should not try to write to this path, as it is very likely read-only. If you install your resources in some other system directory (e.g., in /usr/share or C:\\ProgramData), then you are responsible for keeping track of that yourself. ALLEGRO_TEMP_PATH : Path to the directory for temporary files. ALLEGRO_USER_HOME_PATH : This is the user's home directory. You should not normally write files into this directory directly, or create any sub folders in it, without explicit permission from the user. One practical application of this path would be to use it as the starting place of a file selector in a GUI. ALLEGRO_USER_DOCUMENTS_PATH : This location is easily accessible by the user, and is the place to store documents and files that the user might want to later open with an external program or transfer to another place. You should not save files here unless the user expects it, usually by explicit permission. ALLEGRO_USER_DATA_PATH : If your program saves any data that the user doesn't need to access externally, then you should place it here. This is generally the least intrusive place to store data. This path will usually not be present on the file system, so make sure to create it before writing to it. ALLEGRO_USER_SETTINGS_PATH : If you are saving configuration files (especially if the user may want to edit them outside of your program), then you should place them here. This path will usually not be present on the file system, so make sure to create it before writing to it. ALLEGRO_EXENAME_PATH : The full path to the executable. Returns NULL on failure. The returned path should be freed with [al_destroy_path]. See also: [al_set_app_name], [al_set_org_name], [al_destroy_path], [al_set_exe_name] ## API: al_set_exe_name This override the executable name used by [al_get_standard_path] for ALLEGRO_EXENAME_PATH and ALLEGRO_RESOURCES_PATH. One possibility where changing this can be useful is if you use the Python wrapper. Allegro would then by default think that the system's Python executable is the current executable - but you can set it to the .py file being executed instead. Since: 5.0.6, 5.1.0 See also: [al_get_standard_path] ## API: al_set_app_name Sets the global application name. The application name is used by [al_get_standard_path] to build the full path to an application's files. This function may be called before [al_init] or [al_install_system]. See also: [al_get_app_name], [al_set_org_name] ## API: al_set_org_name Sets the global organization name. The organization name is used by [al_get_standard_path] to build the full path to an application's files. This function may be called before [al_init] or [al_install_system]. See also: [al_get_org_name], [al_set_app_name] ## API: al_get_app_name Returns the global application name string. See also: [al_set_app_name] ## API: al_get_org_name Returns the global organization name string. See also: [al_set_org_name] ## API: al_get_system_config Returns the system configuration structure. The returned configuration should not be destroyed with [al_destroy_config]. This is mainly used for configuring Allegro and its addons. You may populate this configuration before Allegro is installed to control things like the logging levels and other features. Allegro will try to populate this configuration by loading a configuration file from a few different locations, in this order: - *Unix only:* /etc/allegro5rc - *Unix only:* $HOME/allegro5rc - *Unix only:* $HOME/.allegro5rc - allegro5.cfg next to the executable If multiple copies are found, then they are merged using [al_merge_config_into]. The contents of this file are documented inside a prototypical `allegro5.cfg` that you can find in the root directory of the source distributions of Allegro. They are also reproduced below. Note that Allegro will not look into that file unless you make a copy of it and place it next to your executable! ~~~~ini __ALLEGRO_5_CFG ~~~~ ## API: al_get_system_id Returns the platform that Allegro is running on. Since: 5.2.5 See also: [ALLEGRO_SYSTEM_ID] ## API: al_register_assert_handler Register a function to be called when an internal Allegro assertion fails. Pass NULL to reset to the default behaviour, which is to do whatever the standard `assert()` macro does. Since: 5.0.6, 5.1.0 ## API: al_register_trace_handler Register a callback which is called whenever Allegro writes something to its log files. The default logging to allegro.log is disabled while this callback is active. Pass NULL to revert to the default logging. This function may be called prior to al_install_system. See the example allegro5.cfg for documentation on how to configure the used debug channels, logging levels and trace format. Since: 5.1.5 ## API: al_get_cpu_count Returns the number of CPU cores that the system Allegro is running on has and which could be detected, or a negative number if detection failed. Even if a positive number is returned, it might be that it is not correct. For example, Allegro running on a virtual machine will return the amount of CPU's of the VM, and not that of the underlying system. Furthermore even if the number is correct, this only gives you information about the total CPU cores of the system Allegro runs on. The amount of cores available to your program may be less due to circumstances such as programs that are currently running. Therefore, it's best to use this for advisory purposes only. It is certainly a bad idea to make your program exclusive to systems for which this function returns a certain "desirable" number. This function may be called prior to [al_install_system] or [al_init]. Since: 5.1.12 ## API: al_get_ram_size Returns the size in MB of the random access memory that the system Allegro is running on has and which could be detected, or a negative number if detection failed. Even if a positive number is returned, it might be that it is not correct. For example, Allegro running on a virtual machine will return the amount of RAM of the VM, and not that of the underlying system. Furthermore even if the number is correct, this only gives you information about the total physical memory of the system Allegro runs on. The memory available to your program may be less or more than what this function returns due to circumstances such as virtual memory, and other programs that are currently running. Therefore, it's best to use this for advisory purposes only. It is certainly a bad idea to make your program exclusive to systems for which this function returns a certain "desirable" number. This function may be called prior to [al_install_system] or [al_init]. Since: 5.1.12 ## API: ALLEGRO_SYSTEM_ID The system Allegro is running on. * ALLEGRO_SYSTEM_ID_UNKNOWN - Unknown system. * ALLEGRO_SYSTEM_ID_XGLX - Xglx * ALLEGRO_SYSTEM_ID_WINDOWS - Windows * ALLEGRO_SYSTEM_ID_MACOSX - macOS * ALLEGRO_SYSTEM_ID_ANDROID - Android * ALLEGRO_SYSTEM_ID_IPHONE - iOS * ALLEGRO_SYSTEM_ID_GP2XWIZ - GP2XWIZ * ALLEGRO_SYSTEM_ID_RASPBERRYPI - Raspberry Pi * ALLEGRO_SYSTEM_ID_SDL - SDL Since: 5.2.5 See also: [al_get_system_id] allegro5-5.2.10.1/docs/src/refman/threads.txt000066400000000000000000000155201473414355200206450ustar00rootroot00000000000000# Threads Allegro includes a simple cross-platform threading interface. It is a thin layer on top of two threading APIs: Windows threads and POSIX Threads (pthreads). Enforcing a consistent semantics on all platforms would be difficult at best, hence the behaviour of the following functions will differ subtly on different platforms (more so than usual). Your best bet is to be aware of this and code to the intersection of the semantics and avoid edge cases. These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: ALLEGRO_THREAD An opaque structure representing a thread. ## API: ALLEGRO_MUTEX An opaque structure representing a mutex. ## API: ALLEGRO_COND An opaque structure representing a condition variable. ## API: al_create_thread Spawn a new thread which begins executing `proc`. The new thread is passed its own thread handle and the value `arg`. Returns a pointer to the thread on success. Otherwise, returns NULL if there was an error. See also: [al_start_thread], [al_join_thread]. ## API: al_create_thread_with_stacksize Spawn a new thread with the give stacksize in bytes which begins executing `proc`. The new thread is passed its own thread handle and the value `arg`. Returns a pointer to the thread on success. Otherwise, returns NULL if there was an error. Since: 5.2.5 > *[Unstable API]:* New API, may want a better way to specify thread options. See also: [al_start_thread], [al_join_thread]. ## API: al_start_thread When a thread is created, it is initially in a suspended state. Calling [al_start_thread] will start its actual execution. Starting a thread which has already been started does nothing. See also: [al_create_thread]. ## API: al_join_thread Wait for the thread to finish executing. This implicitly calls [al_set_thread_should_stop] first. If `ret_value` is non-`NULL`, the value returned by the thread function will be stored at the location pointed to by `ret_value`. See also: [al_set_thread_should_stop], [al_get_thread_should_stop], [al_destroy_thread]. ## API: al_set_thread_should_stop Set the flag to indicate `thread` should stop. Returns immediately. See also: [al_join_thread], [al_get_thread_should_stop]. ## API: al_get_thread_should_stop Check if another thread is waiting for `thread` to stop. Threads which run in a loop should check this periodically and act on it when convenient. Returns true if another thread has called [al_join_thread] or [al_set_thread_should_stop] on this thread. See also: [al_join_thread], [al_set_thread_should_stop]. > *Note:* We don't support forceful killing of threads. ## API: al_destroy_thread Free the resources used by a thread. Implicitly performs [al_join_thread] on the thread if it hasn't been done already. Does nothing if `thread` is NULL. See also: [al_join_thread]. ## API: al_run_detached_thread Runs the passed function in its own thread, with `arg` passed to it as only parameter. This is similar to calling [al_create_thread], [al_start_thread] and (after the thread has finished) [al_destroy_thread] - but you don't have the possibility of ever calling [al_join_thread] on the thread. ## API: al_create_mutex Create the mutex object (a mutual exclusion device). The mutex may or may not support "recursive" locking. Returns the mutex on success or `NULL` on error. See also: [al_create_mutex_recursive]. ## API: al_create_mutex_recursive Create the mutex object (a mutual exclusion device), with support for "recursive" locking. That is, the mutex will count the number of times it has been locked by the same thread. If the caller tries to acquire a lock on the mutex when it already holds the lock then the count is incremented. The mutex is only unlocked when the thread releases the lock on the mutex an equal number of times, i.e. the count drops down to zero. See also: [al_create_mutex]. ## API: al_lock_mutex Acquire the lock on `mutex`. If the mutex is already locked by another thread, the call will block until the mutex becomes available and locked. If the mutex is already locked by the calling thread, then the behaviour depends on whether the mutex was created with [al_create_mutex] or [al_create_mutex_recursive]. In the former case, the behaviour is undefined; the most likely behaviour is deadlock. In the latter case, the count in the mutex will be incremented and the call will return immediately. See also: [al_unlock_mutex]. **We don't yet have al_mutex_trylock.** ## API: al_unlock_mutex Release the lock on `mutex` if the calling thread holds the lock on it. If the calling thread doesn't hold the lock, or if the mutex is not locked, undefined behaviour results. See also: [al_lock_mutex]. ## API: al_destroy_mutex Free the resources used by the mutex. The mutex should be unlocked. Destroying a locked mutex results in undefined behaviour. Does nothing if `mutex` is `NULL`. ## API: al_create_cond Create a condition variable. Returns the condition value on success or `NULL` on error. ## API: al_destroy_cond Destroy a condition variable. Destroying a condition variable which has threads block on it results in undefined behaviour. Does nothing if `cond` is `NULL`. ## API: al_wait_cond On entering this function, `mutex` must be locked by the calling thread. The function will atomically release `mutex` and block on `cond`. The function will return when `cond` is "signalled", acquiring the lock on the mutex in the process. Example of proper use: ~~~~c al_lock_mutex(mutex); while (something_not_true) { al_wait_cond(cond, mutex); } do_something(); al_unlock_mutex(mutex); ~~~~ The mutex should be locked before checking the condition, and should be rechecked [al_wait_cond] returns. [al_wait_cond] can return for other reasons than the condition becoming true (e.g. the process was signalled). If multiple threads are blocked on the condition variable, the condition may no longer be true by the time the second and later threads are unblocked. Remember not to unlock the mutex prematurely. See also: [al_wait_cond_until], [al_broadcast_cond], [al_signal_cond]. ## API: al_wait_cond_until Like [al_wait_cond] but the call can return if the absolute time passes `timeout` before the condition is signalled. Returns zero on success, non-zero if the call timed out. See also: [al_wait_cond] ## API: al_broadcast_cond Unblock all threads currently waiting on a condition variable. That is, broadcast that some condition which those threads were waiting for has become true. See also: [al_signal_cond]. > *Note:* The pthreads spec says to lock the mutex associated with `cond` before signalling for predictable scheduling behaviour. ## API: al_signal_cond Unblock at least one thread waiting on a condition variable. Generally you should use [al_broadcast_cond] but [al_signal_cond] may be more efficient when it's applicable. See also: [al_broadcast_cond]. allegro5-5.2.10.1/docs/src/refman/time.txt000066400000000000000000000022411473414355200201450ustar00rootroot00000000000000# Time routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: ALLEGRO_TIMEOUT Represent a timeout value. The size of the structure is known so it can be statically allocated. The contents are private. See also: [al_init_timeout] ## API: al_get_time Return the number of seconds since the Allegro library was initialised. The return value is undefined if Allegro is uninitialised. The resolution depends on the used driver, but typically can be in the order of microseconds. ## API: al_init_timeout Set timeout value of some number of seconds after the function call. For compatibility with all platforms, `seconds` must be 2,147,483.647 seconds or less. See also: [ALLEGRO_TIMEOUT], [al_wait_for_event_until] ## API: al_rest Waits for the specified number of seconds. This tells the system to pause the current thread for the given amount of time. With some operating systems, the accuracy can be in the order of 10ms. That is, even ~~~~c al_rest(0.000001) ~~~~ might pause for something like 10ms. Also see the section on Timer routines for easier ways to time your program without using up all CPU. allegro5-5.2.10.1/docs/src/refman/timer.txt000066400000000000000000000072231473414355200203340ustar00rootroot00000000000000# Timer routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: ALLEGRO_TIMER This is an abstract data type representing a timer object. ## API: ALLEGRO_USECS_TO_SECS Convert microseconds to seconds. ## API: ALLEGRO_MSECS_TO_SECS Convert milliseconds to seconds. ## API: ALLEGRO_BPS_TO_SECS Convert beats per second to seconds. ## API: ALLEGRO_BPM_TO_SECS Convert beats per minute to seconds. ## API: al_create_timer Allocates and initializes a timer. If successful, a pointer to a new timer object is returned, otherwise NULL is returned. *speed_secs* is in seconds per "tick", and must be positive. The new timer is initially stopped and needs to be started with [al_start_timer] before [ALLEGRO_EVENT_TIMER] events are sent. Usage note: typical granularity is on the order of microseconds, but with some drivers might only be milliseconds. See also: [al_start_timer], [al_destroy_timer] ## API: al_start_timer Start the timer specified. From then, the timer's counter will increment at a constant rate, and it will begin generating events. Starting a timer that is already started does nothing. Starting a timer that was stopped will reset the timer's counter, effectively restarting the timer from the beginning. See also: [al_stop_timer], [al_get_timer_started], [al_resume_timer] ## API: al_resume_timer Resume the timer specified. From then, the timer's counter will increment at a constant rate, and it will begin generating events. Resuming a timer that is already started does nothing. Resuming a stopped timer will not reset the timer's counter (unlike [al_start_timer]). See also: [al_start_timer], [al_stop_timer], [al_get_timer_started] ## API: al_stop_timer Stop the timer specified. The timer's counter will stop incrementing and it will stop generating events. Stopping a timer that is already stopped does nothing. See also: [al_start_timer], [al_get_timer_started], [al_resume_timer] ## API: al_get_timer_started Return true if the timer specified is currently started. ## API: al_destroy_timer Uninstall the timer specified. If the timer is started, it will automatically be stopped before uninstallation. It will also automatically unregister the timer with any event queues. Does nothing if passed the NULL pointer. See also: [al_create_timer] ## API: al_get_timer_count Return the timer's counter value. The timer can be started or stopped. See also: [al_set_timer_count] ## API: al_set_timer_count Set the timer's counter value. The timer can be started or stopped. The count value may be positive or negative, but will always be incremented by +1 at each tick. See also: [al_get_timer_count], [al_add_timer_count] ## API: al_add_timer_count Add *diff* to the timer's counter value. This is similar to writing: ~~~~c al_set_timer_count(timer, al_get_timer_count(timer) + diff); ~~~~ except that the addition is performed atomically, so no ticks will be lost. See also: [al_set_timer_count] ## API: al_get_timer_speed Return the timer's speed, in seconds. (The same value passed to [al_create_timer] or [al_set_timer_speed].) See also: [al_set_timer_speed] ## API: al_set_timer_speed Set the timer's speed, i.e. the rate at which its counter will be incremented when it is started. This can be done when the timer is started or stopped. If the timer is currently running, it is made to look as though the speed change occurred precisely at the last tick. *speed_secs* has exactly the same meaning as with [al_create_timer]. See also: [al_get_timer_speed] ## API: al_get_timer_event_source Retrieve the associated event source. Timers will generate events of type [ALLEGRO_EVENT_TIMER]. allegro5-5.2.10.1/docs/src/refman/title.txt000066400000000000000000000000351473414355200203270ustar00rootroot00000000000000% Allegro 5 reference manual allegro5-5.2.10.1/docs/src/refman/touch.txt000066400000000000000000000072621473414355200203410ustar00rootroot00000000000000# Touch input These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## API: ALLEGRO_TOUCH_INPUT An abstract data type representing a physical touch screen or touch pad. Since: 5.1.0 ## API: ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT The maximum amount of simultaneous touches that can be detected. Since: 5.1.0 ## API: ALLEGRO_TOUCH_STATE This is a structure that is used to hold a "snapshot" of a touch at a particular instant. Public fields (read only): * id - identifier of the touch. If the touch is valid, this is positive. * x - touch x position * y - touch y position * dx - touch relative x position * dy - touch relative y position * primary - TRUE if this touch is the primary one (usually the first one). * display - The [ALLEGRO_DISPLAY] that was touched. Since: 5.1.0 ## API: ALLEGRO_TOUCH_INPUT_STATE This is a structure that holds a snapshot of all simultaneous touches at a particular instant. Public fields (read only): * touches - an array of [ALLEGRO_TOUCH_STATE] Since: 5.1.0 ## API: ALLEGRO_MOUSE_EMULATION_MODE Type of mouse emulation to apply. ALLEGRO_MOUSE_EMULATION_NONE : Disables mouse emulation. ALLEGRO_MOUSE_EMULATION_TRANSPARENT : Enables transparent mouse emulation. ALLEGRO_MOUSE_EMULATION_INCLUSIVE : Enable inclusive mouse emulation. ALLEGRO_MOUSE_EMULATION_EXCLUSIVE : Enables exclusive mouse emulation. ALLEGRO_MOUSE_EMULATION_5_0_x : Enables mouse emulation that is backwards compatible with Allegro 5.0.x. Since: 5.1.0 > *[Unstable API]:* Seems of limited value, as touch input tends to have different semantics compared to mouse input. ## API: al_install_touch_input Install a touch input driver, returning true if successful. If a touch input driver was already installed, returns true immediately. Since: 5.1.0 See also: [al_uninstall_touch_input] ## API: al_uninstall_touch_input Uninstalls the active touch input driver. If no touch input driver was active, this function does nothing. This function is automatically called when Allegro is shut down. Since: 5.1.0 See also: [al_install_touch_input] ## API: al_is_touch_input_installed Returns true if [al_install_touch_input] was called successfully. Since: 5.1.0 ## API: al_get_touch_input_state Gets the current touch input state. The touch information is copied into the [ALLEGRO_TOUCH_INPUT_STATE] you provide to this function. Since: 5.1.0 ## API: al_set_mouse_emulation_mode Sets the kind of mouse emulation for the touch input subsystem to perform. Since: 5.1.0 > *[Unstable API]:* Seems of limited value, as touch input tends to have different semantics compared to mouse input. See also: [ALLEGRO_MOUSE_EMULATION_MODE], [al_get_mouse_emulation_mode]. ## API: al_get_mouse_emulation_mode Returns the kind of mouse emulation which the touch input subsystem is set to perform. Since: 5.1.0 > *[Unstable API]:* Seems of limited value, as touch input tends to have different semantics compared to mouse input. See also: [ALLEGRO_MOUSE_EMULATION_MODE], [al_set_mouse_emulation_mode]. ## API: al_get_touch_input_event_source Returns the global touch input event source. This event source generates [touch input events][ALLEGRO_EVENT_TOUCH_BEGIN]. Since: 5.1.0 See also: [ALLEGRO_EVENT_SOURCE], [al_register_event_source] ## API: al_get_touch_input_mouse_emulation_event_source Returns the global touch input event source for emulated mouse events. This event source generates [emulated mouse events][ALLEGRO_EVENT_MOUSE_AXES] that are based on touch events. See also: [ALLEGRO_EVENT_SOURCE], [al_register_event_source] Since: 5.1.0 > *[Unstable API]:* Seems of limited value, as touch input tends to have different semantics compared to mouse input. allegro5-5.2.10.1/docs/src/refman/transformations.txt000066400000000000000000000476651473414355200224630ustar00rootroot00000000000000# Transformations These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ Transformations allow you to transform the coordinates you use for drawing operations without additional overhead. Scaling, rotating, translating, and combinations of these are possible as well as using custom transformations. There are two types of transformations that you can set, 'regular' transformations and projection transformations. The projection transform is rarely used in 2D games, but is common in 3D games to set up the projection from the 3D world to the 2D screen. Typically, you would use the regular transform for non-projective types of transformations (that is, translations, rotations, scales, skews... i.e. transformations that are linear), while the projection transform will be used for setting up perspective and possibly more advanced effects. It is possible to do everything with just using the projection transformation (that is, you'd compose the projection transformation with the non-projection transformations that, e.g., move the camera in the world), but it is more convenient to use both for two reasons: - Regular transformations can be changed while the bitmap drawing is held (see [al_hold_bitmap_drawing]). - Regular transformations work with memory bitmaps. As a result, if you're making a 2D game, it's best to leave the projection transformations at their default values. Both types of transformations are set per target-bitmap, i.e. a change of the target bitmap will also change the active transformation. Allegro provides convenience functions to construct transformations in 2D and 3D variants (the latter with a `_3d` suffix), so you don't have to deal with the underlying matrix algebra yourself. The transformations are combined in the order of the function invocations. Thus to create a transformation that first rotates a point and then translates it, you would (starting with an identity transformation) call [al_rotate_transform] and then [al_translate_transform]. This approach is opposite of what OpenGL uses but similar to what Direct3D uses. For those who know the matrix algebra going behind the scenes, what the transformation functions in Allegro do is "pre-multiply" the successive transformations. So, for example, if you have code that does: ~~~~c al_identity_transform(&T); al_compose_transform(&T, &T1); al_compose_transform(&T, &T2); al_compose_transform(&T, &T3); al_compose_transform(&T, &T4); ~~~~ The resultant matrix multiplication expression will look like this: T4 * T3 * T2 * T1 Since the point coordinate vector term will go on the right of that sequence of factors, the transformation that is called first, will also be applied first. This means if you have code like this: ~~~~c al_identity_transform(&T1); al_scale_transform(&T1, 2, 2); al_identity_transform(&T2); al_translate_transform(&T2, 100, 0); al_identity_transform(&T); al_compose_transform(&T, &T1); al_compose_transform(&T, &T2); al_use_transform(&T); ~~~~ it does exactly the same as: ~~~~c al_identity_transform(&T); al_scale_transform(&T, 2, 2); al_translate_transform(&T, 100, 0); al_use_transform(&T); ~~~~ ## API: ALLEGRO_TRANSFORM Defines the generic transformation type, a 4x4 matrix. 2D transforms use only a small subsection of this matrix, namely the top left 2x2 matrix, and the right most 2x1 matrix, for a total of 6 values. *Fields:* * m - A 4x4 float matrix ## API: al_copy_transform Makes a copy of a transformation. *Parameters:* * dest - Source transformation * src - Destination transformation ## API: al_use_transform Sets the transformation to be used for the the drawing operations on the target bitmap (each bitmap maintains its own transformation). Every drawing operation after this call will be transformed using this transformation. Call this function with an identity transformation to return to the default behaviour. This function does nothing if there is no target bitmap. The parameter is passed by reference as an optimization to avoid the overhead of stack copying. The reference will not be stored in the Allegro library so it is safe to pass references to local variables. ~~~~c void setup_my_transformation(void) { ALLEGRO_TRANSFORM transform; al_translate_transform(&transform, 5, 10); al_use_transform(&transform); } ~~~~ *Parameters:* * trans - Transformation to use See also: [al_get_current_transform], [al_transform_coordinates] ## API: al_get_current_transform Returns the transformation of the current target bitmap, as set by [al_use_transform]. If there is no target bitmap, this function returns NULL. *Returns:* A pointer to the current transformation. See also: [al_get_current_projection_transform] ## API: al_use_projection_transform Sets the projection transformation to be used for the drawing operations on the target bitmap (each bitmap maintains its own projection transformation). Every drawing operation after this call will be transformed using this transformation. To return default behavior, call this function with an orthographic transform like so: ~~~~c ALLEGRO_TRANSFORM trans; al_identity_transform(&trans); al_orthographic_transform(&trans, 0, 0, -1.0, al_get_bitmap_width(bitmap), al_get_bitmap_height(bitmap), 1.0); al_set_target_bitmap(bitmap); al_use_projection_transform(&trans); ~~~~ The orthographic transformation above is the default projection transform. This function does nothing if there is no target bitmap. This function also does nothing if the bitmap is a memory bitmap (i.e. memory bitmaps always use an orthographic transform like the snippet above). Note that the projection transform will be reset to default if a video bitmap is converted to a memory bitmap. Additionally, if the bitmap in question is the backbuffer, it's projection transformation will be reset to default if it is resized. Lastly, when you draw a memory bitmap to a video bitmap with a custom projection transform, this transformation will be ignored (i.e. it'll be as if the projection transform of the target bitmap was temporarily reset to default). The parameter is passed by reference as an optimization to avoid the overhead of stack copying. The reference will not be stored in the Allegro library so it is safe to pass references to local variables. Since: 5.1.9 See also: [al_get_current_projection_transform], [al_perspective_transform], [al_orthographic_transform] ## API: al_get_current_projection_transform If there is no target bitmap, this function returns NULL. *Returns:* A pointer to the current transformation. Since: 5.1.9 See also: [al_use_projection_transform] ## API: al_get_current_inverse_transform Returns the inverse of the current transformation of the target bitmap. If there is no target bitmap, this function returns NULL. This is similar to calling `al_invert_transform(al_get_current_transform())` but the result of this function is cached. > *Note*: Allegro's transformation inversion functions work correctly only with 2D transformations. Since: 5.1.0 ## API: al_invert_transform Inverts the passed transformation. If the transformation is nearly singular (close to not having an inverse) then the returned transformation may be invalid. Use [al_check_inverse] to ascertain if the transformation has an inverse before inverting it if you are in doubt. *Parameters:* * trans - Transformation to invert > *Note*: Allegro's transformation inversion functions work correctly only with 2D transformations. See also: [al_check_inverse] ## API: al_transpose_transform Transposes the matrix of the given transform. This can be used for inversing a rotation transform. For example: ~~~~c al_build_camera_transform(camera, 0, 0, 0, x, y, z, xu, yu, zu) al_copy_transform(inverse, camera) al_transpose_transform(camera) // Now "inverse" will be a transformation rotating in the opposite // direction from "camera". Note that this only works if the camera // position is 0/0/0 as in the example. ~~~~ Since: 5.2.5 ## API: al_check_inverse Checks if the transformation has an inverse using the supplied tolerance. Tolerance should be a small value between 0 and 1, with 1e-7 being sufficient for most applications. In this function tolerance specifies how close the determinant can be to 0 (if the determinant is 0, the transformation has no inverse). Thus the smaller the tolerance you specify, the "worse" transformations will pass this test. Using a tolerance of 1e-7 will catch errors greater than 1/1000's of a pixel, but let smaller errors pass. That means that if you transformed a point by a transformation and then transformed it again by the inverse transformation that passed this check, the resultant point should less than 1/1000's of a pixel away from the original point. Note that this check is superfluous most of the time if you never touched the transformation matrix values yourself. The only thing that would cause the transformation to not have an inverse is if you applied a 0 (or very small) scale to the transformation or you have a really large translation. As long as the scale is comfortably above 0, the transformation will be invertible. *Parameters:* * trans - Transformation to check * tol - Tolerance *Returns:* 1 if the transformation is invertible, 0 otherwise > *Note*: Allegro's transformation inversion functions work correctly only with 2D transformations. See also: [al_invert_transform] ## API: al_identity_transform Sets the transformation to be the identity transformation. This is the default transformation. Use [al_use_transform] on an identity transformation to return to the default. ~~~~c ALLEGRO_TRANSFORM t; al_identity_transform(&t); al_use_transform(&t); ~~~~ *Parameters:* * trans - Transformation to alter See also: [al_translate_transform], [al_rotate_transform], [al_scale_transform] ## API: al_build_transform Builds a transformation given some parameters. This call is equivalent to calling the transformations in this order: make identity, rotate, scale, translate. This method is faster, however, than actually calling those functions. *Parameters:* * trans - Transformation to alter * x, y - Translation * sx, sy - Scale * theta - Rotation angle in radians > *Note*: this function was previously documented to be equivalent to a different (and more useful) order of operations: identity, scale, rotate, translate. See also: [al_translate_transform], [al_rotate_transform], [al_scale_transform], [al_compose_transform] ## API: al_build_camera_transform Builds a transformation which can be used to transform 3D coordinates in world space to camera space. This involves translation and a rotation. The function expects three coordinate triplets: The camera's position, the position the camera is looking at and an up vector. The up vector does not need to be of unit length and also does not need to be perpendicular to the view direction - it can usually just be the world up direction (most commonly 0/1/0). For example: ~~~~c al_build_camera_transform(&t, 1, 1, 1, 5, 5, 5, 0, 1, 0); ~~~~ This create a transformation for a camera standing at 1/1/1 and looking towards 5/5/5. > *Note*: If the *position* and *look* parameters are identical, or if the *up* direction is parallel to the view direction, an identity matrix is created. Another example which will simply re-create the identity matrix: ~~~~c al_build_camera_transform(&t, 0, 0, 0, 0, 0, -1, 0, 1, 0); ~~~~ An example where the up vector will cause the camera to lean (roll) by 45 degrees: ~~~~c al_build_camera_transform(&t, 1, 1, 1, 5, 5, 5, 1, 1, 0); ~~~~ Since 5.1.9 See also: [al_translate_transform_3d], [al_rotate_transform_3d], [al_scale_transform_3d], [al_compose_transform], [al_use_transform] ## API: al_translate_transform Apply a translation to a transformation. *Parameters:* * trans - Transformation to alter * x, y - Translation See also: [al_rotate_transform], [al_scale_transform], [al_build_transform] ## API: al_rotate_transform Apply a rotation to a transformation. *Parameters:* * trans - Transformation to alter * theta - Rotation angle in radians See also: [al_translate_transform], [al_scale_transform], [al_build_transform] ## API: al_scale_transform Apply a scale to a transformation. *Parameters:* * trans - Transformation to alter * sx, sy - Scale See also: [al_translate_transform], [al_rotate_transform], [al_build_transform] ## API: al_transform_coordinates Transform a pair of coordinates. *Parameters:* * trans - Transformation to use * x, y - Pointers to the coordinates See also: [al_use_transform], [al_transform_coordinates_3d] ## API: al_transform_coordinates_3d Transform x, y, z coordinates. *Parameters:* * trans - Transformation to use * x, y, z - Pointers to the coordinates Note: If you are using a projection transform you most likely will want to use [al_transform_coordinates_3d_projective] instead. Since 5.1.9 See also: [al_use_transform], [al_transform_coordinates] ## API: al_transform_coordinates_4d Transform x, y, z, w coordinates. *Parameters:* * trans - Transformation to use * x, y, z, w - Pointers to the coordinates Since 5.2.4 See also: [al_use_transform], [al_transform_coordinates], [al_transform_coordinates_3d] ## API: al_transform_coordinates_3d_projective Transform x, y, z as homogeneous coordinates. This is the same as using [al_transform_coordinates_4d] with the w coordinate set to 1, then dividing x, y, z by the resulting w. This will provide the same normalized coordinates Allegro will draw to when a projective transform is in effect as set with [al_use_projection_transform]. To get the actual pixel coordinates from those translate and scale like so (w and h would be the pixel dimensions of the target bitmap): ~~~~c x = w / 2 + x * w / 2 y = h / 2 - y * h / 2 ~~~~ *Parameters:* * trans - Transformation to use * x, y, z - Pointers to the coordinates Example: ~~~~c ALLEGRO_TRANSFORM t2; al_copy_transform(&t2, al_get_current_transform()); al_compose_transform(&t2, al_get_current_projection_transform()); ALLEGRO_TRANSFORM t3; al_identity_transform(&t3); al_scale_transform(&t3, 0.5, -0.5); al_translate_transform(&t3, 0.5, 0.5); al_scale_transform(&t3, al_get_bitmap_width(al_get_target_bitmap()), al_get_bitmap_height(al_get_target_bitmap())); al_transform_coordinates_3d_projective(&t2, &x, &y, &z); // x, y now contain normalized coordinates al_transform_coordinates(&t3, &x, &y); // x, y now contain pixel coordinates ~~~~ Since 5.2.4 See also: [al_use_transform], [al_transform_coordinates], [al_transform_coordinates_3d], [al_use_projection_transform] ## API: al_compose_transform Compose (combine) two transformations by a matrix multiplication. trans := trans other Note that the order of matrix multiplications is important. The effect of applying the combined transform will be as if first applying `trans` and then applying `other` and not the other way around. *Parameters:* * trans - Transformation to alter * other - Transformation used to transform `trans` See also: [al_translate_transform], [al_rotate_transform], [al_scale_transform] ## API: al_orthographic_transform Combines the given transformation with an orthographic transformation which maps the screen rectangle to the given left/top and right/bottom coordinates. near/far is the z range, coordinates outside of that range will get clipped. Normally -1/1 is fine because all 2D graphics will have a z coordinate of 0. However if you for example do al_draw_rectangle(0, 0, 100, 100) and rotate around the x axis ("towards the screen") make sure your z range allows values from -100 to 100 or the rotated rectangle will get clipped. Also, if you are using a depth buffer the z range decides the depth resolution. For example if you have a 16 bit depth buffer there are only 65536 discrete depth values. So if your near/far is set to -1000000/1000000 most of the z positions would not result in separate depth values which could lead to artifacts. The result of applying this transformation to coordinates will be to normalize visible coordinates into the cube from -1/-1/-1 to 1/1/1. Such a transformation is mostly useful for passing it to [al_use_projection_transform] - see that function for an example use. Since: 5.1.3 See also: [al_use_projection_transform], [al_perspective_transform] ## API: al_perspective_transform Like [al_orthographic_transform] but honors perspective. If everything is at a z-position of -near it will look the same as with an orthographic transformation. To use a specific horizontal field of view you can use the relation: tan(hfov / 2) = (right - left) / 2 / near and therefore near = (right - left) / 2 / tan(hfov / 2) Example 1: ~~~~c float w = 800, h = 450; // assume our display is 800 x 450 float fov = tan(90 * ALLEGRO_PI / 180 / 2); // 90 degree field of view // Our projection goes from 0/0 to w/h with the near parameter set // for a 90 degree horizontal viewing angle. ALLEGRO_TRANSFORM projection; al_identity_transform(&projection); al_perspective_transform(&projection, 0, 0, w / 2 / fov, w, h, 2000); al_use_projection_transform(&projection); // Set the camera z to +400 (which is exactly the near distance) ALLEGRO_TRANSFORM camera; al_build_camera_transform(&camera, 0, 0, 400, 0, 0, 0, 0, 1, 0); al_use_transform(&camera); // This will draw two rectangles at the left and right edge of the // screen and vertically centered. The x distance between them is 800 // units, but the camera transform moves them 400 along z, so with // a 90° viewing angle both are visible. al_draw_filled_rectangle(0, 200, 50, 250, red; al_draw_filled_rectangle(750, 200, 800, 250, red); ~~~~ Example 2: ~~~~c float w = 800, h = 450; // assume our display is 800 x 450 float fov = tan(90 * ALLEGRO_PI / 180 / 2); // 90 degree field of view float aspect = h / w; float zoom = 2; // enlarge x 2 // This projection is very different from the one in the first example. // Here we map the left and right edge of the screen to -1 and +1. And // the y axis goes from -1 at the bottom to +1 at the top, scaled by // the aspect ratio. We also add a zoom parameter so we can control // the visible portion of the scene independent of the field of view. ALLEGRO_TRANSFORM projection; al_identity_transform(&projection); al_perspective_transform(&projection, -1 / zoom, aspect / zoom, 1 / fov, 1 / zoom, -aspect / zoom, 2000); al_use_projection_transform(&projection); // Moves everything by -4 in the z direction. ALLEGRO_TRANSFORM camera; al_build_camera_transform(&camera, 0, 0, 4, 0, 0, 0, 0, 1, 0); al_use_transform(&camera); // At a z distance of 4 with a 90° hfov everything would be scaled // down to 25%. However we also zoom 2-fold, so the final scaling is // 50%. This rectangle therefore will appear at a size of 400 x 225 // pixel (assuming the display is 800 x 450). al_draw_filled_rectangle(-1, -1, 1, 1, red); ~~~~ Since: 5.1.3 See also: [al_use_projection_transform], [al_orthographic_transform] ## API: al_translate_transform_3d Combines the given transformation with a transformation which translates coordinates by the given vector. Since: 5.1.3 See also: [al_use_projection_transform] ## API: al_scale_transform_3d Combines the given transformation with a transformation which scales coordinates by the given vector. Since: 5.1.3 See also: [al_use_projection_transform] ## API: al_rotate_transform_3d Combines the given transformation with a transformation which rotates coordinates around the given vector by the given angle in radians. Note: The vector is assumed to be of unit length (otherwise it will also incur a scale). Since: 5.1.3 ## API: al_horizontal_shear_transform Apply a horizontal shear to the transform *Parameters:* * trans - Transformation to alter * theta - Rotation angle in radians Since: 5.1.7 See also: [al_vertical_shear_transform] ## API: al_vertical_shear_transform Apply a vertical shear to the transform *Parameters:* * trans - Transformation to alter * theta - Rotation angle in radians Since: 5.1.7 See also: [al_horizontal_shear_transform] allegro5-5.2.10.1/docs/src/refman/utf8.txt000066400000000000000000000617461473414355200201140ustar00rootroot00000000000000# UTF-8 string routines These functions are declared in the main Allegro header file: ~~~~c #include ~~~~ ## About UTF-8 string routines Some parts of the Allegro API, such as the font rountines, expect Unicode strings encoded in UTF-8. The following basic routines are provided to help you work with UTF-8 strings, however it does *not* mean you need to use them. You should consider another library (e.g. ICU) if you require more functionality. Briefly, Unicode is a standard consisting of a large character set of over 100,000 characters, and rules, such as how to sort strings. A *code point* is the integer value of a character, but not all code points are characters, as some code points have other uses. Unlike legacy character sets, the set of code points is open ended and more are assigned with time. Clearly it is impossible to represent each code point with a 8-bit byte (limited to 256 code points) or even a 16-bit integer (limited to 65536 code points). It is possible to store code points in a 32-bit integers but it is space inefficient, and not actually that useful (at least, when handling the full complexity of Unicode; Allegro only does the very basics). There exist different Unicode Transformation Formats for encoding code points into smaller *code units*. The most important transformation formats are UTF-8 and UTF-16. UTF-8 is a *variable-length encoding* which encodes each code point to between one and four 8-bit bytes each. UTF-8 has many nice properties, but the main advantages are that it is backwards compatible with C strings, and ASCII characters (code points in the range 0-127) are encoded in UTF-8 exactly as they would be in ASCII. UTF-16 is another variable-length encoding, but encodes each code point to one or two 16-bit words each. It is, of course, not compatible with traditional C strings. Allegro does not generally use UTF-16 strings. Here is a diagram of the representation of the word "ål", with a NUL terminator, in both UTF-8 and UTF-16. ---------------- ---------------- -------------- String å l NUL ---------------- ---------------- -------------- Code points U+00E5 (229) U+006C (108) U+0000 (0) ---------------- ---------------- -------------- UTF-8 bytes 0xC3, 0xA5 0x6C 0x00 ---------------- ---------------- -------------- UTF-16LE bytes 0xE5, 0x00 0x6C, 0x00 0x00, 0x00 ---------------- ---------------- -------------- You can see the aforementioned properties of UTF-8. The first code point U+00E5 ("å") is outside of the ASCII range (0-127) so is encoded to multiple code units -- it requires two bytes. U+006C ("l") and U+0000 (NUL) both exist in the ASCII range so take exactly one byte each, as in a pure ASCII string. A zero byte never appears except to represent the NUL character, so many functions which expect C-style strings will work with UTF-8 strings without modification. On the other hand, UTF-16 represents each code point by either one or two 16-bit code units (two or four bytes). The representation of each 16-bit code unit depends on the byte order; here we have demonstrated little endian. Both UTF-8 and UTF-16 are self-synchronising. Starting from any offset within a string, it is efficient to find the beginning of the previous or next code point. Not all sequences of bytes or 16-bit words are valid UTF-8 and UTF-16 strings respectively. UTF-8 also has an additional problem of overlong forms, where a code point value is encoded using more bytes than is strictly necessary. This is invalid and needs to be guarded against. In the following "ustr" functions, be careful whether a function takes code unit (byte) or code point indices. In general, all position parameters are in code unit offsets. This may be surprising, but if you think about it, it is required for good performance. (It also means some functions will work even if they do not contain UTF-8, since they only care about storing bytes, so you may actually store arbitrary data in the ALLEGRO_USTRs.) For actual text processing, where you want to specify positions with code point indices, you should use [al_ustr_offset] to find the code unit offset position. However, most of the time you would probably just work with byte offsets. ## UTF-8 string types ### API: ALLEGRO_USTR An opaque type representing a string. ALLEGRO_USTRs normally contain UTF-8 encoded strings, but they may be used to hold any byte sequences, including NULs. ### API: ALLEGRO_USTR_INFO A type that holds additional information for an [ALLEGRO_USTR] that references an external memory buffer. You can convert it back to [ALLEGRO_USTR] via [al_ref_info]. See also: [al_ref_cstr], [al_ref_buffer], [al_ref_info] and [al_ref_ustr]. ## Creating and destroying strings ### API: al_ustr_new Create a new string containing a copy of the C-style string `s`. The string must eventually be freed with [al_ustr_free]. See also: [al_ustr_new_from_buffer], [al_ustr_newf], [al_ustr_dup], [al_ustr_new_from_utf16] ### API: al_ustr_new_from_buffer Create a new string containing a copy of the buffer pointed to by `s` of the given `size` in bytes. The string must eventually be freed with [al_ustr_free]. See also: [al_ustr_new] ### API: al_ustr_newf Create a new string using a printf-style format string. *Notes:* The "%s" specifier takes C string arguments, not ALLEGRO_USTRs. Therefore to pass an ALLEGRO_USTR as a parameter you must use [al_cstr], and it must be NUL terminated. If the string contains an embedded NUL byte everything from that byte onwards will be ignored. The "%c" specifier outputs a single byte, not the UTF-8 encoding of a code point. Therefore it is only usable for ASCII characters (value <= 127) or if you really mean to output byte values from 128--255. To insert the UTF-8 encoding of a code point, encode it into a memory buffer using [al_utf8_encode] then use the "%s" specifier. Remember to NUL terminate the buffer. See also: [al_ustr_new], [al_ustr_appendf] ### API: al_ustr_free Free a previously allocated string. Does nothing if the argument is NULL. See also: [al_ustr_new], [al_ustr_new_from_buffer], [al_ustr_newf] ### API: al_cstr Get a `char *` pointer to the data in a string. This pointer will only be valid while the [ALLEGRO_USTR] object is not modified and not destroyed. The pointer may be passed to functions expecting C-style strings, with the following caveats: * ALLEGRO_USTRs are allowed to contain embedded NUL (`'\0'`) bytes. That means `al_ustr_size(u)` and `strlen(al_cstr(u))` may not agree. * An ALLEGRO_USTR may be created in such a way that it is not NUL terminated. A string which is dynamically allocated will always be NUL terminated, but a string which references the middle of another string or region of memory will *not* be NUL terminated. * If the ALLEGRO_USTR references another string, the returned C string will point into the referenced string. Again, no NUL terminator will be added to the referenced string. See also: [al_ustr_to_buffer], [al_cstr_dup] ### API: al_ustr_to_buffer Write the contents of the string into a pre-allocated buffer of the given size in bytes. The result will always be NUL terminated, so a maximum of `size - 1` bytes will be copied. See also: [al_cstr], [al_cstr_dup] ### API: al_cstr_dup Create a NUL (`'\0'`) terminated copy of the string. Any embedded NUL bytes will still be presented in the returned string. The new string must eventually be freed with [al_free]. If an error occurs NULL is returned. See also: [al_cstr], [al_ustr_to_buffer], [al_free] ### API: al_ustr_dup Return a duplicate copy of a string. The new string will need to be freed with [al_ustr_free]. See also: [al_ustr_dup_substr], [al_ustr_free] ### API: al_ustr_dup_substr Return a new copy of a string, containing its contents in the byte interval \[`start_pos`, `end_pos`). The new string will be NUL terminated and will need to be freed with [al_ustr_free]. If necessary, use [al_ustr_offset] to find the byte offsets for a given code point that you are interested in. See also: [al_ustr_dup], [al_ustr_free] ## Predefined strings ### API: al_ustr_empty_string Return a pointer to a static empty string. The string is read only and must not be freed. ## Creating strings by referencing other data ### API: al_ref_cstr Create a string that references the storage of a C-style string. The information about the string (e.g. its size) is stored in the structure pointed to by the `info` parameter. The string will not have any other storage allocated of its own, so if you allocate the `info` structure on the stack then no explicit "free" operation is required. The string is valid until the underlying C string disappears. Example: ~~~~c ALLEGRO_USTR_INFO info; ALLEGRO_USTR *us = al_ref_cstr(&info, "my string"); ~~~~ See also: [al_ref_buffer], [al_ref_ustr] ### API: al_ref_buffer Create a string that references the storage of an underlying buffer. The size of the buffer is given in bytes. You can use it to reference only part of a string or an arbitrary region of memory. The string is valid while the underlying memory buffer is valid. See also: [al_ref_cstr], [al_ref_ustr] ### API: al_ref_ustr Create a read-only string that references the storage of another [ALLEGRO_USTR] string. The information about the string (e.g. its size) is stored in the structure pointed to by the `info` parameter. The new string will not have any other storage allocated of its own, so if you allocate the `info` structure on the stack then no explicit "free" operation is required. The referenced interval is \[`start_pos`, `end_pos`). Both are byte offsets. The string is valid until the underlying string is modified or destroyed. If you need a range of code-points instead of bytes, use [al_ustr_offset] to find the byte offsets. See also: [al_ref_cstr], [al_ref_buffer] ### API: al_ref_info Create a read-only string that references the storage of another [ALLEGRO_USTR] string that has already been stored in the [ALLEGRO_USTR_INFO] structure. The string is valid until the underlying string is modified or destroyed. See also: [al_ref_cstr], [al_ref_buffer], [al_ref_ustr] ## Sizes and offsets ### API: al_ustr_size Return the size of the string in bytes. This is equal to the number of code points in the string if the string is empty or contains only 7-bit ASCII characters. See also: [al_ustr_length] ### API: al_ustr_length Return the number of code points in the string. See also: [al_ustr_size], [al_ustr_offset] ### API: al_ustr_offset Return the byte offset (from the start of the string) of the code point at the specified index in the string. A zero index parameter will return the first character of the string. If index is negative, it counts backward from the end of the string, so an index of -1 will return an offset to the last code point. If the index is past the end of the string, returns the offset of the end of the string. See also: [al_ustr_length] ### API: al_ustr_next Find the byte offset of the next code point in string, beginning at `*pos`. `*pos` does not have to be at the beginning of a code point. Returns true on success, and the value pointed to by `pos` will be updated to the found offset. Otherwise returns false if `*pos` was already at the end of the string, and `*pos` is unmodified. This function just looks for an appropriate byte; it doesn't check if found offset is the beginning of a valid code point. If you are working with possibly invalid UTF-8 strings then it could skip over some invalid bytes. See also: [al_ustr_prev] ### API: al_ustr_prev Find the byte offset of the previous code point in string, before `*pos`. `*pos` does not have to be at the beginning of a code point. Returns true on success, and the value pointed to by `pos` will be updated to the found offset. Otherwise returns false if `*pos` was already at the end of the string, and `*pos` is unmodified. This function just looks for an appropriate byte; it doesn't check if found offset is the beginning of a valid code point. If you are working with possibly invalid UTF-8 strings then it could skip over some invalid bytes. See also: [al_ustr_next] ## Getting code points ### API: al_ustr_get Return the code point in `ub` beginning at byte offset `pos`. On success returns the code point value. If `pos` was out of bounds (e.g. past the end of the string), return -1. On an error, such as an invalid byte sequence, return -2. See also: [al_ustr_get_next], [al_ustr_prev_get] ### API: al_ustr_get_next Find the code point in `us` beginning at byte offset `*pos`, then advance to the next code point. On success return the code point value. If `pos` was out of bounds (e.g. past the end of the string), return -1. On an error, such as an invalid byte sequence, return -2. As with [al_ustr_next], invalid byte sequences may be skipped while advancing. See also: [al_ustr_get], [al_ustr_prev_get] ### API: al_ustr_prev_get Find the beginning of a code point before byte offset `*pos`, then return it. Note this performs a *pre-increment*. On success returns the code point value. If `pos` was out of bounds (e.g. past the end of the string), return -1. On an error, such as an invalid byte sequence, return -2. As with [al_ustr_prev], invalid byte sequences may be skipped while advancing. See also: [al_ustr_get_next] ## Inserting into strings ### API: al_ustr_insert Insert `us2` into `us1` beginning at byte offset `pos`. `pos` cannot be less than 0. If `pos` is past the end of `us1` then the space between the end of the string and `pos` will be padded with NUL (`'\0'`) bytes. If required, use [al_ustr_offset] to find the byte offset for a given code point index. Returns true on success, false on error. See also: [al_ustr_insert_cstr], [al_ustr_insert_chr], [al_ustr_append], [al_ustr_offset] ### API: al_ustr_insert_cstr Like [al_ustr_insert] but inserts a C-style string at byte offset `pos`. See also: [al_ustr_insert], [al_ustr_insert_chr] ### API: al_ustr_insert_chr Insert a code point into `us` beginning at byte offset `pos`. `pos` cannot be less than 0. If `pos` is past the end of `us` then the space between the end of the string and `pos` will be padded with NUL (`'\0'`) bytes. Returns the number of bytes inserted, or 0 on error. See also: [al_ustr_insert], [al_ustr_insert_cstr] ## Appending to strings ### API: al_ustr_append Append `us2` to the end of `us1`. Returns true on success, false on error. This function can be used to append an arbitrary buffer: ~~~~c ALLEGRO_USTR_INFO info; al_ustr_append(us, al_ref_buffer(&info, buf, size)); ~~~~ See also: [al_ustr_append_cstr], [al_ustr_append_chr], [al_ustr_appendf], [al_ustr_vappendf] ### API: al_ustr_append_cstr Append C-style string `s` to the end of `us`. Returns true on success, false on error. See also: [al_ustr_append] ### API: al_ustr_append_chr Append a code point to the end of `us`. Returns the number of bytes added, or 0 on error. See also: [al_ustr_append] ### API: al_ustr_appendf This function appends formatted output to the string `us`. `fmt` is a printf-style format string. See [al_ustr_newf] about the "%s" and "%c" specifiers. Returns true on success, false on error. See also: [al_ustr_vappendf], [al_ustr_append] ### API: al_ustr_vappendf Like [al_ustr_appendf] but you pass the variable argument list directly, instead of the arguments themselves. See [al_ustr_newf] about the "%s" and "%c" specifiers. Returns true on success, false on error. See also: [al_ustr_appendf], [al_ustr_append] ## Removing parts of strings ### API: al_ustr_remove_chr Remove the code point beginning at byte offset `pos`. Returns true on success. If `pos` is out of range or `pos` is not the beginning of a valid code point, returns false leaving the string unmodified. Use [al_ustr_offset] to find the byte offset for a code-points offset. See also: [al_ustr_remove_range] ### API: al_ustr_remove_range Remove the interval \[`start_pos`, `end_pos`) from a string. `start_pos` and `end_pos` are byte offsets. Both may be past the end of the string but cannot be less than 0 (the start of the string). Returns true on success, false on error. See also: [al_ustr_remove_chr], [al_ustr_truncate] ### API: al_ustr_truncate Truncate a portion of a string from byte offset `start_pos` onwards. `start_pos` can be past the end of the string (has no effect) but cannot be less than 0. Returns true on success, false on error. See also: [al_ustr_remove_range], [al_ustr_ltrim_ws], [al_ustr_rtrim_ws], [al_ustr_trim_ws] ### API: al_ustr_ltrim_ws Remove leading whitespace characters from a string, as defined by the C function `isspace()`. Returns true on success, or false on error. See also: [al_ustr_rtrim_ws], [al_ustr_trim_ws] ### API: al_ustr_rtrim_ws Remove trailing ("right") whitespace characters from a string, as defined by the C function `isspace()`. Returns true on success, or false on error. See also: [al_ustr_ltrim_ws], [al_ustr_trim_ws] ### API: al_ustr_trim_ws Remove both leading and trailing whitespace characters from a string. Returns true on success, or false on error. See also: [al_ustr_ltrim_ws], [al_ustr_rtrim_ws] ## Assigning one string to another ### API: al_ustr_assign Overwrite the string `us1` with another string `us2`. Returns true on success, false on error. See also: [al_ustr_assign_substr], [al_ustr_assign_cstr] ### API: al_ustr_assign_substr Overwrite the string `us1` with the contents of `us2` in the byte interval \[`start_pos`, `end_pos`). The end points will be clamped to the bounds of `us2`. Usually you will first have to use [al_ustr_offset] to find the byte offsets. Returns true on success, false on error. See also: [al_ustr_assign], [al_ustr_assign_cstr] ### API: al_ustr_assign_cstr Overwrite the string `us1` with the contents of the C-style string `s`. Returns true on success, false on error. See also: [al_ustr_assign_substr], [al_ustr_assign_cstr] ## Replacing parts of string ### API: al_ustr_set_chr Replace the code point beginning at byte offset `start_pos` with `c`. `start_pos` cannot be less than 0. If `start_pos` is past the end of `us` then the space between the end of the string and `start_pos` will be padded with NUL (`'\0'`) bytes. If `start_pos` is not the start of a valid code point, that is an error and the string will be unmodified. On success, returns the number of bytes written, i.e. the offset to the following code point. On error, returns 0. See also: [al_ustr_replace_range] ### API: al_ustr_replace_range Replace the part of `us1` in the byte interval \[`start_pos1`, `end_pos1`) with the contents of `us2`. `start_pos1` cannot be less than 0. If `start_pos1` is past the end of `us1` then the space between the end of the string and `start_pos1` will be padded with NUL (`'\0'`) bytes. Use [al_ustr_offset] to find the byte offsets. Returns true on success, false on error. See also: [al_ustr_set_chr] ## Searching ### API: al_ustr_find_chr Search for the encoding of code point `c` in `us` from byte offset `start_pos` (inclusive). Returns the position where it is found or -1 if it is not found. See also: [al_ustr_rfind_chr] ### API: al_ustr_rfind_chr Search for the encoding of code point `c` in `us` backwards from byte offset `end_pos` (exclusive). Returns the position where it is found or -1 if it is not found. See also: [al_ustr_find_chr] ### API: al_ustr_find_set This function finds the first code point in `us`, beginning from byte offset `start_pos`, that matches any code point in `accept`. Returns the position if a code point was found. Otherwise returns -1. See also: [al_ustr_find_set_cstr], [al_ustr_find_cset] ### API: al_ustr_find_set_cstr Like [al_ustr_find_set] but takes a C-style string for `accept`. See also: [al_ustr_find_set], [al_ustr_find_cset_cstr] ### API: al_ustr_find_cset This function finds the first code point in `us`, beginning from byte offset `start_pos`, that does *not* match any code point in `reject`. In other words it finds a code point in the complementary set of `reject`. Returns the byte position of that code point, if any. Otherwise returns -1. See also: [al_ustr_find_cset_cstr], [al_ustr_find_set] ### API: al_ustr_find_cset_cstr Like [al_ustr_find_cset] but takes a C-style string for `reject`. See also: [al_ustr_find_cset], [al_ustr_find_set_cstr] ### API: al_ustr_find_str Find the first occurrence of string `needle` in `haystack`, beginning from byte offset `start_pos` (inclusive). Return the byte offset of the occurrence if it is found, otherwise return -1. See also: [al_ustr_find_cstr], [al_ustr_rfind_str], [al_ustr_find_replace] ### API: al_ustr_find_cstr Like [al_ustr_find_str] but takes a C-style string for `needle`. See also: [al_ustr_find_str], [al_ustr_rfind_cstr] ### API: al_ustr_rfind_str Find the last occurrence of string `needle` in `haystack` before byte offset `end_pos` (exclusive). Return the byte offset of the occurrence if it is found, otherwise return -1. See also: [al_ustr_rfind_cstr], [al_ustr_find_str] ### API: al_ustr_rfind_cstr Like [al_ustr_rfind_str] but takes a C-style string for `needle`. See also: [al_ustr_rfind_str], [al_ustr_find_cstr] ### API: al_ustr_find_replace Replace all occurrences of `find` in `us` with `replace`, beginning at byte offset `start_pos`. The `find` string must be non-empty. Returns true on success, false on error. See also: [al_ustr_find_replace_cstr] ### API: al_ustr_find_replace_cstr Like [al_ustr_find_replace] but takes C-style strings for `find` and `replace`. ## Comparing ### API: al_ustr_equal Return true iff the two strings are equal. This function is more efficient than [al_ustr_compare] so is preferable if ordering is not important. See also: [al_ustr_compare] ### API: al_ustr_compare This function compares `us1` and `us2` by code point values. Returns zero if the strings are equal, a positive number if `us1` comes after `us2`, else a negative number. This does *not* take into account locale-specific sorting rules. For that you will need to use another library. See also: [al_ustr_ncompare], [al_ustr_equal] ### API: al_ustr_ncompare Like [al_ustr_compare] but only compares up to the first `n` code points of both strings. Returns zero if the strings are equal, a positive number if `us1` comes after `us2`, else a negative number. See also: [al_ustr_compare], [al_ustr_equal] ### API: al_ustr_has_prefix Returns true iff `us1` begins with `us2`. See also: [al_ustr_has_prefix_cstr], [al_ustr_has_suffix] ### API: al_ustr_has_prefix_cstr Returns true iff `us1` begins with `s2`. See also: [al_ustr_has_prefix], [al_ustr_has_suffix_cstr] ### API: al_ustr_has_suffix Returns true iff `us1` ends with `us2`. See also: [al_ustr_has_suffix_cstr], [al_ustr_has_prefix] ### API: al_ustr_has_suffix_cstr Returns true iff `us1` ends with `s2`. See also: [al_ustr_has_suffix], [al_ustr_has_prefix_cstr] ## UTF-16 conversion ### API: al_ustr_new_from_utf16 Create a new string containing a copy of the 0-terminated string `s` which must be encoded as UTF-16. The string must eventually be freed with [al_ustr_free]. See also: [al_ustr_new] ### API: al_ustr_size_utf16 Returns the number of bytes required to encode the string in UTF-16 (including the terminating 0). Usually called before [al_ustr_encode_utf16] to determine the size of the buffer to allocate. See also: [al_ustr_size] ### API: al_ustr_encode_utf16 Encode the string into the given buffer, in UTF-16. Returns the number of bytes written. There are never more than `n` bytes written. The minimum size to encode the complete string can be queried with [al_ustr_size_utf16]. If the `n` parameter is smaller than that, the string will be truncated but still always 0 terminated. See also: [al_ustr_size_utf16], [al_utf16_encode] ## Low-level UTF-8 routines ### API: al_utf8_width Returns the number of bytes that would be occupied by the specified code point when encoded in UTF-8. This is between 1 and 4 bytes for legal code point values. Otherwise returns 0. See also: [al_utf8_encode], [al_utf16_width] ### API: al_utf8_encode Encode the specified code point to UTF-8 into the buffer `s`. The buffer must have enough space to hold the encoding, which takes between 1 and 4 bytes. This routine will refuse to encode code points above 0x10FFFF. Returns the number of bytes written, which is the same as that returned by [al_utf8_width]. See also: [al_utf16_encode] ## Low-level UTF-16 routines ### API: al_utf16_width Returns the number of bytes that would be occupied by the specified code point when encoded in UTF-16. This is either 2 or 4 bytes for legal code point values. Otherwise returns 0. See also: [al_utf16_encode], [al_utf8_width] ### API: al_utf16_encode Encode the specified code point to UTF-16 into the buffer `s`. The buffer must have enough space to hold the encoding, which takes either 2 or 4 bytes. This routine will refuse to encode code points above 0x10FFFF. Returns the number of bytes written, which is the same as that returned by [al_utf16_width]. See also: [al_utf8_encode], [al_ustr_encode_utf16] allegro5-5.2.10.1/docs/src/refman/video.txt000066400000000000000000000134731473414355200203260ustar00rootroot00000000000000# Video streaming addon These functions are declared in the following header file. Link with allegro_video. ~~~~c #include ~~~~ Currently we have an Ogg backend (Theora + Vorbis). See for installation instructions, licensing information and supported video formats. ## API: ALLEGRO_VIDEO_EVENT_TYPE Events sent by [al_get_video_event_source]. ### ALLEGRO_EVENT_VIDEO_FRAME_SHOW This event is sent when it is time to show a new frame. Once you receive this event, you can draw the current frame (as returned by [al_get_video_frame]). [al_get_video_frame] will continue returning the same frame until the next ALLEGRO_EVENT_VIDEO_FRAME_SHOW is sent. user.data1 (ALLEGRO_VIDEO *) : The video which generated the event. Since: 5.1.0 ### ALLEGRO_EVENT_VIDEO_FINISHED This event is sent when the video is finished. Depending on the backend, it may be possible to seek to an earlier part of the video and set the video to play to resume playback. user.data1 (ALLEGRO_VIDEO *) : The video which generated the event. Since: 5.1.0 ## API: ALLEGRO_VIDEO_POSITION_TYPE Used with [al_get_video_position] to specify which position to retrieve. If these get out of sync, audio and video may be out of sync in the display of the video. * ALLEGRO_VIDEO_POSITION_ACTUAL - The amount of time the video has been playing. If the video has audio then this value can be ahead of ALLEGRO_VIDEO_POSITION_VIDEO_DECODE when video decoding lags. * ALLEGRO_VIDEO_POSITION_VIDEO_DECODE - The amount of video that has been decoded. This may lag behind the "actual" and audio positions if decoding is slower than realtime. * ALLEGRO_VIDEO_POSITION_AUDIO_DECODE - The amount of audio that has been decoded. This may be the same as ALLEGRO_VIDEO_POSITION_ACTUAL if audio decode is driving the position, which is common to keep audio and video in sync. Since: 5.1.11 ## API: al_init_video_addon Initializes the video addon. Since: 5.1.12 ## API: al_is_video_addon_initialized Returns true if the video addon is initialized, otherwise returns false. Since: 5.2.6 ## API: al_shutdown_video_addon Shut down the video addon. This is done automatically at program exit, but can be called any time the user wishes as well. Since: 5.1.12 ## API: al_get_allegro_video_version Returns the (compiled) version of the addon, in the same format as [al_get_allegro_version]. Since: 5.1.12 ## API: al_open_video Reads a video file. This does not start playing yet but reads the meta info so you can query e.g. the size or audio rate. Since: 5.1.0 ## API: al_identify_video This works exactly as [al_identify_video_f] but you specify the filename of the file for which to detect the type and not a file handle. The extension, if any, of the passed filename is not taken into account - only the file contents. Since: 5.2.8 See also: [al_init_video_addon], [al_identify_video_f] ## API: al_identify_video_f Tries to guess the video file type of the open ALLEGRO_FILE by reading the first few bytes. By default Allegro cannot recognize any file types, but calling [al_init_video_addon] will add detection of the types it can read. Returns a pointer to a static string with a file extension for the type, including the leading dot. For example ".ogv". Returns NULL if the video type cannot be determined. Since: 5.2.8 See also: [al_init_video_addon], [al_identify_video] ## API: al_close_video Closes the video and frees all allocated resources. The video pointer is invalid after the function returns. Since: 5.1.0 ## API: al_start_video Starts playing the video from the beginning. Since: 5.1.0 ## API: al_start_video_with_voice Like [al_start_video] but audio is routed to the provided voice. Since: 5.1.0 ## API: al_get_video_event_source Get an event source for the video. The possible events are described under [ALLEGRO_VIDEO_EVENT_TYPE]. Since: 5.1.0 ## API: al_set_video_playing Paused or resumes playback. Since: 5.1.12 ## API: al_is_video_playing Returns true if the video is currently playing. Since: 5.1.12 ## API: al_get_video_audio_rate Returns the audio rate of the video, in Hz. Since: 5.1.0 ## API: al_get_video_fps Returns the speed of the video in frames per second. Often this will not be an integer value. Since: 5.1.0 ## API: al_get_video_scaled_width Returns the width with which the video frame should be drawn. Videos often do not use square pixels, so this will may return a value larger than the width of the frame bitmap. Since: 5.1.12 See also: [al_get_video_frame] ## API: al_get_video_scaled_height Returns the height with which the video frame should be drawn. Videos often do not use square pixels, so this will may return a value larger than the height of the frame bitmap. See also: [al_get_video_frame] Since: 5.1.12 ## API: al_get_video_frame Returns the current video frame. The bitmap is owned by the video so do not attempt to free it. The bitmap will stay valid until the next call to al_get_video_frame. Videos often do not use square pixels so the recommended way to draw a video frame would be using code like this: ~~~~c float scale = 1.0; /* Adjust this to fit your target bitmap dimensions. */ ALLEGRO_BITMAP* frame = al_get_video_frame(video); float sw = al_get_bitmap_width(frame); float sh = al_get_bitmap_height(frame); float dw = scale * al_get_video_scaled_width(video); float dh = scale * al_get_video_scaled_height(video); al_draw_scaled_bitmap(frame, 0, 0, sw, sh, 0, 0, dw, dh, 0); ~~~~ Since: 5.1.0 See also: [al_get_video_scaled_width], [al_get_video_scaled_height] ## API: al_get_video_position Returns the current position of the video stream in seconds since the beginning. The parameter is one of the [ALLEGRO_VIDEO_POSITION_TYPE] constants. Since: 5.1.0 ## API: al_seek_video Seek to a different position in the video. Currently only seeking to the beginning of the video is supported. Since: 5.1.0 allegro5-5.2.10.1/examples/000077500000000000000000000000001473414355200152765ustar00rootroot00000000000000allegro5-5.2.10.1/examples/CMakeLists.txt000066400000000000000000000237131473414355200200440ustar00rootroot00000000000000include_directories( ../addons/acodec ../addons/audio ../addons/color ../addons/font ../addons/image ../addons/main ../addons/memfile ../addons/native_dialog ../addons/physfs ../addons/primitives ../addons/shader ../addons/ttf ../addons/video ) if(SUPPORT_PHYSFS) # The physfs example directly includes physfs.h include_directories(${PHYSFS_INCLUDE_DIR}) endif() #-----------------------------------------------------------------------------# # List dependencies explicitly for loading by Android APKs. set(AUDIO x${AUDIO_LINK_WITH}) set(ACODEC ${AUDIO} x${ACODEC_LINK_WITH}) set(COLOR x${COLOR_LINK_WITH}) set(DIALOG x${NATIVE_DIALOG_LINK_WITH}) set(FONT x${FONT_LINK_WITH}) set(IMAGE x${IMAGE_LINK_WITH}) set(MEMFILE x${MEMFILE_LINK_WITH}) set(PHYSFS x${PHYSFS_LINK_WITH}) set(PRIM x${PRIMITIVES_LINK_WITH}) set(TTF ${FONT} x${TTF_LINK_WITH}) set(VIDEO x${VIDEO_LINK_WITH}) set(NIHGUI nihgui.cpp ${FONT} ${PRIM}) include(Helper.cmake) #-----------------------------------------------------------------------------# # Lists of data files to add to Android APKs, to appear after the DATA keyword. # DATA_IMAGES is a special case that includes the DATA keyword. # Examples don't necessarily use every file in the list. set(DATA_IMAGES DATA a4_font.tga alexlogo.bmp alexlogo.png allegro.pcx bkg.png bmpfont.tga cursor.tga fakeamp.bmp fixed_font.tga font.tga gradient1.bmp haiku/air_effect.png icon.tga mysha.pcx mysha256x256.png obp.jpg texture.tga texture2.tga ) set(DATA_TTF DejaVuSans.ttf a4_font.fnt ) set(DATA_AUDIO welcome.wav welcome.voc ) set(DATA_SHADERS ex_prim_shader_pixel.glsl ex_prim_shader_pixel.hlsl ex_prim_shader_vertex.glsl ex_prim_shader_vertex.hlsl ex_prim_wrap_pixel.glsl ex_prim_wrap_pixel.hlsl ex_shader_multitex_pixel.glsl ex_shader_multitex_pixel.hlsl ex_shader_palette_pixel.glsl ex_shader_pixel.glsl ex_shader_pixel.hlsl ex_shader_vertex.glsl ex_shader_vertex.hlsl ) file(GLOB DATA_HAIKU RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/data data/haiku/*) set(DATA_HAIKU ${DATA_HAIKU}) #-----------------------------------------------------------------------------# example(ex_config DATA sample.cfg) example(ex_dir ${DATA_IMAGES}) example(ex_file CONSOLE ${DATA_IMAGES}) example(ex_file_slice CONSOLE) example(ex_get_path) example(ex_memfile CONSOLE ${MEMFILE}) example(ex_monitorinfo) example(ex_path) example(ex_path_test) example(ex_user_events) example(ex_inject_events) if(NOT MSVC) # UTF-8 strings are problematic under MSVC. example(ex_utf8) endif(NOT MSVC) if(ANDROID) example(ex_android ${IMAGE} ${PRIM} ${DATA_IMAGES}) endif(ANDROID) example(ex_bitmap ${IMAGE} ${DATA_IMAGES}) example(ex_bitmap_file ${IMAGE} ${DATA_IMAGES}) example(ex_bitmap_flip ${IMAGE} ${FONT} ${DATA_IMAGES}) example(ex_blend ${FONT} ${IMAGE} ${PRIM} ${DATA_IMAGES}) example(ex_blend2 ex_blend2.cpp ${NIHGUI} ${IMAGE} ${DATA_IMAGES}) example(ex_blend_bench ${IMAGE} ${PRIM} ${DATA_IMAGES}) example(ex_blend_test ${PRIM}) example(ex_blend_target ${IMAGE} ${DATA_IMAGES}) example(ex_blit ${FONT} ${IMAGE} ${COLOR} ${DATA_IMAGES}) example(ex_clip ${FONT} ${COLOR}) example(ex_clipboard ${IMAGE} ${FONT} ${DATA_IMAGES}) example(ex_color ex_color.cpp ${NIHGUI} ${TTF} ${COLOR} DATA ${DATA_TTF}) example(ex_color2 ex_color2.c ${FONT} ${COLOR} ${PRIM}) example(ex_color_gradient ex_color_gradient.c ${TTF} ${COLOR} ${PRIM} DATA ${DATA_TTF}) example(ex_compressed ${IMAGE} ${FONT} ${DATA_IMAGES}) example(ex_convert CONSOLE ${IMAGE}) example(ex_cpu ${FONT}) example(ex_depth_mask ${IMAGE} ${TTF} ${DATA_IMAGES} ${DATA_TTF}) example(ex_depth_target ${IMAGE} ${FONT} ${COLOR} ${PRIM}) example(ex_disable_screensaver ${FONT}) example(ex_display_events ${FONT} ${PRIM}) example(ex_display_options ${FONT} ${PRIM}) example(ex_drag_and_drop ${IMAGE} ${FONT} ${TTF} ${COLOR} ${PRIM}) example(ex_draw ${FONT} ${IMAGE} ${COLOR} ${PRIM} ${DATA_IMAGES}) example(ex_draw_bitmap ${IMAGE} ${FONT} ${DATA_IMAGES}) example(ex_drawpixels) example(ex_dualies ${IMAGE}) example(ex_expose ${IMAGE} ${PRIM} ${DATA_IMAGES}) example(ex_filter ${FONT} ${IMAGE} ${COLOR} ${DATA_IMAGES}) example(ex_fs_resize ${IMAGE} ${PRIM} ${DATA_IMAGES}) example(ex_fs_window ${IMAGE} ${PRIM} ${FONT} ${DATA_IMAGES}) example(ex_icon ${IMAGE} ${DATA_IMAGES}) example(ex_icon2 ${IMAGE} ${DATA_IMAGES}) example(ex_haptic ${PRIM}) example(ex_haptic2 ex_haptic2.cpp ${NIHGUI} ${TTF} DATA ${DATA_TTF}) example(ex_joystick_events ${PRIM} ${FONT}) example(ex_joystick_hotplugging ${PRIM}) example(ex_keyboard_events) example(ex_keyboard_focus) example(ex_lines ${PRIM}) example(ex_loading_thread ${IMAGE} ${FONT} ${PRIM} ${DATA_IMAGES}) example(ex_lockbitmap) example(ex_membmp ${FONT} ${IMAGE} ${DATA_IMAGES}) example(ex_mouse ${IMAGE} ${PRIM} ${DATA_IMAGES}) example(ex_mouse_cursor ${FONT} ${IMAGE} ${DATA_IMAGES}) example(ex_mouse_events ${FONT} ${IMAGE} ${PRIM} ${DATA_IMAGES}) example(ex_mouse_focus) example(ex_mouse_warp ${FONT} ${PRIM}) example(ex_multisample ${FONT} ${COLOR} ${PRIM}) example(ex_multisample_target ${IMAGE} ${FONT} ${COLOR} ${PRIM}) example(ex_multiwin ${IMAGE}) example(ex_nodisplay ${IMAGE} ${DATA_IMAGES}) example(ex_noframe ${IMAGE} ${DATA_IMAGES}) example(ex_physfs ${PHYSFS} ${IMAGE} ${DATA_IMAGES}) example(ex_pixelformat ex_pixelformat.cpp ${NIHGUI} ${IMAGE} ${DATA_IMAGES}) example(ex_polygon ${FONT} ${PRIM}) example(ex_premulalpha ${FONT}) example(ex_prim ${FONT} ${IMAGE} ${PRIM} ${DATA_IMAGES}) example(ex_prim_shader ${PRIM} DATA ${DATA_SHADERS}) example(ex_prim_wrap ${IMAGE} ${FONT} ${PRIM} ${DATA_IMAGES} ${DATA_SHADERS}) example(ex_reparent ${IMAGE} ${PRIM} ${DATA_IMAGES}) example(ex_resize ${PRIM}) example(ex_resize2 ${IMAGE} ${FONT}) example(ex_rotate ${IMAGE} ${DATA_IMAGES}) example(ex_scale ${IMAGE} ${DATA_IMAGES}) example(ex_shader ex_shader.cpp ${IMAGE} ${DATA_IMAGES} ${DATA_SHADERS}) example(ex_shader_multitex ${IMAGE} ${DATA_IMAGES} ${DATA_SHADERS}) example(ex_shader_target ${IMAGE} ${DATA_IMAGES} ${DATA_SHADERS}) example(ex_subbitmap ${IMAGE} ${PRIM} ${DATA_IMAGES}) example(ex_threads ${PRIM}) example(ex_threads2) example(ex_timedwait ${FONT}) example(ex_timer ${FONT} ${PRIM}) example(ex_timer_pause) example(ex_touch_input ${PRIM}) example(ex_transform ${FONT} ${IMAGE} ${PRIM} ${DATA_IMAGES}) example(ex_vertex_buffer ${FONT} ${PRIM}) example(ex_vsync ${FONT} ${IMAGE} ${PRIM}) example(ex_windows ${FONT} ${IMAGE}) example(ex_window_constraints ${FONT} ${IMAGE}) example(ex_window_maximized ${FONT} ${IMAGE} ${PRIM} ${DIALOG}) example(ex_window_title ${IMAGE} ${FONT} ${DATA_IMAGES}) example(ex_winfull) example(ex_video ${AUDIO} ${FONT} ${PRIM} ${VIDEO}) if(WANT_D3D AND D3DX9_FOUND) example(ex_d3d ex_d3d.cpp EXTRA_LIBS ${D3DX9_LIBRARY}) endif() if(SUPPORT_OPENGL AND NOT SUPPORT_OPENGLES) example(ex_gldepth ${FONT} ${IMAGE}) example(ex_glext) example(ex_opengl) example(ex_opengl_pixel_shader ${IMAGE}) endif() if(SUPPORT_OPENGL AND NOT IPHONE AND NOT ALLEGRO_RASPBERRYPI) example(ex_palette ${IMAGE} ${COLOR} ${DATA_IMAGES} ${DATA_SHADERS}) endif() example(ex_font ${FONT} ${IMAGE} ${DATA_IMAGES}) example(ex_font_justify ex_font_justify.cpp ${NIHGUI} ${IMAGE} ${TTF} ${DATA_IMAGES} ${DATA_TTF}) example(ex_font_multiline ex_font_multiline.cpp ${NIHGUI} ${IMAGE} ${TTF} ${COLOR} ${DATA_IMAGES} ${DATA_TTF}) example(ex_logo ${FONT} ${TTF} ${IMAGE} ${PRIM} DATA ${DATA_TTF}) example(ex_projection ${TTF} ${IMAGE} ${DATA_IMAGES} ${DATA_TTF}) example(ex_projection2 ${PRIM} ${FONT} ${IMAGE} ${DATA_IMAGES}) example(ex_camera ${FONT} ${COLOR} ${PRIM} ${IMAGE}) example(ex_ttf ${TTF} ${PRIM} ${IMAGE} DATA ${DATA_TTF} ex_ttf.ini) example(ex_acodec CONSOLE ${AUDIO} ${ACODEC}) example(ex_acodec_multi CONSOLE ${AUDIO} ${ACODEC}) example(ex_audio_devices ${AUDIO}) example(ex_audio_chain ex_audio_chain.cpp ${AUDIO} ${ACODEC} ${PRIM} ${FONT} ${TTF} DATA ${DATA_TTF} ${DATA_HAIKU}) example(ex_audio_props ex_audio_props.cpp ${NIHGUI} ${ACODEC} DATA ${DATA_AUDIO}) example(ex_audio_simple CONSOLE ${AUDIO} ${ACODEC} ${FONT}) example(ex_audio_timer ${AUDIO} ${FONT}) example(ex_haiku ${AUDIO} ${ACODEC} ${IMAGE} ${DATA_IMAGES} ${DATA_HAIKU}) example(ex_kcm_direct CONSOLE ${AUDIO} ${ACODEC}) example(ex_mixer_chain CONSOLE ${AUDIO} ${ACODEC}) example(ex_mixer_pp ${AUDIO} ${ACODEC} ${PRIM} ${IMAGE} ${DATA_IMAGES} ${DATA_AUDIO}) example(ex_record ${AUDIO} ${ACODEC} ${PRIM}) example(ex_record_name ${AUDIO} ${ACODEC} ${PRIM} ${IMAGE} ${FONT}) example(ex_resample_test ${AUDIO}) example(ex_saw ${AUDIO}) example(ex_stream_file CONSOLE ${AUDIO} ${ACODEC}) example(ex_stream_seek ${AUDIO} ${ACODEC} ${PRIM} ${FONT} ${IMAGE} ${DATA_IMAGES} ${DATA_AUDIO}) example(ex_synth ex_synth.cpp ${NIHGUI} ${AUDIO} ${TTF} DATA ${DATA_TTF}) example(ex_native_filechooser ${DIALOG} ${FONT} ${IMAGE} ${COLOR} ${DATA_IMAGES}) example(ex_menu ${DIALOG} ${IMAGE}) # In some configurations CURL pulls in dependencies which we don't check for. # This example isn't important so it's disabled by default to prevent problems. option(WANT_CURL_EXAMPLE "Build ex_curl example" off) if(WANT_CURL_EXAMPLE) find_package(CURL) if(CURL_FOUND) if(WIN32) # select() is in the Winsock library. example(ex_curl ${IMAGE} EXTRA_LIBS ${CURL_LIBRARIES} ws2_32) else(WIN32) example(ex_curl ${IMAGE} EXTRA_LIBS ${CURL_LIBRARIES}) endif(WIN32) endif(CURL_FOUND) endif(WANT_CURL_EXAMPLE) # Only build the enet examples if libenet is installed find_package(ENet) if(ENET_FOUND) example(ex_enet_client ${PRIM} EXTRA_LIBS ${ENET_LIBRARIES}) example(ex_enet_server EXTRA_LIBS ${ENET_LIBRARIES}) endif() # example(ex_ogre3d ex_ogre3d.cpp) # include_directories(/usr/include/OGRE) # target_link_libraries(ex_ogre3d OgreMain) # This is useful for developers to add temporary test programs. include(${CMAKE_CURRENT_SOURCE_DIR}/local_examples.cmake OPTIONAL) #-----------------------------------------------------------------------------# # vim: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/examples/Helper.cmake000066400000000000000000000060501473414355200175200ustar00rootroot00000000000000# Conditionally build an example program. If any of its arguments is the exact # string "x", do nothing. Otherwise strip off the "x" prefixes on arguments # and link to that target. function(example name) # Use cmake_parse_arguments first. set(flags CONSOLE) set(single_args) # none set(accum_args DATA EXTRA_LIBS) cmake_parse_arguments(MYOPTS "${flags}" "${single_args}" "${accum_args}" ${ARGN}) # Parse what remains of the argument list manually. set(sources) set(libs) foreach(arg ${MYOPTS_UNPARSED_ARGUMENTS}) if(arg STREQUAL "x") message(STATUS "Not building ${name}") return() endif() if(arg MATCHES "[.]c$") list(APPEND sources ${arg}) elseif(arg MATCHES "[.]cpp$") list(APPEND sources ${arg}) else() string(REGEX REPLACE "^x" "" arg ${arg}) list(APPEND libs ${arg}) endif() endforeach() # If no sources are listed assume a single C source file. if(NOT sources) set(sources "${name}.c") endif() # Prepend the base libraries. if(ANDROID) set(libs ${ALLEGRO_LINK_WITH} ${libs}) else() set(libs ${ALLEGRO_LINK_WITH} ${ALLEGRO_MAIN_LINK_WITH} ${libs}) endif() # Popup error messages. if(WANT_POPUP_EXAMPLES AND SUPPORT_NATIVE_DIALOG) list(APPEND libs ${NATIVE_DIALOG_LINK_WITH}) endif() # Monolith contains all other libraries which were enabled. if(WANT_MONOLITH) set(libs ${ALLEGRO_MONOLITH_LINK_WITH}) endif() # Append the extra, non-Allegro libraries. foreach(lib ${MYOPTS_EXTRA_LIBS}) list(APPEND libs ${lib}) endforeach() list(REMOVE_DUPLICATES libs) if(WIN32) if(MYOPTS_CONSOLE) # We need stdout and stderr available from cmd.exe, # so we must not use WIN32 here. set(EXECUTABLE_TYPE) else() set(EXECUTABLE_TYPE "WIN32") endif() endif(WIN32) if(IPHONE) set(EXECUTABLE_TYPE MACOSX_BUNDLE) endif(IPHONE) if(ANDROID) if(MYOPTS_CONSOLE) message(STATUS "Not building ${name} - console program") return() endif() add_copy_commands( "${CMAKE_CURRENT_SOURCE_DIR}/data" "${CMAKE_CURRENT_BINARY_DIR}/${name}.project/app/src/main/assets/data" assets "${MYOPTS_DATA}" ) add_android_app("${name}" "${sources};${assets}") elseif(IPHONE) add_our_executable("${name}" SRCS "${sources};${CMAKE_CURRENT_SOURCE_DIR}/data" LIBS "${libs}") set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/data" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") else() add_our_executable("${name}" SRCS "${sources}" LIBS "${libs}") endif() add_dependencies("${name}" copy_example_data) endfunction(example) #-----------------------------------------------------------------------------# # vim: set ts=8 sts=4 sw=4 et: allegro5-5.2.10.1/examples/common.c000066400000000000000000000047341473414355200167420ustar00rootroot00000000000000#include #include #ifdef ALLEGRO_ANDROID #include "allegro5/allegro_android.h" #endif void init_platform_specific(void); void abort_example(char const *format, ...); void open_log(void); void open_log_monospace(void); void close_log(bool wait_for_user); void log_printf(char const *format, ...); void init_platform_specific(void) { #ifdef ALLEGRO_ANDROID al_install_touch_input(); al_android_set_apk_file_interface(); #endif } #ifdef ALLEGRO_POPUP_EXAMPLES #include "allegro5/allegro_native_dialog.h" ALLEGRO_TEXTLOG *textlog = NULL; void abort_example(char const *format, ...) { char str[1024]; va_list args; ALLEGRO_DISPLAY *display; va_start(args, format); vsnprintf(str, sizeof str, format, args); va_end(args); if (al_init_native_dialog_addon()) { display = al_is_system_installed() ? al_get_current_display() : NULL; al_show_native_message_box(display, "Error", "Cannot run example", str, NULL, 0); } else { fprintf(stderr, "%s", str); } exit(1); } void open_log(void) { if (al_init_native_dialog_addon()) { textlog = al_open_native_text_log("Log", 0); } } void open_log_monospace(void) { if (al_init_native_dialog_addon()) { textlog = al_open_native_text_log("Log", ALLEGRO_TEXTLOG_MONOSPACE); } } void close_log(bool wait_for_user) { if (textlog && wait_for_user) { ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue(); al_register_event_source(queue, al_get_native_text_log_event_source( textlog)); al_wait_for_event(queue, NULL); al_destroy_event_queue(queue); } al_close_native_text_log(textlog); textlog = NULL; } void log_printf(char const *format, ...) { char str[1024]; va_list args; va_start(args, format); vsnprintf(str, sizeof str, format, args); va_end(args); al_append_native_text_log(textlog, "%s", str); } #else void abort_example(char const *format, ...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); va_end(args); exit(1); } void open_log(void) { } void open_log_monospace(void) { } void close_log(bool wait_for_user) { (void)wait_for_user; } void log_printf(char const *format, ...) { va_list args; va_start(args, format); #ifdef ALLEGRO_ANDROID char x[1024]; vsnprintf(x, sizeof x, format, args); ALLEGRO_TRACE_CHANNEL_LEVEL("log", 1)("%s", x); #else vprintf(format, args); #endif va_end(args); } #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/data/000077500000000000000000000000001473414355200162075ustar00rootroot00000000000000allegro5-5.2.10.1/examples/data/a4_font.fnt000066400000000000000000001063011473414355200202530ustar00rootroot00000000000000 allegro5-5.2.10.1/examples/data/a4_font.tga000066400000000000000000001476751473414355200202620ustar00rootroot00000000000000 A EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEETRUEVISION-XFILE.allegro5-5.2.10.1/examples/data/alexlogo.bmp000066400000000000000000000265521473414355200205330ustar00rootroot00000000000000BMj-6(4)      !  +  5  9!?##'&!E( L) *$'%+#-"Q/ W/ 0&+-+3#6'd7 ^56,#6.243:,p= ;3j<=/$=28:8@0C/pA}DxD>@?G4,H=K M:MFHGQ:T T=UWMPN%YA'[C7XH]$^H_]#TWUeac!d!*fIhe#i]`^k=gUkh)k$*mRsto$p$.qVehf}0uSr*+vUwwyt.-xXu..yYy"/zZv2lomӁ}#0|[Hxc}*3^},̀*хՀ+svtς-ф/3Չ"҅2)!łG߄8҃@ԇ4׋'݊);gz}{ٌ*Sl2׉8ڍ,ۏ.ڌ=ܐ/3ݑ1ގ>ޒ3Ep5ّA7iE;XxܔE<ޖHC=@KC֚SXCNC_W|EPG۞YHSJޡ\QYMOQcZSIVUgd`YnycYb`mrt㷔꾊yà|ǣ~ɥyʩǏơɗ~ЭѬ϶չھc '6#JG#$5GTQTB" .TQ4 4QVQT=!BUQ3JQVVQT!GQJ  .TVQQ]dz]VVQT4 =VQG K\ GTVQVdz]VVT4 JQVdQVG  *-,$w )V]i]QVT.#VQdidQ G ۮ+Xuqsb\  BYVV]o]VVT.BV]zdQVB~qsqu~- JVf]VVY)  TQziioz]Q TB+ Lb3{ sqsg ZVd]VVY#.T]zizi]Q '{sb,{sqsqs{,2)V]z ]TVY!JVdziiziiz]QQV%'{qs~qqssPguqsu;=V] ]VV[V]oziizod9gqssqulPuqs{39=TVV]]VV[.V]zw-lsslX ! sqsb E 4YVVd`VV[ GVdizoK7'7@* *:ussqu$ K =TVVoZVV[ QV ziizi?**7 0 $070Puqq~-CbggbbL+ 4TTZZVV[#T]ii37$ 7 ~qsuP Puqs qs~b E ZZ` ZVV[BTo ii0770737*XslPuqs qu{X3 VTV ZV[Zo\ 77  lqssjCg sqb$+.[TTQ)Yf S ! h7@usus~F  GYoVZTOJTo \E73qsqqub*O] TZYGV] ߌ 77 jqqsqssCS G[TTYG)V]ioiiE7 XlsuqjsuusqsquLE=cTTYBBTd %|jX;;qsqs{b3  3Mu{qqsuPS_ TY[B OV~ssjjqs-+EE9 CusqssqssX`o TT[=[] o~qqsjbsqsX92Fqsqssqs@=c  TY[==Yo 9A~ssquPbssq   gusjE_ YY[GYTxusqs~* 9bsqsquC  JY [V=#_f^qsb? \jsqss{ Bf[Y[YOB)GYo qsu7 E~qsq{,w4_ o[Y`Y[[B  V[ 8lqsq  CussuHE.Yf[YY` [Y[eO4 /ZfwlsbSlsb+#Y ofY`[[ZOBGYo2~qsX bssqbY  of[[Y[Y[_Z4_Y ^lsX?XsgZ  of[YY[__G6 VYdilsPSPsb Zo  o]Y[ VO=#.O[[8lsP EPssqb+Qff] [ __[Yo|lsP XsquPEBc of[Yf \ qsP jsq~ .c  oc[o &qsX 7uquMk oo  AlsX sg w v  lsb Xuqu 9 `    SlsjE Csq{7Gx2lqs{- *qquC 4t  NlsuP 2*lsuH#e  ls{2 wlsuP_ lsq~- bsq@ Wx  lsuP ?3~b% GolqsuX  $@\Bc ~qsq{C wK 6_  &qs~S _w'qsquC\ e w'qs qsb -@C;+Ot'qsq{CjsuP 4t'qs{*Luqssqsb nx&~qsuC;{sq~*_ c_e mxuqssqb{sqssq{CI oe BG]_er lsLPusqsX S/p me>#=]vctls u- lqssqub _meOBkeceols{$$lsj h We]  (IW_er cls u*$lqsqjGm ecc] Gk [2N~qsu@js@@ 6k keek/=m _Klqs b *~qsq~+ p eekBO x[ls;Husb K ] eck]! Vϛls 'Xsqqsb2 4} teen![KE  lsq{gssqsu n eev4")t\%S''?qsqb Cjuqq{3 W ckk] D075! !*373* qsqu7buqssL  4}tkkv W? 75!7757-| suX lssquP eecp>  v $7:! 73^ sb Lussqs3   ] ekkO"}$7 ! 7A suXbsC Itkc] D$7 $773 *371qsuC !~qssqs7 "tkkp/]!7 *7$\9'7lsu* gsqsb+ ktkpGm277 77lqsqb Psqsqsu >,ppv p!073$ !!𫪑7*lsqsj C{ssqsj n mmn6/ph$*30򪭭kt%7|{qsl$P{qsqss  R }ppkD}-7'Ekkv8qsX*jsqs{  /t kpp(R $70?kpn {squ~{sqsqsj _}ppR O+$779 tkp]|~ sqssO} ppcVS*771ïkppIq s#y  }pn6_ 771ïkpp>9lsqsb%f  ppkt 93*wp)Alsquj9/  ttn>}?\᯴tppe\lsqsg 2 epDkmp] qsqsb%D }ptvýpmp]28~qsq{  kſ pptpI2 {squH Wſ t}ptn61{s~(y }ptlsb+f  tpp?N{qssX9( ttpcE^lssg9 ]  ptnI |lss~2>} vt׮S XlssqqssgXLXjqqsu ht\%  P{uuljjussusqsu7.3@CFHLLMPXbbl~u{l@  *;Pu~sqsX ] -jlquu{{u su{C  -busqsqj>n  b~ubP; *7CLPXPL7 *:;-  Pjusqsu;2 t F{~P*,7-$  :b{gP@L~sqssuXp  C{L;b q jXMC@;;CXlqsqsqqg- jsqqsX  n 2- 7b~~usqsqsu{u sqs~j37Xu~C } 'Pj{ PPuuqssqsqs qsuH , > P{ssuLgssqljsqssCW3{qssXXsj-'lsq{CS\y  XussX @su33ssq squ{uuqqsq{C2E ];{ssub7@guuXHLbjjls qsqjP@CPglsqqsb \%2>y suXusu{{ssl%2 *FX{uus@*P{s@+p*CsuP {sqsqu3HXK@usj$ Iy"1qs~Xgjj@2 E Psj+K f,jPEwKE*uqsj \SE ?K2w Ʊyy sq-K ˱yKh KMussHh Wyw 7~{~P "y ɧyyhS C@*  (pyy??  +?%2 D Жyn SE 2Iy+"DWcɍyyt +\+">Wyyf  ?hS%,"Ity yyWw 9-!/IWmyI.% >]yy<8((Ityyy}9,/DWmƜ>91  >WI:5 >Wttf):9;=>allegro5-5.2.10.1/examples/data/alexlogo.png000066400000000000000000000154571473414355200205430ustar00rootroot00000000000000PNG  IHDRsRGBPLTE     !   + 5  !9#?#'!& (E )L*%'$#+"- /Q /W&0+-+#3'6 7d5^,6.6#342,: =p3;4G=H,K:M MGHF:QT=T UWNPMAY%C['HX7]H^$_#]UWTea!c!dIf*h#ei^`]kUg=k)h$kRm*st$o$pVq.fhe}Su0*rUv+wwy.tXx-.uYy."yZz/2vmol#}[|0cxH*}^3,}*+tvs-/3"2)!G8@4')g;{}z*lS28,.=/31>3ރpE5A7iE;xXEe`g3`>sfʔ2_$+ ?Ws`kꬕi~Ⱦ54KVmٷ V?xx{=PXXݶ7nVkN0ϴ+Urݦؔ]?eK֤my}w?l*B 8qO܃: 1{7>J~ƍ Ӽ)vot'ƀzgVpo[N\q$%M{RGOhՁ}fUZVolEzGG ><{F837C{-KN5A^#pN[pF( |A~O[ݼ}ӕykz2(}'Zp)pG`g x?7igmѯutt,,<<3h%E+wHxx۠^ B| &#)FޙOpB+훮qΧ::Ha;D͛@iH%wzȤ"з<]X=BMH`Q_ 'ӊ߼afYChhs]vMoo?]X08^3 JҚ 9hEY@ 1ڎrxžnFb5"H B&)> fs:}QX<~HT=!jy`~0'yTqp_w덲P^߳g:V枾uk$`K Wytvbި0&^/fGXd4c4%27XpLc$3*~ w.rF46hT$FO&Yl,7_ӑo iM<]XlsA__ qEtF4NZgH>='@WZ9m:L:(XC);/e`u4f%Ny |MVؘ\$7zy2Ђ\ d$ʏM@BLzآM"!W,UЈdİ0E(XHo;5xSRuV(^]<^l!QcX#6C/bAH*FeD%L9IE Fc:6gt"W/AȨ-Ai|L"Kb"dy1fP_%r4OTmryM;.m፦xoj4ürN{!(*6II/Pju~є:'T\f,EB= kwNΌ(PZ$_VQpM]@op¹+H՜2zZ rI Hړc9ܕO|-y|g;З$2eFݏc.yӇ PVm3iBy;xds੗yL>7]+N˹sZ5SΙD׾ݯH90rD F={\"cRze''$ я9'Gݎ9+:>Ob/:wc@ٳg[wj O3i>Y`=9ݫ ;Ϝ?Jޗ<ϏinxEf.wvZCՂNUZv0+"E_Y'M2 Ϣi8>[?:߂:Jb/h]6&;g}.r PU[[!<3-J@TZ<Ν1 qc2;h ).C1O@hsEfnrҌpy^ l*W(ni-E,3 //4良39癝ڭϳZ J3ȲK .I2,*bzZwti$P-OD,"kBED$Y^U;~Ã!]𰥩 m@? B%o$7M `ӎ Ұe Zv DKϴ׹/Ltf MMy{}RxD AD7P"rhtm>,]h3}RiTܹ3N tI%oU9Aw ],koZ#DA,ny3>]0߲MWQ{(9I` syY*.ҪSsר~(s_ Olѭn+`sδ[1kj'-XB,kۆ3}<4sF-6,p2lkllj~, 6E(IFb(oвz:cܟXU5!P cBj _X@/Q->`הZH %GOUwk[ a2# 7Yͬ&jS -HmV&RjmkɛT β)̬Gyz{t䥯"nswWGG6|#dP$qeZ Fgxlu6w~p|_LĴQxwD@uv8 }BgMMՃ=vr5d/.nxvi+tW5?rr9rr`h/"6~ɐY=AvZ`4 A&c=:0gs_p8Ajv Ro ZG] =ظъpGJǃ@8=[}n{эObf:^lv]T}і;zf<^uvc<2;CϡCtR_l;-U摉{(PtBN/X%E8A:lXv^XբQGFin<,[V <#!n{P>}2EսDN ɯm+CMRc:\(tWԒpj!62aW&8k^my޻wƺ'̢xNiu>*'Gp"gqO>jXF14zĚϒrtb-c|@w%w;'Y&9t" ve` ~į ]^.D&xeL ']eNMs^YЃ o~shP\`;EH9krTteA^IV S2WV#O)~=aC gvjy҂~ż+xϫ$DvWυ9 #-## ~^W* LMUn${m(@E%¥N3ߐ*+^I֝+37,Eﹲ(Z]v׃iWF\ā@`쾷 GTa}l\g~n͑⯬{C 5YJe+]\~low!gEsWNؒp^8O`Yt!+_QIO: D@/'z7,QhfxrƿFc9JKY:W[^7 ,X4/ߍO 虑'4N>JCE4>kKFJ|Y;9t|/LCА N*"Djyc#z9D^nژ(\)8]r#b5/꧿gE .ȕ+??,pbhZ>)Ilk ;CBsj}U \`n_2@!U!KRssEz~0*J5y饒Z anO-@P||-;f|L4bPWQxBBtyxLUcaEV }\7'X6NѪyU6?xƌ(,oMРШ&r RFh"U7{}v'ǵ0UUb` R?k5B44KI \ō^qkj+oV1J*f/9tc^5G  ;t$u|XX+/_Hp$r 3%gvk+]^\ֈ p `*sB7R1z3R%ve wɆq `IL`/ ? %@hu9lfoJBv(M38a 6o`Rt)=O$@j~~ީ*\1JRUN ).` 73όٟ`axoukPOHpcwBZTx>=9wl޼c`L$xiF@RR@dīss``»FɃeԍveֵWTfWbFj[ǯJJ rXf C>~̺GS wCY`G'E`W`H,c!S*Q%Șk +U%vŸ;gIUx\ r:?Sp?SDwR4~H;jJ͸;hY?Ɂ\=Ha]mA (%XڱQ>E&~1?"X4,E9%ֺF,d^@';(<.,MRG1e\ ] a|0Te6`Mƕ۱c#O.IَN1'vBj)Q%O䍛)~rKU6w(\֫ cXfV<5be_?@O|fB@$""bQn2QeX UKv ~D`'O.wL~F5tfF¯Lb&@:k Q˒ ;wg1Oÿ|Py+k<ٟyr>FgvyDI5c' tX/x{Odύ IENDB`allegro5-5.2.10.1/examples/data/allegro.pcx000066400000000000000000001254061473414355200203600ustar00rootroot00000000000000 ? Yesph`XxH@h@@hHHpXX``hhppxx@(00``0PP(888HH@PP@HHHPP0ph@xp@phHph8p`@`XPp@hXHXP@xXX Ĕè»꧓ú »Ú °oFš®” ûû“Ѯє˺  ù˺”Ôºú ºєƔúº ܹºƔºĺº ߹o”ѺǺº Moʮº“  ߹Įºúº 仨Óm̺ ùºѮڔ”ѮѺ Ч“ºƓѓē”  o꺧Ómm“ד­ѺÔ §úѓím׭­”˺ M o¨ºѮĭwmím“¶w“úє M FçºíĐwím“¶šź M8M §öÐwÐm­m“׶ȃѺѺ M¹M ŶwÐmºĶ” MM oܹ趚Đw­wmѺz› MMMo¹ܹ¦¶šwíwm®Û M¹MxMooךѮmÐwíwm MùRÌRMM8oד®­ȐĎkwޛ ¹FRRR™RMoדºwjkwmƮ”  oùFRșRŒܹדѮw֐wØjwm“®®Ô Ĺìl¬¬RRRl¶­׮Ѯ­w¶ÐȘwm“”Ý  ¹FŬǬ™l¬°®íwƐwmÓԝ  oF۬řƬl™ùoðךw®íwÐŐmœº”  o¹¬™ìĬlìĨאwmmИȭšmšÓº˧ o¬¬™Ĭ¹ìŦl¦ꧺѮmw…ʛm·ÎЭ׶šÐЧº¹¬¦¦Ĭ¹¬l¦“Ѯm®׶wm›m®ַjiȐ֭Ѯƶš¨˻ùæÏħÚw“דm®ݮwm…yʛݮ·j^i֮Ѻ׶קק軺Úöק“ēúmšmímmݛʮַÎyśݮ֐^i֭®Ú¨»®mw­­׭Ůݛʮšmmm…bmíÛ·Ďyz­ȃ^ÐÓק§ݮwŭ®Ѯ·mmb·yʷŽ·Îʛ֐i­§¨§mwĐwmʮmb·yʮ·mbk÷ʛmi^ק˨§mwj÷ymb…·…·›÷kķym÷i^öק˺ޛmƎ·Žk·…·›·kk÷yʷÃĶקѺޛmb…ŽmݮvivĎk…yʷÎk÷ym֐Ãȶד”ºޛy…b…mʷv£i‰vŽvk·yķ·ʛym֐^îޛy…mʛʷkv^iÉivkʛ·kk·ʅb÷i֮­ÛݛʛzʷkiÉiŽk·ʷkvkvkŷk…÷͝wRyx{zޛzmviʼniÎķʷkvkŷkb···ŽwRyxx{zޛzm÷£ĉivbķʛ÷…kηk·Ʒz{wRbyxzx{{z{zzm…i£˜v·yɷŽkÎbkvk·ŷśzwRbyxzxz{z{{z{zzʷkķƣiŷ÷vŽk^ikķyʛy›wR5ybyxyzxz{{zzzʷjm·v£i·ķmm÷iv^i^^vybƷąʛw5EybP]byxyz:zxzz{zޛޛzʷk÷m·ȘģȎ·mޛy÷vi^iG…bkvkb›{{wR5P]byxP]:|zxz{ޛޛmkjƷȘ£¾ķ…Ûy·vi£i^iÉivbvkb…ʛz{{{wmR5P]byxP]:|]zxÛÛݛ{z››ʷŎķŽ˜֮ybm÷v^v^i·Žkb…byz{{wm5EPbyx]:zxƛyb{zޛʷĎk÷m÷k^vk…kviv·…yz{{wm5E`]byx]:zxyyb{zyŎwm֐ŽŽ֮®֮·bkjk…bk÷ʷmyz{z{{{Øwm5E`]byx;:zxyyby{zŎwmַȾȎȾȷ÷Ѯ֮ĎjŽkb·ʅzz{z{{lØw5E`¤ubyx:zxyby›yby{zʅŽmÎȎþ¾¾Øַ֮ÎkjŽ…ʮ®mzzzz{{{lØw5E`uǝbyxzxbyzʅĎȣ¾àiȎ֐˜jĎm÷Žzzz{lØwE`„u_ĝybxzxbyz{z{ʷmŽw£ȣâĩ߉ȷƎ·֮ѮȎi^izz{l|Øw`u_bybxzxy›z{z·y·m£ȣ Ġe‰i֐Ʒȃi֮z{z{lˆ|˜l˜wÄu_u_Ȩmbyxyzxy›zz݅mmâ q~qŸeŸ~ĉ֐÷ȣiȎ·›z{z{lˆ|lŘl„u_Ǩ»mbyxyzx›yÛyzzm··~ĉqqeƟe~âȷ֮֐Ȏmmśzz{z{z{{lĈ|lu_¨»èû°mxyzx›zzzmw֐Ȣ~q~q Ɵe~âַ֐ַ֮˜ַmymzz{z{z{{lÈP|lu_èmx>xyzxzzݷ¾eGqeà©Ɵ~m˜m…b…mzz{z{lÈP|lu_Qoomx>yzx›zzʅȾĠeGq~àŸ© mjmbz›zz{{lP|lu_QùFoomx>yzxַ¾qeGqàq UmwÎ֮ʷmb›z|zz{lˆPÈlu_Q¹Fomx>yxPĈ֣ ~eGe |€U®·mw›dzcd|{lPDĈl_QoFo¹mxyx˺“]PˆÀUȢeGeŸŸ UÀUÀĮcˆÛ|Sd|:|{lPJgPl`_QoFʬF¹ܹǬmx yx§P]ˆ€DUeGAGeDUU€Uˆ›|Sdc;P;:|:{{lCgJgDgPPl`QoFìlFŬ™lmE  °yEꧨºP]PÀDDeAGAGAGeGeĕĞUĞDU]ž||ˆSc:P¯];:|:]PP{{lgCgJDgPˆl`QKFŬFì™lŋmE yEl¶JĈDCDeAGeGeGeОUžUiÕ]|UVPUScPˆPP]:]:]PPU{lgCgJPPˆl`QK`oùFFìċlm`E`y`EܹЧll\JÀ菶CCDAGeGeGPeGÆÕCeĆPUUĈˆy€ÈˆPĈP]PUUUlgCgPÈll`QKhoܹRFĬR‹[™Rm`hy`¬¹Z\JgDNjVCDAeGeGeĠȆGWVÕC՞ÀÈP]ݯȀˆP]PPÈUlgDCgPˆPlæl`Q`Kho¹F¬R¬ċ۬¹mh`hMyh‹ܹ_Kg\ÂZÂZ~ZeCgDAeGUeAGe© W†VAGWq¢iWņ•DÀUcɀUÈP]P€UlˆgDgPlæl`hBho¹FřÙ۬mhKhRyhĂê鬏KguZ}àe\gßeGeVeAGeşWVWVWVAėWVWVÆDDJDŀUˆPˆUlĈgPlhBoFș¬۹mh`hό[yhġÿz`\鿪łZŠC eGeVGAeßWVAeŸep‡WVwDDÀˆĈ€UÈlDĈgJPl`hBĹFìFì۬m`h`hܿy`h¡Ϊz`h\ۙƪ³ZĩeCeAGeGeWpWAGŸNp‡WVŽCDÀP]€UUĀUlDĈgPlhBhBƹ¬m`h`y`hǿΡzĠğWCeAGeŸpWNpWAGeNpW££ĞDžˆPĀUUlDJÈgCgPlwlBè¹ܹìm`h`۫yh`ǪyzĽéCgeGAGeŸNWpANpW¢ľ\•CÈňÀUÀUlDJˆCgPwBǨ۬¬m`h`ǿy`鿡yzCPĀDž˕CCg¼†CAGeNWpGANp ¢Kņ•žˆPˆ€UÀUlwBŻìm`h`y`یګ髂yzJDDdžCȆÕCĽ¼†CGAGeNpNeGANpNeàľWVC†C†PȀUVlwBhB°oìÙm`y`ی«ygګýàĽAGe½¼†\GAGNpNeGNpNGeߢpWVCÆVˆPĈUVlwhBhBhB°o¹F¬lm`h`Ρy`hڿڡZygΫß ľGAGeӽنVeGAGNWV©eNpNpGeq~NpWpWVWňUV†lwhthBŰoF¹l‹m`h`hαy`hΡygųŠ©êĩeAGeŸ̼ÆeGAGApWVŸeGeGeNppWeGeqqNpWňÀU†ÕlJP]P|:|:|:|lwtLhBðo¹Ëmh`hγybyhګyh~eŠé GAe¼ĽeVWVeGepWVeGeNpWVe ~NW†ǀUžžUlJ]PȈ|:|:lwLtBðoooܹËmh`hγybhBhοyheǠĂĠeAe½ŸeAGWVC~qeeßWVàećpWVWŸeŸqNpWVǀUƞlJ]PɈwB°oܦ‹mh`hnjδybhBhŸery\eşŠĽAGĽeŸeVC~ĠWV âqećWVÆVWeŸqNpWVWVƀUĞlgJgJPɈlwLBܬlmh`KNBŒybNBHGAGeryeß½ ĽeAGĩeßeğeVCUĢWV̾~e~ĆVņVeq~NpWV•{ŀUĕUlgJPˆPPĈwlwLBH‹m`K`KNŒ¡³bybNHeýyŸý ĽeGAGĠe©qĠ~qCVCžU¢ľi~qĆŕŸeqNpWVŀU•ƞlJDgJgPlwLhBH¬ËmKh鿡f³bNHà±óyVéý}³½ğĩVyƉ~qCU¾¾þi~~eƕee£p‡WVCJÀUĞUÞUlJgJPlwlwLBHBFF¬ËmK`h«ÿΡrbNhHfZfr}yb©½©éeŸeĩy¢É¢qeWzVÆVWƾ˜ȃ¢~edž•epWV†•€DƀJŀUlJ]PwlwLBHBoF¦‹mKNK`h¿¡³rbNhf¡r}ybNɩeӾğyĢ~‰¢~eWVzeGeŸeŸq¾ȎȾĠqeŸeGĆWV†eGeȎpWV•JDJ€J€DlJ]PwLBHBFًm`K`h[«ÿ³rbhÂ~ebyb¼©eeGe¾Uyq~~KWVzeGeßeGeľ¾ȣ¾ĠeG†•WV†ŸG¾NpWVVV•JDJD RlJ]P lwLBHB¬یm`K`h뿳rbhÿóeGyb©eGeGeày ~q~pVzŸeŸeGeľȃ£¾ĠeGeŕVeGe¢pWVC†VžJJÀÀU RgJPlwlwBHBH¹ڿm`KhB¡ámbhο¿ó}eyb}ŸeGAGeŸebyâʼnWVzqeq eqľ¢ĠqeGeޕVeGe iWV†VÕUΈ RglwBHBHomNhBġ«ΪmbBhgƿó}bybeeGebyľ¢þ¢WCz~eq~qeqqľq qeGAGe•WVeAGeÉipWVWVĆVP] R\g\glwHDHomBNhB«ΫêmbBhgΪZbGeGeGebþ£ľVz‰ľþeq~eGAGÕV†GAG~^iWV†ÞÕ: RNKpK\K  lwXHHhHomBhB¿ο«mbHBhgl¶Ū‚bľȘÃWVz~qeGeGƆAGeivivWVCDU€: Rt`QhBN  lwlwBHXHBHۙmBH¿¿ګmbHgö¶łb¾Ȏ˜ȃ†CzeƆAivkvVCU;@į@Ư RKaR   whBhLF¬™mXګªmbHgך¶Z¢‚ĶbȎV†zŸeĕCCAvjŽ·CDDˆPP@;@¯d] RK` lwKLlmWN¦ڋmbKBJ¶ƒĂ֐bkbȾȣ~ŸVCz†\ĀCAivjހJPJP]:] Rh`hlwmDmC`mbhg¾ȘַȎbkb£¾ľ¢qeU€CUDzi^{JP];:] cc `hcJcܹ¹Dcc€J‚ĦC`c¸¥SÂlhgȾ˜ŽȎvkbĉȾ¢e\UzDJUDUGAGeŸpNpWV£v{{JcP;|:|:'('0(%0?01=0<0<0=?<=<=8E`Q`_M‘x0,0,41Mx539343E3584E53E_QMxn0=?0=?=102%(=601=194MMFtRÒxa`RhsZYf—ՌësŒhI}´³rñó´r³ýeer}~}r[Yf}~e}Ÿ}fZfYRM10''#'00'+#'#"&!$#'#"!"'!#'#"#"&"#!"#&'#&#%#%#012010?01?1o(01=0163106389M49484’9<@=12=0n7?=daQata58496x7x‘x1dd=nM3979=?@<@?=>Ea`Q`Q`Q3896’‘1ndn¸@##=@=9dSdn=@>nEua83M=2=<2'%#<<=M8x’x8M1M13MaRsI[Yf}fr³¡fY[´Ľ³}rY¡[sssILa8M0'#$#'#$"'#'#"$'#"#'#"%#'#'#%'%#'!#"!&'&#%<36n49345`REME85R5RE9M7n9716M46n149‘xnxdx9SEdn97nd99777n@<22@<201’xSxu5xuExn0=<><=<#%?=xEaLR=0M1M8RLŒs¡[áYYr}~eZf}r³š[sIsILRx0(#'#$#'#"'#'#"#'#'"'#"#'#'#'#'#'&#"&'#'%364M9xME5x45`R5R`585FR5M79=@>2#0<=<22<=<==9xExnnx81M8RF8R8Rs[fZr[IªªôƳ–ſ[IsI[IIaM10%+'##'$#'#'"'"'#"#'#"#'#'#'#"'#'#"&#&'#'%'4143Ex85E85R`5R`F5RQ_E96d7x96M4396n79n7d7n7xM„‘EE1cn7xSEuEd<><@<@=@=<@#'26n799d9’9SxEd<???#'==xEaEx9n0M301M8RLŌsªRsŊsê[–ár}rfrY¡[IRMo'0+#'#'#'#'#'$'"#'#"'#'"#'#"#"#'#'#"'"'#'#9M5`F5RE`5`aRaEEM8`uEɸ=64M’xax4M4d79d79d779ua„7S9x7Sx_`Kt_uMn<<=>@<@'###21x9uauEx’Sdn=@<@2<<><<(0(0(%'#0'010141453435x460oxMRŒI[sR¿rfrfáY‚RFM8310#'#'#"#'#'#'#'#'"#'#"#%'#'#'#"'"#'#48`Ra5R`aR5xE8xaxM=1n946M6=6M45E9x96M989Mn=(=6<0=0o=16=1=39E358499n491n<0?o1(01'0=9dSESdd=@<2<0((0'0#'#,',#',0,0,0614343410+#'0MaRŒIÌLRR[[RFaM13o13o/,10#'#'#'#'#'"#'#'#"#'#"#"#'#6M9Mx8E`R5RaE8M9M916=01n16M49Mn6M9M9MxM4n6nMnME’9Mn==01641n=6<01=8989nMER5EMn1<1=3>2>2%=?269=2(60(%'('#'#'%'%'%'%'%%'%'%'#'%'%'#'#'#'#'#'#%'((=610=643631=(%%%(=6<969E9nĜ>2>2%2=62=960=(610('#'%'#'%%'%'%%'%'%'%'%'#'#'#'%'#'#'#'%(=0106413616=(%%%2=<969n9nœ>2>%(=2=62=2060%(0(%(','%'%'%'%'%'%'%'%'#'#'#'#'#'#%'010601610=%%%(2?=?=Ɯ>7>œ222(=(%6?26=(1961%(%(0'%'#'%'#%'%'%''%'%'%%'#'%'%#'#'%#'%'#'#'#%'0(0=(010160=(2=2=?=?=?2?22>Ɯ>77222%(%=0626206(%=(060(%(0('%'%'%'%'%'%'%''%'%'#'#'#'#'#'#'#'#'%%'0=0(=0=(=(222>Ĝ>7222%(=2=12%01%=0(%(0(%(0(,'%'#'%'%'%'%'%'%'%%'%%'#'#'#'#'#'#'#'#'%'(0=(222>2u7222%26=020((1(%=1((10(0(','%'#'%'%#%%'%'%'#'%'#'#'#'#'#'#'#%#'#'%'%((0=(=(277>2>222%(=26=0%110(%(0('(0('#'%#%'%'#'%'%'%'%%'%'#'#%'#'#'%'#'#'#'#%'#%(0=((=(227œ7>22222(2(06=2(0%1%10(%0'%,#%'#'#'%#%'%'%'%'%'%'%'%'%#'#'#%'#'#'#'#'#'#%((22>7œ>2722222%((0(6161(%(0(=10(0(0(0('#'%'#%'%#'%'%'%'%'%'%'#'#%'#'#'#'#'#'#'#'#'%(((2>œ>2>œ7œ>272222=(('(=021(201(01(010(0,'%#%'%#%%'%'%'%'%'#'%'%'#'%'#'#'%'#'#'#%'#'#'#'#'#%%((2>2œ2>2>œ2>Ɯ7222((('(202?6=101=0=010(0%0,'#'%#%#%'%#%'#'%'%'%'#'#'%#'#%'#'%#'#'#'#'%%%2>2œ>Ü2>2Ɯ222=%=0(0(0((2062<=0=0=0=101=0('#'#%'#%#%'%'#%','%'%'%'#'#'%'#'#'#'#'#'#'#%%%%2>>Ĝ22?œ722722=?=((0(%(0=0(2?0?<60=0=0(10('%'#%'%#'%'%#'%%,#'%'%'#'%'#'#'%'#'#%#%%%222ǜ2227?227?27?22?=(0((0=0?7<7<101?0=0=0(10=0('%#'#,#%'#'%#'%'%,%%'#,#%'%'#'#'#'%'#'#'#'#%'#% s[ccSc{s[Skskc[{KCkCCkKKs[[cckkss{{3;C#+33cc3SS+;;;KKCSSCKKKSS3skC{sCskKsk;scCc[SsCk[K[SC{[[s[kS[KSSS[[[kSc{KCK;sCk{C{3ckC[[+Kkk;++33#SS;[[CCC3KK;33+c[ SK {s3K#SK{k+{K{;3 {k#;SK#+++SC{ck ǧk[3+ ;sc#s+{3cKC#SK+ׯcS{#;KSC׿cc[;{[kק#{+k[#K߿S{k;{Ǘǯ# K; ߯#Ck[+csScC3 +#ǟ33s3SC߷ScS+sc;ǯkkKϗKCϯc׿KC3cCϗ#+Cs[+SC#Kckϗ+3KׯcϯsC;+{k χߗLJk+קScSC+{Ssk ;3[cS;߇ {#s#c#s3Ks[;߷{s sχ+c3[ǧ{c#[k#ߧcϟcSsK#{;sCsSׯ׷{k[ǯ{c{kϿǿSk;s{cSCsc[scǷkcsc{cc{{ǿallegro5-5.2.10.1/examples/data/bkg.png000066400000000000000000000222271473414355200174650ustar00rootroot00000000000000PNG  IHDR X'sRGBbKGDC pHYs  tIME Ԭ/tEXtCommentCreated with GIMPW IDATx;LvP cf  !ԨJd2~~WS<P`($:9x C^;$,y";o\ ˮ`HvMэWC`(X ,{e`H kat ,2V3"Ww̗npZco)WMy JrP`(U9_eLU`岔 ♉'.NYwats yh#2'XX ,7ƿƊnͮ62b zS\^sߵnsBiֵ, @u5%neŖH?óˎ<0}%+3$|]Պm&C7KoOX ,}~҂~ە;dS7-w˻:yge I6rT.` @( "?d`rnE)W+C凜bxH:ȮYߓ̛m,` , Q^盘㖇9F^I3 g^l/;YW8ۻVۏՊyIEO)X ,G hr.kݽAu,OFYl9o4\ߣ_)+P, @uWʚF מ^6_?႖fe[>F#v}Ӣk\'oOX ,]irú13g^ԓ/u<|䐣];]=P`(X\:D!ay'Rm^!_&(;<]93u-ne_jTHS|!C`(X , hrJ>9:!C7f>~sFeG555r]13-wwk<P`(X\V63[3 94ZSF2on5#J͞|Yf9'X , ^fHZ$2de3j03~S%~4W®dU9`(X ,>$tmLk7=(4f^ߵ޿ I^>!OX ,}>3Y,|fiH)kcA|^!`o?.+k4G @0 @(?7w})'#y}+f&9沱r;)3/w+e/MY @P`p]@cJ]1VCNN썖|8nw]>;X߂xP`(&^]Ɂdvew%P4Mffɍ4ymek{vE 3ߥX\{P`(&Җ ;/yЭ8Y]y3(=3}ݿ'ѐ~R @P`ptd?i QW&oD l2`gU>{37fޡ]my(w)<P`(uoT:.=3*%w}!˺9CwݽbG3g6s<P`(uMgy1_퐎˲L޼(#|a%Ayϻ*k] l ]wJQyLP`<+{33ywmjHbk43 >|Wu'1䍇,!ӻ<P`(X\wɽ,y]YC,6p$ˮ(/q{8q+ys!   @ຏܻ{ZFiV]q)yWafsACF7.ՌZ^A ٯ'XX ,|>3~[<.ಌ~eWIvXuQ{Wv @0 @(w%6 IԐT6Օ1]67lk _ YgwW]Wpź1d9`(X ,{]!٩]=]ǜwk"댆$_y_ YҺFYyQ]!kl @0 @(M|633=IRpa[98C`yG5$}Ō4 ?6sY} @0 @(Ej_BɦQ~{7:ɧ|[CZgye=8o0y/,` , Q_N;$9+6/8on _?i뾁;lu͍!7ɮVʊ%7W  @xܿnm]֠W^68yW0o37ƾϼF]13|掺V߅{cr}hL=P`(&'=It}x Rˈ/AYb nQ^n򍧿 缣ʛuy[.{! v-nCf~;$[]e,` , Q:duMʵoa&nܯQޖk WC~5wMɛ]$w , Qқ7怗e5L ޸eMo*7C+q}c]67%  @P`pݕ&0ɹyBX r`&&M޲q$g~[b}we)`(X ,ɽ3ݸ+wf3WjHkv`vyﺏ֫!IyjEr}ٌ]W`S`(Xsly';36oF]CR`׫*߇򅀮̫ ~ @0 @(?7>IRV!,s+;. |$o$#9Q>Wy+z, @u Su}trF;򙊍3?4ҵƆe`S`(X^փ6$UI̱#p4r+{,q;p |dffz^qwPv~V\k<P`(X\w}fܮygHy,y+O?𥍙WrZs'XX ,|\1|,%_ۮT\q[e[\͍߮e 9ߍ k @0 @(?7wu Y#x edƹôkw(ݘ?dZf/| 3o9dNzLP`9~!elH(-y1~ʟ̻{ՊM @P`p|)sϻ2dw4~ugރ+xZ6~[bNs=OX ,}<$+yƁ͛eٸy]]euƙww/fv\vf]~gs}rFCWW]iyo( N$`S`(X8ՎN::w>n9e]y+RwYN  @x$!IG~SCZʢҺzH|ՠkz\7iwHț9+_h5  @x$t211tHpΜfewhz5s>`2x"w,` , Q^{~y]cՎfnkNۙ]yS+ͼ*o4VvTKW|l, @uwkjyuMne.wwC~Vq^w!  @x&63Zq 셏^>3g4䍥ߔ\ygΜxP`(J{WrY^3 j_wʶ׷>$#><P`(&!ɹ'[^}ry[jAHnSweC^S(;kUYѧe_5  @ຟ7Ww9oްQ`銤w=,Ak#׷zLP`P8!wP 'XX ,·"yfZ{y]z홧0.9+>SOLꦯH`(X ,}H㼔Dz-]!9+nF>T0dSO wU_D @P`pMCRwg&5Y֏Y#|噓}!7٘x[΍}zS*,` , Q^D׼)kj˷j#877\UNyHv`wߊt-Z ? @0 @(5 gA"s5*3*KF6&Ð +SvN֍|cloo @P`pݕ$۲毎*?|vun=_1f~an3o DY%OX ,׽wP>AL_\vF_,A7"BY+_^y\  @&!CO"d'(o7 rw i݂NvHOX ,7>:WFy;Jo{'egb[F|mힹks,` , Q6%}kTޝ7Vy3gc}u]wG֍g13$s,` , Qܻ{z92g^Vck(.,3 \UFk9sbe(,cm  @x+M]i]}<3+co+5{ߖ3)we"uGy;s}Y=P`(&^S(߮TMv]!9_ eNޮMLc-y7N/ݵu,` , Q~nr/o.Ԑ.¯v+݂!p1 h~?s/JWx}4$178yǜ77 [?`S`(XsF/"/90el37~]$~y]ɼʻqrҊxFyo;ݡeS%, @uOS^x`c`^W񇼼 l'/oIs.3,[;iZ7l CCxP`(uND&ʮ-wb-N!8]<knuyw OX ,]ir_G#IDAT!yTܵFp28]_({l$7N3-W]_<P`(X\Q2Rv]CQYpYW=9i]]G^M!p1!7 @0 @(5mlE8>3:on4i~@ތ;WGunz_2ɼ!K*xLP`<ߔ%n7$yHbL!eY]gTޕ5CFW#s=deظ̼FzP`(& []r?̦/ nB߽?sey'\{OX ,"8Gxf̋2䘇ՐT޷+ ֫oZt}`W+fs׽?m{LP`<}زe਺}f}8V]~G]wWWa1̫tvO)X ,Gy]V⮜2+Rʊ GHg?FːKP}  @&!qN}&  =$ 0dS'y1dCv  @x7 <P`(X\2sϊx߲Mg5   `xt5.qIENDB`allegro5-5.2.10.1/examples/data/blue_box.png000066400000000000000000000017071473414355200205210ustar00rootroot00000000000000PNG  IHDRPLTE     !   + 5  !9#?#'!& (E )L*%'$#+"- /Q /W&0+-+#3'6 7d5^,6.6#342,: =p3;4G=H,K:M MGHF:QT=T UWNPMAY%C['HX7]H^$_#]UWTea!c!dIf*h#ei^`]kUg=k)h$kRm*st$o$pVq.fhe}Su0*rUv+wwy.tXx-.uYy."yZz/2vmol#}[|0cxH*}^3,}*+tvs-/3"2)!G8@4')g;{}z*lS28,.=/31>3ރpE5A7iE;xXEj k 1vm0WY4͓0Chϡ:S&kQºFU'_S2[fHD2Z ԰ndnd/1X 6N|IFy t&ߟIs]g}c+&^0o^]~\c: \燨vc{̼i7[1wsWUghݟ+PeTc3wM\%--XHWk:kUq m,ǯB.FvЉj~7534Z2[S?xvgpI4n׉j^kzA[0eGtQ5J|F(K{'tDނ -p%@r60Qut t3g&$U2Q(.=ܤ_ 5jn-B0 Fh7^, |6\Sf)Ӭ9]-HR67ߝ/1kV0oAB822KLۥl&wOs!cbVZȅeK錔_ք8;!aIlZNzꏲ ̟ߺLǹqK8l"q{&pm,LZ5.(ߡRH*78)I V ^V*ԃ6UKXXc0o wh&cK)cCp݂3%.R/;n純)pYlf4 :}$}n/i8|(݀IӮgUfA)R(zTu/F4:.w0ue |H"9w(]6M[4]]3gAգĒ/m2E~A։=|VU&݋:FthO`m4O8VwhP8ƻ · *=Rc:{ih:uS wҳc xsai"T+J~OSSX, 0'q+Փӡ*ICh=,( 3Pci}҅c|}en%=_щ^&NJLc̒ ~>#e0uwíZz)YBg}c;LGز93ْ:uyӺ7M<5L}1353NE5<0!gfsՀf~ --%bH#cw2m."<6{ҷB/)ߟ͔"`A#X$F_e7{|&d:ԑԡ^9e`mZb1rQL Q)ש{?Yno:uX/ro¶"o3Ufn 9k]Ī4%gJcF N#֌cL.֧ufV#,ۿy{nSNn OrwÊĸF< > 6g|\ ϬPK:x " 02.bmpUT8IUxPKA; allegro5-5.2.10.1/examples/data/ex_prim_shader_pixel.glsl000066400000000000000000000043001473414355200232610ustar00rootroot00000000000000#ifdef GL_ES precision mediump float; #endif /* This shader implements Phong shading (see http://en.wikipedia.org/wiki/Phong_reflection_model for the math). * It is not the most optimized version of it, as it sticks closely to the mathematics of the model. */ uniform vec3 light_position; /* diffuse color specifies the color of the illumination outside of the highlights, but still within the light * radius */ uniform vec4 diffuse_color; /* alpha is the shininess of a surface. 1 is dull, >1 is shiny. <1 is weird :) */ uniform float alpha; varying vec3 pixel_position; varying vec3 normal; /* Ambient color and intensity specify the color of the illumination outside the range of the light */ #define AMBIENT_COLOR vec4(1, 1, 1, 1) #define AMBIENT_INTENSITY 0.01 /* Specifies the color of the highlights */ #define SPECULAR_COLOR vec4(1, 1, 1, 1) void main() { /* Vector pointing from the point on the surface to the light */ vec3 light_vector = light_position - pixel_position; /* Unit vector of the above */ vec3 light_dir = normalize(light_vector); /* Unit vector normal to the surface (linear interpolation between vertex normals does not produce unit vectors in most cases)*/ vec3 normal_vector = normalize(normal); /* Reflectance is used for both diffuse components and specular components. It needs to be non-negative */ float reflectance = dot(light_dir, normal_vector); reflectance = max(reflectance, 0.0); /* Computes the reflection of the light and then the degree to which it points at the camera. This also is non-negative. * (0, 0, 1) is the vector that points at the camera */ float specular_intensity = dot((2.0 * reflectance * normal_vector - light_dir), vec3(0.0, 0.0, 1.0)); specular_intensity = max(0.0, specular_intensity); specular_intensity = pow(specular_intensity, alpha); /* Compute diffuse intensity by attenuating reflectance with a simple quadratic distance falloff */ float diffuse_intensity = reflectance * 10000.0 / dot(light_vector, light_vector); /* The final color is the combination of the 3 light sources */ gl_FragColor = AMBIENT_COLOR * AMBIENT_INTENSITY + diffuse_color * diffuse_intensity + SPECULAR_COLOR * specular_intensity; } allegro5-5.2.10.1/examples/data/ex_prim_shader_pixel.hlsl000066400000000000000000000017111473414355200232650ustar00rootroot00000000000000float3 light_position; float4 diffuse_color; float alpha; /* Ported from ex_prim_shader_pixel.glsl. See that file for the comments. */ #define AMBIENT_COLOR float4(1, 1, 1, 1) #define AMBIENT_INTENSITY 0.01 #define SPECULAR_COLOR float4(1, 1, 1, 1) float4 ps_main(VS_OUTPUT Input) : COLOR0 { float3 light_vector = light_position - Input.PixelPosition; float3 light_dir = normalize(light_vector); float3 normal_vector = normalize(Input.Normal); float reflectance = dot(light_dir, normal_vector); reflectance = max(reflectance, 0.0f); float specular_intensity = dot((2 * reflectance * normal_vector - light_dir), float3(0, 0, 1)); specular_intensity = max(0, specular_intensity); specular_intensity = pow(specular_intensity, alpha); float diffuse_intensity = reflectance * 10000.0 / dot(light_vector, light_vector); return AMBIENT_COLOR * AMBIENT_INTENSITY + diffuse_color * diffuse_intensity + SPECULAR_COLOR * specular_intensity; } allegro5-5.2.10.1/examples/data/ex_prim_shader_vertex.glsl000066400000000000000000000005361473414355200234640ustar00rootroot00000000000000attribute vec4 al_pos; attribute vec3 al_user_attr_0; uniform mat4 al_projview_matrix; /* pixel_position and normal are used to compute the reflections in the pixel shader */ varying vec3 pixel_position; varying vec3 normal; void main() { pixel_position = al_pos.xyz; normal = al_user_attr_0; gl_Position = al_projview_matrix * al_pos; } allegro5-5.2.10.1/examples/data/ex_prim_shader_vertex.hlsl000066400000000000000000000010641473414355200234620ustar00rootroot00000000000000struct VS_INPUT { float4 Position : POSITION0; float3 Normal : TEXCOORD2; }; struct VS_OUTPUT { float4 Position : POSITION0; /* pixel_position and normal are used to compute the reflections in the pixel shader */ float3 PixelPosition : TEXCOORD0; float3 Normal : TEXCOORD1; }; float4x4 al_projview_matrix; VS_OUTPUT vs_main(VS_INPUT Input) { VS_OUTPUT Output; Output.Position = mul(Input.Position, al_projview_matrix); Output.PixelPosition = Input.Position.xyz; Output.Normal = Input.Normal; return Output; } allegro5-5.2.10.1/examples/data/ex_prim_wrap_pixel.glsl000066400000000000000000000003521473414355200227670ustar00rootroot00000000000000#ifdef GL_ES precision mediump float; #endif uniform sampler2D al_tex; uniform sampler2D tex2; varying vec2 varying_texcoord; void main() { gl_FragColor = texture2D(al_tex, varying_texcoord) * texture2D(tex2, varying_texcoord); } allegro5-5.2.10.1/examples/data/ex_prim_wrap_pixel.hlsl000066400000000000000000000004331473414355200227700ustar00rootroot00000000000000texture al_tex; sampler2D s1 : register(s0) = sampler_state { texture = ; }; texture tex2; sampler2D s2 : register(s1) = sampler_state { texture = ; }; float4 ps_main(VS_OUTPUT Input) : COLOR0 { return tex2D(s1, Input.TexCoord) * tex2D(s2, Input.TexCoord); } allegro5-5.2.10.1/examples/data/ex_shader_multitex_pixel.glsl000066400000000000000000000006471473414355200241770ustar00rootroot00000000000000/* Simple fragment shader which uses the fractional texture coordinate to * look up the color of the second texture (scaled down by factor 100). */ #ifdef GL_ES precision mediump float; #endif uniform sampler2D al_tex; uniform sampler2D tex2; varying vec2 varying_texcoord; void main() { vec4 color = texture2D(tex2, fract(varying_texcoord * 100.0)); gl_FragColor = color * texture2D(al_tex, varying_texcoord); } allegro5-5.2.10.1/examples/data/ex_shader_multitex_pixel.hlsl000066400000000000000000000004421473414355200241710ustar00rootroot00000000000000texture al_tex; sampler2D s1 = sampler_state { texture = ; }; texture tex2; sampler2D s2 = sampler_state { texture = ; }; float4 ps_main(VS_OUTPUT Input) : COLOR0 { float4 color = tex2D(s2, frac(Input.TexCoord * 100)); return color * tex2D(s1, Input.TexCoord); } allegro5-5.2.10.1/examples/data/ex_shader_palette_pixel.glsl000066400000000000000000000012061473414355200237520ustar00rootroot00000000000000#ifdef GL_ES precision mediump float; #endif uniform sampler2D al_tex; uniform sampler2D pal_tex; uniform float pal_set_1; uniform float pal_set_2; uniform float pal_interp; varying vec4 varying_color; varying vec2 varying_texcoord; void main() { float index = texture2D(al_tex, varying_texcoord).r; if (index == 0.0) discard; // Although the palette texture was defined to be 7 pixels tall, // allegro forces textures to be at least 16. vec4 col_1 = texture2D(pal_tex, vec2(index, pal_set_1 / 15.0)); vec4 col_2 = texture2D(pal_tex, vec2(index, pal_set_2 / 15.0)); gl_FragColor = vec4(mix(col_1, col_2, pal_interp).rgb, 1.0); } allegro5-5.2.10.1/examples/data/ex_shader_pixel.glsl000066400000000000000000000004731473414355200222410ustar00rootroot00000000000000#ifdef GL_ES precision mediump float; #endif uniform sampler2D al_tex; uniform vec3 tint; varying vec4 varying_color; varying vec2 varying_texcoord; void main() { vec4 tmp = varying_color * texture2D(al_tex, varying_texcoord); tmp.r *= tint.r; tmp.g *= tint.g; tmp.b *= tint.b; gl_FragColor = tmp; } allegro5-5.2.10.1/examples/data/ex_shader_pixel.hlsl000066400000000000000000000004041473414355200222340ustar00rootroot00000000000000texture al_tex; sampler2D s = sampler_state { texture = ; }; float3 tint; float4 ps_main(VS_OUTPUT Input) : COLOR0 { float4 pixel = tex2D(s, Input.TexCoord.xy); pixel.r *= tint.r; pixel.g *= tint.g; pixel.b *= tint.b; return pixel; } allegro5-5.2.10.1/examples/data/ex_shader_vertex.glsl000066400000000000000000000004461473414355200224350ustar00rootroot00000000000000attribute vec4 al_pos; attribute vec4 al_color; attribute vec2 al_texcoord; uniform mat4 al_projview_matrix; varying vec4 varying_color; varying vec2 varying_texcoord; void main() { varying_color = al_color; varying_texcoord = al_texcoord; gl_Position = al_projview_matrix * al_pos; } allegro5-5.2.10.1/examples/data/ex_shader_vertex.hlsl000066400000000000000000000007341473414355200224360ustar00rootroot00000000000000struct VS_INPUT { float4 Position : POSITION0; float2 TexCoord : TEXCOORD0; float4 Color : TEXCOORD1; }; struct VS_OUTPUT { float4 Position : POSITION0; float4 Color : COLOR0; float2 TexCoord : TEXCOORD0; }; float4x4 al_projview_matrix; VS_OUTPUT vs_main(VS_INPUT Input) { VS_OUTPUT Output; Output.Position = mul(Input.Position, al_projview_matrix); Output.Color = Input.Color; Output.TexCoord = Input.TexCoord; return Output; } allegro5-5.2.10.1/examples/data/ex_ttf.ini000066400000000000000000000016751473414355200202120ustar00rootroot00000000000000# There are problems with UTF-8 string literals under MSVC. # There appear to be two cases: # 1. It thinks our source file use the local file encoding. This mostly # works okay: the UTF-8 strings look like strings in an 8-bit charset and # will be passed through directly. But in other locales (e.g. East Asian) # it won't work. # 2. If we add a UTF-8 byte order mark (signature) then MSVC will recognise # the source file as UTF-8, but will then try to re-encode the strings # into the local charset. # So, unfortunately, for portability to MSVC, we have to externalise UTF-8 # strings or write them out using escape codes. symbols1=■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯▰▱ symbols2=▲△▴▵▶▷▸▹►▻▼▽▾▿◀◁◂◃◄◅◆◇◈◉◊ symbols3=○◌◍◎●◐◑◒◓◔◕◖◗◘◙ substr1=«Thís»|you substr2=should|‘ìş’ substr3=not|“cøünt”|see substr4=réstrïçteđ…|this. allegro5-5.2.10.1/examples/data/exconfig.ini000066400000000000000000000010371473414355200205130ustar00rootroot00000000000000# The ini file consists of sections # which are marked by [ NAME OF SECTION ] [graphics] # mode: # width height bits per pixel mode= 640 480 8 # Whether or not the program should run windowed windowed= TRUE # the actual content of the screen [content] # the header line headline= Welcome to Allegro # and it's color in RGB headercolor= 255 255 255 # the image to display image= mysha.pcx # kind of image display # - 0 : stretch the image to size of screen # - 1 : center the image on screen # - 2 : tile the image on screen display= 0 allegro5-5.2.10.1/examples/data/fakeamp.bmp000066400000000000000000005375261473414355200203350ustar00rootroot00000000000000BMV6(, ̽໻Нkkk—Þ̽໻Нlmm—Þ̽໻Нkkk—Þ̽xxxuuu׫ʎ̽zzzwwwիʎ̽xxxuuu׫ʎ̳̽mmmǟȳ̴̽oooƞȳ̳̽mmmǟȳ̽Ǎnnn쿿ʜ̽ǎqqq꾾ʜ̽Ǎnnn쿿ʜ̽pppsttا̽rrrvwwצ̽pppsttا̽ţnnn™ή̽Ťoooή̽ţnnn™ή̽Ǽ~~~oooⷷӿ̽Ǽqqqⶶӿ̽Ǽ~~~oooⷷӿ̽lll~~~Яթ̽nnoϮթ̽lll~~~Яթ̽ڹkkk̭Ι̽ڹmmm˭Ι̽ڹkkk̭̽ʳuuuuvv¡ܳ̽ʳvvvwxx ܳ̽ʳuuuuvv¡Ρ߽̽mmm˲Ρ߽̽ooo˱Ρ߽̽mmm˲ع̽ѳpppƧع̽ѳqqqɿƧع̽ѳpppƧѦ̽ǥppptuuտϸѦ̽ǥppqvvv˼yyyKKK'''+++OOO~~~ĺθѦ̽ǥppptuuտϽ̽ιnnnòϽ̽ιnnnˡQQQ[[[Ʈ¨Ͻ̽ιnnnòؿ˦̽zzzpppŶqqqkkk{{{ؿ˦̽{{{pppմ[[[eeeijpppjjj{{{ؿ˦̽zzzpppŶqqqkkk{{{ǭż̽mmmھ}}}mmmiiigggmmmȭż̽nnnҺppp ݶ}}}mmmiiigggkkkǭż̽mmmھ}}}mmmiiigggmmmĤ̽mmm׻ssskkklllmmmkkkƥ̽mmm͖'''rrrkkklllmmmkkkĤ̽mmm׻ssskkklllmmmkkkϴ̽uuuvwwʹ{||nnnkkkppppppkkkе̽pppkkk~~~ϴ̽uuuvwwʹ{||nnnkkkppppppkkk⾾̽|||ƪyzzssslllooo}}}vvvkkkuuu俿̽Ċ⾾̽|||ƪyzzssslllooo}}}vvvkkkuuu׿̽tttƳxxxkkklllrrrooonnnŸ̽׿̽tttƳxxxkkklllrrrooonnnȫƽuuu©wxxpppkkkooouuulllzzzɬDz'''999ȫƽuuu©wxxpppkkkooouuulllzzzǷvvv}~~IJssskkklllvvvlllsss¡```pppǷvvv}~~IJssskkklllvvvlllsss˲·oooxxxھnnnkkkppppppjjjyyy̲ ˲·oooxxxھnnnkkkppppppjjjyyyʫxxx}}}׽ssslllmmm}}}wwwkkktttʮpppʫxxx}}}׽ssslllmmm}}}wwwkkktttԻwwwuuuqqqδyyyoookkkrrrlllooo111JJJԻwwwuuuqqqδyyyoookkkrrrlllooo¨~~~ooouuuyzzƭzzzooonnnooopppkkk ¨~~~ooouuuyzzƭzzzooonnnooopppkkk׿rrrwxxnnnƺwwwkkkllluuu}}}kkksss񨨨 ׿rrrwxxnnnƺwwwkkkllluuu}}}kkksssȱ}}}xxx|||pppnnnkkkpppooonnn䓓ȱ}}}xxx|||pppnnnkkkpppooonnnȴrrrtttllluuuössslllmmm|||wwwlll{{{{{{ȴrrrtttllluuuössslllmmm|||wwwlll{{{д}}}oopμ{{{oookkkppplllsssZZZwwwд}}}oopμ{{{oookkkppplllsss俿}}}wwwůqrrzzzuuupppjjjzzzwww俿}}}wwwůqrrzzzuuupppjjjzzztttʯ~~~²wwwkkkuuu劊tttʯ~~~²wwwkkkuuuȬ྿vvvƒlllppp梢Ȭ྿vvvƒlllppp¢̰ѫpppkkk~~~缼 ¢̰ѫpppkkk~~~Ѹؼ{||ǐ~~~kkksss Ѹؼ{||ǐ~~~kkksss°{{|þԟooonnn...vvv~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~fffvvv~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~fffJJJ°{{|þԟooonnnл˔–uuulllzzzooo^^^^^^^^^^^^л˔–uuulllzzzɮ{{{߸َkkksss⢢^^^^^^^^^^^^ɮ{{{߸َkkksssռ醆̓qqqooo ^^^^^^^^^^^^᷸~~~KKK;;;,,,,,, !!)))...777RSSռ醆̓qqqooo崵՜॥zzzyyyߵy{{MMN:::,,,+++ (((---566OPPRRR^^^^^^^^^^^^tttsss...555崵՜॥zzzyyy鷷Ո|||佾lmm///000{{|^^^^^^^^^^^^VVV&&&...ggg鷷Ո|||̣ͪ縸UVV###*++\]]^^^^^^^^^^^^333<<<RRṚͪ縸忿؞ݞ??? ^^^^^^^^^^^^ccc忿؞ݞԴǢWWW^^^^^^^^^^^^&&&mmmԴǢѬ麺yzzwww"""^^^^^^^^^^^^...麺yzz鼽۷˯===^^^^^^^^^^^^000˯ħﭭߺ~~~%%%^^^^^^^^^^^^&&&wwwߺ~~~ݶۅܾTUU^^^^^^^^^^^^WWWܾ𷸸ӸѲܴ444^^^^^^^^^^^^???''' [[[ܴ̤ޥŸ...^^^^^^^^^^^^NNN;;;~~~wwwޥŸwww⾾ۙ䯯TTT ^^^^^^^^^^^^___JJJ>>>䯯ÎةǢȎ^^^^^^^^^^^^^^^ Ǣȴ̯됐ԒĴ'''^^^^^^^^^^^^^^^+++___===Ԓ{{{޼ثܕ,,,^^^^^^^^^^^^^^^zzzggg''' ܕʞǥ۞߲___??????^^^^^^^^^^^^___~~~,,,߲ιڵ郃ڧ+++WWWooo^^^^^^^^^^^^^^^CCC>>>xxxڧ̓۷ljEEEkkk___^^^^^^^^^^^^ooo%%%ljΰϤٓܝѐ vvv~~~^^^^^^^^^^^^^^^ooo'''^^^^^^ܝѨ㼽∈·Ē,,,bbb^^^^^^^^^^^^^^^^^^^^^'''Ē𻻼԰沲֣JJJ///^^^^^^^^^^^^^^^^^^~~~LLL֣ϩАڎǐMMM222GGG^^^^^^^^^^^^^^^;;;BBB888ǐᶷш콽М//0___GGG^^^^^^^^^^^^ggg{{{ţƣδzzzsss'''???^^^^^^^^^^^^___bbboooرѥ˽nookkk??????^^^^^^^^^^^^rrrWWW'''<<<ٸ괴ŧ:;;VVV###??????^^^^^^^^^^^^{{{~~~(((xxxrssyzzΡ常>>>666??????^^^^^^^^^^^^^^^777CCCņkkkkkkuuu}~~乹ػ###OOO??????^^^^^^^^^^^^cccsssnnnpppmmmpppxxxppp칺ʸzzzbbb???^^^^^^^^^^^^~~~ccc|||ͧpppqqqrrroooqqqppp}}}Ψ޿WWWrrrnnn???^^^^^^^^^^^^rrrOOO'''[[[¢sssrrr~~~xxxnnnmmmvvvwwwzzz෷˺III[[[RRR^^^^^^^^^^^^___ KKKڳqqquuurrrlllnnnyyytttĩѼDEEBBB***^^^^^^^^^^^^^^^___///BBBBBBԢoooxxxooonnntttvvw{{{֯ǹ9::...>>>^^^^^^^^^^^^^^^^^^;;<徾vvvppprrrmmmooouuunnn:::OOO+++^^^^^^^^^^^^^^^FFFzzzCCCֺpppxxxqqqpppuuuoop{{{ͮuuu999 ^^^^^^^^^^^^^^^###???zzzGGG̣|||qqqxxxnnnlllwwwuuu}}}ỻrrrrrrGGG'''WWW^^^^^^^^^^^^^^^???>>>nnn###XXX྾ppprrrrrrmmmqqqqqqyyy츹tttsssDDDWWW'''^^^^^^^^^^^^^^^??????^^^...sssΩoooyyynnnmmmtttvvv|||ʥ}}}}}}~~~QRR ~~~~~~^^^^^^^^^^^^???OOO>>>ťsssqqqrrrmmmnnntttsssݼtttrrryyy~+++OOO~~~^^^^^^^^^^^^SSS???NNNڶooowwwĹqqqnnnttt|||{{{뼽}}}sss󸹹[[[###nnn^^^^^^^^^^^^^^^///^^^&&&թoooȿtttmmmpppvvwpppկ{{{www___^^^^^^^^^^^^^^^kkkGHHwwwqqqɿqqqoooqqqppp}~~蹹99:222GGG___^^^^^^^^^^^^fffvvvպpppyyyɿxxxpppvvvvvvttt{{|便pqrbbb___^^^^^^^^^^^^~~~zzz~~~̤|||qqqο~~~qqqȠ˷wwwooo^^^^^^^^^^^^kkk###;<<߽ppprrrοnnn~ԭ---666BBB~~~^^^^^^^^^^^^jjj[[[///yyyΨoooοklloooXYYfffggg^^^^^^^^^^^^vvvBBB>>>åssspppο|}}ooottt载nnn^^^^^^^^^^^^^^^222NNNYZZڶqqqsssοdzpppoooDDD;;;;;;^^^^^^^^^^^^^^^"""^^^#$$ըoooοmmmwwxnnn^^^^^^^^^^^^^^^fffkkkyyy濿wwwqqqοųrrrlll]]]ggg^^^^^^^^^^^^^^^~~~vvvwww001ֹpppyyyοǜooowww&&&CCC666zzz^^^^^^^^^^^^~~~jjj~~~ Ŝ|||uuuο̹xxxuvvxxxvvv^^^^^^^^^^^^^^^wwwZZZ###QQQ淸zzzο嵵ιnnn@AAbbb^^^^^^^^^^^^^^^vvvOOO///777һο۸ғnnn---FFFzzz^^^^^^^^^^^^>>>'((Ȩοsssxxx淺 !!^^^^^^^^^^^^߸οտmmm⊌^^^^^^^^^^^^vvvʧοԋppp\\\ ^^^^^^^^^^^^lmmοmmn{{{Z\\^^^^^^^^^^^^$$$٩ִحmnn刈 ^^^^^^^^^^^^444ě{{{www깺+++^^^^^^^^^^^^ KKK嶶̽Իoop@@@^^^^^^^^^^^^%&&ѧ̽޷Βnnnuvv!!!^^^^^^^^^^^^efgǘŠ̽tttwwxTUU^^^^^^^^^^^^*** KLL̴߯̐̽nnn=>> ^^^^^^^^^^^^:::iii222 )))]^^ˡʵ̽DŽqqr罽QQQ(((,,,^^^ʲ^^^^^^^^^^^^NNN 111}~~Û̝̽noo|}}yyy222000RRR^^^^^^^^^^^^sssϽwww}}}BBB--- &''233000FFFxxx٫Ł̽šooo{|}LMM999666//////$$$%%%(((GGGfffhhh ^^^^^^^^^^^^̽šoooġϰ̽üvvvwwx似򣣣^^^^^^^^^^^^̽üvvvwwx似̽弼lllթ׫ooo^^^^^^^^^^^^̽弼lllթ׫̽չnnnͯЛ...^^^^^^^^^^^^JJJ̽չnnnͯ̽dzqqqyyyģ޵ vvvfffvvvfff̽dzqqqyyyģΡ߽̽oooεУ ɩ߽̽oooεع̽ѱ~~~sssɩڻع̽ѱ~~~sssɩѦ̽ƥnnn||}ҺӨ鋋Ѧ̽ƥnnn||}Ͻ̽ιppp̶Īѿwww¨Ͻ̽ιppp̶ؿ˦̽vvvxxx϶sttnnn}~~áͨZZZxxxؿ˦̽vvvxxx϶sttnnn}~~ǭż̽qqqɩ~~~oookkkijjoopʰǾ{{{ǭż̽qqqɩ~~~oookkkijjoopƤ̽qqqɿuuummmnnnooommmȨ°ݎƤ̽qqqɿuuummmnnnooommmг̽qqqxxxڸ~~~pppmmmrrrrrrmmmҷ秧 г̽qqqxxxڸ~~~pppmmmrrrrrrmmm㾾̽{{|ʹ{{{uvvnnnqqqxxxmmmxxxª濿 㾾̽{{|ʹ{{{uvvnnnqqqxxxmmmxxx׿̽pqqε{{{mmmnnntttqqqppp 222JJJ׿̽pqqε{{{mmmnnntttqqqpppƫƽyzzƮzzzrrrmmmqqqwwwnnn}}}ʭuuuƫƽyzzƮzzzrrrmmmqqqwwwnnn}}}¡Ƿsss{||ɺuuummmnnnxxxnnnuuuţ̧ ¡Ƿsss{||ɺuuummmnnnxxxnnnuuu̳·jjjzzzpppmmmrrrrrrlll|}}ε___ppp̳·jjjzzzpppmmmrrrrrrlll|}}ʬwwwºuuunnnoooyyymmmwwwͮ''':::ʬwwwºuuunnnoooyyymmmwwwԽyyytttuuuѾ{||qqqmmmtttnnnrrrֿ ԽyyytttuuuѾ{||qqqmmmtttnnnrrr¨{{{ooorrrxyyƱ}}}qqqpppqqqrrrmmmūzzz¨{{{ooorrrxyyƱ}}}qqqpppqqqrrrmmmrrrwwwnnnƼyyymmmnnnwwwmmmuuuî~~~rrrwwwnnnƼyyymmmnnnwwwmmmuuuȲ}}}xxx|||oooħpppmmmrrrqqqppp˴zzz~~~'''Ȳ}}}xxx|||oooħpppmmmrrrqqqpppȴrrrtttllluuuؾuuunnnooo~~~yyynnn}}}ʷtttvvvjjj {{{ȴrrrtttllluuuؾuuunnnooo~~~yyynnn}}}д}}}nnnκ}}}ppqmmmrrrnnnuuuӷZZZdddlllsssд}}}nnnκ}}}ppqmmmrrrnnnuuu㾾}}}vvvȮsss|||wwwrrrlll|||³{{{ɟQQQYYY˒pppjjjzzz㾾}}}vvvȮsss|||wwwrrrlll|||׿tttıĴyyymmmvvvġuuuǸyyyKKK'''+++OOO{{{²wwwkkkuuu׿tttıĴyyymmmvvvǭӼvvvąnnnqqqͰο¿ƒlllpppǭӼvvvąnnnqqq¢çӭrrrmmmǨ˯ѫpppkkk¢çӭrrrmmmѷǸ|||ɒmmmuuuܼӼ}}}ǐ~~~kkksssѷǸ|||ɒmmmuuuڻ|||֡qqqpppƲ}}}ԟooonnnڻ|||֡qqqpppׯ͖Ęwwwnnn{||ӻ͖–uuulllzzzׯ͖Ęwwwnnn{||ƫz{{Ẻېmmmuuuβ}}}Ẻَkkksssƫz{{Ẻېmmmuuuӵ눈Εsssqqqܹ눈̓qqqoooӵ눈Εsssqqqڳ՜॥zzzxxx뼼՜ޣxxxwwwڳ՜॥zzzxxx㵶Ո{{{︸ӆzzz㵶Ո{{{ˠͪ縸Ϥͪ嶶~~~ˠͪ縸޹؞ݞ鼼؞ۜ޹؞ݞ컼ԴǢ ԴŠ컼ԴǢˬ麺yyyӱ縸xxxˬ麺yyy޷۷˯ܷɭ޷۷˯Ŧﭭߺ|||ʨﭭݸ{{{Ŧﭭߺ|||۳ۅܾḹ܅ڼ۳ۅܾ뵶ӸѲܴ\չҲڲ뵶ӸѲܴȢޥŸwwwˤݣöuuuȢޥŸwwwݻۙ䯯Í徾ݚ㮮ݻۙ䯯Í꼼ةǢȴŸڪơƲ꼼ةǢȴͮ됐Ԓ{{{α풒ԑzzzͮ됐Ԓ{{{໻ثܕʞ乺ڭܕɜ໻ثܕʞæ۞߲θ~~~ǧݠ߲͸}}}æ۞߲θ~~~ز郃ڧ͂ٶ녅ڧ́ز郃ڧ͂۷ljΰݹljί۷ljΰʣٓܝѨΣەܝѨʣٓܝѨ㼽∈·Ē޿䊊·Ē㼽∈·Ē鹹԰䰰ԡ뻻԰䰰Ԣ鹹԰䰰ԡΧА،ō½ҩА،ŎΧА،ō½බш껻Ιɿⷸш껻Ιබш껻Ιɿâƣޚ̲̹ȣƣޚ̲˷âƣޚ̲̹ٯϣɻ̱۱ϣɻصٯϣɻ̱;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXwwwwwwwwwQQQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@sssyyyBBB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GGGddd~~~sssXXX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GGGddd~~~sssXXX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<>>qqqhhhDDDkkkhhhYYYwwwwwwwwwQQQooowwwwwwQQQEEEkkkuuuOOO;;;XXXwwwwwwwww```;;;XXXwwwwwwwwwiiiwwwwwwwwwooowwwwwwwwwooowwwwwwwwwQQQwwwkkkBBB;;;;;;;;;;;;XXXwwwwwwwwwQQQ;;;;;;;;;XXXwwwwwwwwwQQQ>>>qqqhhhDDDkkkhhh<<<;;;EEE>>>;;;;;;XXXwwwwwwwwwiiiwwwwwwwwwooowwwwwwwwwiiikkk<<>>;;;;;;;;;;;;;;;wwwooo;;;;;;```;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXwwwwwwwwwQQQ;;;;;;;;;XXXwwwwwwwwwiiiwwwwwwwwwiiiwwwwwwwwwooowwwwwwwwwQQQ;;;KKKuuuooo\\\wwwwwwQQQ;;;;;;;;;;;;;;;ZZZ|||yyyiii<<<;;;;;;BBBhhh|||ddd>>>;;;XXXwwwwwwwwwooowwwwwwwwwQQQ;;;EEE{{{VVVXXXwwwwwwwwwQQQ;;;;;;;;;BBBhhh|||ddd>>>;;;XXXwwwwwwwwwQQQ;;;;;;;;;www׹hhh;;;;;;;;;KKKԹ¶qqqwwwԺ;;;www̼ԹԹԹhhhwwwSSS;;;;;;;;;wwwӸhhh;;;;;;;;;wwwԹrrrhhh;;;;;;ooo;;;;;;wwwӹԹԹhhh|||BBBhhhXXX;;;;;;wwwԺ;;;www̼ԹԹhhhIII;;;|||{{{Ѹhhh;;;;;;\\\SSS;;;;;;;;;;;;@@@qqqBBB;;;;;;kkk;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;www׽hhhEEEvvv;;;wwwԸӹԹԹhhhiiihhh;;;;;;;;;DDD;;;\\\SSSwwwԹԹhhhEEEѸhhh;;;;;;\\\SSSwwwԹhhh;;;;;;;;;ZZZQQQ;;;;;;;;;|||kkk```;;;XXXkkk qqqqqqÝQQQwwwʰ<<<;;;;;;ZZZQQQ;;;;;;;;;ZZZãQQQ;;;>>>;;;;;;ZZZ kkk qqqßQQQqqqEEE;;;oooXXX;;;;;;ZZZ```;;;XXXkkkãkkkã[[[oooqqqEEEZZZQQQ;;;EEE;;;;;;;;;;;;QQQ~~~KKK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ZZZͬMMMzzz\\\ZZZkkk kkk qqqßVVVQQQ;;;;;;;;;MMMZZZ qqqßQQQssswwwkkkQQQ;;;EEEZZZãQQQ;;;;;;;;;;;;wwwhhh;;;;;;;;;;;;iiidddhhh;;;www;;;qqq\\\mmmhhh;;;wwwhhh;;;wwwhhh;;;wwwhhh;;;wwwiii;;;;;;XXX;;;;;;;;;wwwhhh;;;;;;;;;;;;;;;wwwhhhiiidddhhh;;;;;;iii^^^;;;;;;wwwhhh;;;wwwhhh;;;wwwhhh<<<;;;;;;<<>>hhh;;;www<<<;;;hhhBBB>>>;;;wwwhhh;;;wwwhhh;;;wwwhhh;;;wwwhhh;;;;;;qqq;;;;;;;;;wwwxxxhhhQQQ;;;wwwhhh>>>hhh;;;;;;www;;;;;;wwwhhh;;;wwwhhh;;;wwwhhh```ZZZ;;;;;;;;;;;;;;;;;;;;;;;;BBB>>>;;;wwwhhh;;;wwwhhhZZZ;;;wwwhhh;;;;;;mmm;;;;;;;;;ooo;;;;;;;;;www}}}mmmMMM;;;;;;;;;;;;wwwhhh;;;;;;;;;wwwhhh^^^KKKwwwhhh;;;wwwhhh;;;wwwhhh;;;wwwhhhooo;;;;;;wwwhhh;;;;;;;;;kkk;;;;;;;;;ZZZkkkmmm;;;;;;;;;ooowwwhhh;;;wwwhhh;;;wwwhhh;;;;;;wwwhhh;;;;;;mmm;;;;;;;;;ooowwwhhh;;;;;;;;;ooonnnwww;;;;;;wwwQQQ;;;;;;VVVhhh;;;www<<>>;;;;;;;;;wwwBBBwwwhhh;;;III~~~```UUUMMMhhhXXXï^^^iiiQQQoooXXX;;;;;;;;;;;;SSSEEEMMM;;;;;;wwwhhh;;;wwwhhhGGGpppiiiólll>>>;;;;;;;;;wwwQQQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wwwuuuKKK|||hhhwwwhhhXXXï^^^BBBhhh;;;;;;;;;|||rrr;;;;;;;;;;;;;;;BBB[[[ï^^^XXXiiiólll>>>wwwhhh;;;;;;;;;pppkkklllqqqppp;;;;;;wwwwwwwwwwwwQQQ;;;qqqDDD;;;wwwhhhͽhhhOOOvvv;;;;;;;;;;;;;;;www;;;wwwǴEEE;;;;;;;;;;;;wwwhhh;;;;;;```wwwhhh;;;qqqDDDwwwӴhhhռ{{{hhhwwwǴ<<<>>>ϴhhhhhhXXX;;;;;;;;;;;;;;;;;;;;;;;;wwwhhh;;;wwwhhh;;;OOOvvv>>>ϴDzXXXiii\\\;;;;;;;;;;;;wwwhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;www{{{;;;hhhXXXhhhwwwǴ<<<;;;^^^hhh;;;;;;;;;hhh;;;;;;;;;\\\QQQiii\\\wwwǴ<<>>oooKKKXXXwwwwwwUUUmmmkkk;;;;;;;;;>>>fffwwwwwwwwwwwwQQQ<<>>fffwwwwwwwwwwwwiiiwwwwwwSSSssshhh;;;;;;BBBhhh~~~hhh>>>;;;;;;;;;;;;;;;XXXwwwwwwwwwwwwwwwwwwQQQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;zzzGGG;;;VVVhhh;;;>>>oooKKKXXXwwwwwwUUUmmmkkk;;;;;;;;;;;;EEEooo{{{hhh;;;;;;;;;IIIIII;;;;;;hhh;;;BBBhhh~~~hhh>>>;;;XXXwwwwwwUUUmmmkkk;;;;;;XXXwwwiiiwwwwwwSSSssshhh;;;;;;BBBhhh~~~hhh>>>;;;;;;wwwhhh;;;;;;;;;rrrkkknnntttnnnz{{;;;XXXhhh;;;;;;;;;;;;;;;;;;;;;wwwhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>><<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXXXXwwwhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@qqq<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>>><<<;;;;;;;;;wwwhhh;;;wwwhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXĴ;;;;;;;;;QQQ@@@qqq<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wwwhhh;;;;;;;;;;;;hhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wwwhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wwwhhh;;;;;;;;;ooommmooonnnzzz;;;wwwƴhhh;;;;;;;;;;;;;;;;;;XXXhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;}}}xxx;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wwwƴXXXhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wwwddd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;}}}xxx;;;;;;;;;XXXhhhXXXhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;www̵ZZZ;;;;;;;;;϶hhhwwwddd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXhhh;;;;;;;;;;;;@@@hhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXwwwQQQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXhhh;;;;;;;;;vvvnnnttttttqqqyyy;;;XXXwwwwwwwwwwwwwwwwwwwwwQQQ;;;;;;;;;;;;;;;;;;wwwhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EEEwwwEEE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXwwwwwwwwwwwwsssVVV;;;wwwhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wwwhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EEEwwwEEE;;;;;;;;;wwwhhhwwwhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXwwwwwwsss;;;;;;;;;;;;XXXwwwwwwwwwQQQwwwhhh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wwwhhh;;;;;;;;;;;;;;;;;;XXX{{{{{{kkkwwwQQQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wwwhhh;;;;;;;;;~~~|}}nnn;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXwwwwwwIII;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXwwwwwwIII;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@qqq<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXwwwwwwIIIXXXwwwwwwIII;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@qqq<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXwwwwwwIII;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XXXwwwwwwIII;;;;;;;;;̽lll;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;̽kkkqqq;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;̽|||ooowww;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;̽dzqqqqqq̽nnnxxx㺺oooppp̽nnnxyy㺺oooppp̽nnnxxx㺺oooppp̽ųrrrmmmзnnnwww̽ųrrrmmnжnnnwww̽ųrrrmmmзnnnwww̽ǜoppvvv˧wwwsss̽ǜpppxxxʧwwwsss̽ǜoppvvv˧wwwsss̹̽xxxvvvݻwww}}}̺̽xxxvwwݻwww}}}̹̽xxxvvvݻwww}}}̽嵵Ϲppp̦̽嵵Ϲqqq˦̽嵵Ϲppp̦̽۷ϔnnnÖ̽۷ϔnoo–̽۷ϔnnnÖ̽rrrwwxؽ̽rrrxxxؽ̽rrrwwxؽ̽տnnnť̽oooŤ̽տnnnť̽הrrr㸸̽הsss㸸̽הrrr㸸̽ooo{{{Ч̽opp|||Ц̽ooo{{{Чִحnnnʛִ̽حnnnʛִ̽حnnnʛallegro5-5.2.10.1/examples/data/fixed_font.tga000066400000000000000000000623571473414355200210460ustar00rootroot00000000000000 a TRUEVISION-XFILE.allegro5-5.2.10.1/examples/data/font.tga000066400000000000000000001072711473414355200176620ustar00rootroot00000000000000  TRUEVISION-XFILE.allegro5-5.2.10.1/examples/data/gradient1.bmp000066400000000000000000000062121473414355200205660ustar00rootroot00000000000000BM |BGRs(` @33ff&@ff < $\2  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~''''''''''''''''''''''''''''''''''''''''''',''''''',',,',',,,,',,,',,,,',,,,,,,,,,,6,,,,,,,,,,6,6,,6,6,,,,6,,6,,,6,66,6,,66,,6,66,66666,66,66666666666666666666666666666666?6??66?666666?66?6?6??6?6?6?66?6???6??????6?????????????????????D???????D?DD?D?DDDD?DDD?DDDD?DDDDDDDDDDDNDDDDDDDDDDNDNDDNDNDDDDNDDNDDDNDNNDNDDNNDDNDNNDNNNNNDNNDNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNWNWWNNWNNNNNNWNNWNWNWWNWNWNWNNWNWWWNWWWWWWNWWWWWWWWWWWWWWWWWWWWW\WWWWWWW\W\\W\W\\\\W\\\W\\\\W\\\\\\\\\\\f\\\\\\\\\\f\f\\f\f\\\\f\\f\\\f\ff\f\\ff\\f\ff\fffff\ff\ffffffffffffffffffffffffffffffffofooffoffffffoffofofoofofofoffofooofoooooofoooooooooooooooooooootoooooootottotottttotttottttottttttttttt~tttttttttt~t~tt~t~tttt~tt~ttt~t~~t~tt~~tt~t~~t~~~~~t~~t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ƼƼƼƼƼƼƼƼƼƼƼƼƼƼƼallegro5-5.2.10.1/examples/data/green.png000066400000000000000000000442651473414355200200300ustar00rootroot00000000000000PNG  IHDR~qȝH|IDATxw$G&qGF In稧գՏ}ov'Ho4c5GO4f(Xp&w},283q%P`=/D矙 r|BLUPAADN< %{ﺶk:hnun0]CXgSAyg Zfih{bTUtO;`%VBs/pBx,(HGp[uWs\CJ)"*I,9t9㘠[Mz[=3βߑ@iiHJ&GSjQ-Y9˧4*U@E*e@<۳蝦DзV2u5mͬ4Jaر弜OE9'9T2A$~Gs4}(o}E^b=TdNFQA j!K{>ŧYTfe"#y.YGnm9 U*_g5 b{`3zRcprX)91#f:G$P1u7AuTeo+JII}h+h^Nh[p@&zr׃/;xr\G"_94M (a6- @^nѭ^O00|?P$Df23O+#ʈP \!:DRx? *0G@>@[ ܚSq*&躹/'' P|-$Hb{Q hiĽtfZSa~ɀ)lȾ!^{v.[%dSic QY2Ke?cɱk׊׋SEqVe'ɠpXuOAmOeؐq 8/1<:'ʉbKoԾ}SsjE^zj1֡5>4>l!|{&)UaXZOK3 A:H{'9!hiЭ!O-ҢݰU:N׎L4lzV&qn&p9N}}"B# Q܀W~\ XԔcN?I?i=l=loܯ[Ʌyڋ =0I\vnȍyNi2JFqEWD}Yd_UWjJMuCH>M>M-k_Ծ@ZֆoxE`3qwnVt]LSnhơ;`+;93bD df&%~q/pdM8ܿ2CR[>+'<8_J;r/IWdL{9/gཤ33l΄btXR2rsfZ暴 -:ILb3vCu" rqq>WɯjMTc{}ƹ㷇A v^R@/܆ s3/ˏG5 ➶-u>PGaɻ㯏VwiŢeL' ~_B+U>h3^ >2aREi}bͳ:Af7qgNh;;<3ogoJh)vTx a.2o@6מ%rS03NBp#8a9#TGtD: Mr1(ݐnW+ǕO*`:,H؞sH#dA俗w:-%M:U;pƈQ.SөiatLo_6k4?NX ˟̏{F5AcO*{ҫS ;B_//N"˟}sѷG^B.GpI?OCuh%h؃Gr4S驉W&^2w3w`;yӷ#<:rb|HpC aB(_~E {޸=QLM6;$;Nҭ4F G|rl>[8C"MDƧ֪z/4g6{Zk5- #{8i ">d%ERRC8YeDFj}]KTuv_ `FͿ5sGp ]0]9[}{`_/pco)"bcH(r%!]Tcpl1; sY?l>3Np-\Z粳?9Sow;Ƙ1[|'IؿLR.\O'ҩ@ Gv15vO4n]s6UdaH2X{#K2x] }AQ1a||הvPNC/,sL7Y=a.#j20/YPJsν;;uz+JZ uRS%K$}P|r!*@D7 `g~|/[J,hT=Yd~Jj6]o-gT; ?6̅Pzx{n.qShM@ ۶p&XM "nG"QZNܪz-!?sNlO Ea­wo /dW푚\jL UP 'n/d'wr8 B+8w|g< Bw´0o \?Oͥs؞1@R|>w+-0;?NWD=[S;z`+ N8!^OaZ.zy*__ 3ņCC f%Ӂ&|oŚp@fSƁ1I縡[鷜MПLS *h aT@&w~^qZru.f9թ8펭yvlرBÿ>ϕtpD1Q +ʿ˼y۞RCn`0f13;V,Z,xSu,9p?r0DSN|gVOy{꫞qp-okLfI؞`Z Vc_L-21ځuညs>`STcHXkYꀧдX|q(+Zչy^{sw۬|dL>o5k[QG}7Pd`&(ϥ98)% R_R~gۨ;5y"f-򆨊f@E~t yAǤԉ#zW\#n G` l[Mw5ݖk3Y6rUҜ$AV䫲 ,s)"#4CoB-Uw|b`]3оҚ06ӂӎ:6 "cST`9<߉<;wyc!6^~X P76Rekϴ: _oa:=;Yy \S\c8"~~ha1]=cUl8*2]<~86?*Nwh:s}9 b β] @lE'`P3kj*RBH!0&H[I_gk>@R2&ޚxlr@00WͿ٬ l0 \Ύ|ECm. G-dp>BфSra6G3UoCˆ פiIa);#0{=&?/&_VS $@ M`?Z5뙅6F#~ k;ه5x<M_ϒ## /L"}H[-̽3NLbpfm׭ ^Lg(a7M^+$8Ww_ix dgcN%& AN˄ ̦~~Wi،3؞s#@cVXGdڛI@jSo4> \g0mچDSdol!˼N@I($mS/ʴWOU"} )_%M'3x&4 #.VlVYX4x 't^0`^,ڏSX>;F5b:tPr2-ڦ W X` |Ũ6E y5/ v:I'}!bmg^yw]{4҂Ȝ0 _oj[U `9tXlAL IwG;x#&knD6EqJT0qh7IYRPU_QǍΦYUlsҌwlܨ:b`vp0U!ZȂ-*i__ˉ\ߔb O8IY}?b-CjOړf>uf]ˏ僳Yn]F;C]fzc` h ZFRĥ \݀Yp︇:` :Mw_/CdET`r|3QaJHx~V^3|>g*"~7*]wp4C-~)dkТi3z$G0Q1  $*(LK*h秡HعCX#7:ٺ aiob,Fnp9,B V@kZlϏδEԎ TX~|b>K"as."BBL1쇇G+ŕ*Ty Fs~f|1t̑9nƾwXsÕY=B<Պ.b{7^1uYMUgxQ&\@/{ /?1% jeKn'b9nw:">tZ͏x߆ o>|~/V9}}:`Q{D"fDA|Y%`yN7k}tnPN^:tlӵIњ6VZkF>W?*gd`+הa*EES'yj/l M:s>5~NңNLu_U4s sOk'x78Z9yDN1Lu:̣QFdp>(:N% I7:w1z2qWw[aJ1C/[xfKaG:,wVt'xo% `ń:K8w`&<,ie\ͮ~lSIVJMb#= eG}nk@ 7gfUgմ8!e9"L*THev6*@̳,t'ܑgecn*eroB 8ȩ;ˍ/3_r%,QUw r%`#V#O0]lZX!ep`^*\h~y@GG8z_}fx[c5#䤟sa+ nrV):"9ۏy<6rjF \uQX6);I|DtI~[m/gO \3FJوiM^w'&m唜cFDFyjO}} m2#N.=2pEA l5jv΂p. 8;0Bą(}@?t㾁.>QTՙLɖDւR/!:-yy<L+R*GmwT6Y[ֺ@z`}:U-"?%`-d-R/lK14~@Y]LLvS)?ַ=SZԾߞC6o6H]>"XxƓOIOgp nm?׽*^zkoUQtW'.Ӟjo?p+f%/ >˧@c>BlvbjZ/udkbnEk-ĵ'@0k 3rr`%c'acYDœtz`k6:D>M@@Fǭ}+Vɋzs_'+`g}b3b&չlnVţ{EƢO9 dƮٵַCkZ^,i'=ߞ'aWz%.BJ`@ Q(mQ⮺˜P,ȥ8I-Dl [LFyP<(ޛVSk@(S C̽l_ 4ϼ+X||l<23<E}a|C脕N*mi!!|"&c nFVXsVdͧͧSӃYaA-mĂC!{b{ƞ'{ʄԇQ3򚜖2KftN'xa/Qѓ;35բZdAz*1z=N2g4[Msxj<ڏ!4Xp;WrcϘ3}SqeF{TZxd}쉮V\35wYW$BԕKc{=Otk@hԴaP ;Y1+{EO|@dD!QA)hG([LnP8:ף6]xڊb*eu78~ƫQ.w qyj$5)?+B 4EQ'Z}58lm;FJ4sI؞kc,CY󡉑T#2(ʪ[ufm@ے# dy“@;) y'(\I(Wxj; '6 4(%_ -W꛽1TZG>|r$9‚3B7m ;SUߤ<fvU{1+y !%E@g-y쁪2֊>V0ݛV-Edk*{De Ӣ^XFQ6R<Ă*a֢^w<%}Sfelo[(üx"&D-j{sV<ߘ10Qq%{r{^-f ʁ 2+!u/fՙD/"hRlq'vUj]i=yt~!KRlbaENi}tCM);aM]3trbjfWiP{͏c9aTƈc*<5䀝Hd{>J>އ~: b@{2+<6͊gx3sl|k4Oeu|OlD{ ;%HEM@^~ۓh*\IљDcc{֞'s@lv#]bGxH@?hUo:T J@9>4NSfl)6rAq2Ƌvb>n4n;@"mEٌȝd0IyKJKbS=LO¯צ_F^>&s\P1+ ty=x>YHv.\²1}!/2T)Swt{7p:Ctރ*vE6x#F5!]-%NZGOa0SŨPuO/̒΋^%(kź qRuYT=Oמ{}@;!e9uQ@(8%,^Z)ty_7H4d֎V7u<;w Q[~lsg,}kEp`/Bp%Kȉ,(\NOQ>1p)xb7(KicTlӵg,}ctM4? su*(P NtZ9)Ϥ9([0g,1ڏa(. N'Q%$ (~nX/XXŲƏy);skmiEU 1غ{镡@ C]?  e5AtKߩ[x(W".RJJtWg@>h"P%Y,/x*s'(؞kXf[}~6qJ4,%罭Q@.e?8'DQ(Bϐ JrNP 4](uh_uvasBT{λҶJVzN/.(=S Xc]8>T%g,9Lg` <֯HɝAN!rN%  R7 ]sAMb\⸘t%g,90Qҷ,P 7 $'T zX1Srz I$GdPnb?=A`T 4ȋeqma.; iz\"k$ I6& b_Gxf\ǂ`E;dEch~~(7Xj_ ؞|gߪZUcذ@Y+ܔ%^BQȀ#&"!EV(L+ꢗn;xrEy9x9؞=c0ښfho͏piQ_SS.euQ;<#dgRY:A',bgKoV]_,PQoiqR̰I6Cb{e1e]uWM/ yaTYx9530~d?baa&A*|-9&NG7t#7A_y^W ِgS,,V_/iފYM|G<(b/#Yc{e0[V~~4}%} ^ku(7DZ^+x>nQgJgJ̛3o&$EDi|&NLF7[uܦ?)O_4>؞ c]ƃƃԽ=|r9w{l$KWՌS/X7oEw&`^?Оg4Nb?`7WW5MҔ=k5qyQkXϬ c=glX!06j>W*Wӓ)2NƀN 5O(Y$^6-pT d%VBПgOؿ_ӓzW;u#Ԟij>EuT#R(HaZ L4/2KE! tٌy1kcGGqA\!O׋B:Bxrx=,.E )!_/̿=ğO9EnrW@ l,Yjm)*s<|*Έ37A|}l"u75ODkqJ28}RgQ7ߘ~fFpo5.]{ƴPYQ*Ӹ~ə~&0VL!3α3>{. AYRS,/X>{# Js]\RZwûQQ؞؞иIa*NBN*uBJK<&'S\j~ȸSH)srQSǙuf[V 's;y}2oZ° PBEgO`ؼ߼/N5IS*pRNƽMkdXC`1#fR,|n>Ov-J?hvc{^|{'8RSO0? @>*$MbD0Db.1Z4_ό'ƚf2nUDzYxVrJ.=J/ 2O捂Qxǜ~gxo fg[U>IN* <_w[V?.Y(ߕLЀp#ʬ8$ʄM~h|V*5`:LӉĬ8/ΓI2 9C:+b|Ï3>'sY? $IMMо :$EU^'gk[vxz`!R9QH t`,9qD)nr^AN' A`*_ѶfkYWJiBdD&3`ɏ4T%M_9„Pʜ2\Կ?זO ĕ0bUJYZT:8%NqA1(ڪԤX})9 \cVGXO-PB#8Dk|U%{W.X|8-BZn 7D)3[A=3:?HC&@Ӡ96'{Ntaݩ}kbƪ[sPVe&!"\q ˁ"_3 |#9x}ϱIRR&SR7%|bZf ŚUCrt'}5N$$IEI11ќʐ2pUPF1viKzI97L#ļ{4\QK'T=Oמ p{{0Ҭ4H%A& 8 13<|$w@%\fNT] ^lwdu'O5/.P2nhoF(˾@?ŗԚꮸ%䔝2X+`0$#GS@$BO)$7OjRz͠6v5@1Ե؞Ӟ (nխ>o})zgμ%-J|?jpð\26L<0ʯ*~I#JaL(R?5}2 }}@eɼGx~ؼ<ͱy6]aI15< S"vPNx*Rd%&$Iy8w&`Y h&"-gG[q멷℈Q;Ce)](e1 z5ow. "m%r"ڿRu=h&^NLISA XHVvqP7yq_c=( | $Ծ>6i>3L}/5%KI` "}I>i_T-=C_ ܢ{Dz9#N 2ժHe=N~?9#/isc!3?ا4YA A*g,Wֿ?tiX-2V,sC9w8qc.l߰˿(Z6GK*~ ٝ2}a  U>SrZƒfĭDN$6ŒS`/3vɎy QBEݯkz0x]6\Uu9\Q$>S<$=nB7f߯743Up5ڱ$Y@y?|^|z)o xg8N|b|,&&GrJE621p_1€3#+mU~^5œj؞ G|-n4% SbZaLp).,!Kc oo3*Nh_k ,Ms8:n?/1tVd}NL*R?5 g?j@9iN= :~^`7H(rCIa!$zZF:}`RM7!l(' b{^{4}_M[s&[Tڗ0OsInKpYN KXBYpF pJLA >ñ7m^-k2ͧ5˅@ A>0qj^NvMvV9M3sm0nE`<XIFb4`@vYxQ 1-`@.=El)9!C 7AK_)L0LXf  9 Ҟ lhﵺ|Tc{^.{O%z^=eoE;LʛHr$ʍrF8|23a!kpYIc0ViFϸ0RtdCJTfgoƮTZ^/ cu/Wu=R1ߌx_CIfK&: N>BAo(@䨉hQ"?t^rq'O񳃀jوB2cy@~<&I7yX\i-[vK僋,>\DTV 祰esǺKuB 8g34;:{X~넘LKGw2:L,-nWDp@Չ&؞=/\*OE<^ Yh_i}4;;F'2\<d,=c9r#ʫkk÷o !a8qkdZan)ݡiVb%/tR<ӯOUEhn)9f8PÊAޢwXb%/ pKOf~879oN4aI4OFUI ƈ:uEb%X. RY5Msӷ qj)LhG? Io62?8;5i]E.O%X{HOd2s\m~esdy)C3C3?Ops7lSmcn_Zgj\kyϻޏ,S66؍%X{_]~E~E.^o}yd<JV••7f{w]zjF4C Ljfu9̥;kcK,IgEV'72y%}q뱶u;yGbS;7Go:j{W+l3 fX_r=p,߼l7kQK,MoqdGi~ 'Rzxl<65}M6]L)bJG)dfw毦nn ׅ֘5f(Qz0_65+Wg%X<[*0;^Woyf+֚fo&hڰ;gy HMlA!dNTARRJ*Y5:Nʳ .Ԓ1VwlٱGVgf˨OwW9r4O,Mi)n[b+6@7MThmV!i RbVbie~aر duYcZ琓,,loG!'OV`c%X$c= i$Gru4PFc4_ud e\#o"LT)6E34+. #Gqoo[0-O%vCqSW[7Xb Bh@2,.%""5 +C`f?Kxhܞ=F,#h  cCٱ&NnlnU#~֠DF,spFq~n6DchO#M|SsK q2ȅ_=#/uw%x2*~m ![o.K,Rۨm K3R,b‘Ӻ#}N"÷-ƸoOZV7zMd!S`Ap—iۏ3K,^pxtoBuV^iQAp G%"cްjkFfM0qrv3,Dn@!OK,1zOxVaD$ q.↸+" 24J C%p&y)Pf{*'f; AqܦuJo=a-[ ԩAT[?sD=Xb%֠&nYy= :Y`lX<$ڵLJ?߁!ÆW-i`jG_x~,z(hhcRВ =ïG,{7bK,L_i71.܃1f+k߉%Xb95 f#pORs W6DZ5?jn]_^~,"?7>Xbe@aᴁz1K,'?p:IENDB`allegro5-5.2.10.1/examples/data/icon.png000066400000000000000000000010001473414355200176340ustar00rootroot00000000000000PNG  IHDR00+"PLTEcolH`(Xx4|S5tRNS@fIDAT8mRQ  kff%}OH L6!E.]mAw tUu%@ylM< ["/f5~t/'1nB@TŰ5sv#cNìs`tRY 諳Y(-šiꚽMh}=1wˎ8h̒8cR*T:[9&&tPbr\Ys2Ցٖy\Վײ4~跎=nLö:5 ziOu, 9yQ2> QHs hδ@( f,ě%Ja^t^[`@A yӷゞ{j5ȼNX"n\K)1zhCxBIENDB`allegro5-5.2.10.1/examples/data/icon.tga000066400000000000000000000220541473414355200176370ustar00rootroot0000000000000000 ((`H(`H4xX4xX4xX4xX(`H(`H4xX4xX4xX4xX4xX(`H(`H(`H4xX4xX4xX4xX(`H(`H4xX4xX4xX4xX4xX(`H4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX(`H(`H4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX(`H(`H4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX(`H(`H4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX|Ĥ|Ĥ4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX|Ĥ|Ĥ4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX|Ĥ|Ĥ4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX|Ĥ|Ĥ4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX4xX|Ĥ|Ĥ4xX4xX4xX4xX4xX(`H(`H4xX4xX4xX4xX4xX|Ĥ|Ĥ4xX4xX4xX4xX4xX(`H(`H4xX4xX4xX(`H(`H4xX4xX4xX(`H(`H4xX4xX4xX4xX4xX4xX4xX4xX4xX(`H(`H4xX4xX(`H4xX4xX4xX4xX(`H4xX4xX|Ĥ|Ĥ|Ĥ|Ĥ4xX4xX4xX4xX4xX|Ĥ|Ĥ|Ĥ|Ĥ4xX4xX4xX4xX4xX|Ĥ|Ĥ|Ĥ|Ĥ4xX4xX4xX4xX4xX|Ĥ|Ĥ|Ĥ|Ĥ4xX4xX4xX4xX4xX|Ĥ|Ĥ|Ĥ|Ĥ4xX4xX4xX4xX4xX(`H(`H|Ĥ|Ĥ|Ĥ|Ĥ4xX4xX4xX4xX4xX(`H(`H|Ĥ|Ĥ4xX4xX4xX4xX4xX(`H(`H(`H(`H|Ĥ|Ĥ4xX4xX4xX4xX4xX(`H(`H(`H(`H4xX4xX4xX4xX(`H4xX4xX4xX4xX(`H(`H4xX4xX4xX4xX(`H4xX4xX4xX4xX(`H(`H4xX4xX4xX4xX(`H4xX4xX4xX4xX4xX4xX(`H(`H|Ĥ|Ĥ4xX4xX4xX4xX(`H(`H|Ĥ|Ĥ4xX4xX4xX4xX4xX4xX4xX(`H(`H|Ĥ|Ĥ4xX4xX4xX4xX(`H(`H|Ĥ|Ĥ4xX4xX4xX4xX4xX4xX4xX(`H(`H|Ĥ|Ĥ4xX4xX(`H(`H|Ĥ|Ĥ|Ĥ|Ĥ|Ĥ|Ĥ|Ĥ|Ĥ|Ĥ4xX4xX(`H(`H|Ĥ|Ĥ|Ĥ|Ĥ|Ĥ|Ĥ|Ĥ|Ĥ|Ĥ4xX4xX(`H(`H4xX4xX(`H(`H4xX4xX4xX4xX4xX4xX(`H(`H4xX4xX4xX4xX4xX4xX(`H(`H4xX4xX4xX4xX4xX(`H(`H4xX4xX4xX(`H(`H4xX4xX4xX4xX4xX(`H(`H4xX4xX4xX(`H(`HTRUEVISION-XFILE.allegro5-5.2.10.1/examples/data/mask.pcx000066400000000000000000000360051473414355200176620ustar00rootroot00000000000000 +,,allegro5-5.2.10.1/examples/data/mysha.pcx000066400000000000000000001702151473414355200200520ustar00rootroot00000000000000 ?,,UUUUUUUUUUUUU@77p77pp771p7pp7epp7711pp7pp7epp77p77epp77pp7ppp7ppepp7pp77ppeppeepp77pp77epp77pp7ppeppepp77pp1pp88eppep77pp1pp1pffppp7pp7p777p11ppp87pfmm77p7ffm117ff7m17ff77m771mff77fmmffmffmmfmmfmm33m3m3mm22p77ppe7pepepp77p77ppeepee77pp77eppep78pfppeppeppe7ppeeppeeppeeppeeppeppeppeppepeeppeeppeppeppeppeppeeppe77ppppeppeep77pp7pp77ppfpp11ppff77p7fp7ffppppp7mff7ff7ff7ffmmffmmffmffmmfmmfmfmm3fmm2mm11p77pp7pp7ppm7ppp77pp77pf8epp77peepp7pp87ppepp7p6ppepeeppepp77ppeepp7ppeepp78pp7pp7ep7pp1pp7pp7pp77pp7ep77p77ppff7pef7ffpf77f77ppfffmff7ffmff117f71mm71ffmm337ffmmfmm3mm33m33227pp77ep1ppe77ppepp77p77ppeeppepp77ppeeppeppeppeeppeppeeppeeppe77epp6eeppeeppepp77ppeppeppee7eeppeeppepeppepp77ppeepp77pp77p77p7pffpp7…fff7ffp7pmmmf7fffmmffffff7mmffmmfmffmmffmm33pp77ep7pp77pp78eppepp7pp77pp7p77ppeppeepppeppepp4ppepp7eeppe4ppeppeppepp77ppeppeppeppeepp77ppep7pp7ppfpp77peff7e77ff711pp77ppf7ff117mffmm11ff7ff7fm7mm77f7f17fmffmm7mmfmffmm33mm32m2m33p77ppepp77ppeppepp7eeppepp7eppeppeeppeppeppeeppeep7peeppeeppeepp4ppeppeppeppepp8pp7ppeepeepeppepp77ppeepp7eppp77pp77ppeppffppp7ff1ffp77ppff77ff7p77f7ppf71ff7ff77ffm7ffmf7mffmmffmmffmff7fmmffmm3pp7pppeppee77pp7eppepeppeppeppeeppepepp7eeppeppeppeppeppeppeepepp77ppeppe7pp17eppeppepp77epeppp7pmpp77pp8ff7717ppfp7177fp17f77p7pff77ffmmfmm7711mffm7ffmffm7mmffmmfmmffmmffmm233nn3ppeppefppfeepeepp7ppeppepeeppeppeepeppepp6ppepppe44ppeepepeppeppeepeeppeeppeppeppeeppeeppeppeppeepp77ppeeppeeppepp7fppeffpp7epp7fpefm7pffp77pp7p77pp17ff7ff7ff7fm7f7mmf7ff7mm7ff1mffmmfmmfmm3f3mmp77pp7p77ee8epp78eppe77pp4ppeppeppeppeppee7peppeppeppeppepp6eppeeppeepepp6ppeppe6eppeppee7ppeppeppepp7pp77ppepp77pp1pp77pp7fp7f7ff7711p77fp77fmm77177mmf7fm7fmffmm1mffmm711mmffmm77ppeeppeepp8peeppeppeppeppeeppeeppeppeeppeeppee77ppee66ee77eppeeppe6peppepe7eepeppeppeppeepeppeeppeepeeppeeppeppeppeeppepp77pp77ppepp77ep77pp77pp77ppefp8pp7pp1fmpff7pmmffpf77ffmffmmfpmmffmmffmmfmmffmm33pp77pp78pp4ppeeppeep77ppeppepp4eeppepp4eeppeepp4p77ppee6ppepp6pep4ppeppepeppeeppepeeppeepp7pp77ppepp77p7pp7ppeppfpp7p7pp77p77ppp7pep17f71pp7pffffm7717mf7ff7mfmmp7ffmm711mffm7ffmmfmmfmm3mm22mpp77pe77pp77eppe7ep77ppeppeepep7ppe88ee77peeppeppeppeppeeppeppeppepepeeppee6peppepeepppp7ppeppeppeeppepeppeep77ppeepp77pp77pppffp1ppff8pp8f7pppff77fmfppffm77fmmfmmf7fmffmffmfmmpmmffmmffm7ffm33pp77ppeppeppe8877pp7eeppepp8ep7eeppeppe4peppeppepeeppepp6eepp4ppeepp4peppe6ppeeppepp44ppeppeeppeeppeppeeppeppeeppeppeppeppepp7ppeepp7ppp771pp11ppff77epmp1177p77pp1mp777p7mffm11ppmf7ff7pmmf7ffm1fmffmm11fmmfmmffmmfmmfmmpep77eepeeppeppeeppeeppe4pppeppeeppeeppeepp4pee4ppeeppeeppeeppep7eeppeeppeppeeppeppeepppeppeppeeppeepepppeeppppeeppeeppeffpepp8pp77ppfppefppp77ppfpfpfp77pf7ff7pp77fpmfpmm1fmmffmmffmmfmmffmmfmffmmppepp77eepp77eppeppeppeppeppepeppepp4peppepp44pp4eppeppee4ppeeppeppeppeepeeppe4ppepeppeppeeppeppeppeepeeppepeppeppeppeppeppepp7pp77pp7pp77pp77pp77ff7117ppm771fmff7p77ffmffff77f77ffmmffmm7mmfmmfmffmm33eeepp7epp88ppeppepeppeppeppeppeppeppeepp6ppeeppeppeeppeeppeppeep6ppeeppeppeeppepeepeeppeeppppeeppeeppeppeppeeppepeeppeepeppeeppeeppeepppeppep78ppeppefppppm77ff8mpp1ff71mfffpf7ffm1pf71mmfmmffmff8ffmffmmffmmffmmeeppe7pepeeppeeppeppeppeppepp66ppe4peepeeppeppeppeeppepp44epp4peeppeppe6p44ppeepppeeppepeppeeppeppeppeeppepepeppeppepp7ppeppepp7pp71ppf7epppppppffpp7mmppe77p11pp7pp7fpf117ff7m1771fffmm11fmmffmffmm3mmppepp4ppepp4eeppeeppeeppeppeppe4ppeeppeppeppeppeop46eep66ppopepeeppeepp6p6eeepeeppeppeeeeppppeppeppeppeeppeeppeppeeppeppeppepeppepeeppeepp77pppepppffppfpf8fp…pp77peffepp8ffp7pfep77pffpmp77fmfp7ffmmffmfffmmffmmfpepp7ppeeppeppeeppeppeeppe6pp4eeppep4ppe6peeppeppeeppeppepp4ppeppeppeppeppeppe4pepp6ppep6ppeppeppepeeppeppepeeppeepepp77ppppffppeepppp77e77ppepp8epp7pp7eppepf7pp7ffpf77pfpfpf7ff7ff7ff11mmfmmf771ffmmfmmfmmfmmfppeppeppeppeeppeeppeeppeeppeppeppeepeeppe6eeeeppeppeeppoppeppepp4ppee4ep4ppeeppeeppee6peppeeppeppeeppeeoeeppeppeeppepeeppppeppeppepp88ppep7fpp77pp7ff7pp77f7eppfp1ff7ffp8ff7ffffmffmmffmffmmfepeppeepeeppeepeepeeppeepeppeppepep4ppee4peeppeppepp6pp64eep464peepp4pp6pp4eep4eeeppeepeepeeppeeppeppeeppeppeeppeppeppeeppepp7ppepeeppeeppeep7pppp7pp77pp7pp1ppffppep711p77ppff77fm1pffmffpfpm77mffp7mmfmmff7ffmmfmm2mmffmmfmeeppeppeepeeppeppeppeppeppeppeepp6eepeppee66eepeppeeppeeppep6eeppe4peppep6eppeppeeppeppeppeppeepeppppeeppeeppepepp7eppeepp8eppfefpp7pp77pp77pp7p77mpp7ffp77ppffff7ffpffmf7mmf11ffmfmmfeppeppe4ppepeeppepp46ppeepp6ppeeppeppeppe6eeppe6ppeppeep4o44ppee64ppeeppp46ppeepp6eeppep6peeppeppppepp66eeppeppe4ee4ppeppep6ppeeppeepppp77ppfp7ep7777f1mfp77p77p77p77ff7fpp7mm7ff7p7mm8ff1mff7m1mfmmffmffmmffeeppeeppeeppeeppeppeeppeepeeppeeppee6eeppeeepp4eppepeep4eep4ppepp4eeeeppeeepe6eeooppeppeeeoppeeeppeppeeppeeppeppeeppeeppeeppppeppeppeeppeeppeppe77ppeppÅ7ffp8f777p17…m7ffppmf…mf7mffff7fmmf7mffmmffmmffmpp44eppeppeppeppeepeppee6peeppeeppeppeppee6p6eppeepee664ppee44pp664pp6ee4peeppeeppee66pepp4pepppp4ppeeppeepeeppeeppeepeeppppeppeppeppepppp77ppp7pppp77pp8ppff7ppffmf7777mff771mmfm7pp1mm7mffmffmf7ff7mmfmmffmmppeepp4eepeeppeepeepeep66eeppee6eppepp46eeppeeppeeeppee6e6eepe6pp6ppeeppeppepeepeeee66eeeeeppeepeep6ppee4ppeeppepeeppeeppeeppeppeeppepeppeeppppepp7ppp77pp77fpp71771p7fff1771ffpmmmfmm1ff8mffpeepeepeeppeppeeppeeppepp46p78e44epeepp6eppeppepe4pee6eppppepp466ope44ee66e6446e66popp6ep46ppeoeep4pp66eeoeepopppeeppe4eeppeeppeepp6eeppeppepeeppeppepp7pppeppppeeppepppepp77ppfpp17pp7pff177fppff77ff77mffm77pmm7mmfff1mffmmffm7ffmmf6epp4eeppeppee6ppeeppeepp6eppeepp446eppee6eep66eppepp4oppe6eppoepep6peeeep6466oppeoeeeoppee6oeĄpepeeppeeppeppeoeepeeeepeppeeppeepppepp4ppeeppppeeppepp7ppppeepp77p77p77pp7fmmffffpp77fmf7ff7fmmfffmm7ffeep44ppeeppeppepp6pp6ppeppeeppee66p66p4pp66ppee6ep4pe6e6ee4ppp6oo6o6p64pee66e6ppoepeooep4oeepe66ee66pp4p4e6eeppeeppeppeeeppeppepeppeeppeppeeppepp7p7pp77p7pp7p7fpf77p77p17pp7pfppmmfmmf77fmmfm1mff7fmffmmffeeppee4eepp6eppeepeppepp66eeopepppeepeo66opp644peoo4eoeee66pp66poeeppoeeooeo44pp6ee6epooo66ee6eppeepeepppepppeeppeeppeppeppeeppeepeppeeppeepeppeeppeepp8ppep788p87pppfppf7fff77pff777pp787f1mp7ff1ffmmf77eeppeeppeppeeppeeppepp4eppepp64peeppee6eppe6e4o44eeppep6pp66eeppeoo6eeooeoo6ep6eeppeo4eopee6e6eopo66o6eep4peepp66oppe4ppeppeppe4eepp6eepeepeeppeeppeepp7ppepp77pp7pppp77ppf77p7ffppffpf771ffppff771ffpffmmff1f7117mff1mmffeep6ppepp64eeeepp6eeop6epeeoppeeppoeeo4epppe66e66oeeeee644oeep66epooeeog6ee6e64ooppoeee466oee6ppooeeeeo6epeppo6epoppeepppeeppepeeppeppeppeeppeeppeeppeepeppeppepp77ppppp77epp7fppff77f7pp7pf7ffÅ7fpff7mfpffmmffp7ffmmfpp4ep4p6e7ppeeppep4epp446pep4ppppe64pp4ee6e6444e6ppe64eeeepp66epp6e6444oep6oe6oooeo6oppoogoo66oo66oo66o66p4o6oeoppeepp4eepe4eep4eepppffppeeppeepp7pp7ppeppffp78ppppmmppfp77pp7ppp7pff771mffmm177ff7mffmffmffmmee=6ee6eep4ppee4epeeoepeepeppe6p6eepe44epe6eeoeeepoee6ep644oo44opeeo4eo4oepeeooooe6ooooooogooooogoooooĄ6oppeoppopoepeeppff8=!!=ffeppeppeepeeppeppepeppep7ppeppepp77pppp17ff7pp7fp77ff7pppffffp1mff7ffpmfm7ff77ppeppeepeepp6ee6ppee44pepeepp46ee46eeppeeooppe446eeppo66ee6p66o4p66oooo646pooo6oooogooggqoo6oo4oogeeo6oo6e6p4eeeppepep1!&LO'OO%A=ffpeppepeepp8p47ppepppp7pp77ppe77pp77ppe71p77877fm7fmp78ff7ff7mmff1711ffmmf6p4ee644ee4eeppeeppeppepeeppee6e6ee6ppoee6epoe6e6oÄeo66eeoooee66eeeo6ooee=oggooogqFD&%RSTVVZXX\YY\\}XXXZZW{TQPRRMMNIJF$@@E@Ahqqo4#Q|yÚKKK#g77ppeeppepepepp7pp7pp1pp7pp1pp77pppffpf1ppfppfff7ff7ffp7ffmff778f7ffpffee644eppee6eppe6opp4pee6eepp6eep44eepe66ee46466eeooooooeoo6e8eppe6ooqggooqq;;9rBA@#&MP'VZZX\\[[]]^^]][[\Y\Y\XZWVTPPOSMN&IJFEthh!$T|ǠÚKž%A8pppeepppp6ppeepp77p7pp7pp77e7f7ppf77p77mm7pfpp7m11ff77ffp1mf11m1mmffmffp7mm7mf717ffmmf4pp6eepeepp6eepeepp6eeeoee6pee6o664646p4oo44ooee66!A!8feoogqqggqqq;ts?E#J&PTZX\]]^^a^^aa^^^[[\YY}WWVT''QPPSRw&JFF$EP{ĜšxxL!eeppeeppeepppeppeppppfppp7epp7pp7p77pp7ffpp8fp78pffpff87ff7ffmmffmmffmfmffeeppeppe6peepeppee4ee4eepp466oeepp6o44oo46eep4466op6RAffooqq:;;qqA?C&%RTVX]aaaaa__a__aaa^^^^[[YYWWUQRMKN&TV|ȚƚxL=7peppeppee4pep77ppeppppp77pp77pp77p11pf77f77f77fm7fmf7ffm171ffmm7ffmf7mffmm7mmf17mf7fmmfeeppeeppee66ee6pp664eeo6oe6o46eoopp6eeop6opoppo44oe8#}|#8m6ogoqq:AtArrAA@EIRPVZX]]aa__b____b__a^^^[[\YYYXXVU||zy{|ǠÛÝxxKww%eppppepeppeppppeeppppeepeeppep77p77ppp77pp…f77ffpmpfp1mf7pffmffmffmff77ffeepp6ee6ppepe6ppeppe66pp6pepeeppee6pe44eep6o64poo66oop"R{{WUI!f8gg<?F&RPTZY[^_bb```bb``bb____^a^^^^[[[[YYW||U{ȳĚxxĞLJgeppeepp1ppepppp7pppp77pp7pp77pp77p78pp7pff77fpff7p77ff777ffmmff77pffm7ffmff7ffmffmmfoeppep46eppee6eeoeeppe=eepeeep46e6oop6oo„e66oee'~{{Qyv;gh@EJI%OTZX\)+a__b```c````b_____^_[[[^[[Y~{{yǶĴ ÝȝȚKKŸMheepeeppeppeppepeppepp78pp8pp7eepp7ppp…p7ffpp77pp77ff7ffffffmf77ff7ffff77ffmf7feeppeppeeppeeppee4466pe6ee6eeo4eoep4o66oo6666oo66=X~~{{xAEIMOTVX\]abbc``c``c``c``__`_b____^^[[[^}W{{| ´ÝžwwLE6p64pp4ppeppeppeeppeppfepp7p77pp7ppp77pff7p117p77ff7pp77p77fmmff7mmffp7ffmmffmmfmffmmfe4pee66ppee6eeppeooepe4p66peep6oee66o6ooeo66ooo6!R}}~~{{äLJRT\^__``c`ccdc`cc`cc``c``b__``__^__^[[į~W|{{|ęÚƞwgo6eep4ppeppeppeeppppffpp7f77ffpppff77ffpfmf7pf77f77ff7ffpffffpffpf7peepeppeppep4466ep4ppe66peepp6ppe4466oepo6666p66ogoo46Y}~QzPVXaa__bcc cd ddccdd``ddc``__``__^^[[[~||~{ǠĴܚȠwÞwL!ee6pppp7ppeppeppeppepp8fpp7fpp77p11ffpffpp17f77ff77f7p17fmm1711771mmff7ffmf7mmeeppeppe66e6e6pp66eeoee66pepp46ee66oo66oeoogo"%\}}~~{|O~_bcc d dd dd dcc``dcc``__`__``___[[~~~{ÝȠ žwwI;66pp46peeppppeepp7pp1pp77ppffff77fppmff77p7mmffp7f7f77ff7ffee6pe6eeppe44ee446pp644ppee66oo6p466ppo66oopoo6VY}}}~{Ť_c`cc ccdd ccd ,,dd ccd```____``____`^^[Y}~~}{{~{˳Ŵ wȠȚwI;eooeppe88pp7pppp77pp7pp77177pp7p11pp77p7mfpp711ff77f717ffff7mmf7p77ff7ffmffmmfe6eppeeoe6ee4ee6p6ppe6ee66ooppoo6ooo6oogoo6#X}}~~zz^cd dd cdd `d,,dd` dc``bb__`_^__^^__`^^[[~~X~{ii~{|̴öȠÞ wwvAggopeepepppepp77pp7pp7fpeppepp77ppp77f7pp77f7ffpmm7f77pffp771m1mffmm7mme66ppeoe446ppee6ppe6ee66oo44pe64466466446o6oooooo==AS\\}}{{yW^`cc`ddccd`cdd,ddcddc``__``__^^^__[ï}}XXY~{{~{Ƕ˴àw xwwx@!r;;q564eppepp77pp77ppË77e77p71p77ppp7fm711ff77ff7ff77ff77pmmfmm76646e44e6eep6ooee6e6ooeoo6oo66oooe6ooooogo55o;?FIOY}}}}]^[Y[^^^___``_`__```b````d`dc_ba\]]X~~y̶özzOKGJE@;q@EMPUYŀ}§~è}}^^[®__`````dcc``ccbba]]\~~|¥̶ƴȵáyyzOߟLLDu@A;<;qEF&R'Z(a_`_Y~}}€}}}}§}~~}Y}\aa__b,`cc`d``b````_``cd`bb__ `__b^__a]]~U|| ȞȝijàǡßĞKKGHFE9qqrqoee66eepppp11pp7ppepp77epp77pp77p7787p77f7fpp77ep711f11pff77ffmm7mmffm1f71ff66o66oeoog66ooee6oo64oo64ogoooCIRV^cc _Y}}ɬɦ}\]]]_bb_`dd,,d,``,d`ccc_bb``b__bb__[]YYY~X{|zȝĴ±™ ڟzğKKKGHDCs9;9:goo4ppepppp87ppf7pp711pp77p77ppf7pp7ff77ff7f77fm77f1p77eeoo6oo664466oogee66oo6ogooqqr9t>sF&RVX]a`cc cc cc_~ÀY}}~~~}j}}j\]]b__``bbcc,d c dc`dccc``‚bc____^^]][[}}{UU|UU||UQzPPLxH ę™ ȞǟȞşžžGGGGGC>9;qIRTXaa``c cc , Y~YY€~~X}\j}}\]+abb`cbcc`,,dcc``cc`bcbb__`b_a^^[[Y~W{U|U||QQ|UxKxH— ÞȟKGGÛDus9qoo6eppeppeppepppp7pp77p7117pp77f77771p7mf77f77ff1m7ooeo66ooee44oo66oo<55<<55&'Zcc cc ,,_XYY}}Ħ~~}}\\+abcc,c,,dcc`c``c`cbb__a^[€}{UUU|V|yyQQLOzwMxv • ÝȞȞğßLKÚÛH?>rqoeepeppeppeepeeppeppppeepp7pp77p77pep7eff77pfpp7pf778f77ff7877ff6644o6oo646og644o6o66ggo<;@E&P(bb _}€}}~~~~X}\)aaccc cbcc ,cc`b``bbb__^^][[Y{UUQ|UyQQyQzOzwxۖ  ›ÚÞǞޟޟܖĖܖ rq5oo66pp6ee4ppeppepp7pp77ppepp8778p77pp77pp7ef7fm77pp11p177o6o66o66oo466o66oo6oogqq:9A>uJNPV()cc c ,~}€}­~~§X~}\]abb c`cc,`cc`c,c`cc,``bbc`c``cbb__^^[\~QQyQ|yOOyQQzzywLvHH   ŚȞÞÛ– ۗstrqo66ppeeppeppppp77pp7pp7p77pp7p77fm177f711771ff7fmm7o66ooe66o66o=4oo66oo6ooggqq;A@&P(]abc cc , }€}¬~~}\]b,,bbc c``c,c``c`cb``c`c`_`___^^YWW{QU{yyQQyzOzLOyGD  – Ú˚ܖ ۗ?tr<L'W\]abbc ccccc d`[}}}ì~~\]**bccbb ccbc, `c``c`b__aY{U|Uy|yQzzwOzGxvGxHDu  šƚݚG— C>rqtqggooeeppepepp7epp77pp8eppep7ffpffpf8p7pp77pp77pfff7f7feff77oo66oo6oo46oo66o6o6oog<<:A$OVaaa*b ccbb`ccaX~Y}Y~~ɦ~X]ababccbb_`cb_bcbbcc` ``cb`_ba[Y}UQyyyUQzLLxxxvKLwvHHD×   GGC>>;q9;qoop6778ppe7pp77pp7ppp77p77ppffpp77p177p77pff77pff7pp77ffm7goo66o66oo66oog66oOX]*c``cb_bbbccb§§{~\]kbbaabbab_aabcc`ccbbaa^]Y}}~{QyLQUQwKKwšxxGGvHHHHDu •   ܖ — ڗÔ9;q5ooppeppeppeppepp4eeppepepp7e77pp77p7pf7pp7711f7p7pe7ff7f78ff7p77p117746o44oo6oo5oo5qq;rr99tt>?R]abccca_bccbbba\{{©~\Y\]+*bb*aabbaab` c` cc`c__aa[}}W{|yQyxOwwxxvvxKKHHHvHHDu ٕ Ĕė  ڔ >9:$F&'(]+**bcc ccbbaabcc`b__bbaY~§X\]ka**bbaa]]aab , ``c`bbca^^a^][}~|Qww˜›vxGvHHKvvHHCsڔ? ė Ĕ >9:5go6eeppeppeppeepeeppeepp7p7pp77pp77p7ffp7877p7788p77pe77pffpf7oo6o6o66oo664oooo6oo5trqgoo66eepp7ppepp4ppe77pp77pp71pp177p1ff77f7717p77p77fp177877g6oo6o66oo6o66oogogoo5q;;#%'Z\]+aaccccc^^abcba]]^^[Y~XX\)+aa]]}{Ŵ{\+*abb_aa^^ab^[]]\}~WQOOxKxt ʾ—HGDD?•tǕ?  ڔ > ٕ>r:tؑؑ Ƒ • Ĕ Õ ‘ ؑqooppeppeeppepp7eppeppeppep7pp87p77p7pp7p7pp77ppf7p7ff66oo6oogoog >gooeppeepeppeeppeppeppeppepp77pp77pff7p77p77p7p7pp…epp7p77p7pppoooo66o6e6oggoo55đ‘ב •‘đ Õđ >rqoopee66oo64o644644o64ppe4peepp177p77ppe7p7fp77p77pp771f77pff76oo66oog6ooooo5gqq:r99ts?CHLTZ(a**bcc ccbbbb_^]\\[\}XX\](\][]+};ͰͱZ\[]]aabaa]][]Y}}X{{W{|ysDDHHCCC”Ñ999r‘ ٕؑ Õ>99r:55<5r‘ؕƑٔڔ • Õ?>rr;ؑt‘ؑב ”? ?>>>99‘>Õ> Õגq‘99Ñב ڗۗ ?>‘ בגؑ9ב>Ɣss Ĕ? ґr:qooppeppeppe7epee7ppe77ppepeepp7pp7p7p77ee8pp777epe77pp77f7ffo6644o66oo6oo=66oo>ڗDDڔ ’ב’9:qooeeppepeppeppeppeppepp7pp77177117pp77pp77p77p77177ff17pp77ogoo6oogooooqr:;::r;rr>>L'X\)aa***cbb**bb_a]][YXZZX\\XX\]]X|Y\\]]]aa]\\][YY}X~{{|ywxKwxxxKKxKwxHDDD?>>??Òב ٔCt99’ ’’ؑ9:5o66ppe6ppeeppeppeepeppeeppeep77pp787peepeppeppepp7pp77p78ffp77f77pf8oo66go4oog5qq;rh9>?E%PV\\))]]+aab*ccbbbb__bbb__baa]\ZZ(\XX\\}}Y\\[[\\[]]aa^aa]]\\[Y}}WW~UVUyzzzxxvxwKxxKKwxGGHHD?‘>???t בבÔC??Ô?> ֍ ג :r:5oppeeppeeppepp17pp77p7ep877pfp77p7pp7f7p77p77oo6oo6ooooqqsD%P\]]aa**bbbb**b*bbba^[ZZ\\XX}}Y\]]\\)]]a]+]]\\}~~{{W{{|yOKGxvĚxvvxxNuÔ??ڗDDH?st9ǒג ٔC×C?9č ֍ 9:5o44ppepeepp6eppeepeeppeepeppepeppepee77pp77pp77ee1pp7ppf7pp7p77oo66o466ooog<>&RTX([))]aa**bbaa^]]^]]^a*b**baab_a+[\\ZVZ(()a\~~XYY]]\(\\][]]^^]]YY\}~W{{UQPwxxKwGHHvGGvvHDDHHܖJDss>r: Ò ?CDD—ÔגŽƍ 9qo6446eppeepp4ppeeppeepepp7ppe77p7p7p77pp7p7p771177p778ppfoo66go66oo<5ELTVX(\\)]]aa**a*aa+]]a]aa^]]YZZ((\+]\~~X\\]]\\]\\]]a]]}}ZWW{{||yOxxvHGvHHvvHHHHHH—”CC‘>9 99ב>??×u??s :5 Í 9qoo6pp4epeppepeppeppee7ppepp7p7pfpp7pp7pepp7pp77pp7787p7poo66oo6oo55q<99ؑÒ>?C????>t955Î Ē:qoo446epeeppe8eepp88ffeeppfp7ppep77ppepp77p77f77p7717p77e717866oo6ooogg<5 999ؕ•s?????ٕ>>ג֍Ž5֒ ֍: 9r:qq5ooee6eppeppeeppeeppeeppeppeppe77pepeepp78pp7pe7pep77peep77e7p77pp7o6oooo<;9?LTVX(\\)]]++a++aab*aa^]])\\XX~{VVXX(\\)\XX\\}Y\\]]][}}~WW{i||yzKKLOKJHHHHGIHD—uՑ>>99’r Ñؕ??s>>???”?555֒::֍::55oopp6eppeppeeppeepeepp77ppeepp77pee77pp77p7711mfepp7p7177p7pogoogg6oo<5<?D&PTZX\\]]++**bb*aaa[]\\YXZVVZZX\\X\\}}XX}\][]]\j~~{{{{|yy|zzzyyIHHGvHDCC??•>>ő9Œ9>>>?ڔC???ؑג55:֒9֒ ’:goo44e6ppeppeppeepp77pep7eeppeppeepp77pffp77ppee77pp7ffp77pp77oooogooC&R'ZXX(\\]]++**bb_aaaaa]]YYXZWVVZZXX~ZZX\Àj}{Z{{|yywȞywwwvHHGH—DDCÕؑؑ9Ò99‘>?s>>??•> 9 : ֍q :??????•>:oÎ55’5oo44eepp4ppeeppeeppepeeppepp7ppeppeeppeepp77ppfppeppp7p7ppoo6oo6ggoo<%PVZX(\\))]]+aa++aaa+]]\\Y(XZV||VZZXX~~Z{|{~~}}X~||yyyHHHHCCCu?•>>99Ē9tÑ>>>>•ٕٕؑ9֍4555֍֍ooep46epeepeppeppepp77pp77pp77ppeepp7pp7fpp77p7pp77ppp7pp78oo66go56oo5oogoo<>9999:qƎ55ooeppeppeeppeeppe78eppeppee77eppep7pp7pe8877pp7877poo66oooogoogg<;q;A&OTZX\)]]++aa++][[]]\\YZVTTVZXZWWZZ~~|i~{~~{ģx šxxGD?ĕ> > ٔCCCCDCCCC??>>Õ?>>:5544Ԏ5o4Ž55o46o44pp46pep6ppeppeppeepp77ep787e77p77p77pp77p77p77p77ffpoogoogooggoo>>>Ñ5Ž4Žo44o5ooo6oee6pp6p7ppeppeeppeppeppe77peppepeppeepp7eppe77pp7p78pp7pp7pp77pp77p> >>?ssCC?> 5544oo66p4peppeppeeppepp87ppeppepe77pp4pp77ppe8pp77e77pp77ff77pogoogoogoog>>>tt>>•sss??>A:55Ž66pp4ee6ppeepp4peppeppepp7pp7pp87ppffpp77p7ppppeppmfpp77po5oogoogooggqq;;>C&PTXX(\]])\((\\))]][))\\(\\}XXZZVPPQTVVZZ{{Zi||ģijxwxqqב99rrr9:::::99>>ؑ>>>•>r999::qÒ:544Ž4peppep6ppepeppeppeeppeepeeppepp77pp77p77pp77pp7877pp7717pp7pff77oo66oo55oo6oo5<>9גr99Ñtđt>>>>>t>>>9qpp:qq’5444opp66eppeppeeppeeppee7epeppeppepepe7pffpfppeep771pff7pp77pp7fppeppgg>@$>>@>>>>‘9‘99‘>>‘>tג44:::oŽpeeppeepeppeeppeepeepp7pepeepp8pp7pp77pp77pp77pp77pp77;rr:;::;<;q;;ENOTVVZX((\\])]][\\YXXXX\\XVVTzRRPTV{{||·µö™ÜDC?’Ēr:qqÒr9t>•ss??>>99Ñ>>t9:ב:<qq::q54ԋՋpeppee6eeppeppepp6ee46eepeeppeppeppeppee7pp77ppe87fep77epp77pe8fpp7tt99AA9ArrAA>tA9;qggoog<??>999999rё>>>>>>ȑt9:֍ō֒::54Žppeeppeeppeppepp77pp77ppeppee877p77pp7177p77p7fft>•>>>s?ssEE@@troo5gg<;A>t>$%OTVZZXX(\)])])[\\YX}XXXXXZZZZViTPzOyTTU|UV{| DCrĒ;r>>s?u?•>99>‘t>>ٕؑ9ؑ9::55o5’;q412Վoo6epp4epeppeepp7eepeppeeppeppeppeeppeppeepp7pp7eppep7717pp7pp7pfp77 ??uuCDDCusoo<;A9rrA>F&L'TZX\\)])\Y\\XX~ZZZZVi|TTQPPzzPT||i{|yµƳű´—uuDD?ؑ9’::r’9>>Õt>>>>99>>>>tt9r::5554455::54p22pp44oo44eeppeep4pp6epeepp6eppee77pp77p77pp7p7pp8p7epp777p77p CCCڗDDHHJDutq:rrq<>>99rƒÑt>>Ñ>>ٕ>99>>99tt>>9r:5555::qo2Ջp4eeppooeeppeppeepeeppeppeppeppeppeppeppeppepp7pe87pee7p77p18e77p CDDHGGvvCr>9’בƑ9>9t>>ؑ>>>9t9ג ֍55q:::5424ppeppep66o=6ppeeppeppeppeppep7pp778eepp7e77pp1877pp7pp877fee77p CĖHHGNNvHsqoogoqr9>@FI%R'TZZX((\\Y\YXZZWVTTVVWZZZWVWZZVZZVTOOPPT||yř uuٕ>t>>9>rđ99r’r99>>99>>>t>>99>9:q:5:::54221ppeppee664peeppeepeppeeppe88epp88ee77pp88ppeeppepeppepp88p77pp77pf7ppۖDDHGGKKxvHDuqoogg?DIMPTVVZZXX(\((\\XXZV|UVZZWVVUVVZVVTyPPRzQTTyźtt ”>>>>ؑ99tؑrrt>ؑ99‘9rr::’9t>ؑ99>‘99:rr;::q::1227ppppeppeeppeepp66o6ee7ppep7eepp7ppepp77pp77ppfp7f7pp77pp77p88>?CDDHHGN%KKxvHF9qggogg<EJNRPTVVZXXXXXXZVTUZXZZVVVVUUVVWWVV|TTQzRzPPyyűŲ± ttu>>9r9đrt>>Ñ9r999rĒ99rt99‘>@999rrג:::<412Ċppeepeppeepeeppee66oeep77peepe78ee8ppeeppeppeppp88ff77pp77ep779?CDDHHGGK%MKKGHDCtog<9׿99r99ttÑؑ9999::999>>t99>>>999::ג42ӊ2ppeeppepeepeppeppeepeepp877eppeppe88p77ee77p7pp7ppe77ppff1787p78>?CDJHH&GGKKMLLGCroogqggoo55q;r>?JNMP'VZZXX\\UVZZZZWVVVVUUTTPPTVVTTPPRMMRPzzwx; ttsÕs>9r>>‘tr99rrA>>ؑr99Œ99A>>99>?>>99Òqo1Ɗ2ppeppeeppepeeppeppeepeepeeppeepep7ppeppeeppepp77ppeepp77ppfp77pfpfCDHH&HGKKMMLLMwKs>‘>@>ؑ999Ò9’9t>‘rÒ999A>>99>>t99r:1ŠÊՋppepp6eeppeepeppeppeepeepp7peepp7ppe7peep77epp7p77pp77pp7fp7877p77 HHI&G%KKLLHggooggqq;rA>E%R'TZZ{VZ(XZWWZZVVTTyOPQTTQPTTPQTTzMMLNNxx tƑrt@?s>>>s9r’ 9גrt>:q9rr9999>>>99tA9>9t99r:<1nÊЊЊ2peppeeppeeppeppeepeeppeppeppeepp7pppp77pe7ff7pÛGGKKMLLxH 6eooqq;rt?NMPTUZZVVZXZZVV|TQTTPPTQOOPP'PP'TTzLP'wxxvvIHHs tttrrÑ??•>>99ג: r99999Ò999t>>9t>>tؑt99A9999EFNRPTTVVZXXZZVVTV|TP''QPPQQTQPROPQPPTTRR'TPMLMNGvHHHDDDss s•ttt>s>>s??s>>99::Òrr:99Ò9999tttt99tttt999:54Њpeppeepeepeeppeeppeppepp8ppepeep77pp77pp88e77p7ff7pp77peep77ešLLK֋216oo<>s>>s??ٕ>>>t9 ֒:::rr999999tÑt99rrr:5124ppeeppeepepeepeepp8eppee88eppepppe77pp77ep787pp7f8877pp77p7p77 GGNNH23poo5?CJ&MOPP'VVZZZZVVU|TQQPP'PPRRPOzRPPTPPTQPzPOzRRMNNHDuus”s•‘’?>>s?•??>>t9גr:::rÒ99tA99A999r:5pӊÊÊe4ppeeppepeepeepepeepeepeeppeppeepee88ppe7ppeeppee77e8e77peppepp887p78e78p77p::>>:2n3mpp77133m11769>$FINMROPTTVVV|QQyOOPPOORRLRROOPPOP'T'PyPRRLMNNvIDC?ss?u??‘>>?>?•???>>>t9:::r:::99r9999992»6ppeppeepeepeppeppeppepp77eppeeppe77pp7ppepp7pp8778pe77p77p77pp77////..00Ј..000.003234"A$J&&%ROOPP'TTVV|TQPOOPOORMMwRRPPQPPQyPzzRMKxGIIHDDÔCCuC??@@????sssٕs??ٕ>s>ؑ99ג::r9rrÒ99rr9rr99Ñ9t>ؑ9;620ˆeepp4ppeepeepeppeeppe88ppeppeppeeppeepeep77p77ppeppe88ppfpeepp---/////.//.0037!EJ&NN%MMROPPQTQQTTQOOzRROOLMLRRMMRPTSSQPSRSRRMKNvIvHJDCFCCuCCڔ??ŕ ???ss>>ٕss>??•>>99::99Ēr9r99ג:55 ב>>t9:qpȈppeepeppeppeeppeeppeeppepp7peepp7pp7ppep77epee77eep7787pp77117-//.017"ECC#D&N%LLROPPORRPOzRwwRRLLRRMMRPPRRPRRMMxNvINHJDCCu??ƕ???>>s??ss??s>>9999rr9r9;;9:9rr9:2mtÕtt995pnȈeeppee6peepepp6ppeppeeppeeppeppeeppepp87e87ppeppeppep77pep77epp87ppeepp..É.щΉ//////.004;;!9$JIGG%MRMKKMRLRMMLLMMNNLLRMMRRMMNGGNHDD—Cuus?s>>ٕ???>>s>$>>9999rr999r99ג:5420 tsÕ>1»ppeppeeppeepee6epeeppeppeeppeppeppepepe87fe77887ee7pep77p77f7pp77.....0..00.......00001447n27"9A$NNIIvxMMKKMKMLLMMNMLLwMMRLLMKMMRMNNxNNHDDCCu?s>s>>sssÕ?s?ƕs>>9‘99t99:. Õt942ӈ2177p7ppeppepeeppeppeepeeppeeppeepeppeeppeppeppe77eeppep88e88epp877pep88///////../...00.00023m2002237<;9@EDDCDHIIG%MKKMMKNNMMKNRMMKKLLKKMxNNvHDHHDDFCCFu??>>sĕ>s>>Õ>>>>>ttt99999rr:4100l//ш t•t1--ъ002nn233m223m33mff117ff77pp7ppep7ppepp78e78epp877ppep77877p8pp77e/////....000..0023376:ttFDDJHGNMNxxN&NxKMNMRMMLMMRMMxNNHDHJJDDCCDu??ٕ>>s??>>•s>>•>>>>99r<5445pmҊ./ ‘o4/-Ή///..0002nn2n33m332mfmffmm7177p7f7f8ppe8epp77p7p/////..//.//00Њ2pqts>?EFDHINNGGNNKNNMRMMNMLMMNGGvHHDDCuCCuss>>>•>>>>>>tt>995566422n0../‰ΈÑq52/Ή/-------//.....00n3nn233mmf/////.//...nprt9qqrts@@IvIHIINNvNMRMMNNIHHDDJFCuu??ssĕ>>>>ttג:55pp412000000..ш--////----////...//////Ή////..5r735:q77!JJHINNINNMMxKNMMNNvHIHHDDFCu?Cus>>>>‘t99:54720/.///... rrqq 2--/./‰////-----//////////06qo04m."A?EFJII&&NMMKK%MxN%NNIIHHJDDFCu?Cu?s•s>>>>9:54pm00...///‰/// rq q o/---////////щ///////----////////.15p.04014A$FJIINNGGNvIIHHJDDCC?uss>>>>9:430./..Ή////// q -////////////ll///////////--/////////////.12.0p//027"9@EJHIINNGIINvIIHHJDDFC?EE?>>ttÑr::::5420.//.///l////n Óqqo/--//////////Ή.//./////////.0.03n.00001";$FJIHII&IIHIIHIIHHJJDDFC??s>>t‘tr:o10ӈ//////////.//Ή“q/////////////////////....0/.00..024EJJHHIHHIIHIJJDFFu??>>99p2ӈÉ///////мq///////////Ή///.щ...0.01$DDJJHIIHHJJDFFCuu??s>>‘992///////Έ rq nn22.////////////.щ/....69@CDDJJHHJJHJJDDCCu??>>tt9r9r9q2/q m0022/////////////////./.04!ECDDJJDJJFFCCuE?ss?>>t99qp--// qqm.ъ2///////-////////////////./..‰l..7>tt‘99׍Ј/////ď //////////////////l//ʼn..003"9@CCFFDCCFCCFCC??Es>>A9999q///-o0./////-////////////Ή//ʼn//////..76!A$EFFCuu??s>>t>tt9999//Ήonn0/.///////////////////////////..01"9>@@E??EE?s?@@>>đ9qÈnq0/////////////////////////Ή///ll.0..075"<9A>>@??@ss@>>ttÑqшqqnl/ n//////////////////////////////...02034;;99A>>tt>>9t>trrΉorqon.qnn./////////////////////.//.0..0m331745;;9A>>>‘q/Ή1oqqe3./Έnqnno2//////////////////////////.//.//.0..0017765ttq½-//Ήoop30./ 00l////////////////////////////////Ј..0023m3115r>ttr oünʻ//m3.//Έrm0pl/////////////////////////////////////////////.É/.00..4q9ttq 2../Έqrm0.om0///////////////////////////////////..ĉl..ˆ.//.35;trqq ýÈ//..0.///2oronll7.//////////////////////////////////////..////.359rqq qmŒ»l////Ήporr;7//n0////////////////////////////////Ή///l//щ//l019rq qn2mn////Ήq570.//n0./////////////////////////////////////////.qrtŒqq ˆӊЈ.///Ӌoe30./Ή/////////////////////////////////////////5ttēqqʊl////Ή02m0./Ήl./////////////////////////////////////05trq:r n-//0.///////////////////////////////////////////////////////qtrq4qr22-/////.щ//////////////////////////////////////////////////////.2qtrn0p n0p/////////////////////////////////////////////////////////3rtson..rrn4o2/////////////////////////////////////////////////////2rttrp0//01rlӋn////////////////////////////////////////////////////2rro2.//.Ӎrrъmpn////////////////////////////////////////////////////.oqo30/0rtqnl/0n12////////////////////////////////////////////////1p2./5rrq/.02n/////////////////////////////////////////////////////////ш/.2oq2.Јl///////////////////////////////////////Ή////////////////////..////.po//////////////////////////////////////////////////////////.n7n///////////////////////////////////////////////////////////////////l.ӈ//////////////////////////////////////////////////////////..l/////////////////////////////////////////////////////////////////////.///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Ή////////////////////////////////////////////////////////////////..////////////////////////////////////////////////////////////////..//////////////////////////////////////////////////// ( 8008((IAAA88QIIYIIaYYiaayqqqiiyyAIIiqqIaq (0QYaaiqiqyqyúAIY8AQaiyYaqy(008((0((888AAAI88I00A00IQQYIIQIIYAAQ88QYYaaaiYYiQQaIIaiiqqqyaaqiiyyyyyqq˲80I0(AA8QQIaú0(8( 0A8I80AIAQQIYaYiYQaiaqyú˺A0I8(AI8QYIa  8088(8IAIA8AI8IA0AYQYQIQYIYiaiaYayqyqiqyiyqaqyqy˺òúY8QqYiqAaqiyyYq( 8(0A08A 0YIQaQYaAQqaiyqyaqiy0 qyyi8A((( 888000IIIQQQYYYaaaiiiqqqyyy<<<}}]]]allegro5-5.2.10.1/examples/data/mysha.tga000066400000000000000000003644071473414355200200430ustar00rootroot00000000000000 @   0 (A008080 (0( A08I8AIAI808 ( 0((I8AQIQQAII8I0((   800A080(((((IAAYIQQAI808 (((((0((0 (0( I8AQAII8A8((((808YIQaQYQAIA8A0 ((0 (8008080((  0((IAIYIQI8A0(( IAIYIQ I8I8(8    8(0A08A8A8080 (0((YIQaQYYIQA08((800QIQYIYYIQA0A ( 808I8IA0A8080 (   8((YIQaQYiYaaIYI8A0 ( (A8AYIQ I8I0 (   A88I8AA8A0(( (0((QAIaQYaYaYIQI8I0 (( A08IIQYIYI8IA0A0 (  ( (A08I8II0A0(8 ( QAIaIYaQYYIQQAI808A88QAIYIQQIQI8IA0A8(80(( A0AI8IA0A8(8 ( (IAAYIYaQYYIYYIQQAIQIIQIQYIQYIYQIQIIQA8AI8IA0A8(80 ( ((  IAAaIYaQYYIYQIYYIYQIQQAII8IA0A0(8 0  (0((8(00( (0( QAIYIQaQYYQYYIYQIQQAIIIQAAI8(8 ( (   808I8AI088(((  (800QIQYQYYQQYIQQIYQIQQAIIIQIAIQAII8IA0A80A0 ( ( 0((8(88088(00 ( ( (   (A0AI8IQAIIAAA00( 0 ((8((IAAYQQYQYYIQQIQQAIIIQQAIIAII8IAAI80A0(88(08(88088(8 ( (   (A08I8AYIQYIIA00 (((0000 ((0( 8((IAAYIIaQYYQYYIQQAIIIQI8IIAII8IAAIA0A80A8(80(8 ( 0 ((  0((I8AYIQYQYI8A0 ( (808A8AA000( (0( A88QAIYQQaQYYIYQIQQAIIAIIIQI8IAAI 80A8(80(80088088(80(( ( (     (80AQAIYIQYQYI8I8(0( (80AI8II8A8(0(( (0((8((8(08((800IAAYIQaYYaQYYQYYIQQIQIIQAAIA8AI8AA0A80A0(80 ( 0 ( 8(08088((   (I8IYIQYIYI8I8(0( (A0AI8IA080(   (( 800A00I88IAAQAAQAIQIIYIIYIQYQQaYYaYaaQYYQYYIYQAIIAIAAI80A8(80(8 ( ( (808I8AA088(((  80AIIQQIQIAI8(8(  0(8A0AI8IA8A808(((8(08((800A00A88IAAYIIYQQaQQaYQYQYaYYYQYaYaaYYYQYYIYQIYQAII8I80A0(8 ( (   (800I8AQAII088(( 0 (AAIQAII8I8080 ( (0 (A0AI8A80A0((   ( 0((( 8((A88IIAYIIYQQaQQaYYaQYaYYYQQaQYaYYaQYYQYYIQQIQI8IAAIA8A80A0(8((8 ( (   (8(8I8AIAIYIQQAII8A0 ( (A8AQAII8IA0A0 (0(880A0(8 (((0( A00IAAQA8QAAYQQaQQaYYiYYiaaiYYiYaiYYaYYaQYYQYaQYYYYYQYQIQQAII8IA8A80A0(8 ( ( (8(8A0AQ8IQAI A0A0 ( (80AIIQQ8IA8A8088(880A8080 (   ( 800QA8YQQaYYiYYqaaiaaqaaiaaiYaiaaiYYaYYYQY YQQYQYQIQIIIQAIIAIAAI88A80A0(8((8 ( (  (0 (80AI8IQAII8I8(8( (808I8IA0A80A8(8 (0( A00I88YIAaQQqaYqaayiiqiayiiiiiqiiqaiiaaiYaaYYaQYaYYaQYYQQYQYYQQYIYQIQIAII8IAAI80A8080(8 ( ( (A0AI8IIAII8A0 (  0 (80AI8IA0A80A8(80(8((8((QA8YQQiYYqiiyiiyqqqiiyiiqiiyiiqiiiaaqaaiYaaYYaQQYQQYQYYQQQIQQAIIAIAAI80A0(8 (   0(8A0AI8II8AA0A0(880AI8IAAIA0A8088(80(8(0( A00QAAaQQiaaqaaqiiyqqyqiyqqyiiqiiyiiqiiqaiqaaqaiiaaiYYaYYaQYYQYYQQ QQQIAII8I88A8(80(8 ( ( (0(8A0AI8IIIQ I8IAAIA0A80A8088(8   (  ( 0( A88YIAaYQqaaqiiyqqqqyqqqqyiiqiiqaiqaaiaaiYaiaaaYYaQYYQQQAII8IA08 ( (   (80AI8IIIQQAIIAIAAIA8AA0A 8(0    (8080((   0( I88YQQiYYqiiyqqqqyqyyqqyyqqyqqqiiqiaqaiiaaaYYaQYYQQYIQYQQYIQYQQQAIA8A0((   (0(880AAAIIAIQAIQIYYIYQIQIIQI8IAAIA0A8(0( (0((8080((  ((800IIAqaYqiayqqqqyyyyyyyqqqyqqyiiqiiqaiiaaiYaaYaaYYYYYYQYYQQIAIA8A0((((888AIAIIIQQIYYIYYIQQIQQAIIIQI8IAAIA8AA0A0(80 (0((808A0A0(( ( ((( 0((0( A88aYQqaaqqyqyyyyyyyyyyyyqqyqqyiiqaiiaaaYaaYYYQYYQQYQYQIQIAIA080(( 0(8I8IQIQQIYYQYQIQQIYQIQQAII8IAAIA0A8(80(800880A8(8 ( (  (8((0 (( ( 800QA8YIIqaYyiiqqyyyyyyyyyyyyyyyyyyyqqyqqyqiyiiqiiiaaiYaaYYaQYYQYaQYYQYYIQQIII8A8000( (  (80AI8IQIQYIYQIYYIYQIQQAII8IAAIA8A88A80A8(80(80080(8 ( 0( 8000(((A08808  (0( 0((0( A00QA8YQQiYYqaaqqyyyyyyyyyyyqqyqqyiiqiiiaaqaaiaaaYaaYYaQYYQYYIQQIIQIQQIIIAAA880(( (  0 (I8IIIQYIYQIQQAII8II8AA8A80A8080(8 (  800IAAA08(A88A0A ((800A88IIAaQQqaYyiiqqyqyyyyyyyyqqqyqqqiiiaaqaiiaiiYaaYaaYYYYYaYY YQYYQQQIIA888(((  (808I8IIIQQIQYIYQIQQIYIIQQAIIAI IIQI8IA8A80A0(8 ((I88QAII8A( A88I8I8(00( QA8aQQiaaqaayiiqqyyyyyyyqqyqqyiiqiiqaiiaaqiiqaiiaaiYaaYaiYaaYYaYaYYYaYYYQYYQQQIIIAAA88A088(0 ( (0(880AAAIIIQQIQYIQYIYQIYQIQ QAIIIQQAIIIQIAII8AA8A0(8 (  0( IAAYIQIAIA008((IAAQIIQAIA00YIAqiayqiqqyyyyyyyyyyyyyyqqyiiqiiqaiiaaqiiqaiaYaiYaaYaaYYYYYaYYYQYaQYYQQQIIIAAA88A000(( ( (((880AAAIIIQQIQYIQYIYQIYYIQYQYQIQQAIIIQAAIA8A8080(( ( 0 (A08YIQaQYYQQQAIYIQaQYiYaiYYyqiyyyyyyyyyyyyyyyqqqqyiiqiiqaiiaiqaiiaaaYaiaaiYaaYaaYYaYaaYYaQYYQYQQQQIQQIIIAAA08A888000(( (0( ((  (8(8I8IIAIYIYYQYYIYYQYQIYQIQIAIA8AA0A80A((8 ((  0((A08QAIaQYaYaiYaaYYaYaiaaqaayiiyqqyyyyyyyyqqqiiqaiqiiqaiiYaaYaaYYaYaaYYaYaaYYaYaaYYaYaaYYaQYaYYYQQQIQIIIIIAIAAI88 A880(( (0((0 (0( ( ( (808I8IIAIQIYYQYYIYYQYQIQQAIIAAA8A8080(( ( ( 0( 0 (8((0 (0((8((8(0A(0 ( ( ((0((8((A00I88QIIaQYaYaiaiqiqyiiyqqqqyyyyyyqqyyqqyqqqiiyqqqaiiaaaaaaYaaYYaYaiYaaYaaaaiaaaYYaYaiYaaYYaYaaYYaYaaYYYYYYQQYIQQIQIIAQAAIAIIAAA88IAAA088(0(((    (0(8AAIIIQYQaYQYYQaYQY YIYQIQIAII8AA88888((8  (( 0( 0((0 (0((0 (8((8(08((0((8(0A(08(0A(08(0A00800A00A08A00A(0A(8A00A(0I00A08I08808I00I08A08808A08A00A08A00A08(( ( 0( 0((8((8(00((0( (0( 0((8((A00QAAYIIYQQiYYqaayqqqiiyqqyyyyyyyyqqyyyqqyiiqiiyiiqaiiaaaYaaYYiYaaYaaYYiYaaYaaYYaYaaYYaYaaYYaYaaYYaQYYYYaQYYQQQQQYQQYQYYQQYIQQIQQIIIAIA88800 ( (((888AIIQYQaaQYaYaaQYYQYQIQIAIAAI888800 (    ( 0( 0((0( 0 (0((8((8(00((8((8(08((8(0A(0800A00A(0A00A08A00A08I08A08A00A08I08A08A00I00I08A00I00I08A08I00A00A08I08A08A00I00A00A08I00A08A00I08(((  ( 800A88 A000 (0( 0((A00QA8YQQaQQaYQqaYqiayqiyqyyyyyyqqqiiqaiiaaiYaaYYaYaiYaaYaaYYaYaiYaaYaiYaaYaiaaaYaiYaiaaaYaiYaaYaaYYYQYYQQYQYYQQYQYaQYYQQQIQQIIIAIA8A808(((0(   ((8A8AIIQYQYaYa aQYYQYYQQQIQIAIA880((   (   (0((800A00A08A00A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A00I08A08I08A08I00I08I00I08A08I00A00A08I08A08A(8I00( 0( A88IIAYIIIIAYIIYIAIIAYQQaYQqaYyqiqqyqyyyyyqqqiqqiiqiqqaiiaiiYaaYaiaaiYaaYaaYYaYaaaaaYaiaaaYaaaaiaaaYYaYaaaaiYaaYaaYYqaYaYaaYYYQYYQQYQYYQQYIQYQQQQQYQQYIQYQQQQQQIQQIIIAAA880(((  ((8A8AIIQYQYaQYiYaaYa aYYYQYQIQIII88A800 (   ( (((88(8A08I08A08I08A08I08A08I08I88I08A08I08A08I08A08I08A08I08A08I08A08 I08A(8A08I08A08I08I00A00A(8A(0I08A00I00A00I08A00A08I08A08A00A08A00A(0A00A08A00 (0( 800A00QA8IIAaYQqaaqiiyiayqiyqqyqyyyyyyqqyqqqiiqaiiaiiaaaYaiaaaYaaaaiaaaaaaYYiYaiaaiYaaYaaaaiYaiaaaYaiaaiYaaYaaYYYQQQIQQQQYQQYQYYQQQIQYIQQQQYQQYIQYQQYIIYQQQIQQIIQIQYQQYIQ YQQQIQQIIA8A8080((8(0808A8AQIQYQYaQYaYaaQYYQQQQQIAAA080 (   ( 0 ( ( 0((880AA0AI08A08I08I88A08I08A08I08A08I88A08I08A08I08A08I08A08I08A08I00A00I08I00A00A08I08A08I08A08I08A08A00A08I08A08A00I08A08I00A00A08I08A08(8((A00YIAaYQqaaqiaqqy yyyyyyqqyqqqiiiiiyiiqiiqaiqiiiiiiaiiaaaYaaaiiaaaaaiaaiYaaYYaaaaYaiYaaYaaYYiaaaYaiaaaYaaYYYQQQIQQIIYQQYQYYQQQIQYIQQQQYQQYIQYQQQQQQIQQIIIAIIAAIIQQIQQQQYQYaYaaYYaYaYQYaQYYQQQIIQAIA08 ( ( ( ( ( (0(8A0AA8AA08I08A08I08A08I08A08I08A08I08I08A08A00A08I08A08A00A08A00A08I08A08A00I08A08I08A00I08A08A00I00A00A08A00800A00( ( 0( (( 8((0((8((A88QA8aQQqaYqqyyyyyyqqiaiqiiqaiqiiiaiiaaiYYaYaiaaaaaiaaiYaaYaiYaaaaaYaiYaaYaiaaaaaaYaaYYiYaaYaaYYYYYYQYYQQQQQQIQQIIYIQQIQYQQYIQQIQYIQQIQYQQQIQYIQYQQYIQYQQYQY YQQaQYYQYaYYYYYYQYYQQYIII880((  (  ( ( ( ( 0((8008A8AI08A08A88A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08A00A08I08A08I08I00A08A(0A08I08A08888AAIIIAQIIaYQaYYYYYQIIAAI0(( (0 (8((8(0A08A008008((8(0800 A00I88IIAYQQaYYqaYyiiyy yyyyqqqiqqiiiaaiYaaYaiYaiaaiaiqaiiaiiaaaYaYQYYYYaYYaYaaaaiaaaYaaYYaaaiaaaYaiaaaYaiaaaYaaYYaYaaYYaQYYQYYQQQQQQIIQIQIIIQIIYIQQIQQQQQIIQIQQIIYQQYIQQQQYQQYQYYQQYQYYQQIAI8880((    ( ( (  ( (((80(888AA8AI88A08I08A08I08A08I08A08I08A08I08A08A08I08A00A08A00A08I08A08A00A08I00A00I00A08A(8I08A00A08A00A08A00A08A00qqyyyyyyyqyiaiYYYAAI((80((8((A08I8AIAAQAAQ8AI8A Q8AYIIYQQaYYiaaqiiqqyòúòyyyqyyqqqaiiaiaYaiYaiaiiYaaYaYQYQIYQIQYQYaYaiaaaYaaYYiYaiaaaYaiaaaYaaYYaQYYQQQQQQIQYIQQIIIIIQIIQIQYIQQIQYQQaQYaQQYQQYQYaQQYQQYQYYQQYIQQIIIAAA08    ( (  (((880AA8AA0AI08A88A08I08A08I08A08I08A08I08A08I08A08I08I08I00A08I08A00A08I08A08I08A00I08I00I08A00A08I08A08I08A08I00A00A08A00I00I08A00I00A08A00A08yqiqaYaIII8080((800I88I8AQAAQ8AQAIQIIYQQqaYqiaqqyyòú˺úòyyyqyyqqqiqiaiiYaiaiqaqqaiaaiaQYaYaaQYYQYYQQQIQIIQIAIQIQaQYaYYiYaaYaaYYiYaiaaaaaaYaaaaaYYYYYaYYaQYYQYYQQQIQIIQIIIQIQQIIQIQQIIQIQYIQQIQYIQYQYYQQQQQQIQYQQYQYYQQaQYYQYaQYYQQYQYYQQYIQQIQYIQQIIIAA8000(( (      (((8008808A88A08I08A08I08A08I08A08I08A08I08A08A(8A08I08A00A08A00I08A08A00I00A00A08A00A(0A(8I00A00A08A00A08A00A08A00 yqyiaiYQYIAI800A00I8AQ8AI8AQAAQ8IQAAQAIQIIYQQaYYqaayiiyqòú˺úò yyyyqyyyyqyyqqqaqyqqqaqqiqiYaaaiiYaaYaaQYYQYYIYQIQQIYYIYQIQaQYaYYiYaaYYaYaiYaiaaiYaaYaaYYaYaYYYYQQQIQQIIQIQYIQQIIYQQYYYYQQQIQYQQYQYYQQaQYYQYaQYYQYYQQaQYYQYaQYYQYYQQYQYYQQQQQQIIIAAA88(((      (((8000008808A08I08A08I08A08I08A08I08A08I08I08A08I08A08A00A08A00A08I00I08A00A08A00A(0A00A08A00A08I08A08A00I08yyyyyqiqYYaQIQI88I08I8AQAI YIIYIQaQYiaaqiayqiòòúú˺úòyyyyyyqyyiyqaqiaqiYaaaiaYaYIYYQaaYaaaiaQYYQaYIYaQYYQaaQYYQYYIYYIQYQYaYaiaaaYaaYYYQYYQQQQQQIQIIIQIIIIQQIQYIQYQQQIQYQQYYYYQQQIQQQQYQQQQQYQQaQYaYYYQYYYYaYYYQQaQYaYYaQYYYYYQYaQYYQQaQQYQQYQYYQQQAAI8A0(( (     ((((0((000808A08A00I08A08I08A08A88A08I08A08A00A08I00A00A08A00A08A00A08I08A08A00A08A00I08A00A08A00I08A08A00A08I00A00A(0A08A00I00qqyyyyyyyyyyyqiqaYaQIQQ8AI8AQ8AQAI YIIYIQaQQaYYqaayqiyqòúòòúú˺úòòyyiyqqyqaqiYqaaiaYaYQaQIYQAaQIYYQaaYaYIYaQYYQYYIQQIQaQYiYYiaaiYaaYYaYaaYYaYaiYaaYaYQYYQQYQYYIQQIQIIQYQQQQQQIQYIQQIQQIYaQYaYYYQYQQQQIIIAIQAIQIQYQQYIQYQQQQQYQQYQYYQQaYYYQYYYYaYYYQYYYYaYYYQYYQQaQYaQQYQQaYYYQQYQYaQYYQQYIQQIIQAA8000 (      (((80((808A08I08A08I08A08A08I08A08I08A08I08A08A00A08A(8A08A00A08I08A00A(0A00A08iaiiiiqiiqqiyqqyqyyyyyyqyqiqiYaYQYQAAI8AQ8AQAAIAAQAI YIIaQYiYYqiiyqòú˺˺úòòyqqaqiYqYQaaAqQAaQ8YA8iQAaYIYYQaaQYYQaYQYQQQYQYaYYaaaaYYYQYaYYiYYaYYYYYYQYYQQYQYYQQQIQYQQQQQQIQYQQaQYaYaaYYYQYQQQQIQYIQQIQaYYYQYaYQYQYYQQaYYaQYYQYYQQYIQQIQQIIA8A800 (     (((8000808A08I08A08I88I08A08I08A08I08I08A08A00A08I08A00A08I08A08A00I08A08A00A08A00A08A00808A08A00A(0A08A00I00A00A08A00aYYaaaiaaqiiqqiyqqqqyyyyqyqiiaYaYIQI8AQ8AQAIQ8AI8AIAA QAIYIIYIQaYYiaaqqòú˺úúòúòqqaqiYqYQaQAaA8i0 AA8iQAaYIYaYaaaiaYaaQYaYaiYaaYaiYaaYaaYYYYYYQQYIQaYYYQYaQYYQYQIQYIQYQQYIQQIQYIQaQQaYYYYYYQYaYYYYYYQYYIQQIQYQQQIQYQYYYYaYYYQQYQYaYYiaaaYYYQQQQQQIQQAII8A800((( (  (((0((808A08I08A08I08A08I08A08I08A08I08A08A08A00A08I08A08I08A08I08A08A00A08I08A(8A08A00A08A(8A(0A08A00A08A(0A08A(0A(8YQQYYYiaaiiiqiiyqqyqyyyyyyqqqiiaQYIAII8AQ8AQAAQ8AQAAI8A IAAQAIQIIYIIYQQqaYqiayqú˺úú˺òú˺òòyiqYiYqYQaA8i0 AA8iQ8YQAaaYaaaiiYqiaiaaiiaiiYaaYaiYaiaiaYaaQYYQYYYYaYYYYYYQQQQQQIYYQYYQQYQYYQQYIQYQQYQYaQYYQYYYYYQYYYYYQYYIYYQQYQYYQQQIQaYYaQYYQYYQQaYYaYaaYYYQQYQYYQQQQQQIQQIIQIQQQQQIQIAIA880(( (     (((80((808A08I08A08I08A08I08A08I08A08I08A08A08I08A08I08I00A08A00I08A00A08A00A08A00A08I08A00A08A(0800A00I00A00A08A00I00QQQaYYaaaiaaqiiqqqyqqyyyyyyyyyiiiaiYQQQAIQ8AI8AQ8AQAAQAIYIIYQQaYYqaaqqòú˺ú˺ú˺òò˺òyyiqaiYqaAqQAaA8iYQaiYqqaqqiqiaqiYqaaiaQYaYaiaiqaiaYaaYYaYaYQQYIQYQQYQYQIQYIQYQYaQYaYYYQYQIQYQYYQQYIQYQYYQQYIYQIQYQQYIQQIQYQQYQYaYYaaaiYYYQYYQQQQQYQQYIQQIQQQQQIQQIIQIQQIIQAAA888000(( (   (((8000808A08I08A08I08A08I08A08I08A08I08I00A08I08A08I08A08I08A08A(8A08I00A(0A00A08A00I08A08A00A(8YQYaaaiiiqiqqqqyqyyqqyyyyyyyyyqqqaiaYaQAII8AQ8AQAAQAIQIQYQQaYYiaayqqyyò˺úúú˺úòúòòqyiqaiYqqYqaqYQAaA8iQAaiYqqaqyiyqiqqaqaYaaQYaaiiaiaYaaYYaYaaYYYQYaYYYYYYQYYQQYQYaQYaYaYYYYQYYIQYQYaQYaYYYYYYQYYQQYQYYQQQQQYIQaYYaaaYYYYQYYQQQIQQIIYIQYQYYIIQIIIAIQAIQIIQIQQIIIAIA8A8000(( (  (((80((A00A08808A08I08A08I08A08I08A08I88I8AI08A08A00A08I08A08A00A08A00A08A(8A(0A08A00A(8A(0A00A08A00A08A00A08I00YYYYYaaaaiiiqiiqiqqqqyqyyyyyyqiqiYaYQYQAII8AQ8AI8AIAI QAIYIQYQQaYYiYYyiiyyò˺ú˺úòúòúòòòqyiqayiqaYQaA8iQAaiYqqaqiaiaYaaaiqaiaaaaYaaYYaQYYQYaYYYQYYQQQIQYQYYYYaYYYQYQQQYIQQIQYQYYQQYIQQIQYQYYYYaYYYQQQIQYQQaYYYQQQIIQAIQIIIIIIAAIAIQIIQIQQIIIAAA880((((8 ((((((80((800808A08I08A08I08I88A88A08I08I00I08A00A08I00A08I08A08I08A08I08A08I08A08I00A08A00A08A00A08A(0A00A08YYaaaaiiiqiiqqqyqqyyyyyyyqyqiqqiiaYaYIQQAAQ8AQ8IQ8AI8AQ8AQAIYIQYQQiYYyiiyqò˺ú˺úòúòòúòyqyiqaiYqA8iYQaiaqqqyyiyqaqiYaaaiiaiqiqyqqqaiiaiaYaYYYYQYYQQQIQYIQYQQYQYaQYaYYYQYYQQQQQQIQQQQYQYQQQYQYYIYaYYYQYYQQQQQ aQYYQYYQQQQQQIQIIQIIIIAIA8AAAIIAAQAIQIIIIIQIIIAAA880000((((( ((((((8808A88A08I08A08I08A08I88I8AQ88I88A08A08A00I00I08A08A00I08A00A08800I00A00A08A00A08I00A00A(0I08A00A08aaaaaiiaiqiiiiiqiiiiiqiqyqqyqyyyqqyqqqaiaQYQIQQAIQIIYIQQIQQAIQAA QAIQAAQAIYIQaQQqaaqqò˺úú˺ú˺úòúò òyqyiqaiYqaAqiYqyiqyqqqyyiyqiqqaqiaiiYaaYaYYaaQYaYaaQYaYYaYaaYYYQYYQQQIQYIQQIQYQYaQYaYYaYaaYYYQQYQYaQYaYYYQQYIQQIQQIIIAIIAAA8AAAIIAAIAIQIIQAII8A8080000((((( (((8000808A08A88I08A08I8AI08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08I08I00A00A08I08A00A08A00A08800I00I08A(8A00A08aYaaaaaaiiaaiaiqaiqiiyqqqiiqaiiYaYQYQIQI8AQAAYIIaQQYQQYIQaQQaYYyiiyòú˺ú˺úòòúòyqyiqyiqaiYqiaqyiyyqyqyqyqyyiyqiqiaiqaiqaqqaiyqqiiiiaaYYYYQYYQQQIQQIIYIQQQQQIQYQQYQYaYYaYaaaaaYaaQYaYYaYYaQYYQYYQQYIQQIQQIIIAAIAIIAAAAIA88A8AIAAIAIQIIIAAA88A088080(((((((8000A08808A08A88I8AA88I08A08I08A08A00A08A00A08A00A08A00A08I00A08A00I08A08A00808A00A08A00A08aQYaYYaYaaYYaYaaYYiYaiaaiYaqaaiYYaQYYIQIAII8AIAAQ8A QAAYIIaQQaYYaQYaYYqaYyqòú˺úú˺˺˺ú˺ú˺úòúò yqyqyiqayiyiyqyyqqqyiaqqaqyiyyqqqaqiaiqiiiaiaYaYIYYIQQIQYIIYIQYQYaYYiYaiaaqaiiaiiiiiaaaYaaaaYYYaYYYQYQQQQIQaYaYYYYQYYQQYYYYQYYQQQIQQQQQIIIAIIAAA8AI8AIAAIIIQIQYIIQAIIAIA8AA88800000(((((80((000A8AI8AI88I08A08A88I08A08I08A08I08A08A08I08A08I08A08I08A08A00A08A00I08A08I08A08A00800A00A08808A00A08A00A08A(0A08A00aQYYQQaQQYQQaQQYIQaQQaYYaQYaQQYQQYIIQAIQ8AI8AQ8AQAA QAIQIIYIQYQQaQYqaYqiayòú˺ú˺ú˺úòyqyiqyiyqyiiYqqaqyiyqaqqiqiaiiYaaYaiYaaYaiYaaYaYQYaYYaaaiaaaaaaYYYYYYQQYQYQQQYQQQQQYQQQQQYQQYIQQIQYQYYQYaQYYQQQIIIIIIAIIIIIAIIIIQIQQIIIAIIAAA88808000888A8AA08I08A08I08A08A08A00A08I08A08I08I00A00A08A00A08A00800A00A08A00A08A00A(0YIIYIQQIQQIIYIIQIIYIIQAAYIIQAIYIIQAAI8AQ8AIAAI8AQ8AQAIQAAYIIYQQaYYqaayqi˺ú˺ú˺úyqyiyiqqaqyqyqyiyyqqqiqyiyqiqiaiqiqqiiiaaaYaYQYYIYQIQYIYQIQYIQQIQQIIQAIQIQYIQYQYYQQaQYYQYYYYYQYYYYaYYaQYYQQQIQQIIQQQYQYQIQQIIQAAIAIAAIIAIIIIQAIQIIQAIIAAA88888808008000808A08A8AI08A08I08I88I08A08I08A08I08A08I88I08A08I08A08I08A00A08808A00A08I08I00A00A(0I08A08A00I08A08A00A08I08I00A(0A08A00Q8AQAAI8AQAAQ8AI8AQ8AI8AQ8AI8AQ8AI8AQ8AI8AQ8AQAAQAIQIIYIIaYQqiiyú˺ú˺ò˺úòyqyqyiqyyyqyiyyqyyqqqaqqiqqqqqiqiiiiaiiaaqaaiaaiYaaYaiYaaYYiYYqaYaYYiYYaYYaYaaaaYQYaYYaYaaYYYYYYQYaYYaQYYQYQQQQIQIAIA8AA8888AA8AIAIQIIQIQQQQQIII8A808000008808A8AA08I08A08I08A08I08A08I08A08I08A08I00A08A00A08A00A08A00A08A00A08A00A08A00I8AI88I8AIAAI8AI88I8AIAAQAAQ8AQAIYIIaQQ˺ú˺òòòòòyqqqqyaYaqqyyqqyiyqqyyqyyyqiqiaiaYaYYaQIQQAIQIQYQYYYYYQYaYYYYYYQQQQQQIQYIQYQQYQYaYaaYYaQYaYYaYaYYYaYYYQYYQQQIQQAIIAIA8AA08A8AI8IIAIQIIQAIIAIQAIIIIQIQIAAA8880800088888AA8AA88I8AA08I88I08A08I08A08I08A08A08I08A08I08A08I08A08I08A08I08A00A08A(0A08A(0A08I08A08A00800A08A(0A00A08A00A08A00A(0A08I08A08I8AIAAI8AQ8AI8AQ8AI8AQ8AQAIYIIaYYúú˺˺òòòyyqyyqqqaqyqyyqyqyqiqiaiaYaYQYQIQQAIQIQQQQYQYYQQYIQQIQYIQQIQYIQYQQQIQQIIIIIQIIQIQQIIYQQQQQYQYaYYaYaaYYYQYYIQQIQYQQYQYYQQQQQQIQQIIQAIIIIQIQQIIIAAA8AA88888A88A8AA88A08I08A08I08A08I88A08I08A08I08A08I08A08I08A08A00A08A00A08A00A08A00A08A00I00A00A08A00800A00808A08A00A08A(0A00I8AQ8AI8AQ8AI8AQ8AI8AQ8AQAAQ8AI8AQ8AQAIYQQ˺˺ú˺úúúòòòòòyqyyyyyyyqqqaiiaiqiqyqqqiiqaiiYaaYaaQYYQYYIQQIQYIQQQQYQQQIQQIIIAIIIQQIQYQQaYaiYaaYaiYaaYaiaaaaaaYYaQQQQQ QIIIAIAAIIAIIIIIAAA8AIAAIAIAAIIIIIAIAAIA8A88A888A8AI88A08A88I08I88A08I08A08A08A00A08I00A00A08A(0A08A00A08A00A08A(8A08I08A088(0A(0A08A00A08A(8QAAI8AI88Q8AIAAI8AQ8AI8AIAAI8AQ8AI8AQ8AIAAQAAQAIYII˺òòòòòò yyyiyiYq qqyyqyyqyyyyyqqqiqiaiiaaiiiqqiyqqyqyqqqaiiYaaQYYQYYIQQAIIAIQIQqiiqiaiaaaYYYYYQQQIIQIIIIIAIAAAAIIAAA88A8AA88888AAIIAIAAIA8A80888AA8AI8AI88A08A88A08I08A08I08A08I08A00A08A88A08A00A08I08I00A08A00I08A00A08A00A(0A00A08I8AQ8AI8AQ8AI8AQ8AI8AQAAQAIYII ˺úòò˺úòòòòqyqaqiaqyyyyqaiYQYYIYYQYaYaiiiyqqyqyyyyyyqqyiiqiiqaiqaaiaaiaiqaaiaaaYYYYYaYYYQYQQQIAAA8AA88A8AI8AA8AA88A8AAAIA8AA88888A8AI8AAAIIAAI8AA8AI8AI88I8AI08I88A08I88A08A00A08I08A08I08I08A08I08A08I08A08A00I08A08I08A00A08A00A08A00I00A08A00A08A00A08A00A08808A00A08I8AI88I8AA8AI8AQ8AI8AQ8AQAAYIIQAIYIIúòò˺úòòò úòòúòqqqqyyyqqiaiiaaaYaaYYYQYYYYYYaaYYaYaYYYYYaaaaiaiiiiqiiyqiqiiaYaiaaaYYYQYQQQQIIIAAAAIA8AA88A8A808A8A888A8AIAAI8AA8AA88A8AAAIIAIIAAI8AA8AA88I88I8AA88A08A88I88A08I08A08I88A08A08A00I08A08A00I00A00I08A00A08A00A08A00A08A00A08A00A08A00A08A00A(0A08I8AI88Q8AI8AIAAI88I8AIAAI8AQ8AI8AQAAQAIYIIú˺òòúò˺úò˺òyyqyyiyyyyyyyyiaiaYaiaaaYaiaaaaaaYaYYYYQYQQQYIQQIQQQQQIQYQYYQQYYYYQQQQQYQQYQYYQQQQQQIIQAIIAIAAI88AA8AAAIIAIAAIA8AIAAA8AAAIIAIIAAIAII8AI0AI08I0AA08I08A08I08I08A08I08A08A(8I08A00I08A08I08A08A00A08808A08A00A08I08I00A00A08808A00I00A00A08I8AI88I8AI88Q8AI8AQAAQ8AIAAI8AQ8AQAAQAIYIIúú˺òòú˺òòò˺˺˺òqyyyyyiyyqyyyyqyyyyqyqiqqiiiiiqiiqaiiaaaYaYYYaYYaYaaYYYQYYQQQIQIIIQIQ aaaaYaYYYYQYYQQQIQIIIIAIAAI88A888A88A8A888AAI88AIAAIAIAAIIAIIAAAAIIAIAAIIAIIIIIAIIIIIAII8AI08A08A88I88I08A08I08A08I08A08I08A08A00A08I08A08A00A08A00A(0A(88(8A08A00A08A00A08A00A08A(8A08A00A08A00I00I8AI88I8AI88I8AQ8AI8AQ8AI8AIAAI8AQAAQAIQAAQAIQIIYIIYQQ˺òò˺ò˺˺òy yqyyyyyqyqiqyqqqiqqaiiaiiaaaaaaYaYYYYQYYQQQIQQQQQIQQQQQIQaYaaYYYQYQIIIIIAAIA8AI8AAAIA8AIAAIAIAAIIAIAAIIAIIAAIAIQIQIAIIAAI8AA88I0AI08A08A88A08I08A08I08A08I08A08I08A08I08A08A00A08A(8A(0A08I08A08A(8A08A00A08A00808A08I8AA8AI8AQ8AI8AQAAI8AQ8AI8AQ8AQAAQAIQIQYIQaQQaYY˺òò˺˺úòyyyyyyqyqiqyqqqqqqiiqiqiiiaaaaYaYYYYQYYYYYQYQQQYQQYQYQIQaYaaYYYYaYYYYQQIIQIAIAAIIAIIIIQIIIIQIIIIAIQAIIIIIIQQIQQIIIAIQAAI8AI08A08I88A08I08A08I08A08A08I08A00A08808A08A00808A00A08A00808A08I00A00A08I08A08A00A08A00A08A00I8AQ8AI8AQ8AI88I8AQAAIAAQAAQAIYIQaQQaYYiaa˺úòò˺ú˺òyqyyyyyyyyqqqiiiaiiaaaYaYQYQIYYQYaYYYQYYQQQIQYQQYYYYQYYYYYQYQQQQIQIAIAAIIAAIAIAAIIAIIIIQIIIIIQIQYQQQIQIIIQIQIIQQIQQIIQ8AI8AA88I0AI08I88A08I08A08I08A08I08I08A08I08A08I08A08A00A08A(0A08A00A08I08A00A08A00A(0A08A00A08A00I8AI88I8AA8AI8AQAAYIIYQQiaa˺ò˺ú˺˺òyyqqyyyqyyyyyyyyqyqiqyqqqiqqaiiaiaYaYQYaYYYQYYQQQIQQQQYIQiaiiaaaaaaYaYYYQQQIIIIAAIAIA8AAAIIAAAAIIAIIIIQIQQIIIIIIAIIIIQIQQIIIAAI8AA08I88I08A08I08A08I08A08A00A08I08A08A00A08I08A00A08A00A08A008008(0A(0I08A08A00A08A00800A00A08A00A08I88I8AI88I8AA8AI8AQ8AQAAIAAQAAQAIQAAQIIYIQYQQqia˺òò˺ò˺˺˺˺òò yyyyqiqyqqyyyqyyyyyyyqqqiqiaiiaaiYaaYaaYYaYaYYaYQYQQQYQQQQQaaaaYaaYYQQQQIQIIIIAIAAIA8AAAIA8AIAAIAIIIIQIQIIQIIIIAIQIIIIQQIQYQQYIQQIIQAIIAAI8AI08I88I08A08I08A08A08I08A08I08A00A08I08A08808I08A08A00I00A08A00A08I08A00A08I08A08A00A08I08A08A00I08A00A08A00A08A00I8AI88I8AI88I8AIAAQAIQAAQAIQIIYIQaIQaQQqia˺òòòú˺˺˺òúyyqiqyqqyyyyyyyyyyyqyyyyqqqiqyqqqiqiaiaaaiaaqiiiaaYQYaYYYQYQIQQQQYQQaYYaQYYQYYQQQIQIIIIAAA8AAAIIAIIIIIIQIAIIIIIIQQIQQIIQAIIAII8AA8AA88I88I08A08I08A08A08I08A08A00A08I08A08A00A08A00A(0A00A08A00800A00A08A00I08A00800A00I00I8AI88Q8AI8AI88I8AQAAIAAQAAQAIYIIYQQaQQaYYqaaúòúò˺˺úòyyyqyyyyyyyyyqiqyyyyyqiqiaiqiiYQYaYYYQQQIQIIIIIQQIQaYaaaaYYaYQYQIQQIIIIIIAAIAIAAIA8AAAIIAIIIQQIQIIIIAIIIQYQQQIQQAII8AI88A08A88I08A08I08A08I08A08I08A08A00A08A00A08A(0A08A00A08A00A08I08A08A(8A00A08A00A08A00I00A00A08A00A08I8AI88I8AA88I88I8AA8AI8AQ8AQAAIAIQAIQIIYIQYQYaYYqqiúòòúò˺˺òqyqyyyyqyyyyyyyyyqyyqq yyyqyyyyyyyyyyqyqqyqqqiqiaiiYaaYYYIQQIQYQYQIQQIIQIQQQQIIQiiiiaiaaaYYYQQQQIQIAIAAIA8AAAIIAIIIIIIQQQQYQQQIQIAIQAII8AA8AI88A88I88I08A08I08A08I08A08A00A08I08A00A08A00A08A00A08A00A08A00A08A00A08A00800A00A08A00I00A08A(0I8AI88I8AI88I8AA8AI8AQAIQAAQAIYIQaYYiYayqqúò˺˺˺ò yyyyyyiyqaiiaiiaa iiiqiqyqqyyyyqqyyiaaaYaiYaaQYQIQYQQQIQqiqqiiiaiiaaaYaYQYYQQQIQIAIAAIIAIAAIIAIQIQIIQIIIIAIIIQYQYYQQQIQQIIIAAI8AA88A08I08I0AA08I08A08A(8I08A08I08A08I08A00A08A00A08A00I08800A08A00A08A(8A(0A00A08A(8A00A08A00I8AI88Q8AI8AA88I8AQ8AIAAQAIYIIYIQaIQYQQaYYiaaqaayqiòúú˺˺˺úòyyyyqqiaiiaaaYaYQYaYYiaiiaaiaiiiiiaiiaaaYaaQYYQYQIQQQQQIQiaiiaaaYaaYYQQQIIQIAIIIIIAIIIQQIQIIQQIQIIQQQQQIQIIQIIIQIIQIQYQYYIQQIIIAAI8AI0AA08I08A08I08A08A08A00A08A00I08A08I00A00A08A(0A08A00A08A00A08A00A(0A00A08A00A08A00I8AQ8AI8AI88I8AQ8AI8AI0AI8AQAIYIQQIQQIIYIIQIIYIQYIIYIQYQYaYYqia˺ò˺˺˺ ˺˺úòyyyyqqqiqyqqqiqiaiaYaiaiiaaaYaaYYaaaiaaaYaiaiaYaaQYYQYYQQYYYYQYQQQQIQIIQQIQQQQYQYQIQQQQYQYYYYYQYYQQQIIIAAI8AI88I0AA08A08A00A08A00I00A00A08I08A08I08A08A(8I08A08I08A08A00A08A00A08A00I00A(0A08A00A(0A00A08A(0I00I8AI88A88I8AI88I8AI88I8AQ88I88I8AQAAQ8AI8AQ8AQAAQAIYIIYQQiaa˺˺ú˺Ӻò˺úyyqyyyyyyqiqiaiqiqqqqqiqqiiiaiiaaiaiaYaYYYYQQQIQQQQYQYaaaiaiqqqiiiiaiaYaYQYQQQQIQIIQIIIIAIQIQQQQYQYQQQYQYQQQQIQYQYA08A00A08A00800A00800A00A08A00A08A00A08A00A08A00800A00A(0800A00A08A00I8AQAAI8AQ8AI8AA8AAAII8AI88I8AI88Q88Q8AI8AQAAQ8AYIIaQQqiaúò˺òúòyiyiaiiiqqqyyyyyyyyqiqYIYYQaiiiqiqqqyqyqyyyyqyqiqiaiiaaiiiiaiaaiaaaiaiiaaaYYYQQQIQYQYQIQQQQYQYiaiiaaaYaYYYQQQIIQIIIIIQA08I08A08A00A08A00A08A00A08A00I08I00A08A00A(8A00I08A08I08A00A08A00A(0A00A(0I8AI88I8AI88I8AI88I8AI88I8AI88I8AIAAQAAIAII8AQAAYQQqia˺ò˺˺òò yyqyiaiYIYYQaaYaYYaIIY0(8IAIQAI80A0(8Q8YYQaqqyqyyyyyyqyyqqiaiaQYYQYaQYaYaaaaiaaaaaiaaaYYYQYYYYYQYYQQaaiiaiiaaaaaaYaaYYYYYYQYA08A00A08A00A08A88A08A00A08A00A08A(8800A00A08A00I00A00A08A00I00A08A00A08A(0A00A(0A00A(0A00I08A00A(0I8AI88I8AI88I8AIAAI8AQ8AI8AQ8AI8AQ8AQAIYIIqaYúòú˺qY˺˺òòyyyqYYaIIQ88A80A 0008I8I0 A 080AYYaiiqyqyyyqyqiqyyyyqyqaiiYaaYaYQYYYYYQYYYYaaaaYYYYYYQYaQYYQYaaiiaiiaaaaaaYYaaaA08A00A08I08A08A00A08A00I00A08A00A(0A00A08A00A08A00A(0A08A(0A08A00I8AI88I8AI88I8AI88I8AIAAQAAI8AIAAQAIQAAQAIQIIYQQqaY˺úò˺Q8Y˺ú yyiai0 A 0 ( (88A80AQ8YIIYaaiqaqyqyyyyqqiaiqiiyqqqiiqiqqaiiaaaYaiaiiYaaQYYQYaYYYQYYIQQIQYQYYYYA08I08A08A00A08A00A08A00800I00A00A08800A00A08800A00800A08A00800A00800A08A00I88I8AI88I8AQ8AI88I8AA8AI8AA8AI8AIAAQ8AQAIQIIQIQYIQYQQaQYiYaiaaqii˺˺ ú˺A8i˺˺yyqyiYa80A 0 (008QIYQAaYQaiaiyqqiaiqiqyyqiqqiiqiqqqqqiiiaiYYYYQYYQQYQYYQQYIQA08I08A08I00A08A00A08I08A08I08A00A08A00A08I08A00A08I08800A00A08A00A08A00A08I8AA8AI8AI88I8AI88I08I88I8AQ8AI8AIAAQAAQAIQAAQAIYIIYIQaQYiYaqii˺ú˺A8i˺òiaqaQYQ8YIIQ 088AaaiiaqqiqyyyyyyqqyyyqqyiiiaiiaaaYaaYYYQYYYYYQYA08808800A00A08A00A08I08A00A08A00A(0A08A00A08A00A08A00800A(0A00A08A(0A00I8AQ8AI8AI0AI8AQ8AI8AA8AI8AIAAI8AIAAI8AQAAQAIQAAQAIQIIYQQaQQqaa˺ú˺qY˺úqaaiQIYQ8YI8I 0I8I ( 0YQaqaqyyyyyyqyyqqyyyqqqiiqiqyqqqiiaYaYYYYQYQIQYIQYQYQQQYQYA08I08A08I08A08A00A08A00A08A(0A00A08A00A08A00A08A00A08A00A08A(8I08A08A00A08A00A08A00A08A(8A08I88I8AI88I8AQ8AI8AQ8AQAAQAIYIIQAIQIIYIIYQQaQQqia úòúӺ˺òòyqaqYIYAAI0(8YQaqai (((8QIYiaiyqqyyyyyyqqqiqyqyyyyqqqiqqqqqiqiaiiaaaYaYQYQIQYQYA08I08A08A00A08808A08I08A08A00A08A00A(0A00A08800A08A00A08A00A(0I8AI88Q8AI8AI88I8AQAAQ8AI8AI88Q8AI8AQ8AQAAQAIYIIYIQaQQiaaú˺úúòyyqyiYa80A0 AYQaI8I0(8YQaiaiyqqyyyyyyyqqqqyyqqqiq yqqqqqqiiaYaaYYaQYYYYYQYYYYYQYYYaYQYA08I08A08A00A08I00A00A08A00A08A00A08A00A08A00A08A00A08A(0A00A088(8A00A(0I88A88I8AI88I8AI88I8AI88I8AQ8AI88QAAQAIYIIQIQYIQaQQ˺òòqiqQ8Y((8A0AI8I0 AI8IQIYaYaaaiqiqyqyyyqyyqqyyyqqqaiiiiqiiqiqiaiYYYYIYYQYYYYaYaYYYYYaaYaA08I08A08A00A(0A00A08A00I00A00808A00A08808A00A08A00A08A(0A08A(0800A00A(0A08Q8AI88I8AI88I8AI88I8AI88I8AI88I8AQ8AI8AQ8AI8AIAAQAIYIIò˺˺òyiyaQY0 AIIQQ8I80A0 A0(8 00 AI8IYQaiaqqiqqaqqiqyqyyyyyqyyqqiaaaYaiaiaQYYQYaYaA08A00A08A00A(8A08A00A08I08A08A(0I00A00A08808A00A08A(0I08A08A00A08A00A08A00I08A08A00A08A00808A08I8AI08A08A88I8AI88I8AI88A88I8AI88I8AI88I8AQ8AI8AQAAQIIòúòyiyiYaQ8Y0 AA0AQAII8IA0A0 AI8IYIYiYayqyyyyyqyyyyyyyyqyyqqqiqiaiaYaaaaaYaYYaaYaaaiA08I08A00A08A00A08A00800808A08808800A00A08800A(0A00A(0A00800A00A08A00A08A00A(0A08800A00I00A00I88I8AA8AI8AI88I8AA8AI8AI88I8AI88I8AI88I8AI88I8AQ8AI8AIAAQAIYQQ˺˺ ˺òqqaqaYaI8I0 A A0AQ8YaaiqiqyqqqqyyqyyyyyqyqiiqaiiaiaYaYYaaYaI08A08I08A08I08A08I08A08A00A08A00A08808A(0A08808A08A00A08A00A08A00A(0A00A(8I08I8AI88I8AI88I8AI88I8AI88A88I8AA8AI8AI88I8AIAAQAAQAIYIQaQYú˺˺˺yqqaqiYqYQaQAaYIYiaiiaqqqyyqyyyyqyyyyyyyyyqiqiaiYYaaaaaYaiaiaaiiaiiaqA00I08A08A00A08A00A08A00A08A00A08A00A08A00A08A00A(0A00A(0A00A(0A008(0A(0A00I8AI88A8AA08I08I8AA8AI8AQ8AQ88I88I8AQAAI8AIAAQAIYIIYIQYQQaQY˺ ˺úòyqyqyiyyyyyyyyyyyyyqiiiYaaYaiaiaYaiiiiaiiaaiaiaaiiaiqiqiaiiaqA08A00A08A00A08A00A08808A00A08A00A(0A08A00I00A00A08A00I00A08A00A08I08A00A08A(0A08A(0A00A88I88I8AA88I8AA8AI88I8AIAAI8AIAAIAII8IQAIYIIYIQYQQaQYò˺ úyyyyyyqyyyyyyyyqqqaiaYaYYaYQYaaaaYaYYaiaiqaqqiqA00A08A00A08I00A00A08A(88(0808A08A00808A(0A00A(0A00A08A00A(08(0A00Q8AI8AI88I8AA8AI88I8AI88I8AQ8AI88I8AQAAQAIQAAYIIQAIQIIYIIYIQò˺ òyyyyyyyyyqqqaiaaiaYaYYaaaiiiqqiqqqyyqyyqA08I08A08I08A08A00I08A00A08A00A08A00A08A(8A(0A00A08A00800A(0A00A08A00A08I08A00A(0A00A(0A00I00A(0A00A08A00A08800A00I88I8AI88I8AI88I8AI88I8AI88I8AI88I8AIAAQAAQAIYII˺ ˺úyyyqyyyyyqyyqqyyyqyyyyqqqiqiaqiaiaaiiiqqiqqqyyqyyA08A00A08808A08A00A08A00A08A(0A08A00A08808800A00A08A00A08A(0A00A08A(0A00A08A00A(08(0A00I88Q88I88I8AI88I8AQ8AI8AQ8AQAIò˺ yyyyyqyyyyqyqiqyqqyqyyqqqiqqaiiaiaaiiaiiaqqiqqqyyqyyI8AI88A88A08I08A08A00A08I08A08I08A08I08A(0A08A00A08A00A08A00A08A00A08A(8A(0A08A00A08A00I00A(0A08A(0A00A08I8AI88I8AI88I8AA88I88I8AI88I8AI88I8AI88I8AQ8AQAA˺˺úyyyqyyyqiqyqqyqyqiqiiqqiqiaqaaiiaqiiqqqyyqyqqyyqyiiqiiiqiiqiqiiiaYYYIIQAIQAAI8AI88I8AI88A88A08I08A00A08I08A00A08A00I08I00A00A08A00A08A00I08A00A(0A00A(0A00A08A00A08A00A08A00A(0A00A(8800A00A(0A00A(0800A(0I8AI88I8AI88I8AQ88I88I8AI08I8AQ8AI8AIAIQAI˺úò yyyqyqiqqqqyqyyyqqiqiaiaaiiaiiYaaaiiiqqqyiiqqiqqiqqqqqiqiaiaYYaQYQAIQ8AI8AI08A08A08A00A08I00I08A08I08A08A00A(0A08A(0A08A(0I00A08A00A08A00A08A00A(8A08A(0A(8A(0A00A(0A(8A00A(0I08A(0A00I8AI88I8AI88I8AA8AI88I08I8AI88I8AI88I8AA88I8AQAAòúyyyqaqiaiqiqyqyyqqyqyqaiiaiiaqaaiYQaYYaaaiiaqaaiiiqqqyiiqiiqqiqqqyqiqqiiiaiaYYYIQQAIQAAI8AI88I08A08A00A08A00A08808A00A08A00A08A00A08I00A00A08A00A(0A00800A00808800A00A08A00800A00A(0I8AI88I8AI08I88I8AI88I8AQ88A88I8AI88I8AI88I8AQ8AQAIò˺ yyqaqiaiyqqqiqqaqaaiiaiaYaQIYYQaiiqiaqiiqqqyyqyyyyyyqyqqyqqqqiqiiiiaaaQYYIQQAAI8AA8AA08I08A08A08I08A08800A08A00A08A00A08A(0A08A00A08A00A08A00A08A00A08A00A(0I00I8AI88I8AI88I8AI88I8AA88I88I8AI88I8AI88I8AQ8AQAIò˺úòúyyyyiaiaaiqiqiiqqiqyqyqqyaaiiaqaaiiaqqqyiiqqqyyyyyqyqqyqqqqqyqqqqiqiaiiYaaQYYIQQAII8AI88A08I08A08A08A00A08A00A08A00A08A00A08A00A08A00A(08(0800A00A(0A00800A00800A(0A00A(08(0A00I8AI88I8AI88I8AI0AI88I8AI0AI8AI88I8AQ8AQAA˺˺úú yyqqqyqyyiyiaqaaiQIYaaiiaqiiqqqyyqyyyyyyyyyyyyyyyqyyqyqyyyyyqyqqyqiqiaiaYaYIQQAIIAAI8AI88A08I88I08A88A08A00A08A00A08I08A08I00A00I00A08A00A08A00808A08A00I08A(0A00A(08(0A00A08800A08A(8800A00I88A88I8AI88I8AI88A8AA88I88I8AA8AQ8AI88A8AA88A0AA8AI8AI88I8AI88Q8AI8AQAAúúqqiqyqqqqyiaqqiqiaqaaiYQaiYqaaiiiqqqyyqyyyyyyyyyyyyyqyqiqiaiaYYYIIQAAQ8AI88I08A08A88I88A08A08I08A08A00I00A08A00I00A00A08A(0A00A08A(0A08A00A08A00800A00A08A008(0A(0A00800A00I8AI08I0AI8AI88I8AI08A88I8AI88I8AQAAIAAQAA˺ú yyqyqiqiaq aaiiYqiaqiiqiaqaYaYQaiYqiaqiiqqqyyyyyyyyyyyyyyyqyqiqiaaaYYYIQQAII8AI08A08I08A08I08A08A08I08A08A00A08A00A08A00A08A(8I08A08A00I08A(0A00A08A(0A08A00A08A(0A00I00A(0A00A(8A(0A(8A(0A00I00A00A(0I88I8AI88I8AA08A88I8AA88I88I8AI08I8AI88I8AA8AI88I8AI88I8A˺ò yyyyqyiaqqiqiaqYQaQAaYQaYYaaaiiaqqqyyqyyyyyyqqqaiiYaYQQQAIQ8II8AI88I08A08808A08A00A08A00A08A00800A00A08A00A(0A00808A00800A08A008(0A(0A00A(0A00A(08008(0A00I08I8AI88I8AI88A88I88I8AQ8AI08I88I8AI88I8AQ8AI8AӺ˺ú˺ yyqqyyyqqaqiaqqaqYQaQAaYQaiYqqaqqqyyiyqyyyy qqqqiiaYYYQQYIIQAIQAAI8AI88A8AI8AA08I08A08A08A00A08I08A08A00A08A00A(0A08I08A08I08A08800A00A08A(0A08A008(0A(0A00I00A(0A00A(0A00A(0A00I88I08A08A88I88 I8AA0AI88I8AI88A88I88A88I88I8AI88I8AI88I8AI88Q8AI8AQ8A˺˺úúyyqyyiyyqyqyiYqiaqYQaQAaYQaiYqiaqqqyqyyyyyqqqiiaYYYQQQIIQ8AI8AA88A08A08I00A00A08A(0A00A08A00800A08A00A08A00A08A(0A00A08A00A(0A00A(0A00A(0A00A(08(0A00A(0800A08A00I8AI88I8AI88I8AA8AI88I8AI88I8AA8AI88I8AA8AQ8AI8AQ8A˺úúòyyqyqqyyqqqyyqyiyqqyiaqiYqiaqqqyyqyyy yyyyyqiiqaiaQYYIQQIIQAIQ8AI8AA08I08A08I08A08A08I08A08A00A08A00A08A00A08A00A08A00A08A00A(0A00A08A00A08A(0I08A00A08A(0A(8A(0A00A08A(0I88I08A08I8AQ8AI88I8AI88I8AI88I8AA88I0AI88I8AA88I88I8AúyyiiaqqyqqaqiaqqqyyqyyyyyyyyqqqiqqaiiaaaQYYIQIAAI8AI08A08I08A08800A00800A00800A08A00A08A00A08808A00A08A(8800I00A00A08A(8A(0A00A(0A00A(0A00A(0A00800A008(0A00A(08(0A00A(08(8I8AI88I8AI88I08I8AI88I8AI88I0AI08I88A8AI8AA8AI8AI88I8Aú˺yyqaqqqyyqyyyqqqyyiyqy yyyqqqiiiiYaiYYYQQQIIQAIIAAI8AI88A08I08A08A00A08A(8I00I08A08A00A08A00A(0A08A00I08A08A(8A(0A00A08A(0A08A00A(8A08A(0A00A(8A(0A00A(8A(0A(8808A00A(08(0A00A08A(0I8AI88I08I88I08I88I0AA88I88I8AI88I8AI88I8AA88I8AI88˺òúúqyyqaqiYqiaqqqyyyqqqyyqyq yyqyqiiiaaaQQYQQYIQQAIQAAI8AI88A08I88A08A08A00A08A00A08808A08A00800A(0800A08808A00A08A00A(0A008(0A00800808A(0A00A(0A00A(0A00A(0A00A(0A00A(0808A(08(0A00I88I8AI88I8AI08I8AQ8AI88I8AI08I88I8AI0AI88A88I8AI88ú úò˺yyyqyiiaqiYqiaqqaqyiyyqqqyyqyyyyqqqiiiYaYQQYIIQAAQ8AI8AI0AI88I08A08A08A00A08I08A00A08808A00A(0A00A08A00A(0A00A(0A00A(0A00A(08(0A(0A(8A(0A(8A00A(88(0A(0A00A(0I08I8AA88A8AI88I8AI08A88I88I8AA88I8AI88I8AI88Q88ò˺yyyiyqaqiaqqqyyiyyqyqyqyyyyyqiiiaaaYYYIQQAII8AI08I88I08A08A08A00I08A08A00A08A00A08A00I00A00A08A00A(0A00A(0A08A00I08A08A00800A(0800A08A(0A00A(08(0A008(0A(08(0800A(0A(8A00800A(08(8I08I88I08I88I8AA88I8AA88A8AI8AI08I88A8AI88I8AI08I8AI88Q8AI8A˺˺ yyqyiyqqyiyqqyy yyyqqqaaiYYYIQQIIQAIQ8AI88A08I08A08I08A08A08I08A08A00A08I08A00A08A00A08A00A(0A08A00A08A00A08A(0A00A(0A00A(0A08A008(0A(0A00A(0A00I88I8AA8AI88A8AA88I8AI08I88A88A08I88A08I08I8AI88I8AI88yiiyòúòyqqqyyyyyqyqqyyyyiiqaaaYQYQQQAIQAAI8AA8AA08I08A08I08A08I08A08I08A08A00A08808800A00A08A(0A(8A008(0A00A08A00A08A(0A08A00A08A(88(0A(08(0A(08(0800A00A08A00A(0A00800A00A(0A00A(08(0I8AI08I8AI88I8AI88I8AI88Q88I88A88I0AA08A8AI88I8AI88I8AI88I8AaQQqaYyqiyú˺òyqyiyyyyyyqyqyqyyqqiaaaYYYIIQAIQAAI8AI88I08A08I08A08A08I08A00A08A00A08A00A08A00I08A08A00A(0A00800A00A08808A00A08808A00A(0A08A00A08A00A(0800A00808A08A00I88A88I88A88A08I08I8AI08I88I08I88A88A08A88I08I8AI88I8AI0AI8AA08A88I8AI88QAIYIIiYYyiay˺òyiiaq qayiyyyqyyqyyyyyyyyyqqqiiiYYYQQQAIQAAQ8AI8AI88A88A08I08A08A08A00A08A00A08A00A08800A00A08A(0A00A(0A00A(0A00A(0A00A(0A08800A(0A008(0A(0A00A(0A00I8AI08I88A88I88I0AA0AI88I8AI88A8AI88A8AI88A08I88I8AA0AA08I08I8AI88I0AIAIQIIYQQqaYyqi˺òyiqayqyyqyyyqyqyyqaiiYaYQQYIQQAAI8AI88I08A08I08A08I08A08A00A08A00A08A00A08A00A088(0A00A08A00I00A00800A08A00800A00A(0A00A(8A(08008(0A(88(0A00A(0A00A(0A00I88I8AI08I88A88I8AI08I88I8AI88A8AA08I88I08I88A88I88I8AI88QAIQIIYIQaQYiaa ˺˺yyqyiiaqqayyqyiyqyyaQQYIIQAIIAAI8AA88A08808A08I08A08I08A08808A08800A08A00800A08A00A08A00A08A00A08800A00800A00800808A08A(0A00A(0A008(0800A(08008(0A(08(0A(0A00800A00I08I88I8AI88I8AI88I08A88I88I08I88I8AI88I8AI0AI88I8AI88QAIYIIaQQaYYòyyyiyqyyiiYqqyiyiyiyqyYIIQAAI8AA8AA88I08A08I08I88A08A00A08A(0A08A00A08A00A(08(8A00A08A00A(0A08808A08A00800A(8A00A(8A(0A00A08A00800A00808A(0A00I00A00A(0I00A(08(0A00I88I08A88 I08A08A8AA88I88I08I88A88A08A88A08A88I88I08A08I8AI0AI08I88A8AI8AI88QAAYIIYIQ˺òyyqqayqqayiyyyyQ8AI8AA08I88A08I08A08I08A08A00A08A00A08A00A08A00I08A00A08A00A(0A00A08A00A(08(0800A08A00A(0A00A(0A008(0A(0A00A(08(0A(0A00A(08(0A(0A00A(0I08I8AI08I8AI88I08I88I08I0AI88I8AI88A08I88I8AA88I08I88I08I88A0AI08I0AQAIYIIӺ˺úyyqyyqyiiYqyiyqyiqayiyqqyI8AI88I8AA08I08A08808A08I08A(8A08I08A08A00A(8A08A00A08A(8A08A(8A08A00A(0A00A(0A08A00A08A00A(08(0A08A00A(0A08A(0A00A(08088(0A(8I88A88I88A08I88I08I88A08I08A08A0AI8AI08I88I08I88I08I8AI88I0AI08I88QAAQAI˺yyqyiyiyiqayiqyqyqyyA08A88I08A08I08A88A08A(8A08A00A08A(0A08A00A08808A(0A08A00A08A00A08A00A08A(0A00A(0A00A(08(0800A(0A00A(0A008(0800A00A(0I88A88I88I08A88I08I88I0AI08A08I88I8AI08I88I08I88I8AI0AI08I8AI88I8AIAA˺òyyyiqayqyiqayqyyiyyqA88A08A0AA08I08A08A08I08A08A00808A08A00A08808A(8A08808A08A00808A08800A00A08A(08(0A00A08800A00A(8A(0A00A(0A08A00A08A00A08A(0A00A(08(0A00A(08(0A(0A008(0A00A(0A08I08A88A08I08I8AI08I88I08A8AI08A88I88I08A08I88I08A08A88I88A08A88A8AI88I08I8A òòyyyiqYyiyyyyqyiyqyyA08A08A00A08808A00I08A00A08A00800A08A00A08808A08A00A(08(0A00800A(0A00A(0A00A(8A(0A00A(0A00A088(08088(0A(08(0A00I88I08A08I88I08I88A88I88I08I88I08A08I88A88I88I8AI08I88A88A8AA08I08I88I08I88˺ò˺yyqyiyqyyyqyyA08A08I08A08I08A08A00A08800A00I00A08A00A08A(0A00A(0A08A00A08A00A08A00A088(0A(0A(8A(0A088(0A08A(0A(8A(08(0A008(0A00A(0A008(0A008(0A(08(0A(0I8AA88I88I08A08I88A08I08I8AI88I08I88I08A88I8AA08I88I08I88˺òyqyqyqyyqA08A(8A00808A08A00808A00A08A00A08800A08A00A08A00A08A00A(0A00A(0A00A08808A(0A00A(0A088(0A008(0A(08(0A00A(08(08(8800A00A(08(0A00A(0800A(08(0A(0I88A88A08I88I0AI8AI08I0AI8AI88I08I0AI08I8AI88I8AI88A0AA08Ӻ˺yqyyyqyiqyA08A88A08I08A08A00800A08A00A(0A08A00A08A00I08A00A(0A08A00A08A00A(0A088(88(0A(0A(8A(0A00A(0A(8A008(0A(0A08A(0A00800A(0A08A(0I8AA88A08A88I88I08A88I88A08I88A88A08A88A08A88I08A08I08I88I08I88I8AI08˺˺yyiyyqy808A08808A08808A08A(8A00800A00A08A(8800808A08A(8A(0A00A(0A08A00A08A(0I00A(0A00800A00A(08(0A(08(0A(08(08008(0A(0A00A(08(0A(0I08I88A08I88I08A08I08I88I08A88I8AI88I8AI88I08I88I08ú˺˺òyiqYyiyyqyyyyA08808800A08A00A08A00808A08A(0A00A08A(0A00A(8A08A00A(0A08A00A(0A(8I00A08A(8A(08(0A(08(0A(0A(8A00A(0I08I88A08I08I8AI08A88I88A08I08I88I0AA08I08I88I08I88I8AA88A08˺˺˺òòyyqyiyqyyA00A08A00A08A(8A08A00A08A00A08A00A(0A00A08800A08A00A08A00A08A(0A008(0A00A(0800A008(0A(08(0A(0A00800A(08(0A00A(0A00I08I88I08A08I08I8AI08I88I08A88I08I88A08I88I0AA0AA08I0AI08˺òúò˺òòyyyyiqayiyqyyA08A00A(0A08I08A08I08A08A00A08A(8A08A008(8A(8A(0A00A08A(8A08A00A(8A(0A00A(0A08A(88(0A00A(0A00A08A(0A08A008008(08008(0A(08(0A008(0I08I88A08I08I88I08A08I08A88I08A88I88A08I88A88A08I08I88˺ò˺ò˺ò yyqqyyiqayiyqyA08808A08A00800A00A08A00A08800A08A00A08A008(0A(0A08A00800A(0A00A(0A00800A00A(0A(8A(0A008(0A(0A00A08A00A(0A00A(08(0A(08(0A(0I08A08I08A08I08I88I08I0AI88I08I88A08I88I0AI88I08I8AI0AI08I88A8AA08˺úúòúúòòyqyyyqyiyyyyA08808A00A08800808A08A(8A00A(8A08A(0A(8A(0A00A(0A088(0A(0A00A08A008(0A(0A08A00A(0A(8A00A(0A00A(0A00A(0A08I08A08I08A08I08A08I08A08A88I88I08A08A88A08I08I88A08I08A08úúúòúúòòyyyqyiyqyyyqyyqYIAA08I08A08I00A(0A08A00A(0A08808A00A08808800A(0A08A(0A08800A00A(0A(8A00A(0A00A(0A00A08800A00A(08(0800A00800A008008(0A(0A00A(08(0A(0A008(0I08A88A08I08I88A08I08I88I08A08I08I8AI0AI08A08I08A88A08I0AI88˺òúòyyqqaqyiyqyqyyyyqiQ8AA08A(0A08A00A(8A(0A00A(0A08A(8A08A(0A(8A00A(0A08A(08(0A(0A00A08A(0A00A(0A(8A00A(0A(8A00A(0A08A(0A(8A(0A08A(0A08A(0A00I08A08I08A08I08A08I08A08I08A88I88A08I08I88I08˺ò˺yyyyqyqqqyyiiaqyiyqyyyyqaaI88A08I88A08A(0I08A08A00A08A00A08A00A08808A08A00A08A(0A00A08800A00A08A00A(0A00A08A00A08A00A(08(0A(0A008088(0A(0A08A00A(08(0A(08(0A(08(0A(08(0A(0I8AI08A08I08A08A88I88I08A08I08I88I08I8AI08A08I0AI08Q88I08A08I08úòòyyyyyqyiqaqqqyyyyyyaIQI08I00A08A00I08A08A00A08808A08A(8A08A00A(0A08A00A08A00A(8A(0A(8A00A(0A(8A(0A(8A(08(0A(0A00A(0A00A(0A(8A(0A00A(08(0A(0A00A(0I88A08A88I88I08A08I08A08A88I88A08I08I88A8AI08A08I08I88I08A08A88I8AQA8yúòqaaqyqyqyqyqyiyyyyqqQ8AA(8I08I0AA08A08808A00A08A00A08A00A08A00I00A08A00A08A(0A00A(0A08A(8A(0A00A08A00A(0A00A(8A00A(8A(08(0A(0A00A08A(08(0A00A(08(0A(0A00A(08(0A(08(0A(0I08I88I08A08I08A08I88I08A08I88I08A08I08I88I08I88I08I0AI8AI08 I00qaIúYIII08 úúúyyyyqqqyyiyqyyqaYQ88I08I0AI08A08A08A00A(8A00A08808A008008(0A(0A(8A(0A00A(8808A00A(08(0A(08(0A00A(0A00A(0A00A(8A(08(88(0A(08(0A088(0A(08(0A(8A(08(0A(08008(0I08A08I88I08I88A08I08A08I08I88A08I08A08I08I88A08I88A08I08A08I08A08I8AA08QA8úúyyYIAA(0I00Q8Aúyyyyyyqqqyyqy yqQA8A00A08I08A08A08A00A08A00A08A00A08A00A08A(88(8800A00A08A008(0A008(0A08A(0A00A(0A00A(0A008(0A(08(0A00A(0A00A(08(0A(0A08A(0800A(08(0I08A08I08A08I08I0AI88I08I88A08I88A88I08I8AI08I00yiaú˺úyiaI008(0I88I8AQ8AI8A˺úyyqyyyyqaII08A08A0AA08I08A(8A08I08A08I08A08I08A08A00A(8A08A00A08808A08A00A08A(8A(0A(8808A00A(8A(0 A088(0A08A(0A088008(0A(0A00A08A(08(0A(08(0A(08(0A(0A00A(0I08A08I08A08I08I88A08I08A08I08A08I08A88I08A88I08A08I8AA8AA08I88yqaQQA(0I8AI8IQAI˺ú yyyqy qiaQ88A00A08I08A08I08A08A08A00A08A00A08A00A08800A08A(0A00A(8A(0A00A(08(8A00A(08(0A00A(08(08(8A(0A00A(08(0800A00800A(08(0A00A(08(0A(0A008(0A(08(0A008(0A(0800A008(0A(0A00A(08(0A(0A88A08I88I08A08I08A08I88I08A08I08A08I08I0AI88YIAaQQYIAI00A(0I08I8AQ8AQAIò˺˺úyqqyiiqaYqaayyqyqqyyyyqYIAI08A08I08A08I08A08A08A(0A088(8A08A00I08A08A00A08A00A08A00A08A00A(0A08I00A(0A08A00I00A088(8A(0A08A(0I00A00A(0A00A(08(88(0A(08(0A(08(0A(0A(88(88(0A(0I08I88A88I08A08I08I88I08A08I08I88I8AA08A88A08I08I88I08A08I88I08A08I0AI8AI08I8AI88I08I00I08A08I0AI08I88I8AI8IIAIQAIQ8AI8AiYYyiayò˺˺úòyyyyqqqyiiqaaaQYaIQYIAqaYyqyyaQQI00A08A0AA08I08A08A00A08A00A08A00A08A00I08A00A(0A00A08A(0A00A08A008(0A00A08A(0A08A008(0800A(0A00A(8A(0A088008(0A(08008(08008(0A(08(0A(0A08A008(0A008(0A(0A00800A00A(08(0A(0A08I08A08I08A08I08A08I88A08I88A08I08A08I08A08I08I88I08A08I08A8AA08I08I8AI88I8AA8AI8AI0AI8AI88I8AYIIaYYyiiyqqyqyòú˺˺˺ú˺òòyqyyqqyiiqaYiYYqaaiYYaQQaIQQAII8AA88yiayyyiaQ8AA00A08I08I08A08A00A08A00A08800A08A00A08800A08A00A08A(8A08A(0A08A(8A(0808800A08A(8A(0A08A(0A(8A(0A00A(0A00A(0A(8A(0A08A00A(0A(88(0A(0A00I00A(0A00A(0A08A(0I08A08I08A88I88I08A08I08A08I08A08I08A08I08A88A08A88A08I8AA88A08I08I8AI88A0AA8AA88I08I8AI88I08I8AA8AI8AA8AI8AI88Q8AI8AI88I8AQ8IIAAQAAQ8AI8AQAIaQQiYa iYYqaYyiayqiqqyyyqqyqiyiiqaaqaYqaaiYaiYYYIIYIAQAAYIIYIQYQYYIQQAII8AI08A08aYQyyqiYIIA08808A08I08A08I08A08I08A08A00A08I08I00A08A00I08A08808A00808A(0A(8A00A08A00A08800A00A08A(88(8A00A(0A08A00808800A(0A08A00A(0A00800A008(0800A(08(0A(08(0A(0A008(0A00A(08(0A(0I88A88A08I08I8AA08I08A08I08A08I08I88A88I08A08A88I08I0AI08I88A08A88I08I08I0AI08A08A88I88I8AI88I8AI08A8AI08I88I8AI0AI8AQ8AQ8IQ8AI8AQ8AQAIYIQaQYaIQYIQaQQaQYiYYqaayiiyqqyqyyyqqqyyyyyqyyyyyyqyyyqiyiiqaaiYYaQQYIIYQQYIQQAAI8AQAAYIIQAII8AI0A808qaYyyyyYIIA00A08I08A08I08A08I08A08I08A08I08A08808A00A08I08A00I08A(8A(0A00A08I08A08808A08I00A08A00A08A00A(8A08A(0A08A(0808A(0A00I00A(0A00A(0A00A(08(0A(08(0A(8A(0A(88(0I08I88A08A88A08I08A08I88A08I08A08A8AI88I08A88I08I88A08I88A88A08A88A08I08I88I8AI88I08A0AI08I8AI08A0AI08I88A88I88I8AI88I08I0AA08I88I8AI88A8AI8AA8AI8AI0AI08A8AI8AI0AI8AQAIYIQ QAIQAAQ8AQAIYIQYIIaQQiYYiYaqaaqaYiYYaQQiYYqaYqaayiiyqiyiaqaYiYYaYQqaYqaaqaYqaaqaYiYYaQQYIIQAAYIIYIQYIIQAIYIIQAAA8AI08I8AQ8AI8AI0AI8AA088(0qaIyyqaQQI00A00A08I08A08I88A08I08A08I08A08I08A08A00A08I08A00A08I08A08I08A00A08800A00A08800A00A08A(8A08A(0A08A00800A00A08A00A088008(0A(8A008008(0A(0A00A(0I00A(0A00800A(0A00A08A(0A00A(08008(0A(08(0A(0I08A08I08I8AA08I08A08I08A08I08A08I08A08I08I88A08I88I08Q88I8AI08I8AI0AA0AA08I8AA8AA88I88I08I88I08I8AI0AI08A88I8AI0AI88I8AI88I8AI0AA0AI0AI08I0AI88A0AI88I8AQ8AI8AQ8AQAIYIIQAAI8AQ8IQAIYIQYQQaQQYIIYIQYIIaIIaQQiYYaQQYIIYIQYIIQAIYIIYIQaIQYIQaIQYIQYIIQAIQ8AQAIQ8AI8AQ8AQAIQ8AI88Q8AI8AI08I8AI88I8AA08I0AI08A(8Q88yqiYIAI00A(0A08I08A08A88A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08A(8A08A00A08A(8A08A(0A08808A08A(0A08A00A(0A08A(0A00A(8A008(8A(8A00A(0A08A(0I00A00A(8A(0A00A(0800A(0A00A(08(0A(0A88A08I08A08I88A08I08A08I08A08I08A08I08A08I08A08I08I88I08A08I08I88I08A08A88A08I08I0AI88A08I08A08I8AA88I08A88I88A8AA88I8AA0AI0AA88I88I8AI08I88I8AA88I8AQ8AI8AI0AI08I88A88I8AI88A88A8AI8AQAIQ8AI88I8AIAIYIIQAAQ8AI8AIAAQAIQ8AYIAYIIaQQYIQQAIQAAQ8AQAIQ8AI8AQAAYIIQAIYIIQ8AQAAI8AQ8AI8AI88A0AI88Q8AI8AQ8AI8AI88 I0AA08I08A(0I08yiaYIAA08808A08I08A88A08I00A08I08A08I08A08A(8A08I08A08I08A08800A00A08A(0A088(0A(0A08I08A08A(0A088(0A(8A00A08A00A08800A00A08A00A(8A(0A00A(0A00A(0A00A(0A00A08A(0A08A(0A00A(08(0A(0A00A(08(0A(0I88A08A88I08I88A88I08A88I08A08I08A08I08A08I0AI08A08I08A08I08I88I08I88I08I88A08I8AI0AI08I88I08A08I8AI0AI08I88I0AI08I88I8AI0AI08I0AI8AI88I08I8AI0AI8AI08A0AI0AI88I08A8AI08I8AA8AI88I0AA0AI8AI08Q88I0AI8AQ8AI8AI0AI8AQ8AQAIQAAI8AQ8AI8AQ8AQAIYIIQ8AQ8II8AQ8AQ8IQAIQ8II8AQ8AI8AA8AI88I8AI0AA08I08I8AI08I88I8AI08A(0I08yiayqiaQQI00A(0I08A08I08A08I08A08I08A08I08A08I08A08I08A08A(8A08A00A08I08A08I08A(88(8I08A08A(0A(8I08I00A(8A00A08A(8808A(8A00A(8A08A00A08A(8A00A08A(08(0A00A08A(08(0A(08(08(8A(08(0A08A(08(88(0A(0A08I08A08I08A08I08A08I88I08I88A08I08A88A08I08A08I08A08A88I88I08I0AI08A88I88I08A08I08I8AA08I08A88I88I08A08I8AI88I08I88A08I88I8AA88A08I88I8AA8AI8AI88A88I88A08I8AI0AA0AA8AI8AI88I8AA8AI8AQ8AI8AQ8AQAIIAII8AI88I8AA88I8AQ8AI08I8AI88I8A I88I08I0AI88I0AA08A88A8AI08I0AA0AI08A0AA08 I08A08I08A08800YIAyqiyyqaQQQ88A(0A08I08A08I08A08I08A08I00A08A88A00A08I08A08808A08A00A08A00A08I08A00A08A00A08I08A00800A08A00I00A00A(0A(88(0A00A(08(0A08A00I00A(0A00A(0A008(0A(08(8800A00800A(08(0A(0I08Q88I88I08I88I08A08A88A08I08A88I08A08I08I8AI08A08I08A08I08A08I08I88A08I88I08A08I08A88I08A08I08I88I0AI08I8AI08I0AI08A8AA08I8AI08I0AI88I0AI08A08I88A88I8AA88I8AA8AA08I08I8AA88I08I8AA88I8AI08A08I08A8AI8AI0AI8AI0AI08I88I8AA8AI8AI0AI8AI0AI8AQ8AI8II8AI0AI8AI0AI8AQ8AI8AI0AI8AI0AI8AI0AI88I8AA08I08I8AA0AA08I0AI8AA08I8AI08A08I08A08A(8A(0I00Q88YIAQ88A(0A(8I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08I08A08I08A08A00A08808A08800A00A(0A00A08A00A(0A08A00A(8A(08(8808A(0A00A08A(8A08A(8A(0808A(0A088088008(0A(0A00A(0A088(0A(08(0A00A(0A00A08A88I08A08A88A08I88I08A00A08I08A08I08A08A88I08A08A88I88A08I08A08A88A08I0AA08I0AI08I88A88A08A88I08I88I08I88A88888A88I08I88A08I08I88A88I08I0AI08A08I88I08A08I88I08I0AI88A88I0AA0AA88I8AI0AI08A08A0AI88I8AI0AI08I88I8AI0AI8AI08I8AI88I8AA08A0AI8AQ8AI8AI88A8AI8AI88I8AI0AI8AI0AA8AI88I8AI88A08A88I8AI88I8AI0AI08I8AA08I08A08A88I08A08I08A88I08A08A88I08A08A0AA08A(8A(0A08I08A08I08A08A00A08A00A08I08A08A(0A08A00I00A08A(8A088(0A08A(0A08A00A08A00A08A(8A08A00A08A(0A008008(0A(08(0800A00A(8A(0A008(0A(08(0A(08(0A(08(0I08A08I88A08I08A08I88A88I08I0AI08A08I88I08I8AA08I88I08A08I08I8AA08I08A08I8AI08I8AA8AA88I0AI08A08I0AA08I08I88I08I88I8AI08I0AA0AI08I0AI08I88A88I8AI08A08A0AI88I08A08I8AI08I8AQ8AI88I0AI08I88I0AI08I88A88I0AI8AI0AI8AA08I8AI08I0AI08I0AA88I88I8AI0AI08I88A08I8AI0AI08I0AI08I8AI88I08A08I08I0AA08A8AI8AI88I08A08I8AA08I08A08A8AA08I08I0AA08I08A0AA08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08A(8A08808A08A00I08A08A00A(0A08A(8A(0A00808A(0A00A08A00A(8A08A(0A00A(0A(8A00A(0A08A(0A008(0A(0A08A(0A(88(0A(0A(8A08A00A(08(0A(0A00I08A08I08A08I08A08I08A08I08A08I08A08A88I08A08I08A08I88A88A08I08A08I08I88I08A08I08I88I08A88I0AI8AA88I08A08I08A08I88A08I88I08A08I08I8AI88I08I8AI0AI08I8AI88I08A08I88I08A08I08I8AA88I08I8AA08I0AI08I88I08I0AI88I08A0AA8AI8AA08I8AA8AI88I8AI88I08A0AI0AI08A08A88A08I08A08I88A0AI8AA8AA08I08A88A08I08A08A8AI08A08I08A88I08A08I88I08A0AA08I08A08I08A08I08A08I08A08A00A08I08A08A00A08A00A08808A08A00A08A(0A(8A00A08A00A(0A(8A(0A08A(0A(8A(0A08A(8A(0A00800A(0A08A(0A00800A(0A08A(08(0A(0800A(0A00800A008(0A(08008(0A(0I08A08I08A88I08A08I88I08A08I08A08I08A08I0AI08A08I88I08I8AA08I08A08A0AA08I08A08I08I8AI88I8AA08A0AA08I88A88A8AI0AA08I08I8AA88I0AI08I8AI08I0AI08I88A08A0AA08I88A08I8AI0AI08A08I8AI08I8AI08I8AA88I0AA08I88I08I88I08A08I8AI0AA0AI8AI88I08I88I0AI08I0AA08A8AI08I0AA08I08I0AA0AA08A0AA08I08A08I0AA08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08808A08I00A08A(8I08A08A00I00A08I00A00A08A(8A08A(0A(8A08A(0A00A(0A(8A(0A00A08A(0A(8A(0A00A(8A00A08A00I00A00A(08008(0A08A00A(0800A(08(0A(0I08A08A88A08I08A08I08A08I08A08I88A08I88A08I08A08I08A08I08I88A08I88A08A88A08I88A08I08I88I0AI08I0AA0AI0AA0AI0AA08A88A8AA08I08I88I08I88I08A88A08I0AA08I88I8AI88I8AI88A08I88A88A08I08I88I08I88A08I8AA0AI08I0AA08I08I8AI08A08A88I8AI08A08I08I88I0AI08I88A08A88A08A88I08I88I08A0AA08A0AI08A08I08A08I08I0AI08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08A00808A08A00A08808A00A08A(8A00A08A00A(0A08A(0808A00A08A00A08A(8800A00A08A00A08A(0A088088(0A(08(0A(0A00A(0A(88(0A(08(08008(0A(0A00A(08(0A(08(0A(0I88I08A08A88I08A08I08A08I08I88A08I08A08I08A08I88I08A08I08A08A88I88I08A08I08I88I08A08I88A0AA8AI08A08I08A08A88I8AA08I08I88I08A08I8AI08A08A0AI08A08I88I0AA08I08I0AI08A08I0AI88A88I88I0AI8AA08I08I8AI08I0AI08I8AA08I08I88I0AI8AI08I0AA0AA08I08I0AA08I08A08I08A08I08A08I08I8AI08A08I08I0AI08A08I08A08I08A08I08A08A0AA08I08A08A88A08I08A08A0AA08I08A08A(8A08I08A08A00A08A(8A08I08A08A00A08A00A08A00A08A00A(8A(0A(88(0A(0A(8A(0A08A(8A00A(08(88(0A(0A00A(0A00A(08(0A(0A(8A(08(0A00A(0A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A88I88A08A00I00I08A88I08A0AA08I08A08I88I08A08I08A08I08A08I08A88A08A0AI08I88I08A08I0AA08I08A08A88I88A8AI8AA0AI0AA08I08A88A8AI08I88I08I88A88I0AI88I08I88A08A0AI0AI8AA08I88I08A08A88I88I0AA08I08I0AI8AI0AI08A0AA08A8AA88A08I88I08I8AI08A08I8AA08A0AA8AA08I08A08I08I0AA88I08A08I08A08I08A08I88I08A08I08A08I08A08I08A08I08A08I08A08A00A08808A08I08A08808A08I08A08I08A08808A08I08A(8A08A00A08A(0A08800A00A08808A08A00A08A(0800A00A(0A(8A08A(0A00A(0A008(0A(08(0A00A088(0A008(0A(0A(8A(08088008(0A(08(0A(08(0A00A(08(0A(0A08I08A08A88I08A08I08A08I08A08I08A08I08A08I88I08A08I08I88I08A08I08A08A88I88I08A08I0AA08I08A08I08I0AI08A08I08I88I08I88I08A08I0AI08I88A08I88A08I08I0AA08I08A08I08A08A8AI08A0AA08I08I0AI08I88A0AI08I0AI08I0AI08A08I0AI08A08I0AI08A08I88A08I08A88A08I0AI08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08808A08I08A(8A08A00A08808A08A00A08A00A(8A(0A(8A08A(88(8808A00800A00800A08A00A(0A(8A(0808800A00800A(0A088(08(8A(88(0A(0A(88(0800A(0I008(0A(0A08A88I08A08I08A08I08A08I08A08I08A08I08A08I08I88A08I08A08I08A08I08A08I08A08I08I88A08I88I08A08I08A08A8AI08I88A88A08I08A88A08I88A88A08I88I08A88A08A8AI08A08I08A08I08I88A08I08A08A88A08A0AI08A08I0AA08A88A08I08A08I08A08I08A08I08A08I08A08I08A08808A08I08A08I08A08I08A08I08A08808A08A00A08A(8A08A00A08808A08A00A08A(8A08I00A08A(0A00A08808A08A(08(0A(0A00A(8A00808A008(0A(0A008008(0A(08(0A00808A088088008(0A008(0A(08(0A(08(0A(0A00A(0A008(0A(08(0A(08(0I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08I88I08A08I08I0AI08A08A88I08I0AA08I08A08I08A08A88I08A08A88A08I0AI08A08A88I08I0AI08A08I08A0AI08A08I08I88I08A0AI8AI0AA08I08A08I08I0AI08I8AA08I08I0AI08A08I08A08I08A08I0AI08A08I08A08I08A08I08A08I08A08A0AA08I08A08I08A08I08A08I08A08I08A08I08A00A(8A08I08A08A(8A00A(0A08I00A(0A00808A00A08800A00A(88(0A00A(0A08808A088(0A(0A(88(0A(0A008(0A(0A(8A(0A(8A00A(08(0A(0A008(0A(08(0A(08(0A(08(0I08A08I08A08I08A88A08I08A08I08A08I08A08A88I88A08I08A08I88A08I08A08I08A08I08A08I08I88I08A08I08I88A08I08A08I08A08A88I8AA88A08I08I88A88A08I08A08A0AA08A88I88A08I08A08I88I08A08I08A08I88A0AA08I08I0AA08I08A08I0AA08I08A08I88I08A08I08A08I08A88I08A88A08I08A08I08A08I88A08I08A08I08A08808A08A00A08A(0A08808A00I08A08A00A(8A008(8A(08008(0A(0A08A00A08A00A08A00A08A00A(0A00A(0A08A008(0A00A(0A00808A08A008(0I00A(08008(0A(0A008(08008(0A(08(0A(08(0A(08(0A(0I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I88I08A08I08A08I08I88I08A08I08A0AA08I08A08I08A08I08A08I88I08A08I08A88A08I0AI08A08I0AI08A08I88I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I0AA08I08A08I08A08I08A08I08A08A00I08A08I08A(8A08I00I08A08A(0I08A(0A08A00A08A00A08A00A08A(8A00A08A008(0A08A00A(0A08A00A08A(0A(8A(0A00A(0A08A(08(0A(0A008(0A(0800A(08(0A(08(0A(0I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A88A08I08A88A08I08A08I08A08I08A08I0AI88A08I88A88I08A08A88I88A88A08I08A08A88A08I88A08A88I08A08A88I08I0AI08I0AA08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08I08A08I08A08I08A08I08A08A00A08808A08A00A(8A08A00A08A00A08800A08A(0A08I08A(8808A08A00800A08A00A(8A08A(0A00A(08(0800A08A(0A(88(0A(0A08A(0A088(88(0A008(0A(0A08A008(0A(08(0A(8A(0A00A(08(0A(08(00((8(0A(08(0A(08(0A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I0AI08A08I08I88I08I0AI08A08I08A08I08A08I8AA08I08A08I08A08A88A8AA08I08A88A0AA8AI08A08A88A08I0AI08A08I08A08I08I88A08I08A08I08A08I08A08I08A08I08I8AI08A08I08A08I08A08I08A08I08A08808A08I08A08I08A08I08A08I00A08I08A(8A08A00A(08(8808A08A00808A08A(8A00A(0A00A08A(8A00A(8A(0A00I08A08A(0A08800A(0A00A(0A08I00A(0A00A(0A(8A(08(0A(08(0A(08(0A(08(0A(0A08I08A08A00A08I08A08I08A08I08A08I08A08I08A08I08I88A08A88I08A08I08A08A88A08I08I88A08I08A08I08A08I08A08I08A08I08A08A88A08I08A08I08A08I08A08I08A08I08A08I08A88A08I08A08I88A08I08A08I88A08I08A08I08A08I08A08I08A08I08A08I08I0AA08I08A08I08A08I08A08A00A08808A08A(0A08I08A08808A08A00I08A00A08I08A08I00I08A08A00A08A00I08A08I08A08A(8A(0A00A08A00A(0A08808A(8A(0A00A08A(08(8A08A(0A08A(8A(0A00A(0A00A(0A00A(08008(0A(08(0A(0A00800A(08(0A(08(0A(08(0A(08(0A(0A08I08A08A88A08I08A08A88I08A08I08A08I08A08I08A08I08A08I08A88A08I08A08I08A08I08A08I08A08I08I8AA08A88I88I08A08I88A08I8AA08I08A08I08A08I08A08I88A08I88I08I0AI08A08I08A08I08A08I08I0AI08A08A0AA08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08808A08I08A08808A08A(0A08A(0A08A(0I00A(0A(8A08A(8A08A00A08I08A(0I08A08I00A(0A(8A08A00A08A(8A(0I08A08A00A08A(0A088(0A08A00A(08(0A(0A(8A08A00A(08(0A(08(0A(0A(8A(08(0A(08(0A(0I08A08I08A00A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I88A08I08A88A08I08A08I08A08I08A08I08A08I08A08I08A08A88I08A08A88A08I08A08I08A08I08I88A08A88A08I08A08A0AA08I08A08I08A08I08A08I08I0AA08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08I08A08I08A08A00808A08A00800A08A(0A00I08A08808A08A(8A08A(8A08A(0A08A008(0A(88(8808A08I08A00A08800A08A00A08A00A(0A08A(0800A00A(0A008(0800A00800A(0A(8A(08(0800A(08(0A(08(0A(08(08((8(0I08A(8I08A08A00I08A08I00A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I88A08I08A08I08A08I08A08I08A08I08A08A0AI08A08I88A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A0AA08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A088(8A(8A08I08A08A(8I08A08A00I00A08I08A(88(8A08I08A(0A088(8808A08A(88(0A00A(0I00A(88(0A08800A(0A008008(0A(08(8A(0A08A(0A00A(08(0800A08A(0A008008(0A(08(0A(08(88(0A(0I00A(08(0A(08(0A(08(0A(08(0A08I08A08A00I08A08A00I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A88A08I08A08I08A08A88A08A88I08A08I08A08I08A88A08I08A08I08A08I08A08I08A08I08A08I08A88A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08808A08I08A08I08A08I08A08I08A08A00A08A00A08A00A08A00A08A00A08A00A(0A00800A00A088(0A00800A(08(0A(0A00A08A00A(8A(08(0A(0A(8A(0A00A(0A00A(08(0A(08(0A008(0A(08(0A(08(0A(08(08((A08I08A08A00I08A08I08A08I08A08I08A08I08A08I08A88A08A0AA08I08A08I08A08I08A08I08A08A88A08I08A88A08I08A08I08A08I08A08I08A08A00I08A08I08A08I08A08I08A08I08A08I08A08808A08I08A08I08A08I08A08I08A08I08A08A(8A08I08A08808A08I08A08I08A08808A08I08A(0A08I08A08A(8A08A(8I00A08A00A08A(8A(0A08I08A(0A08A(8A08A00A08A(0A08A(0A08A(8A(0A08A00A08A(0A00A(0A00A08A00A(0A088(0A(0A088(0800A(08(0A(08(0A(08(0A(08(0A(08(0A(08(0A(08(0A08A00A08I08A08I08A08I08I00A00A08A00I08A08I08A08I00I08A08A00I08A08I08A08I08A88A08I08A08I08A08I08A08I08A08I08A08I88I08A08A88A08I08A08A88A08I08A08I08I88A08I08A08I08A08A88A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08I08A08A00A08808A08A00800A08800A08A(0A00I08A088(0A08800A00A08A00A088008(0A08A00808A00A08A008(0A(08(0800A088(0A(0808A00A(0A00A088(0A(0A00A(08(0800A(08(0A(08(0800A(08(0A(08(0A(08(0A(08(0A(08(0A08A00A08I08A00A08A00I08A08I08A00I08A08A00A08I08A08I08A08I08A08A00A08I08I00I08A00A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08I88A08I08A08I08A08I08A08808A08A00A08I08A08I08A08I08A08I08A(8A08I08A08I08A08A00A08I08A08A00A08808A00A08808A08A(0A08800A08A(0I00A08I00A(0A00A08A(8A08A(8A08A(0A00A(08(0A(0A08A(0A(88(0A00A(08(0A(08(0A(0A00A(08(0A(08(0A(08(0A(08(0A088(0A(08(0A(08(0A00A(08(08((A08A00A08A00I00A08A88A08I08A08I08A08A00A08I08A08I08A08A88I08A08I08A08A88I08A08I08A08A88A08A00A08I08I88A08I08A08I88A08I08A08A88A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08A00A08A(8I08A08A00808A08A00A08A00A08I08A08A(0A08A00A08A(8A00A08A00A08A00A08A(8A08 A00A08I08A08808800A(8A00A(0A00800A08A00A08A(8A(0A(8A(08(0A00800A008(0A(0A00A(8A(0A008(0808A(08(0A08A00A(08(0A008008(0A(08(0A00A(08(0A(08(0A(08(08((8(00((8(0A00A08I08A08I08A08I00A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A00A08I08I88I08A00I08A08I08A08I08I88A08I08A08I08A08I08A00I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08A00A08I08A08A(8A00I08A08A00A08A00A08A00A08I08A(0A(8A08I00A08A00A08800A(08(0A08A(0A00A08A(88(0A(0A08A(0A00A(08(0A(08(0A(0A(8A088(0A(08(0A(08(0A(08(0A(08(08((A08A00A08A00A08A00I08I00I08A08A00I00I08A08I08A00A08A88A08I08A08I08A08I08A08I08A08I08A00A08I08A08I08A08I08A08I08A08I08A08I88I08A08I08A08I08A08I08A08I88A08I08A08I08I88I08A08I08A08I08A00A08I08A08I08A08I08A08A00A08A00A08I08A08A00A08800A08A00A08A00A(0A08A00A(0A00A(0A00800A08A00A(8A(0A08A00A(0A(88(0A00800A008(0A(0A00A(08(0A00A(08(0A(08(08008(0A(08(0A008008(0A(08(0A08I08A08I08A(0A08A(0I08A08I08A08A00A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I88A08I08A08808A08I08A88A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08I08A08I08A08I08A08A00A(0A(8A08I08A(0A08A00I08A08A00A(0A08A(8I08A(08(0808A00A08808A(0A08A00A08A00A08A00808A00A08800A00A(0A00A(0A00A(0A00A(08(0A00A(0A008(0A(0A00A(0A008(0A00A(08008(0A(08(0A(08(0A(08(08((A(08((8(0A08A00A08808A08I08A08I08A00A08A00I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08I08A(8A08I08A00A08800A00I08A08I08A08I08A08A00I08A08I08A08808A08A00808A088(0A08A00A08I00A(0A00800A00A08A(8A(0A08A00800A00A(0A08800A00A(0A00A08A00A08A(0A00A(08(0A(08(0A008008(0A(08(0A00A(08(0A(08(0A008(0A(08(0A(08(0A(08(0A(08(00((8((0 (8((A08A00A08I08A08A00A08I08A08I08A08A00I08A08I08A08A00I08A08I08A08I08A08I08A08I08A08I08A08I08A08A00A08I08A08I08A08I08A08A88A08I08A08I08A08I08A08I08A08I00A08A00A08I08A08I08A08I08A08I08A08A00A08I08A08A00I08A08808A08A00A08A00A08I08A08A(0A08808A08A(8A08A00A(0800A(0A08A00A08A(0A00A(0A00A08A00A(0A00A08A(0A00800A(0A00A(0A00808A(08(0A00A(08(0A(0A008(0A(08(0A(08(0A(08(0A(0A00A(08(0A(08(08((A08A00I08A08A00A08A(8A00A08A00I00I08A08I08A08A00A08A00A08A00A08A00A08I08A08I08A08808A08I08A08I08A08A88A08I08A08A00I08A08I08A88A08I08A08I08A08I08A08A00A08I08A08I08A08I08A08I08A08A00A08I08A08A00A08A00A08A(0A08A00A08I08A(8A(0A00I08A00A(0A00800A08A00A08A(0A00A(0800A008(0A(08(0800A(0A00A(0A00A(08(0A008(0A00A(0A00A(0A(8800A00A(08(0A(08(0A008(0A(08(0A(08(08((8(08((0((8(00((8(08((A00A08A00I08A08808800A08I08A00A08I08A08A00A08A00A08I08A08I08A08A00A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A00I08A08I88I08A08I08A08I08A08A00A08I08A08I08A08I08A00I08A08I08A08I08A08I08A08I08A08A00A08I08A08A00A08A(8A00A08A00A08A00A08A(0A08A00A(8A(0A(8A(0A00A(0A08A(8A00A088(0A(88(0A(0A00A(0A(8A(08(0A(0A(8A(0A(8A(0A008(0A(08(0A(08(0A(08(0A(08(08((800A08A00A08A00A08A00A088(88(0A00A08808A08A00A08A00A08A(0I00I08A08A00A08I08A08A00A08I00A00A08I08A08A00A08I88A08I08A08I08A08I08A08A00A08I08A08A00A08I08A08A00I00A08A00A08A00I08A08A00A08808800808A08A00A(8A08A00A08A00A08A00I08A08A00A(8A08A00A08A(0A00A08I08A(0A00A(0A08A(8A(0A00A(0A00A08A(0A(8A(08(0A(0A00A(08(0A(0800A00A(0A008008(0A00800A(08(08((A00A(08(0A(08(08((8(08((8(08((0((A08A00A08I08A00A08I08A08I08A08A00A08A00A08I08A08808I08A00A08A00I08A08I08A08A00I00A08A(0A08I08A(8A08I08A08I08A00A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A08I08A00A08A(8A08I08A08A(8I08A08A00A08A00A08A00A08A(0A08800A08A(0A00A08A00A(0A08A00A(0A08A(8A08808A08A008(0A(0A00A(0A00A(0A00A(08(0A(08(0A(08(0A(08(0A(08(0A(08(0A(08(08((A(08(00((8(0A00A08A00A08A00800A08A00A08A00I08A08A00800A08A00A08A00I08A08A00A08A00I08A08A(8A00A08A00A08808A08A00A08I08A08A00A08A00A08I08A08I08A08A00A08A00I08A08A00A08A00A08I08A08I08A08A00A08800808A08I00I08A08I08A08A00A08800A08800A08A(0A088(8A08A00A08A00A08A00808A00A08800A08808A08I00A00A08A(08(08(88(0A00A08A00A(08(0800A00A(0A008(0800A00A(0A008(0A008008(0A(0A00A(08(0A(08(0A(08(0A(08(0A(08(08((8(08((8(08((8(00((TRUEVISION-XFILE.allegro5-5.2.10.1/examples/data/mysha256x256.png000066400000000000000000002000531473414355200207200ustar00rootroot00000000000000PNG  IHDR\rfsRGB IDATxٓ׵[;3kyF HA ERD:;7ۏ'nሒ( 3ЍsWe^~9nġ+]}Z !B_',Cp <3pF3)A#>{Ѽ0pId5S<#k-s PmtN>]UZ"Igm1Uyos XcgHt5:Cph+tdcSkw KX˲k=`Y3g |[#}3TfGqjz3J)Opw$d}87RoO8F$33s{H](3}?Z$3pM5s2Zd |39j%ҟNr<'&x<Ʀ͍[K{Fo} 񨏄;L]%]cw{F>3P.y&Ngaˏ@ŐMoz;ja~>aS E_^Se~G?|7B;]xcf|J37K 5m<Տ` 8uU^ձQΖ)~)Ns \SD+)8:s_ >C+߳@G؜yb~0'Ϲ _YC <66> $+ ʂS6wŠLXʹ4 zSʹU"͟> v3M`C 06 8,*DžC5pq Hl*Z5?YY =>'\o}aee䐿7__x̛~,?Α9~ 7eq|G ߧΪ/f7TQFZܽC^ o&KV+dl;Zxy|p :|xa+'yOcwm$D.ߟx7>釼q}e; Y6^6;d75[`@[YԟWMrN ?t-~G_qjCLA21iN|ppFߏ{mvz- qk nË/o=xđ)~73]f.QB9# ~>;&ta?~:.[ =||?OdVd7_]cv ʄB]noSw7_k|zeB.\gX[ PT{hBrJF!y:(?PV_򷿧@_I7&|:?KSܸ6#("J lg7y PX۔'=$u~+@m4~U bܙ'Y~KwFXw> -8m Y!gיײ$ ]v:fY?O*Bp <] Qn^c Q_/v~HdD;'XU_+#v!y +KV:oЕ,zT~y _=rlw}"|M~F"gSϕSrH U- ]鲼r(?>ٗ6@y[Hm )cWD§cI~<7.?1kk>,:k'~~NN42Tr+}9u?&66$(^8[` ɿL\N-p(V,JoXu䉌__QckRj49ڳK{&OQW6|6.\JW6W>2̴6uYW}7hsz27?|0ͿwW"6, iH f=̅D"%ͨWVQ iy^q676NUV/: WjܿfpDY3zz9mф#_?EP>8LqŦ5Qc!f#[#u=&U7ڙPYs}JҘP){8>7S:HY€K!uN /3 ?8,'?u~Vo0.~,7?"̇&SfׯmV`0T"@`O;=VwЌ@Q?;̐ h2\ts=ʉa?W=xـ׍{lYˍ{Od4!|n)'2ok! wfupE4ޡBnZK+MW+0&Qҿ5S" v9f'0Ȑ; $gER=Hܴʍ !#9GH'M:YK/|h/aw3O%N$uH!=# %Rs`?/%i_(貪QsunyJag/'.O_nWvnؔO=Q^;¹7ϯ=/:~߼O.e7g_w<h*HPP6ԛ% ֹ2% U1z9c)vA{/@xIY?D2mw3ܸ: {VFm2װ{R Yh)amL3đa9 ;xl* PpFabLOl*vޟ]4ߌk" .\ƽqv|:i\65Mї(UզJN 7jTV<>2ʍ}L'ӈ KjՌdŀG&`JgE6w J+vdxYvC]8:Q9|j =JL&:B/)fg8Θg82K#luO'9>x{Z*(2.vf+%R&"/h)(_FÀ'Za fɐ)_ZVr)4@C u~S12`l`9=i>@g3P~y4K2 A6hrwY8aM ~@G368|4o_g6ͪѯ qh LSK3~ҐSh!,Ae)=*T7 3dFP dHT.&iyup >FvH:]+U a(k 1ޟvgVXBtXa.6)*p{Z겝 !ZpɉQE n)[fR:,]L&̿-DDnP.5 M^2v/ {wɕL5x9WJe! EI^PFa0k`2 Բk='k0\!p*M?_WH•_\joqT̎]?_H? .\6v-t jǥt15ϣ2<"֨Z7E[V\q>CGEHZMp*Aj4N *O%zzTsʁU(kdStpc ȹWWiS[F/ :zjt]X54{Wjƭ5NgdV2 IU$v0g" ABIrBbPӐ{ؓ"ېZlArvbgƙ?˳Qy>DUy,]KhpjR m|9 u *՛X<K-k)f|G>¥qn\bkMC;lf4"OiuZ E,=-A㽮_J~S﵄Bi\ Z |LD٫iv?*y A!mdWEIf8mٻM _͖ uQbAf4UQ<0;Y4IV^]Aj-7`bllsmƪ:7& pOx݁6MKY+חFtis/~\>eU O9.oML(.Gd{[j*278ZkRε2~\" IDATpvkκbPEARJ6*@ntvՋT,ٸ BA:Oc-B ݝJFV }z:Oa@؎0Si`7SLV]ԥnzO(b*Z#S-rz؍Z j]')cH)ilQDXtMifO[_,g'(Zhah~9@VSCp{ Lbʙ 2:9 y}bB_so.LqΌۤixDbGoQ(-O8j9[眇"I\/5dd1 Ll9 &0Ƹl1vqqnGӢ6t:HGowTigWAZ-$D'cz=ꓪ7Y 6QTT(uJ!ʍxxH*hjG&G%}m, VE}XBj@w1pt(2vXt,uC}K{f1vk\9eqqW@fWdYSFQ8#3;^ʭ wڶ ?J\*jIA*]ث6zni!G}/.e;nZsm1HMO$B n!hiwtDVi@1.ov؂M-q)6#JN0C;(Wh{[!Iچ\wb?.t7麗X)bdDlGkfN~_I7 ~;1ZRUlfN p Vnwn _,;0\v%)DU%{3hQUpvkS_Ly:;3zKaEx:`G5gg(\2;nI65Amj.!5>ieZ&T,pwQW][/0eq!v.#n[M$.ttGt:Qev0@SaHl-;iJ$ZXHXM\VQQ=FOIӔ~Ȯ*5E࢑quvMz.nБ"0k:( b\( c&~bbRkI-Rc1vwwagg~O M2=K-e}lkz6"˜*'mz;Xm1 )G_=?aŤqϕdb0լ@[Hyu2;D\xQ>>?GJ]-إVkIH-a'^% |5~l-uze4P@@"Iv:6^}%t@"N\0vD& lu02.n-ks1P6Ż$>oy^J 0c4% Vl@ҏف($)0&aHcئMvaC*j,/M~1V Fm$MI~Ӹ 9Q1Ꜣ]xi(i5_cd70݀p~H!If{d:5_>pzS+ν>d[]cx6400C4u^7UH] -p)=9-D`3R4odj>47"t5t"H V"@F L.c609 CFF[-D Nv[03;H@;+~ne*ۈ!Jڀv/.B$]:)q?dg!۽bl+/}Ko+f@~'wB?cbm~l宫S r9U4I&(-?{ե/fsJi4MuPS(VzsY!ׁPVtˎ tc(ok#gWgrm1LuU$[j,K*-)yv5'٭Y/dD4".u7jIb1:tC{ ]AFC# 9vӎZtGt]a+T2ZJJ*ЎJN= 5{;cTۭ6~ ]W.,sZ%݁~$WM\`>y?u.-Ԧ5FVFpU$cE M Fݢ\:0fӛN#BjDĻ5S@l-` W߾ݱ1LPj Lإ+u~v:1[t]S,;Ñ#DVY@hE!&@ʆ,U %Wf]mS3Bx CԦ$UD-Q'+ܗvH0l;'hh1.ocm&ORGYkq?%pJ9_eH"S/|.VS6h6n8yX/vmҋ"zbA9>2K 4 K7^Wˣ (Auș* (%5{A7ϽLd~bIśH'@F߽4X_z@c 35J6@ tD#cSS,!贺G:GhB"!FyFhYAsQե"ZM7F-: IH_I0S'L#GXX84D¶0@+02BZPBL(`3M@O3PUHVm4 e'#s]) j,\x|ղ IN7ˎ$4 р;Ý5ԇt3f{x#b  ۔ 'nTENnmucM+ƣ̒G1gJP`߫3AڿiCCV {-"J. vcS'7xE2$=Og/gWzu[Ke-E>5eVR>WU>Odih+{(lTdLT-j\"ׯkh7Z|f_, ׯ051G0-,N/ؐF(ʺi3@ /{ ^I)'T)8Kj6kQ xEZ364k O'ā4fwN=o[q8Zw6 16P!J F!)$+$Z LEh@4a$B6?u Av 꾂a8Z­/\9ʧ^>FfǁAArZkԤذE`[_kO 5Q/&DgUV<ΞbE(նyGkQ*ܨ3+ƣ^8alscD m;3akVZH-0q.I9gP2/_lOU.j\Re& tIGKFOZ`:DQl-lS@5FRYEo g"$2Nh ABґb r"ìYJ ̄]ʺwf=Ww-7( olJ֥au5b.op`00Zc)+aT\#^E%pӅ_E$vggQVۻ+eL7uVz `. Xjy i ֲգNbd3&0ꔊEn/>I{h!A1U 2 B #7d 1qWH;.ʾʄO-Ӧ*X,3\4 O,A9`wF&UdžՇ]=n$ϡ|\lnO(vEiRl-\k5RIWL5 .U-r<@FWxsF 1K6S`q?tBC؊fP`T .ݦ%JE ^;47ƔNCL>W*I3*}:I14SiM OYm%M\{NJ?Ѐi/Aqæx]ylii؇=tӕ\TLÐPƣYlDW@ 1&pg3"AjУKWXͤ~ ;G-rA6UΉkyjpf }Enr8T-WfI1m ޞqiZWJck2* yYc*k3ZZU^nqYg"A>-f#9U~.mOPa6LR"lJxgj;GYĂL{=Ԙu]ETf~$E!Jh t8Y'Y4S% i dF%WdVAPЁܙҼ-B7l3M-Sj/נoj_iFåFypō[9=+gV̓4׮Ot6n=0MYw@?/4E~XH#sO,?;c\Cj&znM0jHfs/wcO9g拞 \ڭ+?S0v`Ķ(r`3V,SdT`HF`WEzVHS7j,tKSe*݉If c eWVRjk-n2NK@HOFVR AKb>-HL0 r%Eb+t;GF]؍ %5 _- uȐjV[[_pyz 6ࡰQL맧R3Vt+~DV.&g, XgTiVb7Oc*Xd*͖ԘDmD4!ĀQ"sHW?g3;>!UfeytԠAuڼwBGwn,R$ mp,tfo[j~h!jIEw YSUn& )+qBWFF]l&o!U/G!q !N!X'}D¨epXz:0PcdN/o -7Z· @ډφ+j1JY*TqVN$im[7#ך98Uۍ5J_]8QeDj'luc);}%l07O`EmȆ΍xjwL 3L͜SFLttfrŦY'F8$i&n@tVjYϋZǷUbUꢳSjLK@DIl- ,b*"c4v2ew[c ~@lq To츟47,a1lOon!qL-'nYؚT ʧQ甌jeI7+ +-AV߉ZxwgtʙuTy8.˩G853<\ X<}RUW#i#uU Ʌ*Œrb;XDzo0()\Y Ab+"FR IDAT dC=bE1iB@D:Q1DD!vǢ}#Ft:]0" iQbuy?0C^&S3+}"詙xfe-$6)!--ʞzrJѹ}&.ʙOJulEzxv{٨-l*ym̪etvmK;B]XI ba]J-ES Bl3.[}FkF1 &qrvF{E43/j{)3hM A>+1 AH!b52"iW$NMё.$J*B]RIXrU):a04FA4IS!6AYV(G1HX}bјv7loGu:+<vh;DG%%vKj:T(bd7lVܾ|f,bg½N=ܖfƕGk+w;X뤘ZRJ f WeZRCTj ߞZIibR-сwp-Qyި.g%0:$;?Og 6.,gËB/bc/p3 4cm:>{ ̙a8Hy`etlu mLͧ5Eډa%w{j :@AmK,7˟)~xn M9WhE\pSrTηЫ\<ѿ5)d7چOO(@(˖/_o.m@ٷ?; Dcq N~YIme9 x>B֩,4sӈ! m%G"r41<ϙfEFrXǏ`Ӊlu{{ˣG(PN8!;eej:'`彗̽y8G@lub+qRcZȉq~g_o[ڻ=M@ q0(O ŜP5t󑧏huSޗQ_&=4adx#8!<dU4]K37ww0L0PwV 1/e~F{~ gcA)`3q*RyiB"b& tȍ"l xAQd"Q֎U|x ?eu:޾|m|PJIn6HNVSM}mI\kVDBCX J@A\e,|)|ez KNM`gg%o^u+>]3v]((ny ޜo6;ꋯW춥m-8y\f{:v~rnC w|c$L# 8Op"?GZ) OG|wtifB7;ahNy: S +dN)ޫ.I GDž0 2.Frhjó5>T>1?ʩwp/L%֬EW?ƗxKČL$w*tu )MK6Dcd>j[m(Gs, `,{x=A|cB"hɞ֑w(z#QmΒIڏ{Fx5Z..gwі~~s5{{E\}9{}Âz#)ss6'!ݭ|2WyW<*Z5YxAB<`Kɰ٩U@I| <=Oins].Y;b1D1])6 G\daזJoW#(`*|B&zu?@.嚝djI)e@1jqzM?p>4J~t->^0])\lptFm ?y?JpD\t& vAIOjzU-h6#1c98k 8mE΄+ # lw="A$2i\C~z )p{븾O/~S-c =)`lzDhOH8^y׿⫓'ȓS8;%sqzg{G8rK&# RH\ui>%vJGPdBN+oCg/`:W]vx)vSkV7gۮ{pUXh`eCnDi'=yzFFrN)ќ<&v=nmO^2<ڜж--ڷWa'YC";P 5x,a:H%B*>k8un]ҿ1Z%O9`*~ x(Aӕu}-~{myß%s1c,:9Vy, UWxOW_6-e!9k,}XՑ4!jHwTbmlNx!ݻxO_Rt%Z<8kpRgUN1f0cFoy챝 N1.f)q?2ȎO29`tОt>5r;Fw#lG enVu' L3'(Psey2q.{ҿsBCۆ >c144 $s1-vq7p_%>|A67<7)ӜszpO}< R瑦[D,9/xr mp7nSW@!U^hҮey4}+ʭf89kJMngi6,Μm iE&zU|4E\PזiÚ8xĭVmh !VɍL**أ2ҠгC ᄡ&Tw-yZ>'Wn@"xK Je:,jRI#ڌNTO!BpBht۽z}`xJ5H^2/t ȃ܋Ip9 Ϯ.86']a o {! 1T8m~"K2S;xnU/ӯꊳMG\8-lB{hTI@K9MC! l|C;Dvq [lȽLpD^Tryar!.|ЅB`ūc`ZٍO&ux( BlE#YB#82#5nǏvVvb4W1~$Ь>E%pk͕yH#c>j;_*_%W.18- j nomTJ مSեKf-E_T{!i}i8}P+E95}¹ _n a,X{H99gp~5\> HswXkp×fr^ksyJuR,xH YS7p㫝 EZ3t["El*B>Wi*2x8k'a]v]y #ĂA8<9ETac7Dڣ@~ލD%n¾rޫ0|myIW9TiNOqh =N`Ȋ, UY^2O>[kIK`8a'lݎ}&QKДCeAϻeXkh?@`$N-Og ^U@ׅdV-Uj?Dh g^=G. Wt 5μ %N{)6u$y*M'/r<汙obD*&P@Q?݂(|Q|[xf].T³g.3 C8$M 1dб/\ Ohsuqco+h{742Z?^#4ޢյ[*=tmx-䥦iKTH ch܄26ayɧЉ"+P=0~ MVmsrzgAU}LC6n'0c$W?s~~@ -I IăXZ3EOrtٗzƗ/N 'P +m8|m[)GP#FY]PxZ"Gk<#tQNGdjiHQ[k Lηg0Ne\7Qbu)$]Z^2Sє34=qo`j?[ƘfhPW q-_&= p=s7U1I H1i!_Zrijlu=/:u?B*6[:@2GtĜfqgef|NN!gN& L#^Ӭր%b%SO0K v G[\`ȁ0S)C3n_~ K!A*츎‡}_`,KuK" bklJ@@@tlDy#=b"ex+]UTcd|UgJģIQO(1"]gBadX)(AW*26_P*HZ\:͉ķbcD2c !yo-$+c3< nMFԣ>%5{*92D3C#3sgiio`C4.))Jj{d*׎ݲVN|j3Y`r#B*>[hi;HHͭ e:>L'RNlSrӜkP*xyl`0_\E NZڰesqy~yGw m?me4S.{Hp.5DVe$@0+|m*^uŚc4v`i*˙\8' >Q mqSҿV;̈́~m"j)jH1CȨm'WҐlcÎ;w ұH )F |t$ڨOʎ6nGEٟ.ۈOvj%5VG$YS.{*DcD'eA4MTN=qkA<rВ 8e<8PIx;[ l[B$Woxt~fû~b%K*)(J`(%9" 2.@.@߈U}TK4Yq?4~O,Zfغ⸝NDq!tbnܔ&{H3SP(nsr zr"OoBp(ԪXdJN49*λ$a9|kdJ.%_NX-'ޱ6X\Wݻkx1ï}e-Y2k "iG+wiK74;Af^ UTVZS][k#Xnª[-fgF`*} In+ȮTgəe*< xh](1b2WPŗ7W6 GerlYfܗ Q햓/| E:7N!&"kadYC_y5 3NR.aK^xISmיgNyLC pn%&ϷK,"dBQɬSΌ5><"!ۼ'ȠKY~{H{{Qƨ1o,D2 Q7-y#/qm۸3c)lOެf2qm@LBnԀ@"辬J0 |kڬbDM#P Uܨ~JqCoNPȒKxɜW~x>clK>53nß_'&N`7 .$-/6זToD8[,-SOq.N!I@Ͽ|A4GcJE*..Xl6mK۶%0Wb%_M!0Thdya>.j-S)a)wbeJ;Kr11@mDLGRA8&}&FZj|(he|3}\KbL&y!:ﵛ6%Gj329L+C $p T\%DD Ȟ3Gc*XGTS֟YZI%Oq '+n2VfFR;ojnN~ 9_{^~{ dR,=(dB5ko89^n9 p/ l}m! ^1ӦitQy&La*Ο?%x?X(64+ʄ: 0d9OXj|uUt %" rDR^'hV7[s>&Qm:ٌ;Ѳ!u$z3G8PqH8# xLyV=-lR"vޛlφs-!{KV]X(i N[9 qTMV4e}thx'|E =MH}qM3\)'pnlן/,w]?kw]~&hsɆ'SJ8WNvs%ҕX* Um/qS9\i&x#6 "c7Т]" "&w!~`"pWH9"HۖlVXځ0dT>FskGR+s9~x{cH+!H {n@R-7{% V%!"@@K{jG!_&&;Cl&.iq?,;4I^Orpd`W7һgF9d]3WgtV'-}YfЉknfG/ë"T&9iwc<*RhHkmTI3>YϠCB|8hlTD3@% c[5ҫZ0fݠ?~Gv÷69?CzR*%@r;i-3ƊYبի]-tQ#=czKDf^O-Y- L3y{4^hyZhmC$bR*MްʡЃA 6qy!s.+b9Kji[d6.&%^?ϖoX_/v2'HaPv^#/=dGwXۣ"w<=|4Aj\vBV|Y@ R7CFA4{ُv/3kRؔy K+s"n.#)qG\!م1$BoKBAFl?O&1}&d6QqhsMH㖍ӫgG"lM'Ps'oHf6'"Mcgkh8n>!`N p8 ?yFRyO*4@YT43y&40ǑL Sr4T\a9%44ڶ_ZC8[ƸCQjݎ0K#ow9KZt vm %oEq>MWQV޽1Z*Q6>QF4÷{ xM!Ҏt'T k Fc:d8)!8Ao;G/'OiV.$sڈ-l6ǀtЂ:,`0H?{EsKw@uV&Ԉ,y&(&_sw{{˛xӏ\g<K.<¤E' O;%{˜tdAZdGTfkw'B{*_«`׿G E oa,G"č BTbU-4.n4C(1^59YTt9BЕDc@C>jBt]W‹" )-EXX hUxDy+e뽨em`&XLs-$ ]%ءr8пh}Kw;zA1XaL^xu)M`W t;_k~?#\n6h^X@D"f/H9r )2{r$ܺ-㧌ooZ[~o(=G-aGO5(}s$EV)3=wUN8e5r.nAGw%%?w-\ x3zUO_O yaVlӈc^T5t ˟? q3gbpϪï/?ϒqs?r/υ%hF;X ޻Ix 3kv&-]Ρnn rC{僭6]*h ??="G'ʸi+BˊXڎ&exlAϣrs;J" vV7{}|7~K_%"?AFڿ|wt9; -uHVT%ñB:Q&31LM^N]J)!J~_Pe 9)ixe,{U#g%mXM1ͬy! (T҉B%hI_i 09/*-JSׁ>EfB᝘q는=0{ i1J&_ƭ mcŞ0~"fMw8X_(2ڱJ&N1Zvη?o[{/B nG<-WA^ê`fͶzw6.E+0=H&pݓ߼99b(©k.N}~24Umr!bPBTK ڏ ĬS䤤~MLe>lB$Znla嬤4R+^r(ʁs"%˟ ' d#c%*+alUyЉ['; * XZz~zZF0e$}<;'K &݀8$"MM $}+Z6S-n>Dc(^gIfxeS5feUo' տ;Bnl#*Z&', :%@2bÔFnP7pٟΎ_7?zآB ^ xZGZdJB789M u06KϦz萴$Tm { ;@ cy ,T2 q,@ʭnS>IPpJ<(,Ӭy\ qaeݛLVH oeL|jıfk=ز#k C<][YdW8qSJV߄y'+t?Iě81+G *g4eRxݏog>Fx3j.BA[ 4SHlw.:Tw0"Bd IDATdW 4d{)oͿX֑7Wt[T"wS,4M'2dU*e I.|UѢI6-4ghe)i8e0R%33$"r: 9-iqKW]"h"-'yW aĆI+>[{^gN_e Dmem[/MYGZ.JK^Y-ڗPG:;{*-0+yd`O@Q ocIq_)٘oa3ʯOi5o_W<-ZS{#k7A'99m0=vj~mOӎ?o%?]<8lOrS>?0<^!#Ok(cJbNjWcl[7?iAh:tWѶ-%EwsS@SX2 ig_&SzJ5,5IL\o018&)qaD ܂'0#K'Cd&<])&^SC:MHP.-3.t.TT}8Hi2Ȑ"N4>~u[rYe=v47Ǖ_?Ro?W_4ŴyBeʜt&IdYz)a@Y0;v=q.= ^?8ޔ:/ O?p_s7l6l-mhab#=GgM|-nɌwݺR 2ěuyXvW~~v@ޤek;PyzN2BFEѣ -alQFhE5C/UmGb20dd13)y UXsjZEЄP<=23Lbd/* a!D\?_ byg[?Qƕ0f ;Y/82CuyDAZ5"wtۡXl,[n`kl>lv؍t=&b>yP @=vh}֫m#t azql&`*U&Mrj܇cMDVetAc[6CNH0FJ Cқ\WDh}ĒR/_Ϳs~ʯ~;v]Ȼl/5ze* h]tQ-hOԒbtqR\ }KWԍy>CW97VU<܆d|[tټT vw2qcXb,7@>D\g0| 9 Bc~߱ۿn[iTD8rGTxwO*_~͉ wN)G%gmׯ6."HP.ӟO=ZL#JKC 99~ۑfJ PRFo?9Hcbݳu>zu3ߐ)yNԤXv+%ֆ8Ei 闄_Wagd]ٝt "e3O;I'PXFhfwH |퉣mCf"u$:(6>k?9_"JwΡmkbI)=߄ʿ+@i>aN8z'-H wT(йF:=9}ҲX1Cd ~ lZ_zDZOR&H-\NV@qzi`]VDxfg_&~iC7o?ȷ_OK4!.SmaHsFJgF 䔮kx+}]KYA2ovɩ#Τԅ1Ban?Pf5Vf2*áp W%7⤫9M_ qv91a/M"XtFMy|k$]xUe&tFUI>#urjĞítTb$4^5kaM7#ꑱT >~GbX!i[&shPQP?w ;F;3Vg8b'LW\]8!f&@* pk!V% x1gPW! } \Ùƃ,B$%%9ِuE| P/!3|%߀+TwO W;3tv9JX)Ԕ+Ao Q?{jUԑ}zʘWGCq$\a+dEsD\^P[ ņ/s\lؓExְD%k'Oj0X!eS#ECEV y-/r_뱟@%Vuʩ;h?q a|Be۬D9bwi͓@F rK<z~&y4 k9i Dۆ߿&*p,6*8i青&#tݮ YHpvժטR# 4\Ȝ1.(C2)%rt% 6noA$Y´TWFrdNҊx|wg4T s AU$ƙ3KLg;XK~H::s):ʘJl;qМ򑬅re$@Hy(z13î@.`$;uۙPF B[A#fo8rӛbL:QFa^bߨܽ@v;\Kw)TrUM~.'XA8"Gzb hfS 6"'{EmM:" (֜[rS̓? _*Xh7e\л7,@Ez姏ݦl *.1Vwvi4sOSG6{pjPFT.WLͰIۆFt"KƠu1֫ZHG9]5-tfՕ1KԴ[2]]0$EuK?&! vVNƈ/ZŅɉr}3r~p:OZ2qۢNiU(X`[P#EWSY&&.HkjY[%{ R0ۧލIJ=Wg)9Sr4Z1R*:.'{Rߛ|DJX}6Cc=Ҵ ׸8% ]+^ yU-ʪ[V~G^ T DxV_2"͊OPS[sUPZ3Su{DFa]s,utXL|*ꀦ)C՚37ڼ(iһJ.v] e0^A}K3㣖)8fUHΐm$眫r?BӢ83cRDaX8y9#RҀr&ӑhYEwph찫JqsU5}(YlX"ue5'[qvw.#\EgGNͶ[Mo8Uha[&:*'B^~t˧OEgȣ糯RphӞ7/@(ܪY- `EJ 5 3Pf|!u=E;١A.K^8`BJLQݦ_[7n:#7o* % TSԖ6inidUr Ljw<'qBZ?uj-uX]r! fDDc2~\ ʠUj!^_b}n$Wߘ0k:Ɔf;j젠Ca܏h`(1/H6UjMğ^k0{wb蚪[LzCM:oՠkzb;)ujdLnr)9 Pynz=@&~ HӘo?j r |#7Qą%LMMKqV$+>ܵ n5۪ey(֢fBԙ ݂<{Z'T0:*5jL Yg1NAYG>h͌+a@{[Ԯ!ޜT BR nTƒIIXҮ(4=6 sD d(h/oy?@ɶ!Gg ]Jy6YZ?!&l/!ִs(y7oʚS7}j҄D- ,' (È#:fr0Ǫj[(2 "l$SubgLf!bMcxuaǬDo7&=`S}]SNN<7i;`LAw׌x eg5":]JAչ?6($WC eN2oZ*Nra֮^޹{kfq-, gH?5űqޙ>럔ޱbO8dҘ/8Dȅ~.y 1!2b%798#%ى2Mt5Bb %-lW];_C[1VR0"UEs5s۪t U%~.zDkPgڸ.Xhj.S7&'N6lY&s*}JՄ?<|n  }7`zy?<6kjQׅ;UjcU~\}+h\z=Ͱ$&GAϕQYv*jL:+] U߄,F(=պXM""Ƒ3y ~T= '/"YQ:i9G@J(2jȳ.J .q2G% 0d>|4^;Տ |/_?{`^#otʛ7_ ?^WZj9~*tw0spv/+Y:5D%zʣR͕:2\%TcܽϵU 1pY*v]gT-#:*ZqDME֊I:FL_ӈlLhs:m)&%xp0A8z𾃒LV )tySU˜/w{:׵89 1"^κ흳@4#wǞ-$UD\}ٛ/uU[Є:o)XdO1%MD0I=iv-Jہo8FMS.X C1lԑ"OڄP6W/ٰѴsd_$2\D?냷mD zޘ>FDz"'p}sox0.xEM+hTP=T"cFu_`g>1978 5MF`eH2!Wyg!xHMx4uXZT9\\GhUnCw4<;a8{Jcm뷌GDZ\ixT 9A>ox6K=]XF}_"JhP̺\:SBQƢypTQQn NGrw$ߠX !8*$TYhRRzYdQU0C4Z^C Fg_i r/@WU4tq_cC۹S7Ņ48.n[Ҭ>12Zkjd=jfr/B@Nz%vBqy{EӢqbR % "drR ehpMØ n.;xA^~N9Ƙ8ps}x(7zrRp^;a"5}x넍5Ai2VyMGPˍRS{\M2Q[3AlӮ^ WU_d j,w\tdm1墅z6_"L(c:ZvK8/'q*r*?n}5E'6U#?NxE][!>m$Pu:Q"5 rY$[MU*S ~*(fYWMRVi]NM'UQu(G }#qT0]ך9eRQӟ:˘eXxFVM)8-4guGU#}$A{9B_W WǙާZ:)dhm[&s~֎b:Rƪ=-gAqģ>Nx[V>k%z xZMSQȉt,h8h ;@kyI 2U+>(bN&'n3ӷ IGITQOhha'yL~ЏiL^>MjسlNյ-IeTѱä&٥ˊBg3}Y{>jJ(#<-j@~cpnn7u]p0сTd('ʋ|7 9/͑!m.B1Knp {_U{Ñ}S{x˦D><8t覩2QVW8塚/ `ت,O }pIwJ4DV׎=kR֎!FG]|2!>9jjvʦȐjGTśA{nn>B lƢGSHuI9!bS$W20SvXN&YSt\+xOL袕@l])L KhbIl&.X`S̆dcS#Q n\܎p^O@7@MF?r;..Q.P|W'cO:=Tq.x;Q$xQ^pCǗxMBR %ELE&j=k5kTݷ .W9iwIV\%b4N#;W+]<8x94c?໎?RGN+qhN/YRukff % ڀ9bPF)zCQKNvWO4c&a,h?.Gt(cY2078E 5U*>לWjQلpN :MU@)VS!:Wt\"';8W^;V%2r?T:sU8'>}KJVA?o.:?$ ٳ/>/\8qG<ii*@h:Ov@DFИȣy셀]3Rzeh zhx*wd![eN~ec[9z)蜼ªW3w:RMt!2.@f)#UDKO'b@-Ácdg:L)QHʍ{蔗?"g݇/9\p8Qr`?cUc9 @{=w.v4duDHxu85A}kZfE׋l~̺eY?9W#GRuL6쁬=mLh1u)Fk8Jq_" dlΌ/04P:f/Vm'R pqG.9'rWHaqiDkOY;mN ɷdvDԯ`"l /_WZMCxDvzn9<'L>U6 F.po ?: R_0A->{$SjhHƁXOǾ[jddp>ێJUˮ+1HXcj8l=rbzut5%f.u0"ڝ4G6a mXD׋&,$Lɕmι+i'>OM_0R,0hL2TnBW7j[,|MWKa!%M K197KY!R OTpZ5cAeɚr:0=nʼnygwU7[_|srN.9;;ǝE94=\]0)=ǣ5d[ԅS sz>\ㅾ$sWz mD #)ekíeERsr]u`(rT!Υ~Ӵ"6.WYEM0$ qzzR1(#".4ԟPP.H26Fo2?]P=.ӑgƔIHp=8ir)@Ga03&6 6˕@LlyE9 + ʺW3d祄ܦ2-t(R@R*.Oov՚}sqqcIqqN p ^.=N,wa*kS{Vxsu7Guҧtn5#‹<34 wG#:<]Z 2 %BH/hcDJjj݌U鴘Km."չ,- Y~=*V)L'~M⎒J'DӜ"S4ـN.d1 +JYGoG{ZY8E/yoWLu!`ZJ$hTkS$eV- t %$*%\gn&a<}ɔ󞮽9!q`Z>X> ܮqE3BRapͱSK- ZGnT<SN"[j}Ƃx("g/<j_*_| '|—/ć/5,ѡEBW{SL:*[@Qoܡp«0LچD59VG-MZ*<{`e㑮p ^R:+uSK>8tYrR6l9 y\\XpN XE>iH 6{O(|:,6sҜ[ʭ ͉rw)x/iRM`Lu+DzV"KVK5ˊ0ӭNyfQ;Gi>۪d5t CN0C}5VL2QxWbSf'*w=1Qi]nuW_'\uY;{:rg9T}s/Nk|uڙZ`` z]'gn*{hN}t }3U:dLÓ`R s$L`6^^q=FTm8{$r9׮W|ޭJZP7 iDmȳK tv*p5 s<_"ɥ"*BL^ic5n;Ui"*"eJ<xtg=Vqj U5Gk/* X}~4\n?_r@_nY۴uTLt9k6蘹;q B n`n|{6ܽ}Al\g?7]:_?; ׼x\*J188==2'q\4 /AN(1r³ahJJ쬮2٦R'J?shy+{,奬f.WMLaIؐk-&Dvm~ !>3cɌet¨J~χco)R("n# &eG/;+L5󡠄'Ӭ0qfZ0nBI*`(8[(g&RMWs}Feeczh)ܧC-r$5[Feՠ#4 S\^|eztL#ăr^O:3׊y2*WӃ&Om/~{"Ϟ&X<{_/BVK2U AWȍҜP<<pwKw)M_[ΙcMSЈFMFBK>ŧ̩mH2K~{ *YT ~gė9) JzPlE/kcɃ7>W9NB71è|7 q{9q߻Zq$O_P>Dh˗gOmru-|w0MTGGO nan!EX2AXFIs7 GҡX6[U)mKzd[eu] h V >8ul2m+U241rɔ2V-z9E^?tuE٣3{K"&pϯi!'9BBw\A+[w0 {=Nc؅'^_P SLX,DkG3Le5,zP-Jn%l9n0V21Gquܦ+Cդ'эd2GEt7P0@^cZ+E?#| _/?oyQOlcf_k>{uEϸ%"#>1x$l**eA'XQAzs{} a2q:xO~@c Kt]:.7&)%R!gSˉJ-}gO88X9XJjI5y4kɯ7ieHq9%A|wO\t%UQw{\\oRFϣT]}^,*hrUȂ>yv25/C^//ѧn3s:dW]'+}J3ILHH;k[Lֻv}"&rI'zী[A/a䷿~[ *&y|gO{B)x9 ޿ j&;o-O+X #:^A# G;^ɔRp{#8GԸT_Qf$*yFnm?SWC= y]gEVݞ=5Zk%)E.YN9"ѦEm QJLL,q0krr4ΙjMqP~.s22h#dn6ҹ tdWݠL h/vZ> Y#TXS|7:O%m-3U7*JNoG?zpoOo)}PJTTOwW tP0-{tsS{7r %\S6&~)\^3edp=@VifМ-uL\["B̿:4 'Ôm j,t4+jOL*aO6-S*XEư'3tnS&ނn/&GeŬ,S6Te.j|W}m U'1{X*qrnk*Tʇ<.-w6֭ÙW>8k =#@Bڣ^an=}xc@/u;xVrF-u:v~;oA.!е^L3aI# a"rj|uH\lSn"iMcDx0ncT<]Ed%!Vk( ]5(eXNۻR74֧;sNj̽o[%lx $Et6?q'jWP_ SB{dlMat'ffv`ۆ>C򢁫Sy r SYhwn ^v%v"]0ŬM>jf-*XgG\eahsa@զj5\uIʺѽTl3#O>~0 ]Sޣ%}4_}%ީ"fs v濎^ȫ*~l3m Ǟ4rBþ w~ǀtԣnO<˔9zϯIC*Nc`+Q\S'P>zv -f|K f?լxyᗿ7y@05? O_յpyU:Lq*fݾ_tn8rnͬ"۟{W|9p/#f}}4oɫ i@ yF8;8jPPƅ1-Yj5AD͂!Ç{>M-1$k>JmqZ'Վt"?jܤ2K5$5pX1aٿ^ӻ"p6<?U/n{ Lm2SS<xRWj$@uўM\BV\3rFl@o2'wH]s.uLAf{v۠Bs$(Uuoj_ "T 4B^:\[t-!@%fsd&4Pא-PbͶAs̼%"bd+ξH~RylodNPjcaNB=XE*_1h%F ӵWHy>FC]6hqO܍laO-<LjT@㜑|Qȕ~81*]D$DaJ"c! 'TQ ]tU0AL3P)ZZ%N }ή | 7cv-)xi)' -wrح``4;@X0O,mtfсA5`0 Е.Tf.mҸGwHgPkP/ѩnd(#U0zgN'G]k+WU${ F G6-"ƕ|V(U-R$3ޔf.ږ&DECb褏4h_YzaZjvS7n'c1i9WBͫ8Ij\B$1&S&BФis+ɉ AݤB0Af$.۫z2dAE;遣Od9> ӳZƒ-xl7>9^n3H=./Wy2/ϯIqNCJ2+wI fE[DOTuiDt5©~rh!(fs{,.ܼi*6k5iTЩHj4֐:ZTh~=ƙ&+Qp9IIMs h~El3F`d {̀\r^Q}y@Jwe~ 1~BDtMFY%n&IBu!4"RG5A SHMQfʯeeN’0%J<  jxL;H1ADޱbrZ =.T{{g3Ԥĩ]FSԪFo ^No֛z@b YI@fҒ7 x~.߄&YbA{~By){ fEff .>>e @-QJgE"TׄZ0nn;m7uHHP om3ի L= ]TԘJаˮ3S̱xVɒjHP0}79F=ˆ M(1Qj2f=g쇹]қ55 >nLF=($3i'ÈxJEtNjQ[-Et >ae֦{%)xQSyPs1k} Ǿ-[MK_::1q` cIFdΘlyd]sX8+=E{|rFvB03ó(__|| )U:aa֓lu$NC‰#4RiS!32CmYVӏ Q-<ϚmT݊sjP˃>\j/iQ“\R.?c}E wz^6t:~(*C|2K0s=XY}Z-'wy2QM(N8;3rN2EcZZ "%-tvsfb㨤,uXR=S{yCQ3SB P&j8ݘOvwU(vI]TA$7IJeNNx#G?'^AVi*#T)xKhj1\="{]ڕ^K\w]5È `jBI⮡ |kVK}R2w11[>sAģWGtѴ>`+߃UBsfSp xg 6l _|5G+OdC1Ж>oQ|ATY$:ɲ]dJD_8Qd3%AfVX.RR«ھEX>|}Z.^p TlP E܀rO2D?&RM6)[M4jKA6/+Xnr_K\\J{5%!FB<#$IuZN~尨Nѕ~YbC7̰g ]zp +tjs/\z~Y}EoA( \xp&|ڂmO0qY/U=Faa#K:mB*RH j P6.x )f#R, R!F,0:~\ pk]f FܒIr݃`K0/U@Aׄ0"#כ.n@,)dHf^a >!Cc!(̄ӤF3ev-/qHרq\TpKԤqɢ}&MzWdQ*UG5rxww>AsO@ PVlpnmE< <8|vMv`I]Ai<o4طFA@KsuI 1ITr522,B,4f8PEky6V %$^ YiIؔzڣHRÁ&D](%9 'o_ n/e#qeaPD REa2}o593o3*BG,x*b Dz%t$uSYiDMӄL IU#>:wFyqC2Bg9:By<׿>UbIgke&NQS,dpݶY!_4FyLOc3~ \;.9#| œ>k*-;bQ DoVHE$ `a !D7[{l 8,-l<:mddQ扽'rnoR`ZnY~l@9ݙ鑥\/jR8e3nް*$ -VKMO??pH3ҁѨ@:v( !!MR5UϿ:c:=Kmׯ@]Xjk dq ʄ0LO< tR_[\[}gg[7L "0ǻ<3oMR 77'e=|d%*mg:׮o2uIܬ,Zr]*d/Z2sPf g)A!ޡ%֣|}Y5 ]WGh ͻiῊݭ-+ٞn}\xL!`jQ\# Ӂ34Klk掩*]uQ;\\dOYfmMn&9| a;(<\}Yyx~o@=Ve8aw7 sdG->XGϲr:B0~-~a7{ROj۠50Q\P2~cE2ڰ?7e/gS(*t59]j Oz\?(r>9$wq&fJL5֘> gN#x5+땖2eO31D{. `.{Q85^e)LO+/> pUMo<dyٱ[",7ۜY^ԳTfe{8ۻ #=LVZ_Zlt^ Z6A-N?ZK{,3?_LM _2(v|~\l,!w"0ЫVq*b3 שy]_UYV2G ZVı6x2Pc4H#LW9@Շ:,O-4ٮNjXؖU*nCD]2R6M Z,ӡjF T6'S^~Ax~f[K [׾[w酮F"3^+0ێ2&mOudcRNUVK{ X^Ղz[;7nqܸiܢ*IL/J&M=YmMJ R0 V".*Pn,cMjBzݹM6 bPN~|R.LW7MjK<*^2)Qɗhٴc>%gɾy?</_UqE~m7(5?ioϽvo ۻBcdxx?qa_̀8eyw ˭= O!c<6tLHY"nqcw _^aRIU[};s{ӆހ)9.peo*(j:QStK%iJ ڡqJm+bסG.!^=oʑ8-ңgY\*`EZ[V4Sjn۶,r%:VuZnk~7|ǔ.+]8{ 4ZcbŖW^qqaas_ߨơ0Lɚ)IL oJR޽U{`a8R ݅U}.,VLBm* M0 %PI׼K:AzxM㧈cAd,괈k "tPJ|1(D3`@p gCcj 2N$&jU8sZY$F+%cnv8EVA'I4>޴Rۙ'(T (3^l4 |U6)^"#^q@A3̡ЊYh6d@AJ bo%@HWSN0Z8IDATceڠVB$@OJKXKJP4-*^ j]P!ZC tDW;ŞTք6! CAݞemy]ij~PLOTgNh*Eໍ5|[~(Vje;-mw@ESZ/v^_ 0 iq82AR_BNhJZѕ[L< sWI+5p@1f,)L2Bh{s6UTv%VI*N q%,Y'3\׋rK]]b*8CO+U3F͵7ɠ9bi?3IGWHͳ"Ա4 Axr >g0U3)^٩FŃDY.Lj h*hmGW.נ5-P- F r$5{ &ݰR06JJ⑑a'RSO|<LBϘ§K&O\K'xSW ϵ8:Y-*(I -CW v\J/a 9FabsFQz%|=I5UqR $%BԄ(ɚhfHhw ROn A\S[gL0;AfX㫇F ^%FK~HC kl׬L[tP)UB3S|hq\=-a+h5wrxTuJ TH1]`j~*W#3.U OXU $ (̇N͠hn7hfz\|l_|'9Y!ՍXMU;C`+<{)sP)9 = 5*a|x>>W_ !K˭TF1T+gX@P5bc܁jBgUP$K5 uQ߻sCQf7&Ѿ!u*8#Ԡ;(n2!#P-/\ɠW?YIc@!?0DȱT4U cN]j&sDW@HrptTn2BAo{JkDLkguB3qAhzgǞ|LU|My:|+& zz]FdD3#MFd$˙AoNTEUc|FiB+UVN/`ӎĤ.".255M +I+L4-VŮ2:!'[d̵-]2-轪9D=x$S {pהW^9FV?fߛ ,Z9ƅ^R7aa!W`1h01855 u}LB#2$ʔ߃"^JeW8^fL' i]$Y[q."p[h]ce"GK˰A)$< L39d?[ apHYuޘll\G13M1%{uY/"lGUs' ']nsb1:UHa8h//Q#c)}LSgPSsJާρNH{VA.R|wKgt1?5,S-R fߙU~4A;x񲣛BE3ak;Rc!8<.U7:"qÖ*"[lGzQVfAwhod<8k5ZZtk6]dlZh䱰xz59C{kjVЯuF$ (L'DܬU7_x1;Bat/_<慏>/od٨z&Q#qYm'E.p2o.0D1Da̝6fF%SYGҺb,/И ,:O 67bNeN(4TvZM4 =cF=qFug|̖|p tA! ?(XGppCJQAeT*/#qŘ}0M0 GthelVithEܺYoJ6s"t.TّBgagAjw%A4R_bf?AFrt2ݑU91e$;en_xe^Y}J%%aui7g& #!0~Ch=B`7_b\/3~Hu9tn^oάk/㾰:nhq4;.jQQrd#Fj&8I LU{Et-C-23 Z@W=(d]'Аv^e|2hO'LA;2Q r#1efx~ƫW^q w\` |3|}̪^xrrIFw&Qj2&:Mh$ѤTWLײV0sqV'vKՕQD8kwy';mث8y7B<' gG|G-u&]6hĎ3 ߾tٮfw k¾?NϼtYDNoP먫zJ&D`=9:ۻ[>Nh1$@|IzT=o@{2PRG1jc_<)xˆ =mG=mi9_칟r`aæ\(~Ke~<ϕmJ%r(FFuR?XcpR|S#jFPcKDD[HU@f-4H=w/fW3^{oD5|ž_98EX ;[0^{ *A煏>FcuH=:,2zC8o|c j,g;# #anz| )Ho\;3ʈkV7׽?dTM_,o{5c>KX칫}z3@8 < r >]ϗ_l@Z=N ZIKdo+C 2-()$ԩVp!!d(ƥC]qN~ W>wxށ2`s(^7(]:i%xU~ly(9H D'ᱼ?sC˗slmi;ckPru`xL%ۿ;߾ nݶ-mp`N'2JIwT-=ۀ;8:q zϏn+Q<8{Fy x%xyWo_1J!%AyL%A+zo^ӧ9xוNǓWv/;Q\o>EɅ)^WKcsOZ^"?ldO.(ơխޘ; y?k_畓OSS=]s ~a5M^_Y,>^lZ'S3Gc6ZYw.꿅/}?y0*h/K\g=|7a{盖'Aw'}4.WjݭK ?wCzW9{?|%=q?.:?~.? >lz[K.ˏ;d@_6.P^U8%cT>|~}x'e5*\x^{J5⢾O  /4;<81yC,hI6pFYXY/^W{iu4ϻ(o!.O8'+< <{gV8'W|1 8q.#'Hч{;^[-RuBYGfV^Gy]">vLޟOf<>i+}G-OE,⩼kG;{Ng} ?Uat_\D @yd8,3y~>|Uݙ;݋h/ 8g;]>95~polYpQ:9}:wo?Ϯ y$+w~4,-2; < .{|r9.GpG b*yzf'ˎ 6ǥM3q,,O2,-OO`|8́fUK\gw8+X߰Π:qwkWW̊C\vg>k"c8{T"<m42{p3Fx+K&WO* _O,kπGExjkKs5DlVX WĪ4M2[g |"6p=^N2z"K.\N)naM?;ùQNmH d?"w;:~jT =3oknYX](K)}w~ Ps@CXP8MVTY]]a 2Ȏ#3p2|~ } Fn._We[M8?q'9:crݣÌ*sҹq^ϯo%ak4{f3:]tϻ'Nn)РᆲR-mw2c?q') t7e#y81pr>o%:{r2DQpIENDB`allegro5-5.2.10.1/examples/data/mysha256x256.webp000066400000000000000000001464121473414355200211010ustar00rootroot00000000000000RIFFWEBPVP8L/?M@ 6l3(ݐ?n"?.~ Y}6vIPU$/_s +g?T6+Nn_6WotҘɛ$#Hɉdc-MvLR{%mI\35@ivH*)1*9)3I l0AH$7LȑtwsJ$29xnpOAC#O9` [dy !;9_rMV@70 9ucwo2#aE6$eQRffvf { xXݯS!`.<~-eۦy8*ZM1?Fb?#g vݨAB\.q0ۓgCr1mitʣ54e"^?pk@" -CHHP;HߋFމD˗8n=nFHw|-7B(} P8h:VE D  |)ՊEC r&A`j8~p%@GQu^ﰏS.8&_~uI]"d(Ȣ:=^ֳU$p%C$mGCJʝQUV]B:C!@6̢7ЊlY,(zeD7 ʢw:)b)BKaO&VT mE\3NټdPE)b|0މ B/kQY$7w˶Բص x?k'ZU|eٜ~HBb垩GyIljv;Gm|7F;`٦T&LVTń5om8ckwGӘdyRxH^7ïe 8ۍU66k|3z+3h?z]`߉/ulGΛ6ϟkGyUZ1=6p'>baGkRb^q\sf99hLz|m8V5iz`a6gzQ:>P^]2$2nB]-#3|MOuW@1qo&2mɶcǎIZ[wE&{均ڝ>#$ elӛwn-V0ɧ({`m:ްVƏ2JȆ>R_ ]~ƶsX=; -6<#H|n #IQ"1Q<3KH,|'d!H@H$dQ6$zBDLPm~ uj?X_g?_ 0Fr첳 VŽ`b[*Fq`#U *P"9`\#qA@U8*@ CF}2#2Kdc *6`>zm'-PkU|< ڨ-M{n/v-E7|#_w qVV+ ^Kn<{ν{rD P޼l  CSHNs<K`>%Giャp [ ol_,+Mfg%&ָ=; PinAlcncV(@&XZbXmZ+@t[p5dmmHcϽO,9@ Y )HYO߃{kjl[%Is C"ŌRm V1Q>{MoKmf[Bl d[c *( Lֶ9?qB0(Lewgfڙ}nu30+K9B+59]B0/Vo'ꀞ!g /(שU> K9_A;lGFJES4)bM0Z9aߑlmVD*Zo닄Y"0'ϩRa^S9$ɑd۶D"F 9SApSlj)νC}.ݹIe=L=˳;p1y>#f&9^^_a&k4FӌmFeMeaNVGֱ Nr,wt+̜:FpٶH{Uus0ȪBϰ?{T3`fp2RU7m۶ٶmIQVU?k~_-i Pжc$?$ >"AqU/#O,A`JPq 0\<^җBF/4ۗ GP#(ǹ~J>t^ .0?}&}ቇW<sbcxo{wWJ gSo/MKܜ֐X ŹLA>1Q4C)u=։3s{|~=k AfJe>/3;lbi_5Kz=!or;夵_~b)J&\|k . YJp]uO ΟxׇY}:zx+Ïr[7~Rb1<7__x_z*y#+&aVd-{GRZn|Cu˷x!wx.U#y8v3o_;g^.N0mE vDgo>]>srܚI@r}!I@XD yy_ǿNj$X,U s $;5X‹IuL:\=d | (;} x6x謃-*1Hck fr tΟVs.g>\䃧ԐɎ7{H)^k'U fwHk?' "EKU;szEv:'#W>P@ٱ(x?޻0<5o=.u)sB6P7-fOTR R`۽G_ĭ}m=`E)Կ:v$/d*le]u+ n:{O!DtQc(0cofGc)nm,ܞc{EAgpQMJX 5u#kBA,߯$@{2XWkZ- j͈/"zQz!@3aYX[2Bo~5WZqV; :?}!fɗT yoy{j R(׶(GBAiӶQ6o1<&~dn]=*}Zщb`P\i1x*k-!TvpEBSPsȏ ȹpSdh'F~a&]x7|ND㷾oZ3AiЀ7 hG GT@4xAgbMl\<5#1h5ʐi+Dpj~$T'RbYY? X6@u-z:#D?dV9d0"~C+U&PlJVn$[J &&4I I4ؐ0uW%Q~ pf_D[CuO^Zaf#f+ٌMj@#u" SK;-a;#E @09r9-2@xu GW^[w:@"_f А:?z$q@N&d 0̸ nA9 M j++|v~7Oʧ=_~_]"[_t>}˷^"ey뷬A @9[+ dY@(OT!jbv @@\qL%2lVh3؀W%xnOk_T| E$|=z[B+ [fM˙̌xBM"ʢ 0 VPRwۃK=l]c7~ް`ѿ[G#*@Z9KL *A2IkT!RLQJiiZz2W "QCHNR'$E` [G6msؒ# x9"2"xT"ĨO5 5ab+ hT|Z RFCBM$yC/[X%ENЩ *<1U@W<)'×dlN># `s1 6ecScbƃ ($ `AZ@=99C䴜3ԜeW1~}2o<2QlGp R2H1,l+blE=g M8".;*%ʜsAPȀfNV6@RAn!ՆPS  mnn^ 2Vc#(9(*LzIJ%>gN1-8Y'8Uc3aSM P(!$B#bb wʀ8#"V0sZ(kD쑎7(b˜ sb z33 3aћ֐&T$` K1PC*)5ܦUGXS23ҧǩ4@ёX`LaT( @apC?D@> K. XI\ÉM٠e{p|l(:ڢ1GSz@4QeΙ6'G?$Fj Z(2ϣBǫPȷ Ӄa p7N#9_|w|>V3C$I٤b2ց #(sK hqI'&X Yl tDH'Mj- 34rE=;K9ȼ 9X;+|Yi9wYd@0&qբ j!m&( [GPK ^U4AT[Łnk xDUUD&$( $ e,B -'O.-]VΪm%"wVx%Ї-nDKJOҀOm +.L ΐ88M#G5T-Q,Ha6E±xu hJxaI !" `ڀ$z1H` "m./)Mdn1;#933`ہlO놙 I-)k؜Ze1"x!Obg8.jݑr`h:8eSRc!Hͨ)IHAA9nhK8!ШO>q*TnP5k51dVCH24lidF<<ڌFQ 6YDjdű(eu1AI/Tzah9˱E37 M8ی @&<}1AZ Nt砜Ⱦɇэ`Қ 5C%1rMPna4@%qNaX( ?^+€i?~H̎K躠\VDĤE_Sb>e<90IfrSW?x@mΘҶSi,$56A.D>|7ݯVA[kb1D#QVы |lXPݖbzUƔh"d x cIGuQ5jʹ#P)ڧQLDir6b嗏JJٷ]oϽӽ=x, Mk@ATh "s/ZBw|s0VWJR]` 0.sf$ 6wE/[ł I0"`QQe`],ùDQ!;քKh/ZB9vDp9.^0W UjI9~q] ioy]z!_+kZdS6ޛ{_S|7AMtη@>VK$^]rxW?+Rӭ()o8˜9ہ:11,\X=$1 *Uo J=[9Y>֘472Rux2H'j&a1RZ y5-/8\\P(mE< Dewl1~, !A  Jɇ냾1)9*UU%^k?ޢ^zg>%81 ٚQtU `a4"@ʎW?y4&[;p?pf%qq1O2BtBRUHL$9#p\\D,Rl_РnT A L *4[HFpEćp0܃Lz ?{X~<+l$Нc %fV8)N.m.޸l ,6f=0x^v~xFpCd1B^k.|,~; 0J# ݍYr8<. ̤`W$I) Тfƣ* 6AKhL1i)0*@9U;An(7+L+.W3LX[jq蛀bDx|1Yh7 0vV # Ks~1"lDlF!0JkVXt ҒͩH@*'5F-@`ěGa3 :?erY0<9$1B3l5IP1%UN eOI H2%RJI؀hBjUuJN%p'3Cs_l`S -^´PtBv#->@l*\7:x ,rrUHW`4*JM{ FA-dR$fT.MEY}ɪ1IÈ&{&> p/-XJ,~?uϹcc2VDhdeђ`V=X7n8qL&"I2i-9Bz}U(dЋ+GW4)8kӥ<ůUۆ"@p6)-M,5,;Aܤ>J'M9#X7- 9dt q,2#NHư|hPP`]r*EEdB]8pq{h{q:5S1|-ι;2DHqHfѼHdΚ8@6r/=EțڴjC0l[wTh !̜9ڜkk 4LXLw&<TUT2:Z}?gPR[ "â!\ּ#O>pTT{?>Bjė0]h9pT!4pMHJf|F~ 0IĐ.! kӵەTd]!7fsks\o >?ߤ@vUuA HhZ"TH!bWcFATMIckHh?uW'p8N^r gGS*7`*ɿ55k3Xg" ѫfdhB)U`F1G2|\|Y> 'ͻ@”#i@2d-rfыdIn9saFƫd:*ľ/#,RQe_ƭ4 & _!p !,Ά҅PgUJ+WRQ56-x+=^_f-"0L@(6\)SLQZ:m?}Q M0_ ff7][ l4.WK}dX}pЇ-`xD ::V@ 0SPuV`AL~~1P)l$gGA^P0H,*W@0B $]Ksf۽}wWf]ٍ̾?f2AN<)RaLRL(7\2"]fp6>K/GLHZ@z$;I-&6lD',ⵢVTj@SSpo%Տޱ^ &HV% 5ϟΩċ^}zOܰQ~'/e`k-!$IxPuʱ,mm6JkJx fF[f AJ!]T'p"݂s,3ȟs>!D NW=זC"R](g/\"b*ȡa0D"[TQ=iX Ҵ&5R( KC*˸K :J4x=QD(a@[/WeI"@@g`..th9dT*oTa:#%遒怜lDe# 8P*L7 >ߣb>}z%@#sCHA!3[8%"w5"w{5EOT1]XSD`b" jY\@%O"8ig zbzU:I (4 2I/x^R##q!0 7MWH̰"1a`(yj4rPSCՠ؃VbwߝzFXehP%YEWX#(aS&Zm~hΞK&+9Ksxx7ς5t䐟u"lطE%\T'KPH܄Q{W؝D7@}8,H=\8YSɼ;hZ vm)(Ff 3WRD(sP*DX0Ux y\ |=l? !,e gʳu`$/D`k Gx`m)P+l!c >ͳu ,vXDzYΒ| `^UU5_ 3_ACV=HAN7TWV 5NocGhg!޼0 ',`^q$U̟i6oܔϱFvwQҔJ!2v\Pf׍6J])\/bP[Vhԍ=t.{ʽg] ׵7kVBS6kw (# ڪH=H *:tn ʮqQ){LxEĤx^V%ѾZ) jnFt0+Y|}3$+x˃ikV5[[ˋYTjp;-э] Y_ vݹXY4^OzƏ*6F2)uEl˅z<3ͩJ/. l+/th Vch\ld+j>].,eeu`pҘU=Z+ T|ĮQU; S>%OW+Fb}Y:%F{)l6!!m6-gγ` P@)C2\֔r%.15jm ף̇S?hn:H-{n ُRi(rX(aVŭ3TPڼUeB by<5]|A(`9.rTaJ-˫rJP),Upɻ\ s 6Ubb(C+?xLɉOU ㄩHnNW3D sJ}6B /ѷ6qri ^\do\VDmv!׫*6@>D*%VhQS5僢Au%Rfgv|&^&֠̅-licA%Pa:Q2 qPK^f1FF] w])VSe^Z,/y3)JyYb\?y*D$f|4$I8*܊"b 3דm9}s<4Sqjyiz<]JV׊y+(R=2iYV^ _g|!޸PA%cVE RMRQKZP嚑EZxuD GsNPۋ$_ʣ~n]xTO2LT06:2%NC5!mry% b*tOYDHlT.En]P~{#/u|5[_ @BN$A6$r,j*D,:jA#J=PԲ&g9:#B?hᩃOuԛL!t h) b;U8(d@uY ) Y-QGRQYB;i5OlHFvoy ˮ,-_eޣTrO1mXU2t'`kL,Qmr/]J;2+   cœlIDl d{v'qUV1|6I`2v1X̵̏bq<"RqX| 8Ig?thv6H/vjۮ _.yJ~,-D-Aw Qҽ~)(\JtV1I.Qb"Y =/[_ 8CPfanٶ_C` 3p69`)Vapm*(N 6F#Ձp(ŭJۮ5 "zlcYN?u%4\u2LK "O `IC y(&vntcuh0eRvдߑ<YjYt ecBJF#It5ĞK}Z\&\#o} ߩ&7d,EUdY ܪgu~,V1ΐzR_zel  &Bɯ*8mA~u>>>(F)n`~=v "T,Y;3]8ؘ` HA,c&h Lhύӹ'ZucS56E&Ҡ1x,*t)@g 萁nGW<%mNoLX4P%S*R)ZJK#{@Pa [pbi%^ktom.PI|3 Ujy_hI`ގV<xFn""YLdӘ !4^+j@f[ffRfW":\(׀esS& |4 %Piz kxWp fY,Y5~}-M9LýG#uP7٪m2@"pJ&DFHwKB 04_v.}etM 5E#NJR^ƻʔ>p6&~ +-Q v,(75Br|h)d|P-ؼ8eEȤ$V`+jdf'bH ȼ'xB@,C n SAHÖ<&JZ 9guiOv膡ݧR~S^)30homHeaO/2'Q4rJ,2&>jkDH(fN@p%pSV<DY"!ЉT0.[ )m<kh[%vJn)NYa2 @h"O`pA"d$X)&o !ݘup" U  Ir4q>cyGQX- 0>ֳW{ΛK P9JN56J)@å(&l.d\ opַGĚb3n(vX$S0.J;H@]bMCaT/X͖[GK'V.PB$b0\ g`@r\voʾ3l d𲜂)p,uM#^c1{#a'L`b*@ #_T̀":Nj/` t8ЖȷY1`  `aÔN{:G4g:s&j))lI ZE) GP*rM=W#5]DN6}H$y7ȿ\!wB'lYIuYɝ?SԃUƔ= kTM,elօ*e.Q@9=M7Fx!ƃPh+:1kuxYm>Uඣ&h_Y$j?W`t<)D2~nb>&1_3(J˼Y3xXC.*J=Qr,2R"dơ3L]WqZ\XEYBE"|Fm OdSW#? 6ANBHZPEX{^RY7'th,GŪ.ZUZbD?;u*nkX' FU5Cf,%7B^v[lrh#r!{uŀN澯~9P^ FC}lekzlͳEfs F:& BhB 9&Bs5st4YS$< ; "2rAo| T'?isř;7xf0 ▕OGq ^~@ٯ]RwƆBT$FD Yj{"Pǫ_Գx~wfU,P î5X.j^Nz^N g#qQ X%?:OŨRfdI06%zTO7ί!{H:(fY  PdbA]}|#Ĥ. JM= r۔PY";؂o_@_4xH##$jw+}8X.}_Ç?/F"9^ A2SԩHHu 4*+]G~ 35L2Sp3c깴i\7ҮUĨJPt_9.2(7 /Gi%t(\>8/A"1zPh(̡|aD&lH[Em aG#IL{wMnՄNv|\v|ƍH>NRPyHÏnmQB@Y3g=OiɝØ jZaB$`D:y總_}@ fT'/w"Dm|a J8Z&*]9SՎ;U aMrLǡs"CMx "UVf(%TdN:n ܅mXMu TRpl#E@wS5@[ph6KC*V^>@9(*GFcQ$Dikz `K0m~A%@SukoRV.mAԀPkBEZUxpWm8?#mcX4vNߵxx=,֞}5_? y5q CH"b#c*uƼ%)&K]vLg9V%8n ~$>]wl]3V5?zSb>EF$  US,NzWK|!ȊN O AcU6|왚D Z2*5H#ؒݬޔ.|EZT Y٢!v];J)X${Jۚ©̴Is/O}=*2\' % xڈ]V Y,@'H-)ϒ7e@BTݟDJ܇I\3>x'y aN/EMi1{HWTnXa̐/- G6:v#'_︃BU;DX7(khh/%"땋>eˉcq1=( ISR4 U](`|Pu< v>Xh )qUs[$k M͐ΚĨ% p!]D[H\SN$)ZW2@X  vEO58G'/ ^`H^2) &MtpkfdGUgC"OzLbO : .AƧq[`Pv͛mhzQѾu<eu>K @r^޽yxAD r{/C䃨Bp|S*?覆!IqqjfrP3pQCP) ,RH1\0=9c(J;@k`Bبr(^6~d+iDp.cx/|nja:(&`A :hذ8B#Y\WS2Z .~3tlO.^aO+gmV/־M\ .cbOU0䣒D63 !j b },@M2^^0a@D$DČ!mҳjʤUD7HTmo=G;0v`7S7{ ~QTS Z?I`0c Zn$TQ0FFkJt- O,T&_bePɢtYqwb'W`S 44t[xF;'q g g,:U] 7mܭJf((`xBIdD$45ʥVh)FNͧ;3,++Q`$ ʵ]Rt"K9ϰ+>̾Vq'ȥcb1ֈi!&aLs[']fg%(B@f#?y@:;"q -.KUXmgub8P,rey6)=S{E\@{ C J9KEUAkEơA1DOHa6h0 :3' nTigѝ4Hlj&0@ÒQ*%SF^irp*UPRtE\3c4-X\6=ݨMbbI7ɚNT0ἔ-^g)a:ؤ͘"K&bm3n eH'ϣlcfFq 0vi CuCC#6]tVZ,'Puh1ǕހE4M҂} =7 nkRFLhyꏉJ*E $d d]Q2dHi" z,#Q=)H011i!)2g^Ёj11J#Fp @5 y @ ?z+ (M,)JH $|^$O!R@,klBpݼ Ķ#SeEfݐϨ\SyYJF@{i&$8Ȇ"|8?*n5:J=9,Nuw6VG{y(59R8 '8ovp@P+k8 S>[k1FRXa-魃L@m g4p;AnɎ͋Ey./SuY8 6'_x+*[?A\_؋/0.@&5$JB 8'S)H  b/F3t0,nz ,l=؃1(B$p\ ,qy^\^P-K*Hk"MBzL8R)ׅY^gs(8i0_}h- P`Tyx \(;eJ9(E9N._<}#,\,`^d=Vʁ*][cisELaXfS`6wͲo@ӡG u<%Q-E* )PSHw6`7q@;]{#[~=,-j $\䑞3LStCvh\f#4ՀK1HCEY]w13{}s-! iԙ )rRZRٞPwH R e*tlقb*Ěhf1٩T4%?0~MCwo5@-8"M~aზU3*nj3Op.&0DPuxy9 *:2aFék'>7u9Rp8=AA"D,L6XDhWJ4ml~vKv!h4C {JӚ>,q;z()Zٵ"sJQdi~4k`!}([W ! hOr(@QPQBAEB`HwVac7D FqL:.pLxITEn@.6\i%&ӠS ""֧pޠp! Eu6sk0*mN{+~a߂.@EЄ*pߘPU `%IrĔuigUY3(kKc v7u" @;7I`Lcg+(5T^ @7: G41L:ZWJHB% h@1ҭ1Xnun$q,rL+B^F|r0"8 a,8ِ+nzDJh4 87("n@*T:v:p:t4VwR|*rm1tOg6S1Z`5ꪬLjY1[4oz}sD3Ȉ{I 3Hm?j{+{)`"J٬`t-0f jZ:ѷ q⎉l-8XMN.R=7!\-(/v!5!qDe' fu@Hb^lyk:c3]!G)CȁSpI]R dDZia 5ﺄpxjh)"P[ 49V M3M׈|ȳ` -.Cʐ]O/\fK90ˤ97z >h#9y -<%h!9x : W4sցN°oBN5W6zՐ"TI6L{{l8w;JP2< YyV8o'E3#/RA6]<9R 7~F /qp/sRF& CXuK11Yb484et#-``Dux;Fj;B2MsĢzű.pb/Ͻ lv`a9v8=~Hͥ0<ԨÁamdJ ƎJieXvl4./nܳtnS*IGi160 kR .XnYbm!vW Ych&AwO~i@x"^A)Q|Jqmfd$R MXD(dd8˓O> E/ʦfx7W!Nz>^,Sϓi r< m "Zxz 3o"i4voPWh}thQ.: ,""3X]P+4c3&hoTY9/{~2} ǰ㔪<%2GSWc/8s)[_])9~]>)%VL)0w$?%]~'rnYsЙp {x{<3 J'$2x[ H o{v_􉿷O:ߓ<߄y"LϪ!Dw>h PU1 In^ SZF<^.}Hb583<0 |x}Nx1$1ADD䖩D(6Y'FyP=U-U p 2A ?5.`S!Ǹ\VUR XW rƥsኾ{NJG 58D76 Qx"g_a}vbΘ`c7pSelBD~ QB + vx=.Gl9$ލARâupIZa\\$&E Յ[J;vo~@%YlCAaZ5B(8FpKՀH$Y3*OE2n(nvR;&Q;>xrYΩg|bF=[walWQ3Ն800,r/_.o1?I K 8:4Ou$B| )Td/Or(Ab?&& d˾9ɇC#1&2!DR&F IɀsRq"c`W9v*{+r- x*MS<1)g+` 6sF6JDRIlSːEUU J˳)>~?J3uaw}`{qs |pG!= \|b~u3\Ad*g`S.D?\XGpzl)L3&uuPȀ h 0:5p>/>ISr8+)+ZebL]Q T;*I'J"W+1ifYOsíD\RV w(E{cպwPl7kL`F,gTN> cx&5x6nS.#Hdr%NS %f ī_s|OF F`^7}CIwk e;@ȧ3^C*;$/rYK 7t_O1 -z<DE 4(!%ĮT'gq-"|qCP!Q uNO=UyN;cQ ,x୦ݛxR9! 足v3;S P}GUǴcsdj.[3U2-@7lE%5NjԔP, $XFUUJ(ڳ(hU[e*n,9c/h{1 v 2SXNrhxs~T_C*`@`I $Bf6 $`(e$iTСTv#sed;)X6`{OOGn}QI\b$ ZMW6J,+BPv!}LJ-p<{5_~==3>8fba=EC>YC0Nڰ6ewg=jqT[;şv3`ܔ N.%[) :Af(am-w9KUjZְF;r!ަ\cpʂo*/DiF%8$/v&7(lL!Eg?HL0"y{FnE؀bP&ނӂ$(51G?,l:ڜuy;J]*9uy _1. ŭ+B{bs`ax]M7z'Le>z8a6^m-%`.% C6>[c[^!WPˡ/ -9[41AqC 3`J w)0'zjL4C5AC4ŁBn6Au:׺6bA~JI\N}z7"KO`NP׫ DI;"\0.Q pI'oYPP"$̵R( j8ȀdX>-KwCe+,%?L/#z <"e#^Y'&~j@cy/?4vu%l+V$:8 >߀ ./lѳ޷Xb]`teǜv` PaL-{DGc_S5Q ԩ A)ߍJvtls٘8Lq5:p~{ڡN S[ќ D)O@xY!y^*Nqt J \ vBZ36uvZg>R=uPyEES 1!b"`)0Ԫf/^( e#}Qu- uGowgqh͡^._,BlqPdL )T *|1㲅1k1YĤ. >WaXN\[ Kh'y[\]b'5$5#\USHhX]d׉:BdY5\hs,mi%ʟ=?Z)D޵["'OξVQM^0/p/wlƖΙI)9ղV].`1<}Lk )[<#ƀ|Dr#~1@WwQeh곐ȳnd(Vtt"pl.%)p~Q6!mq(KYePT' X4C(Rlν ra gPEWGCƴ+܅ӮyԌAaj4Z @JB]F+#a0р_n9vЎ[m8(f JSgZ$99[휁O{k lX"f{rLށ!Q -D *%7 ,v ەҙLʋJ@aģ8.řNؼ$Lz wE<&d& @VVf*Tv~d)ќ '8dς[7 43Hx^6}@b_J%%/(GX!todtIL8- $8' 2(=up$p&B_.'|'!HtC82f# $3m%p ct7=uSg| c9ˉ Qfզs{ ]͠0S*@l^0^r'p]Ԕ dL)*,{mtx +-;tl\r/(DpZ m;]JXbęC~Xi-fPGJ9M*78 a0G[s܄п+7< ʒp,fȡ.@SWgMDot8F/NK nx(?vRصP{ʚSS93F06%*$˛lN#cEA³.y!Gv/ }Q;$N 1 ?z*n8ol~PDbK+[L#&:vd z+@BptD8Vy!_!MyPEWi'P4/@J)S ᕮQ<2R(Ȋ*h{ j{TbdxH$@tvSj( 2X Qf @ 511 @vTb 4,}4$IvBx [P.!j]H;j.%Ѓ 8bi43SIB&@atT_V$ȨKVr K98Fm~(u6eYzωԴC!Pe<(! =9S׶āT%NL1{x " g[1$A0W4g&SQUV\bkbzq NYStGg{{T7Pdۄ(E䖱(m@d .QHvA 64LۀB C 34 R D4X70&$TK&Ƀ$^V07h~S2w֎5%X&,mD=H+1 04-8!;t" HODe">q@,1w {\'2&@$!OOHSLRZhA vL+&$FpHDӅLQm=F}.0G5cڤL:-om$u'&fZJ @Kt=D'#7XHfhBer~\ RLJ `Ӏ?]]*30SL8ŇW9n4Ni s9%؋԰JFD\bڮ 4nNIrT^앱H!5XU02;\O58H Kd8eAB=58k aq gQ-vZpr-Uj0 }35J (6DtԔib8%z!bS @Ȝ.y'g@90ha4 RLϺ_GI|r\.4qR 8~l @.?2V 'GEl<_,Zz^4>ee&c6 "v9|hhm0 Pjlci0F*i3li 'ba%R EOdaWv,CaܻVog :F#w=t@n! lVF*RNf WZmqJC׶+f`Vl'ͬ -W0>t[=C=YBWq b <@g62Fx6 2ѦT?QDN+ 85n3 #  *`KhX 'BshO0M+plhQn D;[U7H'""܇(NQqr+ nh©2T(R K$ eۘtGO 6̲iy̌q_կQ'dH#6%CHBQc-`]Wa;pEiHy"tvrTZBk|g ޢӎELXPK]7 م-dgѸ0#XOo3[|wĴJ9ךx羻RFa^*yR}r*?E a!sDtľ 2M@# hCNQ6䦶GG}]hfR8ƨVZp^X0ZWş~Gsa!CiƵ>6bӔ-'N' @,i[ً-o  4KcFzuzb`s%&I"`m0X԰ c0 "QEm{H\3 f,`P0'EvN_6ĦiSu56x@>/K| Ru)Kw<@XՓZBc_5~o` ` f! fF82d MsWf4rhY"'辔ʺ"!A 70϶=QMP %A>^"˒os S5|7 @;riPA`鎁Y HKᄐ3(G'spiHuX F K E X*+M_v#v:OiMX Fb?@2ZpʽT_kpL4 ccI,RB4Y 9\ )^%bˁ %=U ۛڅhҁx2^h@A|*:xC1p]z΃ (E~ -'C ~sH(R3a; gxqsO3 *4 v[bS{Z7J~ UFbhr1Zc'dD.xRo@fW92K J$Ș[Q(`13:?h jEoBrw5.JXgC*07\A ^7N2]w9! *,dƦs3e,_DﻥXFzPyʼ { x/jMJG*BXTpeUHqglZE&mG yYΊoxb{3waч*qxH)[VVZcӇoݯ?9p`588eBUι9@]W%p`ŮC GTgT OZU^:]C!5d0S *tc0Ȳ&&Ad$_{Vb{9р*`,|)Qm8D샒i; ]Nv2ELppaoq3n PB02u{=d $"yAid ,diwyˆrm2qʤAH֦Xb+j+V RWwd1qƕ,0Mf5N |g["z x3"!FBcoE垶r]kJ" 3HBDTz`܀@qN6XAEȰfR6x(lJDɦZ&sb8sf Xg/F4C8/Ť7 m@2OUZw@|q71S(^V`4𫰸> tbf'sKPZV!@hgbK)r̷.߇~ {sF\w9Is23ÔތK^Ӭٷ2cְR2AU+{G̰HlR= q8P2_5C8>PqN͟3pUS":R_aj RKWD HBxA#s;9ivKw F,m6( ق |NbJUuo"6w!vq-Yܨ+I$%$ub3Rb׭h8wֲM u/5=r{_>֦G,D\B "seչ!>ܐ]VYa ЁgZvI&L0SG 0`M$2ϩ46v;D+3O;G5*TɅs󑶾%Ə%NtodCXW grpn5h†0$J28 |FO| '\  4 3O7pڽMM%EwAm&qwC}]0Ѳp Sl 1(p[\5L@5 c*0 ,6"f}7KUIv"p:A;7c7[qTaHB*`-n>i`aI,oFu212°.S]zA |[z@'%`/nTf'@$A|C):.zsykepn)CU𰑎 1$Z gD?NJxZ<8rMБreф4noQ&`'LLe.R#44QXB p\*%b΄FGTL[ U`yH'O*\za+nh4$r#@E(c0eg1-GehC؍X; 6eNv3dfYPeFsBKNL^?>k\]0 g'Eft}b6t0: 'VҔb# p&*Ics&=6XJF4͉w1Mx(,l0෸XjPo0FP! +SA vّҚIswB,xo$^>?z}姏Y"[LѴL=jBhlN.J .R2qDkF%`Mf3%EW>\2 ?Ov `%b S>}X$Η@S"LvmJe`n6-s26xYVn+lm4Pe|SeX{'Z^^ twŢ90}5Sh-n@625;Xင g-W.ʽ4l'Ҵ*$x?NzojE xYz0kBll# S"0HHvԄ$ pjg *oQx8OƱVD(WC%Jj0p`(Q+ 059 _8ww}h/ I_nzCfM twW`+}$("i@ tp='vhG5GeqC$PSoeyQv:"I#@D+Ƴ2FC+r$O NSQB5.I"/1$P1bh_NL#?ش0%1DyҺ;-&@0fA'1#OV^aTVqȚ#8]XQŨ9;`Nxw*Uk/1 *Xnu&GL.3j\b͓}C?jﮔ.(_YEEf]sˆ俕 .Iu:ER;.f Ԋ"/fރlp9ܺxx?xwSg Cw oL3F._o*-`-ԃ7l(;|vawI %S~@/Ɏa+Y"7~h+ǶBùg:.X&na6@KaEbUHKII{! Q}@^Iҩ,kD4AHKhg,M'!+{(#$DPXF;*5YM9I|r09 @;<.cs9&QrxH\Fg9WCϠ:Fq0}flKXCxP/ywԉݟ'D \fpۘ=oޒ d hXO#"4Fe*V/QQ}=2{ɑC!ċG\]1WQA؛xB鵢]@l,I5)T^*d%Z.p(w!ެs\&(.Ev,L")e+< 6xky;f eڙMpKL"8A! 5UAm ;IB8#)'g3g]2WD3M޲l}dUDfLč Sp;с4v!D(B*mjwЁ6 ρ9)&CvE(W')CA6Z?{<ҙB9  F DJ=JE٢QPJ1Sf#fZ'N2nʁ.o^*x #不Tr)yrh7CiU |-s|v>7؂o8p0+Rmݦ;D lf KQyeD Mdrl){bm_}}m&45͌ (5Bd˰Нj^# ڃuC [+(mk'@c㮊\4W:xV-a&ŷA w&l@xڡ>$ 9FD2,֝+ T 8e$B Q +1~DD:79ĠRE $:KhYp (D& 0%5ʦOxε.j !ߑ[(G;>~),Np ˋ+Q?٦ ~!qVb{n,^D>5#e40HDl)\VlۦP\k]`PmDIc\wr3/yŠf^SK`=!DE*N,@wUAFDkZ0V3l:"(Ih\3p<RT41*iUmm]:Uy`98,]iLjY$tr{^)*\(U= + PQl@@ ,fSĂؠ[iU:Mqw;t^\N3bNڳ 0H8!) #@aiNE:rj0L(U=CZWnuZx^,B LSӑs"@udwXUf&^E l&S>?ceS~W~ˢG46V ZDx6<\J Os]GˎF` 0%*p@E\DECDblU^z~'^&m~NJ P8)!( zpG;xs CjJ&hˆ dC:r 0@s IM, juQ fQ9/: hBzt%>~J~-G3, GժsUwP+` HK@DNeMB`nMNr9}Cn]xQ̍ $. ˆ%s-ova E9naH0sMJ*WmH)K*Mo0񐝔sE@2Co)_j@;(cHZ(l C@)/D۽hQH^!F}]^n@nn띞j{SPr^r xmK}3bH)X-P#ۂdg4RuWԻ]'ӝ{ m%aZUsqr丘k'b$bGRnwd7Γsy떳۹Rbe?ard܇DFHa?IH[c l mA{ʇ2N,٫ H4+g+z392v迁 B`+06laώ(Rʀ@ lȖJIQt#a3R:U怀̀0C;FedL3fg)[ TI^136 Iܒ+l!lzV2 ?^Ž3Y]x/7R{~%Pq[o}?[gρ|$O*t&@ vfkNڞ`ngy$oKC% 8yJE W%*^!]su5pА˂͏WQk*]RyPh[ ,maظ0EEW0yL)эa< P , U-}mwo_{ӛ{~ZoBgcwzR V8zX{ aA=![H10 ']\ U^в{=K?e ?rFg>;.BN"C墰Z)\mT/؛}Ӿ<8QD:Qm9 O~pJLGg 2xpJ=R>`V3,Ʊ! f W[t4mk L@ȑ9@!s) Api#~3+f&k=3z{V 2?nXp&ox;K$xE:_&h-ÛIEq]6qU`V20{ D/TnyN+1.+-yt?5 pE!Ur\'/NVy22'[pk’²t`X @fb200$TdK)%& f@`n~5;HaC8 ߥ~>\PU[t2d#Dg+{~gL8} =YxP)8'8~= BZ`!Fgyu;b.ASWwiX"P sYx%/% ʑH(CdD`$m<'hgq'a%P ߈&̢!KIS+XY]G_30hGCNAf}s|x lXG<8b|ĺAA7[9&@"ԝ>}YP@(t:]H9K2 bt2aQHivUA0?[8$ En:/֡o&P+D[jNb$f(k`3B$4"ܱCr %1A^HIuKXz9bTSkpxxxX[ a CÑ%ּY>4}><Ӗ,F "(ۈ|H@$܄ ( DrネA g+ }s`|!3zr 71VY4?7'Giz y,0[!%`Z {WTlBՈ 袲ݲ K}s\4խv#ZSU"z`y*w]b#|Y| [{ uD1"QJEA4OK&W@  XxVũ`I\[ӏ{ RHA&LJwϐc'J`~)j7/K A X$xzi"33*%e50;# UVk.;k5צ7?5Ӿ퍻cHI2AZkYDi&A ^ËNPuH.`t*o(/ 3* eCY PS+SG cnlӨ-3U*lۦl[;9wG!35C.&)x*)ML 3r1a 3!T2 "xG ! [ހ64Q"c ,$%lC,IxY7x+䀥{4iD輷'6N*݂9 N$Q"*21[cJBj[d )=2HF 0C@,[Sviy2FXj>| ¸g/UѯXlp`'\(RҶ] bv P!td|7YV@U%6*QY -26yp|3BmV:M.Dj5 XgXh,!V^m'$1c#l}͌02mJhoۻ]HBʆ%;V~wG7r`@_s.lCd.@1$`ȎQD^c-&Zɇ3?)> ܓC(yEX"Z tABnA& p# p[9ũoz@e y fT,0\$\# W /q! Nۑw&uiAWp,N"?xrU:S*%ͺX?imHl62pP0 fU#Fla 8|.hXHE؁Nc:#D41K~҅ߢa]in3σ@ UI)]쯂~F5%a AO޼ AQBt5`f#R-_ _(ኃ$,l/+Ez'mQ%@@F ("b@,@HgKb큽,ľ;ޑ0EWHJu{"QjI)IRNL̜iͫn% sFBp|4( ΃mnr6@VQxx!d]~,uQzd@K 5g[K.8eKeQ#((0 !|Z;ۃBθ7?xSfw2+βg|er1ř5"DðF.ǠiBXC"R{/ߠt0]xW /gOw?eOW1bn.Elxtr$}P8|ÝNGRG ~C"CJo0[.f0 S~EBI+*HQ_+4w*?34D # oWވ[ J`spXeQAEĀ1dCb6\\F|xAeXcvPDkLP@oC+Դ!FZ}o7^S^~7Hx0dgQ`80ԩ&r." 61a|% 1XNF) d(q0k/h{ /Xޭ͒oFx8(@]D0H ,4@$V)7@fiVCaV/Jen,:BC5 Y„wpi_{5^҈/7jFp))3b5qpXm4rLLCw $AAB9^Z@@# &@{g岸'[%y!)/ly4 (C8"`|"73`c(dFh c6Rdj6F'k7w@ qK1t.GWBfFrOCljc -'h'J*Ϫsi{7'sUw_." +%EE #º"Qd\4` 1D`!Z  Ryxg\EC (%RؒN+Y&oʏF ſ`w+:n^D"pnF-%H\$2`t*6U4 |F]ǣ`IQy=\V=up~PDF @ J |tAgހ11G T$c3œlվ| W/ĊwTO_#;7O XYLVkm&V1Pbip޴Pj F- Bs~N_Ðzɓ^ r@|d D@ v2b\\d׀|=9DG֐f(HFX|/ `~qr twH $B ΁MW6ṍgB  $  ƒ A@/c?n]lf3)~.li[(^()I,!蘑_1 )ɀDM#_A<)տ/ @$F#QVJCʻ-fl X֍z(r} e?/kWYH 3Q@@օ`Bg &EbE&Fmw!x$P% $MzR 4' HQe+ Q`VŜ*9fWPT'*eW: >Tp{?Y;۟HTZ\,/1柽E:0h# |FМr x" NY $tOHL6GS"n4`1 BɊujI E  A_#X{g%}P)J- B*#. `kԹ|cN_J(v2A}3DdžT, Q3G _Z"]!H4'JVc'ʎ(-`$xL0#Փ0J^ܺ/k9XPq" e5"#(&a1rK@*59'^izOw }.0Ξ},,)/g0mz."J5! $byxq,O^qX>* ^~V?jՋսՂ"!*b   c0@"!i! XC.'v7Gӿ;>9:Bب $Tb{^S"xGty1\ۋYpIrh^!^zDPF "Q\b~K@_%Qx@I7H7cR xq8 x'^ 1q>05bO8 @gfɊKyp ڨE*g BP $bCD}#'#Nemp_+ C  +% (q1`bǰJP X8HGY@$xSNBRt G N&JSPeY!  IHl|CK`O_D""@@ Kv<0~":QKr#c/0״g:Ca(Ȣ2*K 2  (O[:hCќNvYI  @!a\t9;}v snCzQ<27y3c򷼛x.V@Tet@VDC$D"APTUQc@D$P (`x7 .EOoSqԍ ܧB/AJD$`#L@5Sr$6l6e$+a$ R(x! `@D@0zhW|h!|C #ym( A A䈨MZY_a&l1(nD iBa@""KD;b5c wa.n/xq"Ӏ  *=w Ϛ%nӼu,.5.Ž%]d!q14#K+Tl؊ķ ax9e+8.:Xf$TȤx~$O}Z[9^w|׃'X?0#?p) #T>O@T[! $l-|yOh"o;ow8gnƢjt-@H P$dE>Z+ +"s<ݚIEJd:ъWynQOG .I{ܜ ,+|߼pRn]sJ"%'vzGa¯§;*"k+"0`-B@VI-/9_~;n,瀏OQPY<ȹD#K0|DZ[= ;>|h#  Kw8=ZV$KU>@y|@[* ;Ǵ7Twg4VX 1'v,1}{W*gD~"i|q1f" .ʭ|K\ c/q4o??dGD[~pWݲ^-k&R3ݕI%,Azyw7%$+w,? 7s}6qoNXp싼mg͍$#b(_DÂ? ϟ+?q(ciYvE| ėbcx5~;'T *j7n|>|' n?e01<_gxv #Kzl/>@xv>allegro5-5.2.10.1/examples/data/mysha_dxt1.dds000066400000000000000000000766001473414355200207750ustar00rootroot00000000000000DDS | @} DXT1@9!A1]9!9!*91A199IjA1__9!*(((A1_9H19H1hA1_A1A1H92A1A1A191*99jZ99YZ99ijA191A1A1A199Zj99Z99ZA1׈A1A199jVA19!A1A199A1A1A1_A1ׇ9991$A191&hA1)9VUBH1G9 2hA1}}hA1wH91?91꫈9h) (H19  91:H1_81_UW81}:H1}}UU:H1]11VZ11101110G1I1 G)H9G1I11(1'1G1I1 G1I1G!G1UUVUG)G1UUG)G1QUAUG1EA1A1WA1}91ꪪA1W9H1A199jA1A199A1A199999999%99jjj91*99j99Z*99P99Z9999A19999j99@99e99A199ZA199A199j9999ej99jH99UUPUA19999j9!*(99A1׈A1A1A1A1_A1}9G1A1BH1_:H191H19*91:H1_:H1__:H1]:H1_:H1U_H11 11111111j111111i1111G1I1*G1I11(G!G1ZUUUF!G1iUeg1)A1WA1}A1]A19!A1A1__999 999ZZA1A1A1A1}A19999ji999 999jji9199Z9991A199999991*99je99*I:9UU99j99j9999Z99A199U9999j99iA199jj99Z99A1H9299H99UUTUA1A1A199j9h)1H99! A1W}]_H929H1iU9H1:H1_:H19181U}10 :G1_1110111'1H19 G111111G1I1 G1I1 ( G1I11(F!G1UiH92A1A1A19!99A199Z99jZ99jA19 99999999999jjj99I9999iUU999 9*I99I:9UWUu9 999VI:9]UWU99Zj99Ui99jeA19 9*9 9*I199fU9999j9999i99i99Z99jji99ZYY99j99jZfj999999H9299H92 99 H99UUUhA1~9!9H1H92919H1j 9191ꪮ91 :G1}:H1u :G1U:H1wU:H1U:H1__u10:H1uU111'111ZG1I110*G1I1 10G1I1*G1I1 G)G1UUU99A1A199@9999Z9 9*99V99ZZ99jj99999999@A1?9999H991A99ijj99@IB9WUUI:9u}U]99*9 : A9UVUZI99f9 9HB9UuUwI:9UWU]A19 999A!99*A!99I199ifi99Ah1ωA19999j99jVi99Z99*A1A199*BH19H199UA19h)A199j91 BG19H1Zi9H1f9191:H19181UU91꾪H19"2H1Wu:H1WU10(11G1I1 1111H9G!G1I1*G!G1UUUG1I1G1I19999Z9 999eYY99V99jI:9UUU99VZ99i9999Z99VV99999 9**9h99 99h9IB9UUU9 9I999 99 9I999 9*9 :9 9*9 9*9h9A9UՕ9h9A1A9UUuGA! H999999i99I99I999999*99iZ99Z9I99A1?99f999999ZA199jH92*H99TUUUA1A1)9YUZUH99UTUU9H1ZH92*9191:H1:H1W81UU2H1_81WU:H1Uר9H1Z:H1]UuU10* :H1}U_U10*(G)H91111F)I9G1I1("*G1I1 (I:9UUW9 99 999eii9h999ji99jYi9h9ωA19 9**9 99999UI99j9h9?H99jUI9U][99VZ9 : "(IB9U_9 9 *9 9(H99VYhA9Ue99 A9}UA9YUYH99ZA9I9U{UA9UA9UUiVA99BA9uUU9B 99H1AI991AA199ZZ9999YZ9I999999V99A19I9999fj99jH99UUUP99jH99UQUUA1A1H92*A1A1_91ꪮH92:H1_91H199181U2H1}U10 10*G19* 119H1UQUU1111H9G!*11jG1I1A1I:9_UU]I99j99*I:9UUWA!99**A199Vef99UVIB9UU}WAh1I19h9ω9:JB9WU9 999 A9I9YU_HB9}IB9W}_JB9U}HB9WA9]UUHB9WW9 BGB9WuwA9u}A9iU BH9 BH9H99HB9]W}9h9HB9}__9B IB9]U]9 BA9U]U9J 9i91Aj99*A1?I199iVj99Z99e9999999999ej99jA199jj99ZA19! A1A1A191gA191919("2H191:H1w:H1UWW9111U10*1111 11:H1UUU_G1I199PI99ijV9 1*9 9I99jI99IB9UW}UI99I:9uUU99*"99*I99H99A9UEU|IB9U_ A9U_9 BH99ZHB9UJB9UH99YA9YHA :HJ9wA9( BI9AH:A9KJ9WAhAJR9AKJ 9I**AI:*A B*9I A9AH:  BH9HB9UUA9U\}A9YUVH999UU%9UU h1Ur9UU^9H199V99U99999199f99jA1A199A1H99UUUA1_9H1A1_91몪 BG1}H19:H1W1H9i9119*(81UU :G1:H1Uu__11H11U:H1UWU1111 :G1UuUu109i9I:9]UUA9UYeH999J9 9*9h939 9I:9UuUu99"HB9UWw9TU9UU9UU9U9 A9WW9IA *HB9_9HA "A9UAJ:*I9AUV9Ij9IJR9�RAU^RAs+JU s9s92 BWt+JUUs9s9_cAuZAURAUWKJ9z BH9*AKJ)AI: ƈ9UU9 ЋQr1^xKB'19999A199V99Ziև99jH99AU99jZ19UUQW9!(A1BH11H9Z919H191믪1H9jBH1]9H1Z912H1_19 9111H11AEH11D2H1_W10 1110H9G!9 9 I:9UUW]I99j99KB9UU_I9999*I99JB9UU9@T9PUUU    AUUU9HA :J9Ub BH19IjA@APTUAUUUAUUU JU|WT:okUsUz՜U{UWUZUZU9{{WؽokUwZU*BW*JU{A_AU5ԤZR{R_1ЃeRӔ]r1^XpA19999ijV99ZU9999)9U99A19H1)9UUU1G99g)( H19 :G1_:H1_91꾪91꺯:H1}:H1U__11111111 :G1UU}U10" 109G1UQUU9999H9999**9h9?9h9?99*(*H99Z9@@9TUUU      AU95% ؽj*Vh1W\9@IPUUU    Z[*j]}[ޛUޛUTPPzοZUZ_ZصZ ZΗꪨ6_z2Wꠠ6Ћz{RЃ {***.RREQEokJ ӌ9UWV\Q9UWUW9999H99UP__A1W99A1hA1A1]1G981uUU]G19*19(H1981]]:H1WWW1111jji10**10H191(1?1111I99iH99j9999 *99UiU9i9HB9W_999@@PP        ෭^TPPꪗԤxxjҌ      UU窪\ꪪ[]*Z^zYZ6x~*ГxXNzϋsz`σ{ -QRr2?r9Xpp`H991A9H19h) 9H1 9191:H1__]H19 81WUU_H11U:H1UWH11UE11i2H1U10**H11:H1UWUW10*:H1UWUW11fH99H99H99Z99ei9 :I99jZ9h93H99ZZ9PPPP        UUU޸uw@TTU       ~iZ޿]]窪**?]_]Z֪Y֪JƨપŪZZΗuؽZחդ``xЋx|^V.cZЃ>-R߿RR(Ћ꯫JS%9999*9h)9g)*9H1 H919g)誀91:H1U81_H11Q10 (:H1UUu111G1jU1111jU1110*1'19 :( **9 :9B 9 9*I99jZVH99U99(*H:99PPPP         AEEU        uwޯ^֪~Z >WYΪ^Z[__ƾ~ŠWwZΗꪜؽW͋Whh֤WpxxzR7 RUꪫO+pR./ -VU&R ыRZ991AA1uH929!hA1V:H1__gA1mhA1uuH11U@U:H1_9111YYH11UQ10 *111(1?111110(9 :* H:99:*H99iij9: 9:*HB9w׉99PPU9TUUU    AUUQA             ZƬ.ZށiUޛUU@]YﯺZU"[``[Θdl62h~_R(.mN𾷩Q?%ѓ Ԝk99?H99UUU9919@U_99A1A1}uA1W91:H12H19G1j :G1_:H1___11iY:H1_]11ZV1111Z1111j9:*H99eiUA9_uU99fH:9_IB9}}U I9U}WA9WUU    JUUUKJAA             ]]UED]}=jjj^着^X\~o[Θ`rP\Г\Nr&ЋֿN*R/ԤSԤJ9 B?9 B *99jj9 :99H99hA19H1A19191919h) +81W_U:H1}2H1_81_U}}10 2H1W2H1_U:H1U߈10 10*HB9W99jHB9_}99UUAUI:9_H99iZZJB9WA9    *JՔkJ/            מߪ]ޮߪ]ޯ]ުꪪW^֨z{{Θxx|W|XsN{hXЋ{5-{QUЋO jVVkЃ?Nk B_~xKJ99 :**99iji9999A1)9ZVUA1׈A1}A1U:H1_9!1G12H12H1_wH11A@T11着112H1U]10 *2H1HB9}99A9jZHB9UH:9A9VjjI9_W9I *    @@@{+ @            ~߿[מ{WW_^^ֳ[֪_ZκUưUZΗ`pV2hxRhR- {r oWЋ s O|R-/+?/1Z^x-c JW~xKJ99h9̇99j9999A1W9! A1}_:H1uA1uu:H1_:H1_:H1W11꺪11H11UUUE10(1110 2H1wU}U11VA9jA9I1I9uݩI9VWU_AH29I9I    ZΫ ^TTTP      {UEEA    =U^ިTTTTޛEPTUZީؽWZΗ V~U׵,62xP|Ѓ|xX\.sjzσ s)Ћ kV{r R +_Q{Q{zsZ^XRA~A9ZZ999999hA1mU9!9!*A1uA1_ߨ9H19 191:H1]__:H1:H1]H11@Q2H1u_10 10(*H19 A9ZjA9I9mU}HB9A9ZQ9WI9}*BAUUU    U>PPP@     UU:@     ]ު^ƈκ~WZΗj_VؽU*صߖդ:_Ԥ}R8{RsxЃ sbWns bz^* k*b σ s)-ЋRO|S R{{eNk{%%-k B~~xKJ9^9 J99991A/9! 9H19!9g)8A1U]9!91:H1_1H1:H1_10(H11DQUE10(H11EP2H1_9I*"I1Q9w]]I9k_רI9]]_I9~9IJJ9     ߺ޿^@@     ؽƵ- TTTT    ]Ϋ\֪zZZΗVԜVV(zS. 53貼kЃR_ kjXsj{ R kJZ6 k{X`dh{Ѓ_^{jnsPsWUUNskRxxKR19 : 99(99)919UUAWA1_A1}9!A1}]H11UUU:H1߈A1uU])9i11109!*112H1119I*9II1z9I*(9I A1AAj*JAU JUTTT    ]}]ߜ֊ʞޯUUUTP    ٽ +" PPP@    =֪]ZzzZΗ귵xzV-R\R^у .jЃ' R{{ kԮ{ kjx ks kKZ σ kխ+MsЃMsNs ksjjZMk%%AR* 9A)JB9UU99j)9koA19!A1w:H1:H1uH11UUEU9h) :H19!*19:H181U]UH11UAPA2H1WuI1nI19I*Q9IJ9IJ9JAտRA *kRTTTT    >֥UJ]ߜ֢_^ *P@   ؽ[έ@@@@    =՛ߪ"*Z___VzWrxxxz5 _o{WRo{Ѓ^WR{ s/Rs{bxpMsZsbσ k+U-sЃ99A1A1wA1uA1]9H1ZZ911G1j2H19h)*"* 2H1_WH11AQUU:H12H1W119I*A9Q9}_}9I"Q9}9I* A B@KJ9 +kRTTTT    ߪ]%j^ߜ5~^ΨzP@UU{UU[Ɨ/+)/[{@@@@    bŨzٽhxzԜhj~t{AxXb'9_~-k9=U{I -.sQ{Nssbx\ cKZ MsZMsZZ k)9VW__A1_A1uH929! 9h)*1G1j:H1}9! 9H1ZA1_W:H1H11QEUU81}}UU9I9I I9}I9I9U_*BAUUKJ9+R Jd    ^栨Ϫꪪ^ߛ [X[ΨVફصxj~~ص5ƛΖ) ZzՕ    {[ΕVVUŪZΗ`x\^Ԝps shxNs9ܞ~3bW\XWAAUUUEjA+ - -k5+ NkzNk{)s kNkZx|z cJR cJRZ k9999jA19h)A1_9H1ZA1Uu]A1UuUר9H11H9VA1]_W1H1:H1:H1]_Q9}_9I I9uA9A B@@@JJ9RA*UbA/ .cTTTT    ^*^תV]תj]ߜު\ր]ڽꪪ^zYƘ_^[Ɨ//ٽ/ {Ψa@@@    :ZΘVxZ~Ԥ`xoRNs`b0h\T0AUUPIAU5 k( / -k)} Mk^'{ c~XnkkZ_ cJR cJRՋZ R  [ { [ kZLk9999ZA1߈)9jA1u}A1_}1H19h)H11UUU9!9!2H1_9!2H19I"I9_]9I J9KR1/JJ9JJ9RA7%/    ׀  *ޞﯺߩ֪ޛjƪZΘ^xZΘٽ ݵլ@    Z[_}ؽ@@TTؽjz62`pXЃwKjZ׮*r9_RF9_RYR{{ k\sZ\MkZ cIJ cJR cJRbsMkZxWZ J JR RRjJRZJRZ JRZj BR%9II9919__A1A1Ո9!hA1[wUH911A *A1UH91:H1_2H1H11PUTEH11UE9I**9I*(9I(9IJAUUU*JAR J cKJ nkTTTT    ^כ UW[Πջ[Π_[ΪU[Ϊ[_ZΗh~W ?7?ٽˏZƘ    ZƘzzصꗵդRhjЃzR{+Z~R{2Ѓ*UR{NsX{ kXU"{ZWsbx cJRZ cJRuWW RRbMk?NsjRꀪ~ cIJ^xURAIR9Z JUR JUWZJRAzz~zIB9U_9 9*99Z99fH99UPUWA19H1jA1}_߈9h)ʠA1W_w9! (hA1w9h) 91hA1UWW9h)"9I*9I9I*9IA BT*BAUUJJ9*RA*+- -cTTTT    ޻~Ϊ[[ΪUƂU_UZΘxWZƘ[Ɨ*UTPP   WUդ^62|ԤڗЃ%mns{ ksh){ c(_{bUnskZNkZ_WNcZbU cJRUJRR RRZ c_/ cJRZJWIJ9RAWIJA *R JZ JRAZJJ99999V99j99ꩪ99)9WWWA1A1A1A1WW9h)ʈ9h)* 9!9H1Z9g)9g)(A1U}_Q9_A B@9I*(A BA B@*BAUVJJ9RA kRTTTT    ]ߜ/UU^כ_U]ΈZWƢٽٽYƘzxؽ^^VWwUUؽؽVWVS^ դ5xVo{_RsݿNkx^`sb_sb~}MkZZ c* Z JZ JRIJRZR kZJRA^_J9)JAUIJARARAAIJ))&*A9Vjj9h9?9999Zj9999)9W[W99iA1uH92A1__9191A1WA1UU_H91UUA1w_A1U_KJ9I9AAAAA B@AA@@ BAJJ9KJTTTP   [UUUƛU*Uٽٽ՛ٽ*ؽU:صjjUjص^xzդ/WصXwؽrjؽؽ^_Vxլz.__[rjz1 s .k\{ZpkkZU~skZUsJRU{kRUUs*JUW-c JUJRnkUbNk_NcZ cIJ_~ZBUj)J9UUjIJ9)R9ߪ(JAVZjZIJ9HJ9IB9uI99jj999 19999)9WWkg99A1WA1_9H1A1׈A1_H91A1_:H1_1H1@:H1_RA]UuJJ9AKJKJ9JAUUU^9IIBA*JAR@@5 UUU{U[ZZƙZƙ(:ٽZ:صjUصpUU*ZW_WhV^`W /ص*լS_լWѓXUO~WЋs+Vb/Ns]{ k^rMk J~b J cJR_U cJRպUZ J_ [JJUUZ JR cZZ?Z cZ RZ JzR9W^RAUJJA R J} BE19f1A9jjjZ99*H99j9999jU99ZH9999k9!A1_A1:H1_9H19h)9h)9H1A1U_:H19H1 cKRNkRUMkkRUsR*{RUꀏsAU_~RAuիRAZ J+"ԔZ --՜ W**ZƘ[ZZƙ:ؽZjVYuZUUصUص^՜S/V׵WuU2xZ^Sz_OwWo,j(zlj /-{r{j{b{sbU{WkkZUu cJR U~ cJRU cJJ*W cJRU cIR cJRJRZJRZ__Z R*Z JRAIJ9AIJj`jJ Jj JF)~1 91/A9ZYA9UVA9UUZ9 999j99)9WWWA1U99iiA1_A1W]A1WA1UA1}w9!*"A1]_UA1U:H1_McZ/sMk{sUUsjZR{2bzzbA_^\x9IRAskR-c +/ص+V UUVZƘ:صjZVZص(xص+صWٵUصص*ص~Ԝx^V_6՜U.xoLjzO rUza@`p_nsa-{j{MsZZsb/} kZuKRZZJRZV cJR_JRZZUJRZ*VZiJ(Z R RR꥖JRKRZ [ [JRRI(Z JxRAJJA  JJ1x^1 WD)9)+;9 9999h99ZZH99U99VU9 B1AA1_A1U9!A1]}A1U9191:H1׈A1U}U1H1hA1WsZ+|NkSs+Ӕs Rsxh`NkA\xxx BAJBARA+2|Z/-6s +-ص *)صVzV`^ص*صص_WvUԜW՜_՜ߗ՜zS{zp\ԜVsO{`એ{azzjaUU~*jIb Z5/ kKZ֋Z k kJR* cJR/ cKRZRJRZ** [JRW_ [JR}UJRZj Z R/Z Jz JRꪘKRRJZZJRZoWZMSZRTVPR c ZJꨨRIJR&!x1 x_U!e!C **9)9? 999Z99Z9h999U99V9919WGWWA1A1A1UA1}WA1A1]H92*hA1W_9H1jZ1H1:H1]R{UR{URs ZUUԜ*UsMkp~Ms1xx^^A JBAKJA* cA +/.c+-ws+՜(*/` ص 5՜ZZWVU}VVjWRԜW{S{~x{ khsj<nskZ{򪫌Z k! cKZ JZU) cJRխ cJR cJZ *b[ McZZRU@R)JjZJJwW JRiZ J RJRV SJRZR5UUZ JZkRZ R bR_} RRUUUR9zA~W !$) A)+/99A199VVj99ZVZI9999ZYf991A# 1H9A1WA1_A1_}_9!( 919H1Z9!*)99h)"(A1WU!{AUUUIB!UUAWR!UURUU9!UU9! UU!1U9A*UU :B UUZ+) ԜRkUW2WԜV* ԜTS~SWԜ|*S_Vm_VyW՜уz~Nkzkb^kb뺪NkZꨠNcZWZ cZ cKZ" cKZ*Z cj cKZ( (Z cZ cZRWT@PRJJUTTZ JRIRA *(RI*R RRg9^jRG1 =bjRZkRZ Bj*Jxx^E9() *Ic+A9`PS_999h9?99YY99*99Z99Z9999A1A1A1_A1׈A1A1Wu_hA1׉A1U_A1]__A1U9H19!AUU!AUUAޠuUBV!AUUAUUAV!B E)//JB UJJ_Uk! UUsg)*US BSb sӔuS@UPXԜ퓔sssVUZjSszz~zs k cs kb_~Z cZj cLZMcZjZ cZbZZj* JRZiRZTR RꪪR BWR9ukR_JJBU1!^IR(----b J cKRZ9hx~^1BzxpAUU(/= xzAU%1/?Ո1BU1AU9AU9A9U9U99U9U99!_9)Ո9&!9G)W9G1jUH191A9H1j199!9i)" A1_hA1U[ABAUAUUAB@ABABABABAQUUUABABABT@AB@@A!jBB !B]UAb+լZ!{ cF1+}s /{R*RsssԔ_sZZZV{TTUUQs cs%kbz cJZZj jZWUubB*rZuWUUZRZ9^kRWRWU)BbU9BUU%)Bu!AUUV)AՕ= J()- RZf JZ&IR9zzAxxxUW__A_ UWUUUU UUBUUbUUjBUUBU}B|UUATUUUUUUU_UUUUUU!_UU%!UU)UU&)UUG)UUG1UUABABABABABABABABPABABPABABABAB@@ABABPAPAB@@PA9cbjU9cky)b5JBWUs&!U{9 -Ssss{sj{sVUsOkjjjVNk cTTTUNcZ [KZZ RZ%)^ZcURBWU1A~UUBUUUBYUUAtUUUABA@BAATWEABABP AUUJZB+/ RZZjZ JjZjjIRAoA1x辿f9!W^xA<ABABABABABAB@ABQABU@@ABABTABUAABABUU@CA@ABUU@ABEUABAUCUUABUABUUABABABABABABAB@@ABABABABABABAB@@ABABAB@@@B]UUQABe!"jR-Uk s B |Nk|Ok_sRkb cLRLcZ~_Z Jꪪ JRA \\x)AWW^UAA AAABAB@@TABAB@BAABAU@Ab%- JRA*ZAjAJ& G1b(\\9b!AWVV\AUUUAABAB@ABAB@@ABABABPAB@ABABABABABPABEABABABABABABAUUUABAUUAUABAAUUUABABPABABABABAB@ABABUPAB@ABAB@ABPABUTAB@@ABPQ@BABABABcAUUBB ABUcBU+R-U.c+Nk)NkRsZ} cZKRZUbRuuZ JzJJAjI)_z1AWAU_PpA?WTA=UABABTABABAB@ /A!յ/ J&9bpg9bIRAJG9|f9B\|xxABABAB@AB@ABPABABAB@ABABABABABTABAB@ABABAUQUUABPAB@AB@@ABABAEUUUABAABABAB@@ABABAB@@ABAB@@ABABABABPABUABUAB@AAB@@ABABAB@PABUTTABUABABPPABABAUB**+!B []KJ UUokUUZUR&)UZ1UZ JZIJRA{~jI)_~F9_(_~AUW^!UuAUP@AUUUTABABf1A%%-*J ~ABpZWUAA5-JRg9{z`pA/?%5Izx`D@AB@AB@PABAB@ABPAB@ABABAB@ABABABABABAABABAB@ABAB@ABABAB@TABAB@ABABABABAB@ABABABPABT@ABAABPABABPABAB@AB@AB@@ABAB@ATABUABAB@ABTAABPABABT@AB@PUEABABUABjBABABUUVZb(Zc+ՋZ1 ZAoIRA JF9A)xTA_+1AU AC ABABTP!B-UU!A\UUUC AU*R %-)+kR `p^9b75Ach~_ABABAB@ABABABPABABABABABABABABABTABAB@ABABUABABABABABAB@@AUUUQAUUQUAUUUABABAB@jAB@ABABP@ABABAB@ABABABABAB@EEABAB@AB@ABAUPABABABTAB@@ABUPABPABUABQT@ABPQABjABEDABjBTWBAAUUlZ! b9^b9JRg9WA~F9AUVxUUABABAB@PABABbAUը9U'!Ax^UUcA5UU)A^WUUAB@ABE@@AUUUAB@ABQABABABABABABPABAB@ABABABABUDAB@@TABPAB@ABAUQUUABAUUUbABbAAUUUABABAB@EAB@@UAB@UABAB@@ABPAB@AB@UABUBAABABABEABPABAT@TBAABPUABTABABPABAB@@ABABAAB@D@ABAB@ABP@UAB@ABQUATABUAZF) KRxxX^*Rb --5KR(^XpAb/5WA Z-9!UW^xATTTQABABDABPABAB@ABABABABUABUAABPEUABABUABABPABAB@ABABABABABABABUAB@ABPDAB@AABUABU@@AB@ABUABTABAUUUAB@PbABAB@ABPAB@TABUABABABP@ABUABAB@UUAB@@ABTABDT@TABUABABDTCAAB@ABTPABPACABABPUABTPABEABPAABTABUABUDABABTT@PABUUTABUABPAU')AXWUU9A5UKR IBW^xx1A-U1bxj}UD@ABABA@ABAAB@ABPABABPUAB@ABUABTABUUABPUABAABABPABABAB@ABABABAB@ABABABABAB@ABUABAB@ABABABAB@@ABABABEABABABP@ABABAB@ABAAB@@ABABAB@AB@TABABABUUABU@TABUABAABTPDABUUAB@@TABPABTTTQABABABUAB@AUABABUEABTUQ@ABAABQTTABABABABABA!B UUg1!D@AB@AB@PABTPAB@PABAUTPABUABABABUAB@ABP@ABAUABDABA@A@AB@@AB@AB@@ABATABABPABAB@PABABPABTABABTABUABUAABABABTABAB@AB@@AB@ABAABABAPAUUUAB@AB@AB@ABD@AABAAB@ABABPABABP@TABAABEPAB@ABUABTP@@ABABAABEABUPPAB@T@ABPABPABUTAB@ECAABUUBUuABPUABTPABAPPABAB@ABAB@ABABAB@UABPABEAB@TTABUTAAB@QAB@PABPABAB@ABABABABABABUUABEUDABABTUAB@PAB@AB@ABABABABT@UABAB@ABTABABA@@ABUAB@UABABABABABPABPABAB@ABAB@AABPallegro5-5.2.10.1/examples/data/mysha_dxt3.dds000066400000000000000000001752001473414355200207730ustar00rootroot00000000000000DDS |@ DXT391UTEA91Q91@A91@@9G191@998*91PP9191P9H19H1hA1_9191@H9191919199UUU99UU99UP99UU9199UUUQ9191@9199UU99UUU99UUU91919199UU91@@919191@@99UUUT91@9191P919991$9191&hA191A@9H19G1hA1}}hA1wH91?9H1j9h) (9H1ZYZ9G19H1jZ1H1P1H1ATU9H1iiUU9H1Y1H1PU1H1TU@U1H1TPQ1H1PQAU1H1UTUUH1G1PH9H1UUUEH1G1U1G1UUUQ1G1UUTUH1G1UEH1G1UTUTG1G)G1G)E@G1G)G1F)TUT91@91T91A9H1j91T9H19199TUU919199UUDE919199UPUU99QQUE99UQUA99ࠨ99E99UUU99UPU99 99UUU99UAU99TEUU99QQQU9199UTQU99UTT99UUU99UEQ99EUET9199UUE9199QUUA9199UUU99EAU@99UU99UUU9H9919999UUU9199UUEA9191@9191@91P91A9G191@@9H1Z9H1jH91<9H1Yj1H11H1Z9H1ZZ1H1Q1H1@P9H1UZ1H1UeUZ1G1Ue1H1VVY1H1UjY1H1ETD1H1iUUU1H1eUY1G1TUT1G1UUUe1G1TUUUH1G1U@H1G1TU1G1UTUUG1G)G1G)Tg1)91T@@91A91Q@91@91P91@A1__99UTUU99VUUU99UE919191@91@A919999TU99UPUU99UUeU99P99UUEU99UTT99QPUU99UUEU9199UUEU99UQUU99UUUT99UUU99UQ99UUU99UU99EEU99DUU99TUUU99EUU9991@@99U@U99UUUT99TTU99UUT9199UU99UUU99UEUU919H1999H991919199UTU9h)H9191P@91TAQP9H19H1iU9H19H1Z1H1@H91?1H1UQ1H1TUUP9G1Z1H1UjU1H1@EQP1G1eZU1G1QUUQ9H1UZU1G1EUUU1G1UUjU1G1UYH1G1TPH1G1PATPH1G1UQ1G1UUUEG1G)PP9H991@919191UP99UUTE9199TUE99UE99U@E9199UYUU99UUUQ99EQUA99eUUU99TUQT99U99U@QP99UUVU99U99EUUU99UiU99eUYU99UVUe99QUUU99UUT99YUVU99TA99TE99UU9199UUU99PUUA9UUUT99AQ99UPUU99UQQ99PAAP99(99UQQ99UTU99P99T99TU@9999EDUD99UUUA99QUEU9H999APQA9G9P999H9jhA1~91P9H19H1H919H1jH919H1j9H1jj1G1i9H1e9G1Uj9H1fU9H1U1H1P@PE1H1iVUV1H1EU1G1efV1G1UQU1G1TTUH1G11G1UUUH1G1TPP1G1UUTUH1G1U@UH1G1EG1G)P99PUQE919199UUU9999AUU99UUU99EPE99EA99EU99UUUT99AUUU99UUEU99EUUA1?99TTE@99UYVU99UUYYA199U99UUUA9VUU99eiUY99UUU99UZeUA9UVUZ99UUU99TUUU99UeUf99UVUYA199UUQU99UUEUA199UUQA199QTUUA9UTUU99U99UUTTA9UUUEA199UT@E99UTU99U99UEA9991@91999H1@9H199UPQ91@@9h)9199*9H9Yi9G1@9H1Zi9H1f9H1VYH9139H1j9H1j1H1TP9H1j9H1fY1H1jjVe1H1VU1H1PP1H1UVUH1G1UPQ1H1ZUV1H1UUZUH9H1UTUUH1G1@TG1G)@H1G1UTH1G1U99DPTP99UQQ99UUYU99@99TUP99UET99UUU99QQ99PU@99UUEU99EAA99QQ99UTQP99UVYU99UU99UUTU99QUUU99UiUeA9UUU99UUU99VUUV99ZUiV99UUU99UUUT99YUU99UVU99VUU99UeU9h9A9UՕ99UEUUA1A9UUuGA199UUiU99UUPU99UQQ99QQUP99UUeU99UUQU99E@TU99UUU99UU99UUUA9UUU99UUUAA1?99UAU99TUUT99PPUT99@DP9199*9H9j9H99191@919H99H1Z9H9jH91H9109H11H1V1H1ZZ1H1Z1H1UU1H1U9H1Z9G1QUeU1H1PQ9H1iUZU1H1UEH9G1QUUU1G1VVfV1H1UAUUH1E) H1G1AD@H1G1EA99UUV99TUUT99UEUU99E99UUUQ99UP99@99UUe9199ZZ99UUUZ99UQQU99QQQ99UZe9h9?99fUA9U]S99EQ99efi99UZ99Ue99AQU99UYhA9Ue99VUU99eUA9QUQ99UUY99UAUA9UsU99UUEA9UUaT99UUAUA9VUQUA9uUUA9YUEU99UQUUA9UUUQ99UTQUA1A199TT99UUEU99@TA9UUU9999UUUY99QQU99UUE@91@A9UUUT99TTQU99UU99*9H999*9H991919H9j9191P9H1j9H19H1Z9H1jj9H1UUH91?1H1ZiU1H1AU1H1TTA1H1U9G1jZU1G1YjVV9H1U]U1H1UUZe1G1UUH9H1UUU1G1UVeH1G1T9199ZUUY99UUU99UUU99UUVA199UUA199Vef99UE99UUiVA9UQUUA9UEUU99AUTE9999VU99ZUU99UUe99VjiZI9QU_99ij99ViZ99UAA9VA9]UUA9VVA9Y99Vef99QA9AUA9UA9AXR99iZUe99YVi9h999iZZA9UZUA9YUYA9UUUA9U]UA9UUUE9i9A1?99UUUA1?A199P99QUU99P@@99TUUU99UUUP99U@UP99UUUA99@T99UTU91@99UU99EUU9191@919191@9H1jgA19H1jV9H1Z9H1q\1H1@@9H1ZU1H1D1H1UVV9H1ZYU1G1UUD1H1@Q1H1UfV1G1eZVU1H1eYeU9H1UUUZH1G199UUD99U99YUU99UTUU99UYU99eUVU99UViU99jUUU99eUU99UY99UVe99iZZY99YYUYA9UEU|99UZ99ETA9YVV99iVZA9U99U99ZViA9YA9_A9jfjA9UYA9ZZAAA9 J9WAA JAUUUKJAUUZPI1AAj JAA9EA9&A9A9T%@99UUA9U\}A9YUT99eUUi9UU%9UU h1Ur9UU^9H199TEA99A@T99UPPP99UUUQ99UUEU99UUU99UEU91919991@9H9Z91P9H191P9G1A@9G1A9H1U9H1VH91-?rVRsj2@TTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU9UU99h)9g)*9H1 H919g)誀9H1Yjj9H1Uj1H1UZ1H1Zjj1H1P@9H1jUUe1G1e1G1jU1G1VUU1H1UA1H1YUf1H1ZUU1G1UQUQ99iejj99UYA9UZZ99jjU99Z99UeU99999 UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU~窪ef^ ^֪~Z >WYΪ^ZR__(x~kΠzWUWwZؽW͋WhhWpxxzR 7 UO+pR./ -brZZ2@@PUUUUUUUUUUUUUUUUUUUUUUUU9UUU@UUUUUUUUUUUUUUUUUUUU191E9G191QPhA1V1H1PPgA1mhA1uu1H1P9H1jZj9H11H1UQ1H1@U1H1TQ1H1TTUP1H1UUU1H1UU1H1UVj1H1iUY99jVe9999jY99Z99Z99jA9f99j9 UUUU UUUU UUUU UUUUA UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUUTPPPZZ'Z(ޛUu@=YZU}{90ZU"[``[ΘdlԺ62h~_(.N𾷩R?%ѓ ԜkRTTTTUUUUUUUUUUUUUUUUUUUU99@9UTTPUUUUUUUUUUUUUUUUUUUU199UQUT9191AE91TH91?1H11H19G1j9G1Z1H1ZZZ1G1@A9H1ZY1H1UU1G1V1G1UAT1G1fVff1H1UUU99jYU99f99U99f99Z99iiUA9Uc99U UUUU UUUU UUUU UUUU J@KJUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUUPPPP=?:E =U~}=jjjU^ީ*$^X\~o[Θ`rP\Г\Nr&ۚ.N*R/2??@PUUUUUUUUUUUUUUUUUUUUAA9YZj99UQ9@9UUUTUUUUUUUUUUUUUUUUh9UUhA19H191@9H11G1P9H1Z9h) +1H1P1H1A1H1P1H11H1UQ1H1V1H1PU1H1U1H1UT1H1PQAA9jV99j99PA9999Z99j99VA9 UUUU UUUU UUUU UUUU*J@@@@ՔkJ/ UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUUPPPP~מߪ=ަߪ=ޥV=ުj~W^֨z{{Θxx|W|XsN{hXЋ{5-{QUЋ5*PTUUUUUUUUUUUUUUUUUUosUNk B_~x B9z99UUjj99T9TP@@UUUUUUUUUUUUUUUUUUUU99191T9191@@A91@@U1H1P91AEU1G11G11H1jZf1H1A1G1e1H1YiZ1H1UQ1H1U1H199i99A9jZ99U99jA9VjjI9_WA9PP@ UUUU UUUU UUUU UUUU@@@{+ UUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUUPPP@^ޚh߿=ZUU=ު^bVVZ^ֳ[ZZ0 UUUU UUUU UUUU UUUU UUUU@@:UUU UUUU UUUU UUUU UUUU UUUUUUTT=ު߼{ |WZΗj_ؽVzUصդ:_Ԥ}R8{RsxЃ sbWns bz^* k*b Ѓ s)-@@@@UUUUUUUUUUUUUUUUQUUU11ЃZZjZσ@UU{Nk``-k B~~x J9\A9UTUU99UPUE9UUUTUUUUUUUUUUUUUUUU9919H191P@9g)891UQ91U@TUH919H1jZ1H11H1P1H1@1H11H1P1H1@@1H1PA1֥UJ]ߜ֢_}_UU UUUU UUUU UUUUV@ؽTUUU[   UUUU UUUU UUUU UUUU=PPPP>ުޛ֪fjUZ___VzWrxxxz5 _o{WRo{RЃXVRу` js/Rs{bxpMsZnsbσ k+Un{PPPPUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU9UU9191@D91@E@91Q9H1ZZH911H1j1H1j9h)*"*1H1PT1H11H11H1@T@1H1A9@A1A9APAA1<RZUYSUejVsVUZjsppxpsNkWs-c[kb_~ cZ\bZZ-cbfUUj cZ]UUjZ cZb SbZUjUeZRp-?rVRsj H$2@TTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUII$9UU99h)9g)*9H1 H919g)誀9H1Yjj9H1Uj1H1UZ1H1Zjj1H1P@9H1jUUe1G1e1G1jU1G1VUU1H1UA1H1YUf1H1ZUU1G1UQUQ99iejj99UYA9UZZ99jjU99Z99UeU99999 UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU~窪ef^ ^֪~Z >WYΪ^ZR__(x~kΠzWUWwZؽW͋WhhWpxxzR 7 UO+pR./ -brZZ $2@@PUUUUUUUUUUUUUUUUUUUUUUUUI$I 9UUU@UUUUUUUUUUUUUUUUUUUU I191E9G191QPhA1V1H1PPgA1mhA1uu1H1P9H1jZj9H11H1UQ1H1@U1H1TQ1H1TTUP1H1UUU1H1UU1H1UVj1H1iUY99jVe9999jY99Z99Z99jA9f99j9 UUUU UUUU UUUU UUUUA UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUUTPPPZZ'Z(ޛUu@=YZU}{90ZU"[``[ΘdlԺ62h~_(.N𾷩R?%ѓ ԜkH$H$RTTTTUUUUUUUUUUUUUUUUUUUUI99@I$H$9UTTPUUUUUUUUUUUUUUUUUUUU199UQUT9191AE91TH91?1H11H19G1j9G1Z1H1ZZZ1G1@A9H1ZY1H1UU1G1V1G1UAT1G1fVff1H1UUU99jYU99f99U99f99Z99iiUA9Uc99U UUUU UUUU UUUU UUUU J@KJUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUUPPPP=?:E =U~}=jjjU^ީ*$^X\~o[Θ`rP\Г\Nr&ۚ.N*R/2??$@PUUUUUUUUUUUUUUUUUUUUIAA9YZj99UQ9@I$I$9UUUTUUUUUUUUUUUUUUUU I$h9UUhA19H191@9H11G1P9H1Z9h) +1H1P1H1A1H1P1H11H1UQ1H1V1H1PU1H1U1H1UT1H1PQAA9jV99j99PA9999Z99j99VA9 UUUU UUUU UUUU UUUU*J@@@@ՔkJ/ UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUUPPPP~מߪ=ަߪ=ޥV=ުj~W^֨z{{Θxx|W|XsN{hXЋ{5-{QUЋ5*@$I$PTUUUUUUUUUUUUUUUUUUIIosUNk B_~x B9z99UUjj99TH$ 9TP@@UUUUUUUUUUUUUUUUUUUU99191T9191@@A91@@U1H1P91AEU1G11G11H1jZf1H1A1G1e1H1YiZ1H1UQ1H1U1H199i99A9jZ99U99jA9VjjI9_WA9PP@ UUUU UUUU UUUU UUUU@@@{+ UUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUUPPP@^ޚh߿=ZUU=ު^bVVZ^ֳ[ZZ0 UUUU UUUU UUUU UUUU UUUU@@:UUU UUUU UUUU UUUU UUUU UUUUUUTT=ު߼{ |WZΗj_ؽVzUصդ:_Ԥ}R8{RsxЃ sbWns bz^* k*b Ѓ s)-  @@@@UUUUUUUUUUUUUUUUI$IQUUU11ЃZZjZσ@UU{Nk``-k B~~x J9\A9UTUU99UPUEI$I$9UUUTUUUUUUUUUUUUUUUU 9919H191P@9g)891UQ91U@TUH919H1jZ1H11H1P1H1@1H11H1P1H1@@1H1PA1<A9AUTA9DQQI9k_A9] ]_I9~A9 BA UUUU UUUU UUUU UUUU UUUU}0}?^UU UUUU UUUU UUUU UUUU UUUUؽ@PPPƵ-  UUUU UUUU UUUU UUUUTTPP=ީޜ֪pPZΗVԜVԤ_V(z7s53貼kЃR_ kjXs sW~{ kUUPU kJZ6{ k %!)  @@@@UUUUUUUUUUUUUUUUI 1QЃZX{jσs_W{s@TUUNsKJxhKR9W^X|99ZZZ99VUUH$@ 9TTP@UUUUUUUUUUUUUUUUII$1UU991P91A91@T@91AQ1H1i1H191EUQ91UUU1G11H1Q@91UUU1G1Zj1H11H1A9T@UA9UUA1"A9@AA9PA1AAUUU*JAU J UUUU UUUU UUUU UUUU~ߖVYj]֊ZJ~ޯU UUUU UUUU UUUU UUUUٽPPPP +"  UUUU UUUU UUUU UUUUPPPP=֪=VeeUZppZص`PxjxzV-R\R^у .jЃ' R{{ kԮ{ kjxs kUU\ kZ 0σ kխ+ ${@@@PUUUUUUUUUUUUUUUUUUUUUUUUUUUU I$MsUU$NsU$-kU$bU$9U99UUj 9@@UUUUUUUUUUUUUUUUUUUU 19191Q91D@9H19H1e1H19h) 9H191UPA1H1EU1H11H1E1H11H1TEA1A1A9@A9@)BAUUU J9KJA*)R BU +kR UUUU UUUU UUUU UUUU>֥UJ]ߜ֢_}_UU UUUU UUUU UUUUV@ؽTUUU[   UUUU UUUU UUUU UUUU=PPPP>ުޛ֪fjUZ___VzWrxxxz5 _o{WRo{RЃXVRу` js/Rs{bxpMsZnsbσ k+U@$@$n{PPPPUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUII$9UU9191@D91@E@91Q9H1ZZH911H1j1H1j9h)*"*1H1PT1H11H11H1@T@1H1A9@A1A9APAA1<<A9AA9@PT)BAUUUKJA )kR UUUU UUUU UUUU UUUU}]p?^ߜ5~^֨zUUUU{UUTUUU[Ɨ/+)/֜YieU{ UUUU UUUU UUUU UUUUP@@@ߛ&Z^WWWٽzٽhxzԜhj~t{AxXb'9_~-k9=U{I -.sЃ@UsbVsbx\ cZ B kZ,kbUUU@$H$bPPTTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU 991P91@E9H191A9h)*1H1@1H1A@91UUU9H1Z91P@T9H11H11H1A9UA1I9}I95I9U_*BAUUJJA)R*J  [ UUUU UUUU UUUU UUUU^U~??ߪj^ [X[ΨVZX`صxj~~ص5ƂhZZzՕ UUUU UUUU UUUU UUUU@@@@[ΕVVUƪXZΗ`x\^Ԝps shxNs9ܞ~3bW\XWAAjA+ - -k5+ Nkz{nk|s.kNkZx|zZJRbJRH$I$ZTTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU I999UUQ91@9h)91P9H1Z91UEQ91UEU9H1H9191QPT1H11H19H1YZA9APA9PPI9uA1 )BAU*JAURA*UbA/ .c UUUU UUUU UUUU UUUU~VVZ^תV]תj~RZUYSUejVsVUZjsppxpsNkWs-c[kb_~ cZ\bZZ-cbfUUj cZ]UUjZ cZb SbZUjUeZRp8F82=60;60<>7F=6D91C 90D91C91B91D\X_YT\TQX    YT[7/A:0B80B    c_e 8/A 80C  91Cqz91D70CRNV7/B SMW z  91D]X]]Ya91E_[db^cQLTTNWQMU_[a  mhlq|TMW70C SNVvqw70Cndlwy҆ }zPKTג70D WNZkbh`\d ^Zb]X]80D e_k80Cyt}VPYᎆ\XaZT_]Yb qq|`\azyH?L{_\cslroksxrwsmvզihscaj)&yÿͅJ?NynvnboJCN('ú$%0tnsA8J>5IA8Jrnvr""gxJALf_ig|TJc]yI\UE"B@)Mprji8_UAbltȄ6Mv{"xP,M[5Biz0mY꺣Rœ8*韬p\Bزڤﭔ}5҈Oc IDATx͝y|U XQVZ*#*U-gF4 8h!*N:Vy1!@BBBd $(Yks}& ?~>G>Uo;~;o+_]ӿ7 lП h]K;.XN?$^.ĺֹ~ODZhuСc?裏;_:c9Wn 6kD'~b~_J^_U}S9?2s(ݯ: B6!@[~ZHhѻ_+{gO~kh~ <_/E V`á@1"ׯTg 7E?km^u إ{,:!ዔ#B!S_ A[nZ7_t K")Дnr[yBT7 B\Bv/ „~E3['ȁ]`t<+"ŰXC0:] R`9) 4)5aD珔C(R^GH.`{.|х?@c(c %H}*)? Dfma }fb9-9!J\ԁ1s1eeg@Mtf+,6lm"T;G!~` {upeAQ"bH1!/Q2ՉREN%QHwr;u较^GVm`2c9 ^2[ǢM]ID~YF*2eFrAY]#,±[v;Drgp5 Yȁ~]/C]&&r[KFHN:ЯB׮[ 0sJC%4E cCX1]GёӘ6aF+Ԟ j9 T"+3(Evtc&tú;Kkf7et,c_Gc"./pՁ:(:h/BF̆"|&0>", (]Ø:st^8Lh|n_Eͬ1.kgL6Ĩ v s{^sD#qŢWسY> b۝IlŶ oLCf9#MTOh6k3~lkq:tbӂ>CVHՁ>K?2ӟ_V7pS3 b eA#X}u#& wHɁ쟡RYoq4F HTUP-ҧL'\,5"9@#hR˲=:ˀeg Zu@ Tv9f[@8P,~1=qos~:`C򇊩7Y>4?~-, ߧ#^`HdzaCoǩta~X%bq I-P>>8C!B|k #W]ud+H𤈉`ux1?PK\>^W}#&$IIINӅO9n{}2PIZ 5U1~ʛ9! X(Ca @l~ COPpʵ)D0&bS{]c?׉xU"&-?t>e%%-]Iu}^R!~$b}~m/KII&$pփ3{|Oqy Yv+bNg-vD.{;1ڐ!!x 0#B!IpYswB>& RRd l[x3f\~ݴis(F!=->r_v]_#!DTdK1#_)H)S䧈S#1"9yO(N08gAMX/Zj g.򳻒YKre2#aj GAʣ X ث%|~N~֛-Bы`4V$[>iq\|Q92Ʋ0s)Q+[)PY>+~[) 0Y7oNԩS?x޼y-\H_>6̙52{キ0_zd TEZ=q T @HB~nAHz,<+?_*__A?+%xLw}wK/^/D`s5 W~79ex0{JAZ&)OŘ W--ܾq,S@EEuQQ5oH]o^o_5@\xCg&LՏQq~&R%iE1i~^<"ii q->Z,!\_#zVol+[W_H^<S/7nP3gNw[?OuXF=^}߀ (D&>i=lVEqKܮ쯾>|x{K W0DZ'g~x>/ÆAp֥Q;m>4tN-0KR1s}7j5WWzg/ |x?l}0[G>c(Xw"<{Z3Ud 8p.ݻr2"ݡ<đJb8 uԥ.(r|nܻw_&M4l0{뭷|C?A{wN;Eê@Kp^̜}non!-B_J _;!.7@~~EEQ^D.]krK}IxG<׿T  N;{aUe–ߞHK\̑kd}k ! u0..{[O9y/KoZ_n޾Mٳ簞 #I1CHʁ6q]fT6UW0Y3(-LѮopi9IpwBUՊr_]nk]HКt >&|E(p@x [n1#a.0Tc ފ/(!x~DA +}aݕG߅,Yi_ z8akYlMYPw"Ib$h(_|M7 75 P?Cjv RS4WY#4|h!~OL i+:iB^,orDR+sZ@HQuCp8 DH{o)#, Ox վ Pzat!z-Ɂ :0]6@ 5Gvz2sWq.Rܼq㖺p$ ⃋44($ݔW So)M6^8˙h,᭷@=`B/;@:u _1X0=nsRwލ [I Sn X6 IMʒVjp8(M=2׷R!!u3Qa"x<,\ЀjĂ> w$z^SS=?Va*j\F&?*H>u7Fd Ηǩ!+~ўT%Rz8^Jlyvra*&PCIqeʌ֕m+Z==Lϖ-V'ov[DMD2_(8Ag.lRհH}YYZJUtw!5?X{Oy9y/ xY+3[I+3 2zcs5_$v@@CX͙ Wq?>Xλ/pV—VP.:iۃ,ݓV^д$=c%J0JpFJ୚Iwpa_*c &~ x{C=v s3FO>38u@ ; Zj<Ļ *Y,@jjT6R۷$d"-س \2ᛘDxofz+G,[x w]6=VW:ʻ e;U]"2_.ke`##Ñ~DP Mgf zc ?=["jWDF穷hK jAZ~QXԌe3䗶n; NL:gn=%%gZ^*;զl[OM83"/K'$eBNǍ[qŃg W,P%X [u{l$LAZBsKVq8Kiy@za7Rj1(pzpJ?`U4zl_̻!!OMVolhۖ ~9k Tj(aWJ29k7egS4@SbD_}wI# cЌ(2Fr 5{a\ũɩsy @!{Rnt»tR`AzJ09k0"e[W+c_>(}{|C뮻XO( 08 KK4)(wKzc`:<$3ީVeaځe}c0Lp+< aV/Kglܵ!]`[yT1H6{ˠLzٖ'6<~9f~ ehrH)x; 8{j8~|XovEXrV@jDP]v`Ff/#S8`@$}ưU! 2P0f8R]QzV L _3\J؞#G6p`Mbj90*<5ULr8/qb>q[惟HnY+ggG(R $瓓 ,q/1.>GDp965K0 ĩjvg΄[@)\L3LFj~2%΁R|<;As>0Vx  tA9I"lFoTa  ".$m]t:93嗯}kcs 7dAPƪ=6ncr+fԁdrjkT3 #!`%i%3k2と1T"~ z}I`<ə1Ϗ8%PNnعZf 1~9+IF$Cbpʹ!=[dk>x-h(meBž1>CF6o-ݷip"ueԂD0I*g*4f$ mۯhҚG C)UCyeYJўՁjң7 8OF-&X5 홤 99Lx_hp1i;\nQ: JC1,o9=KgEts x[vkj_6Hxi+X)@U`ZΝ!9:c.K_7^㵘x?n1A3ņH A3LY灞g 0P-pʒ38U&6פb[1̣}ʁ(bvn5z?aȁ#_K5Oָŋ_7n.X !ΒYuGT {f"N]0HƆM/##cg&/rkddS-)BLjp9q \7>̡*"fP IDATOjae# Lg?)w jFbf9+۔0'.l޸PFSd`&} JL'$}0.coO7S)P څ2axi qhk߰.ve۾AB$Ō '$dq҉'*4>K1/_Sƽ> b ^xHk[*_N xWM(benߞs%Ṿ(p% ČI&L(#%߆~4I!{PQFiQU I/!|gC"k-uJ.Mʆ:$ gC)ě44?&$0NBzgP̘AM)IP')b| Ik~7MA!w=z̚տQ wRe vCMwg1Lv>3S ĵA!, sא ֺ̠8Y|$#!~$8m=NtQoP#1  , 2s`E޽RHoLH%͚++ g!8z+աDVoobnߙݠkTKLKm5 &`U?S'PDa$ %n~z>ݗWk8@4ãn "ܵk}Cn"volHVW =Q+e(NeumiK_%SOy_z.d9K +5?i $xo ݻ7uHzf-l06 !Bʀ%iYYiGWn&߿p ?s uPÐ,I^bx.$h;]"X)Go֟< ?}y+_OI-;o&`W T-]6`pZMM$VT7//r$o;dbg@ D$Oߑ5#W{R\\DAr b C""@2}iO OxיּL)Bۚ J2u\&@}&=tv㔉TBT@dP,(-/ς,!|{IY R:^d g"sW9D~7p k n2 z= SE q;J۹SU1kx(?0ЅҼ< 4ȁ?m Dpx!8:{w KR'2jmF1N vzQKiʄ ra.9c0CszQK&ide ~au@E>}FtL&jwd  BFĨR9Cp ޞZ_ P ;0ZT$Әud#Aߙ$.$*-@JAG 8g=K |G>$S&΁>!,9|76lޖ]p3S`3HpI\>RVuˮ*9ܹ}i!iiHz(> 4,e" lpxH6,U`c.X >7$.hz(s$X(i{J*~=^XՁHKlpR`xdGt2M^piE`n^)#_}|w{"3iCT%)c(|W/qmʉv{a>ʛ녝s|"h! Rx;2R(摝ԑKk߿Y wcf~"-hFԫƘshc_3? iVW7gC!VXspt޿x6\U+v X D>7oѢyEO8[$,8}8eDž{}M@oX!\om2\[tFNI+R?tsŹy8E‡S-Z ht1^zݦR mO6B!c]9qU'bTsaӕTȅJ["a'Mfb,0B2`YE1Cg@q) !G$ɳ!J!oK׏Qt49&xp'sZϴi 4Ws/.4&EP!T?3e K3/'CEΑ' +x-WQpyzlTdP.\/ƥ֔˒ݔ.u2,$a \/l~10EB@@î gS*0@Q( g7U]{a91(ҨaXTn۶vڭFTSWAǵ8+&)r<ƪWQfgo_O<)ʁX#RFH Ka@#E(Չ1$ a>>^[T6KC7 וCy Q+\PG_ݺNOד}:pDNu :nf7Ϡ%@NF/-hK`"\DTRVzyV )~/ A,R8gȞĉس{MYQ D흭PoO!XY_X[#|f [v*0YGY'͖݆}q*N曩oI%S䔔RRF05%NbCg6g}K -!ܢ-VT#`;v |{||^ٹ}9ݧo/>pNi7W#Tpǎgc(XorZdm݊B~ҥ>Mˀw#繵pU /Te;V D?J?=E&"8x(|Q2Ldb `o^Ć]&B?vapV#@)bHp.ߛ uqoA +7KMJ,CՇe”nCL&"_D $E?h2 :&xG \4J Wb|C7U0nx|?ҡ,S d .]xtowuưڔ3L>RxVsz֝T,뫫9%n <E$%?` A J)SD +h`hrH[nhoᡇP'ՒN*ʎ C9r{8m:!N@+n@^"SLpD ] cn&g ؖKn r:<3tN׮uC8y-hil0,R`4@EpIdI<)מni{ʁTjsh 7: ^JZrZ7$B}-v!+00r:}/4Ɔ'7^E?-JI΋t,1&pm!9/Ȃ!Nt$42SY83LwL?8C`;4F4:&<1!~W!|'ΥF䠻F'rá}0ƦmvttF—@OL1v\ LzcADju`3ct;cT ?:Fxqf%8oE=PQۚSC 0 ˘{¶G#P1F3kD'jv+еd9y tӚ3 F^ K?@wp;Qaʁgr ZШՈhF@xϸp'f0btI.y~0cC4rE@=P567#x8Xh^IENDB`allegro5-5.2.10.1/examples/data/obp.jpg000066400000000000000000000714441473414355200175030ustar00rootroot00000000000000JFIFHHC   %# , #&')*)-0-(0%()(C   ((((((((((((((((((((((((((((((((((((((((((((((((((("A!1A"Qaq2#BR3br$4C%Ds2!1A"Qa2qBRb ?),*'e.3aY*=?fݲt!/(nнۡQ!ޑ3!? =PRY),YII`5t74N^&G(|Kek?xZ1А$6Fτ@=|.[%+ᕮIrtIz<<=!n55'`.@)9tl#q`. =FAform, 7< ЇnLJzC4ډTHWG h7&< ނG~4nShלu_W$&?O&B XKۧOYfa`t9ptGΫ&g[-z#;A3:TyYH6P1oKc5,V]Rhzzf63@.{#3u"u䳸 / ,cCq ʒPveû(E'&w2ʶ}V cADQ4m6-}Zt$>H5Gl&2<.7@YpwCptwI:v.HFV8+'%2:'ĝ h`{FT6,&WT$^2G"'fÁA\-~#  JI;AR|'1ᤶrK0y5U'ttgA xŒtlnF{ڏ2L9M)b\4z}]8pY XOP2Blⱞ WCĒ5DI#oG&|V ݤ*ˡ 2p)KkILn_<ylߥ|eY[/w&=TM|ǪezҍJS1p͊A`663%e㹭]#Rc$<9x8vOo@,wWF $iC,Lܑ?8wTxlcUcN%}'rTDΚ tq~Jc?72`͵avvDw #nK桪NpK!wLxJ!!i.Bmo 4g_Ic{gt.$cu+CDrXVp'78OvL]G#Cu/#zWG&Xbx`cq'*!`xwm<.Ý^Ts9y^pv.dgu;{ȨG._Ggvh;7eu["w=>2`7\T}v#%eqo/+l:b/3sj¾HHkQ^Γ*Y@h}4&"A=CT6cGsL챭-P@P=,FyQIlO" S']Y h;s.=o>o3.g ڮbL[zGFLke+\Y`FP\}ӻ[ͫCBK%~=l=[J_R 4}vX+h&LpIpH- #9N O+.Z4DHmo5дmiH0IIÎmӇ . +p).Nm+D@7\m#)'⨝%h?WpoQu̱;saخG C;r Z7Il0Þ&M#oů弐tq{k] }i\R=KdDڶY7vs[U wRk L\r^幂b ț #cyxDPvF<Sv8>Ambz#\@_Vme)'2dŒi??eD X6Pw{Ƈ4i-.t%;I#tbZYT7J=ŚM{Ӽ7>CC}b5el.VI1 ktΙ5FJ55q6CDN,ͷPx)Č얘|*_唹YkdwB绛%tnmDԜ.ƢD(1!K4C8)In KmG!o&Z@(QLBP'Ӭpu {KXM`;UXa66]ۏ@`q'=1vLn!o֯{!g%m~i oi [yQ C)oIllVcКdd>.1Q.h!=F?3i7{F]2w/k ΛŅ 4E}BVꇬӥ!^C :MHQyNu9yW?jP6WlLHfn4%Pe ikS@q!U4&mNtb'YpUpiozT>uâ^fdQb X\Cˉ.S[A\ܩZ7Cnhen ` /E0H"{%ZrO"Œ6ǹۥ<B D'hix!u%)!j Kb`vGƽ#"v?&Îڕt^I{ܬ` ]~_Qlny2-[tt[wVpDj*t4(-J)tatbm5} pݑcѪRH],[qJ,Ҷ{-BS${i,1Hp4K[h!om%4vHe}DܤQZEp(u%tIYI@wH`};mha 4N+Wݠ'tzmGM`$)` ,&J[z-n#X-]GN蟲c')9r殢Ȏ8+sWBni չGl쓸ǃlPdDƵRqș6JCZ^H5jM2N/Ɂt$Y?e87A1=纴]2~$)4~EO>G\}|R:vk;^f繙K ٥' È*<)bېpDe nu.j?%nЎV?4(ÐMT1r+@4Y@r쎨!i ~(RBuG*XH(#EQ'AiZ,u",̡]r-ڊ|n%@KQI -XGD TϠ&!e-G;iڔPKpP&UHr$ j2 mtցhnLh-J BXIsT2D2qjK|jXz}@Q=CTVD[_^ Rc;w!(D9h/1t'w7KxkxSpd̝W+[|hrsg,%{/N^Itj{INn2e!-%Js ,@j&tamnA`CX?g!;&\[|ӛ Y4lW䕃<~ޕ_Sc{ھ~U#"l4]_<8kOxJ2'{<ɋ:BX'i#؜^2ͲR%c]tEȢE+q# 7%…Fw]#L%~BR{\ǷiM,sTrn>/RL+ýGCt{V?z~<<ōyn;~ dz|b?n?M[_ҡEV_akkcɶiVu0^ B6b6\3]!I#79Iy?Ц|Yr3)6Y; '+xe?DHoH?='dp7)0ںe;:t<2'_rRsECrk}ߩO>K.,8[eI{kaz*;Y qk㌴u+nnRʍLq[rGڭn$͍5;KAwR&GGᆺ2wh]N˪=U*~BZc-Fr#/HɮP]#:Bll2C[-l8T\R&UнòBZCN(VhP% R$nb԰qJ[=Mҩ:6x<񵲹;.N$3`nB[=]{kU5KXZZߧlh>bM?DpH5,R*dS_27U L6/dڰ!Gt{,-dW DP=H:!vF*I(AҞFKIrQqCC Oݩn$m(\omR??Rͭm><} &E_es 1`^fbrtǡ@lFmGeȔvE˞,s~Sfc /wbC.wnovб !r#%:ŰH깓}hVԧ 4Ľh܅;^ DҲ$jcEk萅9H\C@ifQAc̮|1L5 &+L\>xbLt6;rF)wg.$NƗ[kN.^Ǵcv n la;v23C# \emX,\8[t[FǷ*_50A5G=Ag~5y¢Dxrq !=֠H5sVSQvCpwkoWPkwt/'IcBInݮUyP^u+R4,֡dw[h-iޯeG3|p{E4j:&i9 L̊\MȞsiEҚO`iV;!ZhlpkRQ9Un;]8,Q`8lVJ9[uYIQH B-G (@BH4hqXNuGT-HlOIKiڽҲ){~+\?=򩲙2rmy/݅>D:͒AVL_*;{;]o FNCHۧVC-bv@Gu22;&K?Ul~ Di$E;):(in;_1;ꉥ `Hh A {#h-϶ 1E$py LvC$l?d״YCWT+EF\Hh9T[n\kreP!9A/Q})_44UH-kHq'^9a/ Wߚ5Mv4PHRt6LE0lU:Omrlʶ\R%|f\ZW?σkS]M繿?/Xt4{?/?N}edi v腑$FtnK\6PYnI 8jp/dX{PV>@Y>I\C+uzaG'x.LnI<3ЉD=]O}zNsD29V<~ة~-=G E >"N?U~+3 lDգDyGױ,.c潻q#G@;㢣.Mniwec][=oثj[a["|3acG&dn15K)lfNٽ?4Oe"EP$lVP3U#BJCBj +t [i pR&.-FLOfS.K\4A$Fl˚4uy1e%޸]H}2#.`5lTKqخt Gq&zh,>qD$yv[Cʁ^y"*Oᥠ(jzAtL$LҪzEHNij3Nox wJ%2NRN$HvtցW>ݸ@'&#|(@4q xY^R7c%<ݓ-tvvM`0>W{c {Q_꓀Je/LNpptv634aMpk3Y19lo`d . okYpْs}Oi gI{McNtPh+vTM[sAtǞV &h~u߶@CC':AEm.O 36ΒJd6l:cgq4زGs\䦹/׍ZZ}_+3ݍuT.v5D&"+&(9qitOP (-Ό-"Z<2`-k ޲&9lDiv$,EƒR0M@cfuX~v>Mش ,%o_HڊXuF6rR'H2;GM5` d伺=UUt2s3 tK.c$rH c ~/:t3,LKd&52PFo0rvn% sZ.\#cCA~\~Pio?Nԧ^H<9tv7߿)M,u)əτ|۱eEyp>0۵Cz뿖VOƶI#L'uؚT+DZÓ :\kpy ky^)]>lPt= `;~k|QCٳ}HIo%gQv#\ 24#7W4<cSC0{kTMmtqsG[-ULQj4T;w@FYhQjHY1dZ ;TeRY{E-0ࠖYK+,c~Kޔ6I![.4t3~lx|r88|5PTָضtΫLe9o{ZI Q1 rzR_+^lU7hPdz!5Ǻ,iZ%PSvV5ۅ'>!7]&Fb#1Hxc-Q 䥵H7^@&KùQ!IYS45e5r&1$e]Je8WSNCAmIdI$9^N]Cɗ%Lc@h7~<׺bCi4IϜ%۷5]cCM n?iK 7_#$i.WR;s1${{Nɞ~IcK z\9x;`ލӛ'kj?Ν34@8wx=.XswI:Coet 5{3k#sTӺkpkv7j>S$o~a"qѲkn) . 9Lipk[ L%D1@o\wů:IEF[|=cײ6lK#[龰v''0>@⿩ڲ0>#54Xs8ƪEG3OQ˜,R1R IGa{ =-3D!GymQ䮂) 8KϞ^Mgŏ4 {%ku\t&5:6Q`d ~}uPzvvN-7.}?kk m]Ob` 8Pmr|,{5^ULF٭k"`gfنY!|O3u}"_G.S}Ǻ?Pa0mch$OyF&_?U]^Dfg E#H }.or1t߸^p%npl)"ZIk3<ORW+.^[i|T[6?)# qIN{|,3YuA$ oVs_nW7u@ ۦF`DR7`t~9,Ly\~<+=wy]Cǂ z7]?9;4> |7NezL͉eL2R.c4 L†~?ĔӺ{ȲۺHe#&ӆȱw ue9ҞFКZ( RKrmK!A,ZŲ7Xs[tln !!&4lLJ9Ah['i (Ch[nS 5J3FI +Fm;o-U<e:7W!;ZH{}_4WJ+ Q7H Z&ھ3"nLYg0F\vI230I.sft[fL%sqq ۈ\X&3\[{TC2]<4jZJ Q;-]&HK=6ormWM#?/I;YM:3W~ەddf3I;XȚ5_EqY =8&2Km$WtICj$V7. .G:i(IZ+g\a"5^*H p AFKmxv:1ԣFM呑^8{A[ he 10XkaZQ|\tvI$lA4{EgTR1E[~{^V5%sdl:͏aiqOlU2Ldokxi#At4Ihq{~8 ;P܌i2k!YqEGO&\:FKꌷU;ۑ[#XߟI#$sY#ڑ+_Kubg&&@{I{ ˥䱔q^*Qpl;͉ b:WQ%} ֙fRf4VV!kHiDsDxDSM 8lsޓpPgMvFX݂ O#dIrIB!6 Eәs?X;ҫLZ .cGS mrۈ)'ˋ$misv<@QE'6,ƖZL8t*E{hq|)O$;oh[M 6Qe!ԞZzT{{)ʉ wM`&E{E)l&I a(me#vU7ԤLSV~U\QXN1%yWOĥMFk[:H|Vsbc;?:W1F7{[nY[:',n`~ [ h.':ŏI@8Dm7sot2yio"&XIp Sq0r[#Pm`w5,w0W'GM cI5HM`o32XcF}24?H-`-;{S&{H nw>e:pD=`wPv.32K ߚ h`ku Թy:l qs$u{$X v=Ÿ$S7!{͒h4ss*fr#c1)OsH NVEꭒMg㠞۪\̂Y] eܝrW _vm̧I￲n;bDz1|ǹ&\Tqb4mH|3I1Y$[GHuj|q2 Z ԱFi$2rŃCs9~{>͢GeU..${&,S?8%0LmŖ&CN=ʙ>d8-H $}4aD&t1N?v2Ng:l9,G&`~-F- dwDw݂-k8X5 /pI DUga3A;ˣwGd܇tynw5{,?Lu4Fz ~??RPI1 1*#a]ue;5hHSe4~Cm4x4:"#C }!fK\D6Nt?9K@$Iƥ#"s`Gm88AɯϥA"JRt,dZYk&K0ȕ_Dn2=G$E7=zGk㤒wGa46B6v{)Ŧ7V߲PLdos7ظ>%]:7ly"nd29BI+ >mBA`HNDO'"LV("8dQ5Q#mrUc%c8+I\IR>AL:}:S }'mHnV"y:h;IngCT3@ |BC!混pvg^G%&Z wK U) ; i6 wt@H?d2-FN@v@B[`FzS> ;졉{%87_trV$W"CI}\u6"ebo8l)#Gk6UD!;{C{^rp =DtSJ5 VF3oq&\Pt_)I_ڴ<`cOv-/ƥw##d1Fml&mb'`ܭ=& ŮĹF~G*M9Mղ A\?YT]VZ6+ƙ#\<_ %U7ռA !w$I͹>*SrEPaaOe;aG94qe&|IDSMZFw5kߪ5ZX9esŗ\Nv{*uqCfG<0CC3s.\@ٮ;y+ɾ8;bڤ"Yޜni̘ 1ʤnc4bI4v~68XF66m]ɺ1Hё%1fy7\b6&I;&ǝ#qq v(||Rwg{i$rEϺu\:iK@.#HD{a^dYU)GxoaOʊ(2HIkN[g*e&aEc1 m+3NKۈ4M_L-ӯU5o׵t:3nUkL;;ֲ-E$X60C-B'ip%d%&ś=prd}qx#H+6P+C^A'WwR8ԮoR$kg9$ Ct#lAQ3Cl i}Vn䥲6qہ[*; 9k_*7 >iW22'~XFĹ\xGI5CYsv.O_d:i4:Mץaǁyh.c8"=o1]uRJKxP? GP("W/˫_42=(^l O=ZaG>\N/Qu6Ia$I{nGjC+Ȍl)5l 9 ZP4t{ZYMʽ> F56ED_T䵡Rhm\D|CQ7MH6?T2U-:&[hi;,p2FgU6Kȳ{`8 n8dZq/gDDZ)?}49(.G~BkN~e @Ж9NhT [-+>|ZpZi[Af`9$ qIrk^;C#u 5²ٚZ,AjEad#b8JPL;'4aC؞vl{&['Ҕ +11r :q,cKܪ=#e~Iq̒9"K۞;{ޠeyv=KYٌ.sdEISΰ]4w8o7ܗg],c k h)pc&t-3qFzVDt28Xm],qI?k{~jFEs)nbpv3cp aγv::rP9#; LN \( +|\>HW#^\水вF>5*;.pC|ǀ8X纞IT6q+m7-|˗.GKlM3GHtƷ~ot:&LF0LCEA5Aʭy{IM#] R_Z@[ fG>By= QM;Y&9[ڹI˒h\ǵ3quzQCNILFSdcBwQbyM#bO_UT/7.]Ye2Wj'jK2(/o"dlGak 4DfG}Ã1Ŀk]рW>bnnɍne!!iD4~juo@"g(kS@` h.lnHz{ܐ N )KBŲ7XttƧ6X tcoشl쥔ψwUQJګZ+遵DNoOdQ| Ths/jm "W+\~o]_Wg5?lM5^q|sA9Egk/;r|V5elz$N^~4#F;Hڽ\e=1}6ΛSA TeN aye~9<YHz8I6GUM1W{/979m^;5C!YVk?/f9Oتd5{c멋Aa01oX^>Vv16v,я; tZwAFd͂&?'1 zw4۲ V;_QB{\% g?%ΜB/>WW ,n@a!10nb֏*DS7k*#IdW>:3soRqzPiX8V{m!ըۭ:vkLq88l&&8Z5͡ki!Q|H5gnTM6(s۲V@"0ob_TfNhUYC <}+s[$9ڶNn$Fih-["  zMrFzl4{M{ICޞa<ІB 2@KHt ylv csKOv߅KIQ"=Żۿ+#:,%]mChDE~ k|Go}ͧMѢVEӚ}6r,m`IN씟. V$-ΏGWr 7n;/s \|pW/iM4oU-R.VW4n f&R[-NO!!Kd8p|%=&R\RŇFwрY 0t/] LJjSZwX6H D <6HXPRWowX/tɡ쟠v*%wDC9KK&G^D81z{*( %-1|I]z˞3k4+۲'<R/%fvSG d._;%3"uuHAT0ֶx[ɕ9$ܚ}FMG>7-db6{@,T1һRIvqEEJ:|db' g.7To|1qgm˩~I_Fm{%sHKfpuQk#Yi"e,|vAbMj[e> ׆0r grnB($- VhXI{I >ˏrJ`ioH W\3-"5kwv\%P4w{)%U좽tV*EF4ۀP=Ԉ6bIEmH|momiM%|l_Kr<5sC%pk $Mܬne0 vd}͢Q0&8:ܙT-b=0{5AV{e#aHB4 BCEjG\m4U!}.hh[1060^ݷ '27Qn !IkI{F- m}XFM6JN\q-ﰮwXuw/bl]wo|#CFkF/ShmgK)^<9]COq^ʓ0nc_Wa<첹1Z wiew$fg.MV,V ޤV`v胶IFAaBw&;9KH䆌sV &Ա'uO+QkVỠ{7`mृkNH,"l$6Bhe%XM ;XFP9E+ M3?gG&ivh]ֹ4\5u9MBCeK9}YqS?x~.3ew0CI2e8)!r}w<5E}Oc9?͑4}-o\ ĽB/=9Gk]D~8dLZȷPx#̞V/fA+6vU~dI} 3?6IkM-{u cəٷG&5$lMoS4=ޝE!fp``Ӣ?_tSV ~yF_ i")=F%{|@u]PUiQ]DYԑ VKrX;>=AjQ%7. V$M=8>p#mz8 qvTQz^2AZ^iiFS{j]"I{Jϭ$nI_! .w9X.ZҊ)Ӱ62ơw'*G7$JQ=FȾ,8X]xj@i TUq7Yp$hCIitmEGj@3O`i[c%{P[p:wZ I+h[7Iƀ֑svhYH *\PUv&|EuOeQe[Uc7Q{_=Z0H$X]$W hvJLc]- ;%KzK/ZyiQCIHyF⣼4M;RJ ivRIQkȯvu"x%ɒٲ1ۤm4 *]uBMFl'NBlcYhRdE7CV#^?UxLΫIn"_㻊Ŏ0q'4AwcG}<#v6.pٿ q/nS߷eDs%kxq2?< 1q)?ݾW{չ= qr>ȧ?8+ue8%hTqDY딏T*縹丟u9A%܇ 6xd4sMˉeF47;.v^QsŸ̌ 4]mvS^uI#߅uiuGKifDVIw,/ӽ}LF6uZ܊NΜqWdE0P,H GL[D\:[QKkKpklJiߊX.KhK$YI-ؠ?TmǓAmi6htzl 1G ңG\ѥji&.i\MmUMm᫤F }3K{ Ge%G=6Z?r@آ<\ (nKejjm 'bE Q!ސ K`)ۭyX)bELJ8#(WEe>WXQyZfX Z,֭d8?p~IMʴ+-.g'UEҺ|ORBz= nTRސYa5W&UoFFll;?E_-.xF&g7훷e˕/,Ŗ"1ꌍ؀>\*<ƬYCPF͎{&P1[#LtMĂ$&{JB\94T :yq܅vHIŸʙKe}h..w6*,e~2$zBlo- rcD4K颙pb&XڵF.4{vuS@ɵҥDmM?'7[_6SDl9wjk@Yyos:\n4V_B䃩 BsݫrAָ2N] 4|B-Tw_X&<=-3# &)q,zˊힺ TUrIh(%;ypxj;/ n8poROŅ{uƹgstA76.ltbB)Q΄:n9IIyЂO+jbb|Mk8:c2yd8F_âP*vJ1TGVR8{cpx^dA'rIBzgC_RzR裾7 .{{kOoD.=W#;>7_?*3q$/>j -~ńZ/Gkb# n:FTi5H;] ׆NHMl}e\}&=gN:ZidŖ+~U?ዱiN𗅞ּ k{EIίQ-]W֧Ʊ"<6gkU>PAqM]7g[쾯w+^$U- 8S~푎ldVH{@ڗ1ÎrDŽynF 88vl.i< sbQVς<-NsqGeWz_k~g]@{6<0bGG{J8w= bgc~Eby / 4LxSb QrOS]*ߨ[5wENĄDX}J xsI Ì\Q3ܷ R_"fAo+Q:[Czv?zF/% ?a臖BHҺ3#_cھ% =7%E܄twlwrb<5?T|ק3Cz?Mhھ1 =/MwJn& t-{XEy΄%OK ҁQj< j#Һc,}QHWpYD^.zp}u)W?Ne!OwEi;[=d|XF?'-g{zN,>:G*Ayj %b)Õ{Z+YafA,|j~FBtX/1,lxߩ$"; \\ŋHuR얝`|9c.N7ŽBww *0yH'&xxC䤹:D)D$xݮ,iլu/c iicpJ,#w["wVCOkQ Sf<twp>Lf{`ۥJpDO/Cך0P^3zX/m'ο6P)6>] m{ !ɂ9 Zw(; "pQE&9^x6bO+@6E+$*AYuQn)k%9o0CHȫp*̙<[955=4=n[[Azկ[1e{}Fō5%q(/:k@ƗdͰ]R3cNK#X| eGu)ˏ_pot$e\ˇTLȐdm25߲cIC_bvZ8u5}-;*H̏ct9evu hdA$O$<]Ƌ:3P>YN.'dJd7{%,<. csi-WQ$3K dS%Phn_w67s5l\\9as,w[c<G^{QY1yO*ϭ>JdZxTO99G L\Jx4e(޷3FXxgd-];F %:,kI%; |ޫ֞Iĕ2OpǥskZu8lV_gsF@;N=`|7AqRM#Xֵ=;)j{ղc׻ufL  SGd*3i. p9(H36 <=丣s I9/kA}_#^ 's@f̗Yh<.{oޒ$~t[XuXV'lta֔Yhܧ9֐##5Ntnbcp,Muζbt]qJxdҶ2E\GCXCjd6- !Q'Fnmu j HPqljcV;`wRYD#h4IPY8v| i/&)!: $>KXIE/'@qDq&O`gUr3h]55~P1k`~i02`{O]. P^u i1lj6p%@pdhc$odFF!Hb 7h6Al#qsjE= H ji u*>ƋcM>B\n 貋#٬%ծ]*r͉G&ei܋9Wxwÿ f6{]sRc֦8($1G @G#HpFѪ':ۢ6h45nۓKL9g4|Jcۥ|-Mch1;nnag vC1Y50yR{]a 7Aj_B(yrYyR5\2l6ScAb6Mc6٤6;QBW7$0GnOZdI{+bKgB% G/j!*c0yR"O~1ҝq%56g9p,Lvp|h)-,Ѷ=Q[X>@O.C쉄>tMÂ/o;ݖ^K aV=pI9qEZm<и+3Y0\w?eJ1 8+i /HH,r>?15G"W94j)8s[mMňm$$Ms"ܔ~[f{.p:9InǺjAVKKKѦ1c]pCM&CtԔ\6 [ c2Y#K;XTDu0icYހZ3EGt; k7SEv2m=k{tcZKx6ӮM:FR27F=Qw$&:wcMqB3# gpĠ.t4ѧS63QHC\I=̈́- EO2<$iH$Ȓސ GV h88p5I5Ҥ;2\q$fF\푑3K5fQ>BIQddF^_СCQdE9 円v9ٯ-R1Daqd'K 6{$;Cdi\[\|˚_6yͻ Mlr7k|m2Kq%mгW죉AcNRI/{Lo'ἦG2A=to%6X /$J^Q>ipܒy #AlDoE!!ߕΗwMd5 $GP`,wFLs- ha=QVmLwOfv9 t&ljTQ};CqcK)pe6$Z]WAkZhLdr<&4>65z7oe)»{Y] MlPsM!-%snPXӥ L3`V:9ɧ>fQ c #938C97", ", c #B6B0C0", "' c #C9CBDA", ") c #DEE1EE", "$@@@$$@+@@@@@+@@@@+@@@@@@#@@$&$@$+++....", "$@@@@@+@@@$$+$@@@+++@@@@@$@@@@@@+@++.++.", "@@@@@@@+&@@&$+@@@@@@@@+++++@@@+@+$$$++..", "@@+@+@+##++++@$#++$@+@@@@++@#@@@$@$++@..", "++++@@$#+&@*#*#**###@@+++++@@@@@@++.#++.", "+@@@@@&#&&***;,,,,>;=,->;@+@@@@@@@#@+##+", "+++#+$***,,>'))))))',;;->+@@+$@@@$$+#.++", "+++$+$*#>,,>'))')'',>-->>*#@@@$@@@@@++++", "*#*$$***',,>''))))),>-->>>=*@@@@+###@+$+", "$*&$**;)',>,')))))''>-->>>>*@@@@+@$$$$.+", "+$#$*=))',,')))))',,>-;>>>>>*+@&@@$@@.+$", "****=,)))','))))',>>;;;;>;;;*++@+@@+@@++", "$***;')))'')'')',-@>-==;;;;==&@++++@$$&$", "***=;'))))''%''',% ;;===;;&==&##+@@@++@$", "****>'')))''''',,>>>;==&;;=&%&+@++#@@+@@", "**#*;,')''',,,,>>>;;===;;=%%&&@@@+@@@#@$", "*****,'''',>,,>>=;*=======*=&@@@@@@@@++$", "=;>*&>,',>,,>>-*--=========%%@+++++@@@@@", ">>>=*=>,,>,,>--;*=;=======& %@+@+++@@+@@", " ..;->>>>;-==;==== == @@@++@@+@+$", " & =>-;;==& ** ", " *;==&. @ ", " =&% . ", " *% ", " "}; [section] # Comment inside the section. old_var = old section value # UTF8 in section names, key names and values. [adição] €=¿ # The following line contains spaces but will probably be trimmed when # written back out. # Final line. allegro5-5.2.10.1/examples/data/texture.tga000066400000000000000000000143571473414355200204160ustar00rootroot00000000000000 @@~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~,,~~,,~~,,~~,,pp>>pp>>ӄpp>>pp>>ӈaa aa %aa aa ,,9>>@;FFAA   hh,,~~>>hh,,~~>>>>t9,,>>>>~~~~pp~~~~pp~~gtSS>>~~ ~~SS>>~~~~ tmmQQӂppӂ~~ppӂ~~tӃ~~Ӄ~~t~~~~xt~~~~t~~,,~~,,t(,,pp>>ӄpp>>g9QQӈ aa ,,aa Y  ,,NN>>YYAAFFAA   hh,,~~>>NNNNhh,,~~>>hh,,~~>>>>~~~~pp~~~~pp~~~~pp~~SS>>~~~~ SS>>~~ ~~SS>>~~~~ӂppӂ~~ppӂ~~ppӂ~~Ӄ~~Ӄ~~Ӄ~~~~~~~~~~~~~~~~,,##66~~,,~~,,ӄpp>>݄NN##pp>>pp>>ӈ ,, aa 1{{## aa aa ,,>>9>>FFAA@RRFFAA  >>~~>>>>t>>HH,,YY++hh,,~~>>>>~~pp~~gtYY]]OOYY~~pp~~~~ t99++YYgg YYSS>>~~~~ӂ~~tggOOggĂYYppӂ~~~~tăYYӃ~~~~xt]]YY~~~~AAtggYY~~AA~~t,,ggYY,,~~ӆ~~FF>>,,g2=OO++~~FF33EE ,,~~ ""Y CC ~~ ,,>>~~GG~~pp>>FFAA\\}}\\FFAA   >>~~>>hh,,~~>>hh,,~~>>hh,,~~>>>>~~pp~~~~pp~~~~pp~~~~pp~~ ~~SS>>~~ ~~SS>>~~ ~~SS>>~~~~ӂ~~ppӂ~~ppӂ~~ppӂ~~~~Ӄ~~Ӄ~~Ӄ~~~~~~~~~~~~AA~~AA~~AA~~~~~~~~~~,,~~FF>>,,~~FF>>,,~~FF>>,,pp>>~~ ~~ ~~ SS ~~~~~~Ӂ>>Ӈ>>Ӈ>>ӆhhTRUEVISION-XFILE.allegro5-5.2.10.1/examples/data/texture2.tga000066400000000000000000000056271473414355200205000ustar00rootroot00000000000000 uj^RJ=k28'^'#`S#`-K~F.JC;M~uj^RF8U28'#`.JC;L\DO~rj^SF9U28'#`.KB;MhHOwNPuh]RJ9U39(WBNuMPUQth]QJ=k29(TQ\Rth]QJ=k39(#c[SdT|th]RG=k29("ckV|ui^RF=j39(#b,Ks\|ti]RG=k29(#c,J>:M[R}d|ti]RG9T28(#c,J>:McGObTՅl|pi]RF9U39(#b-J>:LWBNuMPTQ[SbSfTnWv_g֋q|qi]RF9U29(#c,J?:LVCOuMPTQ[SbTiUnVv_Ӏgֈoڔ{|ph]RF9U0+(#c,K?:LcFNuMPTQ[SbTiUnWw_Ӏgֈoّwݝ|pe]RG9U0,("c-J?:LcGOuMPTQ[RbTiUnWv_gֈoّwۗ|ᦊ|qe^RF8U0+(#b,K?:LcGOtMPTQ[SbSiUnWw_Ҁgֈoّwܙޟ㯓zpe]RG9U/+(#b,J>:McGO{PQTQ[RbTiUqZv_gֈoّwܙޟ⨍淚yneZRG9U0+"~"b-J>9LcGO{OPTQ[SbTiUqYv_g։oّwܚޟ⨌䱔ynfYRF9U0+"~"b,J>:McGO{PQTR[RbSiUqZv_gֈoّwܚߢᨌ展蹝ɫf[RF8U0+"}"c-J>:LcFO{OQWR[RbTiUqZzbҀgֈoّwܙߢᨍ䱔繜ίZOF9U0+"~%U,J>9McGOzOPVR[RbTiUqZzbgֈoِwܚߣᨌ屔蹜¤ʫ׷zNC9U0+"~%V-K>:LcFO{OPVR[RbTiUqZzbgՈoّwܚߢᩍ䱕繜ʫҳ߿nB5E/+{PQVR[RbTiUqZzaԂjֈoّwܙߢ⫏尕纝¤ʫҴظbWOB6F,]SbTiUqZybԂiՈoّwܚߢ㫏屔躜ʬҳظV, mbTiUqZybԃjՈoّwܚߢ㫏䰔纜ʫҳںK!m)I{OPiUqZybԃj׋qّwܚߢ㫏峗蹜¤ʬҴڻC)J)2KVRqYzaԂj׋rّwܙߣ⫏洗繜¤ʫҳڻ5F66LO?N^SzaԂi׋rّwܚߢ⫏洗繜ʫҳۻ,!m)J66LO@NpKPeTԃj׋rّwܚߢ⫏泗輟¤ʬҳڻ!m)J66MO?MpLPSQZRaTiUmVv^gֈoّwۗ}ޠ⩎䱖軞æɪѳٺTRUEVISION-XFILE.allegro5-5.2.10.1/examples/data/welcome.voc000066400000000000000000000570611473414355200203640ustar00rootroot00000000000000Creative Voice File )^}zzzzzzzzzzzzz{{}}}}}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}~~~~~~~~~~~}}}}}}}}}}}}}}{{}}}{{}}}}}}~~~~~~~~~~~}}}}}}}}}}}}~~~}}{{{{{{{zzzzzzxxxxxxxxxxxxxxwwvvtssttssqqqqqqqssssttvwxxz{}~~{wtqmjifecbaaaabcefhilmpsvx{}~~}{xwtspmjiheba_^[ZXWUUWXZ[\^abehjloqtwz}ÿzsmhb^[XWTRQQPPQPPPPQQRTUWZ\acimszvlb[TPJFC@???@BCDFJMNPQRUX[^aefimqvz~{wtqojhebbbcfims{Ƽwme^WPJC=82.+*(((+.49?GPZep}xme\UKC;41.../259=CJPU^emsw{~~{wsmhca_\[XWUUWX[\^aehlpsx~}obUJ@<99999; #define SCREEN_W 640 #define SCREEN_H 480 #define FPS 30 // framerate #define PLAYER_SIZE 16 // radius of player circle #define PLAYER_SPEED 200 // movement rate of player in pixels/sec #define MAX_PLAYER_COUNT 32 #define DEFAULT_PORT 9234 typedef enum { PLAYER_JOIN, PLAYER_LEAVE, POSITION_UPDATE, } MESSAGE_TYPE; // message sent from client to server typedef struct { int x; // requested x movement (-1, 0, or 1) int y; // requested y movement (-1, 0, or 1) } ClientMessage; // message sent from server to client typedef struct { int player_id; MESSAGE_TYPE type; int x; // current position (x) int y; // current position (y) ALLEGRO_COLOR color; // valid when type == PLAYER_JOIN } ServerMessage; // storage for all players struct { bool active; int x, y; // current position int dx, dy; // direction of movemnt ALLEGRO_COLOR color; } players[MAX_PLAYER_COUNT]; #endif allegro5-5.2.10.1/examples/ex_acodec.c000066400000000000000000000073171473414355200173640ustar00rootroot00000000000000/* * Ryan Dickie * Audio example that loads a series of files and puts them through the mixer. * Originlly derived from the audio example on the wiki. */ #define ALLEGRO_UNSTABLE #include #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_acodec.h" #include "common.c" int main(int argc, char **argv) { ALLEGRO_VOICE *voice; ALLEGRO_MIXER *mixer; ALLEGRO_SAMPLE_INSTANCE *sample; int i; char const **filenames; int n; if (argc < 2) { n = 1; filenames = malloc(sizeof *filenames); filenames[0] = "data/welcome.wav"; } else { n = argc - 1; filenames = malloc(sizeof *filenames * n); for (i = 1; i < argc; ++i) { filenames[i - 1] = argv[i]; } } if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); al_init_acodec_addon(); if (!al_install_audio()) { abort_example("Could not init sound!\n"); } voice = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); if (!voice) { abort_example("Could not create ALLEGRO_VOICE.\n"); } mixer = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); if (!mixer) { abort_example("al_create_mixer failed.\n"); } if (!al_attach_mixer_to_voice(mixer, voice)) { abort_example("al_attach_mixer_to_voice failed.\n"); } sample = al_create_sample_instance(NULL); if (!sample) { abort_example("al_create_sample failed.\n"); } for (i = 0; i < n; ++i) { ALLEGRO_SAMPLE *sample_data = NULL; const char *filename = filenames[i]; float sample_time = 0; /* A matrix that puts everything in the left channel. */ float mono_to_stereo[] = {1.0, 0.0}; /* Load the entire sound file from disk. */ sample_data = al_load_sample(filename); if (!sample_data) { abort_example("Could not load sample from '%s'!\n", filename); continue; } if (!al_set_sample(sample, sample_data)) { abort_example("al_set_sample_instance_ptr failed.\n"); continue; } if (!al_attach_sample_instance_to_mixer(sample, mixer)) { abort_example("al_attach_sample_instance_to_mixer failed.\n"); goto done; } /* Play sample in looping mode. */ al_set_sample_instance_playmode(sample, ALLEGRO_PLAYMODE_LOOP); al_play_sample_instance(sample); sample_time = al_get_sample_instance_time(sample); log_printf("Playing '%s' (%.3f seconds) normally.\n", filename, sample_time); al_rest(sample_time); if (al_get_channel_count(al_get_sample_instance_channels(sample)) == 1) { if (!al_set_sample_instance_channel_matrix(sample, mono_to_stereo)) { abort_example("Failed to set channel matrix.\n"); } log_printf("Playing left channel only.\n"); al_rest(sample_time); } if (!al_set_sample_instance_gain(sample, 0.5)) { abort_example("Failed to set gain.\n"); } log_printf("Playing with gain 0.5.\n"); al_rest(sample_time); if (!al_set_sample_instance_gain(sample, 0.25)) { abort_example("Failed to set gain.\n"); } log_printf("Playing with gain 0.25.\n"); al_rest(sample_time); al_stop_sample_instance(sample); log_printf("Done playing '%s'\n", filename); /* Free the memory allocated. */ al_set_sample(sample, NULL); al_destroy_sample(sample_data); } al_destroy_sample_instance(sample); al_destroy_mixer(mixer); al_destroy_voice(voice); al_uninstall_audio(); done: close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_acodec_multi.c000066400000000000000000000065401473414355200205730ustar00rootroot00000000000000/* * Milan Mimica * Audio example that plays multiple files at the same time * Originlly derived from the ex_acodec example. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_acodec.h" #include "common.c" char *default_files[] = {NULL, "data/welcome.voc", "data/haiku/earth_0.ogg", "data/haiku/water_0.ogg", "data/haiku/fire_0.ogg", "data/haiku/air_0.ogg"}; int main(int argc, char **argv) { int i; ALLEGRO_SAMPLE **sample_data; ALLEGRO_SAMPLE_INSTANCE **sample; ALLEGRO_MIXER *mixer; ALLEGRO_VOICE *voice; float longest_sample; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); if (argc < 2) { log_printf("This example can be run from the command line.\nUsage: %s {audio_files}\n", argv[0]); argv = default_files; argc = 6; } al_init_acodec_addon(); if (!al_install_audio()) { abort_example("Could not init sound!\n"); } sample = malloc(argc * sizeof(*sample)); if (!sample) { abort_example("Out of memory!\n"); } sample_data = malloc(argc * sizeof(*sample_data)); if (!sample_data) { abort_example("Out of memory!\n"); } /* a voice is used for playback */ voice = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); if (!voice) { abort_example("Could not create ALLEGRO_VOICE from sample\n"); } mixer = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); if (!mixer) { abort_example("al_create_mixer failed.\n"); } if (!al_attach_mixer_to_voice(mixer, voice)) { abort_example("al_attach_mixer_to_voice failed.\n"); } for (i = 1; i < argc; ++i) { const char *filename = argv[i]; sample[i] = NULL; /* loads the entire sound file from disk into sample data */ sample_data[i] = al_load_sample(filename); if (!sample_data[i]) { abort_example("Could not load sample from '%s'!\n", filename); } sample[i] = al_create_sample_instance(sample_data[i]); if (!sample[i]) { log_printf("Could not create sample!\n"); al_destroy_sample(sample_data[i]); sample_data[i] = NULL; continue; } if (!al_attach_sample_instance_to_mixer(sample[i], mixer)) { log_printf("al_attach_sample_instance_to_mixer failed.\n"); continue; } } longest_sample = 0; for (i = 1; i < argc; ++i) { const char *filename = argv[i]; float sample_time; if (!sample[i]) continue; /* play each sample once */ al_play_sample_instance(sample[i]); sample_time = al_get_sample_instance_time(sample[i]); log_printf("Playing '%s' (%.3f seconds)\n", filename, sample_time); if (sample_time > longest_sample) longest_sample = sample_time; } al_rest(longest_sample); log_printf("Done\n"); for (i = 1; i < argc; ++i) { /* free the memory allocated when creating the sample + voice */ if (sample[i]) { al_stop_sample_instance(sample[i]); al_destroy_sample_instance(sample[i]); al_destroy_sample(sample_data[i]); } } al_destroy_mixer(mixer); al_destroy_voice(voice); free(sample); free(sample_data); al_uninstall_audio(); close_log(true); return 0; } allegro5-5.2.10.1/examples/ex_android.c000066400000000000000000000153721473414355200175660ustar00rootroot00000000000000#include #include #include #ifdef ALLEGRO_ANDROID #include /* al_android_set_apk_file_interface */ #endif ALLEGRO_DEBUG_CHANNEL("main") #define MAX_TOUCH 10 struct touch { bool down; double x, y; } touch[MAX_TOUCH]; /* debugging */ #define print_standard_path(std) \ do { \ ALLEGRO_PATH *path = al_get_standard_path(std); \ ALLEGRO_DEBUG(#std ": %s", al_path_cstr(path, '/')); \ } while (0) static void print_standard_paths(void) { print_standard_path(ALLEGRO_RESOURCES_PATH); print_standard_path(ALLEGRO_TEMP_PATH); print_standard_path(ALLEGRO_USER_DATA_PATH); print_standard_path(ALLEGRO_USER_HOME_PATH); print_standard_path(ALLEGRO_USER_SETTINGS_PATH); print_standard_path(ALLEGRO_USER_DOCUMENTS_PATH); print_standard_path(ALLEGRO_EXENAME_PATH); } static void draw_touches(void) { int i; for (i = 0; i < MAX_TOUCH; i++) { if (touch[i].down) { al_draw_filled_rectangle( touch[i].x-40, touch[i].y-40, touch[i].x+40, touch[i].y+40, al_map_rgb(100+i*20, 40+i*20, 40+i*20)); } } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *dpy; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; ALLEGRO_TIMER *timer; ALLEGRO_BITMAP *image; ALLEGRO_BITMAP *image2; (void) argc; (void) argv; ALLEGRO_DEBUG("init allegro!"); if (!al_init()) { return 1; } ALLEGRO_DEBUG("init primitives"); al_init_primitives_addon(); ALLEGRO_DEBUG("init image addon"); al_init_image_addon(); ALLEGRO_DEBUG("init touch input"); al_install_touch_input(); ALLEGRO_DEBUG("init keyboard"); al_install_keyboard(); ALLEGRO_DEBUG("creating display"); dpy = al_create_display(800, 480); if (!dpy) { ALLEGRO_ERROR("failed to create display!"); return 1; } print_standard_paths(); /* This is loaded from assets in the apk. */ #ifdef ALLEGRO_ANDROID al_android_set_apk_file_interface(); #endif image = al_load_bitmap("data/alexlogo.png"); if (!image) { ALLEGRO_DEBUG("failed to load alexlogo.png"); return 1; } #ifdef ALLEGRO_ANDROID /* Copy the .png from the .apk into the user data area. */ ALLEGRO_FILE *fin = al_fopen("data/alexlogo.png", "rb"); al_set_standard_file_interface(); ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_USER_DATA_PATH); al_set_path_filename(path, "alexlogo.png"); ALLEGRO_FILE *fout = al_fopen(al_path_cstr(path, '/'), "wb"); while (!al_feof(fin)) { char buf[1024]; int n = al_fread(fin, buf, 1024); al_fwrite(fout, buf, n); } al_fclose(fin); al_fclose(fout); /* This is now loaded with the normal stdio file interface and not * from the APK. */ image2 = al_load_bitmap(al_path_cstr(path, '/')); al_destroy_path(path); #else image2 = image; #endif al_convert_mask_to_alpha(image, al_map_rgb(255,0,255)); if (image2) al_convert_mask_to_alpha(image2, al_map_rgb(255,0,255)); queue = al_create_event_queue(); al_register_event_source(queue, al_get_display_event_source(dpy)); al_register_event_source(queue, al_get_touch_input_event_source()); al_register_event_source(queue, al_get_keyboard_event_source()); timer = al_create_timer(1/60.0); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); bool draw = true; bool running = true; int count = 0; while (running) { al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_TOUCH_BEGIN: //ALLEGRO_DEBUG("touch %i begin", event.touch.id); touch[event.touch.id].down = true; touch[event.touch.id].x = event.touch.x; touch[event.touch.id].y = event.touch.y; break; case ALLEGRO_EVENT_TOUCH_END: //ALLEGRO_DEBUG("touch %i end", event.touch.id); touch[event.touch.id].down = false; touch[event.touch.id].x = 0.0; touch[event.touch.id].y = 0.0; break; case ALLEGRO_EVENT_TOUCH_MOVE: //ALLEGRO_DEBUG("touch %i move: %fx%f", event.touch.id, event.touch.x, event.touch.y); touch[event.touch.id].x = event.touch.x; touch[event.touch.id].y = event.touch.y; break; case ALLEGRO_EVENT_TOUCH_CANCEL: //ALLEGRO_DEBUG("touch %i canceled", event.touch.id); break; case ALLEGRO_EVENT_KEY_UP: if (event.keyboard.keycode == ALLEGRO_KEY_BACK) { ALLEGRO_DEBUG("back key pressed, exit!"); running = false; } else { ALLEGRO_DEBUG("%i key pressed", event.keyboard.keycode); } break; case ALLEGRO_EVENT_TIMER: draw = true; if (count == 60) { ALLEGRO_DEBUG("tick"); count = 0; } count++; break; case ALLEGRO_EVENT_DISPLAY_CLOSE: ALLEGRO_DEBUG("display close"); running = false; break; case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING: ALLEGRO_DEBUG("halt drawing"); // Stop the timer so we don't run at all while our display isn't // active. al_stop_timer(timer); ALLEGRO_DEBUG("after set target"); draw = false; al_acknowledge_drawing_halt(dpy); break; case ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING: ALLEGRO_DEBUG("resume drawing"); al_acknowledge_drawing_resume(dpy); ALLEGRO_DEBUG("done waiting for surface recreated"); al_start_timer(timer); break; case ALLEGRO_EVENT_DISPLAY_RESIZE: ALLEGRO_DEBUG("display resize"); al_acknowledge_resize(dpy); ALLEGRO_DEBUG("done resize"); break; } if (draw && al_event_queue_is_empty(queue)) { draw = false; al_clear_to_color(al_map_rgb(255, 255, 255)); if (image) { al_draw_bitmap(image, al_get_display_width(dpy)/2 - al_get_bitmap_width(image)/2, al_get_display_height(dpy)/2 - al_get_bitmap_height(image)/2, 0); } if (image2) { al_draw_bitmap(image2, al_get_display_width(dpy)/2 - al_get_bitmap_width(image)/2, al_get_display_height(dpy)/2 + al_get_bitmap_height(image)/2, 0); } draw_touches(); al_flip_display(); } } ALLEGRO_DEBUG("done"); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_audio_chain.cpp000066400000000000000000000547341473414355200207560ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * * Demonstrate the audio addons. */ #include #include #include #include #include #include #include #include #include #include #include "common.c" #define DISP_W 800 #define DISP_H 600 using namespace std; class Element; class Voice; class Mixer; class SampleInstance; class Sample; class Audiostream; struct Context { ALLEGRO_FONT *font; ALLEGRO_COLOR bg; ALLEGRO_COLOR fg; ALLEGRO_COLOR fill; ALLEGRO_COLOR disabled; ALLEGRO_COLOR highlight; }; class Element { public: Element(); virtual ~Element() {}; void set_pos(int x, int y); void set_random_pos(); bool attach(Element *elt); bool detach(); bool is_attached_to(Element const *elt); virtual bool is_playing() const = 0; virtual bool toggle_playing() = 0; virtual float get_gain() const = 0; virtual bool adjust_gain(float d) = 0; void draw(Context const& ctx, bool highlight) const; void draw_arrow(Context const& ctx, float px, float py, bool highlight) const; void move_by(int dx, int dy); bool contains(int x, int y) const; void output_point(float & ox, float & oy) const; void input_point(float & ox, float & oy) const; virtual char const *get_label() const = 0; typedef vector::iterator iter; protected: int x, y, w, h; private: virtual bool do_attach(Mixer & mixer); virtual bool do_attach(SampleInstance & spl); virtual bool do_attach(Audiostream & stream); virtual bool do_detach() = 0; void set_attached_to(Element const *elt); Element const *attached_to; }; class Voice : public Element { public: Voice(); ~Voice(); bool valid() const; bool is_playing() const; bool toggle_playing(); float get_gain() const; bool adjust_gain(float d); char const *get_label() const; private: bool do_attach(Mixer & mixer); bool do_attach(SampleInstance & spl); bool do_attach(Audiostream & stream); bool do_detach(); ALLEGRO_VOICE *voice; }; class Mixer : public Element { public: Mixer(); ~Mixer(); operator ALLEGRO_MIXER *() const { return mixer; } bool is_playing() const; bool toggle_playing(); float get_gain() const; bool adjust_gain(float d); char const *get_label() const; private: bool do_attach(Mixer & mixer); bool do_attach(SampleInstance & spl); bool do_attach(Audiostream & stream); bool do_detach(); ALLEGRO_MIXER *mixer; }; class SampleInstance : public Element { public: SampleInstance(); ~SampleInstance(); operator ALLEGRO_SAMPLE_INSTANCE *() const { return splinst; } bool is_playing() const; bool toggle_playing(); float get_gain() const; bool adjust_gain(float d); char const *get_label() const; bool set_sample(Sample const & wav); private: bool do_detach(); ALLEGRO_SAMPLE_INSTANCE *splinst; Sample const *spl; unsigned pos; }; class Sample { public: Sample(char const *filename); ~Sample(); operator ALLEGRO_SAMPLE *() const { return spl; } bool valid() const; string const& get_filename() const; private: ALLEGRO_SAMPLE *spl; string filename; }; class Audiostream : public Element { public: Audiostream(string const& filename); ~Audiostream(); operator ALLEGRO_AUDIO_STREAM *() const { return stream; } bool valid() const; bool is_playing() const; bool toggle_playing(); float get_gain() const; bool adjust_gain(float d); char const *get_label() const; private: bool do_detach(); ALLEGRO_AUDIO_STREAM *stream; string filename; }; /*---------------------------------------------------------------------------*/ static ALLEGRO_PATH *make_path(char const *str) { static ALLEGRO_PATH *dir; ALLEGRO_PATH *path; if (!dir) { dir = al_get_standard_path(ALLEGRO_RESOURCES_PATH); #ifdef ALLEGRO_MSVC { /* Hack to cope automatically with MSVC workspaces. */ const char *last = al_get_path_component(dir, -1); if (0 == strcmp(last, "Debug") || 0 == strcmp(last, "RelWithDebInfo") || 0 == strcmp(last, "Release") || 0 == strcmp(last, "Profile")) { al_remove_path_component(dir, -1); } } #endif } path = al_create_path(str); al_rebase_path(dir, path); return path; } static void basename(const string & filename, string & out) { size_t pos = filename.find_last_of("/"); if (pos != string::npos) out = filename.substr(pos + 1); else out = filename; } static float clamp(float lo, float mid, float hi) { if (mid < lo) return lo; if (mid > hi) return hi; return mid; } /*---------------------------------------------------------------------------*/ Element::Element() : x(0), y(0), w(40), h(40), attached_to(0) { } void Element::set_pos(int x, int y) { this->x = x; this->y = y; } void Element::set_random_pos() { /* Could be smarter. */ x = rand() % (DISP_W - w); y = rand() % (DISP_H - h); } bool Element::attach(Element *elt) { Mixer *mixer; SampleInstance *splinst; Audiostream *stream; bool rc = false; if ((mixer = dynamic_cast(elt))) { rc = do_attach(*mixer); } else if ((splinst = dynamic_cast(elt))) { rc = do_attach(*splinst); } else if ((stream = dynamic_cast(elt))) { rc = do_attach(*stream); } if (rc) { elt->set_attached_to(this); } return rc; } bool Element::do_attach(Mixer & other) { (void)other; return false; } bool Element::do_attach(SampleInstance & other) { (void)other; return false; } bool Element::do_attach(Audiostream & other) { (void)other; return false; } bool Element::detach() { bool rc = attached_to && do_detach(); if (rc) { attached_to = NULL; } return rc; } void Element::set_attached_to(Element const *attached_to) { this->attached_to = attached_to; } bool Element::is_attached_to(Element const *elt) { return attached_to == elt; } void Element::draw(Context const& ctx, bool highlight) const { if (attached_to) { float x2, y2; attached_to->input_point(x2, y2); draw_arrow(ctx, x2, y2, highlight); } ALLEGRO_COLOR textcol = ctx.fg; ALLEGRO_COLOR boxcol = ctx.fg; if (highlight) boxcol = ctx.highlight; if (!is_playing()) textcol = ctx.disabled; float rad = 7.0; al_draw_filled_rounded_rectangle(x+0.5, y+0.5, x+w-0.5, y+h-0.5, rad, rad, ctx.fill); al_draw_rounded_rectangle(x+0.5, y+0.5, x+w-0.5, y+h-0.5, rad, rad, boxcol, 1.0); float th = al_get_font_line_height(ctx.font); al_draw_text(ctx.font, textcol, x + w/2, y + h/2 - th/2, ALLEGRO_ALIGN_CENTRE, get_label()); float gain = get_gain(); if (gain > 0.0) { float igain = 1.0 - clamp(0.0, gain, 2.0)/2.0; al_draw_rectangle(x+w+1.5, y+h*igain, x+w+3.5, y+h, ctx.fg, 1.0); } } void Element::draw_arrow(Context const& ctx, float x2, float y2, bool highlight) const { float x1, y1; ALLEGRO_COLOR col; output_point(x1, y1); col = (highlight ? ctx.highlight : ctx.fg); al_draw_line(x1, y1, x2, y2, col, 1.0); float a = atan2(y1-y2, x1-x2); float a1 = a + 0.5; float a2 = a - 0.5; float len = 7.0; al_draw_line(x2, y2, x2 + len*cos(a1), y2 + len*sin(a1), col, 1.0); al_draw_line(x2, y2, x2 + len*cos(a2), y2 + len*sin(a2), col, 1.0); } void Element::move_by(int dx, int dy) { x += dx; y += dy; if (x < 0) x = 0; if (y < 0) y = 0; if (x+w > DISP_W) x = DISP_W-w; if (y+h > DISP_H) y = DISP_H-h; } bool Element::contains(int px, int py) const { return px >= x && px < x + w && py >= y && py < y + h; } void Element::output_point(float & ox, float & oy) const { ox = x + w/2; oy = y; } void Element::input_point(float & ox, float & oy) const { ox = x + w/2; oy = y + h; } /*---------------------------------------------------------------------------*/ Voice::Voice() { set_random_pos(); voice = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); } Voice::~Voice() { al_destroy_voice(voice); } bool Voice::valid() const { return (voice != NULL); } bool Voice::do_attach(Mixer & mixer) { return al_attach_mixer_to_voice(mixer, voice); } bool Voice::do_attach(SampleInstance & spl) { return al_attach_sample_instance_to_voice(spl, voice); } bool Voice::do_attach(Audiostream & stream) { return al_attach_audio_stream_to_voice(stream, voice); } bool Voice::do_detach() { return false; } bool Voice::is_playing() const { return al_get_voice_playing(voice); } bool Voice::toggle_playing() { bool playing = al_get_voice_playing(voice); return al_set_voice_playing(voice, !playing); } float Voice::get_gain() const { return 0.0; } bool Voice::adjust_gain(float d) { (void)d; return false; } char const *Voice::get_label() const { return "Voice"; } /*---------------------------------------------------------------------------*/ Mixer::Mixer() { set_random_pos(); mixer = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); } Mixer::~Mixer() { al_destroy_mixer(mixer); } bool Mixer::do_attach(Mixer & other) { return al_attach_mixer_to_mixer(other, mixer); } bool Mixer::do_attach(SampleInstance & spl) { return al_attach_sample_instance_to_mixer(spl, mixer); } bool Mixer::do_attach(Audiostream & stream) { return al_attach_audio_stream_to_mixer(stream, mixer); } bool Mixer::do_detach() { return al_detach_mixer(mixer); } bool Mixer::is_playing() const { return al_get_mixer_playing(mixer); } bool Mixer::toggle_playing() { bool playing = al_get_mixer_playing(mixer); return al_set_mixer_playing(mixer, !playing); } float Mixer::get_gain() const { return al_get_mixer_gain(mixer); } bool Mixer::adjust_gain(float d) { float gain = al_get_mixer_gain(mixer) + d; gain = clamp(0, gain, 2); return al_set_mixer_gain(mixer, gain); } char const *Mixer::get_label() const { return "Mixer"; } /*---------------------------------------------------------------------------*/ SampleInstance::SampleInstance() : spl(NULL), pos(0) { w = 150; set_random_pos(); splinst = al_create_sample_instance(NULL); } SampleInstance::~SampleInstance() { al_destroy_sample_instance(splinst); } bool SampleInstance::do_detach() { return al_detach_sample_instance(splinst); } bool SampleInstance::is_playing() const { return al_get_sample_instance_playing(splinst); } bool SampleInstance::toggle_playing() { bool playing = is_playing(); if (playing) pos = al_get_sample_instance_position(splinst); else al_set_sample_instance_position(splinst, pos); return al_set_sample_instance_playing(splinst, !playing); } float SampleInstance::get_gain() const { return al_get_sample_instance_gain(splinst); } bool SampleInstance::adjust_gain(float d) { float gain = al_get_sample_instance_gain(splinst) + d; gain = clamp(0, gain, 2); return al_set_sample_instance_gain(splinst, gain); } bool SampleInstance::set_sample(Sample const & spl) { bool playing = is_playing(); bool rc = al_set_sample(splinst, spl); if (rc) { this->spl = &spl; al_set_sample_instance_playmode(splinst, ALLEGRO_PLAYMODE_LOOP); al_set_sample_instance_playing(splinst, playing); } return rc; } char const *SampleInstance::get_label() const { if (spl) { return spl->get_filename().c_str(); } return "No sample"; } /*---------------------------------------------------------------------------*/ Sample::Sample(char const *filename) { spl = al_load_sample(filename); basename(filename, this->filename); } Sample::~Sample() { al_destroy_sample(spl); } bool Sample::valid() const { return spl; } string const& Sample::get_filename() const { return filename; } /*---------------------------------------------------------------------------*/ Audiostream::Audiostream(string const& filename) { w = 150; set_random_pos(); basename(filename, this->filename); stream = al_load_audio_stream(filename.c_str(), 4, 2048); if (stream) { al_set_audio_stream_playmode(stream, ALLEGRO_PLAYMODE_LOOP); } } Audiostream::~Audiostream() { al_destroy_audio_stream(stream); } bool Audiostream::valid() const { return stream; } bool Audiostream::do_detach() { return al_detach_audio_stream(stream); } bool Audiostream::is_playing() const { return al_get_audio_stream_playing(stream); } bool Audiostream::toggle_playing() { bool playing = al_get_audio_stream_playing(stream); return al_set_audio_stream_playing(stream, !playing); } float Audiostream::get_gain() const { return al_get_audio_stream_gain(stream); } bool Audiostream::adjust_gain(float d) { float gain = al_get_audio_stream_gain(stream) + d; gain = clamp(0, gain, 2); return al_set_audio_stream_gain(stream, gain); } char const *Audiostream::get_label() const { return filename.c_str(); } /*---------------------------------------------------------------------------*/ class Prog { public: Prog(); void init(); void add_sample(char const *filename); void add_stream_path(char const *filename); void initial_config(); void run(void); private: Voice *new_voice(); Mixer *new_mixer(); SampleInstance *new_sample_instance(); Audiostream *new_audiostream(); void process_mouse_button_down(int mb, int mx, int my); void process_mouse_button_up(int mb, int mx, int my); void process_mouse_axes(int mx, int my, int dx, int dy); void process_mouse_wheel(int dz); void process_key_char(int unichar); Element *find_element(int x, int y); void delete_element(Element *elt); void redraw(); ALLEGRO_DISPLAY *dpy; ALLEGRO_EVENT_QUEUE *queue; Context ctx; vector samples; vector stream_paths; vector elements; int cur_button; Element *cur_element; float connect_x; float connect_y; }; Prog::Prog() : cur_button(0), cur_element(NULL) { } void Prog::init() { if (!al_init()) { abort_example("Could not initialise Allegro.\n"); } if (!al_init_primitives_addon()) { abort_example("Could not initialise primitives.\n"); } al_init_font_addon(); if (!al_init_ttf_addon()) { abort_example("Could not initialise TTF fonts.\n"); } if (!al_install_audio()) { abort_example("Could not initialise audio.\n"); } if (!al_init_acodec_addon()) { abort_example("Could not initialise audio codecs.\n"); } init_platform_specific(); if (!(dpy = al_create_display(800, 600))) { abort_example("Could not create display.\n"); } if (!al_install_keyboard()) { abort_example("Could not install keyboard.\n"); } if (!al_install_mouse()) { abort_example("Could not install mouse.\n"); } ctx.font = al_load_ttf_font("data/DejaVuSans.ttf", 10, 0); if (!ctx.font) { abort_example("Could not load font.\n"); } ctx.bg = al_map_rgb_f(0.9, 0.9, 0.9); ctx.fg = al_map_rgb_f(0, 0, 0); ctx.fill = al_map_rgb_f(0.85, 0.85, 0.85); ctx.disabled = al_map_rgb_f(0.6, 0.6, 0.6); ctx.highlight = al_map_rgb_f(1, 0.1, 0.1); queue = al_create_event_queue(); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(dpy)); } void Prog::add_sample(char const *filename) { ALLEGRO_PATH *path = make_path(filename); Sample *spl = new Sample(al_path_cstr(path, '/')); if (spl) { samples.push_back(spl); } else { delete spl; } al_destroy_path(path); } void Prog::add_stream_path(char const *filename) { ALLEGRO_PATH *path = make_path(filename); stream_paths.push_back(al_path_cstr(path, '/')); al_destroy_path(path); } void Prog::initial_config() { Voice *voice = new_voice(); if (!voice) { abort_example("Could not create initial voice.\n"); } voice->set_pos(300, 50); Mixer *mixer = new_mixer(); mixer->set_pos(300, 150); voice->attach(mixer); SampleInstance *splinst = new_sample_instance(); splinst->set_pos(220, 300); mixer->attach(splinst); splinst->toggle_playing(); SampleInstance *splinst2 = new_sample_instance(); splinst2->set_pos(120, 240); mixer->attach(splinst2); splinst2->toggle_playing(); Mixer *mixer2 = new_mixer(); mixer2->set_pos(500, 250); mixer->attach(mixer2); Audiostream *stream; if ((stream = new_audiostream())) { stream->set_pos(450, 350); mixer2->attach(stream); } } Voice *Prog::new_voice() { Voice *voice = new Voice(); if (voice->valid()) { elements.push_back(voice); } else { delete voice; voice = NULL; } return voice; } Mixer *Prog::new_mixer() { Mixer *mixer = new Mixer(); elements.push_back(mixer); return mixer; } SampleInstance *Prog::new_sample_instance() { SampleInstance *splinst = new SampleInstance(); if (samples.size() > 0) { static unsigned i = 0; unsigned n = (i++) % samples.size(); splinst->set_sample(*samples[n]); i++; } elements.push_back(splinst); return splinst; } Audiostream *Prog::new_audiostream() { if (stream_paths.size() > 0) { static unsigned i = 0; unsigned n = (i++) % stream_paths.size(); Audiostream *stream = new Audiostream(stream_paths[n]); if (stream->valid()) { elements.push_back(stream); return stream; } delete stream; } return NULL; } void Prog::run() { for (;;) { if (al_is_event_queue_empty(queue)) { redraw(); } ALLEGRO_EVENT ev; al_wait_for_event(queue, &ev); switch (ev.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: return; case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: process_mouse_button_down(ev.mouse.button, ev.mouse.x, ev.mouse.y); break; case ALLEGRO_EVENT_MOUSE_BUTTON_UP: process_mouse_button_up(ev.mouse.button, ev.mouse.x, ev.mouse.y); break; case ALLEGRO_EVENT_MOUSE_AXES: if (ev.mouse.dz) { process_mouse_wheel(ev.mouse.dz); } else { process_mouse_axes(ev.mouse.x, ev.mouse.y, ev.mouse.dx, ev.mouse.dy); } break; case ALLEGRO_EVENT_KEY_CHAR: if (ev.keyboard.unichar == 27) { return; } process_key_char(ev.keyboard.unichar); break; } } } void Prog::process_mouse_button_down(int mb, int mx, int my) { if (cur_button == 0) { cur_element = find_element(mx, my); if (cur_element) { cur_button = mb; } if (cur_button == 2) { connect_x = mx; connect_y = my; } } } void Prog::process_mouse_button_up(int mb, int mx, int my) { if (mb != cur_button) return; if (cur_button == 2 && cur_element) { Element *sink = find_element(mx, my); cur_element->detach(); if (sink && sink != cur_element) { sink->attach(cur_element); } cur_element = NULL; } cur_button = 0; } void Prog::process_mouse_axes(int mx, int my, int dx, int dy) { if (cur_button == 1 && cur_element) { cur_element->move_by(dx, dy); } if (cur_button == 2 && cur_element) { connect_x = mx; connect_y = my; } } void Prog::process_mouse_wheel(int dz) { if (cur_element) { cur_element->adjust_gain(dz * 0.1); } } void Prog::process_key_char(int unichar) { int upper = toupper(unichar); if (upper == 'V') { new_voice(); } else if (upper == 'M') { new_mixer(); } else if (upper == 'S') { new_sample_instance(); } else if (upper == 'A') { new_audiostream(); } else if (upper == ' ') { if (cur_element) { cur_element->toggle_playing(); } } else if (upper == 'X') { if (cur_element) { delete_element(cur_element); cur_element = NULL; } } else if (upper >= '1' && upper <= '9') { unsigned n = upper - '1'; SampleInstance *splinst; if (n < samples.size() && (splinst = dynamic_cast(cur_element))) { splinst->set_sample(*samples.at(n)); } } } Element *Prog::find_element(int x, int y) { for (Element::iter it = elements.begin(); it != elements.end(); it++) { if ((*it)->contains(x, y)) return *it; } return NULL; } void Prog::delete_element(Element *elt) { for (Element::iter it = elements.begin(); it != elements.end(); it++) { if ((*it)->is_attached_to(elt)) { (*it)->detach(); } } for (Element::iter it = elements.begin(); it != elements.end(); it++) { if (*it == elt) { (*it)->detach(); delete *it; elements.erase(it); break; } } } void Prog::redraw() { al_clear_to_color(ctx.bg); for (Element::iter it = elements.begin(); it != elements.end(); it++) { bool highlight = (*it == cur_element); (*it)->draw(ctx, highlight); if (highlight && cur_button == 2) { (*it)->draw_arrow(ctx, connect_x, connect_y, highlight); } } float y = al_get_display_height(dpy); float th = al_get_font_line_height(ctx.font); al_draw_textf(ctx.font, ctx.fg, 0, y-th*2, ALLEGRO_ALIGN_LEFT, "Create [v]oices, [m]ixers, [s]ample instances, [a]udiostreams. " "[SPACE] pause playback. " "[1]-[9] set sample. " "[x] delete."); al_draw_textf(ctx.font, ctx.fg, 0, y-th*1, ALLEGRO_ALIGN_LEFT, "Mouse: [LMB] select element. " "[RMB] attach sources to sinks " "(sample->mixer, mixer->mixer, mixer->voice, sample->voice)"); al_flip_display(); } int main(int argc, char **argv) { Prog prog; prog.init(); prog.add_sample("data/haiku/air_0.ogg"); prog.add_sample("data/haiku/air_1.ogg"); prog.add_sample("data/haiku/earth_0.ogg"); prog.add_sample("data/haiku/earth_1.ogg"); prog.add_sample("data/haiku/earth_2.ogg"); prog.add_sample("data/haiku/fire_0.ogg"); prog.add_sample("data/haiku/fire_1.ogg"); prog.add_sample("data/haiku/water_0.ogg"); prog.add_sample("data/haiku/water_1.ogg"); prog.add_stream_path("../demos/cosmic_protector/data/sfx/game_music.ogg"); prog.add_stream_path("../demos/cosmic_protector/data/sfx/title_music.ogg"); prog.initial_config(); prog.run(); /* Let Allegro handle the cleanup. */ return 0; (void)argc; (void)argv; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_audio_devices.c000066400000000000000000000014071473414355200207430ustar00rootroot00000000000000/* This example lists the available audio devices. */ #define ALLEGRO_UNSTABLE #include #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "common.c" int main(int argc, char **argv) { (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } if (!al_install_audio()) { abort_example("Could not init sound!\n"); } open_log(); int count = al_get_num_audio_output_devices(); if (count < 0) { log_printf("Platform not supported.\n"); goto done; } for (int i = 0; i < count; i++) { const ALLEGRO_AUDIO_DEVICE* device = al_get_audio_output_device(i); log_printf("%s\n", al_get_audio_device_name(device)); } done: close_log(true); } allegro5-5.2.10.1/examples/ex_audio_props.cpp000066400000000000000000000122411473414355200210220ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * * Test audio properties (gain and panning, for now). */ #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_primitives.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_acodec.h" #include "nihgui.hpp" #include #include "common.c" ALLEGRO_FONT *font_gui; ALLEGRO_SAMPLE *sample; ALLEGRO_SAMPLE_INSTANCE *sample_inst; class Prog { private: Dialog d; Label length_label; HSlider length_slider; ToggleButton pan_button; HSlider pan_slider; Label speed_label; HSlider speed_slider; ToggleButton bidir_button; ToggleButton play_button; Label gain_label; VSlider gain_slider; Label mixer_gain_label; VSlider mixer_gain_slider; Label two_label; Label one_label; Label zero_label; public: Prog(const Theme & theme, ALLEGRO_DISPLAY *display, unsigned int instance_len); void run(); void update_properties(); }; Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display, unsigned int instance_len) : d(Dialog(theme, display, 40, 20)), length_label(Label("Length")), length_slider(HSlider(instance_len, instance_len)), pan_button(ToggleButton("Pan")), pan_slider(HSlider(1000, 2000)), speed_label(Label("Speed")), speed_slider(HSlider(1000, 5000)), bidir_button(ToggleButton("Bidir")), play_button(ToggleButton("Play")), gain_label(Label("Gain")), gain_slider(VSlider(1000, 2000)), mixer_gain_label(Label("Mixer gain")), mixer_gain_slider(VSlider(1000, 2000)), two_label(Label("2.0")), one_label(Label("1.0")), zero_label(Label("0.0")) { pan_button.set_pushed(true); play_button.set_pushed(true); d.add(length_label, 2, 8, 4, 1); d.add(length_slider, 6, 8, 22, 1); d.add(pan_button, 2, 10, 4, 1); d.add(pan_slider, 6, 10, 22, 1); d.add(speed_label, 2, 12, 4, 1); d.add(speed_slider, 6, 12, 22, 1); d.add(bidir_button, 2, 14, 4, 1); d.add(play_button, 6, 14, 4, 1); d.add(gain_label, 29, 1, 2, 1); d.add(gain_slider, 29, 2, 2, 17); d.add(mixer_gain_label, 33, 1, 6, 1); d.add(mixer_gain_slider, 35, 2, 2, 17); d.add(two_label, 32, 2, 2, 1); d.add(one_label, 32, 10, 2, 1); d.add(zero_label, 32, 18, 2, 1); } void Prog::run() { d.prepare(); while (!d.is_quit_requested()) { if (d.is_draw_requested()) { update_properties(); al_clear_to_color(al_map_rgb(128, 128, 128)); d.draw(); al_flip_display(); } d.run_step(true); } } void Prog::update_properties() { int length; float pan; float speed; float gain; float mixer_gain; if (pan_button.get_pushed()) pan = pan_slider.get_cur_value() / 1000.0f - 1.0f; else pan = ALLEGRO_AUDIO_PAN_NONE; al_set_sample_instance_pan(sample_inst, pan); speed = speed_slider.get_cur_value() / 1000.0f; al_set_sample_instance_speed(sample_inst, speed); length = length_slider.get_cur_value(); al_set_sample_instance_length(sample_inst, length); if (bidir_button.get_pushed()) al_set_sample_instance_playmode(sample_inst, ALLEGRO_PLAYMODE_BIDIR); else al_set_sample_instance_playmode(sample_inst, ALLEGRO_PLAYMODE_LOOP); al_set_sample_instance_playing(sample_inst, play_button.get_pushed()); gain = gain_slider.get_cur_value() / 1000.0f; al_set_sample_instance_gain(sample_inst, gain); mixer_gain = mixer_gain_slider.get_cur_value() / 1000.0f; al_set_mixer_gain(al_get_default_mixer(), mixer_gain); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; const char *filename; if (argc >= 2) { filename = argv[1]; } else { filename = "data/welcome.wav"; } if (!al_init()) { abort_example("Could not init Allegro\n"); } al_install_keyboard(); al_install_mouse(); al_init_font_addon(); al_init_primitives_addon(); al_init_acodec_addon(); init_platform_specific(); if (!al_install_audio()) { abort_example("Could not init sound!\n"); } if (!al_reserve_samples(1)) { abort_example("Could not set up voice and mixer.\n"); } sample = al_load_sample(filename); if (!sample) { abort_example("Could not load sample from '%s'!\n", filename); } al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(640, 480); if (!display) { abort_example("Unable to create display\n"); } font_gui = al_create_builtin_font(); if (!font_gui) { abort_example("Failed to create builtin font\n"); } /* Loop the sample. */ sample_inst = al_create_sample_instance(sample); al_set_sample_instance_playmode(sample_inst, ALLEGRO_PLAYMODE_LOOP); al_attach_sample_instance_to_mixer(sample_inst, al_get_default_mixer()); al_play_sample_instance(sample_inst); /* Don't remove these braces. */ { Theme theme(font_gui); Prog prog(theme, display, al_get_sample_instance_length(sample_inst)); prog.run(); } al_destroy_sample_instance(sample_inst); al_destroy_sample(sample); al_uninstall_audio(); al_destroy_font(font_gui); return 0; (void)argc; (void)argv; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_audio_simple.c000066400000000000000000000204031473414355200206070ustar00rootroot00000000000000/* * Example program for the Allegro library. * * Demonstrate 'simple' audio interface. */ #define ALLEGRO_UNSTABLE #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_acodec.h" #include "common.c" #define RESERVED_SAMPLES 16 #define MAX_SAMPLE_DATA 10 const char *default_files[] = {NULL, "data/welcome.wav", "data/haiku/fire_0.ogg", "data/haiku/fire_1.ogg", "data/haiku/fire_2.ogg", "data/haiku/fire_3.ogg", "data/haiku/fire_4.ogg", "data/haiku/fire_5.ogg", "data/haiku/fire_6.ogg", "data/haiku/fire_7.ogg", }; int main(int argc, const char *argv[]) { ALLEGRO_SAMPLE *sample_data[MAX_SAMPLE_DATA] = {NULL}; ALLEGRO_DISPLAY *display = NULL; ALLEGRO_EVENT_QUEUE *event_queue; ALLEGRO_EVENT event; ALLEGRO_SAMPLE_ID sample_id; bool sample_id_valid = false; ALLEGRO_TIMER* timer; ALLEGRO_FONT* font; ALLEGRO_AUDIO_STREAM *music = NULL; int i; bool panning = false; if (!al_init()) { abort_example("Could not init Allegro.\n"); } if (!al_init_font_addon()) { abort_example("Could not init the font addon.\n"); } open_log(); if (argc < 2) { log_printf("This example can be run from the command line.\nUsage: %s {audio_files}\n", argv[0]); argv = default_files; argc = 10; } argc--; argv++; al_install_keyboard(); display = al_create_display(640, 480); if (!display) { abort_example("Could not create display\n"); } font = al_create_builtin_font(); timer = al_create_timer(1/60.0); al_start_timer(timer); event_queue = al_create_event_queue(); al_register_event_source(event_queue, al_get_keyboard_event_source()); al_register_event_source(event_queue, al_get_display_event_source(display)); al_register_event_source(event_queue, al_get_timer_event_source(timer)); al_init_acodec_addon(); Restart: if (!al_install_audio()) { abort_example("Could not init sound!\n"); } if (!al_reserve_samples(RESERVED_SAMPLES)) { abort_example("Could not set up voice and mixer.\n"); } memset(sample_data, 0, sizeof(sample_data)); for (i = 0; i < argc && i < MAX_SAMPLE_DATA; i++) { const char *filename = argv[i]; /* Load the entire sound file from disk. */ sample_data[i] = al_load_sample(argv[i]); if (!sample_data[i]) { log_printf("Could not load sample from '%s'!\n", filename); continue; } } log_printf( "Press digits to play sounds.\n" "Space to stop sounds.\n" "Add Alt to play sounds repeatedly.\n" "'p' to pan the last played sound.\n" "Escape to quit.\n"); while (true) { al_wait_for_event(event_queue, &event); if (event.type == ALLEGRO_EVENT_KEY_CHAR) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } if (event.keyboard.unichar == ' ') { log_printf("Stopping all sounds\n"); al_stop_samples(); if (music) { al_set_audio_stream_playing(music, false); } } if (event.keyboard.keycode >= ALLEGRO_KEY_0 && event.keyboard.keycode <= ALLEGRO_KEY_9) { bool loop = event.keyboard.modifiers & ALLEGRO_KEYMOD_ALT; bool bidir = event.keyboard.modifiers & ALLEGRO_KEYMOD_CTRL; bool reversed = event.keyboard.modifiers & ALLEGRO_KEYMOD_SHIFT; i = (event.keyboard.keycode - ALLEGRO_KEY_0 + 9) % 10; if (sample_data[i]) { ALLEGRO_SAMPLE_ID new_sample_id; ALLEGRO_PLAYMODE playmode; const char* playmode_str; if (loop) { playmode = ALLEGRO_PLAYMODE_LOOP; playmode_str = "on a loop"; } else if (bidir) { playmode = ALLEGRO_PLAYMODE_BIDIR; playmode_str = "on a bidirectional loop"; } else { playmode = ALLEGRO_PLAYMODE_ONCE; playmode_str = "once"; } bool ret = al_play_sample(sample_data[i], 1.0, 0.0, 1.0, playmode, &new_sample_id); if (reversed) { ALLEGRO_SAMPLE_INSTANCE* inst = al_lock_sample_id(&new_sample_id); al_set_sample_instance_position(inst, al_get_sample_instance_length(inst) - 1); al_set_sample_instance_speed(inst, -1); al_unlock_sample_id(&new_sample_id); } if (ret) { log_printf("Playing %d %s\n", i, playmode_str); } else { log_printf( "al_play_sample_data failed, perhaps too many sounds\n"); } if (!panning) { if (ret) { sample_id = new_sample_id; sample_id_valid = true; } } } } if (event.keyboard.unichar == 'p') { if (sample_id_valid) { panning = !panning; if (panning) { log_printf("Panning\n"); } else { log_printf("Not panning\n"); } } } if (event.keyboard.unichar == 'm') { music = al_play_audio_stream("../demos/cosmic_protector/data/sfx/title_music.ogg"); } /* Hidden feature: restart audio subsystem. * For debugging race conditions on shutting down the audio. */ if (event.keyboard.unichar == 'r') { for (i = 0; i < argc && i < MAX_SAMPLE_DATA; i++) { if (sample_data[i]) al_destroy_sample(sample_data[i]); } al_uninstall_audio(); goto Restart; } } else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } else if (event.type == ALLEGRO_EVENT_TIMER) { int y = 12; int dy = 12; if (panning && sample_id_valid) { ALLEGRO_SAMPLE_INSTANCE* instance = al_lock_sample_id(&sample_id); if (instance) { al_set_sample_instance_pan(instance, sin(al_get_time())); } al_unlock_sample_id(&sample_id); } al_clear_to_color(al_map_rgb_f(0., 0., 0.)); al_draw_text(font, al_map_rgb_f(1., 0.5, 0.5), 12, y, ALLEGRO_ALIGN_LEFT, "CONTROLS"); y += dy; al_draw_text(font, al_map_rgb_f(1., 0.5, 0.5), 12, y, ALLEGRO_ALIGN_LEFT, "1-9 - play the sounds"); y += dy; al_draw_text(font, al_map_rgb_f(1., 0.5, 0.5), 12, y, ALLEGRO_ALIGN_LEFT, "SPACE - stop all sounds"); y += dy; al_draw_text(font, al_map_rgb_f(1., 0.5, 0.5), 12, y, ALLEGRO_ALIGN_LEFT, "Ctrl 1-9 - play sounds with bidirectional looping"); y += dy; al_draw_text(font, al_map_rgb_f(1., 0.5, 0.5), 12, y, ALLEGRO_ALIGN_LEFT, "Alt 1-9 - play sounds with regular looping"); y += dy; al_draw_text(font, al_map_rgb_f(1., 0.5, 0.5), 12, y, ALLEGRO_ALIGN_LEFT, "Shift 1-9 - play sounds reversed"); y += dy; al_draw_text(font, al_map_rgb_f(1., 0.5, 0.5), 12, y, ALLEGRO_ALIGN_LEFT, "p - pan the last played sound"); y += dy; al_draw_text(font, al_map_rgb_f(1., 0.5, 0.5), 12, y, ALLEGRO_ALIGN_LEFT, "m - play music"); y += 2 * dy; al_draw_text(font, al_map_rgb_f(0.5, 1., 0.5), 12, y, ALLEGRO_ALIGN_LEFT, "SOUNDS"); y += dy; for (i = 0; i < argc && i < MAX_SAMPLE_DATA; i++) { al_draw_textf(font, al_map_rgb_f(0.5, 1., 0.5), 12, y, ALLEGRO_ALIGN_LEFT, "%d - %s", i + 1, argv[i]); y += dy; } al_flip_display(); } } for (i = 0; i < argc && i < MAX_SAMPLE_DATA; i++) { if (sample_data[i]) al_destroy_sample(sample_data[i]); } /* Sample data and other objects will be automatically freed. */ al_uninstall_audio(); al_destroy_display(display); close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_audio_timer.c000066400000000000000000000100261473414355200204360ustar00rootroot00000000000000/* * Example program for the Allegro library. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_font.h" #include "common.c" #define RESERVED_SAMPLES 16 #define PERIOD 5 static ALLEGRO_DISPLAY *display; static ALLEGRO_FONT *font; static ALLEGRO_SAMPLE *ping; static ALLEGRO_TIMER *timer; static ALLEGRO_EVENT_QUEUE *event_queue; static ALLEGRO_SAMPLE *create_sample_s16(int freq, int len) { char *buf = al_malloc(freq * len * sizeof(int16_t)); return al_create_sample(buf, len, freq, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_1, true); } /* Adapted from SPEED. */ static ALLEGRO_SAMPLE *generate_ping(void) { float osc1, osc2, vol, ramp; int16_t *p; int len; int i; /* ping consists of two sine waves */ len = 8192; ping = create_sample_s16(22050, len); if (!ping) return NULL; p = (int16_t *)al_get_sample_data(ping); osc1 = 0; osc2 = 0; for (i=0; i 1) { bps--; al_set_timer_speed(timer, 1.0 / bps); } } } else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } if (redraw && al_is_event_queue_empty(event_queue)) { ALLEGRO_COLOR c; if (last_timer % PERIOD == 0) c = al_map_rgb_f(1, 1, 1); else c = al_map_rgb_f(0.5, 0.5, 1.0); al_clear_to_color(al_map_rgb(0, 0, 0)); al_draw_textf(font, c, 640/32, 480/32 - 4, ALLEGRO_ALIGN_CENTRE, "%u", last_timer); al_flip_display(); } } close_log(false); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_bitmap.c000066400000000000000000000121571473414355200174200ustar00rootroot00000000000000/* This example displays a picture on the screen, with support for * command-line parameters, multi-screen, screen-orientation and * zooming. */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "common.c" int main(int argc, char **argv) { const char *filename; ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *bitmap; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; bool redraw = true; double zoom = 1; double t0; double t1; /* The first commandline argument can optionally specify an * image to display instead of the default. Allegro's image * addon supports BMP, DDS, PCX, TGA and can be compiled with * PNG and JPG support on all platforms. Additional formats * are supported by platform specific libraries and support for * image formats can also be added at runtime. */ if (argc > 1) { filename = argv[1]; } else { filename = "data/mysha.pcx"; } if (!al_init()) { abort_example("Could not init Allegro.\n"); } // Initializes and displays a log window for debugging purposes. open_log(); /* The second parameter to the process can optionally specify what * adapter to use. */ if (argc > 2) { al_set_new_display_adapter(atoi(argv[2])); } /* Allegro requires installing drivers for all input devices before * they can be used. */ al_install_mouse(); al_install_keyboard(); /* Initialize the image addon. Requires the allegro_image addon * library. */ al_init_image_addon(); // Helper functions from common.c. init_platform_specific(); // Create a new display that we can render the image to. display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } al_set_window_title(display, filename); // Load the image and time how long it took for the log. t0 = al_get_time(); bitmap = al_load_bitmap(filename); t1 = al_get_time(); if (!bitmap) { abort_example("%s not found or failed to load\n", filename); } log_printf("Loading took %.4f seconds\n", t1 - t0); // Create a timer that fires 30 times a second. timer = al_create_timer(1.0 / 30); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); // Start the timer // Primary 'game' loop. while (1) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); // Wait for and get an event. if (event.type == ALLEGRO_EVENT_DISPLAY_ORIENTATION) { int o = event.display.orientation; if (o == ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES) { log_printf("0 degrees\n"); } else if (o == ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES) { log_printf("90 degrees\n"); } else if (o == ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES) { log_printf("180 degrees\n"); } else if (o == ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES) { log_printf("270 degrees\n"); } else if (o == ALLEGRO_DISPLAY_ORIENTATION_FACE_UP) { log_printf("Face up\n"); } else if (o == ALLEGRO_DISPLAY_ORIENTATION_FACE_DOWN) { log_printf("Face down\n"); } } if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; /* Use keyboard to zoom image in and out. * 1: Reset zoom. * +: Zoom in 10% * -: Zoom out 10% * f: Zoom to width of window */ if (event.type == ALLEGRO_EVENT_KEY_CHAR) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; // Break the loop and quite on escape key. if (event.keyboard.unichar == '1') zoom = 1; if (event.keyboard.unichar == '+') zoom *= 1.1; if (event.keyboard.unichar == '-') zoom /= 1.1; if (event.keyboard.unichar == 'f') zoom = (double)al_get_display_width(display) / al_get_bitmap_width(bitmap); } // Trigger a redraw on the timer event if (event.type == ALLEGRO_EVENT_TIMER) redraw = true; // Redraw, but only if the event queue is empty if (redraw && al_is_event_queue_empty(queue)) { redraw = false; // Clear so we don't get trippy artifacts left after zoom. al_clear_to_color(al_map_rgb_f(0, 0, 0)); if (zoom == 1) al_draw_bitmap(bitmap, 0, 0, 0); else al_draw_scaled_rotated_bitmap( bitmap, 0, 0, 0, 0, zoom, zoom, 0, 0); al_flip_display(); } } al_destroy_bitmap(bitmap); close_log(false); return 0; } /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/examples/ex_bitmap_file.c000066400000000000000000000126101473414355200204110ustar00rootroot00000000000000/* This example displays a picture on the screen, with support for * command-line parameters, multi-screen, screen-orientation and * zooming. It is a little different from ex_bitmap in the sense * that it uses the ALLEGRO_FILE interface. */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "common.c" int main(int argc, char **argv) { const char *filename; char *fileextension = NULL; ALLEGRO_DISPLAY *display; ALLEGRO_FILE *file; ALLEGRO_BITMAP *bitmap = NULL; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; bool redraw = true; double zoom = 1; double t0; double t1; /* The first commandline argument can optionally specify an * image to display instead of the default. Allegro's image * addon supports BMP, DDS, PCX, TGA and can be compiled with * PNG and JPG support on all platforms. Additional formats * are supported by platform specific libraries and support for * image formats can also be added at runtime. */ if (argc > 1) { filename = argv[1]; } else { filename = "data/mysha.pcx"; } if (!al_init()) { abort_example("Could not init Allegro.\n"); } // Initializes and displays a log window for debugging purposes. open_log(); /* The second parameter to the process can optionally specify what * adapter to use. */ if (argc > 2) { al_set_new_display_adapter(atoi(argv[2])); } /* Allegro requires installing drivers for all input devices before * they can be used. */ al_install_mouse(); al_install_keyboard(); /* Initialize the image addon. Requires the allegro_image addon * library. */ al_init_image_addon(); // Helper functions from common.c. init_platform_specific(); // Create a new display that we can render the image to. display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } al_set_window_title(display, filename); // Load the image and time how long it took for the log. t0 = al_get_time(); file = al_fopen(filename, "rb"); if (file) { fileextension = strrchr(filename, '.'); bitmap = al_load_bitmap_f(file, fileextension); al_fclose( file ); } t1 = al_get_time(); if (!bitmap) { abort_example("%s not found or failed to load\n", filename); } log_printf("Loading took %.4f seconds\n", t1 - t0); // Create a timer that fires 30 times a second. timer = al_create_timer(1.0 / 30); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); // Start the timer // Primary 'game' loop. while (1) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); // Wait for and get an event. if (event.type == ALLEGRO_EVENT_DISPLAY_ORIENTATION) { int o = event.display.orientation; if (o == ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES) { log_printf("0 degrees\n"); } else if (o == ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES) { log_printf("90 degrees\n"); } else if (o == ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES) { log_printf("180 degrees\n"); } else if (o == ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES) { log_printf("270 degrees\n"); } else if (o == ALLEGRO_DISPLAY_ORIENTATION_FACE_UP) { log_printf("Face up\n"); } else if (o == ALLEGRO_DISPLAY_ORIENTATION_FACE_DOWN) { log_printf("Face down\n"); } } if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; /* Use keyboard to zoom image in and out. * 1: Reset zoom. * +: Zoom in 10% * -: Zoom out 10% * f: Zoom to width of window */ if (event.type == ALLEGRO_EVENT_KEY_CHAR) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; // Break the loop and quite on escape key. if (event.keyboard.unichar == '1') zoom = 1; if (event.keyboard.unichar == '+') zoom *= 1.1; if (event.keyboard.unichar == '-') zoom /= 1.1; if (event.keyboard.unichar == 'f') zoom = (double)al_get_display_width(display) / al_get_bitmap_width(bitmap); } // Trigger a redraw on the timer event if (event.type == ALLEGRO_EVENT_TIMER) redraw = true; // Redraw, but only if the event queue is empty if (redraw && al_is_event_queue_empty(queue)) { redraw = false; // Clear so we don't get trippy artifacts left after zoom. al_clear_to_color(al_map_rgb_f(0, 0, 0)); if (zoom == 1) al_draw_bitmap(bitmap, 0, 0, 0); else al_draw_scaled_rotated_bitmap( bitmap, 0, 0, 0, 0, zoom, zoom, 0, 0); al_flip_display(); } } al_destroy_bitmap(bitmap); close_log(false); return 0; } /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/examples/ex_bitmap_flip.c000066400000000000000000000117761473414355200204400ustar00rootroot00000000000000/* An example showing bitmap flipping flags, by Steven Wallace. */ #include #include #include #include "common.c" /* Fire the update every 10 milliseconds. */ #define INTERVAL 0.01 float bmp_x = 200; float bmp_y = 200; float bmp_dx = 96; float bmp_dy = 96; int bmp_flag = 0; /* Updates the bitmap velocity, orientation and position. */ static void update(ALLEGRO_BITMAP *bmp) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); int display_w = al_get_bitmap_width(target); int display_h = al_get_bitmap_height(target); int bitmap_w = al_get_bitmap_width(bmp); int bitmap_h = al_get_bitmap_height(bmp); bmp_x += bmp_dx * INTERVAL; bmp_y += bmp_dy * INTERVAL; /* Make sure bitmap is still on the screen. */ if (bmp_y < 0) { bmp_y = 0; bmp_dy *= -1; bmp_flag &= ~ALLEGRO_FLIP_VERTICAL; } if (bmp_x < 0) { bmp_x = 0; bmp_dx *= -1; bmp_flag &= ~ALLEGRO_FLIP_HORIZONTAL; } if (bmp_y > display_h - bitmap_h) { bmp_y = display_h - bitmap_h; bmp_dy *= -1; bmp_flag |= ALLEGRO_FLIP_VERTICAL; } if (bmp_x > display_w - bitmap_w) { bmp_x = display_w - bitmap_w; bmp_dx *= -1; bmp_flag |= ALLEGRO_FLIP_HORIZONTAL; } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_BITMAP *bmp; ALLEGRO_BITMAP *mem_bmp; ALLEGRO_BITMAP *disp_bmp; ALLEGRO_FONT *font; char *text; bool done = false; bool redraw = true; /* Silence unused arguments warnings. */ (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } /* Initialize the image addon. Requires the allegro_image addon * library. */ if (!al_init_image_addon()) { abort_example("Failed to init IIO addon.\n"); } /* Initialize the image font. Requires the allegro_font addon * library. */ al_init_font_addon(); init_platform_specific(); /* Helper functions from common.c. */ /* Create a new display that we can render the image to. */ display = al_create_display(640, 480); if (!display) { abort_example("Error creating display.\n"); } /* Allegro requires installing drivers for all input devices before * they can be used. */ if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } /* Loads a font from disk. This will use al_load_bitmap_font if you * pass the name of a known bitmap format, or else al_load_ttf_font. */ font = al_load_font("data/fixed_font.tga", 0, 0); if (!font) { abort_example("Error loading data/fixed_font.tga\n"); } bmp = disp_bmp = al_load_bitmap("data/mysha.pcx"); if (!bmp) { abort_example("Error loading data/mysha.pcx\n"); } text = "Display bitmap (space to change)"; al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); mem_bmp = al_load_bitmap("data/mysha.pcx"); if (!mem_bmp) { abort_example("Error loading data/mysha.pcx\n"); } timer = al_create_timer(INTERVAL); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(display)); al_start_timer(timer); /* Default premultiplied aplha blending. */ al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); /* Primary 'game' loop. */ while (!done) { ALLEGRO_EVENT event; /* If the timer has since been fired and the queue is empty, draw.*/ if (redraw && al_is_event_queue_empty(queue)) { update(bmp); /* Clear so we don't get trippy artifacts left after zoom. */ al_clear_to_color(al_map_rgb_f(0, 0, 0)); al_draw_tinted_bitmap(bmp, al_map_rgba_f(1, 1, 1, 0.5), bmp_x, bmp_y, bmp_flag); al_draw_text(font, al_map_rgba_f(1, 1, 1, 0.5), 0, 0, 0, text); al_flip_display(); redraw = false; } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; else if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) { /* Spacebar toggles whether render from a memory bitmap * or display bitamp. */ if (bmp == mem_bmp) { bmp = disp_bmp; text = "Display bitmap (space to change)"; } else { bmp = mem_bmp; text = "Memory bitmap (space to change)"; } } break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_TIMER: redraw = true; break; } } al_destroy_bitmap(bmp); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_blend.c000066400000000000000000000234241473414355200172270ustar00rootroot00000000000000/* An example demonstrating different blending modes. */ #define ALLEGRO_UNSTABLE #include #include #include #include #include #include #include #include "common.c" /* A structure holding all variables of our example program. */ struct Example { ALLEGRO_BITMAP *example; /* Our example bitmap. */ ALLEGRO_BITMAP *offscreen; /* An offscreen buffer, for testing. */ ALLEGRO_BITMAP *memory; /* A memory buffer, for testing. */ ALLEGRO_FONT *myfont; /* Our font. */ ALLEGRO_EVENT_QUEUE *queue; /* Our events queue. */ int image; /* Which test image to use. */ int mode; /* How to draw it. */ int BUTTONS_X; /* Where to draw buttons. */ int FPS; double last_second; int frames_accum; double fps; } ex; /* Print some text with a shadow. */ static void print(int x, int y, bool vertical, char const *format, ...) { va_list list; char message[1024]; ALLEGRO_COLOR color; int h; int j; va_start(list, format); vsnprintf(message, sizeof message, format, list); va_end(list); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); h = al_get_font_line_height(ex.myfont); for (j = 0; j < 2; j++) { if (j == 0) color = al_map_rgb(0, 0, 0); else color = al_map_rgb(255, 255, 255); if (vertical) { int i; ALLEGRO_USTR_INFO ui; const ALLEGRO_USTR *us = al_ref_cstr(&ui, message); for (i = 0; i < (int)al_ustr_length(us); i++) { ALLEGRO_USTR_INFO letter; al_draw_ustr(ex.myfont, color, x + 1 - j, y + 1 - j + h * i, 0, al_ref_ustr(&letter, us, al_ustr_offset(us, i), al_ustr_offset(us, i + 1))); } } else { al_draw_text(ex.myfont, color, x + 1 - j, y + 1 - j, 0, message); } } } /* Create an example bitmap. */ static ALLEGRO_BITMAP *create_example_bitmap(void) { ALLEGRO_BITMAP *bitmap; int i, j; ALLEGRO_LOCKED_REGION *locked; unsigned char *data; bitmap = al_create_bitmap(100, 100); locked = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ABGR_8888, ALLEGRO_LOCK_WRITEONLY); data = locked->data; for (j = 0; j < 100; j++) { for (i = 0; i < 100; i++) { int x = i - 50, y = j - 50; int r = sqrt(x * x + y * y); float rc = 1 - r / 50.0; if (rc < 0) rc = 0; data[i * 4 + 0] = i * 255 / 100; data[i * 4 + 1] = j * 255 / 100; data[i * 4 + 2] = rc * 255; data[i * 4 + 3] = rc * 255; } data += locked->pitch; } al_unlock_bitmap(bitmap); return bitmap; } /* Draw our example scene. */ static void draw(void) { ALLEGRO_COLOR test[5]; ALLEGRO_BITMAP *target = al_get_target_bitmap(); char const *blend_names[] = {"ZERO", "ONE", "ALPHA", "INVERSE"}; char const *blend_vnames[] = {"ZERO", "ONE", "ALPHA", "INVER"}; int blend_modes[] = {ALLEGRO_ZERO, ALLEGRO_ONE, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA}; float x = 40, y = 40; int i, j; al_clear_to_color(al_map_rgb_f(0.5, 0.5, 0.5)); test[0] = al_map_rgba_f(1, 1, 1, 1); test[1] = al_map_rgba_f(1, 1, 1, 0.5); test[2] = al_map_rgba_f(1, 1, 1, 0.25); test[3] = al_map_rgba_f(1, 0, 0, 0.75); test[4] = al_map_rgba_f(0, 0, 0, 0); print(x, 0, false, "D E S T I N A T I O N (%0.2f fps)", ex.fps); print(0, y, true, "S O U R C E"); for (i = 0; i < 4; i++) { print(x + i * 110, 20, false, blend_names[i]); print(20, y + i * 110, true, blend_vnames[i]); } al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); if (ex.mode >= 1 && ex.mode <= 5) { al_set_target_bitmap(ex.offscreen); al_clear_to_color(test[ex.mode - 1]); } if (ex.mode >= 6 && ex.mode <= 10) { al_set_target_bitmap(ex.memory); al_clear_to_color(test[ex.mode - 6]); } for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { al_set_blender(ALLEGRO_ADD, blend_modes[j], blend_modes[i]); if (ex.image == 0) al_draw_bitmap(ex.example, x + i * 110, y + j * 110, 0); else if (ex.image >= 1 && ex.image <= 6) { al_draw_filled_rectangle(x + i * 110, y + j * 110, x + i * 110 + 100, y + j * 110 + 100, test[ex.image - 1]); } } } if (ex.mode >= 1 && ex.mode <= 5) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_set_target_bitmap(target); al_draw_bitmap_region(ex.offscreen, x, y, 430, 430, x, y, 0); } if (ex.mode >= 6 && ex.mode <= 10) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_set_target_bitmap(target); al_draw_bitmap_region(ex.memory, x, y, 430, 430, x, y, 0); } #define IS(x) ((ex.image == x) ? "*" : " ") print(ex.BUTTONS_X, 20 * 1, false, "What to draw"); print(ex.BUTTONS_X, 20 * 2, false, "%s Picture", IS(0)); print(ex.BUTTONS_X, 20 * 3, false, "%s Rec1 (1/1/1/1)", IS(1)); print(ex.BUTTONS_X, 20 * 4, false, "%s Rec2 (1/1/1/.5)", IS(2)); print(ex.BUTTONS_X, 20 * 5, false, "%s Rec3 (1/1/1/.25)", IS(3)); print(ex.BUTTONS_X, 20 * 6, false, "%s Rec4 (1/0/0/.75)", IS(4)); print(ex.BUTTONS_X, 20 * 7, false, "%s Rec5 (0/0/0/0)", IS(5)); #undef IS #define IS(x) ((ex.mode == x) ? "*" : " ") print(ex.BUTTONS_X, 20 * 9, false, "Where to draw"); print(ex.BUTTONS_X, 20 * 10, false, "%s screen", IS(0)); print(ex.BUTTONS_X, 20 * 11, false, "%s offscreen1", IS(1)); print(ex.BUTTONS_X, 20 * 12, false, "%s offscreen2", IS(2)); print(ex.BUTTONS_X, 20 * 13, false, "%s offscreen3", IS(3)); print(ex.BUTTONS_X, 20 * 14, false, "%s offscreen4", IS(4)); print(ex.BUTTONS_X, 20 * 15, false, "%s offscreen5", IS(5)); print(ex.BUTTONS_X, 20 * 16, false, "%s memory1", IS(6)); print(ex.BUTTONS_X, 20 * 17, false, "%s memory2", IS(7)); print(ex.BUTTONS_X, 20 * 18, false, "%s memory3", IS(8)); print(ex.BUTTONS_X, 20 * 19, false, "%s memory4", IS(9)); print(ex.BUTTONS_X, 20 * 20, false, "%s memory5", IS(10)); #undef IS } /* Called a fixed amount of times per second. */ static void tick(void) { /* Count frames during the last second or so. */ double t = al_get_time(); if (t >= ex.last_second + 1) { ex.fps = ex.frames_accum / (t - ex.last_second); ex.frames_accum = 0; ex.last_second = t; } draw(); al_flip_display(); ex.frames_accum++; } /* Run our test. */ static void run(void) { ALLEGRO_EVENT event; float x, y; bool need_draw = true; while (1) { /* Perform frame skipping so we don't fall behind the timer events. */ if (need_draw && al_is_event_queue_empty(ex.queue)) { tick(); need_draw = false; } al_wait_for_event(ex.queue, &event); switch (event.type) { /* Was the X button on the window pressed? */ case ALLEGRO_EVENT_DISPLAY_CLOSE: return; /* Was a key pressed? */ case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) return; break; /* Is it time for the next timer tick? */ case ALLEGRO_EVENT_TIMER: need_draw = true; break; /* Mouse click? */ case ALLEGRO_EVENT_MOUSE_BUTTON_UP: x = event.mouse.x; y = event.mouse.y; if (x >= ex.BUTTONS_X) { int button = y / 20; if (button == 2) ex.image = 0; if (button == 3) ex.image = 1; if (button == 4) ex.image = 2; if (button == 5) ex.image = 3; if (button == 6) ex.image = 4; if (button == 7) ex.image = 5; if (button == 10) ex.mode = 0; if (button == 11) ex.mode = 1; if (button == 12) ex.mode = 2; if (button == 13) ex.mode = 3; if (button == 14) ex.mode = 4; if (button == 15) ex.mode = 5; if (button == 16) ex.mode = 6; if (button == 17) ex.mode = 7; if (button == 18) ex.mode = 8; if (button == 19) ex.mode = 9; if (button == 20) ex.mode = 10; } break; } } } /* Initialize the example. */ static void init(void) { ex.BUTTONS_X = 40 + 110 * 4; ex.FPS = 60; ex.myfont = al_load_font("data/font.tga", 0, 0); if (!ex.myfont) { abort_example("data/font.tga not found\n"); } ex.example = create_example_bitmap(); ex.offscreen = al_create_bitmap(640, 480); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); ex.memory = al_create_bitmap(640, 480); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_install_keyboard(); al_install_mouse(); al_install_touch_input(); al_init_image_addon(); al_init_font_addon(); init_platform_specific(); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } init(); timer = al_create_timer(1.0 / ex.FPS); ex.queue = al_create_event_queue(); al_register_event_source(ex.queue, al_get_keyboard_event_source()); al_register_event_source(ex.queue, al_get_mouse_event_source()); al_register_event_source(ex.queue, al_get_display_event_source(display)); al_register_event_source(ex.queue, al_get_timer_event_source(timer)); if (al_is_touch_input_installed()) { al_register_event_source(ex.queue, al_get_touch_input_mouse_emulation_event_source()); } al_start_timer(timer); run(); al_destroy_event_queue(ex.queue); return 0; } allegro5-5.2.10.1/examples/ex_blend2.cpp000066400000000000000000000250151473414355200176470ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * * Compare software blending routines with hardware blending. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_image.h" #include #include "common.c" #include "nihgui.hpp" ALLEGRO_BITMAP *allegro; ALLEGRO_BITMAP *mysha; ALLEGRO_BITMAP *allegro_bmp; ALLEGRO_BITMAP *mysha_bmp; ALLEGRO_BITMAP *target; ALLEGRO_BITMAP *target_bmp; class Prog { private: Dialog d; Label memory_label; Label texture_label; Label source_label; Label destination_label; List source_image; List destination_image; List draw_mode; Label operation_label[6]; List operations[6]; Label rgba_label[3]; HSlider r[3]; HSlider g[3]; HSlider b[3]; HSlider a[3]; public: Prog(const Theme & theme, ALLEGRO_DISPLAY *display); void run(); private: void blending_test(bool memory); void draw_samples(); void draw_bitmap(const std::string &, const std::string &, bool, bool); }; Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) : d(Dialog(theme, display, 20, 40)), memory_label(Label("Memory")), texture_label(Label("Texture")), source_label(Label("Source", false)), destination_label(Label("Destination", false)), source_image(List(0)), destination_image(List(1)), draw_mode(List(0)) { d.add(memory_label, 9, 0, 10, 2); d.add(texture_label, 0, 0, 10, 2); d.add(source_label, 1, 15, 6, 2); d.add(destination_label, 7, 15, 6, 2); List *images[] = {&source_image, &destination_image, &draw_mode}; for (int i = 0; i < 3; i++) { List & image = *images[i]; if (i < 2) { image.append_item("Mysha"); image.append_item("Allegro"); image.append_item("Mysha (tinted)"); image.append_item("Allegro (tinted)"); image.append_item("Color"); } else { image.append_item("original"); image.append_item("scaled"); image.append_item("rotated"); } d.add(image, 1 + i * 6, 16, 4, 6); } for (int i = 0; i < 4; i++) { operation_label[i] = Label(i % 2 == 0 ? "Color" : "Alpha", false); d.add(operation_label[i], 1 + i * 3, 23, 3, 2); List &l = operations[i]; l.append_item("ONE"); l.append_item("ZERO"); l.append_item("ALPHA"); l.append_item("INVERSE"); l.append_item("SRC_COLOR"); l.append_item("DEST_COLOR"); l.append_item("INV_SRC_COLOR"); l.append_item("INV_DEST_COLOR"); l.append_item("CONST_COLOR"); l.append_item("INV_CONST_COLOR"); d.add(l, 1 + i * 3, 24, 3, 10); } for (int i = 4; i < 6; i++) { operation_label[i] = Label(i == 4 ? "Blend op" : "Alpha op", false); d.add(operation_label[i], 1 + i * 3, 23, 3, 2); List &l = operations[i]; l.append_item("ADD"); l.append_item("SRC_MINUS_DEST"); l.append_item("DEST_MINUS_SRC"); d.add(l, 1 + i * 3, 24, 3, 6); } rgba_label[0] = Label("Source tint/color RGBA"); rgba_label[1] = Label("Dest tint/color RGBA"); rgba_label[2] = Label("Const color RGBA"); d.add(rgba_label[0], 1, 34, 5, 1); d.add(rgba_label[1], 7, 34, 5, 1); d.add(rgba_label[2], 13, 34, 5, 1); for (int i = 0; i < 3; i++) { r[i] = HSlider(255, 255); g[i] = HSlider(255, 255); b[i] = HSlider(255, 255); a[i] = HSlider(255, 255); d.add(r[i], 1 + i * 6, 35, 5, 1); d.add(g[i], 1 + i * 6, 36, 5, 1); d.add(b[i], 1 + i * 6, 37, 5, 1); d.add(a[i], 1 + i * 6, 38, 5, 1); } } void Prog::run() { d.prepare(); while (!d.is_quit_requested()) { if (d.is_draw_requested()) { al_clear_to_color(al_map_rgb(128, 128, 128)); draw_samples(); d.draw(); al_flip_display(); } d.run_step(true); } } int str_to_blend_mode(const std::string & str) { if (str == "ZERO") return ALLEGRO_ZERO; if (str == "ONE") return ALLEGRO_ONE; if (str == "SRC_COLOR") return ALLEGRO_SRC_COLOR; if (str == "DEST_COLOR") return ALLEGRO_DEST_COLOR; if (str == "INV_SRC_COLOR") return ALLEGRO_INVERSE_SRC_COLOR; if (str == "INV_DEST_COLOR") return ALLEGRO_INVERSE_DEST_COLOR; if (str == "ALPHA") return ALLEGRO_ALPHA; if (str == "INVERSE") return ALLEGRO_INVERSE_ALPHA; if (str == "ADD") return ALLEGRO_ADD; if (str == "SRC_MINUS_DEST") return ALLEGRO_SRC_MINUS_DEST; if (str == "DEST_MINUS_SRC") return ALLEGRO_DEST_MINUS_SRC; if (str == "CONST_COLOR") return ALLEGRO_CONST_COLOR; if (str == "INV_CONST_COLOR") return ALLEGRO_INVERSE_CONST_COLOR; ALLEGRO_ASSERT(false); return ALLEGRO_ONE; } void draw_background(int x, int y) { ALLEGRO_COLOR c[] = { al_map_rgba(0x66, 0x66, 0x66, 0xff), al_map_rgba(0x99, 0x99, 0x99, 0xff) }; for (int i = 0; i < 320 / 16; i++) { for (int j = 0; j < 200 / 16; j++) { al_draw_filled_rectangle(x + i * 16, y + j * 16, x + i * 16 + 16, y + j * 16 + 16, c[(i + j) & 1]); } } } static ALLEGRO_COLOR makecol(int r, int g, int b, int a) { /* Premultiply alpha. */ float rf = (float)r / 255.0f; float gf = (float)g / 255.0f; float bf = (float)b / 255.0f; float af = (float)a / 255.0f; return al_map_rgba_f(rf*af, gf*af, bf*af, af); } static bool contains(const std::string & haystack, const std::string & needle) { return haystack.find(needle) != std::string::npos; } void Prog::draw_bitmap(const std::string & str, const std::string &how, bool memory, bool destination) { int i = destination ? 1 : 0; int rv = r[i].get_cur_value(); int gv = g[i].get_cur_value(); int bv = b[i].get_cur_value(); int av = a[i].get_cur_value(); ALLEGRO_COLOR color = makecol(rv, gv, bv, av); ALLEGRO_BITMAP *bmp; if (contains(str, "Mysha")) bmp = (memory ? mysha_bmp : mysha); else bmp = (memory ? allegro_bmp : allegro); if (how == "original") { if (str == "Color") al_draw_filled_rectangle(0, 0, 320, 200, color); else if (contains(str, "tint")) al_draw_tinted_bitmap(bmp, color, 0, 0, 0); else al_draw_bitmap(bmp, 0, 0, 0); } else if (how == "scaled") { int w = al_get_bitmap_width(bmp); int h = al_get_bitmap_height(bmp); float s = 200.0 / h * 0.9; if (str == "Color") { al_draw_filled_rectangle(10, 10, 300, 180, color); } else if (contains(str, "tint")) { al_draw_tinted_scaled_bitmap(bmp, color, 0, 0, w, h, 160 - w * s / 2, 100 - h * s / 2, w * s, h * s, 0); } else { al_draw_scaled_bitmap(bmp, 0, 0, w, h, 160 - w * s / 2, 100 - h * s / 2, w * s, h * s, 0); } } else if (how == "rotated") { if (str == "Color") { al_draw_filled_circle(160, 100, 100, color); } else if (contains(str, "tint")) { al_draw_tinted_rotated_bitmap(bmp, color, 160, 100, 160, 100, ALLEGRO_PI / 8, 0); } else { al_draw_rotated_bitmap(bmp, 160, 100, 160, 100, ALLEGRO_PI / 8, 0); } } } void Prog::blending_test(bool memory) { ALLEGRO_COLOR transparency = al_map_rgba_f(0, 0, 0, 0); int op = str_to_blend_mode(operations[4].get_selected_item_text()); int aop = str_to_blend_mode(operations[5].get_selected_item_text()); int src = str_to_blend_mode(operations[0].get_selected_item_text()); int asrc = str_to_blend_mode(operations[1].get_selected_item_text()); int dst = str_to_blend_mode(operations[2].get_selected_item_text()); int adst = str_to_blend_mode(operations[3].get_selected_item_text()); int rv = r[2].get_cur_value(); int gv = g[2].get_cur_value(); int bv = b[2].get_cur_value(); int av = a[2].get_cur_value(); ALLEGRO_COLOR color = makecol(rv, gv, bv, av); /* Initialize with destination. */ al_clear_to_color(transparency); // Just in case. al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); draw_bitmap(destination_image.get_selected_item_text(), "original", memory, true); /* Now draw the blended source over it. */ al_set_separate_blender(op, src, dst, aop, asrc, adst); al_set_blend_color(color); draw_bitmap(source_image.get_selected_item_text(), draw_mode.get_selected_item_text(), memory, false); } void Prog::draw_samples() { ALLEGRO_STATE state; al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP | ALLEGRO_STATE_BLENDER); /* Draw a background, in case our target bitmap will end up with * alpha in it. */ draw_background(40, 20); draw_background(400, 20); /* Test standard blending. */ al_set_target_bitmap(target); blending_test(false); /* Test memory blending. */ al_set_target_bitmap(target_bmp); blending_test(true); /* Display results. */ al_restore_state(&state); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_bitmap(target, 40, 20, 0); al_draw_bitmap(target_bmp, 400, 20, 0); al_restore_state(&state); } int main(int argc, char *argv[]) { ALLEGRO_DISPLAY *display; ALLEGRO_FONT *font; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro\n"); } al_init_primitives_addon(); al_install_keyboard(); al_install_mouse(); al_init_font_addon(); al_init_image_addon(); init_platform_specific(); al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(800, 600); if (!display) { abort_example("Unable to create display\n"); } font = al_load_font("data/fixed_font.tga", 0, 0); if (!font) { abort_example("Failed to load data/fixed_font.tga\n"); } allegro = al_load_bitmap("data/allegro.pcx"); if (!allegro) { abort_example("Failed to load data/allegro.pcx\n"); } mysha = al_load_bitmap("data/mysha256x256.png"); if (!mysha) { abort_example("Failed to load data/mysha256x256.png\n"); } target = al_create_bitmap(320, 200); al_add_new_bitmap_flag(ALLEGRO_MEMORY_BITMAP); allegro_bmp = al_clone_bitmap(allegro); mysha_bmp = al_clone_bitmap(mysha); target_bmp = al_clone_bitmap(target); /* Don't remove these braces. */ { Theme theme(font); Prog prog(theme, display); prog.run(); } al_destroy_bitmap(allegro); al_destroy_bitmap(allegro_bmp); al_destroy_bitmap(mysha); al_destroy_bitmap(mysha_bmp); al_destroy_bitmap(target); al_destroy_bitmap(target_bmp); al_destroy_font(font); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_blend_bench.c000066400000000000000000000075571473414355200203770ustar00rootroot00000000000000/* * Benchmark for memory blenders. */ #include #include #include #include #include #include "common.c" /* Do a few un-timed runs to switch CPU to performance mode and cache * data and so on - seems to make the results more stable here. * Also used to guess the number of timed iterations. */ #define WARMUP 100 /* How many seconds the timing should approximately take - a fixed * number of iterations is not enough on very fast systems but takes * too long on slow systems. */ #define TEST_TIME 5.0 enum Mode { ALL, PLAIN_BLIT, SCALED_BLIT, ROTATE_BLIT }; static char const *names[] = { "", "Plain blit", "Scaled blit", "Rotated blit" }; ALLEGRO_DISPLAY *display; static void step(enum Mode mode, ALLEGRO_BITMAP *b2) { switch (mode) { case ALL: break; case PLAIN_BLIT: al_draw_bitmap(b2, 0, 0, 0); break; case SCALED_BLIT: al_draw_scaled_bitmap(b2, 0, 0, 320, 200, 0, 0, 640, 480, 0); break; case ROTATE_BLIT: al_draw_scaled_rotated_bitmap(b2, 10, 10, 10, 10, 2.0, 2.0, ALLEGRO_PI/30, 0); break; } } /* al_get_current_time() measures wallclock time - but for the benchmark * result we prefer CPU time so clock() is better. */ static double current_clock(void) { clock_t c = clock(); return (double)c / CLOCKS_PER_SEC; } static bool do_test(enum Mode mode) { ALLEGRO_STATE state; ALLEGRO_BITMAP *b1; ALLEGRO_BITMAP *b2; int REPEAT; double t0, t1; int i; al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); b1 = al_load_bitmap("data/mysha.pcx"); if (!b1) { abort_example("Error loading data/mysha.pcx\n"); return false; } b2 = al_load_bitmap("data/allegro.pcx"); if (!b2) { abort_example("Error loading data/mysha.pcx\n"); return false; } al_set_target_bitmap(b1); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); step(mode, b2); /* Display the blended bitmap to the screen so we can see something. */ al_store_state(&state, ALLEGRO_STATE_ALL); al_set_target_backbuffer(display); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_draw_bitmap(b1, 0, 0, 0); al_flip_display(); al_restore_state(&state); log_printf("Benchmark: %s\n", names[mode]); log_printf("Please wait...\n"); /* Do warmup run and estimate required runs for real test. */ t0 = current_clock(); for (i = 0; i < WARMUP; i++) { step(mode, b2); } t1 = current_clock(); REPEAT = TEST_TIME * 100 / (t1 - t0); /* Do the real test. */ t0 = current_clock(); for (i = 0; i < REPEAT; i++) { step(mode, b2); } t1 = current_clock(); log_printf("Time = %g s, %d steps\n", t1 - t0, REPEAT); log_printf("%s: %g FPS\n", names[mode], REPEAT / (t1 - t0)); log_printf("Done\n"); al_destroy_bitmap(b1); al_destroy_bitmap(b2); return true; } int main(int argc, char **argv) { enum Mode mode = ALL; int i; if (argc > 1) { i = strtol(argv[1], NULL, 10); switch (i) { case 0: mode = PLAIN_BLIT; break; case 1: mode = SCALED_BLIT; break; case 2: mode = ROTATE_BLIT; break; } } if (!al_init()) { abort_example("Could not init Allegro\n"); } open_log(); al_init_image_addon(); al_init_primitives_addon(); init_platform_specific(); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } if (mode == ALL) { for (mode = PLAIN_BLIT; mode <= ROTATE_BLIT; mode++) { do_test(mode); } } else { do_test(mode); } al_destroy_display(display); close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_blend_target.c000066400000000000000000000067501473414355200206000ustar00rootroot00000000000000#define ALLEGRO_UNSTABLE #include #include #include #include #include #include "common.c" #define FPS 60 static ALLEGRO_BITMAP *load_bitmap(char const *filename) { ALLEGRO_BITMAP *bitmap = al_load_bitmap(filename); if (!bitmap) abort_example("%s not found or failed to load\n", filename); return bitmap; } int main(int argc, char **argv) { ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP* mysha; ALLEGRO_BITMAP* parrot; ALLEGRO_BITMAP* targets[4]; ALLEGRO_BITMAP* backbuffer; int w; int h; bool done = false; bool need_redraw = true; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } if (!al_init_image_addon()) { abort_example("Failed to init image addon.\n"); } init_platform_specific(); mysha = load_bitmap("data/mysha.pcx"); parrot = load_bitmap("data/obp.jpg"); w = al_get_bitmap_width(mysha); h = al_get_bitmap_height(mysha); display = al_create_display(2 * w, 2 * h); if (!display) { abort_example("Error creating display.\n"); } if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } /* Set up blend modes once. */ backbuffer = al_get_backbuffer(display); targets[0] = al_create_sub_bitmap(backbuffer, 0, 0, w, h ); al_set_target_bitmap(targets[0]); al_set_bitmap_blender(ALLEGRO_DEST_MINUS_SRC, ALLEGRO_SRC_COLOR, ALLEGRO_DST_COLOR); targets[1] = al_create_sub_bitmap(backbuffer, w, 0, w, h ); al_set_target_bitmap(targets[1]); al_set_bitmap_blender(ALLEGRO_ADD, ALLEGRO_SRC_COLOR, ALLEGRO_DST_COLOR); al_set_bitmap_blend_color(al_map_rgb_f(0.5, 0.5, 1.0)); targets[2] = al_create_sub_bitmap(backbuffer, 0, h, w, h ); al_set_target_bitmap(targets[2]); al_set_bitmap_blender(ALLEGRO_SRC_MINUS_DEST, ALLEGRO_SRC_COLOR, ALLEGRO_DST_COLOR); targets[3] = al_create_sub_bitmap(backbuffer, w, h, w, h ); al_set_target_bitmap(targets[3]); al_set_bitmap_blender(ALLEGRO_DEST_MINUS_SRC, ALLEGRO_INVERSE_SRC_COLOR, ALLEGRO_DST_COLOR); timer = al_create_timer(1.0 / FPS); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(display)); al_start_timer(timer); while (!done) { ALLEGRO_EVENT event; if (need_redraw) { int i; al_set_target_bitmap(backbuffer); al_draw_bitmap(parrot, 0, 0, 0); for (i = 0; i < 4; i++) { /* Simply setting the target also sets the blend mode. */ al_set_target_bitmap(targets[i]); al_draw_bitmap(mysha, 0, 0, 0); } al_flip_display(); need_redraw = false; } while (true) { al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_CHAR: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_TIMER: need_redraw = true; break; } if (al_is_event_queue_empty(queue)) break; } } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_blend_test.c000066400000000000000000000203711473414355200202640ustar00rootroot00000000000000#include #include #include #include #include "common.c" int test_only_index = 0; int test_index = 0; bool test_display = false; ALLEGRO_DISPLAY *display; static void print_color(ALLEGRO_COLOR c) { float r, g, b, a; al_unmap_rgba_f(c, &r, &g, &b, &a); log_printf("%.2f, %.2f, %.2f, %.2f", r, g, b, a); } static ALLEGRO_COLOR test(ALLEGRO_COLOR src_col, ALLEGRO_COLOR dst_col, int src_format, int dst_format, int src, int dst, int src_a, int dst_a, int operation, bool verbose) { ALLEGRO_COLOR result; ALLEGRO_BITMAP *dst_bmp; al_set_new_bitmap_format(dst_format); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); dst_bmp = al_create_bitmap(1, 1); al_set_target_bitmap(dst_bmp); al_clear_to_color(dst_col); if (operation == 0) { ALLEGRO_BITMAP *src_bmp; al_set_new_bitmap_format(src_format); src_bmp = al_create_bitmap(1, 1); al_set_target_bitmap(src_bmp); al_clear_to_color(src_col); al_set_target_bitmap(dst_bmp); al_set_separate_blender(ALLEGRO_ADD, src, dst, ALLEGRO_ADD, src_a, dst_a); al_draw_bitmap(src_bmp, 0, 0, 0); al_destroy_bitmap(src_bmp); } else if (operation == 1) { al_set_separate_blender(ALLEGRO_ADD, src, dst, ALLEGRO_ADD, src_a, dst_a); al_draw_pixel(0, 0, src_col); } else if (operation == 2) { al_set_separate_blender(ALLEGRO_ADD, src, dst, ALLEGRO_ADD, src_a, dst_a); al_draw_line(0, 0, 1, 1, src_col, 0); } result = al_get_pixel(dst_bmp, 0, 0); al_set_target_backbuffer(display); if (test_display) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_draw_bitmap(dst_bmp, 0, 0, 0); } al_destroy_bitmap(dst_bmp); if (!verbose) return result; log_printf("---\n"); log_printf("test id: %d\n", test_index); log_printf("source : "); print_color(src_col); log_printf(" %s format=%d mode=%d alpha=%d\n", operation == 0 ? "bitmap" : operation == 1 ? "pixel" : "prim", src_format, src, src_a); log_printf("destination: "); print_color(dst_col); log_printf(" format=%d mode=%d alpha=%d\n", dst_format, dst, dst_a); log_printf("result : "); print_color(result); log_printf("\n"); return result; } static bool same_color(ALLEGRO_COLOR c1, ALLEGRO_COLOR c2) { float r1, g1, b1, a1; float r2, g2, b2, a2; float dr, dg, db, da; float d; al_unmap_rgba_f(c1, &r1, &g1, &b1, &a1); al_unmap_rgba_f(c2, &r2, &g2, &b2, &a2); dr = r1 - r2; dg = g1 - g2; db = b1 - b2; da = a1 - a2; d = sqrt(dr * dr + dg * dg + db * db + da * da); if (d < 0.01) return true; else return false; } static float get_factor(int operation, float alpha) { switch(operation) { case ALLEGRO_ZERO: return 0; case ALLEGRO_ONE: return 1; case ALLEGRO_ALPHA: return alpha; case ALLEGRO_INVERSE_ALPHA: return 1 - alpha; } return 0; } static bool has_alpha(int format) { if (format == ALLEGRO_PIXEL_FORMAT_RGB_888) return false; if (format == ALLEGRO_PIXEL_FORMAT_BGR_888) return false; return true; } #define CLAMP(x) (x > 1 ? 1 : x) static ALLEGRO_COLOR reference_implementation( ALLEGRO_COLOR src_col, ALLEGRO_COLOR dst_col, int src_format, int dst_format, int src_mode, int dst_mode, int src_alpha, int dst_alpha, int operation) { float sr, sg, sb, sa; float dr, dg, db, da; float r, g, b, a; float src, dst, asrc, adst; al_unmap_rgba_f(src_col, &sr, &sg, &sb, &sa); al_unmap_rgba_f(dst_col, &dr, &dg, &db, &da); /* Do we even have source alpha? */ if (operation == 0) { if (!has_alpha(src_format)) { sa = 1; } } r = sr; g = sg; b = sb; a = sa; src = get_factor(src_mode, a); dst = get_factor(dst_mode, a); asrc = get_factor(src_alpha, a); adst = get_factor(dst_alpha, a); r = r * src + dr * dst; g = g * src + dg * dst; b = b * src + db * dst; a = a * asrc + da * adst; r = CLAMP(r); g = CLAMP(g); b = CLAMP(b); a = CLAMP(a); /* Do we even have destination alpha? */ if (!has_alpha(dst_format)) { a = 1; } return al_map_rgba_f(r, g, b, a); } static void do_test2(ALLEGRO_COLOR src_col, ALLEGRO_COLOR dst_col, int src_format, int dst_format, int src_mode, int dst_mode, int src_alpha, int dst_alpha, int operation) { ALLEGRO_COLOR reference, result, from_display; test_index++; if (test_only_index && test_index != test_only_index) return; reference = reference_implementation( src_col, dst_col, src_format, dst_format, src_mode, dst_mode, src_alpha, dst_alpha, operation); result = test(src_col, dst_col, src_format, dst_format, src_mode, dst_mode, src_alpha, dst_alpha, operation, false); if (!same_color(reference, result)) { test(src_col, dst_col, src_format, dst_format, src_mode, dst_mode, src_alpha, dst_alpha, operation, true); log_printf("expected : "); print_color(reference); log_printf("\n"); log_printf("FAILED\n"); } else { log_printf(" OK"); } if (test_display) { dst_format = al_get_display_format(display); from_display = al_get_pixel(al_get_backbuffer(display), 0, 0); reference = reference_implementation( src_col, dst_col, src_format, dst_format, src_mode, dst_mode, src_alpha, dst_alpha, operation); if (!same_color(reference, from_display)) { test(src_col, dst_col, src_format, dst_format, src_mode, dst_mode, src_alpha, dst_alpha, operation, true); log_printf("displayed : "); print_color(from_display); log_printf("\n"); log_printf("expected : "); print_color(reference); log_printf("\n"); log_printf("(FAILED on display)\n"); } } } static void do_test1(ALLEGRO_COLOR src_col, ALLEGRO_COLOR dst_col, int src_format, int dst_format) { int i, j, k, l, m; int smodes[4] = {ALLEGRO_ALPHA, ALLEGRO_ZERO, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA}; int dmodes[4] = {ALLEGRO_INVERSE_ALPHA, ALLEGRO_ZERO, ALLEGRO_ONE, ALLEGRO_ALPHA}; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { for (k = 0; k < 4; k++) { for (l = 0; l < 4; l++) { for (m = 0; m < 3; m++) { do_test2(src_col, dst_col, src_format, dst_format, smodes[i], dmodes[j], smodes[k], dmodes[l], m); } } } } } } #define C al_map_rgba_f int main(int argc, char **argv) { int i, j, l, m; ALLEGRO_COLOR src_colors[2]; ALLEGRO_COLOR dst_colors[2]; int src_formats[2] = { ALLEGRO_PIXEL_FORMAT_ABGR_8888, ALLEGRO_PIXEL_FORMAT_BGR_888 }; int dst_formats[2] = { ALLEGRO_PIXEL_FORMAT_ABGR_8888, ALLEGRO_PIXEL_FORMAT_BGR_888 }; src_colors[0] = C(0, 0, 0, 1); src_colors[1] = C(1, 1, 1, 1); dst_colors[0] = C(1, 1, 1, 1); dst_colors[1] = C(0, 0, 0, 0); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-d")) test_display = 1; else test_only_index = strtol(argv[i], NULL, 10); } if (!al_init()) { abort_example("Could not initialise Allegro\n"); } open_log(); al_init_primitives_addon(); if (test_display) { display = al_create_display(100, 100); if (!display) { abort_example("Unable to create display\n"); } } for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { for (l = 0; l < 2; l++) { for (m = 0; m < 2; m++) { do_test1( src_colors[i], dst_colors[j], src_formats[l], dst_formats[m]); } } } } log_printf("\nDone\n"); if (test_only_index && test_display) { ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; al_flip_display(); al_install_keyboard(); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_wait_for_event(queue, &event); } close_log(true); return 0; } allegro5-5.2.10.1/examples/ex_blit.c000066400000000000000000000151001473414355200170650ustar00rootroot00000000000000/* An example demonstrating different blending modes. */ #include #include #include #include #include #include #include #include "common.c" struct Example { ALLEGRO_BITMAP *pattern; ALLEGRO_FONT *font; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_COLOR background, text, white; double timer[4], counter[4]; int FPS; float text_x, text_y; } ex; static ALLEGRO_BITMAP *example_bitmap(int w, int h) { int i, j; float mx = w * 0.5; float my = h * 0.5; ALLEGRO_STATE state; ALLEGRO_BITMAP *pattern = al_create_bitmap(w, h); al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP); al_set_target_bitmap(pattern); al_lock_bitmap(pattern, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); for (i = 0; i < w; i++) { for (j = 0; j < h; j++) { float a = atan2(i - mx, j - my); float d = sqrt(pow(i - mx, 2) + pow(j - my, 2)); float sat = pow(1.0 - 1 / (1 + d * 0.1), 5); float hue = 3 * a * 180 / ALLEGRO_PI; hue = (hue / 360 - floorf(hue / 360)) * 360; al_put_pixel(i, j, al_color_hsv(hue, sat, 1)); } } al_put_pixel(0, 0, al_map_rgb(0, 0, 0)); al_unlock_bitmap(pattern); al_restore_state(&state); return pattern; } static void set_xy(float x, float y) { ex.text_x = x; ex.text_y = y; } static void get_xy(float *x, float *y) { *x = ex.text_x; *y = ex.text_y; } static void print(char const *format, ...) { va_list list; char message[1024]; int th = al_get_font_line_height(ex.font); va_start(list, format); vsnprintf(message, sizeof message, format, list); va_end(list); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(ex.font, ex.text, ex.text_x, ex.text_y, 0, "%s", message); ex.text_y += th; } static void start_timer(int i) { ex.timer[i] -= al_get_time(); ex.counter[i]++; } static void stop_timer(int i) { ex.timer[i] += al_get_time(); } static double get_fps(int i) { if (ex.timer[i] == 0) return 0; return ex.counter[i] / ex.timer[i]; } static void draw(void) { float x, y; int iw = al_get_bitmap_width(ex.pattern); int ih = al_get_bitmap_height(ex.pattern); ALLEGRO_BITMAP *screen, *temp; ALLEGRO_LOCKED_REGION *lock; void *data; int size, i, format; al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_clear_to_color(ex.background); screen = al_get_target_bitmap(); set_xy(8, 8); /* Test 1. */ /* Disabled: drawing to same bitmap is not supported. */ /* print("Screen -> Screen (%.1f fps)", get_fps(0)); get_xy(&x, &y); al_draw_bitmap(ex.pattern, x, y, 0); start_timer(0); al_draw_bitmap_region(screen, x, y, iw, ih, x + 8 + iw, y, 0); stop_timer(0); set_xy(x, y + ih); */ /* Test 2. */ print("Screen -> Bitmap -> Screen (%.1f fps)", get_fps(1)); get_xy(&x, &y); al_draw_bitmap(ex.pattern, x, y, 0); temp = al_create_bitmap(iw, ih); al_set_target_bitmap(temp); al_clear_to_color(al_map_rgba_f(1, 0, 0, 1)); start_timer(1); al_draw_bitmap_region(screen, x, y, iw, ih, 0, 0, 0); al_set_target_bitmap(screen); al_draw_bitmap(temp, x + 8 + iw, y, 0); stop_timer(1); set_xy(x, y + ih); al_destroy_bitmap(temp); /* Test 3. */ print("Screen -> Memory -> Screen (%.1f fps)", get_fps(2)); get_xy(&x, &y); al_draw_bitmap(ex.pattern, x, y, 0); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); temp = al_create_bitmap(iw, ih); al_set_target_bitmap(temp); al_clear_to_color(al_map_rgba_f(1, 0, 0, 1)); start_timer(2); al_draw_bitmap_region(screen, x, y, iw, ih, 0, 0, 0); al_set_target_bitmap(screen); al_draw_bitmap(temp, x + 8 + iw, y, 0); stop_timer(2); set_xy(x, y + ih); al_destroy_bitmap(temp); al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP); /* Test 4. */ print("Screen -> Locked -> Screen (%.1f fps)", get_fps(3)); get_xy(&x, &y); al_draw_bitmap(ex.pattern, x, y, 0); start_timer(3); lock = al_lock_bitmap_region(screen, x, y, iw, ih, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); format = lock->format; size = lock->pixel_size; data = malloc(size * iw * ih); for (i = 0; i < ih; i++) memcpy((char*)data + i * size * iw, (char*)lock->data + i * lock->pitch, size * iw); al_unlock_bitmap(screen); lock = al_lock_bitmap_region(screen, x + 8 + iw, y, iw, ih, format, ALLEGRO_LOCK_WRITEONLY); for (i = 0; i < ih; i++) memcpy((char*)lock->data + i * lock->pitch, (char*)data + i * size * iw, size * iw); al_unlock_bitmap(screen); free(data); stop_timer(3); set_xy(x, y + ih); } static void tick(void) { draw(); al_flip_display(); } static void run(void) { ALLEGRO_EVENT event; bool need_draw = true; while (1) { if (need_draw && al_is_event_queue_empty(ex.queue)) { tick(); need_draw = false; } al_wait_for_event(ex.queue, &event); switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: return; case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) return; break; case ALLEGRO_EVENT_TIMER: need_draw = true; break; } } } static void init(void) { ex.FPS = 60; ex.font = al_load_font("data/fixed_font.tga", 0, 0); if (!ex.font) { abort_example("data/fixed_font.tga not found\n"); } ex.background = al_color_name("beige"); ex.text = al_color_name("black"); ex.white = al_color_name("white"); ex.pattern = example_bitmap(100, 100); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_install_mouse(); al_init_image_addon(); al_init_font_addon(); init_platform_specific(); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } init(); timer = al_create_timer(1.0 / ex.FPS); ex.queue = al_create_event_queue(); al_register_event_source(ex.queue, al_get_keyboard_event_source()); al_register_event_source(ex.queue, al_get_mouse_event_source()); al_register_event_source(ex.queue, al_get_display_event_source(display)); al_register_event_source(ex.queue, al_get_timer_event_source(timer)); al_start_timer(timer); run(); al_destroy_event_queue(ex.queue); return 0; } allegro5-5.2.10.1/examples/ex_camera.c000066400000000000000000000431431473414355200173730ustar00rootroot00000000000000/* An example demonstrating how to use ALLEGRO_TRANSFORM to represent a 3D * camera. */ #include #include #include #include #include #include #include "common.c" #define pi ALLEGRO_PI typedef struct { float x, y, z; } Vector; typedef struct { Vector position; Vector xaxis; /* This represent the direction looking to the right. */ Vector yaxis; /* This is the up direction. */ Vector zaxis; /* This is the direction towards the viewer ('backwards'). */ double vertical_field_of_view; /* In radians. */ } Camera; typedef struct { Camera camera; /* controls sensitivity */ double mouse_look_speed; double movement_speed; /* keyboard and mouse state */ int button[10]; int key[ALLEGRO_KEY_MAX]; int keystate[ALLEGRO_KEY_MAX]; int mouse_dx, mouse_dy; /* control scheme selection */ int controls; char const *controls_names[3]; /* the vertex data */ int n, v_size; ALLEGRO_VERTEX *v; /* used to draw some info text */ ALLEGRO_FONT *font; /* if not NULL the skybox picture to use */ ALLEGRO_BITMAP *skybox; } Example; Example ex; /* Calculate the dot product between two vectors. This corresponds to the * angle between them times their lengths. */ static double vector_dot_product(Vector a, Vector b) { return a.x * b.x + a.y * b.y + a.z * b.z; } /* Calculate the cross product of two vectors. This produces a normal to the * plane containing the operands. */ static Vector vector_cross_product(Vector a, Vector b) { Vector v = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return v; } /* Return a vector multiplied by a scalar. */ static Vector vector_mul(Vector a, float s) { Vector v = {a.x * s, a.y * s, a.z * s}; return v; } /* Return the vector norm (length). */ static double vector_norm(Vector a) { return sqrt(vector_dot_product(a, a)); } /* Return a normalized version of the given vector. */ static Vector vector_normalize(Vector a) { double s = vector_norm(a); if (s == 0) return a; return vector_mul(a, 1 / s); } /* In-place add another vector to a vector. */ static void vector_iadd(Vector *a, Vector b) { a->x += b.x; a->y += b.y; a->z += b.z; } /* Rotate the camera around the given axis. */ static void camera_rotate_around_axis(Camera *c, Vector axis, double radians) { ALLEGRO_TRANSFORM t; al_identity_transform(&t); al_rotate_transform_3d(&t, axis.x, axis.y, axis.z, radians); al_transform_coordinates_3d(&t, &c->yaxis.x, &c->yaxis.y, &c->yaxis.z); al_transform_coordinates_3d(&t, &c->zaxis.x, &c->zaxis.y, &c->zaxis.z); /* Make sure the axes remain orthogonal to each other. */ c->zaxis = vector_normalize(c->zaxis); c->xaxis = vector_cross_product(c->yaxis, c->zaxis); c->xaxis = vector_normalize(c->xaxis); c->yaxis = vector_cross_product(c->zaxis, c->xaxis); } /* Move the camera along its x axis and z axis (which corresponds to * right and backwards directions). */ static void camera_move_along_direction(Camera *camera, double right, double forward) { vector_iadd(&camera->position, vector_mul(camera->xaxis, right)); vector_iadd(&camera->position, vector_mul(camera->zaxis, -forward)); } /* Get a vector with y = 0 looking in the opposite direction as the camera z * axis. If looking straight up or down returns a 0 vector instead. */ static Vector get_ground_forward_vector(Camera *camera) { Vector move = vector_mul(camera->zaxis, -1); move.y = 0; return vector_normalize(move); } /* Get a vector with y = 0 looking in the same direction as the camera x axis. * If looking straight up or down returns a 0 vector instead. */ static Vector get_ground_right_vector(Camera *camera) { Vector move = camera->xaxis; move.y = 0; return vector_normalize(move); } /* Like camera_move_along_direction but moves the camera along the ground plane * only. */ static void camera_move_along_ground(Camera *camera, double right, double forward) { Vector f = get_ground_forward_vector(camera); Vector r = get_ground_right_vector(camera); camera->position.x += f.x * forward + r.x * right; camera->position.z += f.z * forward + r.z * right; } /* Calculate the pitch of the camera. This is the angle between the z axis * vector and our direction vector on the y = 0 plane. */ static double get_pitch(Camera *c) { Vector f = get_ground_forward_vector(c); return asin(vector_dot_product(f, c->yaxis)); } /* Calculate the yaw of the camera. This is basically the compass direction. */ static double get_yaw(Camera *c) { return atan2(c->zaxis.x, c->zaxis.z); } /* Calculate the roll of the camera. This is the angle between the x axis * vector and its project on the y = 0 plane. */ static double get_roll(Camera *c) { Vector r = get_ground_right_vector(c); return asin(vector_dot_product(r, c->yaxis)); } /* Set up a perspective transform. We make the screen span * 2 vertical units (-1 to +1) with square pixel aspect and the camera's * vertical field of view. Clip distance is always set to 1. */ static void setup_3d_projection(void) { ALLEGRO_TRANSFORM projection; ALLEGRO_DISPLAY *display = al_get_current_display(); double dw = al_get_display_width(display); double dh = al_get_display_height(display); double f; al_identity_transform(&projection); al_translate_transform_3d(&projection, 0, 0, -1); f = tan(ex.camera.vertical_field_of_view / 2); al_perspective_transform(&projection, -1 * dw / dh * f, f, 1, f * dw / dh, -f, 1000); al_use_projection_transform(&projection); } /* Adds a new vertex to our scene. */ static void add_vertex(double x, double y, double z, double u, double v, ALLEGRO_COLOR color) { int i = ex.n++; if (i >= ex.v_size) { ex.v_size += 1; ex.v_size *= 2; ex.v = realloc(ex.v, ex.v_size * sizeof *ex.v); } ex.v[i].x = x; ex.v[i].y = y; ex.v[i].z = z; ex.v[i].u = u; ex.v[i].v = v; ex.v[i].color = color; } /* Adds two triangles (6 vertices) to the scene. */ static void add_quad(double x, double y, double z, double u, double v, double ux, double uy, double uz, double uu, double uv, double vx, double vy, double vz, double vu, double vv, ALLEGRO_COLOR c1, ALLEGRO_COLOR c2) { add_vertex(x, y, z, u, v, c1); add_vertex(x + ux, y + uy, z + uz, u + uu, v + uv, c1); add_vertex(x + vx, y + vy, z + vz, u + vu, v + vv, c2); add_vertex(x + vx, y + vy, z + vz, u + vu, v + vv, c2); add_vertex(x + ux, y + uy, z + uz, u + uu, v + uv, c1); add_vertex(x + ux + vx, y + uy + vy, z + uz + vz, u + uu + vu, v + uv + vv, c2); } /* Create a checkerboard made from colored quads. */ static void add_checkerboard(void) { int x, y; ALLEGRO_COLOR c1 = al_color_name("yellow"); ALLEGRO_COLOR c2 = al_color_name("green"); for (y = 0; y < 20; y++) { for (x = 0; x < 20; x++) { double px = x - 20 * 0.5; double py = 0.2; double pz = y - 20 * 0.5; ALLEGRO_COLOR c = c1; if ((x + y) & 1) { c = c2; py -= 0.1; } add_quad(px, py, pz, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, c, c); } } } /* Create a skybox. This is simply 5 quads with a fixed distance to the * camera. */ static void add_skybox(void) { Vector p = ex.camera.position; ALLEGRO_COLOR c1 = al_color_name("black"); ALLEGRO_COLOR c2 = al_color_name("blue"); ALLEGRO_COLOR c3 = al_color_name("white"); double a = 0, b = 0; if (ex.skybox) { a = al_get_bitmap_width(ex.skybox) / 4.0; b = al_get_bitmap_height(ex.skybox) / 3.0; c1 = c2 = c3; } /* Back skybox wall. */ add_quad(p.x - 50, p.y - 50, p.z - 50, a * 4, b * 2, 100, 0, 0, -a, 0, 0, 100, 0, 0, -b, c1, c2); /* Front skybox wall. */ add_quad(p.x - 50, p.y - 50, p.z + 50, a, b * 2, 100, 0, 0, a, 0, 0, 100, 0, 0, -b, c1, c2); /* Left skybox wall. */ add_quad(p.x - 50, p.y - 50, p.z - 50, 0, b * 2, 0, 0, 100, a, 0, 0, 100, 0, 0, -b, c1, c2); /* Right skybox wall. */ add_quad(p.x + 50, p.y - 50, p.z - 50, a * 3, b * 2, 0, 0, 100, -a, 0, 0, 100, 0, 0, -b, c1, c2); /* Top of skybox. */ add_vertex(p.x - 50, p.y + 50, p.z - 50, a, 0, c2); add_vertex(p.x + 50, p.y + 50, p.z - 50, a * 2, 0, c2); add_vertex(p.x, p.y + 50, p.z, a * 1.5, b * 0.5, c3); add_vertex(p.x + 50, p.y + 50, p.z - 50, a * 2, 0, c2); add_vertex(p.x + 50, p.y + 50, p.z + 50, a * 2, b, c2); add_vertex(p.x, p.y + 50, p.z, a * 1.5, b * 0.5, c3); add_vertex(p.x + 50, p.y + 50, p.z + 50, a * 2, b, c2); add_vertex(p.x - 50, p.y + 50, p.z + 50, a, b, c2); add_vertex(p.x, p.y + 50, p.z, a * 1.5, b * 0.5, c3); add_vertex(p.x - 50, p.y + 50, p.z + 50, a, b, c2); add_vertex(p.x - 50, p.y + 50, p.z - 50, a, 0, c2); add_vertex(p.x, p.y + 50, p.z, a * 1.5, b * 0.5, c3); } static void draw_scene(void) { Camera *c = &ex.camera; /* We save Allegro's projection so we can restore it for drawing text. */ ALLEGRO_TRANSFORM projection = *al_get_current_projection_transform(); ALLEGRO_TRANSFORM t; ALLEGRO_COLOR back = al_color_name("black"); ALLEGRO_COLOR front = al_color_name("white"); int th; double pitch, yaw, roll; setup_3d_projection(); al_clear_to_color(back); /* We use a depth buffer. */ al_set_render_state(ALLEGRO_DEPTH_TEST, 1); al_clear_depth_buffer(1); /* Recreate the entire scene geometry - this is only a very small example * so this is fine. */ ex.n = 0; add_checkerboard(); add_skybox(); /* Construct a transform corresponding to our camera. This is an inverse * translation by the camera position, followed by an inverse rotation * from the camera orientation. */ al_build_camera_transform(&t, ex.camera.position.x, ex.camera.position.y, ex.camera.position.z, ex.camera.position.x - ex.camera.zaxis.x, ex.camera.position.y - ex.camera.zaxis.y, ex.camera.position.z - ex.camera.zaxis.z, ex.camera.yaxis.x, ex.camera.yaxis.y, ex.camera.yaxis.z); al_use_transform(&t); al_draw_prim(ex.v, NULL, ex.skybox, 0, ex.n, ALLEGRO_PRIM_TRIANGLE_LIST); /* Restore projection. */ al_identity_transform(&t); al_use_transform(&t); al_use_projection_transform(&projection); al_set_render_state(ALLEGRO_DEPTH_TEST, 0); /* Draw some text. */ th = al_get_font_line_height(ex.font); al_draw_textf(ex.font, front, 0, th * 0, 0, "look: %+3.1f/%+3.1f/%+3.1f (change with left mouse button and drag)", -c->zaxis.x, -c->zaxis.y, -c->zaxis.z); pitch = get_pitch(c) * 180 / pi; yaw = get_yaw(c) * 180 / pi; roll = get_roll(c) * 180 / pi; al_draw_textf(ex.font, front, 0, th * 1, 0, "pitch: %+4.0f yaw: %+4.0f roll: %+4.0f", pitch, yaw, roll); al_draw_textf(ex.font, front, 0, th * 2, 0, "vertical field of view: %3.1f (change with Z/X)", c->vertical_field_of_view * 180 / pi); al_draw_textf(ex.font, front, 0, th * 3, 0, "move with WASD or cursor"); al_draw_textf(ex.font, front, 0, th * 4, 0, "control style: %s (space to change)", ex.controls_names[ex.controls]); } static void setup_scene(void) { ex.camera.xaxis.x = 1; ex.camera.yaxis.y = 1; ex.camera.zaxis.z = 1; ex.camera.position.y = 2; ex.camera.vertical_field_of_view = 60 * pi / 180; ex.mouse_look_speed = 0.03; ex.movement_speed = 0.05; ex.controls_names[0] = "FPS"; ex.controls_names[1] = "airplane"; ex.controls_names[2] = "spaceship"; ex.font = al_create_builtin_font(); } static void handle_input(void) { double x = 0, y = 0; double xy; if (ex.key[ALLEGRO_KEY_A] || ex.key[ALLEGRO_KEY_LEFT]) x = -1; if (ex.key[ALLEGRO_KEY_S] || ex.key[ALLEGRO_KEY_DOWN]) y = -1; if (ex.key[ALLEGRO_KEY_D] || ex.key[ALLEGRO_KEY_RIGHT]) x = 1; if (ex.key[ALLEGRO_KEY_W] || ex.key[ALLEGRO_KEY_UP]) y = 1; /* Change field of view with Z/X. */ if (ex.key[ALLEGRO_KEY_Z]) { double m = 20 * pi / 180; ex.camera.vertical_field_of_view -= 0.01; if (ex.camera.vertical_field_of_view < m) ex.camera.vertical_field_of_view = m; } if (ex.key[ALLEGRO_KEY_X]) { double m = 120 * pi / 180; ex.camera.vertical_field_of_view += 0.01; if (ex.camera.vertical_field_of_view > m) ex.camera.vertical_field_of_view = m; } /* In FPS style, always move the camera to height 2. */ if (ex.controls == 0) { if (ex.camera.position.y > 2) ex.camera.position.y -= 0.1; if (ex.camera.position.y < 2) ex.camera.position.y = 2; } /* Set the roll (leaning) angle to 0 if not in airplane style. */ if (ex.controls == 0 || ex.controls == 2) { double roll = get_roll(&ex.camera); camera_rotate_around_axis(&ex.camera, ex.camera.zaxis, roll / 60); } /* Move the camera, either freely or along the ground. */ xy = sqrt(x * x + y * y); if (xy > 0) { x /= xy; y /= xy; if (ex.controls == 0) { camera_move_along_ground(&ex.camera, ex.movement_speed * x, ex.movement_speed * y); } if (ex.controls == 1 || ex.controls == 2) { camera_move_along_direction(&ex.camera, ex.movement_speed * x, ex.movement_speed * y); } } /* Rotate the camera, either freely or around world up only. */ if (ex.button[1]) { if (ex.controls == 0 || ex.controls == 2) { Vector up = {0, 1, 0}; camera_rotate_around_axis(&ex.camera, ex.camera.xaxis, -ex.mouse_look_speed * ex.mouse_dy); camera_rotate_around_axis(&ex.camera, up, -ex.mouse_look_speed * ex.mouse_dx); } if (ex.controls == 1) { camera_rotate_around_axis(&ex.camera, ex.camera.xaxis, -ex.mouse_look_speed * ex.mouse_dy); camera_rotate_around_axis(&ex.camera, ex.camera.zaxis, -ex.mouse_look_speed * ex.mouse_dx); } } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; int redraw = 0; bool halt_drawing = false; char const *skybox_name = NULL; if (argc > 1) { skybox_name = argv[1]; } if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_font_addon(); al_init_primitives_addon(); init_platform_specific(); al_install_keyboard(); al_install_mouse(); al_set_config_value(al_get_system_config(), "osx", "allow_live_resize", "false"); al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST); al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST); al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 16, ALLEGRO_SUGGEST); al_set_new_display_flags(ALLEGRO_RESIZABLE); display = al_create_display(640, 360); if (!display) { abort_example("Error creating display\n"); } if (skybox_name) { al_init_image_addon(); ex.skybox = al_load_bitmap(skybox_name); if (ex.skybox) { printf("Loaded skybox %s: %d x %d\n", skybox_name, al_get_bitmap_width(ex.skybox), al_get_bitmap_height(ex.skybox)); } else { printf("Failed loading skybox %s\n", skybox_name); } } timer = al_create_timer(1.0 / 60); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); setup_scene(); al_start_timer(timer); while (true) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; else if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { al_acknowledge_resize(display); } else if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) { ex.controls++; ex.controls %= 3; } ex.key[event.keyboard.keycode] = 1; ex.keystate[event.keyboard.keycode] = 1; } else if (event.type == ALLEGRO_EVENT_KEY_UP) { /* In case a key gets pressed and immediately released, we will still * have set ex.key so it is not lost. */ ex.keystate[event.keyboard.keycode] = 0; } else if (event.type == ALLEGRO_EVENT_TIMER) { int i; handle_input(); redraw = 1; /* Reset keyboard state for keys not held down anymore. */ for (i = 0; i < ALLEGRO_KEY_MAX; i++) { if (ex.keystate[i] == 0) ex.key[i] = 0; } ex.mouse_dx = 0; ex.mouse_dy = 0; } else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { ex.button[event.mouse.button] = 1; } else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { ex.button[event.mouse.button] = 0; } else if (event.type == ALLEGRO_EVENT_DISPLAY_HALT_DRAWING) { halt_drawing = true; al_acknowledge_drawing_halt(display); } else if (event.type == ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING) { halt_drawing = false; al_acknowledge_drawing_resume(display); } else if (event.type == ALLEGRO_EVENT_MOUSE_AXES) { ex.mouse_dx += event.mouse.dx; ex.mouse_dy += event.mouse.dy; } if (!halt_drawing && redraw && al_is_event_queue_empty(queue)) { draw_scene(); al_flip_display(); redraw = 0; } } return 0; } allegro5-5.2.10.1/examples/ex_clip.c000066400000000000000000000127461473414355200170770ustar00rootroot00000000000000/* Test performance of al_draw_bitmap_region, al_create_sub_bitmap and * al_set_clipping_rectangle when clipping a bitmap. */ #include #include #include #include #include #include #include "common.c" struct Example { ALLEGRO_BITMAP *pattern; ALLEGRO_FONT *font; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_COLOR background, text, white; double timer[4], counter[4]; int FPS; float text_x, text_y; } ex; static ALLEGRO_BITMAP *example_bitmap(int w, int h) { int i, j; float mx = w * 0.5; float my = h * 0.5; ALLEGRO_STATE state; ALLEGRO_BITMAP *pattern = al_create_bitmap(w, h); al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP); al_set_target_bitmap(pattern); al_lock_bitmap(pattern, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); for (i = 0; i < w; i++) { for (j = 0; j < h; j++) { float a = atan2(i - mx, j - my); float d = sqrt(pow(i - mx, 2) + pow(j - my, 2)); float l = 1 - pow(1.0 - 1 / (1 + d * 0.1), 5); float hue = a * 180 / ALLEGRO_PI; float sat = 1; if (i == 0 || j == 0 || i == w - 1 || j == h - 1) { hue += 180; } else if (i == 1 || j == 1 || i == w - 2 || j == h - 2) { hue += 180; sat = 0.5; } al_put_pixel(i, j, al_color_hsl(hue, sat, l)); } } al_unlock_bitmap(pattern); al_restore_state(&state); return pattern; } static void set_xy(float x, float y) { ex.text_x = x; ex.text_y = y; } static void get_xy(float *x, float *y) { *x = ex.text_x; *y = ex.text_y; } static void print(char const *format, ...) { va_list list; char message[1024]; int th = al_get_font_line_height(ex.font); va_start(list, format); vsnprintf(message, sizeof message, format, list); va_end(list); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(ex.font, ex.text, ex.text_x, ex.text_y, 0, "%s", message); ex.text_y += th; } static void start_timer(int i) { ex.timer[i] -= al_get_time(); ex.counter[i]++; } static void stop_timer(int i) { ex.timer[i] += al_get_time(); } static double get_fps(int i) { if (ex.timer[i] == 0) return 0; return ex.counter[i] / ex.timer[i]; } static void draw(void) { float x, y; int iw = al_get_bitmap_width(ex.pattern); int ih = al_get_bitmap_height(ex.pattern); ALLEGRO_BITMAP *temp; int cx, cy, cw, ch, gap = 8; al_get_clipping_rectangle(&cx, &cy, &cw, &ch); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_clear_to_color(ex.background); /* Test 1. */ set_xy(8, 8); print("al_draw_bitmap_region (%.1f fps)", get_fps(0)); get_xy(&x, &y); al_draw_bitmap(ex.pattern, x, y, 0); start_timer(0); al_draw_bitmap_region(ex.pattern, 1, 1, iw - 2, ih - 2, x + 8 + iw + 1, y + 1, 0); stop_timer(0); set_xy(x, y + ih + gap); /* Test 2. */ print("al_create_sub_bitmap (%.1f fps)", get_fps(1)); get_xy(&x, &y); al_draw_bitmap(ex.pattern, x, y, 0); start_timer(1); temp = al_create_sub_bitmap(ex.pattern, 1, 1, iw - 2, ih - 2); al_draw_bitmap(temp, x + 8 + iw + 1, y + 1, 0); al_destroy_bitmap(temp); stop_timer(1); set_xy(x, y + ih + gap); /* Test 3. */ print("al_set_clipping_rectangle (%.1f fps)", get_fps(2)); get_xy(&x, &y); al_draw_bitmap(ex.pattern, x, y, 0); start_timer(2); al_set_clipping_rectangle(x + 8 + iw + 1, y + 1, iw - 2, ih - 2); al_draw_bitmap(ex.pattern, x + 8 + iw, y, 0); al_set_clipping_rectangle(cx, cy, cw, ch); stop_timer(2); set_xy(x, y + ih + gap); } static void tick(void) { draw(); al_flip_display(); } static void run(void) { ALLEGRO_EVENT event; bool need_draw = true; while (1) { if (need_draw && al_is_event_queue_empty(ex.queue)) { tick(); need_draw = false; } al_wait_for_event(ex.queue, &event); switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: return; case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) return; break; case ALLEGRO_EVENT_TIMER: need_draw = true; break; } } } static void init(void) { ex.FPS = 60; ex.font = al_create_builtin_font(); if (!ex.font) { abort_example("Error creating builtin font.\n"); } ex.background = al_color_name("beige"); ex.text = al_color_name("blue"); ex.white = al_color_name("white"); ex.pattern = example_bitmap(100, 100); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_install_mouse(); al_init_font_addon(); init_platform_specific(); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display.\n"); } init(); timer = al_create_timer(1.0 / ex.FPS); ex.queue = al_create_event_queue(); al_register_event_source(ex.queue, al_get_keyboard_event_source()); al_register_event_source(ex.queue, al_get_mouse_event_source()); al_register_event_source(ex.queue, al_get_display_event_source(display)); al_register_event_source(ex.queue, al_get_timer_event_source(timer)); al_start_timer(timer); run(); al_destroy_event_queue(ex.queue); return 0; } allegro5-5.2.10.1/examples/ex_clipboard.c000066400000000000000000000052561473414355200201050ustar00rootroot00000000000000/* An example showing bitmap flipping flags, by Steven Wallace. */ #include #include #include #include "common.c" #define INTERVAL 0.1 int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_FONT *font; char *text = NULL; bool done = false; bool redraw = true; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } if (!al_init_image_addon()) { abort_example("Failed to init IIO addon.\n"); } al_init_font_addon(); init_platform_specific(); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display.\n"); } if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } font = al_load_font("data/fixed_font.tga", 0, 0); if (!font) { abort_example("Error loading data/fixed_font.tga\n"); } timer = al_create_timer(INTERVAL); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(display)); al_start_timer(timer); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); while (!done) { ALLEGRO_EVENT event; if (redraw && al_is_event_queue_empty(queue)) { if (text) al_free(text); if (al_clipboard_has_text(display)) { text = al_get_clipboard_text(display); } else { text = NULL; } al_clear_to_color(al_map_rgb_f(0, 0, 0)); if (text) { al_draw_text(font, al_map_rgba_f(1, 1, 1, 1.0), 0, 0, 0, text); } else { al_draw_text(font, al_map_rgba_f(1, 0, 0, 1.0), 0, 0, 0, "No clipboard text available."); } al_flip_display(); redraw = false; } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { done = true; } else if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) { al_set_clipboard_text(display, "Copied from Allegro!"); } break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_TIMER: redraw = true; break; } } al_destroy_font(font); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_color.cpp000066400000000000000000000165621473414355200176260ustar00rootroot00000000000000/* * Example program for the Allegro library, by Elias Pschernig. * * Demonstrates some of the conversion functions in the color addon. */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_ttf.h" #include "allegro5/allegro_color.h" #include #include "nihgui.hpp" #include "common.c" #define SLIDERS_COUNT 19 char const *names[] = {"R", "G", "B", "H", "S", "V", "H", "S", "L", "Y", "U", "V", "C", "M", "Y", "K", "L", "C", "H"}; float clamp(float x) { if (x < 0) return 0; if (x > 1) return 1; return x; } class Prog { private: Dialog d; VSlider sliders[SLIDERS_COUNT]; Label labels[SLIDERS_COUNT]; Label labels2[SLIDERS_COUNT]; int previous[SLIDERS_COUNT]; public: Prog(const Theme & theme, ALLEGRO_DISPLAY *display); void run(); private: void draw_swatch(float x, float y, float w, float h, float v[3]); }; Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) : d(Dialog(theme, display, 640, 480)) { for (int i = 0; i < SLIDERS_COUNT; i++) { int j = i < 12 ? i / 3 : i < 16 ? 4 : 5; sliders[i] = VSlider(1000, 1000); d.add(sliders[i], 8 + i * 32 + j * 16, 8, 15, 256); labels[i].set_text(names[i]); d.add(labels[i], i * 32 + j * 16, 8 + 256, 32, 20); d.add(labels2[i], i * 32 + j * 16, 8 + 276, 32, 20); previous[i] = 0; } } void Prog::run() { d.prepare(); while (!d.is_quit_requested()) { if (d.is_draw_requested()) { al_clear_to_color(al_map_rgb(128, 128, 128)); float v[SLIDERS_COUNT]; int keep = -1; for (int i = 0; i < SLIDERS_COUNT; i++) { int x = sliders[i].get_cur_value(); v[i] = x / 1000.0; if (previous[i] != x) { keep = i; } } if (keep != -1) { int space = keep < 12 ? keep / 3 : keep < 16 ? 4 : 5; switch (space) { case 0: al_color_rgb_to_hsv(v[0], v[1], v[2], v + 3, v + 4, v + 5); al_color_rgb_to_hsl(v[0], v[1], v[2], v + 6, v + 7, v + 8); al_color_rgb_to_cmyk(v[0], v[1], v[2], v + 12, v + 13, v + 14, v + 15); al_color_rgb_to_yuv(v[0], v[1], v[2], v + 9, v + 10, v + 11); al_color_rgb_to_lch(v[0], v[1], v[2], v + 16, v + 17, v + 18); v[3] /= 360; v[6] /= 360; v[18] /= ALLEGRO_PI * 2; break; case 1: al_color_hsv_to_rgb(v[3] * 360, v[4], v[5], v + 0, v + 1, v + 2); al_color_rgb_to_hsl(v[0], v[1], v[2], v + 6, v + 7, v + 8); al_color_rgb_to_cmyk(v[0], v[1], v[2], v + 12, v + 13, v + 14, v + 15); al_color_rgb_to_yuv(v[0], v[1], v[2], v + 9, v + 10, v + 11); al_color_rgb_to_lch(v[0], v[1], v[2], v + 16, v + 17, v + 18); v[6] /= 360; v[18] /= ALLEGRO_PI * 2; break; case 2: al_color_hsl_to_rgb(v[6] * 360, v[7], v[8], v + 0, v + 1, v + 2); al_color_rgb_to_hsv(v[0], v[1], v[2], v + 3, v + 4, v + 5); al_color_rgb_to_cmyk(v[0], v[1], v[2], v + 12, v + 13, v + 14, v + 15); al_color_rgb_to_yuv(v[0], v[1], v[2], v + 9, v + 10, v + 11); al_color_rgb_to_lch(v[0], v[1], v[2], v + 16, v + 17, v + 18); v[3] /= 360; v[18] /= ALLEGRO_PI * 2; break; case 3: al_color_yuv_to_rgb(v[9], v[10], v[11], v + 0, v + 1, v + 2); v[0] = clamp(v[0]); v[1] = clamp(v[1]); v[2] = clamp(v[2]); al_color_rgb_to_yuv(v[0], v[1], v[2], v + 9, v + 10, v + 11); al_color_rgb_to_hsv(v[0], v[1], v[2], v + 3, v + 4, v + 5); al_color_rgb_to_hsl(v[0], v[1], v[2], v + 6, v + 7, v + 8); al_color_rgb_to_cmyk(v[0], v[1], v[2], v + 12, v + 13, v + 14, v + 15); al_color_rgb_to_lch(v[0], v[1], v[2], v + 16, v + 17, v + 18); v[3] /= 360; v[6] /= 360; v[18] /= ALLEGRO_PI * 2; break; case 4: al_color_cmyk_to_rgb(v[12], v[13], v[14], v[15], v + 0, v + 1, v + 2); al_color_rgb_to_hsv(v[0], v[1], v[2], v + 3, v + 4, v + 5); al_color_rgb_to_hsl(v[0], v[1], v[2], v + 6, v + 7, v + 8); al_color_rgb_to_yuv(v[0], v[1], v[2], v + 9, v + 10, v + 11); al_color_rgb_to_lch(v[0], v[1], v[2], v + 16, v + 17, v + 18); v[3] /= 360; v[6] /= 360; v[18] /= ALLEGRO_PI * 2; break; case 5: al_color_lch_to_rgb(v[16], v[17], v[18] * 2 * ALLEGRO_PI, v + 0, v + 1, v + 2); v[0] = clamp(v[0]); v[1] = clamp(v[1]); v[2] = clamp(v[2]); al_color_rgb_to_hsv(v[0], v[1], v[2], v + 3, v + 4, v + 5); al_color_rgb_to_hsl(v[0], v[1], v[2], v + 6, v + 7, v + 8); al_color_rgb_to_yuv(v[0], v[1], v[2], v + 9, v + 10, v + 11); al_color_rgb_to_lch(v[0], v[1], v[2], v + 16, v + 17, v + 18); v[3] /= 360; v[6] /= 360; v[18] /= ALLEGRO_PI * 2; break; } } for (int i = 0; i < SLIDERS_COUNT; i++) { sliders[i].set_cur_value((int)(v[i] * 1000)); previous[i] = sliders[i].get_cur_value(); char c[100]; sprintf(c, "%d", (int)(v[i] * 100)); labels2[i].set_text(c); } d.draw(); ALLEGRO_BITMAP *target = al_get_target_bitmap(); int w = al_get_bitmap_width(target); int h = al_get_bitmap_height(target); draw_swatch(0, h - 80, w, h, v); al_flip_display(); } d.run_step(true); } } void Prog::draw_swatch(float x1, float y1, float x2, float y2, float v[3]) { al_draw_filled_rectangle(x1, y1, x2, y2, al_map_rgb_f(v[0], v[1], v[2])); char const *name = al_color_rgb_to_name(v[0], v[1], v[2]); char html[8]; al_color_rgb_to_html(v[0], v[1], v[2], html); al_draw_text(d.get_theme().font, al_map_rgb(0, 0, 0), x1, y1 - 20, 0, name); al_draw_text(d.get_theme().font, al_map_rgb(0, 0, 0), x1, y1 - 40, 0, html); } int main(int argc, char *argv[]) { ALLEGRO_DISPLAY *display; ALLEGRO_FONT *font; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro\n"); } al_init_primitives_addon(); al_install_keyboard(); al_install_mouse(); al_init_font_addon(); al_init_ttf_addon(); init_platform_specific(); al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(720, 480); if (!display) { abort_example("Unable to create display\n"); } font = al_load_font("data/DejaVuSans.ttf", 12, 0); if (!font) { abort_example("Failed to load data/DejaVuSans.ttf\n"); } /* Prog is destroyed at the end of this scope. */ { Theme theme(font); Prog prog(theme, display); prog.run(); } al_destroy_font(font); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_color2.c000066400000000000000000000244671473414355200173530ustar00rootroot00000000000000#define ALLEGRO_UNSTABLE #include #include #include #include #include #include #include "common.c" #define FPS 60 typedef struct { ALLEGRO_COLOR rgb; float l, a, b; } Color; struct Example { ALLEGRO_FONT *font; ALLEGRO_BITMAP *lab[512]; ALLEGRO_COLOR black; ALLEGRO_COLOR white; Color color[2]; int mx, my; int mb; // 1 = clicked, 2 = released, 3 = pressed int slider; int top_y; int left_x; int slider_x; int half_x; } example; static void draw_lab(int l) { if (example.lab[l]) return; example.lab[l] = al_create_bitmap(512, 512); ALLEGRO_LOCKED_REGION *rg = al_lock_bitmap(example.lab[l], ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_WRITEONLY); int x, y; for (y = 0; y < 512; y++) { for (x = 0; x < 512; x++) { float a = (x - 511.0 / 2) / (511.0 / 2); float b = (y - 511.0 / 2) / (511.0 / 2); b = -b; ALLEGRO_COLOR rgb = al_color_lab(l / 511.0, a, b); if (!al_is_color_valid(rgb)) { rgb = al_map_rgb_f(0, 0, 0); } int red = 255 * rgb.r; int green = 255 * rgb.g; int blue = 255 * rgb.b; uint8_t *p = rg->data; p += rg->pitch * y; p += x * 4; p[0] = red; p[1] = green; p[2] = blue; p[3] = 255; } } al_unlock_bitmap(example.lab[l]); } static void draw_range(int ci) { float l = example.color[ci].l; int cx = (example.color[ci].a * 511.0 / 2) + 511.0 / 2; int cy = (-example.color[ci].b * 511.0 / 2) + 511.0 / 2; int r = 2; /* Loop around the center in outward circles, starting with a 3 x 3 * rectangle, then 5 x 5, then 7 x 7, and so on. * Each loop has four sides, top, right, bottom, left. For example * these are the four loops for the 5 x 5 case: * 1 2 3 4 . * . . * . . * . . * . . . . . * * o o o o 1 * . 2 * . 3 * . 4 * . . . . . * * o o o o o * . o * . o * . 3 2 1 1 * * o o o o o * 4 o * 3 o * 2 o * 1 o o o o * * 1654321 */ while (true) { bool found = false; int x = cx - r / 2; int y = cy - r / 2; int i; for (i = 0; i < r * 4; i++) { if (i < r) x++; else if (i < r * 2) y++; else if (i < r * 3) x--; else y--; float a = (x - 511.0 / 2) / (511.0 / 2); float b = (y - 511.0 / 2) / (511.0 / 2); float rf, gf, bf; b = -b; al_color_lab_to_rgb(l, a, b, &rf, &gf, &bf); if (rf < 0 || rf > 1 || gf < 0 || gf > 1 || bf < 0 || bf > 1) { continue; } ALLEGRO_COLOR rgb = {rf, gf, bf, 1}; float d = al_color_distance_ciede2000(rgb, example.color[ci].rgb); if (d <= 0.05) { if (d > 0.04) { al_draw_pixel(example.half_x * ci + example.left_x + x, example.top_y + y, example.white); } found = true; } } if (!found) break; r += 2; if (r > 128) break; } } static void init(void) { example.black = al_map_rgb_f(0, 0, 0); example.white = al_map_rgb_f(1, 1, 1); example.left_x = 120; example.top_y = 48; example.slider_x = 48; example.color[0].l = 0.5; example.color[1].l = 0.5; example.color[0].a = 0.2; example.half_x = al_get_display_width(al_get_current_display()) / 2; } static void draw_axis(float x, float y, float a, float a2, float l, float tl, char const *label, int ticks, char const *numformat, float num1, float num2, float num) { al_draw_line(x, y, x + l * cos(a), y - l * sin(a), example.white, 1); int i; for (i = 0; i < ticks; i++) { float x2 = x + l * cos(a) * i / (ticks - 1); float y2 = y - l * sin(a) * i / (ticks - 1); al_draw_line(x2, y2, x2 + tl * cos(a2), y2 - tl * sin(a2), example.white, 1); al_draw_textf(example.font, example.white, (int)(x2 + (tl + 2) * cos(a2)), (int)(y2 - (tl + 2) * sin(a2)), ALLEGRO_ALIGN_RIGHT, numformat, num1 + i * (num2 - num1) / (ticks - 1)); } float lv = (num - num1) * l / (num2 - num1); al_draw_filled_circle(x + lv * cos(a), y - lv * sin(a), 8, example.white); al_draw_textf(example.font, example.white, (int)(x + (l + 4) * cos(a)) - 24, (int)(y - (l + 4) * sin(a)) - 12, 0, "%s", label); } static void redraw(void) { al_clear_to_color(example.black); int w = al_get_display_width(al_get_current_display()); int h = al_get_display_height(al_get_current_display()); int ci; for (ci = 0; ci < 2; ci++) { int cx = w / 2 * ci; float l = example.color[ci].l; float a = example.color[ci].a; float b = example.color[ci].b; ALLEGRO_COLOR rgb = example.color[ci].rgb; draw_lab((int)(l * 511)); al_draw_bitmap(example.lab[(int)(l * 511)], cx + example.left_x, example.top_y, 0); draw_axis(cx + example.left_x, example.top_y + 512.5, 0, ALLEGRO_PI / -2, 512, 16, "a*", 11, "%.2f", -1, 1, a); draw_axis(cx + example.left_x - 0.5, example.top_y + 512, ALLEGRO_PI / 2, ALLEGRO_PI, 512, 16, "b*", 11, "%.2f", -1, 1, b); al_draw_textf(example.font, example.white, cx + example.left_x + 36, 8, 0, "L*a*b* = %.2f/%.2f/%.2f sRGB = %.2f/%.2f/%.2f", l, a, b, rgb.r, rgb.g, rgb.b); draw_axis(cx + example.slider_x - 0.5, example.top_y + 512, ALLEGRO_PI / 2, ALLEGRO_PI, 512, 4, "L*", 3, "%.1f", 0, 1, l); ALLEGRO_COLOR c = al_map_rgb_f(rgb.r, rgb.g, rgb.b); al_draw_filled_rectangle(cx, h - 128, cx + w / 2, h, c); draw_range(ci); } al_draw_textf(example.font, example.white, example.left_x + 36, 28, 0, "%s", "Lab colors visible in sRGB"); al_draw_textf(example.font, example.white, example.half_x + example.left_x + 36, 28, 0, "%s", "ellipse shows CIEDE2000 between 0.4 and 0.5"); al_draw_line(w / 2, 0, w / 2, h - 128, example.white, 4); float dr = example.color[0].rgb.r - example.color[1].rgb.r; float dg = example.color[0].rgb.g - example.color[1].rgb.g; float db = example.color[0].rgb.b - example.color[1].rgb.b; float drgb = sqrt(dr * dr + dg * dg + db * db); float dl = example.color[0].l - example.color[1].l; float da = example.color[0].a - example.color[1].a; db = example.color[0].b - example.color[1].b; float dlab = sqrt(da * da + db * db + dl * dl); float d2000 = al_color_distance_ciede2000(example.color[0].rgb, example.color[1].rgb); al_draw_textf(example.font, example.white, w / 2, h - 64, ALLEGRO_ALIGN_CENTER, "dRGB = %.2f", drgb); al_draw_textf(example.font, example.white, w / 2, h - 64 + 12, ALLEGRO_ALIGN_CENTER, "dLab = %.2f", dlab); al_draw_textf(example.font, example.white, w / 2, h - 64 + 24, ALLEGRO_ALIGN_CENTER, "CIEDE2000 = %.2f", d2000); al_draw_rectangle(w / 2 - 80, h - 70, w / 2 + 80, h - 24, example.white, 4); } static void update(void) { if (example.mb == 1 || example.mb == 3) { if (example.mb == 1) { int s = 0; int mx = example.mx; if (example.mx >= example.half_x) { mx -= example.half_x; s += 2; } if (mx > example.left_x) { s += 1; } example.slider = s; } if (example.slider == 0 || example.slider == 2) { int l = example.my - example.top_y; if (l < 0) l = 0; if (l > 511) l = 511; example.color[example.slider / 2].l = 1 - l / 511.0; } else { int ci = example.slider / 2; int a = example.mx - example.left_x - ci * example.half_x; int b = example.my - example.top_y; b = 511 - b; if (a < 0) a = 0; if (b < 0) b = 0; if (a > 511) a = 511; if (b > 511) b = 511; example.color[ci].a = 2 * a / 511.0 - 1; example.color[ci].b = 2 * b / 511.0 - 1; } } if (example.mb == 1) example.mb = 3; if (example.mb == 2) example.mb = 0; int ci; for (ci = 0; ci < 2; ci++) { example.color[ci].rgb = al_color_lab(example.color[ci].l, example.color[ci].a, example.color[ci].b); } } int main(int argc, char **argv) { ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_DISPLAY *display; int w = 1280, h = 720; bool done = false; bool need_redraw = true; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } al_init_font_addon(); example.font = al_create_builtin_font(); init_platform_specific(); display = al_create_display(w, h); if (!display) { abort_example("Error creating display.\n"); } al_install_keyboard(); al_install_mouse(); al_init_primitives_addon(); init(); timer = al_create_timer(1.0 / FPS); queue = al_create_event_queue(); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(display)); al_start_timer(timer); while (!done) { ALLEGRO_EVENT event; if (need_redraw) { redraw(); al_flip_display(); need_redraw = false; } while (true) { al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_CHAR: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; break; case ALLEGRO_EVENT_MOUSE_AXES: example.mx = event.mouse.x; example.my = event.mouse.y; break; case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: example.mb = 1; break; case ALLEGRO_EVENT_MOUSE_BUTTON_UP: example.mb = 2; break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_TIMER: update(); need_redraw = true; break; } if (al_is_event_queue_empty(queue)) break; } } return 0; } allegro5-5.2.10.1/examples/ex_color_gradient.c000066400000000000000000000215701473414355200211360ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Color gradient example program. * * This example draws several color gradients, each one linearly * interpolating between two colors. For each version interpolating * the raw R/G/B values there is also versions interpolating the * components in other color spaces (e.g. Oklab L/a/b). * * See readme.txt for copyright information. */ #define ALLEGRO_UNSTABLE #include #include #include #include #include #include #include #include #include "common.c" const int SCREEN_W = 1280; const int SCREEN_H = 720; typedef enum { RGB, LINEAR, HSV, OKLAB, CIELAB } ColorSpace; static char const *colorspace_name[] = { "RGB", "Linear RGB", "HSV", "Oklab", "CIE Lab" }; struct Example { ALLEGRO_FONT *font; bool resized; int ox, oy; float scale; int count; char const *colors[1 + 8]; } example; static void print(int x, int y, char const *format, ...) { va_list args; va_start(args, format); char s[1000]; vsnprintf(s, 1000, format, args); va_end(args); float tw = al_get_text_width(example.font, s) / example.scale; float ox = 0; if (x - tw / 2 < 0) ox = tw / 2 - x; if (x + tw / 2 > SCREEN_W) ox = SCREEN_W - x - tw / 2; ALLEGRO_TRANSFORM backup = *al_get_current_transform(); ALLEGRO_TRANSFORM t; // Since we re-load the font when the window is resized we need to // un-scale it for drawing (but keep the scaled position). al_identity_transform(&t); al_scale_transform(&t, 1 / example.scale, 1 / example.scale); al_translate_transform(&t, x, y); al_compose_transform(&t, &backup); al_use_transform(&t); // black "outline" (not really, just offset by 1 pixel but good enough) al_draw_text(example.font, al_map_rgba_f(0, 0, 0, .5), (ox - tw / 2) * example.scale + 1, 1, 0, s); al_draw_text(example.font, al_map_rgb_f(1, 1, 1), (ox - tw / 2) * example.scale, 0, 0, s); al_use_transform(&backup); } static ALLEGRO_COLOR get_colorspace_rgb(ColorSpace cs, float *v) { if (cs == RGB) { return al_map_rgb_f(v[0], v[1], v[2]); } if (cs == OKLAB) { return al_color_oklab(v[0], v[1], v[2]); } if (cs == CIELAB) { return al_color_lab(v[0], v[1], v[2]); } if (cs == LINEAR) { return al_color_linear(v[0], v[1], v[2]); } if (cs == HSV) { return al_color_hsv(v[0], v[1], v[2]); } return al_map_rgb(0, 0, 0); } static void draw_gradient(int x, int y, ColorSpace cs, int color1, int color2) { ALLEGRO_COLOR rgb1 = al_color_name(example.colors[color1]); ALLEGRO_COLOR rgb2 = al_color_name(example.colors[color2]); float v1[3], v2[3]; if (cs == RGB) { al_unmap_rgb_f(rgb1, v1 + 0, v1 + 1, v1 + 2); al_unmap_rgb_f(rgb2, v2 + 0, v2 + 1, v2 + 2); } if (cs == OKLAB) { al_color_rgb_to_oklab(rgb1.r, rgb1.g, rgb1.b, v1 + 0, v1 + 1, v1 + 2); al_color_rgb_to_oklab(rgb2.r, rgb2.g, rgb2.b, v2 + 0, v2 + 1, v2 + 2); } if (cs == CIELAB) { al_color_rgb_to_lab(rgb1.r, rgb1.g, rgb1.b, v1 + 0, v1 + 1, v1 + 2); al_color_rgb_to_lab(rgb2.r, rgb2.g, rgb2.b, v2 + 0, v2 + 1, v2 + 2); } if (cs == LINEAR) { al_color_rgb_to_linear(rgb1.r, rgb1.g, rgb1.b, v1 + 0, v1 + 1, v1 + 2); al_color_rgb_to_linear(rgb2.r, rgb2.g, rgb2.b, v2 + 0, v2 + 1, v2 + 2); } if (cs == HSV) { al_color_rgb_to_hsv(rgb1.r, rgb1.g, rgb1.b, v1 + 0, v1 + 1, v1 + 2); al_color_rgb_to_hsv(rgb2.r, rgb2.g, rgb2.b, v2 + 0, v2 + 1, v2 + 2); } int w = ceil(300 * example.scale); float ly; for (int i = 0; i < w; i++) { float p = 1.0 * i / (w - 1); float v[3]; v[0] = v1[0] + p * (v2[0] - v1[0]); v[1] = v1[1] + p * (v2[1] - v1[1]); v[2] = v1[2] + p * (v2[2] - v1[2]); ALLEGRO_COLOR rgb = get_colorspace_rgb(cs, v); float colx = x + 10 + i / example.scale; al_draw_filled_rectangle(colx, y + 10, colx + 1 / example.scale, y + 80, rgb); float l, a, b; al_color_rgb_to_oklab(rgb.r, rgb.g, rgb.b, &l, &a, &b); if (i > 0) { al_draw_line(colx, y + 6 - ly * 50, colx + 1, y + 6 - l * 50, al_map_rgb_f(1, 1, 1), 0); } ly = l; } al_draw_rectangle(x + 11, y + 11, x + 311, y + 81, al_map_rgb_f(0, 0, 0), 1); al_draw_rectangle(x + 10, y + 10, x + 310, y + 80, al_map_rgb_f(1, 1, 1), 1); } static void redraw(void) { if (example.resized) { // We maintain a transformation to scale and offset everything so // a logical resolution of SCREEN_W x SCREEN_H fits into the // actual window (centered if it doesn't completely fit). example.resized = false; float dw = al_get_display_width(al_get_current_display()); float dh = al_get_display_height(al_get_current_display()); if (SCREEN_W * dh / dw < SCREEN_H) { example.ox = (dw - SCREEN_W * dh / SCREEN_H) / 2; example.oy = 0; example.scale = dh / SCREEN_H; } else { example.ox = 0; example.oy = (dh - SCREEN_H * dw / SCREEN_W) / 2; example.scale = dw / SCREEN_W; } // For best text quality we reload the font for the specific pixel // size whenever the transformation changes. example.font = al_load_font("data/DejaVuSans.ttf", 20 * example.scale, 0); } ALLEGRO_TRANSFORM transform; al_build_transform(&transform, example.ox, example.oy, example.scale, example.scale, 0); al_use_transform(&transform); al_clear_to_color(al_map_rgb_f(0.5, 0.5, 0.5)); // Here is the actual example. Draw interpolated gradients for // various color spaces. ColorSpace cs[] = {RGB, OKLAB, CIELAB, LINEAR, HSV}; example.count = 0; print(640, 10, "color gradients interpolated in different color spaces, with luminance curves"); float y = 20; for (int i = 0; i < 5; i++) { for (int j = 0; j < 4; j++) { print(160 + j * 320, y + 30, colorspace_name[cs[i]]); } draw_gradient(0, y + 50, cs[i], 1, 2); draw_gradient(320, y + 50, cs[i], 3, 4); draw_gradient(640, y + 50, cs[i], 5, 6); draw_gradient(960, y + 50, cs[i], 7, 8); y += 140; } } static void init(void) { example.colors[1] = "blue"; example.colors[2] = "white"; example.colors[3] = "blue"; example.colors[4] = "gold"; example.colors[5] = "red"; example.colors[6] = "lime"; example.colors[7] = "black"; example.colors[8] = "pink"; } int main(int argc, char **argv) { ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_DISPLAY *display; bool done = false; bool need_redraw = true; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } al_init_font_addon(); al_init_ttf_addon(); init_platform_specific(); example.resized = true; al_set_new_display_flags(ALLEGRO_RESIZABLE); al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST); al_set_new_display_option(ALLEGRO_SAMPLES, 16, ALLEGRO_SUGGEST); display = al_create_display(SCREEN_W, SCREEN_H); if (!display) { abort_example("Error creating display.\n"); } al_install_keyboard(); al_install_mouse(); al_init_primitives_addon(); init(); timer = al_create_timer(1.0 / 5); queue = al_create_event_queue(); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(display)); al_start_timer(timer); while (!done) { ALLEGRO_EVENT event; if (need_redraw) { redraw(); al_flip_display(); need_redraw = false; } while (true) { al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_CHAR: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_DISPLAY_RESIZE: al_acknowledge_resize(display); example.resized = true; break; case ALLEGRO_EVENT_TIMER: need_redraw = true; break; } if (al_is_event_queue_empty(queue)) break; } } return 0; } allegro5-5.2.10.1/examples/ex_compressed.c000066400000000000000000000135421473414355200203070ustar00rootroot00000000000000#include #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_font.h" #include "common.c" typedef struct BITMAP_TYPE { ALLEGRO_BITMAP* bmp; ALLEGRO_BITMAP* clone; ALLEGRO_BITMAP* decomp; ALLEGRO_BITMAP* lock_clone; ALLEGRO_PIXEL_FORMAT format; const char* name; } BITMAP_TYPE; int main(int argc, char **argv) { const char *filename; ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_FONT *font; ALLEGRO_BITMAP *bkg; bool redraw = true; int ii; int cur_bitmap = 0; bool compare = false; #define NUM_BITMAPS 4 BITMAP_TYPE bitmaps[NUM_BITMAPS] = { {NULL, NULL, NULL, NULL, ALLEGRO_PIXEL_FORMAT_ANY, "Uncompressed"}, {NULL, NULL, NULL, NULL, ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1, "DXT1"}, {NULL, NULL, NULL, NULL, ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3, "DXT3"}, {NULL, NULL, NULL, NULL, ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5, "DXT5"}, }; if (argc > 1) { filename = argv[1]; } else { filename = "data/mysha.pcx"; } if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); if (argc > 2) { al_set_new_display_adapter(atoi(argv[2])); } al_init_image_addon(); al_init_font_addon(); al_install_keyboard(); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } for (ii = 0; ii < NUM_BITMAPS; ii++) { double t0, t1; al_set_new_bitmap_format(bitmaps[ii].format); /* Load */ t0 = al_get_time(); bitmaps[ii].bmp = al_load_bitmap(filename); t1 = al_get_time(); if (!bitmaps[ii].bmp) { abort_example("%s not found or failed to load\n", filename); } log_printf("%s load time: %f sec\n", bitmaps[ii].name, t1 - t0); /* Clone */ t0 = al_get_time(); bitmaps[ii].clone = al_clone_bitmap(bitmaps[ii].bmp); t1 = al_get_time(); if (!bitmaps[ii].clone) { abort_example("Couldn't clone %s\n", bitmaps[ii].name); } log_printf("%s clone time: %f sec\n", bitmaps[ii].name, t1 - t0); /* Decompress */ al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY); t0 = al_get_time(); bitmaps[ii].decomp = al_clone_bitmap(bitmaps[ii].bmp); t1 = al_get_time(); if (!bitmaps[ii].decomp) { abort_example("Couldn't decompress %s\n", bitmaps[ii].name); } log_printf("%s decompress time: %f sec\n", bitmaps[ii].name, t1 - t0); /* RW lock */ al_set_new_bitmap_format(bitmaps[ii].format); bitmaps[ii].lock_clone = al_clone_bitmap(bitmaps[ii].bmp); if (!bitmaps[ii].lock_clone) { abort_example("Couldn't clone %s\n", bitmaps[ii].name); } if (al_get_bitmap_width(bitmaps[ii].bmp) > 128 && al_get_bitmap_height(bitmaps[ii].bmp) > 128) { int bitmap_format = al_get_bitmap_format(bitmaps[ii].bmp); int block_width = al_get_pixel_block_width(bitmap_format); int block_height = al_get_pixel_block_height(bitmap_format); /* Lock and unlock it, hopefully causing a no-op operation */ al_lock_bitmap_region_blocked(bitmaps[ii].lock_clone, 16 / block_width, 16 / block_height, 64 / block_width, 64 / block_height, ALLEGRO_LOCK_READWRITE); al_unlock_bitmap(bitmaps[ii].lock_clone); } } bkg = al_load_bitmap("data/bkg.png"); if (!bkg) { abort_example("data/bkg.png not found or failed to load\n"); } al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY); font = al_create_builtin_font(); timer = al_create_timer(1.0 / 30); queue = al_create_event_queue(); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (1) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: goto EXIT; case ALLEGRO_EVENT_TIMER: redraw = true; break; case ALLEGRO_EVENT_KEY_DOWN: switch (event.keyboard.keycode) { case ALLEGRO_KEY_LEFT: cur_bitmap = (cur_bitmap - 1 + NUM_BITMAPS) % NUM_BITMAPS; break; case ALLEGRO_KEY_RIGHT: cur_bitmap = (cur_bitmap + 1) % NUM_BITMAPS; break; case ALLEGRO_KEY_SPACE: compare = true; break; case ALLEGRO_KEY_ESCAPE: goto EXIT; } break; case ALLEGRO_EVENT_KEY_UP: if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) { compare = false; } break; } if (redraw && al_is_event_queue_empty(queue)) { int w = al_get_bitmap_width(bitmaps[cur_bitmap].bmp); int h = al_get_bitmap_height(bitmaps[cur_bitmap].bmp); int idx = compare ? 0 : cur_bitmap; redraw = false; al_clear_to_color(al_map_rgb_f(0, 0, 0)); al_draw_bitmap(bkg, 0, 0, 0); al_draw_textf(font, al_map_rgb_f(1, 1, 1), 5, 5, ALLEGRO_ALIGN_LEFT, "SPACE to compare. Arrows to switch. Format: %s", bitmaps[idx].name); al_draw_bitmap(bitmaps[idx].bmp, 0, 20, 0); al_draw_bitmap(bitmaps[idx].clone, w, 20, 0); al_draw_bitmap(bitmaps[idx].decomp, 0, 20 + h, 0); al_draw_bitmap(bitmaps[idx].lock_clone, w, 20 + h, 0); al_flip_display(); } } EXIT: al_destroy_bitmap(bkg); for (ii = 0; ii < NUM_BITMAPS; ii++) { al_destroy_bitmap(bitmaps[ii].bmp); } close_log(false); return 0; } /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/examples/ex_config.c000066400000000000000000000064111473414355200174050ustar00rootroot00000000000000/* * Example program for the Allegro library. * * Test config file reading and writing. */ #include #include "allegro5/allegro.h" #include "common.c" static int passed = true; #define TEST(name, expr) \ do { \ if (expr) \ log_printf(" PASS - %s\n", name); \ else { \ log_printf("!FAIL - %s\n", name); \ passed = false; \ } \ } while (0) int main(int argc, char **argv) { ALLEGRO_CONFIG *cfg; const char *value; ALLEGRO_CONFIG_SECTION *iterator; ALLEGRO_CONFIG_ENTRY *iterator2; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); cfg = al_load_config_file("data/sample.cfg"); if (!cfg) { abort_example("Couldn't load data/sample.cfg\n"); } value = al_get_config_value(cfg, NULL, "old_var"); TEST("global var", value && !strcmp(value, "old global value")); value = al_get_config_value(cfg, "section", "old_var"); TEST("section var", value && !strcmp(value, "old section value")); value = al_get_config_value(cfg, "", "mysha.xpm"); TEST("long value", value && strlen(value) == 1394); /* Test removing. */ al_set_config_value(cfg, "empty", "key_remove", "to be removed"); al_remove_config_key(cfg, "empty", "key_remove"); al_set_config_value(cfg, "schrödinger", "box", "cat"); al_remove_config_section(cfg, "schrödinger"); /* Test whether iterating through our whole sample.cfg returns all * sections and entries, in order. */ value = al_get_first_config_section(cfg, &iterator); TEST("section1", value && !strcmp(value, "")); value = al_get_first_config_entry(cfg, value, &iterator2); TEST("entry1", value && !strcmp(value, "old_var")); value = al_get_next_config_entry(&iterator2); TEST("entry2", value && !strcmp(value, "mysha.xpm")); value = al_get_next_config_entry(&iterator2); TEST("entry3", value == NULL); value = al_get_next_config_section(&iterator); TEST("section2", value && !strcmp(value, "section")); value = al_get_first_config_entry(cfg, value, &iterator2); TEST("entry4", value && !strcmp(value, "old_var")); value = al_get_next_config_entry(&iterator2); TEST("entry5", value == NULL); value = al_get_next_config_section(&iterator); TEST("section3", value); value = al_get_first_config_entry(cfg, value, &iterator2); TEST("entry6", value); value = al_get_next_config_entry(&iterator2); TEST("entry7", value == NULL); value = al_get_next_config_section(&iterator); TEST("empty", value && !strcmp(value, "empty")); value = al_get_first_config_entry(cfg, value, &iterator2); TEST("empty entry", value == NULL); value = al_get_next_config_section(&iterator); TEST("section4", value == NULL); al_set_config_value(cfg, "", "new_var", "new value"); al_set_config_value(cfg, "section", "old_var", "new value"); TEST("save_config", al_save_config_file("test.cfg", cfg)); log_printf("Done\n"); al_destroy_config(cfg); close_log(true); return passed ? 0 : 1; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_convert.c000066400000000000000000000021761473414355200176240ustar00rootroot00000000000000/* Image conversion example */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "common.c" int main(int argc, char **argv) { ALLEGRO_BITMAP *bitmap; double t0; double t1; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); if (argc < 3) { log_printf("This example needs to be run from the command line.\n"); log_printf("Usage: %s \n", argv[0]); log_printf("\tPossible file types: BMP PCX PNG TGA\n"); goto done; } al_init_image_addon(); al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ARGB_8888); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); bitmap = al_load_bitmap_flags(argv[1], ALLEGRO_NO_PREMULTIPLIED_ALPHA); if (!bitmap) { log_printf("Error loading input file\n"); goto done; } t0 = al_get_time(); if (!al_save_bitmap(argv[2], bitmap)) { log_printf("Error saving bitmap\n"); goto done; } t1 = al_get_time(); log_printf("Saving took %.4f seconds\n", t1 - t0); al_destroy_bitmap(bitmap); done: close_log(true); return 0; } allegro5-5.2.10.1/examples/ex_cpu.c000066400000000000000000000042601473414355200167270ustar00rootroot00000000000000/* An example showing the use of al_get_cpu_count() and al_get_ram_size(). */ #include #include #include #include "common.c" #define INTERVAL 0.1 int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_FONT *font; bool done = false; bool redraw = true; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } al_init_font_addon(); init_platform_specific(); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display.\n"); } if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } font = al_create_builtin_font(); timer = al_create_timer(INTERVAL); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(display)); al_start_timer(timer); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); while (!done) { ALLEGRO_EVENT event; if (redraw && al_is_event_queue_empty(queue)) { al_clear_to_color(al_map_rgba_f(0, 0, 0, 1.0)); al_draw_textf(font, al_map_rgba_f(1, 1, 0, 1.0), 16, 16, 0, "Amount of CPU cores detected: %d.", al_get_cpu_count()); al_draw_textf(font, al_map_rgba_f(0, 1, 1, 1.0), 16, 32, 0, "Size of random access memory: %d MiB.", al_get_ram_size()); al_flip_display(); redraw = false; } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { done = true; } break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_TIMER: redraw = true; break; } } al_destroy_font(font); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_curl.c000066400000000000000000000231041473414355200171030ustar00rootroot00000000000000/* * Example program for Allegro library. * * Custom file stream using cURL library. */ /* * Adapted from libcurl example fopen.c; licensed as follows: *--- * Coyright (c)2003 Simtec Electronics * * Re-implemented by Vincent Sanders with extensive * reference to original curl example code * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 #ifndef WIN32 # include #endif #include #include #include #include #include #include "common.c" typedef struct CURL_FILE CURL_FILE; struct CURL_FILE { CURL *curl; char *buffer; /* buffer to store cached data */ size_t buffer_len; /* currently allocated buffers length */ size_t buffer_pos; /* end of data in buffer*/ int still_running; /* Is background url fetch still in progress */ }; /* forward declaration */ static ALLEGRO_FILE_INTERFACE curl_file_vtable; /* we use a global one for convenience */ static CURLM *multi_handle; /* curl calls this routine to get more data. */ static size_t write_callback(char *buffer, size_t size, size_t nitems, void *userp) { CURL_FILE *cf = userp; char *newbuff; size_t rembuff; size *= nitems; rembuff = cf->buffer_len - cf->buffer_pos; if (size > rembuff) { /* Not enough space in buffer. */ newbuff = realloc(cf->buffer, cf->buffer_len + size - rembuff); if (!newbuff) { log_printf("callback buffer grow failed\n"); size = rembuff; } else { /* realloc increase buffer size. */ cf->buffer_len += size - rembuff; cf->buffer = newbuff; } } memcpy(cf->buffer + cf->buffer_pos, buffer, size); cf->buffer_pos += size; return size; } static void *curl_file_fopen(const char *path, const char *mode) { CURL_FILE *cf; /* Only support reading. */ if (strcmp(mode, "r") != 0 && strcmp(mode, "rb") != 0) return NULL; cf = calloc(1, sizeof(*cf)); if (!cf) return NULL; cf->curl = curl_easy_init(); curl_easy_setopt(cf->curl, CURLOPT_URL, path); curl_easy_setopt(cf->curl, CURLOPT_WRITEDATA, cf); curl_easy_setopt(cf->curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(cf->curl, CURLOPT_WRITEFUNCTION, write_callback); if (!multi_handle) multi_handle = curl_multi_init(); curl_multi_add_handle(multi_handle, cf->curl); /* Let's start the fetch. */ while (curl_multi_perform(multi_handle, &cf->still_running) == CURLM_CALL_MULTI_PERFORM); if ((cf->buffer_pos == 0) && (!cf->still_running)) { /* If still_running is 0 now, we should return NULL. */ curl_multi_remove_handle(multi_handle, cf->curl); curl_easy_cleanup(cf->curl); free(cf); cf = NULL; } return cf; } static bool curl_file_fclose(ALLEGRO_FILE *f) { CURL_FILE *cf = al_get_file_userdata(f); curl_multi_remove_handle(multi_handle, cf->curl); curl_easy_cleanup(cf->curl); if (cf->buffer) free(cf->buffer); free(cf); return true; } static bool fill_buffer(CURL_FILE *cf, size_t size) { fd_set fdread; fd_set fdwrite; fd_set fdexcep; struct timeval timeout; int rc; /* Only attempt to fill buffer if transactions still running and buffer * doesn't exceed required size already. */ if (!cf->still_running || cf->buffer_pos > size) return false; /* Attempt to fill buffer. */ do { int maxfd = -1; CURLMcode mc; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* Set a suitable timeout to fail on. */ timeout.tv_sec = 10; timeout.tv_usec = 0; /* Get file descriptors from the transfers. */ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); if(mc != CURLM_OK) { abort_example("curl_multi_fdset() failed, code %d.\n", mc); } if (maxfd > -1) { rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); } else { al_rest(0.1); rc = 0; } switch (rc) { case -1: /* select error */ break; case 0: default: /* Timeout or readable/writable sockets. */ curl_multi_perform(multi_handle, &cf->still_running); break; } } while (cf->still_running && cf->buffer_pos < size); return true; } static void use_buffer(CURL_FILE *cf, size_t size) { if (cf->buffer_pos - size <= 0) { cf->buffer_pos = 0; } else { /* Move rest down make it available for later. */ memmove(cf->buffer, cf->buffer + size, cf->buffer_pos - size); cf->buffer_pos -= size; } } static size_t curl_file_fread(ALLEGRO_FILE *f, void *ptr, size_t size) { CURL_FILE *cf = al_get_file_userdata(f); fill_buffer(cf, size); if (!cf->buffer_pos) return 0; if (cf->buffer_pos < size) size = cf->buffer_pos; memcpy(ptr, cf->buffer, size); use_buffer(cf, size); return size; } static size_t curl_file_fwrite(ALLEGRO_FILE *f, const void *ptr, size_t size) { (void)f; (void)ptr; (void)size; al_set_errno(EBADF); return 0; } static bool curl_file_fflush(ALLEGRO_FILE *f) { (void)f; return true; } static int64_t curl_file_ftell(ALLEGRO_FILE *f) { /* Not implemented. */ (void)f; al_set_errno(ENOSYS); return -1; } static bool curl_file_fseek(ALLEGRO_FILE *f, int64_t offset, int whence) { if (whence != ALLEGRO_SEEK_CUR || offset < 0) { /* Not implemented. */ al_set_errno(ENOSYS); return false; } while (offset > 0) { if (al_fgetc(f) == EOF) break; offset--; } return offset == 0; } static bool curl_file_feof(ALLEGRO_FILE *f) { CURL_FILE *cf = al_get_file_userdata(f); return (cf->buffer_pos == 0 && !cf->still_running); } static int curl_file_ferror(ALLEGRO_FILE *f) { /* Not implemented. */ (void)f; return false; } static const char *curl_file_ferrmsg(ALLEGRO_FILE *f) { /* Not implemented. */ (void)f; return ""; } static void curl_file_fclearerr(ALLEGRO_FILE *f) { /* Not implemented. */ (void)f; } static int curl_file_fungetc(ALLEGRO_FILE *f, int c) { /* Not implemented. */ (void)f; (void)c; al_set_errno(ENOSYS); return -1; } static off_t curl_file_fsize(ALLEGRO_FILE *f) { /* Not implemented. */ (void)f; al_set_errno(ENOSYS); return -1; } static ALLEGRO_FILE_INTERFACE curl_file_vtable = { curl_file_fopen, curl_file_fclose, curl_file_fread, curl_file_fwrite, curl_file_fflush, curl_file_ftell, curl_file_fseek, curl_file_feof, curl_file_ferror, curl_file_ferrmsg, curl_file_fclearerr, curl_file_fungetc, curl_file_fsize }; static void show_image(ALLEGRO_BITMAP *bmp, ALLEGRO_DISPLAY *disp) { ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(disp)); while (true) { al_draw_bitmap(bmp, 0, 0, 0); al_flip_display(); al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } } al_destroy_event_queue(queue); } int main(int argc, const char *argv[]) { const char *url; ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *bmp; bool wait_for_log = true; if (argc > 1) url = argv[1]; else url = "http://liballeg.org/images/logo.png"; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); al_init_image_addon(); al_install_keyboard(); display = al_create_display(640, 480); if (!display) { abort_example("Unable to create display.\n"); } curl_global_init(CURL_GLOBAL_ALL); al_set_new_file_interface(&curl_file_vtable); bmp = al_load_bitmap(url); if (bmp) { show_image(bmp, display); al_destroy_bitmap(bmp); wait_for_log = false; } curl_global_cleanup(); al_destroy_display(display); close_log(wait_for_log); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_d3d.cpp000066400000000000000000000062331473414355200171540ustar00rootroot00000000000000/* * Example of using D3D calls * by Jacob Dawid & Trent Gamblin */ #include #include #include #include #include #include "common.c" #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE) struct D3DVERTEX { float fX, fY, fZ; DWORD dwColor; }; int main(int argc, char *argv[]) { ALLEGRO_DISPLAY *display; (void)argc; (void)argv; if (!al_init()) { abort_example("Error initialising Allegro.\n"); } open_log(); al_install_keyboard(); al_set_new_display_flags(ALLEGRO_DIRECT3D); al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 16, ALLEGRO_SUGGEST); display = al_create_display(640, 480); if (!display) { abort_example("Unable to create display.\n"); } ALLEGRO_KEYBOARD_STATE state; IDirect3DDevice9 *d3dd = al_get_d3d_device(display); d3dd->SetRenderState(D3DRS_AMBIENT, 0x11111111); d3dd->SetRenderState(D3DRS_LIGHTING,false); d3dd->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE); d3dd->SetRenderState(D3DRS_ZENABLE,D3DZB_TRUE); d3dd->SetFVF(D3DFVF_CUSTOMVERTEX); D3DXMATRIX m_matProjection; float m_fAspectRatio = 1.0f; float m_fFieldOfView = D3DX_PI / 4.0f; float m_fNearPlane = 1.0f; float m_fFarPlane = 1000.0f; D3DXMatrixPerspectiveFovLH( &m_matProjection, m_fFieldOfView, m_fAspectRatio, m_fNearPlane, m_fFarPlane); d3dd->SetTransform(D3DTS_PROJECTION, &m_matProjection); LPDIRECT3DVERTEXBUFFER9 pTriangleVB = NULL; VOID *pData; D3DVERTEX aTriangle[] = { { -0.5, -0.5f, 0.0f, 0xffff0000 }, { 0.5f, -0.5f, 0.0f, 0xff00ff00 }, { 0.0f, 0.5f, 0.0f, 0xff0000ff } }; d3dd->CreateVertexBuffer(sizeof(aTriangle), D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &pTriangleVB, NULL); pTriangleVB->Lock(0, sizeof(pData), (void **)&pData, 0); memcpy(pData, aTriangle, sizeof(aTriangle)); pTriangleVB->Unlock(); float angle = 0.0f; D3DXMATRIX mat; double start = al_get_time(); double start_secs = al_get_time(); long frames = 0; do { d3dd->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); /* * The X and Y translation here is to offset * a translation Allegro does internally so * that its coordinate space matches OpenGL's. * Normally you don't have to worry about this * but if you're using D3D directly you do. */ D3DXMatrixTranslation(&mat, 0.5, 0.5, 2.0f); d3dd->SetTransform(D3DTS_WORLDMATRIX(0), &mat); angle += 50 * (al_get_time() - start); D3DXMatrixRotationY(&mat, angle); d3dd->MultiplyTransform(D3DTS_WORLDMATRIX(0), &mat); d3dd->SetFVF(D3DFVF_CUSTOMVERTEX); d3dd->SetStreamSource(0, pTriangleVB, 0, sizeof(D3DVERTEX)); d3dd->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1); al_flip_display(); al_get_keyboard_state(&state); start = al_get_time(); frames++; } while (!al_key_down(&state, ALLEGRO_KEY_ESCAPE)); double elapsed = al_get_time() - start_secs; log_printf("%g fps\n", frames/elapsed); al_destroy_display(display); close_log(true); return 0; } allegro5-5.2.10.1/examples/ex_depth_mask.c000066400000000000000000000146051473414355200202630ustar00rootroot00000000000000#include #include #include #include #include #include "common.c" #define FPS 60 #define COUNT 80 struct Example { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *mysha, *obp; ALLEGRO_FONT *font, *font2; double direct_speed_measure; struct Sprite { double x, y, angle; } sprites[COUNT]; } example; static void redraw(void) { ALLEGRO_TRANSFORM t; int i; /* We first draw the Obp background and clear the depth buffer to 1. */ al_set_render_state(ALLEGRO_ALPHA_TEST, true); al_set_render_state(ALLEGRO_ALPHA_FUNCTION, ALLEGRO_RENDER_GREATER); al_set_render_state(ALLEGRO_ALPHA_TEST_VALUE, 0); al_set_render_state(ALLEGRO_DEPTH_TEST, false); al_set_render_state(ALLEGRO_WRITE_MASK, ALLEGRO_MASK_DEPTH | ALLEGRO_MASK_RGBA); al_clear_depth_buffer(1); al_clear_to_color(al_map_rgb_f(0, 0, 0)); al_draw_scaled_bitmap(example.obp, 0, 0, 532, 416, 0, 0, 640, 416 * 640 / 532, 0); /* Next we draw all sprites but only to the depth buffer (with a depth value * of 0). */ al_set_render_state(ALLEGRO_DEPTH_TEST, true); al_set_render_state(ALLEGRO_DEPTH_FUNCTION, ALLEGRO_RENDER_ALWAYS); al_set_render_state(ALLEGRO_WRITE_MASK, ALLEGRO_MASK_DEPTH); for (i = 0; i < COUNT; i++) { struct Sprite *s = example.sprites + i; int x, y; al_hold_bitmap_drawing(true); for (y = -480; y <= 0; y += 480) { for (x = -640; x <= 0; x += 640) { al_identity_transform(&t); al_rotate_transform(&t, s->angle); al_translate_transform(&t, s->x + x, s->y + y); al_use_transform(&t); al_draw_text(example.font, al_map_rgb(0, 0, 0), 0, 0, ALLEGRO_ALIGN_CENTER, "Allegro 5"); } } al_hold_bitmap_drawing(false); } al_identity_transform(&t); al_use_transform(&t); /* Finally we draw Mysha, with depth testing so she only appears where * sprites have been drawn before. */ al_set_render_state(ALLEGRO_DEPTH_FUNCTION, ALLEGRO_RENDER_EQUAL); al_set_render_state(ALLEGRO_WRITE_MASK, ALLEGRO_MASK_RGBA); al_draw_scaled_bitmap(example.mysha, 0, 0, 320, 200, 0, 0, 320 * 480 / 200, 480, 0); /* Finally we draw an FPS counter. */ al_set_render_state(ALLEGRO_DEPTH_TEST, false); al_draw_textf(example.font2, al_map_rgb_f(1, 1, 1), 640, 0, ALLEGRO_ALIGN_RIGHT, "%.1f FPS", 1.0 / example.direct_speed_measure); } static void update(void) { int i; for (i = 0; i < COUNT; i++) { struct Sprite *s = example.sprites + i; s->x -= 4; if (s->x < 80) s->x += 640; s->angle += i * ALLEGRO_PI / 180 / COUNT; } } static void init(void) { int i; for (i = 0; i < COUNT; i++) { struct Sprite *s = example.sprites + i; s->x = (i % 4) * 160; s->y = (i / 4) * 24; } } int main(int argc, char **argv) { ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_MONITOR_INFO info; int w = 640, h = 480; bool done = false; bool need_redraw = true; bool background = false; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } if (!al_init_image_addon()) { abort_example("Failed to init IIO addon.\n"); } al_init_font_addon(); if (!al_init_ttf_addon()) { abort_example("Failed to init TTF addon.\n"); } init_platform_specific(); al_get_num_video_adapters(); al_get_monitor_info(0, &info); int flags = 0; #ifdef ALLEGRO_IPHONE flags |= ALLEGRO_FULLSCREEN_WINDOW; #endif if (argc > 1 && strcmp(argv[1], "shader") == 0) { flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; } al_set_new_display_flags(flags); al_set_new_display_option(ALLEGRO_SUPPORTED_ORIENTATIONS, ALLEGRO_DISPLAY_ORIENTATION_ALL, ALLEGRO_SUGGEST); al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 8, ALLEGRO_SUGGEST); al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); example.display = al_create_display(w, h); if (!example.display) { abort_example("Error creating display.\n"); } if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } example.font = al_load_font("data/DejaVuSans.ttf", 40, 0); if (!example.font) { abort_example("Error loading data/DejaVuSans.ttf\n"); } example.font2 = al_load_font("data/DejaVuSans.ttf", 12, 0); if (!example.font2) { abort_example("Error loading data/DejaVuSans.ttf\n"); } example.mysha = al_load_bitmap("data/mysha.pcx"); if (!example.mysha) { abort_example("Error loading data/mysha.pcx\n"); } example.obp = al_load_bitmap("data/obp.jpg"); if (!example.obp) { abort_example("Error loading data/obp.jpg\n"); } init(); timer = al_create_timer(1.0 / FPS); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(example.display)); al_start_timer(timer); while (!done) { ALLEGRO_EVENT event; w = al_get_display_width(example.display); h = al_get_display_height(example.display); if (!background && need_redraw && al_is_event_queue_empty(queue)) { double t = -al_get_time(); redraw(); t += al_get_time(); example.direct_speed_measure = t; al_flip_display(); need_redraw = false; } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_CHAR: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING: background = true; al_acknowledge_drawing_halt(event.display.source); break; case ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING: background = false; break; case ALLEGRO_EVENT_DISPLAY_RESIZE: al_acknowledge_resize(event.display.source); break; case ALLEGRO_EVENT_TIMER: update(); need_redraw = true; break; } } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_depth_target.c000066400000000000000000000152651473414355200206210ustar00rootroot00000000000000#define ALLEGRO_UNSTABLE #include #include #include #include #include #include #include #include "common.c" #define FPS 60 struct Example { ALLEGRO_BITMAP *target_depth; ALLEGRO_BITMAP *target_no_depth; ALLEGRO_BITMAP *target_no_multisample; ALLEGRO_FONT *font; double t; double direct_speed_measure; } example; static void draw_on_target(ALLEGRO_BITMAP *target) { ALLEGRO_STATE state; ALLEGRO_TRANSFORM transform; al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP | ALLEGRO_STATE_TRANSFORM | ALLEGRO_STATE_PROJECTION_TRANSFORM); al_set_target_bitmap(target); al_clear_to_color(al_map_rgba_f(0, 0, 0, 0)); al_clear_depth_buffer(1); al_identity_transform(&transform); al_translate_transform_3d(&transform, 0, 0, 0); al_orthographic_transform(&transform, -1, 1, -1, 1, -1, 1); al_use_projection_transform(&transform); al_draw_filled_rectangle(-0.75, -0.5, 0.75, 0.5, al_color_name("blue")); al_set_render_state(ALLEGRO_DEPTH_TEST, true); int i, j; for (i = 0; i < 24; i++) { for (j = 0; j < 2; j++) { al_identity_transform(&transform); al_translate_transform_3d(&transform, 0, 0, j * 0.01); al_rotate_transform_3d(&transform, 0, 1, 0, ALLEGRO_PI * (i / 12.0 + example.t / 2)); al_rotate_transform_3d(&transform, 1, 0, 0, ALLEGRO_PI * 0.25); al_use_transform(&transform); if (j == 0) al_draw_filled_rectangle(0, -.5, .5, .5, i % 2 == 0 ? al_color_name("yellow") : al_color_name("red")); else al_draw_filled_rectangle(0, -.5, .5, .5, i % 2 == 0 ? al_color_name("goldenrod") : al_color_name("maroon")); } } al_set_render_state(ALLEGRO_DEPTH_TEST, false); al_identity_transform(&transform); al_use_transform(&transform); al_draw_line(0.9, 0, 1, 0, al_color_name("black"), 0.05); al_draw_line(-0.9, 0, -1, 0, al_color_name("black"), 0.05); al_draw_line(0, 0.9, 0, 1, al_color_name("black"), 0.05); al_draw_line(0, -0.9, 0, -1, al_color_name("black"), 0.05); al_restore_state(&state); } static void redraw(void) { double w = 512, h = 512; ALLEGRO_COLOR black = al_color_name("black"); draw_on_target(example.target_depth); draw_on_target(example.target_no_depth); draw_on_target(example.target_no_multisample); al_clear_to_color(al_color_name("green")); ALLEGRO_TRANSFORM transform; al_identity_transform(&transform); al_use_transform(&transform); al_translate_transform(&transform, -128, -128); al_rotate_transform(&transform, example.t * ALLEGRO_PI / 3); al_translate_transform(&transform, 512 + 128, 128); al_use_transform(&transform); al_draw_bitmap(example.target_no_depth, 0, 0, 0); al_draw_text(example.font, black, 0, 0, 0, "no depth"); al_identity_transform(&transform); al_use_transform(&transform); al_translate_transform(&transform, -128, -128); al_rotate_transform(&transform, example.t * ALLEGRO_PI / 3); al_translate_transform(&transform, 512 + 128, 256 + 128); al_use_transform(&transform); al_draw_bitmap(example.target_no_multisample, 0, 0, 0); al_draw_textf(example.font, black, 0, 0, 0, "no multisample"); al_identity_transform(&transform); al_use_transform(&transform); al_translate_transform(&transform, -256, -256); al_rotate_transform(&transform, example.t * ALLEGRO_PI / 3); al_translate_transform(&transform, 256, 256); al_use_transform(&transform); al_draw_bitmap(example.target_depth, 0, 0, 0); al_draw_line(30, h / 2, 60, h / 2, black, 12); al_draw_line(w - 30, h / 2, w - 60, h / 2, black, 12); al_draw_line(w / 2, 30, w / 2, 60, black, 12); al_draw_line(w / 2, h - 30, w / 2, h - 60, black, 12); al_draw_text(example.font, black, 30, h / 2 - 16, 0, "back buffer"); al_draw_text(example.font, black, 0, h / 2 + 10, 0, "bitmap"); al_identity_transform(&transform); al_use_transform(&transform); al_draw_textf(example.font, black, w, 0, ALLEGRO_ALIGN_RIGHT, "%.1f FPS", 1.0 / example.direct_speed_measure); } static void update(void) { example.t += 1.0 / FPS; } static void init(void) { al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); al_set_new_bitmap_depth(16); al_set_new_bitmap_samples(4); example.target_depth = al_create_bitmap(512, 512); al_set_new_bitmap_depth(0); example.target_no_depth = al_create_bitmap(256, 256); al_set_new_bitmap_samples(0); example.target_no_multisample = al_create_bitmap(256, 256); } int main(int argc, char **argv) { ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_DISPLAY *display; int w = 512 + 256, h = 512; bool done = false; bool need_redraw = true; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } if (!al_init_image_addon()) { abort_example("Failed to init IIO addon.\n"); } al_init_font_addon(); example.font = al_create_builtin_font(); al_init_primitives_addon(); init_platform_specific(); al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 16, ALLEGRO_SUGGEST); al_set_new_display_flags(ALLEGRO_PROGRAMMABLE_PIPELINE); display = al_create_display(w, h); if (!display) { abort_example("Error creating display.\n"); } if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } init(); timer = al_create_timer(1.0 / FPS); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(display)); al_start_timer(timer); double t = -al_get_time(); while (!done) { ALLEGRO_EVENT event; if (need_redraw) { t += al_get_time(); example.direct_speed_measure = t; t = -al_get_time(); redraw(); al_flip_display(); need_redraw = false; } while (true) { al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_CHAR: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_TIMER: update(); need_redraw = true; break; } if (al_is_event_queue_empty(queue)) break; } } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_dir.c000066400000000000000000000063471473414355200167260ustar00rootroot00000000000000#include #include #include "common.c" static void print_file(ALLEGRO_FS_ENTRY *entry) { int mode = al_get_fs_entry_mode(entry); time_t now = time(NULL); time_t atime = al_get_fs_entry_atime(entry); time_t ctime = al_get_fs_entry_ctime(entry); time_t mtime = al_get_fs_entry_mtime(entry); off_t size = al_get_fs_entry_size(entry); const char *name = al_get_fs_entry_name(entry); log_printf("%-36s %s%s%s%s%s%s %8u %8u %8u %8u\n", name, mode & ALLEGRO_FILEMODE_READ ? "r" : ".", mode & ALLEGRO_FILEMODE_WRITE ? "w" : ".", mode & ALLEGRO_FILEMODE_EXECUTE ? "x" : ".", mode & ALLEGRO_FILEMODE_HIDDEN ? "h" : ".", mode & ALLEGRO_FILEMODE_ISFILE ? "f" : ".", mode & ALLEGRO_FILEMODE_ISDIR ? "d" : ".", (unsigned)(now - ctime), (unsigned)(now - mtime), (unsigned)(now - atime), (unsigned)size); } static void print_entry(ALLEGRO_FS_ENTRY *entry) { ALLEGRO_FS_ENTRY *next; print_file(entry); if (!(al_get_fs_entry_mode(entry) & ALLEGRO_FILEMODE_ISDIR)) return; if (!al_open_directory(entry)) { log_printf("Error opening directory: %s\n", al_get_fs_entry_name(entry)); return; } while (1) { next = al_read_directory(entry); if (!next) break; print_entry(next); al_destroy_fs_entry(next); } al_close_directory(entry); } static int print_fs_entry_cb(ALLEGRO_FS_ENTRY * entry, void * extra) { (void) extra; print_file(entry); return ALLEGRO_FOR_EACH_FS_ENTRY_OK; } static int print_fs_entry_cb_norecurse(ALLEGRO_FS_ENTRY * entry, void * extra) { (void) extra; print_file(entry); return ALLEGRO_FOR_EACH_FS_ENTRY_SKIP; } static void print_fs_entry(ALLEGRO_FS_ENTRY * dir) { log_printf("\n------------------------------------\nExample of al_for_each_fs_entry with recursion:\n\n"); al_for_each_fs_entry(dir, print_fs_entry_cb, (void*) al_get_fs_entry_name(dir)); } static void print_fs_entry_norecurse(ALLEGRO_FS_ENTRY * dir) { log_printf("\n------------------------------------\nExample of al_for_each_fs_entry without recursion:\n\n"); al_for_each_fs_entry(dir, print_fs_entry_cb_norecurse, (void*) al_get_fs_entry_name(dir)); } int main(int argc, char **argv) { int i; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log_monospace(); log_printf("Example of filesystem entry functions:\n\n%-36s %-6s %8s %8s %8s %8s\n", "name", "flags", "ctime", "mtime", "atime", "size"); log_printf( "------------------------------------ " "------ " "-------- " "-------- " "-------- " "--------\n"); #ifdef ALLEGRO_ANDROID al_android_set_apk_fs_interface(); #endif if (argc == 1) { ALLEGRO_FS_ENTRY *entry = al_create_fs_entry("data"); print_entry(entry); print_fs_entry(entry); print_fs_entry_norecurse(entry); al_destroy_fs_entry(entry); } for (i = 1; i < argc; i++) { ALLEGRO_FS_ENTRY *entry = al_create_fs_entry(argv[i]); print_entry(entry); print_fs_entry(entry); print_fs_entry_norecurse(entry); al_destroy_fs_entry(entry); } close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_disable_screensaver.c000066400000000000000000000034701473414355200221450ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "common.c" int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_FONT *font; ALLEGRO_EVENT_QUEUE *events; ALLEGRO_EVENT event; bool done = false; bool active = true; bool fullscreen = false; if (argc == 2) { if (!strcmp(argv[1], "-fullscreen")) { fullscreen = true; } } if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_init_font_addon(); al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS | (fullscreen ? ALLEGRO_FULLSCREEN : 0)); display = al_create_display(640, 480); if (!display) { abort_example("Could not create display.\n"); } font = al_create_builtin_font(); if (!font) { abort_example("Error creating builtin font\n"); } events = al_create_event_queue(); al_register_event_source(events, al_get_keyboard_event_source()); /* For expose events */ al_register_event_source(events, al_get_display_event_source(display)); do { al_clear_to_color(al_map_rgb(0, 0, 0)); al_draw_textf(font, al_map_rgb_f(1, 1, 1), 0, 0, 0, "Screen saver: %s", active ? "Normal" : "Inhibited"); al_flip_display(); al_wait_for_event(events, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; else if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) { if (al_inhibit_screensaver(active)) { active = !active; } } break; } } while (!done); al_destroy_font(font); al_destroy_event_queue(events); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_display_events.c000066400000000000000000000066621473414355200212010ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_primitives.h" #include "common.c" #define MAX_EVENTS 23 static char events[MAX_EVENTS][1024]; static void add_event(char const *f, ...) { va_list args; memmove(events[1], events[0], (MAX_EVENTS - 1) * 1024); va_start(args, f); vsnprintf(events[0], 1024, f, args); va_end(args); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; ALLEGRO_FONT *font; ALLEGRO_COLOR color, black, red, blue; int i; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_install_mouse(); al_install_keyboard(); al_init_font_addon(); al_set_new_display_flags(ALLEGRO_RESIZABLE); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } font = al_create_builtin_font(); if (!font) { abort_example("Error creating builtin font\n"); } black = al_map_rgb_f(0, 0, 0); red = al_map_rgb_f(1, 0, 0); blue = al_map_rgb_f(0, 0, 1); queue = al_create_event_queue(); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); while (1) { if (al_is_event_queue_empty(queue)) { float x = 8, y = 28; al_clear_to_color(al_map_rgb(0xff, 0xff, 0xc0)); al_draw_textf(font, blue, 8, 8, 0, "Display events (newest on top)"); color = red; for (i = 0; i < MAX_EVENTS; i++) { if (!events[i]) continue; al_draw_textf(font, color, x, y, 0, "%s", events[i]); color = black; y += 20; } al_flip_display(); } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY: add_event("ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY"); break; case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY: add_event("ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY"); break; case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { goto done; } break; case ALLEGRO_EVENT_DISPLAY_RESIZE: add_event("ALLEGRO_EVENT_DISPLAY_RESIZE x=%d, y=%d, " "width=%d, height=%d", event.display.x, event.display.y, event.display.width, event.display.height); al_acknowledge_resize(event.display.source); break; case ALLEGRO_EVENT_DISPLAY_CLOSE: add_event("ALLEGRO_EVENT_DISPLAY_CLOSE"); break; case ALLEGRO_EVENT_DISPLAY_LOST: add_event("ALLEGRO_EVENT_DISPLAY_LOST"); break; case ALLEGRO_EVENT_DISPLAY_FOUND: add_event("ALLEGRO_EVENT_DISPLAY_FOUND"); break; case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT: add_event("ALLEGRO_EVENT_DISPLAY_SWITCH_OUT"); break; case ALLEGRO_EVENT_DISPLAY_SWITCH_IN: add_event("ALLEGRO_EVENT_DISPLAY_SWITCH_IN"); break; } } done: al_destroy_event_queue(queue); return 0; } /* vim: set sw=3 sts=3 et: */ allegro5-5.2.10.1/examples/ex_display_options.c000066400000000000000000000274561473414355200213740ustar00rootroot00000000000000/* Test retrieving and settings possible modes. */ #include #include #include #include #include "common.c" ALLEGRO_FONT *font; ALLEGRO_COLOR white; int font_h; int modes_count; int options_count; char status[256]; int flags, old_flags; int visible_rows; int first_visible_row; int selected_column; int selected_mode; int selected_option; #define X(x, m) {#x, ALLEGRO_##x, 0, m, 0} struct { char const *name; int option; int value, max_value; int required; } options[] = { X(COLOR_SIZE, 32), X(RED_SIZE, 8), X(GREEN_SIZE, 8), X(BLUE_SIZE, 8), X(ALPHA_SIZE, 8), X(RED_SHIFT, 32), X(GREEN_SHIFT, 32), X(BLUE_SHIFT, 32), X(ALPHA_SHIFT, 32), X(DEPTH_SIZE, 32), X(FLOAT_COLOR, 1), X(FLOAT_DEPTH, 1), X(STENCIL_SIZE, 32), X(SAMPLE_BUFFERS, 1), X(SAMPLES, 8), X(RENDER_METHOD, 2), X(SINGLE_BUFFER, 1), X(SWAP_METHOD, 1), X(VSYNC, 2), X(COMPATIBLE_DISPLAY, 1), X(MAX_BITMAP_SIZE, 65536), X(SUPPORT_NPOT_BITMAP, 1), X(CAN_DRAW_INTO_BITMAP, 1), X(SUPPORT_SEPARATE_ALPHA, 1), }; #undef X static char const *flag_names[32]; static void init_flags(void) { int i; #define X(f) if (1 << i == ALLEGRO_##f) flag_names[i] = #f; for (i = 0; i < 32; i++) { X(WINDOWED) X(FULLSCREEN) X(OPENGL) X(RESIZABLE) X(FRAMELESS) X(GENERATE_EXPOSE_EVENTS) X(FULLSCREEN_WINDOW) X(MINIMIZED) } #undef X } static void load_font(void) { font = al_create_builtin_font(); if (!font) { abort_example("Error creating builtin font\n"); } font_h = al_get_font_line_height(font); } static void display_options(ALLEGRO_DISPLAY *display) { int i, y = 10; int x = 10; int n = options_count; int dw = al_get_display_width(display); int dh = al_get_display_height(display); ALLEGRO_COLOR c; modes_count = al_get_num_display_modes(); c = al_map_rgb_f(0.8, 0.8, 1); al_draw_textf(font, c, x, y, 0, "Create new display"); y += font_h; for (i = first_visible_row; i < modes_count + 2 && i < first_visible_row + visible_rows; i++) { ALLEGRO_DISPLAY_MODE mode; if (i > 1) { al_get_display_mode(i - 2, &mode); } else if (i == 1) { mode.width = 800; mode.height = 600; mode.format = 0; mode.refresh_rate = 0; } else { mode.width = 800; mode.height = 600; mode.format = 0; mode.refresh_rate = 0; } if (selected_column == 0 && selected_mode == i) { c = al_map_rgb_f(1, 1, 0); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_draw_filled_rectangle(x, y, x + 300, y + font_h, c); } c = al_map_rgb_f(0, 0, 0); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); if ((i == first_visible_row && i > 0) || (i == first_visible_row + visible_rows - 1 && i < modes_count + 1)) { al_draw_textf(font, c, x, y, 0, "..."); } else { al_draw_textf(font, c, x, y, 0, "%s %d x %d (fmt: %x, %d Hz)", i > 1 ? "Fullscreen" : i == 0 ? "Windowed" : "FS Window", mode.width, mode.height, mode.format, mode.refresh_rate); } y += font_h; } x = dw / 2 + 10; y = 10; c = al_map_rgb_f(0.8, 0.8, 1); al_draw_textf(font, c, x, y, 0, "Options for new display"); al_draw_textf(font, c, dw - 10, y, ALLEGRO_ALIGN_RIGHT, "(current display)"); y += font_h; for (i = 0; i < n; i++) { if (selected_column == 1 && selected_option == i) { c = al_map_rgb_f(1, 1, 0); al_draw_filled_rectangle(x, y, x + 300, y + font_h, c); } switch (options[i].required) { case ALLEGRO_REQUIRE: c = al_map_rgb_f(0.5, 0, 0); break; case ALLEGRO_SUGGEST: c = al_map_rgb_f(0, 0, 0); break; case ALLEGRO_DONTCARE: c = al_map_rgb_f(0.5, 0.5, 0.5); break; } al_draw_textf(font, c, x, y, 0, "%s: %d (%s)", options[i].name, options[i].value, options[i].required == ALLEGRO_REQUIRE ? "required" : options[i].required == ALLEGRO_SUGGEST ? "suggested" : "ignored"); c = al_map_rgb_f(0.9, 0.5, 0.3); al_draw_textf(font, c, dw - 10, y, ALLEGRO_ALIGN_RIGHT, "%d", al_get_display_option(display, options[i].option)); y += font_h; } c = al_map_rgb_f(0, 0, 0.8); x = 10; y = dh - font_h - 10; y -= font_h; al_draw_textf(font, c, x, y, 0, "PageUp/Down: modify values"); y -= font_h; al_draw_textf(font, c, x, y, 0, "Return: set mode or require option"); y -= font_h; al_draw_textf(font, c, x, y, 0, "Cursor keys: change selection"); y -= font_h * 2; for (i = 0; i < 32; i++) { if (flag_names[i]) { if (flags & (1 << i)) c = al_map_rgb_f(0.5, 0, 0); else if (old_flags & (1 << i)) c = al_map_rgb_f(0.5, 0.4, 0.4); else continue; al_draw_text(font, c, x, y, 0, flag_names[i]); x += al_get_text_width(font, flag_names[i]) + 10; } } c = al_map_rgb_f(1, 0, 0); al_draw_text(font, c, dw / 2, dh - font_h, ALLEGRO_ALIGN_CENTRE, status); } static void update_ui(void) { int h = al_get_display_height(al_get_current_display()); visible_rows = h / font_h - 10; } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_TIMER *timer; bool redraw = false; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } init_flags(); al_init_primitives_addon(); white = al_map_rgba_f(1, 1, 1, 1); al_install_keyboard(); al_install_mouse(); al_init_font_addon(); display = al_create_display(800, 600); if (!display) { abort_example("Could not create display.\n"); } load_font(); timer = al_create_timer(1.0 / 60); modes_count = al_get_num_display_modes(); options_count = sizeof(options) / sizeof(options[0]); update_ui(); al_clear_to_color(al_map_rgb_f(1, 1, 1)); display_options(display); al_flip_display(); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (1) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { if (event.mouse.button == 1) { int dw = al_get_display_width(display); int y = 10; int row = (event.mouse.y - y) / font_h - 1; int column = event.mouse.x / (dw / 2); if (column == 0) { if (row >= 0 && row <= modes_count) { selected_column = column; selected_mode = row; redraw = true; } } if (column == 1) { if (row >= 0 && row < options_count) { selected_column = column; selected_option = row; redraw = true; } } } } if (event.type == ALLEGRO_EVENT_TIMER) { int f = al_get_display_flags(display); if (f != flags) { redraw = true; flags = f; old_flags |= f; } } if (event.type == ALLEGRO_EVENT_KEY_CHAR) { int change; if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; if (event.keyboard.keycode == ALLEGRO_KEY_LEFT) { selected_column = 0; redraw = true; } if (event.keyboard.keycode == ALLEGRO_KEY_RIGHT) { selected_column = 1; redraw = true; } if (event.keyboard.keycode == ALLEGRO_KEY_UP) { if (selected_column == 0) selected_mode -= 1; if (selected_column == 1) selected_option -= 1; redraw = true; } if (event.keyboard.keycode == ALLEGRO_KEY_DOWN) { if (selected_column == 0) selected_mode += 1; if (selected_column == 1) selected_option += 1; redraw = true; } if (event.keyboard.keycode == ALLEGRO_KEY_ENTER) { if (selected_column == 0) { ALLEGRO_DISPLAY_MODE mode; ALLEGRO_DISPLAY *new_display; if (selected_mode > 1) { al_get_display_mode(selected_mode - 2, &mode); al_set_new_display_flags(ALLEGRO_FULLSCREEN); } else if (selected_mode == 1) { mode.width = 800; mode.height = 600; al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW); } else { mode.width = 800; mode.height = 600; al_set_new_display_flags(ALLEGRO_WINDOWED); } al_destroy_font(font); font = NULL; new_display = al_create_display( mode.width, mode.height); if (new_display) { al_destroy_display(display); display = new_display; al_set_target_backbuffer(display); al_register_event_source(queue, al_get_display_event_source(display)); update_ui(); sprintf(status, "Display creation succeeded."); } else { sprintf(status, "Display creation failed."); } load_font(); } if (selected_column == 1) { options[selected_option].required += 1; options[selected_option].required %= 3; al_set_new_display_option( options[selected_option].option, options[selected_option].value, options[selected_option].required); } redraw = true; } change = 0; if (event.keyboard.keycode == ALLEGRO_KEY_PGUP) change = 1; if (event.keyboard.keycode == ALLEGRO_KEY_PGDN) change = -1; if (change && selected_column == 1) { options[selected_option].value += change; if (options[selected_option].value < 0) options[selected_option].value = 0; if (options[selected_option].value > options[selected_option].max_value) options[selected_option].value = options[selected_option].max_value; al_set_new_display_option(options[selected_option].option, options[selected_option].value, options[selected_option].required); redraw = true; } } if (selected_mode < 0) selected_mode = 0; if (selected_mode > modes_count + 1) selected_mode = modes_count + 1; if (selected_option < 0) selected_option = 0; if (selected_option >= options_count) selected_option = options_count - 1; if (selected_mode < first_visible_row) first_visible_row = selected_mode; if (selected_mode > first_visible_row + visible_rows - 1) first_visible_row = selected_mode - visible_rows + 1; if (redraw && al_is_event_queue_empty(queue)) { redraw = false; al_clear_to_color(al_map_rgb_f(1, 1, 1)); display_options(display); al_flip_display(); } } al_destroy_font(font); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_drag_and_drop.c000066400000000000000000000144571473414355200207340ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * System drag&drop example. * * This example shows how an Allegro window can receive pictures * (and text) from other applications. * * See readme.txt for copyright information. */ #define ALLEGRO_UNSTABLE #include #include #include #include #include #include #include "common.c" #define XDIV 3 #define YDIV 4 // We only accept up to 25 lines of text or files at a time. typedef struct Cell { char *rows[25]; ALLEGRO_BITMAP *bitmap; } Cell; int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_FONT *font; bool done = false; bool redraw = true; Cell grid[XDIV * YDIV]; int drop_x = -1; int drop_y = -1; (void)argc; (void)argv; // Initialize everything to NULL for (int i = 0; i < XDIV * YDIV; i++) { grid[i].rows[0] = strdup("drop file or text here"); for (int r = 1; r < 25; r++) grid[i].rows[r] = NULL; grid[i].bitmap = NULL; } if (!al_init()) { abort_example("Failed to init Allegro.\n"); } al_init_image_addon(); al_init_primitives_addon(); al_init_font_addon(); al_init_ttf_addon(); init_platform_specific(); ALLEGRO_MONITOR_INFO info; al_get_monitor_info(0, &info); // Make the window half as wide as the desktop and 4:3 aspect int w = (info.x2 - info.x1) / 2; int h = w * 3 / 4; // Turn on drag/drop support al_set_new_display_flags(ALLEGRO_DRAG_AND_DROP); display = al_create_display(w, h); if (!display) { abort_example("Error creating display.\n"); } if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } font = al_load_font("data/DejaVuSans.ttf", 20, 0); if (!font) { abort_example("Could not load font.\n"); } timer = al_create_timer(1 / 60.0); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); // drag&drop events will come from the display, if enabled al_register_event_source(queue, al_get_display_event_source(display)); al_start_timer(timer); while (!done) { ALLEGRO_EVENT event; int fh = al_get_font_line_height(font); if (redraw && al_is_event_queue_empty(queue)) { // draw a grid with the dropped text rows or files ALLEGRO_COLOR c1 = al_color_name("gainsboro"); ALLEGRO_COLOR c2 = al_color_name("orange"); al_clear_to_color(al_map_rgb_f(0, 0, 0)); for (int y = 0; y < YDIV; y++) { for (int x = 0; x < XDIV; x++) { int gx = x * w / XDIV; int gy = y * h / YDIV; if (grid[x + y * XDIV].bitmap) { ALLEGRO_BITMAP *bmp = grid[x + y * XDIV].bitmap; float bw = al_get_bitmap_width(bmp); float bh = al_get_bitmap_height(bmp); float s = w / XDIV / bw; if (s > (h / YDIV - fh) / bh) s = (h / YDIV - fh) / bh; al_draw_scaled_bitmap(bmp, 0, 0, bw, bh, gx, gy + fh, bw * s, bh * s, 0); } for (int r = 0; r < 25; r++) { if (!grid[x + y * XDIV].rows[r]) break; al_draw_textf(font, c1, gx, gy + r * fh, 0, "%s", grid[x + y * XDIV].rows[r]); } if (drop_x >= gx && drop_x < gx + w / XDIV && drop_y >= gy && drop_y < gy + h / YDIV) { al_draw_rectangle(gx, gy, gx + w / XDIV, gy + h / YDIV, c2, 2); } else { al_draw_rectangle(gx, gy, gx + w / XDIV, gy + h / YDIV, c1, 0); } } } al_flip_display(); redraw = false; } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { done = true; } break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_TIMER: redraw = true; break; case ALLEGRO_EVENT_DROP: drop_x = event.drop.x; drop_y = event.drop.y; int col = drop_x * XDIV / w; int row = drop_y * YDIV / h; int i = col + row * XDIV; if (event.drop.text) { if (event.drop.row == 0) { // clear the previous contents of the cell for (int r = 0; r < 25; r++) { if (grid[i].rows[r]) { al_free(grid[i].rows[r]); grid[i].rows[r] = NULL; } } // insert the first row/file grid[i].rows[0] = event.drop.text; if (event.drop.is_file) { // if a file, try and load it as a bitmap to display if (grid[i].bitmap) al_destroy_bitmap(grid[i].bitmap); grid[i].bitmap = al_load_bitmap(grid[i].rows[0]); } } else { if (event.drop.row < 25) { grid[i].rows[event.drop.row] = event.drop.text; } else { al_free(event.drop.text); } } } if (event.drop.is_complete) { // stop highlighting a cell when the drop is completed drop_x = -1; drop_y = -1; } break; } } al_destroy_font(font); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_draw.c000066400000000000000000000210271473414355200170750ustar00rootroot00000000000000/* Tests some drawing primitives. */ #include #include #include #include #include #include #include #include "common.c" struct Example { ALLEGRO_FONT *font; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_COLOR background, text, white, foreground; ALLEGRO_COLOR outline; ALLEGRO_BITMAP *pattern; ALLEGRO_BITMAP *zoom; double timer[4], counter[4]; int FPS; float text_x, text_y; bool software; int samples; int what; int thickness; } ex; char const *names[] = { "filled rectangles", "rectangles", "filled circles", "circles", "lines" }; static void draw_pattern(ALLEGRO_BITMAP *b) { int w = al_get_bitmap_width(b); int h = al_get_bitmap_height(b); int x, y; int format = ALLEGRO_PIXEL_FORMAT_BGR_888; ALLEGRO_COLOR light = al_map_rgb_f(1, 1, 1); ALLEGRO_COLOR dark = al_map_rgb_f(1, 0.9, 0.8); ALLEGRO_LOCKED_REGION *lock; lock = al_lock_bitmap(b, format, ALLEGRO_LOCK_WRITEONLY); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { ALLEGRO_COLOR c = (x + y) & 1 ? light : dark; unsigned char r, g, b; unsigned char *data = lock->data; al_unmap_rgb(c, &r, &g, &b); data += y * lock->pitch; data += x * 3; data[0] = r; data[1] = g; data[2] = b; } } al_unlock_bitmap(b); } static void set_xy(float x, float y) { ex.text_x = x; ex.text_y = y; } static void print(char const *format, ...) { va_list list; char message[1024]; ALLEGRO_STATE state; int th = al_get_font_line_height(ex.font); al_store_state(&state, ALLEGRO_STATE_BLENDER); va_start(list, format); vsnprintf(message, sizeof message, format, list); va_end(list); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(ex.font, ex.text, ex.text_x, ex.text_y, 0, "%s", message); al_restore_state(&state); ex.text_y += th; } static void primitive(float l, float t, float r, float b, ALLEGRO_COLOR color, bool never_fill) { float cx = (l + r) / 2; float cy = (t + b) / 2; float rx = (r - l) / 2; float ry = (b - t) / 2; int tk = never_fill ? 0 : ex.thickness; int w = ex.what; if (w == 0 && never_fill) w = 1; if (w == 2 && never_fill) w = 3; if (w == 0) al_draw_filled_rectangle(l, t, r, b, color); if (w == 1) al_draw_rectangle(l, t, r, b, color, tk); if (w == 2) al_draw_filled_ellipse(cx, cy, rx, ry, color); if (w == 3) al_draw_ellipse(cx, cy, rx, ry, color, tk); if (w == 4) al_draw_line(l, t, r, b, color, tk); } static void draw(void) { float x, y; int cx, cy, cw, ch; int w = al_get_bitmap_width(ex.zoom); int h = al_get_bitmap_height(ex.zoom); ALLEGRO_BITMAP *screen = al_get_target_bitmap(); ALLEGRO_BITMAP *mem; int rects_num = 16, i, j; float rects[16 * 4]; for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { rects[(j * 4 + i) * 4 + 0] = 2 + i * 0.25 + i * 7; rects[(j * 4 + i) * 4 + 1] = 2 + j * 0.25 + j * 7; rects[(j * 4 + i) * 4 + 2] = 2 + i * 0.25 + i * 7 + 5; rects[(j * 4 + i) * 4 + 3] = 2 + j * 0.25 + j * 7 + 5; } } al_get_clipping_rectangle(&cx, &cy, &cw, &ch); al_clear_to_color(ex.background); set_xy(8, 0); print("Drawing %s (press SPACE to change)", names[ex.what]); set_xy(8, 16); print("Original"); set_xy(80, 16); print("Enlarged x 16"); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); if (ex.software) { al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); al_set_new_bitmap_format(al_get_bitmap_format(al_get_target_bitmap())); mem = al_create_bitmap(w, h); al_set_target_bitmap(mem); x = 0; y = 0; } else { mem = NULL; x = 8; y = 40; } al_draw_bitmap(ex.pattern, x, y, 0); /* Draw the test scene. */ al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); for (i = 0; i < rects_num; i++) { ALLEGRO_COLOR rgba = ex.foreground; rgba.a *= 0.5; primitive( x + rects[i * 4 + 0], y + rects[i * 4 + 1], x + rects[i * 4 + 2], y + rects[i * 4 + 3], rgba, false); } al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); if (ex.software) { al_set_target_bitmap(screen); x = 8; y = 40; al_draw_bitmap(mem, x, y, 0); al_destroy_bitmap(mem); } /* Grab screen contents into our bitmap. */ al_set_target_bitmap(ex.zoom); al_draw_bitmap_region(screen, x, y, w, h, 0, 0, 0); al_set_target_bitmap(screen); /* Draw it enlarged. */ x = 80; y = 40; al_draw_scaled_bitmap(ex.zoom, 0, 0, w, h, x, y, w * 16, h * 16, 0); /* Draw outlines. */ for (i = 0; i < rects_num; i++) { primitive( x + rects[i * 4 + 0] * 16, y + rects[i * 4 + 1] * 16, x + rects[i * 4 + 2] * 16, y + rects[i * 4 + 3] * 16, ex.outline, true); } set_xy(8, 640 - 48); print("Thickness: %d (press T to change)", ex.thickness); print("Drawing with: %s (press S to change)", ex.software ? "software" : "hardware"); print("Supersampling: %dx (edit ex_draw.ini to change)", ex.samples); // FIXME: doesn't work // al_get_display_option(ALLEGRO_SAMPLE_BUFFERS)); } static void tick(void) { draw(); al_flip_display(); } static void run(void) { ALLEGRO_EVENT event; bool need_draw = true; while (1) { if (need_draw && al_is_event_queue_empty(ex.queue)) { tick(); need_draw = false; } al_wait_for_event(ex.queue, &event); switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: return; case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) return; if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) { ex.what++; if (ex.what == 5) ex.what = 0; } if (event.keyboard.keycode == ALLEGRO_KEY_S) { ex.software = !ex.software; } if (event.keyboard.keycode == ALLEGRO_KEY_T) { ex.thickness++; if (ex.thickness == 2) ex.thickness = 0; } break; case ALLEGRO_EVENT_TIMER: need_draw = true; break; } } } static void init(void) { ex.FPS = 60; ex.font = al_load_font("data/fixed_font.tga", 0, 0); if (!ex.font) { abort_example("data/fixed_font.tga not found.\n"); } ex.background = al_color_name("beige"); ex.foreground = al_color_name("black"); ex.outline = al_color_name("red"); ex.text = al_color_name("blue"); ex.white = al_color_name("white"); ex.pattern = al_create_bitmap(32, 32); ex.zoom = al_create_bitmap(32, 32); draw_pattern(ex.pattern); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_CONFIG *config; char const *value; char str[256]; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_install_keyboard(); al_install_mouse(); al_init_image_addon(); al_init_font_addon(); init_platform_specific(); /* Read supersampling info from ex_draw.ini. */ ex.samples = 0; config = al_load_config_file("ex_draw.ini"); if (!config) config = al_create_config(); value = al_get_config_value(config, "settings", "samples"); if (value) ex.samples = strtol(value, NULL, 0); sprintf(str, "%d", ex.samples); al_set_config_value(config, "settings", "samples", str); al_save_config_file("ex_draw.ini", config); al_destroy_config(config); if (ex.samples) { al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_REQUIRE); al_set_new_display_option(ALLEGRO_SAMPLES, ex.samples, ALLEGRO_SUGGEST); } display = al_create_display(640, 640); if (!display) { abort_example("Unable to create display.\n"); } init(); timer = al_create_timer(1.0 / ex.FPS); ex.queue = al_create_event_queue(); al_register_event_source(ex.queue, al_get_keyboard_event_source()); al_register_event_source(ex.queue, al_get_mouse_event_source()); al_register_event_source(ex.queue, al_get_display_event_source(display)); al_register_event_source(ex.queue, al_get_timer_event_source(timer)); al_start_timer(timer); run(); al_destroy_event_queue(ex.queue); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_draw_bitmap.c000066400000000000000000000312561473414355200204360ustar00rootroot00000000000000#include #include #include #include #include #include "common.c" ALLEGRO_DEBUG_CHANNEL("main") #define FPS 60 #define MAX_SPRITES 1024 typedef struct Sprite { float x, y, dx, dy; } Sprite; char const *text[] = { "H - toggle held drawing", "Space - toggle use of textures", "B - toggle alpha blending", "Left/Right - change bitmap size", "Up/Down - change bitmap count", "F1 - toggle help text" }; struct Example { Sprite sprites[MAX_SPRITES]; bool use_memory_bitmaps; int blending; ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *mysha, *bitmap; bool hold_bitmap_drawing; int bitmap_size; int sprite_count; bool show_help; ALLEGRO_FONT *font; int t; ALLEGRO_COLOR white; ALLEGRO_COLOR half_white; ALLEGRO_COLOR dark; ALLEGRO_COLOR red; double direct_speed_measure; int ftpos; double frame_times[FPS]; } example; static void add_time(void) { example.frame_times[example.ftpos++] = al_get_time(); if (example.ftpos >= FPS) example.ftpos = 0; } static void get_fps(int *average, int *minmax) { int i; int prev = FPS - 1; double min_dt = 1; double max_dt = 1 / 1000000.0; double av = 0; double d; for (i = 0; i < FPS; i++) { if (i != example.ftpos) { double dt = example.frame_times[i] - example.frame_times[prev]; if (dt < min_dt) min_dt = dt; if (dt > max_dt) max_dt = dt; av += dt; } prev = i; } av /= (FPS - 1); *average = ceil(1 / av); d = 1 / min_dt - 1 / max_dt; *minmax = floor(d / 2); } static void add_sprite(void) { if (example.sprite_count < MAX_SPRITES) { int w = al_get_display_width(example.display); int h = al_get_display_height(example.display); int i = example.sprite_count++; Sprite *s = example.sprites + i; float a = rand() % 360; s->x = rand() % (w - example.bitmap_size); s->y = rand() % (h - example.bitmap_size); s->dx = cos(a) * FPS * 2; s->dy = sin(a) * FPS * 2; } } static void add_sprites(int n) { int i; for (i = 0; i < n; i++) add_sprite(); } static void remove_sprites(int n) { example.sprite_count -= n; if (example.sprite_count < 0) example.sprite_count = 0; } static void change_size(int size) { int bw, bh; if (size < 1) size = 1; if (size > 1024) size = 1024; if (example.bitmap) al_destroy_bitmap(example.bitmap); al_set_new_bitmap_flags( example.use_memory_bitmaps ? ALLEGRO_MEMORY_BITMAP : ALLEGRO_VIDEO_BITMAP); example.bitmap = al_create_bitmap(size, size); example.bitmap_size = size; al_set_target_bitmap(example.bitmap); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_clear_to_color(al_map_rgba_f(0, 0, 0, 0)); bw = al_get_bitmap_width(example.mysha); bh = al_get_bitmap_height(example.mysha); al_draw_scaled_bitmap(example.mysha, 0, 0, bw, bh, 0, 0, size, size * bh / bw, 0); al_set_target_backbuffer(example.display); } static void sprite_update(Sprite *s) { int w = al_get_display_width(example.display); int h = al_get_display_height(example.display); s->x += s->dx / FPS; s->y += s->dy / FPS; if (s->x < 0) { s->x = -s->x; s->dx = -s->dx; } if (s->x + example.bitmap_size > w) { s->x = -s->x + 2 * (w - example.bitmap_size); s->dx = -s->dx; } if (s->y < 0) { s->y = -s->y; s->dy = -s->dy; } if (s->y + example.bitmap_size > h) { s->y = -s->y + 2 * (h - example.bitmap_size); s->dy = -s->dy; } if (example.bitmap_size > w) s->x = w / 2 - example.bitmap_size / 2; if (example.bitmap_size > h) s->y = h / 2 - example.bitmap_size / 2; } static void update(void) { int i; for (i = 0; i < example.sprite_count; i++) sprite_update(example.sprites + i); example.t++; if (example.t == 60) { ALLEGRO_DEBUG("tick"); example.t = 0; } } static void redraw(void) { int w = al_get_display_width(example.display); int h = al_get_display_height(example.display); int i; int f1, f2; int fh = al_get_font_line_height(example.font); char const *info[] = {"textures", "memory buffers"}; char const *binfo[] = {"alpha", "additive", "tinted", "solid", "alpha test"}; ALLEGRO_COLOR tint = example.white; if (example.blending == 0) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); tint = example.half_white; } else if (example.blending == 1) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); tint = example.dark; } else if (example.blending == 2) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); tint = example.red; } else if (example.blending == 3) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); } if (example.blending == 4) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_set_render_state(ALLEGRO_ALPHA_TEST, true); al_set_render_state(ALLEGRO_ALPHA_FUNCTION, ALLEGRO_RENDER_GREATER); al_set_render_state(ALLEGRO_ALPHA_TEST_VALUE, 128); } else { al_set_render_state(ALLEGRO_ALPHA_TEST, false); } if (example.hold_bitmap_drawing) { al_hold_bitmap_drawing(true); } for (i = 0; i < example.sprite_count; i++) { Sprite *s = example.sprites + i; al_draw_tinted_bitmap(example.bitmap, tint, s->x, s->y, 0); } if (example.hold_bitmap_drawing) { al_hold_bitmap_drawing(false); } al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); if (example.show_help) { int dh = fh * 3.5; for (i = 5; i >= 0; i--) { al_draw_text(example.font, example.white, 0, h - dh, 0, text[i]); dh += fh * 6; } } al_draw_textf(example.font, example.white, 0, 0, 0, "count: %d", example.sprite_count); al_draw_textf(example.font, example.white, 0, fh, 0, "size: %d", example.bitmap_size); al_draw_textf(example.font, example.white, 0, fh * 2, 0, "%s", info[example.use_memory_bitmaps]); al_draw_textf(example.font, example.white, 0, fh * 3, 0, "%s", binfo[example.blending]); get_fps(&f1, &f2); al_draw_textf(example.font, example.white, w, 0, ALLEGRO_ALIGN_RIGHT, "FPS: %4d +- %-4d", f1, f2); al_draw_textf(example.font, example.white, w, fh, ALLEGRO_ALIGN_RIGHT, "%4d / sec", (int)(1.0 / example.direct_speed_measure)); } int main(int argc, char **argv) { ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_MONITOR_INFO info; const char* bitmap_filename; int w = 640, h = 480; bool done = false; bool need_redraw = true; bool background = false; example.show_help = true; example.hold_bitmap_drawing = false; if (argc > 1) { bitmap_filename = argv[1]; } else { bitmap_filename = "data/mysha256x256.png"; } if (!al_init()) { abort_example("Failed to init Allegro.\n"); } if (!al_init_image_addon()) { abort_example("Failed to init IIO addon.\n"); } al_init_font_addon(); init_platform_specific(); al_get_num_video_adapters(); al_get_monitor_info(0, &info); al_set_new_display_option(ALLEGRO_SUPPORTED_ORIENTATIONS, ALLEGRO_DISPLAY_ORIENTATION_ALL, ALLEGRO_SUGGEST); example.display = al_create_display(w, h); if (!example.display) { abort_example("Error creating display.\n"); } w = al_get_display_width(example.display); h = al_get_display_height(example.display); if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } if (!al_install_mouse()) { abort_example("Error installing mouse.\n"); } al_install_touch_input(); example.font = al_create_builtin_font(); if (!example.font) { abort_example("Error creating builtin font\n"); } example.mysha = al_load_bitmap(bitmap_filename); if (!example.mysha) { abort_example("Error loading %s\n", bitmap_filename); } example.white = al_map_rgb_f(1, 1, 1); example.half_white = al_map_rgba_f(1, 1, 1, 0.5); example.dark = al_map_rgb(15, 15, 15); example.red = al_map_rgb_f(1, 0.2, 0.1); change_size(256); add_sprite(); add_sprite(); timer = al_create_timer(1.0 / FPS); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); if (al_install_touch_input()) al_register_event_source(queue, al_get_touch_input_event_source()); al_register_event_source(queue, al_get_display_event_source(example.display)); al_start_timer(timer); while (!done) { float x, y; ALLEGRO_EVENT event; w = al_get_display_width(example.display); h = al_get_display_height(example.display); if (!background && need_redraw && al_is_event_queue_empty(queue)) { double t = -al_get_time(); add_time(); al_clear_to_color(al_map_rgb_f(0, 0, 0)); redraw(); t += al_get_time(); example.direct_speed_measure = t; al_flip_display(); need_redraw = false; } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_CHAR: /* includes repeats */ if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; else if (event.keyboard.keycode == ALLEGRO_KEY_UP) { add_sprites(1); } else if (event.keyboard.keycode == ALLEGRO_KEY_DOWN) { remove_sprites(1); } else if (event.keyboard.keycode == ALLEGRO_KEY_LEFT) { change_size(example.bitmap_size - 1); } else if (event.keyboard.keycode == ALLEGRO_KEY_RIGHT) { change_size(example.bitmap_size + 1); } else if (event.keyboard.keycode == ALLEGRO_KEY_F1) { example.show_help ^= 1; } else if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) { example.use_memory_bitmaps ^= 1; change_size(example.bitmap_size); } else if (event.keyboard.keycode == ALLEGRO_KEY_B) { example.blending++; if (example.blending == 5) example.blending = 0; } else if (event.keyboard.keycode == ALLEGRO_KEY_H) { example.hold_bitmap_drawing ^= 1; } break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING: background = true; al_acknowledge_drawing_halt(event.display.source); break; case ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING: background = false; al_acknowledge_drawing_resume(event.display.source); break; case ALLEGRO_EVENT_DISPLAY_RESIZE: al_acknowledge_resize(event.display.source); break; case ALLEGRO_EVENT_TIMER: update(); need_redraw = true; break; case ALLEGRO_EVENT_TOUCH_BEGIN: x = event.touch.x; y = event.touch.y; goto click; case ALLEGRO_EVENT_MOUSE_BUTTON_UP: x = event.mouse.x; y = event.mouse.y; goto click; click: { int fh = al_get_font_line_height(example.font); if (x < fh * 12 && y >= h - fh * 30) { int button = (y - (h - fh * 30)) / (fh * 6); if (button == 0) { example.use_memory_bitmaps ^= 1; change_size(example.bitmap_size); } if (button == 1) { example.blending++; if (example.blending == 5) example.blending = 0; } if (button == 3) { if (x < fh * 6) remove_sprites(example.sprite_count / 2); else add_sprites(example.sprite_count); } if (button == 2) { int s = example.bitmap_size * 2; if (x < fh * 6) s = example.bitmap_size / 2; change_size(s); } if (button == 4) { example.show_help ^= 1; } } break; } } } al_destroy_bitmap(example.bitmap); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_drawpixels.c000066400000000000000000000062401473414355200203220ustar00rootroot00000000000000#include #include #include "common.c" #define WIDTH 640 #define HEIGHT 480 #define NUM_STARS 300 #define TARGET_FPS 9999 typedef struct Point { float x, y; } Point; int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_KEYBOARD_STATE key_state; Point stars[3][NUM_STARS/3]; float speeds[3] = { 0.0001f, 0.05f, 0.15f }; ALLEGRO_COLOR colors[3]; long start, now, elapsed, frame_count; int total_frames = 0; double program_start; double length; int layer, star; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); al_install_keyboard(); display = al_create_display(WIDTH, HEIGHT); if (!display) { abort_example("Could not create display.\n"); } colors[0] = al_map_rgba(255, 100, 255, 128); colors[1] = al_map_rgba(255, 100, 100, 255); colors[2] = al_map_rgba(100, 100, 255, 255); for (layer = 0; layer < 3; layer++) { for (star = 0; star < NUM_STARS/3; star++) { Point *p = &stars[layer][star]; p->x = rand() % WIDTH; p->y = rand() % HEIGHT; } } start = al_get_time() * 1000; now = start; elapsed = 0; frame_count = 0; program_start = al_get_time(); while (1) { if (frame_count < (1000/TARGET_FPS)) { frame_count += elapsed; } else { int X, Y; frame_count -= (1000/TARGET_FPS); al_clear_to_color(al_map_rgb(0, 0, 0)); for (star = 0; star < NUM_STARS/3; star++) { Point *p = &stars[0][star]; al_draw_pixel(p->x, p->y, colors[0]); } al_lock_bitmap(al_get_backbuffer(display), ALLEGRO_PIXEL_FORMAT_ANY, 0); for (layer = 1; layer < 3; layer++) { for (star = 0; star < NUM_STARS/3; star++) { Point *p = &stars[layer][star]; // put_pixel ignores blending al_put_pixel(p->x, p->y, colors[layer]); } } /* Check that dots appear at the window extremes. */ X = WIDTH - 1; Y = HEIGHT - 1; al_put_pixel(0, 0, al_map_rgb_f(1, 1, 1)); al_put_pixel(X, 0, al_map_rgb_f(1, 1, 1)); al_put_pixel(0, Y, al_map_rgb_f(1, 1, 1)); al_put_pixel(X, Y, al_map_rgb_f(1, 1, 1)); al_unlock_bitmap(al_get_backbuffer(display)); al_flip_display(); total_frames++; } now = al_get_time() * 1000; elapsed = now - start; start = now; for (layer = 0; layer < 3; layer++) { for (star = 0; star < NUM_STARS/3; star++) { Point *p = &stars[layer][star]; p->y -= speeds[layer] * elapsed; if (p->y < 0) { p->x = rand() % WIDTH; p->y = HEIGHT; } } } al_rest(0.001); al_get_keyboard_state(&key_state); if (al_key_down(&key_state, ALLEGRO_KEY_ESCAPE)) break; } length = al_get_time() - program_start; if (length != 0) { log_printf("%d FPS\n", (int)(total_frames / length)); } al_destroy_display(display); close_log(true); return 0; } allegro5-5.2.10.1/examples/ex_dualies.c000066400000000000000000000035611473414355200175710ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include #include "common.c" static void go(void) { ALLEGRO_DISPLAY *d1, *d2; ALLEGRO_BITMAP *b1, *b2; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; al_set_new_display_flags(ALLEGRO_FULLSCREEN); al_set_new_display_adapter(0); d1 = al_create_display(640, 480); if (!d1) { abort_example("Error creating first display\n"); } b1 = al_load_bitmap("data/mysha.pcx"); if (!b1) { abort_example("Error loading mysha.pcx\n"); } al_set_new_display_adapter(1); d2 = al_create_display(640, 480); if (!d2) { abort_example("Error creating second display\n"); } b2 = al_load_bitmap("data/allegro.pcx"); if (!b2) { abort_example("Error loading allegro.pcx\n"); } queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); while (1) { if (!al_is_event_queue_empty(queue)) { al_get_next_event(queue, &event); if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } } } al_set_target_backbuffer(d1); al_draw_scaled_bitmap(b1, 0, 0, 320, 200, 0, 0, 640, 480, 0); al_flip_display(); al_set_target_backbuffer(d2); al_draw_scaled_bitmap(b2, 0, 0, 320, 200, 0, 0, 640, 480, 0); al_flip_display(); al_rest(0.1); } al_destroy_bitmap(b1); al_destroy_bitmap(b2); al_destroy_display(d1); al_destroy_display(d2); } int main(int argc, char **argv) { (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_init_image_addon(); if (al_get_num_video_adapters() < 2) { abort_example("You need 2 or more adapters/monitors for this example.\n"); } go(); return 0; } allegro5-5.2.10.1/examples/ex_enet_client.c000066400000000000000000000201701473414355200204270ustar00rootroot00000000000000/* Simple networked game example using ENet (http://enet.bespin.org/). * * You will need enet installed to run this demo. * * This example is based on http://enet.bespin.org/Tutorial.html * * To try this example, first run ex_enet_server. * Then start multiple instances of ex_enet_client. */ #include #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_primitives.h" #include "common.c" #include "enet_common.h" static ENetHost* create_client(void) { ENetHost * client; client = enet_host_create(NULL /* create a client host */, 1 /* only allow 1 outgoing connection */, 2 /* allow up 2 channels to be used, 0 and 1 */, 57600 / 8 /* 56K modem with 56 Kbps downstream bandwidth */, 14400 / 8 /* 56K modem with 14 Kbps upstream bandwidth */); if (client == NULL) abort_example("Client: Failed to create the client.\n"); return client; } static void disconnect_client(ENetHost *client, ENetPeer *server) { enet_peer_disconnect(server, 0); /* Allow up to 3 seconds for the disconnect to succeed * and drop any packets received packets. */ ENetEvent event; while (enet_host_service (client, &event, 3000) > 0) { switch (event.type) { case ENET_EVENT_TYPE_RECEIVE: enet_packet_destroy(event.packet); break; case ENET_EVENT_TYPE_DISCONNECT: puts("Client: Disconnect succeeded."); return; case ENET_EVENT_TYPE_NONE: case ENET_EVENT_TYPE_CONNECT: break; } } // failed to disconnect gracefully, force the connection closed enet_peer_reset(server); } static ENetPeer* connect_client(ENetHost *client, int port) { ENetAddress address; ENetEvent event; ENetPeer *server; enet_address_set_host(&address, "localhost"); address.port = port; /* Initiate the connection, allocating the two channels 0 and 1. */ server = enet_host_connect(client, &address, 2, 0); if (server == NULL) abort_example("Client: No available peers for initiating an ENet connection.\n"); /* Wait up to 5 seconds for the connection attempt to succeed. */ if (enet_host_service(client, &event, 5000) > 0 && event.type == ENET_EVENT_TYPE_CONNECT) { printf("Client: Connected to %x:%u.\n", event.peer->address.host, event.peer->address.port); } else { /* Either the 5 seconds are up or a disconnect event was */ /* received. Reset the peer in the event the 5 seconds */ /* had run out without any significant event. */ enet_peer_reset(server); abort_example("Client: Connection to server failed."); } return server; } static void send_receive(ENetHost *client) { ENetEvent event; ServerMessage *msg; // Check if we have any queued incoming messages, but do not wait otherwise. // This also sends outgoing messages queued with enet_peer_send. while (enet_host_service(client, &event, 0) > 0) { // clients only care about incoming packets, they will not receive // connect/disconnect events. if (event.type == ENET_EVENT_TYPE_RECEIVE) { msg = (ServerMessage*)event.packet->data; switch (msg->type) { case POSITION_UPDATE: players[msg->player_id].x = msg->x; players[msg->player_id].y = msg->y; break; case PLAYER_JOIN: printf("Client: player #%d joined\n", msg->player_id); players[msg->player_id].active = true; players[msg->player_id].x = msg->x; players[msg->player_id].y = msg->y; players[msg->player_id].color = msg->color; break; case PLAYER_LEAVE: printf("Client: player #%d left\n", msg->player_id); players[msg->player_id].active = false; break; } /* Clean up the packet now that we're done using it. */ enet_packet_destroy(event.packet); } } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; ENetHost *client; ENetPeer *server; bool update = true; // when true, update positions and render bool done = false; // when true, client exits int dx = 0, dy = 0; // movement direction int port = DEFAULT_PORT; int i; if (argc == 2) { port = atoi(argv[1]); } else if (argc > 2) abort_example("Usage: %s [portnum]", argv[0]); // --- allegro setup --- if (!al_init()) abort_example("Could not init Allegro.\n"); init_platform_specific(); al_install_keyboard(); al_init_primitives_addon(); // Create a new display that we can render the image to. display = al_create_display(SCREEN_W, SCREEN_H); if (!display) abort_example("Error creating display\n"); timer = al_create_timer(1.0 / FPS); // Run at 30FPS queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); // --- enet setup --- if (enet_initialize() != 0) abort_example("An error occurred while initializing ENet.\n"); client = create_client(); server = connect_client(client, port); // --- game loop --- bool direction_changed = false; while (!done) { al_wait_for_event(queue, &event); // Wait for and get an event. switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_KEY_DOWN: switch (event.keyboard.keycode) { case ALLEGRO_KEY_UP: case ALLEGRO_KEY_W: dy -= 1; direction_changed = true; break; case ALLEGRO_KEY_DOWN: case ALLEGRO_KEY_S: dy += 1; direction_changed = true; break; case ALLEGRO_KEY_LEFT: case ALLEGRO_KEY_A: dx -= 1; direction_changed = true; break; case ALLEGRO_KEY_RIGHT: case ALLEGRO_KEY_D: dx += 1; direction_changed = true; break; } break; case ALLEGRO_EVENT_KEY_UP: switch (event.keyboard.keycode) { case ALLEGRO_KEY_UP: case ALLEGRO_KEY_W: dy += 1; direction_changed = true; break; case ALLEGRO_KEY_DOWN: case ALLEGRO_KEY_S: dy -= 1; direction_changed = true; break; case ALLEGRO_KEY_LEFT: case ALLEGRO_KEY_A: dx += 1; direction_changed = true; break; case ALLEGRO_KEY_RIGHT: case ALLEGRO_KEY_D: dx -= 1; direction_changed = true; break; } break; case (ALLEGRO_EVENT_TIMER): update = true; break; } // update, but only if the event queue is empty if (update && al_is_event_queue_empty(queue)) { update = false; // if player changed direction this frame, notify the server. // only check once per frame to stop clients from flooding the server if (direction_changed) { direction_changed = false; ClientMessage msg = { dx, dy }; ENetPacket *packet = enet_packet_create(&msg, sizeof(msg), ENET_PACKET_FLAG_RELIABLE); enet_peer_send(server, 0, packet); } // this will send our queued direction message if we have one, and get // position updates for other clients send_receive(client); // draw each player al_clear_to_color(al_map_rgb_f(0, 0, 0)); for (i = 0; i < MAX_PLAYER_COUNT; i++) { if (!players[i].active) continue; int x = players[i].x; int y = players[i].y; ALLEGRO_COLOR color = players[i].color; al_draw_filled_circle(x, y, PLAYER_SIZE, color); } al_flip_display(); } } disconnect_client(client, server); enet_host_destroy(client); enet_deinitialize(); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_enet_server.c000066400000000000000000000154541473414355200204700ustar00rootroot00000000000000/* Simple networked game example using ENet (http://enet.bespin.org/). * * You will need enet installed to run this demo. * * This example is based on http://enet.bespin.org/Tutorial.html * * This is the server, which you will want to start first. Once the server is * running, run ex_enet_client to connect each client. */ #include #include #include #include #include #include "common.c" #include "enet_common.h" #define PLAYER_SPEED 200 // pixels / second const int port = 9234; static float rand01(void) { return rand() / (float)RAND_MAX; } static int init_player(void) { int i; // find the first open player slot for (i = 0 ; i < MAX_PLAYER_COUNT ; ++i) { if (!players[i].active) { // assign a random color and position to this new player players[i].active = true; players[i].color = al_map_rgb_f(rand01(), rand01(), rand01()); players[i].x = rand01() * SCREEN_W; players[i].y = rand01() * SCREEN_H; return i; } } abort_example("Cannot create more than %d clients", MAX_PLAYER_COUNT); return -1; } static ServerMessage create_join_message(int player_id) { ServerMessage msg_out; msg_out.type = PLAYER_JOIN; msg_out.player_id = player_id; msg_out.color = players[player_id].color; msg_out.x = players[player_id].x; msg_out.y = players[player_id].y; return msg_out; } static void send_receive(ENetHost *server) { ClientMessage *msg_in; ServerMessage msg_out; ENetPacket *packet; ENetEvent event; int i; // Process all messages in queue, exit as soon as it is empty while (enet_host_service(server, &event, 0) > 0) { switch (event.type) { case ENET_EVENT_TYPE_NONE: break; case ENET_EVENT_TYPE_CONNECT: printf("Server: A new client connected from %x:%u.\n", event.peer->address.host, event.peer->address.port); int player_id = init_player(); // store the id with the peer we can correlate messages from this // client with this ID event.peer->data = malloc(sizeof(int)); *(int*)event.peer->data = player_id; // notify all clients of the new player msg_out = create_join_message(player_id); printf("Server: created player #%d at %d,%d\n", player_id, players[player_id].x, players[player_id].y); packet = enet_packet_create(&msg_out, sizeof(msg_out), ENET_PACKET_FLAG_RELIABLE); enet_host_broadcast(server, 0, packet); // notify new client of all other existing players for (i = 0 ; i < MAX_PLAYER_COUNT ; ++i) { if (!players[i].active || i == player_id) continue; msg_out = create_join_message(i); packet = enet_packet_create(&msg_out, sizeof(msg_out), ENET_PACKET_FLAG_RELIABLE); enet_peer_send(event.peer, 0, packet); } break; case ENET_EVENT_TYPE_RECEIVE: msg_in = (ClientMessage*)event.packet->data; // update the player's movement player_id = *(int*)event.peer->data; players[player_id].dx = msg_in->x; players[player_id].dy = msg_in->y; /* Clean up the incoming packet now that we're done using it. */ enet_packet_destroy(event.packet); break; case ENET_EVENT_TYPE_DISCONNECT: printf("Server: client #%d disconnected.\n", *((int*)event.peer->data)); // notify all other players that a player left msg_out.type = PLAYER_LEAVE; msg_out.player_id = *(int*)event.peer->data; packet = enet_packet_create(&msg_out, sizeof(msg_out), ENET_PACKET_FLAG_RELIABLE); enet_host_broadcast(server, 0, packet); /* Reset the peer's server information. */ free(event.peer->data); event.peer->data = NULL; } } } static void update_players(ENetHost *server, float time) { int i; for (i = 0 ; i < MAX_PLAYER_COUNT ; ++i) { if (!players[i].active) continue; players[i].x += players[i].dx * PLAYER_SPEED * time; players[i].y += players[i].dy * PLAYER_SPEED * time; // notify all clients of this player's new position ServerMessage msg; msg.type = POSITION_UPDATE; msg.player_id = i; msg.x = players[i].x; msg.y = players[i].y; ENetPacket *packet = enet_packet_create(&msg, sizeof(ServerMessage), ENET_PACKET_FLAG_RELIABLE); enet_host_broadcast(server, 0, packet); } } static ENetHost* create_server(int port) { ENetAddress address; ENetHost *server; /* Bind the server to the default localhost. */ /* A specific host address can be specified by */ /* enet_address_set_host (&address, "x.x.x.x"); */ address.host = ENET_HOST_ANY; /* Bind the server to port 1234. */ address.port = port; server = enet_host_create(&address /* the address to bind the server host to */, 32 /* allow up to 32 clients and/or outgoing connections */, 2 /* allow up to 2 channels to be used, 0 and 1 */, 0 /* assume any amount of incoming bandwidth */, 0 /* assume any amount of outgoing bandwidth */); if (server == NULL) { fprintf(stderr, "Failed to create the server.\n"); exit(EXIT_FAILURE); } return server; } int main(int argc, char **argv) { ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; double last_time; // time of last update double cur_time; // time of this update srand(time(NULL)); ENetHost * server; int port; if (argc == 1) port = DEFAULT_PORT; else if (argc == 2) port = atoi(argv[1]); else abort_example("Usage: %s [portnum]", argv[0]); if (!al_init()) abort_example("Could not init Allegro.\n"); if (enet_initialize() != 0) { fprintf(stderr, "An error occurred while initializing ENet.\n"); return EXIT_FAILURE; } timer = al_create_timer(1.0 / FPS); // Run at 30FPS queue = al_create_event_queue(); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); server = create_server(port); last_time = al_get_time(); while(1) { al_wait_for_event(queue, &event); // Wait for and get an event. if (event.type == ALLEGRO_EVENT_TIMER) { cur_time = al_get_time(); update_players(server, cur_time - last_time); last_time = cur_time; send_receive(server); } } enet_host_destroy(server); enet_deinitialize(); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_expose.c000066400000000000000000000053671473414355200174540ustar00rootroot00000000000000#include #include #include #include "common.c" int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *bitmap; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_init_image_addon(); al_install_keyboard(); al_install_mouse(); init_platform_specific(); al_set_new_display_flags(ALLEGRO_RESIZABLE | ALLEGRO_GENERATE_EXPOSE_EVENTS); al_set_new_display_option(ALLEGRO_SINGLE_BUFFER, true, ALLEGRO_REQUIRE); display = al_create_display(320, 200); if (!display) { abort_example("Error creating display\n"); } bitmap = al_load_bitmap("data/mysha.pcx"); if (!bitmap) { abort_example("mysha.pcx not found or failed to load\n"); } al_draw_bitmap(bitmap, 0, 0, 0); al_flip_display(); timer = al_create_timer(0.1); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (true) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { al_acknowledge_resize(event.display.source); } if (event.type == ALLEGRO_EVENT_DISPLAY_EXPOSE) { int x = event.display.x, y = event.display.y, w = event.display.width, h = event.display.height; /* Draw a red rectangle over the damaged area. */ al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_draw_filled_rectangle(x, y, x + w, y + h, al_map_rgba_f(1, 0, 0, 1)); al_flip_display(); } if (event.type == ALLEGRO_EVENT_TIMER) { /* Slowly restore the original bitmap. */ int x, y; al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); for (y = 0; y < al_get_display_height(display); y += 200) { for (x = 0; x < al_get_display_width(display); x += 320) { al_draw_tinted_bitmap(bitmap, al_map_rgba_f(1, 1, 1, 0.1), x, y, 0); } } al_flip_display(); } } al_destroy_event_queue(queue); al_destroy_bitmap(bitmap); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_file.c000066400000000000000000000100731473414355200170560ustar00rootroot00000000000000#include #include "common.c" static int error = 0; #define SEP() \ log_printf("\n# line %d\n", __LINE__) #define CHECK(_expr, _type, _expect) \ do { \ _type res = (_expr); \ if (res != (_expect)) { \ log_printf("FAIL %s\n", #_expr); \ error++; \ } else { \ log_printf("OK %s\n", #_expr); \ } \ } while (0) static void read_test(void) { ALLEGRO_FILE *f; uint8_t bs[8]; int32_t sz; f = al_fopen("data/allegro.pcx", "rb"); if (!f) { error++; return; } /* Test: reading bytes advances position. */ SEP(); CHECK(al_ftell(f), int, 0); CHECK(al_fgetc(f), int, 0xa); CHECK(al_fgetc(f), int, 0x5); CHECK(al_ftell(f), int64_t, 2); /* Test: ungetc moves position back. */ SEP(); CHECK(al_fungetc(f, 0x55), bool, true); CHECK(al_ftell(f), int64_t, 1); /* Test: read buffer. */ SEP(); CHECK(al_fread(f, bs, sizeof(bs)), size_t, sizeof(bs)); CHECK(bs[0], uint8_t, 0x55); /* pushback */ CHECK(bs[1], uint8_t, 0x01); CHECK(bs[2], uint8_t, 0x08); CHECK(bs[3], uint8_t, 0x00); CHECK(bs[4], uint8_t, 0x00); CHECK(bs[5], uint8_t, 0x00); CHECK(bs[6], uint8_t, 0x00); CHECK(bs[7], uint8_t, 0x3f); CHECK(al_ftell(f), int64_t, 9); /* Test: seek absolute. */ SEP(); CHECK(al_fseek(f, 13, ALLEGRO_SEEK_SET), bool, true); CHECK(al_ftell(f), int64_t, 13); CHECK(al_fgetc(f), int, 0x02); /* Test: seek nowhere. */ SEP(); CHECK(al_fseek(f, 0, ALLEGRO_SEEK_CUR), bool, true); CHECK(al_ftell(f), int64_t, 14); CHECK(al_fgetc(f), int, 0xe0); /* Test: seek nowhere with pushback. */ SEP(); CHECK(al_fungetc(f, 0x55), bool, true); CHECK(al_fseek(f, 0, ALLEGRO_SEEK_CUR), bool, true); CHECK(al_ftell(f), int64_t, 14); CHECK(al_fgetc(f), int, 0xe0); /* Test: seek relative backwards. */ SEP(); CHECK(al_fseek(f, -3, ALLEGRO_SEEK_CUR), bool, true); CHECK(al_ftell(f), int64_t, 12); CHECK(al_fgetc(f), int, 0x80); /* Test: seek backwards with pushback. */ SEP(); CHECK(al_ftell(f), int64_t, 13); CHECK(al_fungetc(f, 0x66), bool, true); CHECK(al_ftell(f), int64_t, 12); CHECK(al_fseek(f, -2, ALLEGRO_SEEK_CUR), bool, true); CHECK(al_ftell(f), int64_t, 10); CHECK(al_fgetc(f), int, 0xc7); /* Test: seek relative to end. */ SEP(); CHECK(al_fseek(f, 0, ALLEGRO_SEEK_END), bool, true); CHECK(al_feof(f), bool, false); CHECK(al_ftell(f), int64_t, 0xab06); /* Test: read past EOF. */ SEP(); CHECK(al_fgetc(f), int, -1); CHECK(al_feof(f), bool, true); CHECK(al_ferror(f), int, 0); /* Test: seek clears EOF indicator. */ SEP(); CHECK(al_fseek(f, 0, ALLEGRO_SEEK_END), bool, true); CHECK(al_feof(f), bool, false); CHECK(al_ftell(f), int64_t, 0xab06); /* Test: seek backwards from end. */ SEP(); CHECK(al_fseek(f, -20, ALLEGRO_SEEK_END), bool, true); CHECK(al_ftell(f), int64_t, 0xaaf2); /* Test: seek forwards from end. */ SEP(); CHECK(al_fseek(f, 20, ALLEGRO_SEEK_END), bool, true); CHECK(al_ftell(f), int64_t, 0xab1a); CHECK(al_fgetc(f), int, -1); CHECK(al_feof(f), bool, true); /* Test: get file size if possible. */ SEP(); CHECK(sz = al_fsize(f), int64_t, sz); if (sz != -1) CHECK(sz, int64_t, 0xab06); /* Test: close. */ SEP(); CHECK(al_fclose(f), bool, true); } int main(int argc, char *argv[]) { (void)argc; (void)argv; if (!al_init()) return 1; init_platform_specific(); open_log_monospace(); read_test(); close_log(true); if (error) { exit(EXIT_FAILURE); } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_file_slice.c000066400000000000000000000054401473414355200202370ustar00rootroot00000000000000/* * ex_file_slice - Use slices to pack many objects into a single file. * * This example packs two strings into a single file, and then uses a * file slice to open them one at a time. While this usage is contrived, * the same principle can be used to pack multiple images (for example) * into a single file, and later read them back via Allegro's image loader. * */ #include "allegro5/allegro.h" #include "common.c" #define BUFFER_SIZE 1024 static void pack_object(ALLEGRO_FILE *file, const void *object, size_t len) { /* First write the length of the object, so we know how big to make the slice when it is opened later. */ al_fwrite32le(file, len); al_fwrite(file, object, len); } static ALLEGRO_FILE *get_next_chunk(ALLEGRO_FILE *file) { /* Reads the length of the next chunk, and if not at end of file, returns a slice that represents that portion of the file. */ const uint32_t length = al_fread32le(file); return !al_feof(file) ? al_fopen_slice(file, length, "rw") : NULL; } int main(int argc, const char *argv[]) { ALLEGRO_FILE *master, *slice; ALLEGRO_PATH *tmp_path; const char *first_string = "Hello, World!"; const char *second_string = "The quick brown fox jumps over the lazy dog."; char buffer[BUFFER_SIZE]; (void) argc, (void) argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); master = al_make_temp_file("ex_file_slice_XXXX", &tmp_path); if (!master) { abort_example("Unable to create temporary file\n"); } /* Pack both strings into the master file. */ pack_object(master, first_string, strlen(first_string)); pack_object(master, second_string, strlen(second_string)); /* Seek back to the beginning of the file, as if we had just opened it */ al_fseek(master, 0, ALLEGRO_SEEK_SET); /* Loop through the main file, opening a slice for each object */ while ((slice = get_next_chunk(master))) { /* Note: While the slice is open, we must avoid using the master file! If you were dealing with packed images, this is where you would pass 'slice' to al_load_bitmap_f(). */ if (al_fsize(slice) < BUFFER_SIZE) { /* We could have used al_fgets(), but just to show that the file slice is constrained to the string object, we'll read the entire slice. */ al_fread(slice, buffer, al_fsize(slice)); buffer[al_fsize(slice)] = 0; log_printf("Chunk of size %d: '%s'\n", (int) al_fsize(slice), buffer); } /* The slice must be closed before the next slice is opened. Closing the slice will advanced the master file to the end of the slice. */ al_fclose(slice); } al_fclose(master); al_remove_filename(al_path_cstr(tmp_path, '/')); close_log(true); return 0; } allegro5-5.2.10.1/examples/ex_filter.c000066400000000000000000000122771473414355200174340ustar00rootroot00000000000000#include #include #include #include #include #include "common.c" #define FPS 60 static struct Example { ALLEGRO_DISPLAY *display; ALLEGRO_FONT *font; ALLEGRO_BITMAP *bitmaps[2][9]; ALLEGRO_COLOR bg, fg, info; int bitmap; int ticks; } example; static int const filter_flags[6] = { 0, ALLEGRO_MIN_LINEAR, ALLEGRO_MIPMAP, ALLEGRO_MIN_LINEAR | ALLEGRO_MIPMAP, 0, ALLEGRO_MAG_LINEAR }; static char const *filter_text[4] = { "nearest", "linear", "nearest mipmap", "linear mipmap" }; static void update(void) { example.ticks++; } static void redraw(void) { int w = al_get_display_width(example.display); int h = al_get_display_height(example.display); int i; al_clear_to_color(example.bg); for (i = 0; i < 6; i++) { float x = (i / 2) * w / 3 + w / 6; float y = (i % 2) * h / 2 + h / 4; ALLEGRO_BITMAP *bmp = example.bitmaps[example.bitmap][i]; float bw = al_get_bitmap_width(bmp); float bh = al_get_bitmap_height(bmp); float t = 1 - 2 * fabs((example.ticks % (FPS * 16)) / 16.0 / FPS - 0.5); float scale; float angle = example.ticks * ALLEGRO_PI * 2 / FPS / 8; if (i < 4) scale = 1 - t * 0.9; else scale = 1 + t * 9; al_draw_textf(example.font, example.fg, x, y - 64 - 14, ALLEGRO_ALIGN_CENTRE, "%s", filter_text[i % 4]); al_set_clipping_rectangle(x - 64, y - 64, 128, 128); al_draw_scaled_rotated_bitmap(bmp, bw / 2, bh / 2, x, y, scale, scale, angle, 0); al_set_clipping_rectangle(0, 0, w, h); } al_draw_textf(example.font, example.info, w / 2, h - 14, ALLEGRO_ALIGN_CENTRE, "press space to change"); } int main(int argc, char **argv) { ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; int w = 640, h = 480; bool done = false; bool need_redraw = true; int i; ALLEGRO_BITMAP *mysha; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } if (!al_init_image_addon()) { abort_example("Failed to init IIO addon.\n"); } al_init_font_addon(); init_platform_specific(); example.display = al_create_display(w, h); if (!example.display) { abort_example("Error creating display.\n"); } if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } if (!al_install_mouse()) { abort_example("Error installing mouse.\n"); } example.font = al_load_font("data/fixed_font.tga", 0, 0); if (!example.font) { abort_example("Error loading data/fixed_font.tga\n"); } mysha = al_load_bitmap("data/mysha256x256.png"); if (!mysha) { abort_example("Error loading data/mysha256x256.png\n"); } for (i = 0; i < 6; i++) { ALLEGRO_LOCKED_REGION *lock; int x, y; /* Only power-of-two bitmaps can have mipmaps. */ al_set_new_bitmap_flags(filter_flags[i]); example.bitmaps[0][i] = al_create_bitmap(1024, 1024); example.bitmaps[1][i] = al_clone_bitmap(mysha); lock = al_lock_bitmap(example.bitmaps[0][i], ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_WRITEONLY); for (y = 0; y < 1024; y++) { unsigned char *row = (unsigned char *)lock->data + lock->pitch * y; unsigned char *ptr = row; for (x = 0; x < 1024; x++) { int c = 0; if (((x >> 2) & 1) ^ ((y >> 2) & 1)) c = 255; *(ptr++) = c; *(ptr++) = c; *(ptr++) = c; *(ptr++) = 255; } } al_unlock_bitmap(example.bitmaps[0][i]); } example.bg = al_map_rgb_f(0, 0, 0); example.fg = al_map_rgb_f(1, 1, 1); example.info = al_map_rgb_f(0.5, 0.5, 1); timer = al_create_timer(1.0 / FPS); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(example.display)); al_start_timer(timer); while (!done) { ALLEGRO_EVENT event; if (need_redraw && al_is_event_queue_empty(queue)) { redraw(); al_flip_display(); need_redraw = false; } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) example.bitmap = (example.bitmap + 1) % 2; break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_TIMER: update(); need_redraw = true; break; case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: example.bitmap = (example.bitmap + 1) % 2; break; } } for (i = 0; i < 6; i++) { al_destroy_bitmap(example.bitmaps[0][i]); al_destroy_bitmap(example.bitmaps[1][i]); } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_font.c000066400000000000000000000105221473414355200171040ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_image.h" #include "common.c" #define EURO "\xe2\x82\xac" static void wait_for_esc(ALLEGRO_DISPLAY *display) { ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_BITMAP *screen_clone; al_install_keyboard(); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); screen_clone = al_clone_bitmap(al_get_target_bitmap()); while (1) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; else if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; } else if (event.type == ALLEGRO_EVENT_DISPLAY_EXPOSE) { int x = event.display.x; int y = event.display.y; int w = event.display.width; int h = event.display.height; al_draw_bitmap_region(screen_clone, x, y, w, h, x, y, 0); al_update_display_region(x, y, w, h); } } al_destroy_bitmap(screen_clone); al_destroy_event_queue(queue); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *bitmap, *font_bitmap; ALLEGRO_FONT *f1, *f2, *f3; int range, index, x, y; int ranges[] = { 0x0020, 0x007F, /* ASCII */ 0x00A1, 0x00FF, /* Latin 1 */ 0x0100, 0x017F, /* Extended-A */ 0x20AC, 0x20AC}; /* Euro */ (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_image_addon(); al_init_font_addon(); init_platform_specific(); al_set_new_display_option(ALLEGRO_SINGLE_BUFFER, true, ALLEGRO_SUGGEST); al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(640, 480); if (!display) { abort_example("Failed to create display\n"); } bitmap = al_load_bitmap("data/mysha.pcx"); if (!bitmap) { abort_example("Failed to load mysha.pcx\n"); } f1 = al_load_font("data/bmpfont.tga", 0, 0); if (!f1) { abort_example("Failed to load bmpfont.tga\n"); } font_bitmap = al_load_bitmap("data/a4_font.tga"); if (!font_bitmap) { abort_example("Failed to load a4_font.tga\n"); } f2 = al_grab_font_from_bitmap(font_bitmap, 4, ranges); f3 = al_create_builtin_font(); if (!f3) { abort_example("Failed to create builtin font.\n"); } /* Draw background */ al_draw_scaled_bitmap(bitmap, 0, 0, 320, 240, 0, 0, 640, 480, 0); /* Draw red text */ al_draw_textf(f1, al_map_rgb(255, 0, 0), 10, 10, 0, "red"); /* Draw green text */ al_draw_textf(f1, al_map_rgb(0, 255, 0), 120, 10, 0, "green"); /* Draw a unicode symbol */ al_draw_textf(f2, al_map_rgb(0, 0, 255), 60, 60, 0, "Mysha's 0.02" EURO); /* Draw a yellow text with the builtin font */ al_draw_textf(f3, al_map_rgb(255, 255, 0), 20, 200, ALLEGRO_ALIGN_CENTER, "a string from builtin font data"); /* Draw all individual glyphs the f2 font's range in rainbow colors. */ x = 10; y = 300; al_draw_textf(f3, al_map_rgb(0, 255, 255), x, y - 20, 0, "Draw glyphs: "); for (range = 0; range < 4; range++) { int start = ranges[2*range]; int stop = ranges[2*range + 1]; for (index = start; index < stop; index ++) { /* Use al_get_glyph_advance for the stride. */ int width = al_get_glyph_advance(f2, index, ALLEGRO_NO_KERNING); int r = fabs(sin(ALLEGRO_PI * (index) * 36 / 360.0)) * 255.0; int g = fabs(sin(ALLEGRO_PI * (index + 12) * 36 / 360.0)) * 255.0; int b = fabs(sin(ALLEGRO_PI * (index + 24) * 36 / 360.0)) * 255.0; al_draw_glyph(f2, al_map_rgb(r, g, b), x, y, index); x += width; if (x > (al_get_display_width(display) - 10)) { x = 10; y += al_get_font_line_height(f2); } } } al_flip_display(); wait_for_esc(display); al_destroy_bitmap(bitmap); al_destroy_bitmap(font_bitmap); al_destroy_font(f1); al_destroy_font(f2); al_destroy_font(f3); return 0; } /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/examples/ex_font_justify.cpp000066400000000000000000000065161473414355200212310ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * * Test text justification routines. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_ttf.h" #include #include "nihgui.hpp" #include "common.c" ALLEGRO_FONT *font; ALLEGRO_FONT *font_gui; class Prog { private: Dialog d; Label text_label; Label width_label; Label diff_label; TextEntry text_entry; HSlider width_slider; HSlider diff_slider; public: Prog(const Theme & theme, ALLEGRO_DISPLAY *display); void run(); void draw_text(); }; Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) : d(Dialog(theme, display, 10, 20)), text_label(Label("Text")), width_label(Label("Width")), diff_label(Label("Diff")), text_entry(TextEntry("Lorem ipsum dolor sit amet")), width_slider(HSlider(400, al_get_display_width(display))), diff_slider(HSlider(100, al_get_display_width(display))) { d.add(text_label, 0, 10, 1, 1); d.add(text_entry, 1, 10, 8, 1); d.add(width_label, 0, 12, 1, 1); d.add(width_slider, 1, 12, 8, 1); d.add(diff_label, 0, 14, 1, 1); d.add(diff_slider, 1, 14, 8, 1); } void Prog::run() { d.prepare(); while (!d.is_quit_requested()) { if (d.is_draw_requested()) { al_clear_to_color(al_map_rgb(128, 128, 128)); draw_text(); d.draw(); al_flip_display(); } d.run_step(true); } } void Prog::draw_text() { ALLEGRO_BITMAP *target = al_get_target_bitmap(); const int cx = al_get_bitmap_width(target) / 2; const int x1 = cx - width_slider.get_cur_value() / 2; const int x2 = cx + width_slider.get_cur_value() / 2; const int diff = diff_slider.get_cur_value(); const int th = al_get_font_line_height(font); al_draw_justified_text(font, al_map_rgb_f(1, 1, 1), x1, x2, 50, diff, ALLEGRO_ALIGN_INTEGER, text_entry.get_text()); al_draw_rectangle(x1, 50, x2, 50 + th, al_map_rgb(0, 0, 255), 0); al_draw_line(cx - diff / 2, 53 + th, cx + diff / 2, 53 + th, al_map_rgb(0, 255, 0), 0); } int main(int argc, char *argv[]) { ALLEGRO_DISPLAY *display; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro\n"); } al_init_primitives_addon(); al_install_keyboard(); al_install_mouse(); al_init_image_addon(); al_init_font_addon(); al_init_ttf_addon(); init_platform_specific(); al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(640, 480); if (!display) { abort_example("Unable to create display\n"); } /* Test TTF fonts or bitmap fonts. */ #if 1 font = al_load_font("data/DejaVuSans.ttf", 24, 0); if (!font) { abort_example("Failed to load data/DejaVuSans.ttf\n"); } #else font = al_load_font("data/font.tga", 0, 0); if (!font) { abort_example("Failed to load data/font.tga\n"); } #endif font_gui = al_load_font("data/DejaVuSans.ttf", 14, 0); if (!font_gui) { abort_example("Failed to load data/DejaVuSans.ttf\n"); } /* Don't remove these braces. */ { Theme theme(font_gui); Prog prog(theme, display); prog.run(); } al_destroy_font(font); al_destroy_font(font_gui); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_font_multiline.cpp000066400000000000000000000163261473414355200215360ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * * Test multi line text routines. */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_ttf.h" #include "allegro5/allegro_color.h" #include "allegro5/allegro_primitives.h" #include "nihgui.hpp" #include "common.c" #define TEST_TEXT "This is utf-8 €€€€€ multi line text output with a\nhard break,\n\ntwice even!" /* This is a custom mult line output function that demonstrates * al_do_multiline_text. See below for the implementation. */ static void draw_custom_multiline(ALLEGRO_FONT * font, int x, int y, int max_width, int line_height, int tick, const char * text); ALLEGRO_TIMER *timer; ALLEGRO_FONT *font; ALLEGRO_FONT *font_ttf; ALLEGRO_FONT *font_bmp; ALLEGRO_FONT *font_gui; ALLEGRO_FONT *font_bin; class Prog : public EventHandler { private: Dialog d; Label text_label; Label width_label; Label height_label; Label align_label; Label font_label; TextEntry text_entry; HSlider width_slider; VSlider height_slider; List text_align; List text_font; int tick; public: Prog(const Theme & theme, ALLEGRO_DISPLAY *display); virtual ~Prog() {} void run(); void draw_text(); void handle_event(const ALLEGRO_EVENT & event); }; Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) : d(Dialog(theme, display, 14, 20)), text_label(Label("Text")), width_label(Label("Width")), height_label(Label("Line height")), align_label(Label("Align")), font_label(Label("Font")), text_entry(TextEntry(TEST_TEXT)), width_slider(HSlider(200, al_get_display_width(display))), height_slider(VSlider(0, 50)), text_align(List(0)), text_font(List(0)) { text_align.append_item("Left"); text_align.append_item("Center"); text_align.append_item("Right"); text_font.append_item("Truetype"); text_font.append_item("Bitmap"); text_font.append_item("Builtin"); d.add(text_label, 0, 14, 1, 1); d.add(text_entry, 1, 14, 12, 1); d.add(width_label, 0, 15, 1, 1); d.add(width_slider, 1, 15, 12, 1); d.add(align_label, 0, 17, 2, 1); d.add(text_align , 2, 17, 2, 3); d.add(font_label, 4, 17, 2, 1); d.add(text_font , 6, 17, 2, 3); d.add(height_label, 8, 17, 2, 1); d.add(height_slider, 10, 17, 2, 3); } void Prog::run() { d.prepare(); d.register_event_source(al_get_timer_event_source(timer)); d.set_event_handler(this); while (!d.is_quit_requested()) { if (d.is_draw_requested()) { al_clear_to_color(al_map_rgb(128, 128, 128)); draw_text(); d.draw(); al_flip_display(); } d.run_step(true); } } void Prog::handle_event(const ALLEGRO_EVENT & event) { if (event.type == ALLEGRO_EVENT_TIMER) { tick = (int)event.timer.count; d.request_draw(); } } void Prog::draw_text() { int x = 10, y = 10; int sx = 10, sy = 10; int w = width_slider.get_cur_value(); int h = height_slider.get_cur_value(); int flags = 0; const char * text = text_entry.get_text(); if (text_font.get_selected_item_text() == "Truetype") { font = font_ttf; } else if (text_font.get_selected_item_text() == "Bitmap") { font = font_bmp; } else if (text_font.get_selected_item_text() == "Builtin") { font = font_bin; } if (text_align.get_selected_item_text() == "Left") { flags = ALLEGRO_ALIGN_LEFT | ALLEGRO_ALIGN_INTEGER; } else if (text_align.get_selected_item_text() == "Center") { flags = ALLEGRO_ALIGN_CENTER | ALLEGRO_ALIGN_INTEGER; x = 10 + w / 2; } else if (text_align.get_selected_item_text() == "Right") { flags = ALLEGRO_ALIGN_RIGHT | ALLEGRO_ALIGN_INTEGER; x = 10 + w; } /* Draw a red rectangle on the top with the requested width, * a blue rectangle around the real bounds of the text, * a green line for the X axis location of drawing the text * and the line height, and finally the text itself. */ al_draw_rectangle(sx, sy-2 + 30, sx + w, sy - 1 + 30, al_map_rgb(255, 0, 0), 0); al_draw_line(x, y + 30, x, y + h + 30, al_map_rgb(0, 255, 0), 0); al_draw_multiline_text(font, al_map_rgb_f(1, 1, 1), x, y + 30, w, h, flags, text); /* also do some custom bultiline drawing */ al_draw_text(font, al_map_rgb_f(1, 1, 1), w + 10, y, 0, "Custom multiline text:" ); draw_custom_multiline(font, w + 10 , y + 30, w, h, tick, text); } int main(int argc, char *argv[]) { ALLEGRO_DISPLAY *display; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro\n"); } al_init_primitives_addon(); al_install_keyboard(); al_install_mouse(); al_init_image_addon(); al_init_font_addon(); al_init_ttf_addon(); init_platform_specific(); al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(640, 480); if (!display) { abort_example("Unable to create display\n"); } /* Test TTF fonts and bitmap fonts. */ font_ttf = al_load_font("data/DejaVuSans.ttf", 24, 0); if (!font_ttf) { abort_example("Failed to load data/DejaVuSans.ttf\n"); } font_bmp = al_load_font("data/font.tga", 0, 0); if (!font_bmp) { abort_example("Failed to load data/font.tga\n"); } font_bin = al_create_builtin_font(); font = font_ttf; font_gui = al_load_font("data/DejaVuSans.ttf", 14, 0); if (!font_gui) { abort_example("Failed to load data/DejaVuSans.ttf\n"); } timer = al_create_timer(1.0 / 60); al_start_timer(timer); /* Don't remove these braces. */ { Theme theme(font_gui); Prog prog(theme, display); prog.run(); } al_destroy_font(font_bmp); al_destroy_font(font_ttf); al_destroy_font(font_bin); al_destroy_font(font_gui); al_destroy_timer(timer); return 0; } /* Helper struct for draw_custom_multiline. */ typedef struct DRAW_CUSTOM_LINE_EXTRA { const ALLEGRO_FONT *font; float x; float y; int tick; float line_height; int flags; } DRAW_CUSTOM_LINE_EXTRA; /* This function is the helper callback that implements the actual drawing * for draw_custom_multiline. */ static bool draw_custom_multiline_cb(int line_num, const char *line, int size, void *extra) { DRAW_CUSTOM_LINE_EXTRA *s = (DRAW_CUSTOM_LINE_EXTRA *) extra; float x, y; ALLEGRO_USTR_INFO info; ALLEGRO_COLOR c = al_color_hsv(fmod(360.0 * (float)line_num / 5.0 + s->tick, 360.0), 1.0, 1.0); x = s->x + 10 + sin(line_num + s->tick * 0.05) * 10; y = s->y + (s->line_height * line_num); al_draw_ustr(s->font, c, x, y, 0, al_ref_buffer(&info, line, size)); return (line_num < 5); } /* This is a custom mult line output function that demonstrates * al_do_multiline_text. */ static void draw_custom_multiline(ALLEGRO_FONT * font, int x, int y, int max_width, int line_height, int tick, const char * text) { DRAW_CUSTOM_LINE_EXTRA extra; extra.font = font; extra.x = x; extra.y = y; extra.line_height = line_height + al_get_font_line_height(font); extra.tick = tick; al_do_multiline_text(font, max_width, text, draw_custom_multiline_cb, (void *)&extra); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_fs_resize.c000066400000000000000000000072101473414355200201270ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include #include #include "common.c" #define NUM_RESOLUTIONS 4 static struct { int w, h; } res[NUM_RESOLUTIONS] = { { 640, 480 }, { 800, 600 }, { 1024, 768 }, { 1280, 1024 } }; static int cur_res = 0; static void redraw(ALLEGRO_BITMAP *picture) { ALLEGRO_COLOR color; ALLEGRO_BITMAP *target = al_get_target_bitmap(); int w = al_get_bitmap_width(target); int h = al_get_bitmap_height(target); color = al_map_rgb( 128 + rand() % 128, 128 + rand() % 128, 128 + rand() % 128); al_clear_to_color(color); color = al_map_rgb(255, 0, 0); al_draw_line(0, 0, w, h, color, 0); al_draw_line(0, h, w, 0, color, 0); al_draw_bitmap(picture, 0, 0, 0); al_flip_display(); } static void main_loop(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *picture) { ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; bool can_draw; int new_res; queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); can_draw = true; while (1) { if (al_is_event_queue_empty(queue) && can_draw) { redraw(picture); } al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_LOST) { log_printf("Display lost\n"); can_draw = false; continue; } if (event.type == ALLEGRO_EVENT_DISPLAY_FOUND) { log_printf("Display found\n"); can_draw = true; continue; } if (event.type != ALLEGRO_EVENT_KEY_CHAR) { continue; } if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } new_res = cur_res; if (event.keyboard.unichar == '+' || event.keyboard.unichar == ' ' || event.keyboard.keycode == ALLEGRO_KEY_ENTER) { new_res++; if (new_res >= NUM_RESOLUTIONS) new_res = 0; } else if (event.keyboard.unichar == '-') { new_res--; if (new_res < 0) new_res = NUM_RESOLUTIONS - 1; } if (new_res != cur_res) { cur_res = new_res; log_printf("Switching to %dx%d... ", res[cur_res].w, res[cur_res].h); if (al_resize_display(display, res[cur_res].w, res[cur_res].h)) { log_printf("Succeeded.\n"); } else { log_printf("Failed. current resolution: %dx%d\n", al_get_display_width(display), al_get_display_height(display)); } } } al_destroy_event_queue(queue); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *picture; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_install_keyboard(); al_init_image_addon(); init_platform_specific(); open_log_monospace(); if (argc == 2) { al_set_new_display_adapter(atoi(argv[1])); } al_set_new_display_flags(ALLEGRO_FULLSCREEN | ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(res[cur_res].w, res[cur_res].h); if (!display) { abort_example("Error creating display\n"); } picture = al_load_bitmap("data/mysha.pcx"); if (!picture) { abort_example("mysha.pcx not found\n"); } main_loop(display, picture); al_destroy_bitmap(picture); /* Destroying the fullscreen display restores the original screen * resolution. Shutting down Allegro would automatically destroy the * display, too. */ al_destroy_display(display); return 0; } allegro5-5.2.10.1/examples/ex_fs_window.c000066400000000000000000000066111473414355200201410ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include #include #include "common.c" static ALLEGRO_DISPLAY *display; static ALLEGRO_BITMAP *picture; static ALLEGRO_EVENT_QUEUE *queue; static ALLEGRO_FONT *font; static bool big; static void redraw(void) { ALLEGRO_COLOR color; int w = al_get_display_width(display); int h = al_get_display_height(display); int pw = al_get_bitmap_width(picture); int ph = al_get_bitmap_height(picture); int th = al_get_font_line_height(font); float cx = (w - pw) * 0.5; float cy = (h - ph) * 0.5; ALLEGRO_COLOR white = al_map_rgb_f(1, 1, 1); color = al_map_rgb_f(0.8, 0.7, 0.9); al_clear_to_color(color); color = al_map_rgb(255, 0, 0); al_draw_line(0, 0, w, h, color, 0); al_draw_line(0, h, w, 0, color, 0); al_draw_bitmap(picture, cx, cy, 0); al_draw_textf(font, white, w / 2, cy + ph, ALLEGRO_ALIGN_CENTRE, "Press Space to toggle fullscreen"); al_draw_textf(font, white, w / 2, cy + ph + th, ALLEGRO_ALIGN_CENTRE, "Press Enter to toggle window size"); al_draw_textf(font, white, w / 2, cy + ph + th * 2, ALLEGRO_ALIGN_CENTRE, "Window: %dx%d (%s)", al_get_display_width(display), al_get_display_height(display), (al_get_display_flags(display) & ALLEGRO_FULLSCREEN_WINDOW) ? "fullscreen" : "not fullscreen"); al_flip_display(); } static void run(void) { ALLEGRO_EVENT event; bool quit = false; while (!quit) { while (al_get_next_event(queue, &event)) { if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) quit = true; else if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) quit = true; else if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) { bool opp = !(al_get_display_flags(display) & ALLEGRO_FULLSCREEN_WINDOW); al_set_display_flag(display, ALLEGRO_FULLSCREEN_WINDOW, opp); redraw(); } else if (event.keyboard.keycode == ALLEGRO_KEY_ENTER) { big = !big; if (big) al_resize_display(display, 800, 600); else al_resize_display(display, 640, 480); redraw(); } } } /* FIXME: Lazy timing */ al_rest(0.02); redraw(); } } int main(int argc, char **argv) { (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_install_keyboard(); al_init_image_addon(); al_init_font_addon(); init_platform_specific(); al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); picture = al_load_bitmap("data/mysha.pcx"); if (!picture) { abort_example("mysha.pcx not found\n"); } font = al_load_font("data/fixed_font.tga", 0, 0); if (!font) { abort_example("data/fixed_font.tga not found.\n"); } redraw(); run(); al_destroy_display(display); al_destroy_event_queue(queue); return 0; } allegro5-5.2.10.1/examples/ex_get_path.c000066400000000000000000000031061473414355200177310ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "common.c" static void show_path(int id, const char *label) { ALLEGRO_PATH *path; const char *path_str; path = al_get_standard_path(id); path_str = (path) ? al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP) : ""; log_printf("%s: %s\n", label, path_str); al_destroy_path(path); } int main(int argc, char **argv) { int pass; (void)argc; (void)argv; /* defaults to blank */ al_set_org_name("liballeg.org"); /* defaults to the exename, set it here to remove the .exe on windows */ al_set_app_name("ex_get_path"); if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); for (pass = 1; pass <= 3; pass++) { if (pass == 1) { log_printf("With default exe name:\n"); } else if (pass == 2) { log_printf("\nOverriding exe name to blahblah\n"); al_set_exe_name("blahblah"); } else if (pass == 3) { log_printf("\nOverriding exe name to /tmp/blahblah.exe:\n"); al_set_exe_name("/tmp/blahblah.exe"); } show_path(ALLEGRO_RESOURCES_PATH, "RESOURCES_PATH"); show_path(ALLEGRO_TEMP_PATH, "TEMP_PATH"); show_path(ALLEGRO_USER_DATA_PATH, "USER_DATA_PATH"); show_path(ALLEGRO_USER_SETTINGS_PATH, "USER_SETTINGS_PATH"); show_path(ALLEGRO_USER_HOME_PATH, "USER_HOME_PATH"); show_path(ALLEGRO_USER_DOCUMENTS_PATH, "USER_DOCUMENTS_PATH"); show_path(ALLEGRO_EXENAME_PATH, "EXENAME_PATH"); } close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_gldepth.c000066400000000000000000000141541473414355200175720ustar00rootroot00000000000000/* An example program showing how to set and use a depth buffer with an OpenGL * display. Use arrow keys to rotate, PgUp/PgDown to move closer/farther away. */ #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_opengl.h" #include "allegro5/allegro_font.h" #include "common.c" struct camera { double xangle, yangle, zangle; double dist; }; struct camera camera = { 0.0, 0.0, 0.0, 20.0 }; double angle_speed = 5.0; double dist_speed = 1.0; GLuint tex; ALLEGRO_BITMAP *bmp; bool key[ALLEGRO_KEY_MAX]; static void set_camera_position(void) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 40.0); glTranslatef(0, 0, -camera.dist); glRotatef(camera.xangle, 1, 0, 0); glRotatef(camera.yangle, 0, 1, 0); glRotatef(camera.zangle, 0, 0, 1); glMatrixMode(GL_MODELVIEW); } static void keyboard(void) { if(key[ALLEGRO_KEY_LEFT]) camera.yangle += angle_speed; if(key[ALLEGRO_KEY_RIGHT]) camera.yangle -= angle_speed; if(key[ALLEGRO_KEY_UP]) camera.xangle += angle_speed; if(key[ALLEGRO_KEY_DOWN]) camera.xangle -= angle_speed; if(key[ALLEGRO_KEY_PGUP]) camera.dist -= dist_speed; if(key[ALLEGRO_KEY_PGDN]) camera.dist += dist_speed; } static void draw(void) { // Clear the RGB buffer and the depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Set the modelview matrix to be the identity matrix glLoadIdentity(); // Translate and rotate the object glTranslatef(-2.5, 0.0, 0.0); glRotatef(-30, 1.0, 0.0, 0.0); glRotatef(30, 0.0, 1.0, 0.0); glRotatef(30, 0.0, 0.0, 1.0); glColor3f(1.0, 0.0, 1.0); // Draw the sides of the three-sided pyramid glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3d(0, 4, 0); glTexCoord2f(1, 0); glVertex3d(0, -4, -4); glTexCoord2f(1, 1); glVertex3d(-4, -4, 4); glTexCoord2f(0, 1); glVertex3d(4, -4, 4); glTexCoord2f(1, 0); glVertex3d(0, -4, -4); glEnd(); glColor3f(0.0, 1.0, 1.0); // Draw the base of the pyramid glBegin(GL_TRIANGLES); glTexCoord2f(1, 0); glVertex3d(0, -4, -4); glTexCoord2f(0, 1); glVertex3d(4, -4, 4); glTexCoord2f(1, 1); glVertex3d(-4, -4, 4); glEnd(); glLoadIdentity(); glTranslatef(2.5, 0.0, 0.0); glRotatef(45, 1.0, 0.0, 0.0); glRotatef(45, 0.0, 1.0, 0.0); glRotatef(45, 0.0, 0.0, 1.0); glColor3f(0.0, 1.0, 0.0); glDisable(GL_TEXTURE_2D); // Draw the sides of the cube glBegin(GL_QUAD_STRIP); glVertex3d(3, 3, -3); glVertex3d(3, -3, -3); glVertex3d(-3, 3, -3); glVertex3d(-3, -3, -3); glVertex3d(-3, 3, 3); glVertex3d(-3, -3, 3); glVertex3d(3, 3, 3); glVertex3d(3, -3, 3); glVertex3d(3, 3, -3); glVertex3d(3, -3, -3); glEnd(); glColor3f(0.0, 0.0, 1.0); // Draw the top of the cube glBegin(GL_QUADS); glVertex3d(-3, -3, -3); glVertex3d(3, -3, -3); glVertex3d(3, -3, 3); glVertex3d(-3, -3, 3); glEnd(); /* Bottom is texture-mapped */ glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3d(-3, 3, -3); glTexCoord2f(1, 0); glVertex3d(-3, 3, 3); glTexCoord2f(1, 1); glVertex3d(3, 3, 3); glTexCoord2f(0, 1); glVertex3d(3, 3, -3); glEnd(); } static void setup_textures(ALLEGRO_DISPLAY *display) { ALLEGRO_BITMAP *tmp_bmp; ALLEGRO_FONT *font; int w, h, depth; font = al_load_font("data/fixed_font.tga", 0, 0); if(!font) { abort_example("Error loading `data/fixed_font.tga'\n"); } tmp_bmp = al_load_bitmap("data/mysha.pcx"); if(!tmp_bmp) { abort_example("Error loading `data/mysha.pcx'\n"); } w = 128; h = 128; bmp = al_create_bitmap(w, h); al_set_target_bitmap(bmp); al_draw_scaled_bitmap(tmp_bmp, 0, 0, al_get_bitmap_width(bmp), al_get_bitmap_height(bmp), 0, 0, w, h, 0); depth = al_get_display_option(display, ALLEGRO_DEPTH_SIZE); if (!depth) al_draw_textf(font, al_map_rgb(255, 0, 0), 0, 5, 0, "No Z-buffer!"); else al_draw_textf(font, al_map_rgb(255, 0, 0), 0, 5, 0, "Z-buffer: %i bits", depth); al_set_target_backbuffer(display); al_destroy_bitmap(tmp_bmp); al_destroy_font(font); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); tex = al_get_opengl_texture(bmp); } int main(void) { ALLEGRO_DISPLAY *display; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_TIMER *timer; ALLEGRO_EVENT event; if(!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_image_addon(); al_init_font_addon(); al_install_keyboard(); al_set_new_display_flags(ALLEGRO_OPENGL); al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 16, ALLEGRO_SUGGEST); display = al_create_display(640, 480); if(!display) { abort_example("Could not create display.\n"); } timer = al_create_timer(1. / 60.); queue = al_create_event_queue(); al_register_event_source(queue,al_get_keyboard_event_source()); al_register_event_source(queue,al_get_display_event_source(display)); al_register_event_source(queue,al_get_timer_event_source(timer)); glEnable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); setup_textures(display); al_start_timer(timer); while(true) { al_wait_for_event(queue, &event); switch(event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: goto done; case ALLEGRO_EVENT_KEY_DOWN: if(event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) goto done; key[event.keyboard.keycode] = true; break; case ALLEGRO_EVENT_KEY_UP: key[event.keyboard.keycode] = false; break; case ALLEGRO_EVENT_TIMER: keyboard(); if(al_is_event_queue_empty(queue)) { set_camera_position(); draw(); al_flip_display(); } break; } } done: al_destroy_bitmap(bmp); return 0; } allegro5-5.2.10.1/examples/ex_glext.c000066400000000000000000000226611473414355200172700ustar00rootroot00000000000000/* This examples demonstrates how to use the extension mechanism. * Taken from AllegroGL. */ #define ALLEGRO_UNSTABLE #include #include #include #include #include #include "common.c" #ifdef __APPLE__ #include #else #include #endif #define WINDOW_W 640 #define WINDOW_H 480 #define MESH_SIZE 64 GLfloat mesh[MESH_SIZE][MESH_SIZE][3]; GLfloat wave_movement = 0.0f; /* Define our vertex program. * It basically does: * pos = vertex.position; * pos.y = (sin(wave.x + pos.x / 5) + sin(wave.x + pos.z / 4)) * 2.5; * result.position = modelview * projection * pos; */ /* Plain ARBvp doesn't have a SIN opcode, so we provide one, built on a taylor * expansion, with some fugding. * * First, we convert the operand to the [-pi..+pi] period by: * - Dividing by 2pi, adding 1/2 * - Taking the fraction of the result * - Multiplying by 2pi, then subtracting pi. * x' = frac((x / 2pi) + 0.5) * 2pi - pi * * Then, we compute the sine using a 7th order Taylor series centered at 0: * x' = x - x^3/3! + x^5/5! - x^7/7! * * Note that we begin by multiplying x by 0.98 as a fugding factor to * compensate for the fact that our Taylor series is just an approximation. * The error is then reduced to < 0.5% from the ideal sine function. */ #define SIN(d, s, t) \ /* Convert to [-pi..+pi] period */ \ "MAD "d", "s", one_over_pi, 0.5;\n" \ "FRC "d","d";\n" \ "MAD "d","d", two_pi, -pi;\n" \ "MUL "d","d", 0.98;\n" /* Scale input to compensate for prec error */\ /* Compute SIN(d), using a Taylor series */ \ "MUL "t".x, "d", "d";\n" /* x^2 */ \ "MUL "t".y, "t".x, "d";\n" /* x^3 */ \ "MUL "t".z, "t".y, "t".x;\n" /* x^5 */ \ "MUL "t".w, "t".z, "t".x;\n" /* x^7 */ \ "MAD "d", "t".y,-inv_3_fact, "d";\n" /* x - x^3/3! */ \ "MAD "d", "t".z, inv_5_fact, "d";\n" /* x - x^3/3! + x^5/5! */ \ "MAD "d", "t".w,-inv_7_fact, "d";\n" /* x - x^3/3! + x^5/5! - x^7/7!*/ /* This is the actual vertex program. * It computes sin(wave.x + pos.x / 5) and sin(wave.x + pos.z), adds them up, * scales the result by 2.5 and stores that as the vertex's y component. * * Then, it does the modelview-projection transform on the vertex. * * XXX Broken ATI drivers need a \n after each "line" */ const char *program = "!!ARBvp1.0\n" "ATTRIB pos = vertex.position;\n" "ATTRIB wave = vertex.attrib[1];\n" "PARAM modelview[4] = { state.matrix.mvp };\n" "PARAM one_over_pi = 0.1591549;\n" "PARAM pi = 3.1415926;\n" "PARAM two_pi = 6.2831853;\n" "PARAM inv_3_fact = 0.1666666;\n" "PARAM inv_5_fact = 0.00833333333;\n" "PARAM inv_7_fact = 0.00019841269841269;\n" "TEMP temp, temp2;\n" /* temp.y = sin(wave.x + pos.x / 5) */ "MAD temp.y, pos.x, 0.2, wave.x;\n" SIN("temp.y", "temp.y", "temp2") /* temp.y += sin(wave.x + pos.z / 4) */ "MAD temp.x, pos.z, 0.25, wave.x;\n" SIN("temp.x", "temp.x", "temp2") "ADD temp.y, temp.x, temp.y;\n" /* pos.y = temp.y * 2.5 */ "MOV temp2, pos;\n" "MUL temp2.y, temp.y, 2.5;\n" /* Transform the position by the modelview matrix */ "DP4 result.position.w, temp2, modelview[3];\n" "DP4 result.position.x, temp2, modelview[0];\n" "DP4 result.position.y, temp2, modelview[1];\n" "DP4 result.position.z, temp2, modelview[2];\n" "MOV result.color, vertex.color;\n" "END"; /* NVIDIA drivers do a better job; let's use a simpler program if we can. */ const char *program_nv = "!!ARBvp1.0" "OPTION NV_vertex_program2;" "ATTRIB wave = vertex.attrib[1];" "PARAM modelview[4] = { state.matrix.mvp };" "TEMP temp;" "TEMP pos;" "MOV pos, vertex.position;" /* temp.x = sin(wave.x + pos.x / 5) */ /* temp.z = sin(wave.x + pos.z / 4) */ "MAD temp.xz, pos, {0.2, 1.0, 0.25, 1.0}, wave.x;" "SIN temp.x, temp.x;" "SIN temp.z, temp.z;" /* temp.y = temp.x + temp.z */ "ADD temp.y, temp.x, temp.z;" /* pos.y = temp.y * 2.5 */ "MUL pos.y, temp.y, 2.5;" /* Transform the position by the modelview matrix */ "DP4 result.position.w, pos, modelview[3];" "DP4 result.position.x, pos, modelview[0];" "DP4 result.position.y, pos, modelview[1];" "DP4 result.position.z, pos, modelview[2];" "MOV result.color, vertex.color;" "END"; static void create_mesh(void) { int x, z; /* Create our mesh */ for (x = 0; x < MESH_SIZE; x++) { for (z = 0; z < MESH_SIZE; z++) { mesh[x][z][0] = (float) (MESH_SIZE / 2) - x; mesh[x][z][1] = 0.0f; mesh[x][z][2] = (float) (MESH_SIZE / 2) - z; } } } static void draw_mesh(void) { int x, z; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor4f(0.5f, 1.0f, 0.5f, 1.0f); for (x = 0; x < MESH_SIZE - 1; x++) { glBegin(GL_TRIANGLE_STRIP); for (z = 0; z < MESH_SIZE - 1; z++) { glVertexAttrib1fARB(1, wave_movement); glVertex3fv(&mesh[x][z][0]); glVertex3fv(&mesh[x+1][z][0]); wave_movement += 0.00001f; if (wave_movement > 2 * ALLEGRO_PI) { wave_movement = 0.0f; } } glEnd(); } glFlush(); } int main(int argc, const char *argv[]) { GLuint pid; ALLEGRO_DISPLAY *d; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; ALLEGRO_TIMER *timer; int frames = 0; double start; bool limited = true; if (argc > 1 && 0 == strcmp(argv[1], "-nolimit")) { limited = false; } if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); al_set_new_display_flags(ALLEGRO_OPENGL); al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST); al_set_new_display_option(ALLEGRO_SAMPLES, 4, ALLEGRO_SUGGEST); d = al_create_display(WINDOW_W, WINDOW_H); if (!d) { abort_example("Unable to open a OpenGL display.\n"); } if (al_get_display_option(d, ALLEGRO_SAMPLE_BUFFERS)) { log_printf("With multisampling, level %i\n", al_get_display_option(d, ALLEGRO_SAMPLES)); } else { log_printf("Without multisampling.\n"); } al_install_keyboard(); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(d)); if (limited) { timer = al_create_timer(1/60.0); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); } else { timer = NULL; } if (al_get_opengl_extension_list()->ALLEGRO_GL_ARB_multisample) { glEnable(GL_MULTISAMPLE_ARB); } if (!al_get_opengl_extension_list()->ALLEGRO_GL_ARB_vertex_program) { abort_example("This example requires a video card that supports " " the ARB_vertex_program extension.\n"); } glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glDisable(GL_CULL_FACE); /* Setup projection and modelview matrices */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, WINDOW_W/(float)WINDOW_H, 0.1, 100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* Position the camera to look at our mesh from a distance */ gluLookAt(0.0f, 20.0f, -45.0f, 0.0f, 0.0f, 0.0f, 0, 1, 0); create_mesh(); /* Define the vertex program */ glEnable(GL_VERTEX_PROGRAM_ARB); glGenProgramsARB(1, &pid); glBindProgramARB(GL_VERTEX_PROGRAM_ARB, pid); glGetError(); if (al_get_opengl_extension_list()->ALLEGRO_GL_NV_vertex_program2_option) { glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(program_nv), program_nv); } else { glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(program), program); } /* Check for errors */ if (glGetError()) { const char *pgm = al_get_opengl_extension_list()->ALLEGRO_GL_NV_vertex_program2_option ? program_nv : program; GLint error_pos; const GLubyte *error_str = glGetString(GL_PROGRAM_ERROR_STRING_ARB); glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos); abort_example("Error compiling the vertex program:\n%s\n\nat " "character: %i\n%s\n", error_str, (int)error_pos, pgm + error_pos); } start = al_get_time(); while (1) { if (limited) { al_wait_for_event(queue, NULL); } if (!al_is_event_queue_empty(queue)) { while (al_get_next_event(queue, &event)) { switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: goto done; case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) goto done; break; } } } draw_mesh(); al_flip_display(); frames++; } done: log_printf("%.1f FPS\n", frames / (al_get_time() - start)); glDeleteProgramsARB(1, &pid); al_destroy_event_queue(queue); al_destroy_display(d); close_log(true); return 0; } allegro5-5.2.10.1/examples/ex_haiku.c000066400000000000000000000642021473414355200172430ustar00rootroot00000000000000/* * Haiku - A Musical Instrument, by Mark Oates. * * Allegro example version by Peter Wang. * * It demonstrates use of the audio functions, and other things besides. */ /* This version leaves out some things from Mark's original version: * the nice title sequence, text labels and mouse cursors. */ #define ALLEGRO_UNSTABLE #include #include #include #include #include "common.c" const float PI = ALLEGRO_PI; const float TWOPI = ALLEGRO_PI * 2.0; enum { TYPE_EARTH, TYPE_WIND, TYPE_WATER, TYPE_FIRE, NUM_TYPES, TYPE_NONE = NUM_TYPES }; enum { IMG_EARTH = TYPE_EARTH, IMG_WIND = TYPE_WIND, IMG_WATER = TYPE_WATER, IMG_FIRE = TYPE_FIRE, IMG_BLACK, IMG_DROPSHADOW, IMG_GLOW, IMG_GLOW_OVERLAY, IMG_AIR_EFFECT, IMG_WATER_DROPS, IMG_FLAME, IMG_MAIN_FLAME, IMG_MAX }; typedef enum { INTERP_LINEAR, INTERP_FAST, INTERP_DOUBLE_FAST, INTERP_SLOW, INTERP_DOUBLE_SLOW, INTERP_SLOW_IN_OUT, INTERP_BOUNCE } Interp; typedef struct Anim Anim; typedef struct Token Token; typedef struct Flair Flair; typedef struct Sprite Sprite; #define MAX_ANIMS 10 struct Anim { float *lval; /* NULL if unused */ float start_val; float end_val; Interp func; float start_time; float end_time; }; struct Sprite { unsigned image; /* IMG_ */ float x, scale_x, align_x; float y, scale_y, align_y; float angle; float r, g, b; float opacity; Anim anims[MAX_ANIMS]; /* keep it simple */ }; struct Token { unsigned type; /* TYPE_ */ float x; float y; int pitch; /* [0, NUM_PITCH) */ Sprite bot; Sprite top; }; struct Flair { Flair *next; float end_time; Sprite sprite; }; /****************************************************************************/ /* Globals */ /****************************************************************************/ enum { NUM_PITCH = 8, TOKENS_X = 16, TOKENS_Y = NUM_PITCH, NUM_TOKENS = TOKENS_X * TOKENS_Y, }; ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *refresh_timer; ALLEGRO_TIMER *playback_timer; ALLEGRO_BITMAP *images[IMG_MAX]; ALLEGRO_SAMPLE *element_samples[NUM_TYPES][NUM_PITCH]; ALLEGRO_SAMPLE *select_sample; Token tokens[NUM_TOKENS]; Token buttons[NUM_TYPES]; Sprite glow; Sprite glow_overlay; ALLEGRO_COLOR glow_color[NUM_TYPES]; Flair *flairs = NULL; Token *hover_token = NULL; Token *selected_button = NULL; int playback_column = 0; const int screen_w = 1024; const int screen_h = 600; const float game_board_x = 100.0; const float token_size = 64; const float token_scale = 0.8; const float button_size = 64; const float button_unsel_scale = 0.8; const float button_sel_scale = 1.1; const float dropshadow_unsel_scale = 0.6; const float dropshadow_sel_scale = 0.9; const float refresh_rate = 60.0; const float playback_period = 2.7333; #define HAIKU_DATA "data/haiku/" /****************************************************************************/ /* Init */ /****************************************************************************/ static void load_images(void) { int i; images[IMG_EARTH] = al_load_bitmap(HAIKU_DATA "earth4.png"); images[IMG_WIND] = al_load_bitmap(HAIKU_DATA "wind3.png"); images[IMG_WATER] = al_load_bitmap(HAIKU_DATA "water.png"); images[IMG_FIRE] = al_load_bitmap(HAIKU_DATA "fire.png"); images[IMG_BLACK] = al_load_bitmap(HAIKU_DATA "black_bead_opaque_A.png"); images[IMG_DROPSHADOW] = al_load_bitmap(HAIKU_DATA "dropshadow.png"); images[IMG_AIR_EFFECT] = al_load_bitmap(HAIKU_DATA "air_effect.png"); images[IMG_WATER_DROPS] = al_load_bitmap(HAIKU_DATA "water_droplets.png"); images[IMG_FLAME] = al_load_bitmap(HAIKU_DATA "flame2.png"); images[IMG_MAIN_FLAME] = al_load_bitmap(HAIKU_DATA "main_flame2.png"); images[IMG_GLOW] = al_load_bitmap(HAIKU_DATA "healthy_glow.png"); images[IMG_GLOW_OVERLAY]= al_load_bitmap(HAIKU_DATA "overlay_pretty.png"); for (i = 0; i < IMG_MAX; i++) { if (images[i] == NULL) abort_example("Error loading image.\n"); } } static void load_samples(void) { const char *base[NUM_TYPES] = {"earth", "air", "water", "fire"}; char name[128]; int t, p; for (t = 0; t < NUM_TYPES; t++) { for (p = 0; p < NUM_PITCH; p++) { sprintf(name, HAIKU_DATA "%s_%d.ogg", base[t], p); element_samples[t][p] = al_load_sample(name); if (!element_samples[t][p]) abort_example("Error loading %s.\n", name); } } select_sample = al_load_sample(HAIKU_DATA "select.ogg"); if (!select_sample) abort_example("Error loading select.ogg.\n"); } static void init_sprite(Sprite *spr, int image, float x, float y, float scale, float opacity) { int i; spr->image = image; spr->x = x; spr->y = y; spr->scale_x = spr->scale_y = scale; spr->align_x = spr->align_y = 0.5; spr->angle = 0.0; spr->r = spr->g = spr->b = 1.0; spr->opacity = opacity; for (i = 0; i < MAX_ANIMS; i++) spr->anims[i].lval = NULL; } static void init_tokens(void) { const float token_w = token_size * token_scale; const float token_x = game_board_x + token_w/2.0; const float token_y = 80; int i; for (i = 0; i < NUM_TOKENS; i++) { int tx = i % TOKENS_X; int ty = i / TOKENS_X; float px = token_x + tx * token_w; float py = token_y + ty * token_w; tokens[i].type = TYPE_NONE; tokens[i].x = px; tokens[i].y = py; tokens[i].pitch = NUM_PITCH - 1 - ty; assert(tokens[i].pitch >= 0 && tokens[i].pitch < NUM_PITCH); init_sprite(&tokens[i].bot, IMG_BLACK, px, py, token_scale, 0.4); init_sprite(&tokens[i].top, IMG_BLACK, px, py, token_scale, 0.0); } } static void init_buttons(void) { const float dist[NUM_TYPES] = {-1.5, -0.5, 0.5, 1.5}; int i; for (i = 0; i < NUM_TYPES; i++) { float x = screen_w/2 + 150 * dist[i]; float y = screen_h - 80; buttons[i].type = i; buttons[i].x = x; buttons[i].y = y; init_sprite(&buttons[i].bot, IMG_DROPSHADOW, x, y, dropshadow_unsel_scale, 0.4); buttons[i].bot.align_y = 0.0; init_sprite(&buttons[i].top, i, x, y, button_unsel_scale, 1.0); } } static void init_glow(void) { init_sprite(&glow, IMG_GLOW, screen_w/2, screen_h, 1.0, 1.0); glow.align_y = 1.0; glow.r = glow.g = glow.b = 0.0; init_sprite(&glow_overlay, IMG_GLOW_OVERLAY, 0.0, 0.0, 1.0, 1.0); glow_overlay.align_x = 0.0; glow_overlay.align_y = 0.0; glow_overlay.r = glow_overlay.g = glow_overlay.b = 0.0; glow_color[TYPE_EARTH] = al_map_rgb(0x6b, 0x8e, 0x23); /* olivedrab */ glow_color[TYPE_WIND] = al_map_rgb(0xad, 0xd8, 0xe6); /* lightblue */ glow_color[TYPE_WATER] = al_map_rgb(0x41, 0x69, 0xe1); /* royalblue */ glow_color[TYPE_FIRE] = al_map_rgb(0xff, 0x00, 0x00); /* red */ } /****************************************************************************/ /* Flairs */ /****************************************************************************/ static Sprite *make_flair(int image, float x, float y, float end_time) { Flair *fl = malloc(sizeof *fl); init_sprite(&fl->sprite, image, x, y, 1.0, 1.0); fl->end_time = end_time; fl->next = flairs; flairs = fl; return &fl->sprite; } static void free_old_flairs(float now) { Flair *prev, *fl, *next; prev = NULL; for (fl = flairs; fl != NULL; fl = next) { next = fl->next; if (fl->end_time > now) prev = fl; else { if (prev) prev->next = next; else flairs = next; free(fl); } } } static void free_all_flairs(void) { Flair *next; for (; flairs != NULL; flairs = next) { next = flairs->next; free(flairs); } } /****************************************************************************/ /* Animations */ /****************************************************************************/ static Anim *get_next_anim(Sprite *spr) { static Anim dummy_anim; unsigned i; for (i = 0; i < MAX_ANIMS; i++) { if (spr->anims[i].lval == NULL) return &spr->anims[i]; } assert(false); return &dummy_anim; } static void fix_conflicting_anims(Sprite *grp, float *lval, float start_time, float start_val) { unsigned i; for (i = 0; i < MAX_ANIMS; i++) { Anim *anim = &grp->anims[i]; if (anim->lval != lval) continue; /* If an old animation would overlap with the new one, truncate it * and make it converge to the new animation's starting value. */ if (anim->end_time > start_time) { anim->end_time = start_time; anim->end_val = start_val; } /* Cancel any old animations which are scheduled to start after the * new one, or which have been reduced to nothing. */ if (anim->start_time >= start_time || anim->start_time >= anim->end_time) { grp->anims[i].lval = NULL; } } } static void anim_full(Sprite *spr, float *lval, float start_val, float end_val, Interp func, float delay, float duration) { float start_time; Anim *anim; start_time = al_get_time() + delay; fix_conflicting_anims(spr, lval, start_time, start_val); anim = get_next_anim(spr); anim->lval = lval; anim->start_val = start_val; anim->end_val = end_val; anim->func = func; anim->start_time = start_time; anim->end_time = start_time + duration; } static void anim(Sprite *spr, float *lval, float start_val, float end_val, Interp func, float duration) { anim_full(spr, lval, start_val, end_val, func, 0.0, duration); } static void anim_to(Sprite *spr, float *lval, float end_val, Interp func, float duration) { anim_full(spr, lval, *lval, end_val, func, 0.0, duration); } static void anim_delta(Sprite *spr, float *lval, float delta, Interp func, float duration) { anim_full(spr, lval, *lval, *lval + delta, func, 0.0, duration); } static void anim_tint(Sprite *spr, const ALLEGRO_COLOR color, Interp func, float duration) { float r, g, b; al_unmap_rgb_f(color, &r, &g, &b); anim_to(spr, &spr->r, r, func, duration); anim_to(spr, &spr->g, g, func, duration); anim_to(spr, &spr->b, b, func, duration); } static float interpolate(Interp func, float t) { switch (func) { case INTERP_LINEAR: return t; case INTERP_FAST: return -t*(t-2); case INTERP_DOUBLE_FAST: t--; return t*t*t + 1; case INTERP_SLOW: return t*t; case INTERP_DOUBLE_SLOW: return t*t*t; case INTERP_SLOW_IN_OUT: { // Quadratic easing in/out - acceleration until halfway, then deceleration float b = 0; float c = 1; float d = 1; t /= d/2; if (t < 1) { return c/2 * t * t + b; } else { t--; return -c/2 * (t*(t-2) - 1) + b; } } case INTERP_BOUNCE: { // BOUNCE EASING: exponentially decaying parabolic bounce // t: current time, b: beginning value, c: change in position, d: duration // bounce easing out if (t < (1/2.75)) return (7.5625*t*t); if (t < (2/2.75)) { t -= (1.5/2.75); return (7.5625*t*t + 0.75); } if (t < (2.5/2.75)) { t -= (2.25/2.75); return (7.5625*t*t + 0.9375); } t -= (2.625/2.75); return (7.5625*t*t + 0.984375); } default: assert(false); return 0.0; } } static void update_anim(Anim *anim, float now) { float dt, t, range; if (!anim->lval) return; if (now < anim->start_time) return; dt = now - anim->start_time; t = dt / (anim->end_time - anim->start_time); if (t >= 1.0) { /* animation has run to completion */ *anim->lval = anim->end_val; anim->lval = NULL; return; } range = anim->end_val - anim->start_val; *anim->lval = anim->start_val + interpolate(anim->func, t) * range; } static void update_sprite_anims(Sprite *spr, float now) { int i; for (i = 0; i < MAX_ANIMS; i++) update_anim(&spr->anims[i], now); } static void update_token_anims(Token *token, float now) { update_sprite_anims(&token->bot, now); update_sprite_anims(&token->top, now); } static void update_anims(float now) { Flair *fl; int i; for (i = 0; i < NUM_TOKENS; i++) update_token_anims(&tokens[i], now); for (i = 0; i < NUM_TYPES; i++) update_token_anims(&buttons[i], now); update_sprite_anims(&glow, now); update_sprite_anims(&glow_overlay, now); for (fl = flairs; fl != NULL; fl = fl->next) update_sprite_anims(&fl->sprite, now); } /****************************************************************************/ /* Drawing */ /****************************************************************************/ static void draw_sprite(const Sprite *spr) { ALLEGRO_BITMAP *bmp; ALLEGRO_COLOR tint; float cx, cy; bmp = images[spr->image]; cx = spr->align_x * al_get_bitmap_width(bmp); cy = spr->align_y * al_get_bitmap_height(bmp); tint = al_map_rgba_f(spr->r, spr->g, spr->b, spr->opacity); al_draw_tinted_scaled_rotated_bitmap(bmp, tint, cx, cy, spr->x, spr->y, spr->scale_x, spr->scale_y, spr->angle, 0); } static void draw_token(const Token *token) { draw_sprite(&token->bot); draw_sprite(&token->top); } static void draw_screen(void) { Flair *fl; int i; al_clear_to_color(al_map_rgb(0, 0, 0)); al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_ONE); draw_sprite(&glow); draw_sprite(&glow_overlay); for (i = 0; i < NUM_TOKENS; i++) draw_token(&tokens[i]); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); for (i = 0; i < NUM_TYPES; i++) draw_token(&buttons[i]); al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_ONE); for (fl = flairs; fl != NULL; fl = fl->next) draw_sprite(&fl->sprite); al_flip_display(); } /****************************************************************************/ /* Playback */ /****************************************************************************/ static void spawn_wind_effects(float x, float y) { const float now = al_get_time(); Sprite *spr; spr = make_flair(IMG_AIR_EFFECT, x, y, now + 1.0); anim(spr, &spr->scale_x, 0.9, 1.3, INTERP_FAST, 1.0); anim(spr, &spr->scale_y, 0.9, 1.3, INTERP_FAST, 1.0); anim(spr, &spr->opacity, 1.0, 0.0, INTERP_FAST, 1.0); spr = make_flair(IMG_AIR_EFFECT, x, y, now + 1.2); anim(spr, &spr->opacity, 1.0, 0.0, INTERP_LINEAR, 1.2); anim(spr, &spr->scale_x, 1.1, 1.5, INTERP_FAST, 1.2); anim(spr, &spr->scale_y, 1.1, 0.5, INTERP_FAST, 1.2); anim_delta(spr, &spr->x, 10.0, INTERP_FAST, 1.2); } static void spawn_fire_effects(float x, float y) { const float now = al_get_time(); Sprite *spr; int i; spr = make_flair(IMG_MAIN_FLAME, x, y, now + 0.8); spr->align_y = 0.75; anim_full(spr, &spr->scale_x, 0.2, 1.3, INTERP_BOUNCE, 0.0, 0.4); anim_full(spr, &spr->scale_y, 0.2, 1.3, INTERP_BOUNCE, 0.0, 0.4); anim_full(spr, &spr->scale_x, 1.3, 1.4, INTERP_BOUNCE, 0.4, 0.5); anim_full(spr, &spr->scale_y, 1.3, 1.4, INTERP_BOUNCE, 0.4, 0.5); anim_full(spr, &spr->opacity, 1.0, 0.0, INTERP_FAST, 0.3, 0.5); for (i = 0; i < 3; i++) { spr = make_flair(IMG_FLAME, x, y, now + 0.7); spr->align_x = 1.3; spr->angle = TWOPI / 3 * i; anim_delta(spr, &spr->angle, -PI, INTERP_DOUBLE_FAST, 0.7); anim(spr, &spr->opacity, 1.0, 0.0, INTERP_SLOW, 0.7); anim(spr, &spr->scale_x, 0.2, 1.0, INTERP_FAST, 0.7); anim(spr, &spr->scale_y, 0.2, 1.0, INTERP_FAST, 0.7); } } static float random_sign(void) { return (rand() % 2) ? -1.0 : 1.0; } static float random_float(float min, float max) { return ((float) rand()/RAND_MAX)*(max-min) + min; } static void spawn_water_effects(float x, float y) { #define RAND(a, b) (random_float((a), (b))) #define MRAND(a, b) (random_float((a), (b)) * max_duration) #define SIGN (random_sign()) float now = al_get_time(); float max_duration = 1.0; Sprite *spr; int i; spr = make_flair(IMG_WATER, x, y, now + max_duration); anim(spr, &spr->scale_x, 1.0, 2.0, INTERP_FAST, 0.5); anim(spr, &spr->scale_y, 1.0, 2.0, INTERP_FAST, 0.5); anim(spr, &spr->opacity, 0.5, 0.0, INTERP_FAST, 0.5); for (i = 0; i < 9; i++) { spr = make_flair(IMG_WATER_DROPS, x, y, now + max_duration); spr->scale_x = RAND(0.3, 1.2) * SIGN; spr->scale_y = RAND(0.3, 1.2) * SIGN; spr->angle = RAND(0.0, TWOPI); spr->r = RAND(0.0, 0.6); spr->g = RAND(0.4, 0.6); spr->b = 1.0; if (i == 0) { anim_to(spr, &spr->opacity, 0.0, INTERP_LINEAR, max_duration); } else { anim_to(spr, &spr->opacity, 0.0, INTERP_DOUBLE_SLOW, MRAND(0.7, 1.0)); } anim_to(spr, &spr->scale_x, RAND(0.8, 3.0), INTERP_FAST, MRAND(0.7, 1.0)); anim_to(spr, &spr->scale_y, RAND(0.8, 3.0), INTERP_FAST, MRAND(0.7, 1.0)); anim_delta(spr, &spr->x, MRAND(0, 20.0)*SIGN, INTERP_FAST, MRAND(0.7, 1.0)); anim_delta(spr, &spr->y, MRAND(0, 20.0)*SIGN, INTERP_FAST, MRAND(0.7, 1.0)); } #undef RAND #undef MRAND #undef SIGN } static void play_element(int type, int pitch, float vol, float pan) { al_play_sample(element_samples[type][pitch], vol, pan, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL); } static void activate_token(Token *token) { const float sc = token_scale; Sprite *spr = &token->top; switch (token->type) { case TYPE_EARTH: play_element(TYPE_EARTH, token->pitch, 0.8, 0.0); anim(spr, &spr->scale_x, spr->scale_x+0.4, spr->scale_x, INTERP_FAST, 0.3); anim(spr, &spr->scale_y, spr->scale_y+0.4, spr->scale_y, INTERP_FAST, 0.3); break; case TYPE_WIND: play_element(TYPE_WIND, token->pitch, 0.8, 0.0); anim_full(spr, &spr->scale_x, sc*1.0, sc*0.8, INTERP_SLOW_IN_OUT, 0.0, 0.5); anim_full(spr, &spr->scale_x, sc*0.8, sc*1.0, INTERP_SLOW_IN_OUT, 0.5, 0.8); anim_full(spr, &spr->scale_y, sc*1.0, sc*0.8, INTERP_SLOW_IN_OUT, 0.0, 0.5); anim_full(spr, &spr->scale_y, sc*0.8, sc*1.0, INTERP_SLOW_IN_OUT, 0.5, 0.8); spawn_wind_effects(spr->x, spr->y); break; case TYPE_WATER: play_element(TYPE_WATER, token->pitch, 0.7, 0.5); anim_full(spr, &spr->scale_x, sc*1.3, sc*0.8, INTERP_BOUNCE, 0.0, 0.5); anim_full(spr, &spr->scale_x, sc*0.8, sc*1.0, INTERP_BOUNCE, 0.5, 0.5); anim_full(spr, &spr->scale_y, sc*0.8, sc*1.3, INTERP_BOUNCE, 0.0, 0.5); anim_full(spr, &spr->scale_y, sc*1.3, sc*1.0, INTERP_BOUNCE, 0.5, 0.5); spawn_water_effects(spr->x, spr->y); break; case TYPE_FIRE: play_element(TYPE_FIRE, token->pitch, 0.8, 0.0); anim(spr, &spr->scale_x, sc*1.3, sc, INTERP_SLOW_IN_OUT, 1.0); anim(spr, &spr->scale_y, sc*1.3, sc, INTERP_SLOW_IN_OUT, 1.0); spawn_fire_effects(spr->x, spr->y); break; } } static void update_playback(void) { int y; for (y = 0; y < TOKENS_Y; y++) activate_token(&tokens[y * TOKENS_X + playback_column]); if (++playback_column >= TOKENS_X) playback_column = 0; } /****************************************************************************/ /* Control */ /****************************************************************************/ static bool is_touched(Token *token, float size, float x, float y) { float half = size/2.0; return (token->x - half <= x && x < token->x + half && token->y - half <= y && y < token->y + half); } static Token *get_touched_token(float x, float y) { int i; for (i = 0; i < NUM_TOKENS; i++) { if (is_touched(&tokens[i], token_size, x, y)) return &tokens[i]; } return NULL; } static Token *get_touched_button(float x, float y) { int i; for (i = 0; i < NUM_TYPES; i++) { if (is_touched(&buttons[i], button_size, x, y)) return &buttons[i]; } return NULL; } static void unselect_token(Token *token) { if (token->type != TYPE_NONE) { Sprite *spr = &token->top; anim_full(spr, &spr->opacity, spr->opacity, 0.0, INTERP_SLOW, 0.15, 0.15); token->type = TYPE_NONE; } } static void unselect_all_tokens(void) { int i; for (i = 0; i < NUM_TOKENS; i++) unselect_token(&tokens[i]); } static void select_token(Token *token) { unsigned prev_type; if (!selected_button) return; prev_type = token->type; unselect_token(token); /* Unselect only if same type, for touch input. */ if (prev_type != selected_button->type) { Sprite *spr = &token->top; spr->image = selected_button->type; anim_to(spr, &spr->opacity, 1.0, INTERP_FAST, 0.15); token->type = selected_button->type; } } static void change_healthy_glow(int type, float x) { anim_tint(&glow, glow_color[type], INTERP_SLOW_IN_OUT, 3.0); anim_to(&glow, &glow.x, x, INTERP_SLOW_IN_OUT, 3.0); anim_tint(&glow_overlay, glow_color[type], INTERP_SLOW_IN_OUT, 4.0); anim_to(&glow_overlay, &glow_overlay.opacity, 1.0, INTERP_SLOW_IN_OUT, 4.0); } static void select_button(Token *button) { Sprite *spr; if (button == selected_button) return; if (selected_button) { spr = &selected_button->top; anim_to(spr, &spr->scale_x, button_unsel_scale, INTERP_SLOW, 0.3); anim_to(spr, &spr->scale_y, button_unsel_scale, INTERP_SLOW, 0.3); anim_to(spr, &spr->opacity, 0.5, INTERP_DOUBLE_SLOW, 0.2); spr = &selected_button->bot; anim_to(spr, &spr->scale_x, dropshadow_unsel_scale, INTERP_SLOW, 0.3); anim_to(spr, &spr->scale_y, dropshadow_unsel_scale, INTERP_SLOW, 0.3); } selected_button = button; spr = &button->top; anim_to(spr, &spr->scale_x, button_sel_scale, INTERP_FAST, 0.3); anim_to(spr, &spr->scale_y, button_sel_scale, INTERP_FAST, 0.3); anim_to(spr, &spr->opacity, 1.0, INTERP_FAST, 0.3); spr = &button->bot; anim_to(spr, &spr->scale_x, dropshadow_sel_scale, INTERP_FAST, 0.3); anim_to(spr, &spr->scale_y, dropshadow_sel_scale, INTERP_FAST, 0.3); change_healthy_glow(button->type, button->x); al_play_sample(select_sample, 1.0, 0.0, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL); } static void on_mouse_down(float x, float y, int mbut) { Token *token; Token *button; if (mbut == 1) { if ((token = get_touched_token(x, y))) select_token(token); else if ((button = get_touched_button(x, y))) select_button(button); } else if (mbut == 2) { if ((token = get_touched_token(x, y))) unselect_token(token); } } static void on_mouse_axes(float x, float y) { Token *token = get_touched_token(x, y); if (token == hover_token) return; if (hover_token) { Sprite *spr = &hover_token->bot; anim_to(spr, &spr->opacity, 0.4, INTERP_DOUBLE_SLOW, 0.2); } hover_token = token; if (hover_token) { Sprite *spr = &hover_token->bot; anim_to(spr, &spr->opacity, 0.7, INTERP_FAST, 0.2); } } static void main_loop(ALLEGRO_EVENT_QUEUE *queue) { ALLEGRO_EVENT event; bool redraw = true; for (;;) { if (redraw && al_is_event_queue_empty(queue)) { float now = al_get_time(); free_old_flairs(now); update_anims(now); draw_screen(); redraw = false; } al_wait_for_event(queue, &event); if (event.timer.source == refresh_timer) { redraw = true; continue; } if (event.timer.source == playback_timer) { update_playback(); continue; } if (event.type == ALLEGRO_EVENT_MOUSE_AXES) { on_mouse_axes(event.mouse.x, event.mouse.y); continue; } if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { on_mouse_down(event.mouse.x, event.mouse.y, event.mouse.button); continue; } if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; if (event.keyboard.keycode == ALLEGRO_KEY_C) unselect_all_tokens(); } } } int main(int argc, char **argv) { ALLEGRO_EVENT_QUEUE *queue; (void)argc; (void)argv; if (!al_init()) { abort_example("Error initialising Allegro.\n"); } if (!al_install_audio() || !al_reserve_samples(128)) { abort_example("Error initialising audio.\n"); } al_init_acodec_addon(); al_init_image_addon(); init_platform_specific(); al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); display = al_create_display(screen_w, screen_h); if (!display) { abort_example("Error creating display.\n"); } al_set_window_title(display, "Haiku - A Musical Instrument"); load_images(); load_samples(); init_tokens(); init_buttons(); init_glow(); select_button(&buttons[TYPE_EARTH]); al_install_keyboard(); al_install_mouse(); refresh_timer = al_create_timer(1.0 / refresh_rate); playback_timer = al_create_timer(playback_period / TOKENS_X); queue = al_create_event_queue(); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_timer_event_source(refresh_timer)); al_register_event_source(queue, al_get_timer_event_source(playback_timer)); if (al_is_touch_input_installed()) { al_register_event_source(queue, al_get_touch_input_mouse_emulation_event_source()); } al_start_timer(refresh_timer); al_start_timer(playback_timer); main_loop(queue); free_all_flairs(); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_haptic.c000066400000000000000000000061671473414355200174200ustar00rootroot00000000000000/* * Example program for the Allegro library, by Beoran. * * This program tests haptic effects. */ #define ALLEGRO_UNSTABLE #include #include #include "common.c" static void test_haptic_joystick(ALLEGRO_JOYSTICK *joy) { ALLEGRO_HAPTIC_EFFECT_ID id; ALLEGRO_HAPTIC *haptic; ALLEGRO_HAPTIC_EFFECT effect; const double intensity = 1.0; const double duration = 1.0; haptic = al_get_haptic_from_joystick(joy); if (!haptic) { log_printf("Could not get haptic device from joystick!"); return; } log_printf("Can play back %d haptic effects.\n", al_get_max_haptic_effects(haptic)); log_printf("Set gain to 0.8: %d.\n", al_set_haptic_gain(haptic, 0.8)); log_printf("Get gain: %lf.\n", al_get_haptic_gain(haptic)); log_printf("Capabilities: %d.\n", al_get_haptic_capabilities(haptic)); memset(&effect, 0, sizeof(effect)); effect.type = ALLEGRO_HAPTIC_RUMBLE; effect.data.rumble.strong_magnitude = intensity; effect.data.rumble.weak_magnitude = intensity; effect.replay.delay = 0.1; effect.replay.length = duration; log_printf("Upload effect: %d.\n", al_upload_haptic_effect(haptic, &effect, &id)); log_printf("Playing effect: %d.\n", al_play_haptic_effect(&id, 3)); do { al_rest(0.1); } while (al_is_haptic_effect_playing(&id)); log_printf("Set gain to 0.4: %d.\n", al_set_haptic_gain(haptic, 0.4)); log_printf("Get gain: %lf.\n", al_get_haptic_gain(haptic)); log_printf("Playing effect again: %d.\n", al_play_haptic_effect(&id, 5)); al_rest(2.0); log_printf("Stopping effect: %d.\n", al_stop_haptic_effect(&id)); do { al_rest(0.1); } while (al_is_haptic_effect_playing(&id)); log_printf("Release effect: %d.\n", al_release_haptic_effect(&id)); log_printf("Release haptic: %d.\n", al_release_haptic(haptic)); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; int num_joysticks; int i; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } display = al_create_display(640, 480); if (!display) { abort_example("al_create_display failed\n"); } if (!al_install_joystick()) { abort_example("al_install_joystick failed\n"); } if (!al_install_haptic()) { abort_example("al_install_haptic failed\n"); } open_log(); num_joysticks = al_get_num_joysticks(); log_printf("Found %d joysticks.\n", num_joysticks); for (i = 0; i < num_joysticks; i++) { ALLEGRO_JOYSTICK *joy = al_get_joystick(i); if (!joy) { continue; } if (al_is_joystick_haptic(joy)) { log_printf("Joystick %s supports force feedback.\n", al_get_joystick_name(joy)); test_haptic_joystick(joy); } else { log_printf("Joystick %s does not support force feedback.\n", al_get_joystick_name(joy)); } al_release_joystick(joy); } log_printf("\nAll done!\n"); close_log(true); return 0; } /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_haptic2.cpp000066400000000000000000000652671473414355200200500ustar00rootroot00000000000000/* * Example program for the Allegro library, by Beoran. * * Exhaustive haptics example. */ #include #define ALLEGRO_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_primitives.h" #include "allegro5/allegro_ttf.h" #include "nihgui.hpp" #include "common.c" struct Haptic { ALLEGRO_HAPTIC *haptic; ALLEGRO_HAPTIC_EFFECT effect; ALLEGRO_HAPTIC_EFFECT_ID id; const char *name; bool playing; }; #define EX_MAX_HAPTICS 8 static Haptic haptics[EX_MAX_HAPTICS]; static int num_haptics = 0; static ALLEGRO_EVENT_QUEUE * joystick_queue; static ALLEGRO_TIMER * update_timer = NULL; static void release_all_haptics() { for (int i = 0; i < num_haptics; i++) { al_release_haptic(haptics[i].haptic); haptics[i].haptic = NULL; } } static void get_all_haptics() { num_haptics = 0; ALLEGRO_DISPLAY * display = al_get_current_display(); if (al_is_display_haptic(display)) { haptics[num_haptics].haptic = al_get_haptic_from_display(display); if (haptics[num_haptics].haptic) { haptics[num_haptics].name = (const char *)"display"; haptics[num_haptics].playing = false; num_haptics++; } } for (int i = 0; num_haptics < EX_MAX_HAPTICS && i < al_get_num_joysticks(); i++) { ALLEGRO_JOYSTICK *joy = al_get_joystick(i); if (al_is_joystick_haptic(joy)) { haptics[num_haptics].haptic = al_get_haptic_from_joystick(joy); if (haptics[num_haptics].haptic) { const char *name = al_get_joystick_name(joy); haptics[num_haptics].name = (const char *)name; haptics[num_haptics].playing = false; num_haptics++; } } } } struct CapacityName { int value; const char *name; }; static const CapacityName capname[] = { {ALLEGRO_HAPTIC_RUMBLE, "ALLEGRO_HAPTIC_RUMBLE"}, {ALLEGRO_HAPTIC_PERIODIC, "ALLEGRO_HAPTIC_PERIODIC"}, {ALLEGRO_HAPTIC_CONSTANT, "ALLEGRO_HAPTIC_CONSTANT"}, {ALLEGRO_HAPTIC_SPRING, "ALLEGRO_HAPTIC_SPRING"}, {ALLEGRO_HAPTIC_FRICTION, "ALLEGRO_HAPTIC_FRICTION"}, {ALLEGRO_HAPTIC_DAMPER, "ALLEGRO_HAPTIC_DAMPER"}, {ALLEGRO_HAPTIC_INERTIA, "ALLEGRO_HAPTIC_INERTIA"}, {ALLEGRO_HAPTIC_RAMP, "ALLEGRO_HAPTIC_RAMP"}, {ALLEGRO_HAPTIC_SQUARE, "ALLEGRO_HAPTIC_SQUARE"}, {ALLEGRO_HAPTIC_TRIANGLE, "ALLEGRO_HAPTIC_TRIANGLE"}, {ALLEGRO_HAPTIC_SINE, "ALLEGRO_HAPTIC_SINE"}, {ALLEGRO_HAPTIC_SAW_UP, "ALLEGRO_HAPTIC_SAW_UP"}, {ALLEGRO_HAPTIC_SAW_DOWN, "ALLEGRO_HAPTIC_SAW_DOWN"}, {ALLEGRO_HAPTIC_CUSTOM, "ALLEGRO_HAPTIC_CUSTOM"}, {ALLEGRO_HAPTIC_GAIN, "ALLEGRO_HAPTIC_GAIN"}, {ALLEGRO_HAPTIC_ANGLE, "ALLEGRO_HAPTIC_ANGLE"}, {ALLEGRO_HAPTIC_RADIUS, "ALLEGRO_HAPTIC_RADIUS"}, {ALLEGRO_HAPTIC_AZIMUTH, "ALLEGRO_HAPTIC_AZIMUTH"} }; #define EX_START_TYPES 0 #define EX_MAX_TYPES 8 #define EX_END_TYPES 8 #define EX_START_WAVES 8 #define EX_END_WAVES 13 #define EX_MAX_WAVES 5 /* Ignore custom waveforms for now... */ #define EX_START_COORDS 15 #define EX_MAX_COORDS 3 #define EX_END_COORDS 18 class CanStopAndPlay { public: virtual void on_play() = 0; virtual void on_stop() = 0; }; class PlayButton: public Button { protected: CanStopAndPlay *stop_and_play; public: PlayButton(CanStopAndPlay *snp) : Button("Play"), stop_and_play(snp) { } void on_click(int mx, int my); }; void PlayButton::on_click(int, int) { if (is_disabled()) return; log_printf("Start playing...\n"); if (stop_and_play) { stop_and_play->on_play(); } } class StopButton: public Button { protected: CanStopAndPlay *stop_and_play; public: StopButton(CanStopAndPlay *snp) : Button("Stop"), stop_and_play(snp) { } void on_click(int mx, int my); }; void StopButton::on_click(int, int) { if (is_disabled()) return; log_printf("Stop playing...\n"); if (stop_and_play) { stop_and_play->on_stop(); } } class Prog: public CanStopAndPlay { private: Dialog d; List device_list; List type_list; List waveform_list; Label device_label; Label type_label; Label waveform_label; HSlider length_slider; HSlider delay_slider; HSlider loops_slider; Label replay_label; Label length_label; Label delay_label; Label loops_label; HSlider attack_length_slider; HSlider attack_level_slider; HSlider fade_length_slider; HSlider fade_level_slider; Label envelope_label; Label attack_length_label; Label attack_level_label; Label fade_length_label; Label fade_level_label; HSlider angle_slider; HSlider radius_slider; HSlider azimuth_slider; Label coordinates_label; Label angle_label; Label radius_label; Label azimuth_label; HSlider level_slider; Label constant_effect_label; Label level_label; HSlider start_level_slider; HSlider end_level_slider; Label ramp_effect_label; Label start_level_label; Label end_level_label; HSlider right_saturation_slider; HSlider right_coeff_slider; HSlider left_saturation_slider; HSlider left_coeff_slider; HSlider deadband_slider; HSlider center_slider; Label right_saturation_label; Label right_coeff_label; Label left_saturation_label; Label left_coeff_label; Label condition_effect_label; Label deadband_label; Label center_label; HSlider period_slider; HSlider magnitude_slider; HSlider offset_slider; HSlider phase_slider; Label periodic_effect_label; Label period_label; Label magnitude_label; Label offset_label; Label phase_label; HSlider strong_magnitude_slider; HSlider weak_magnitude_slider; Label rumble_effect_label; Label strong_magnitude_label; Label weak_magnitude_label; HSlider gain_slider; Label gain_label; HSlider autocenter_slider; Label autocenter_label; Label message_label; Label message_label_label; PlayButton play_button; StopButton stop_button; Haptic *last_haptic; Haptic *show_haptic; public: Prog(const Theme & theme, ALLEGRO_DISPLAY *display); void run(); void update(); void update_controls(Haptic *dev); virtual void on_play(); virtual void on_stop(); void get_envelope(ALLEGRO_HAPTIC_ENVELOPE *envelope); }; Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) : d(Dialog(theme, display, 20, 40)), device_list(0), type_list(0), waveform_list(0), device_label("Haptic Device"), type_label("Haptic Effect Type"), waveform_label("Wave Form Periodic Effect"), length_slider(1, 10), delay_slider(1, 10), loops_slider(1, 10), replay_label("Replay"), length_label("Length", false), delay_label("Delay", false), loops_label("Loops"), attack_length_slider(2, 10), attack_level_slider(4, 10), fade_length_slider(2, 10), fade_level_slider(4, 10), envelope_label("Envelope"), attack_length_label("Attack Length", false), attack_level_label("Attack Level", false), fade_length_label("Fade Length", false), fade_level_label("Fade Level", false), angle_slider(0, 360), radius_slider(0, 10), azimuth_slider(180, 360), coordinates_label("Coordinates"), angle_label("Angle", false), radius_label("Radius", false), azimuth_label("Azimuth", false), level_slider(5, 10), constant_effect_label("Constant Effect"), level_label("Level", false), start_level_slider(3, 10), end_level_slider(7, 10), ramp_effect_label("Ramp Effect"), start_level_label("Start Level", false), end_level_label("End Level", false), right_saturation_slider(5, 10), right_coeff_slider(5, 10), left_saturation_slider(5, 10), left_coeff_slider(5, 10), deadband_slider(1, 10), center_slider(5, 10), right_saturation_label("Right Saturation", false), right_coeff_label("Right Coefficient", false), left_saturation_label("Left Saturation", false), left_coeff_label("Left Coefficient", false), condition_effect_label("Condition Effect"), deadband_label("Deadband", false), center_label("Center", false), period_slider(1, 10), magnitude_slider(5, 10), offset_slider(0, 10), phase_slider(0, 10), periodic_effect_label("Periodic Effect"), period_label("Period", false), magnitude_label("Magnitude", false), offset_label("Offset", false), phase_label("Phase", false), strong_magnitude_slider(5, 10), weak_magnitude_slider(5, 10), rumble_effect_label("Rumble effect"), strong_magnitude_label("Strong Magnitude", false), weak_magnitude_label("Weak Magnitude", false), gain_slider(10, 10), gain_label("Gain"), autocenter_slider(0, 10), autocenter_label("Autocenter"), message_label("Ready.", false), message_label_label("Status", false), play_button(this), stop_button(this), last_haptic(NULL), show_haptic(NULL) { for (int i = 0; i < num_haptics; i++) { device_list.append_item(haptics[i].name); } d.add(device_label, 0, 1, 7, 1); d.add(device_list, 0, 2, 7, 8); for (int i = EX_START_TYPES; i < EX_END_TYPES; i++) { type_list.append_item(capname[i].name); } d.add(type_label, 7, 1, 6, 1); d.add(type_list, 7, 2, 6, 8); for (int i = EX_START_WAVES; i < EX_END_WAVES; i++) { waveform_list.append_item(capname[i].name); } d.add(waveform_label, 13, 1, 7, 1); d.add(waveform_list, 13, 2, 7, 8); d.add(replay_label, 0, 11, 7, 1); d.add(length_label, 0, 12, 2, 1); d.add(length_slider, 2, 12, 5, 1); d.add(delay_label, 0, 13, 2, 1); d.add(delay_slider, 2, 13, 5, 1); d.add(loops_label, 7, 11, 7, 1); d.add(loops_slider, 7, 12, 6, 1); d.add(gain_label, 13, 11, 7, 1); d.add(gain_slider, 13, 12, 7, 1); d.add(autocenter_label, 13, 13, 7, 1); d.add(autocenter_slider, 13, 14, 7, 1); d.add(envelope_label, 0, 15, 9, 1); d.add(attack_length_label, 0, 16, 3, 1); d.add(attack_length_slider, 4, 16, 6, 1); d.add(attack_level_label, 0, 17, 3, 1); d.add(attack_level_slider, 4, 17, 6, 1); d.add(fade_length_label, 0, 18, 3, 1); d.add(fade_length_slider, 4, 18, 6, 1); d.add(fade_level_label, 0, 19, 3, 1); d.add(fade_level_slider, 4, 19, 6, 1); d.add(coordinates_label, 11, 15, 9, 1); d.add(angle_label, 11, 16, 2, 1); d.add(angle_slider, 13, 16, 7, 1); d.add(radius_label, 11, 17, 2, 1); d.add(radius_slider, 13, 17, 7, 1); d.add(azimuth_label, 11, 18, 2, 1); d.add(azimuth_slider, 13, 18, 7, 1); d.add(condition_effect_label, 0, 21, 9, 1); d.add(right_coeff_label, 0, 22, 4, 1); d.add(right_coeff_slider, 4, 22, 6, 1); d.add(right_saturation_label, 0, 23, 4, 1); d.add(right_saturation_slider, 4, 23, 6, 1); d.add(left_coeff_label, 0, 24, 4, 1); d.add(left_coeff_slider, 4, 24, 6, 1); d.add(left_saturation_label, 0, 25, 4, 1); d.add(left_saturation_slider, 4, 25, 6, 1); d.add(deadband_label, 0, 26, 4, 1); d.add(deadband_slider, 4, 26, 6, 1); d.add(center_label, 0, 27, 4, 1); d.add(center_slider, 4, 27, 6, 1); d.add(periodic_effect_label, 11, 21, 9, 1); d.add(period_label, 11, 22, 2, 1); d.add(period_slider, 13, 22, 7, 1); d.add(magnitude_label, 11, 23, 2, 1); d.add(magnitude_slider, 13, 23, 7, 1); d.add(offset_label, 11, 24, 2, 1); d.add(offset_slider, 13, 24, 7, 1); d.add(phase_label, 11, 25, 2, 1); d.add(phase_slider, 13, 25, 7, 1); d.add(ramp_effect_label, 11, 29, 9, 1); d.add(start_level_label, 11, 30, 2, 1); d.add(start_level_slider, 13, 30, 7, 1); d.add(end_level_label, 11, 31, 2, 1); d.add(end_level_slider, 13, 31, 7, 1); d.add(rumble_effect_label, 0, 29, 9, 1); d.add(strong_magnitude_label, 0, 30, 4, 1); d.add(strong_magnitude_slider, 4, 30, 6, 1); d.add(weak_magnitude_label, 0, 31, 4, 1); d.add(weak_magnitude_slider, 4, 31, 6, 1); d.add(constant_effect_label, 0, 33, 9, 1); d.add(level_label, 0, 34, 3, 1); d.add(level_slider, 4, 34, 6, 1); d.add(message_label_label, 0, 36, 2, 1); d.add(message_label, 2, 36, 12, 1); d.add(play_button, 6, 38, 3, 2); d.add(stop_button, 12, 38, 3, 2); d.register_event_source(al_get_timer_event_source(update_timer)); } void Prog::update() { /* Update playing state and display. */ if (last_haptic && last_haptic->playing) { if (!al_is_haptic_effect_playing(&last_haptic->id)) { last_haptic->playing = false; al_release_haptic_effect(&last_haptic->id); message_label.set_text("Done."); play_button.set_disabled(false); d.request_draw(); log_printf("Play done on %s\n", last_haptic->name); } } ALLEGRO_EVENT e; /* Check for hot plugging*/ while(al_get_next_event(joystick_queue, &e)) { /* clear, reconfigure and fetch haptics again. */ if (e.type == ALLEGRO_EVENT_JOYSTICK_CONFIGURATION) { al_reconfigure_joysticks(); release_all_haptics(); get_all_haptics(); device_list.clear_items(); for (int i = 0; i < num_haptics; i++) { device_list.append_item(haptics[i].name); } log_printf("Hot plugging detected...\n"); message_label.set_text("Hot Plugging..."); play_button.set_disabled(false); d.request_draw(); } } /* Update availability of controls based on capabilities. */ int devno = device_list.get_cur_value(); Haptic *dev = haptics + devno; if (dev && dev->haptic) { if (dev != show_haptic) { play_button.set_disabled(false); update_controls(dev); show_haptic = dev; message_label.set_text("Haptic Device Found."); d.request_draw(); } } else { play_button.set_disabled(true); message_label.set_text("No Haptic Device."); d.request_draw(); } } void Prog::run() { d.prepare(); while (!d.is_quit_requested()) { update(); if (d.is_draw_requested()) { al_clear_to_color(al_map_rgb(128, 148, 168)); d.draw(); al_flip_display(); } d.run_step(true); } /* Stop playing anything we were still playing. */ on_stop(); } #define TEST_CAP(CAP, FLAG) (((CAP) & (FLAG)) == (FLAG)) void Prog::update_controls(Haptic *dev) { /* Take a deep breath, here we go... */ bool condition, envelope, periodic; int cap = 0; if (dev) { cap = al_get_haptic_capabilities(dev->haptic); } /* Gain capability */ gain_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_GAIN)); gain_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_GAIN)); /* Autocenter capability */ autocenter_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AUTOCENTER)); autocenter_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AUTOCENTER)); /* Envelope related capabilities and sliders. */ envelope = TEST_CAP(cap, ALLEGRO_HAPTIC_PERIODIC) || TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT) || TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP); envelope_label.set_disabled(!envelope); attack_level_slider.set_disabled(!envelope); attack_length_slider.set_disabled(!envelope); fade_level_slider.set_disabled(!envelope); fade_length_slider.set_disabled(!envelope); attack_level_label.set_disabled(!envelope); attack_length_label.set_disabled(!envelope); fade_level_label.set_disabled(!envelope); fade_length_label.set_disabled(!envelope); /* Coordinate related capabilities. */ angle_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_ANGLE)); angle_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_ANGLE)); radius_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RADIUS)); radius_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RADIUS)); azimuth_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AZIMUTH)); azimuth_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AZIMUTH)); /* Condition effect related capabilities. */ condition = TEST_CAP(cap, ALLEGRO_HAPTIC_DAMPER) || TEST_CAP(cap, ALLEGRO_HAPTIC_FRICTION) || TEST_CAP(cap, ALLEGRO_HAPTIC_INERTIA) || TEST_CAP(cap, ALLEGRO_HAPTIC_SPRING); condition_effect_label.set_disabled(!condition); right_coeff_slider.set_disabled(!condition); left_coeff_slider.set_disabled(!condition); right_saturation_slider.set_disabled(!condition); left_saturation_slider.set_disabled(!condition); center_slider.set_disabled(!condition); deadband_slider.set_disabled(!condition); right_coeff_label.set_disabled(!condition); left_coeff_label.set_disabled(!condition); right_saturation_label.set_disabled(!condition); left_saturation_label.set_disabled(!condition); center_label.set_disabled(!condition); deadband_label.set_disabled(!condition); /* Constant effect related capabilities. */ constant_effect_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT)); level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT)); level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT)); /* Ramp effect capabilities. */ ramp_effect_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP)); start_level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP)); start_level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP)); end_level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP)); end_level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP)); /* Period effect capabilities. */ periodic = TEST_CAP(cap, ALLEGRO_HAPTIC_PERIODIC); waveform_label.set_disabled(!periodic); waveform_list.set_disabled(!periodic); periodic_effect_label.set_disabled(!periodic); period_slider.set_disabled(!periodic); magnitude_slider.set_disabled(!periodic); offset_slider.set_disabled(!periodic); phase_slider.set_disabled(!periodic); period_label.set_disabled(!periodic); magnitude_label.set_disabled(!periodic); offset_label.set_disabled(!periodic); phase_label.set_disabled(!periodic); /* Change list of supported effect types. */ type_list.clear_items(); for (int i = EX_START_TYPES; i < EX_END_TYPES; i++) { const CapacityName *cn = &capname[i]; if (TEST_CAP(cap, cn->value)) { type_list.append_item(cn->name); } } /* Change list of supported wave form types. */ waveform_list.clear_items(); for (int i = EX_START_WAVES; i < EX_END_WAVES; i++) { const CapacityName *cn = &capname[i]; if (TEST_CAP(cap, cn->value)) { waveform_list.append_item(cn->name); } } } static int name_to_cap(const std::string & name) { for (int i = 0; i < EX_END_WAVES; i++) { if (name == capname[i].name) { return capname[i].value; } } return -1; } static const char *cap_to_name(int cap) { for (int i = 0; i < EX_END_WAVES; i++) { if (cap == capname[i].value) { return capname[i].name; } } return "unknown"; } static double slider_to_magnitude(const HSlider & slider) { double value = (double)slider.get_cur_value(); double max = (double)slider.get_max_value(); return value / max; } static double slider_to_duration(const HSlider & slider) { double value = (double)slider.get_cur_value(); double max = 1.0; return value / max; } static double slider_to_angle(const HSlider & slider) { double value = (double)slider.get_cur_value(); double max = (double)slider.get_max_value(); return value / max; } void Prog::get_envelope(ALLEGRO_HAPTIC_ENVELOPE *envelope) { if (!envelope) return; envelope->attack_length = slider_to_duration(attack_length_slider); envelope->fade_length = slider_to_duration(fade_length_slider); envelope->attack_level = slider_to_magnitude(attack_level_slider); envelope->fade_level = slider_to_magnitude(fade_level_slider); } void Prog::on_play() { int devno = device_list.get_cur_value(); if (devno < 0 || devno >= num_haptics) { message_label.set_text("No Haptic Device!"); log_printf("No such device: %d\n", devno); return; } Haptic *haptic = haptics + devno; if (!haptic || !haptic->haptic) { log_printf("Device is NULL: %d\n", devno); message_label.set_text("Device Is NULL!"); return; } if (!al_is_haptic_active(haptic->haptic)) { message_label.set_text("Device Not Active!"); log_printf("Device is not active: %d\n", devno); return; } /* Stop playing previous effect. */ if (haptic->playing) { al_stop_haptic_effect(&haptic->id); haptic->playing = false; al_release_haptic_effect(&haptic->id); } /* First set gain. */ double gain = slider_to_magnitude(gain_slider); al_set_haptic_gain(haptic->haptic, gain); /* Set autocentering. */ double autocenter = slider_to_magnitude(autocenter_slider); al_set_haptic_autocenter(haptic->haptic, autocenter); /* Now fill in the effect struct. */ int type = name_to_cap(type_list.get_selected_item_text()); int wavetype = name_to_cap(waveform_list.get_selected_item_text()); if (type < 0) { message_label.set_text("Unknown Effect Type!"); log_printf("Unknown effect type: %d on %s\n", type, haptic->name); return; } if ((wavetype < 0) && (type == ALLEGRO_HAPTIC_PERIODIC)) { message_label.set_text("Unknown Wave Form!"); log_printf("Unknown wave type: %d on %s\n", wavetype, haptic->name); return; } haptic->effect.type = type; haptic->effect.replay.delay = slider_to_duration(delay_slider); haptic->effect.replay.length = slider_to_duration(length_slider); int loops = loops_slider.get_cur_value(); haptic->effect.direction.angle = slider_to_angle(angle_slider); haptic->effect.direction.radius = slider_to_magnitude(angle_slider); haptic->effect.direction.azimuth = slider_to_angle(angle_slider); switch (type) { case ALLEGRO_HAPTIC_RUMBLE: haptic->effect.data.rumble.strong_magnitude = slider_to_magnitude(strong_magnitude_slider); haptic->effect.data.rumble.weak_magnitude = slider_to_magnitude(weak_magnitude_slider); break; case ALLEGRO_HAPTIC_PERIODIC: get_envelope(&haptic->effect.data.periodic.envelope); haptic->effect.data.periodic.waveform = wavetype; haptic->effect.data.periodic.magnitude = slider_to_magnitude(magnitude_slider); haptic->effect.data.periodic.period = slider_to_duration(period_slider); haptic->effect.data.periodic.offset = slider_to_duration(offset_slider); haptic->effect.data.periodic.phase = slider_to_duration(phase_slider); haptic->effect.data.periodic.custom_len = 0; haptic->effect.data.periodic.custom_data = NULL; break; case ALLEGRO_HAPTIC_CONSTANT: get_envelope(&haptic->effect.data.constant.envelope); haptic->effect.data.constant.level = slider_to_magnitude(level_slider); break; case ALLEGRO_HAPTIC_RAMP: get_envelope(&haptic->effect.data.ramp.envelope); haptic->effect.data.ramp.start_level = slider_to_magnitude(start_level_slider); haptic->effect.data.ramp.end_level = slider_to_magnitude(end_level_slider); break; case ALLEGRO_HAPTIC_SPRING: case ALLEGRO_HAPTIC_FRICTION: case ALLEGRO_HAPTIC_DAMPER: case ALLEGRO_HAPTIC_INERTIA: /* fall through. */ haptic->effect.data.condition.right_saturation = slider_to_magnitude(right_saturation_slider); haptic->effect.data.condition.left_saturation = slider_to_magnitude(left_saturation_slider); haptic->effect.data.condition.right_coeff = slider_to_magnitude(right_coeff_slider); haptic->effect.data.condition.left_coeff = slider_to_magnitude(left_coeff_slider); haptic->effect.data.condition.deadband = slider_to_magnitude(deadband_slider); haptic->effect.data.condition.center = slider_to_magnitude(center_slider); /* XXX need a different conversion function here, but I don't have a * controller that supports condition effects anyway... :p */ break; default: message_label.set_text("Unknown Effect Type!"); log_printf("Unknown effect type %d %d\n", devno, type); return; } if (!al_is_haptic_effect_ok(haptic->haptic, &haptic->effect)) { message_label.set_text("Effect Not Supported!"); log_printf("Playing of effect type %s on %s not supported\n", cap_to_name(type), haptic->name); return; } haptic->playing = al_upload_and_play_haptic_effect(haptic->haptic, &haptic->effect, &haptic->id, loops); if (haptic->playing) { message_label.set_text("Playing..."); log_printf("Started playing %d loops of effect type %s on %s\n", loops, cap_to_name(type), haptic->name); last_haptic = haptic; } else { message_label.set_text("Playing of effect failed!"); log_printf("Playing of effect type %s on %s failed\n", cap_to_name(type), haptic->name); } play_button.set_disabled(true); } void Prog::on_stop() { int devno = device_list.get_cur_value(); if (devno < 0 || devno >= num_haptics) { log_printf("No such device %d\n", devno); return; } Haptic *haptic = haptics + devno; if (haptic->playing && al_is_haptic_effect_playing(&haptic->id)) { al_stop_haptic_effect(&haptic->id); haptic->playing = false; al_release_haptic_effect(&haptic->id); log_printf("Stopped device %d: %s\n", devno, haptic->name); } message_label.set_text("Stopped."); play_button.set_disabled(false); } int main(int argc, char *argv[]) { ALLEGRO_DISPLAY *display; ALLEGRO_FONT *font; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro\n"); } al_init_primitives_addon(); al_install_keyboard(); al_install_mouse(); al_install_joystick(); if (!al_install_haptic()) { abort_example("Could not init haptics\n"); } al_init_font_addon(); al_init_ttf_addon(); al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(800, 600); if (!display) { abort_example("Unable to create display\n"); } open_log(); font = al_load_font("data/DejaVuSans.ttf", 11, 0); if (!font) { log_printf("Failed to load data/DejaVuSans.ttf\n"); font = al_create_builtin_font(); if (!font) { abort_example("Could not create builtin font.\n"); } } joystick_queue = al_create_event_queue(); if (!joystick_queue) { abort_example("Could not create joystick event queue font.\n"); } al_register_event_source(joystick_queue, al_get_joystick_event_source()); get_all_haptics(); /* Don't remove these braces. */ { /* Set up a timer so the display of playback state is polled regularly. */ update_timer = al_create_timer(1.0); Theme theme(font); Prog prog(theme, display); al_start_timer(update_timer); prog.run(); al_destroy_timer(update_timer); } release_all_haptics(); al_destroy_event_queue(joystick_queue); close_log(false); al_destroy_font(font); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_icon.c000066400000000000000000000036631473414355200170760ustar00rootroot00000000000000#include #include "allegro5/allegro_image.h" #include "common.c" int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *icon1; ALLEGRO_BITMAP *icon2; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_TIMER *timer; int i; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_init_image_addon(); init_platform_specific(); display = al_create_display(320, 200); if (!display) { abort_example("Error creating display\n"); } al_clear_to_color(al_map_rgb_f(0, 0, 0)); al_flip_display(); /* First icon: Read from file. */ icon1 = al_load_bitmap("data/icon.tga"); if (!icon1) { abort_example("icon.tga not found\n"); } /* Second icon: Create it. */ al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); icon2 = al_create_bitmap(16, 16); al_set_target_bitmap(icon2); for (i = 0; i < 256; i++) { int u = i % 16; int v = i / 16; al_put_pixel(u, v, al_map_rgb_f(u / 15.0, v / 15.0, 1)); } al_set_target_backbuffer(display); al_set_window_title(display, "Changing icon example"); timer = al_create_timer(0.5); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); for (;;) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } if (event.type == ALLEGRO_EVENT_TIMER) { al_set_display_icon(display, (event.timer.count & 1) ? icon2 : icon1); } } al_uninstall_system(); return 0; } allegro5-5.2.10.1/examples/ex_icon2.c000066400000000000000000000041701473414355200171520ustar00rootroot00000000000000/* * Example program for the Allegro library. * * Set multiple window icons, a big one and a small one. * The small would would be used for the task bar, * and the big one for the alt-tab popup, for example. */ #define ALLEGRO_UNSTABLE #include #include "allegro5/allegro_image.h" #ifdef ALLEGRO_UNIX #include #endif #include "common.c" #define NUM_ICONS 2 int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *icons[NUM_ICONS]; ALLEGRO_EVENT_QUEUE *queue; int u, v; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_init_image_addon(); init_platform_specific(); /* First icon 16x16: Read from file. */ icons[0] = al_load_bitmap("data/cursor.tga"); if (!icons[0]) { abort_example("icons.tga not found\n"); } #if defined(ALLEGRO_UNIX) && !defined(ALLEGRO_RASPBERRYPI) al_x_set_initial_icon(icons[0]); #endif display = al_create_display(320, 200); if (!display) { abort_example("Error creating display\n"); } al_clear_to_color(al_map_rgb_f(0, 0, 0)); al_flip_display(); /* Second icon 32x32: Create it. */ al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); icons[1] = al_create_bitmap(32, 32); al_set_target_bitmap(icons[1]); for (v = 0; v < 32; v++) { for (u = 0; u < 32; u++) { al_put_pixel(u, v, al_map_rgb_f(u / 31.0, v / 31.0, 1)); } } al_set_target_backbuffer(display); al_set_display_icons(display, NUM_ICONS, icons); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); for (;;) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } } al_uninstall_system(); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_inject_events.c000066400000000000000000000041311473414355200207750ustar00rootroot00000000000000/* * Ryan Roden-Corrent * Example that injects regular (non-user-type) allegro events into a queue. * This could be useful for 'faking' certain event sources. * For example, you could imitate joystick events without a * joystick. * * Based on the ex_user_events.c example. */ #include #include "allegro5/allegro.h" #include "common.c" int main(int argc, char **argv) { ALLEGRO_EVENT_SOURCE fake_src; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT fake_keydown_event, fake_joystick_event; ALLEGRO_EVENT event; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); /* register our 'fake' event source with the queue */ al_init_user_event_source(&fake_src); queue = al_create_event_queue(); al_register_event_source(queue, &fake_src); /* fake a joystick event */ fake_joystick_event.any.type = ALLEGRO_EVENT_JOYSTICK_AXIS; fake_joystick_event.joystick.stick = 1; fake_joystick_event.joystick.axis = 0; fake_joystick_event.joystick.pos = 0.5; al_emit_user_event(&fake_src, &fake_joystick_event, NULL); /* fake a keyboard event */ fake_keydown_event.any.type = ALLEGRO_EVENT_KEY_DOWN; fake_keydown_event.keyboard.keycode = ALLEGRO_KEY_ENTER; al_emit_user_event(&fake_src, &fake_keydown_event, NULL); /* poll for the events we injected */ while (!al_is_event_queue_empty(queue)) { al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_DOWN: ALLEGRO_ASSERT(event.user.source == &fake_src); log_printf("Got keydown: %d\n", event.keyboard.keycode); break; case ALLEGRO_EVENT_JOYSTICK_AXIS: ALLEGRO_ASSERT(event.user.source == &fake_src); log_printf("Got joystick axis: stick=%d axis=%d pos=%f\n", event.joystick.stick, event.joystick.axis, event.joystick.pos); break; } } al_destroy_user_event_source(&fake_src); al_destroy_event_queue(queue); log_printf("Done.\n"); close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_joystick_events.c000066400000000000000000000151331473414355200213640ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * * This program tests joystick events. */ #include #include #include #include "common.c" #define MAX_AXES 3 #define MAX_STICKS 16 #define MAX_BUTTONS 32 /* globals */ ALLEGRO_EVENT_QUEUE *event_queue; ALLEGRO_FONT *font; ALLEGRO_COLOR black; ALLEGRO_COLOR grey; ALLEGRO_COLOR white; int num_sticks = 0; int num_buttons = 0; int num_axes[MAX_STICKS] = { 0 }; float joys[MAX_STICKS][MAX_AXES] = {{ 0 }}; bool joys_buttons[MAX_BUTTONS] = { 0 }; static void setup_joystick_values(ALLEGRO_JOYSTICK *joy) { ALLEGRO_JOYSTICK_STATE jst; int i, j; if (joy == NULL) { num_sticks = 0; num_buttons = 0; return; } al_get_joystick_state(joy, &jst); num_sticks = al_get_joystick_num_sticks(joy); if (num_sticks > MAX_STICKS) num_sticks = MAX_STICKS; for (i = 0; i < num_sticks; i++) { num_axes[i] = al_get_joystick_num_axes(joy, i); for (j = 0; j < num_axes[i]; ++j) joys[i][j] = jst.stick[i].axis[j]; } num_buttons = al_get_joystick_num_buttons(joy); if (num_buttons > MAX_BUTTONS) { num_buttons = MAX_BUTTONS; } for (i = 0; i < num_buttons; i++) { joys_buttons[i] = (jst.button[i] >= 16384); } } static void draw_joystick_axes(ALLEGRO_JOYSTICK *joy, int cx, int cy, int stick) { const int size = 30; const int csize = 5; const int osize = size + csize; int zx = cx + osize + csize * 2; int x = cx + joys[stick][0] * size; int y = cy + joys[stick][1] * size; int z = cy + joys[stick][2] * size; int i; al_draw_filled_rectangle(cx-osize, cy-osize, cx+osize, cy+osize, grey); al_draw_rectangle(cx-osize+0.5, cy-osize+0.5, cx+osize-0.5, cy+osize-0.5, black, 0); al_draw_filled_rectangle(x-5, y-5, x+5, y+5, black); if (num_axes[stick] >= 3) { al_draw_filled_rectangle(zx-csize, cy-osize, zx+csize, cy+osize, grey); al_draw_rectangle(zx-csize+0.5f, cy-osize+0.5f, zx+csize-0.5f, cy+osize-0.5f, black, 0); al_draw_filled_rectangle(zx-5, z-5, zx+5, z+5, black); } if (joy) { al_draw_text(font, black, cx, cy + osize + 1, ALLEGRO_ALIGN_CENTRE, al_get_joystick_stick_name(joy, stick)); for (i = 0; i < num_axes[stick]; i++) { al_draw_text(font, black, cx, cy + osize + (1 + i) * 10, ALLEGRO_ALIGN_CENTRE, al_get_joystick_axis_name(joy, stick, i)); } } } static void draw_joystick_button(ALLEGRO_JOYSTICK *joy, int button, bool down) { ALLEGRO_BITMAP *bmp = al_get_target_bitmap(); int x = al_get_bitmap_width(bmp)/2-120 + (button % 8) * 30; int y = al_get_bitmap_height(bmp)-120 + (button / 8) * 30; ALLEGRO_COLOR fg; al_draw_filled_rectangle(x, y, x + 25, y + 25, grey); al_draw_rectangle(x+0.5, y+0.5, x + 24.5, y + 24.5, black, 0); if (down) { al_draw_filled_rectangle(x + 2, y + 2, x + 23, y + 23, black); fg = white; } else { fg = black; } if (joy) { const char *name = al_get_joystick_button_name(joy, button); if (strlen(name) < 4) { al_draw_text(font, fg, x + 13, y + 8, ALLEGRO_ALIGN_CENTRE, name); } } } static void draw_all(ALLEGRO_JOYSTICK *joy) { ALLEGRO_BITMAP *bmp = al_get_target_bitmap(); int width = al_get_bitmap_width(bmp); int height = al_get_bitmap_height(bmp); int i; al_clear_to_color(al_map_rgb(0xff, 0xff, 0xc0)); if (joy) { al_draw_textf(font, black, width / 2, 10, ALLEGRO_ALIGN_CENTRE, "Joystick: %s", al_get_joystick_name(joy)); } for (i = 0; i < num_sticks; i++) { int u = i%4; int v = i/4; int cx = (u + 0.5) * width/4; int cy = (v + 0.5) * height/6; draw_joystick_axes(joy, cx, cy, i); } for (i = 0; i < num_buttons; i++) { draw_joystick_button(joy, i, joys_buttons[i]); } al_flip_display(); } static void main_loop(void) { ALLEGRO_EVENT event; while (true) { if (al_is_event_queue_empty(event_queue)) draw_all(al_get_joystick(0)); al_wait_for_event(event_queue, &event); switch (event.type) { /* ALLEGRO_EVENT_JOYSTICK_AXIS - a joystick axis value changed. */ case ALLEGRO_EVENT_JOYSTICK_AXIS: if (event.joystick.stick < MAX_STICKS && event.joystick.axis < MAX_AXES) { joys[event.joystick.stick][event.joystick.axis] = event.joystick.pos; } break; /* ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN - a joystick button was pressed. */ case ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN: joys_buttons[event.joystick.button] = true; break; /* ALLEGRO_EVENT_JOYSTICK_BUTTON_UP - a joystick button was released. */ case ALLEGRO_EVENT_JOYSTICK_BUTTON_UP: joys_buttons[event.joystick.button] = false; break; case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) return; break; /* ALLEGRO_EVENT_DISPLAY_CLOSE - the window close button was pressed. */ case ALLEGRO_EVENT_DISPLAY_CLOSE: return; case ALLEGRO_EVENT_JOYSTICK_CONFIGURATION: al_reconfigure_joysticks(); setup_joystick_values(al_get_joystick(0)); break; /* We received an event of some type we don't know about. * Just ignore it. */ default: break; } } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_init_font_addon(); display = al_create_display(1024, 768); if (!display) { abort_example("al_create_display failed\n"); } al_install_keyboard(); black = al_map_rgb(0, 0, 0); grey = al_map_rgb(0xe0, 0xe0, 0xe0); white = al_map_rgb(255, 255, 255); font = al_create_builtin_font(); al_install_joystick(); event_queue = al_create_event_queue(); if (!event_queue) { abort_example("al_create_event_queue failed\n"); } if (al_get_keyboard_event_source()) { al_register_event_source(event_queue, al_get_keyboard_event_source()); } al_register_event_source(event_queue, al_get_display_event_source(display)); al_register_event_source(event_queue, al_get_joystick_event_source()); setup_joystick_values(al_get_joystick(0)); main_loop(); al_destroy_font(font); return 0; } /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_joystick_hotplugging.c000066400000000000000000000103671473414355200224130ustar00rootroot00000000000000#include #include #include #include "common.c" static void print_joystick_info(ALLEGRO_JOYSTICK *joy) { int i, n, a; if (!joy) return; log_printf("Joystick: '%s'\n", al_get_joystick_name(joy)); log_printf(" Buttons:"); n = al_get_joystick_num_buttons(joy); for (i = 0; i < n; i++) { log_printf(" '%s'", al_get_joystick_button_name(joy, i)); } log_printf("\n"); n = al_get_joystick_num_sticks(joy); for (i = 0; i < n; i++) { log_printf(" Stick %d: '%s'\n", i, al_get_joystick_stick_name(joy, i)); for (a = 0; a < al_get_joystick_num_axes(joy, i); a++) { log_printf(" Axis %d: '%s'\n", a, al_get_joystick_axis_name(joy, i, a)); } } } static void draw(ALLEGRO_JOYSTICK *curr_joy) { int x = 100; int y = 100; ALLEGRO_JOYSTICK_STATE joystate; int i; al_clear_to_color(al_map_rgb(0, 0, 0)); if (curr_joy) { al_get_joystick_state(curr_joy, &joystate); for (i = 0; i < al_get_joystick_num_sticks(curr_joy); i++) { al_draw_filled_circle( x+joystate.stick[i].axis[0]*20 + i * 80, y+joystate.stick[i].axis[1]*20, 20, al_map_rgb(255, 255, 255) ); } for (i = 0; i < al_get_joystick_num_buttons(curr_joy); i++) { if (joystate.button[i]) { al_draw_filled_circle( i*20+10, 400, 9, al_map_rgb(255, 255, 255) ); } } } al_flip_display(); } int main(int argc, char **argv) { int num_joysticks; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_JOYSTICK *curr_joy; ALLEGRO_DISPLAY *display; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } if (!al_install_joystick()) { abort_example("Could not init joysticks.\n"); } al_install_keyboard(); al_init_primitives_addon(); open_log(); display = al_create_display(640, 480); if (!display) { abort_example("Could not create display.\n"); } queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_joystick_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); num_joysticks = al_get_num_joysticks(); log_printf("Num joysticks: %d\n", num_joysticks); if (num_joysticks > 0) { curr_joy = al_get_joystick(0); print_joystick_info(curr_joy); } else { curr_joy = NULL; } draw(curr_joy); while (1) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } else if (event.type == ALLEGRO_EVENT_KEY_CHAR) { int n = event.keyboard.unichar - '0'; if (n >= 0 && n < num_joysticks) { curr_joy = al_get_joystick(n); log_printf("switching to joystick %d\n", n); print_joystick_info(curr_joy); } } else if (event.type == ALLEGRO_EVENT_JOYSTICK_CONFIGURATION) { al_reconfigure_joysticks(); num_joysticks = al_get_num_joysticks(); log_printf("after reconfiguration num joysticks = %d\n", num_joysticks); if (curr_joy) { log_printf("current joystick is: %s\n", al_get_joystick_active(curr_joy) ? "active" : "inactive"); } curr_joy = al_get_joystick(0); } else if (event.type == ALLEGRO_EVENT_JOYSTICK_AXIS) { log_printf("axis event from %p, stick %d, axis %d\n", event.joystick.id, event.joystick.stick, event.joystick.axis); } else if (event.type == ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN) { log_printf("button down event %d from %p\n", event.joystick.button, event.joystick.id); } else if (event.type == ALLEGRO_EVENT_JOYSTICK_BUTTON_UP) { log_printf("button up event %d from %p\n", event.joystick.button, event.joystick.id); } draw(curr_joy); } close_log(false); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_kcm_direct.c000066400000000000000000000054111473414355200202430ustar00rootroot00000000000000/* Shows the ability to play a sample without a mixer. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_acodec.h" #include "common.c" char *default_files[] = {NULL, "data/welcome.wav"}; int main(int argc, char **argv) { ALLEGRO_VOICE *voice; ALLEGRO_SAMPLE_INSTANCE *sample; int i; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); if (argc < 2) { log_printf("This example can be run from the command line.\nUsage: %s {audio_files}\n", argv[0]); argv = default_files; argc = 2; } al_init_acodec_addon(); if (!al_install_audio()) { abort_example("Could not init sound!\n"); } for (i = 1; i < argc; ++i) { ALLEGRO_SAMPLE *sample_data = NULL; const char *filename = argv[i]; ALLEGRO_CHANNEL_CONF chan; ALLEGRO_AUDIO_DEPTH depth; unsigned long freq; float sample_time = 0; /* Load the entire sound file from disk. */ sample_data = al_load_sample(filename); if (!sample_data) { log_printf("Could not load sample from '%s'!\n", filename); continue; } sample = al_create_sample_instance(NULL); if (!sample) { abort_example("al_create_sample failed.\n"); } if (!al_set_sample(sample, sample_data)) { log_printf("al_set_sample failed.\n"); continue; } depth = al_get_sample_instance_depth(sample); chan = al_get_sample_instance_channels(sample); freq = al_get_sample_instance_frequency(sample); log_printf("Loaded sample: %i-bit depth, %i channels, %li Hz\n", (depth < 8) ? (8+depth*8) : 0, (chan>>4)+(chan%0xF), freq); log_printf("Trying to create a voice with the same specs... "); voice = al_create_voice(freq, depth, chan); if (!voice) { abort_example("Could not create ALLEGRO_VOICE.\n"); } log_printf("done.\n"); if (!al_attach_sample_instance_to_voice(sample, voice)) { abort_example("al_attach_sample_instance_to_voice failed.\n"); } /* Play sample in looping mode. */ al_set_sample_instance_playmode(sample, ALLEGRO_PLAYMODE_LOOP); al_play_sample_instance(sample); sample_time = al_get_sample_instance_time(sample); log_printf("Playing '%s' (%.3f seconds) 3 times", filename, sample_time); al_rest(sample_time * 3); al_stop_sample_instance(sample); log_printf("\n"); /* Free the memory allocated. */ al_set_sample(sample, NULL); al_destroy_sample(sample_data); al_destroy_sample_instance(sample); al_destroy_voice(voice); } al_uninstall_audio(); close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_keyboard_events.c000066400000000000000000000100141473414355200213160ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * Updated by Ryan Dickie. * * This program tests keyboard events. */ #include #define ALLEGRO_UNSTABLE #include #include "common.c" #define WIDTH 640 #define HEIGHT 480 #define SIZE_LOG 50 /* globals */ ALLEGRO_EVENT_QUEUE *event_queue; ALLEGRO_DISPLAY *display; static void log_key(char const *how, int keycode, int unichar, int modifiers) { char multibyte[5] = {0, 0, 0, 0, 0}; const char* key_name; al_utf8_encode(multibyte, unichar <= 32 ? ' ' : unichar); key_name = al_keycode_to_name(keycode); log_printf("%-8s code=%03d, char='%s' (%4d), modifiers=%08x, [%s]\n", how, keycode, multibyte, unichar, modifiers, key_name); } /* main_loop: * The main loop of the program. Here we wait for events to come in from * any one of the event sources and react to each one accordingly. While * there are no events to react to the program sleeps and consumes very * little CPU time. See main() to see how the event sources and event queue * are set up. */ static void main_loop(void) { ALLEGRO_EVENT event; log_printf("Focus on the main window (black) and press keys to see events. "); log_printf("Escape quits.\n\n"); while (true) { /* Take the next event out of the event queue, and store it in `event'. */ al_wait_for_event(event_queue, &event); /* Check what type of event we got and act accordingly. ALLEGRO_EVENT * is a union type and interpretation of its contents is dependent on * the event type, which is given by the 'type' field. * * Each event also comes from an event source and has a timestamp. * These are accessible through the 'any.source' and 'any.timestamp' * fields respectively, e.g. 'event.any.timestamp' */ switch (event.type) { /* ALLEGRO_EVENT_KEY_DOWN - a keyboard key was pressed. */ case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { return; } log_key("KEY_DOWN", event.keyboard.keycode, 0, 0); break; /* ALLEGRO_EVENT_KEY_UP - a keyboard key was released. */ case ALLEGRO_EVENT_KEY_UP: log_key("KEY_UP", event.keyboard.keycode, 0, 0); break; /* ALLEGRO_EVENT_KEY_CHAR - a character was typed or repeated. */ case ALLEGRO_EVENT_KEY_CHAR: { char const *label = (event.keyboard.repeat ? "repeat" : "KEY_CHAR"); log_key(label, event.keyboard.keycode, event.keyboard.unichar, event.keyboard.modifiers); break; } /* ALLEGRO_EVENT_DISPLAY_CLOSE - the window close button was pressed. */ case ALLEGRO_EVENT_DISPLAY_CLOSE: return; case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT: al_clear_keyboard_state(event.display.source); log_printf("Cleared keyboard state\n"); break; /* We received an event of some type we don't know about. * Just ignore it. */ default: break; } } } int main(int argc, char **argv) { (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log_monospace(); display = al_create_display(WIDTH, HEIGHT); if (!display) { abort_example("al_create_display failed\n"); } al_clear_to_color(al_map_rgb_f(0, 0, 0)); al_flip_display(); if (!al_install_keyboard()) { abort_example("al_install_keyboard failed\n"); } event_queue = al_create_event_queue(); if (!event_queue) { abort_example("al_create_event_queue failed\n"); } al_register_event_source(event_queue, al_get_keyboard_event_source()); al_register_event_source(event_queue, al_get_display_event_source(display)); main_loop(); close_log(false); return 0; } /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_keyboard_focus.c000066400000000000000000000027761473414355200211510ustar00rootroot00000000000000/* * Example program for the Allegro library. * * This program tests if the ALLEGRO_KEYBOARD_STATE `display' field * is set correctly to the focused display. */ #include "allegro5/allegro.h" #include "common.c" static ALLEGRO_DISPLAY *display1; static ALLEGRO_DISPLAY *display2; static void redraw(ALLEGRO_COLOR color1, ALLEGRO_COLOR color2) { al_set_target_backbuffer(display1); al_clear_to_color(color1); al_flip_display(); al_set_target_backbuffer(display2); al_clear_to_color(color2); al_flip_display(); } int main(int argc, char **argv) { ALLEGRO_COLOR black; ALLEGRO_COLOR red; ALLEGRO_KEYBOARD_STATE kbdstate; (void)argc; (void)argv; if (!al_init()) { abort_example("Error initialising Allegro.\n"); } if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } display1 = al_create_display(300, 300); display2 = al_create_display(300, 300); if (!display1 || !display2) { abort_example("Error creating displays.\n"); } black = al_map_rgb(0, 0, 0); red = al_map_rgb(255, 0, 0); while (1) { al_get_keyboard_state(&kbdstate); if (al_key_down(&kbdstate, ALLEGRO_KEY_ESCAPE)) { break; } if (kbdstate.display == display1) { redraw(red, black); } else if (kbdstate.display == display2) { redraw(black, red); } else { redraw(black, black); } al_rest(0.1); } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_lines.c000066400000000000000000000100571473414355200172530ustar00rootroot00000000000000/* * This example exercises line drawing, and single buffer mode. */ #include #include "allegro5/allegro.h" #include #include "common.c" /* XXX the software line drawer currently doesn't perform clipping properly */ const int W = 640; const int H = 480; ALLEGRO_DISPLAY *display; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_COLOR black; ALLEGRO_COLOR white; ALLEGRO_COLOR background; ALLEGRO_BITMAP *dbuf; int last_x = -1; int last_y = -1; static void fade(void) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); al_draw_filled_rectangle(0, 0, W, H, al_map_rgba_f(0.5, 0.5, 0.6, 0.2)); } static void red_dot(int x, int y) { al_draw_filled_rectangle(x - 2, y - 2, x + 2, y + 2, al_map_rgb_f(1, 0, 0)); } static void draw_clip_rect(void) { al_draw_rectangle(100.5, 100.5, W - 100.5, H - 100.5, black, 0); } static void my_set_clip_rect(void) { al_set_clipping_rectangle(100, 100, W - 200, H - 200); } static void reset_clip_rect(void) { al_set_clipping_rectangle(0, 0, W, H); } static void flip(void) { al_set_target_backbuffer(display); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_draw_bitmap(dbuf, 0.0, 0.0, 0); al_flip_display(); } static void plonk(const int x, const int y, bool blend) { al_set_target_bitmap(dbuf); fade(); al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_ZERO); draw_clip_rect(); red_dot(x, y); if (last_x == -1 && last_y == -1) { last_x = x; last_y = y; } else { my_set_clip_rect(); if (blend) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); } al_draw_line(last_x, last_y, x, y, white, 0); last_x = last_y = -1; reset_clip_rect(); } flip(); } static void splat(const int x, const int y, bool blend) { double theta; al_set_target_bitmap(dbuf); fade(); al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_ZERO); draw_clip_rect(); red_dot(x, y); my_set_clip_rect(); if (blend) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); } for (theta = 0.0; theta < 2.0 * ALLEGRO_PI; theta += ALLEGRO_PI/16.0) { al_draw_line(x, y, x + 40.0 * cos(theta), y + 40.0 * sin(theta), white, 0); } reset_clip_rect(); flip(); } int main(int argc, char **argv) { ALLEGRO_EVENT event; ALLEGRO_KEYBOARD_STATE kst; bool blend; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_install_keyboard(); al_install_mouse(); display = al_create_display(W, H); if (!display) { abort_example("Error creating display\n"); } black = al_map_rgb_f(0.0, 0.0, 0.0); white = al_map_rgb_f(1.0, 1.0, 1.0); background = al_map_rgb_f(0.5, 0.5, 0.6); if (argc > 1 && 0 == strcmp(argv[1], "--memory-bitmap")) { al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); } dbuf = al_create_bitmap(W, H); if (!dbuf) { abort_example("Error creating double buffer\n"); } al_set_target_bitmap(dbuf); al_clear_to_color(background); draw_clip_rect(); flip(); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); while (true) { al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { al_get_keyboard_state(&kst); blend = al_key_down(&kst, ALLEGRO_KEY_LSHIFT) || al_key_down(&kst, ALLEGRO_KEY_RSHIFT); if (event.mouse.button == 1) { plonk(event.mouse.x, event.mouse.y, blend); } else { splat(event.mouse.x, event.mouse.y, blend); } } else if (event.type == ALLEGRO_EVENT_DISPLAY_SWITCH_OUT) { last_x = last_y = -1; } else if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } } al_destroy_event_queue(queue); al_destroy_bitmap(dbuf); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_loading_thread.c000066400000000000000000000145641473414355200211140ustar00rootroot00000000000000#include #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_primitives.h" #include "common.c" static const int load_total = 100; static int load_count = 0; static ALLEGRO_BITMAP *bitmaps[100]; static ALLEGRO_MUTEX *mutex; static void *loading_thread(ALLEGRO_THREAD *thread, void *arg) { ALLEGRO_FONT *font; ALLEGRO_COLOR text; font = al_load_font("data/fixed_font.tga", 0, 0); text = al_map_rgb_f(255, 255, 255); /* In this example we load mysha.pcx 100 times to simulate loading * many bitmaps. */ load_count = 0; while (load_count < load_total) { ALLEGRO_COLOR color; ALLEGRO_BITMAP *bmp; color = al_map_rgb(rand() % 256, rand() % 256, rand() % 256); color.r /= 4; color.g /= 4; color.b /= 4; color.a /= 4; if (al_get_thread_should_stop(thread)) break; bmp = al_load_bitmap("data/mysha.pcx"); /* Simulate different contents. */ al_set_target_bitmap(bmp); al_draw_filled_rectangle(0, 0, 320, 200, color); al_draw_textf(font, text, 0, 0, 0, "bitmap %d", 1 + load_count); al_set_target_bitmap(NULL); /* Allow the main thread to see the completed bitmap. */ al_lock_mutex(mutex); bitmaps[load_count] = bmp; load_count++; al_unlock_mutex(mutex); /* Simulate that it's slow. */ al_rest(0.05); } al_destroy_font(font); return arg; } static void print_bitmap_flags(ALLEGRO_BITMAP *bitmap) { ALLEGRO_USTR *ustr = al_ustr_new(""); if (al_get_bitmap_flags(bitmap) & ALLEGRO_VIDEO_BITMAP) al_ustr_append_cstr(ustr, " VIDEO"); if (al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP) al_ustr_append_cstr(ustr, " MEMORY"); if (al_get_bitmap_flags(bitmap) & ALLEGRO_CONVERT_BITMAP) al_ustr_append_cstr(ustr, " CONVERT"); al_ustr_trim_ws(ustr); al_ustr_find_replace_cstr(ustr, 0, " ", " | "); log_printf("%s", al_cstr(ustr)); al_ustr_free(ustr); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; bool redraw = true; ALLEGRO_FONT *font; ALLEGRO_BITMAP *spin, *spin2; int current_bitmap = 0; int loaded_bitmap = 0; ALLEGRO_THREAD *thread; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_image_addon(); al_init_font_addon(); al_init_primitives_addon(); init_platform_specific(); open_log(); al_install_mouse(); al_install_keyboard(); spin = al_load_bitmap("data/cursor.tga"); log_printf("default bitmap without display: %p\n", spin); al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP); spin2 = al_load_bitmap("data/cursor.tga"); log_printf("video bitmap without display: %p\n", spin2); log_printf("%p before create_display: ", spin); print_bitmap_flags(spin); log_printf("\n"); display = al_create_display(64, 64); if (!display) { abort_example("Error creating display\n"); } spin2 = al_load_bitmap("data/cursor.tga"); log_printf("video bitmap with display: %p\n", spin2); log_printf("%p after create_display: ", spin); print_bitmap_flags(spin); log_printf("\n"); log_printf("%p after create_display: ", spin2); print_bitmap_flags(spin2); log_printf("\n"); al_destroy_display(display); log_printf("%p after destroy_display: ", spin); print_bitmap_flags(spin); log_printf("\n"); log_printf("%p after destroy_display: ", spin2); print_bitmap_flags(spin2); log_printf("\n"); display = al_create_display(640, 480); log_printf("%p after create_display: ", spin); print_bitmap_flags(spin); log_printf("\n"); log_printf("%p after create_display: ", spin2); print_bitmap_flags(spin2); log_printf("\n"); font = al_load_font("data/fixed_font.tga", 0, 0); mutex = al_create_mutex(); thread = al_create_thread(loading_thread, NULL); al_start_thread(thread); timer = al_create_timer(1.0 / 30); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (1) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; } if (event.type == ALLEGRO_EVENT_TIMER) redraw = true; if (redraw && al_is_event_queue_empty(queue)) { float x = 20, y = 320; int i; ALLEGRO_COLOR color = al_map_rgb_f(0, 0, 0); float t = al_current_time(); redraw = false; al_clear_to_color(al_map_rgb_f(0.5, 0.6, 1)); al_draw_textf(font, color, x + 40, y, 0, "Loading %d%%", 100 * load_count / load_total); al_lock_mutex(mutex); if (loaded_bitmap < load_count) { /* This will convert any video bitmaps without a display * (all the bitmaps being loaded in the loading_thread) to * video bitmaps we can use in the main thread. */ al_convert_bitmap(bitmaps[loaded_bitmap]); loaded_bitmap++; } al_unlock_mutex(mutex); if (current_bitmap < loaded_bitmap) { int bw; al_draw_bitmap(bitmaps[current_bitmap], 0, 0, 0); if (current_bitmap + 1 < loaded_bitmap) current_bitmap++; for (i = 0; i <= current_bitmap; i++) { bw = al_get_bitmap_width(bitmaps[i]); al_draw_scaled_rotated_bitmap(bitmaps[i], 0, 0, (i % 20) * 640 / 20, 360 + (i / 20) * 24, 32.0 / bw, 32.0 / bw, 0, 0); } } if (loaded_bitmap < load_total) { al_draw_scaled_rotated_bitmap(spin, 16, 16, x, y, 1.0, 1.0, t * ALLEGRO_PI * 2, 0); } al_flip_display(); } } al_join_thread(thread, NULL); al_destroy_mutex(mutex); al_destroy_font(font); al_destroy_display(display); close_log(true); return 0; } allegro5-5.2.10.1/examples/ex_lockbitmap.c000066400000000000000000000134061473414355200202670ustar00rootroot00000000000000/* * Example program for the Allegro library. * * From left to right you should see Red, Green, Blue gradients. */ #define ALLEGRO_UNSTABLE #include "allegro5/allegro.h" #include "common.c" enum Mode { MODE_VIDEO, MODE_MEMORY, MODE_BACKBUFFER }; static void fill(ALLEGRO_BITMAP *bitmap, int lock_flags) { ALLEGRO_LOCKED_REGION *locked; uint8_t *ptr; int i, j; /* Locking the bitmap means, we work directly with pixel data. We can * choose the format we want to work with, which may imply conversions, or * use the bitmap's actual format so we can work directly with the bitmap's * pixel data. * We use a 16-bit format and odd positions and sizes to increase the * chances of uncovering bugs. */ locked = al_lock_bitmap_region(bitmap, 193, 65, 3*127, 127, ALLEGRO_PIXEL_FORMAT_RGB_565, lock_flags); if (!locked) return; for (j = 0; j < 127; j++) { ptr = (uint8_t *)locked->data + j * locked->pitch; for (i = 0; i < 3*127; i++) { uint8_t red; uint8_t green; uint8_t blue; uint16_t col; uint16_t *cptr = (uint16_t *)ptr; if (j == 0 || j == 126 || i == 0 || i == 3*127-1) { red = green = blue = 0; } else if (i < 127) { red = 255; green = blue = j*2; } else if (i < 2*127) { green = 255; red = blue = j*2; } else { blue = 255; red = green = j*2; } /* The RGB_555 format means, the 16 bits per pixel are laid out like * this, least significant bit right: RRRRR GGGGGG BBBBB * Because the byte order can vary per platform (big endian or * little endian) we encode an integer and store that * directly rather than storing each component separately. * * In READWRITE mode the light blue background should should through * the stipple pattern. */ if ((lock_flags & ALLEGRO_LOCK_WRITEONLY) || (j + i) % 2 == 1) { col = ((red/8) << 11) | ((green/4) << 5) | (blue/8); *cptr = col; } ptr += 2; } } al_unlock_bitmap(bitmap); } static void draw(ALLEGRO_DISPLAY *display, enum Mode mode, int lock_flags) { ALLEGRO_BITMAP *bitmap; /* Create the bitmap to lock, or use the display backbuffer. */ if (mode == MODE_VIDEO) { log_printf("Locking video bitmap"); al_clear_to_color(al_map_rgb(0, 0, 0)); al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP); bitmap = al_create_bitmap(3*256, 256); } else if (mode == MODE_MEMORY) { log_printf("Locking memory bitmap"); al_clear_to_color(al_map_rgb(0, 0, 0)); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); bitmap = al_create_bitmap(3*256, 256); } else { log_printf("Locking display backbuffer"); bitmap = al_get_backbuffer(display); } if (!bitmap) { abort_example("Error creating bitmap"); } if (lock_flags & ALLEGRO_LOCK_WRITEONLY) { log_printf(" in write-only mode\n"); } else { log_printf(" in read/write mode\n"); } al_set_target_bitmap(bitmap); al_clear_to_color(al_map_rgb_f(0.8, 0.8, 0.9)); al_set_target_backbuffer(display); fill(bitmap, lock_flags); if (mode != MODE_BACKBUFFER) { al_draw_bitmap(bitmap, 0, 0, 0); al_destroy_bitmap(bitmap); bitmap = NULL; } al_flip_display(); } static enum Mode cycle_mode(enum Mode mode) { switch (mode) { case MODE_VIDEO: return MODE_MEMORY; case MODE_MEMORY: return MODE_BACKBUFFER; case MODE_BACKBUFFER: default: return MODE_VIDEO; } } static int toggle_writeonly(int lock_flags) { return lock_flags ^ ALLEGRO_LOCK_WRITEONLY; } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_EVENT_QUEUE *events; ALLEGRO_EVENT event; enum Mode mode = MODE_VIDEO; int lock_flags = ALLEGRO_LOCK_WRITEONLY; bool redraw = true; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_install_mouse(); al_install_touch_input(); open_log(); /* Create a window. */ display = al_create_display(3*256, 256); if (!display) { abort_example("Error creating display\n"); } events = al_create_event_queue(); al_register_event_source(events, al_get_keyboard_event_source()); al_register_event_source(events, al_get_mouse_event_source()); if (al_is_touch_input_installed()) { al_register_event_source(events, al_get_touch_input_mouse_emulation_event_source()); } log_printf("Press space to change bitmap type\n"); log_printf("Press w to toggle WRITEONLY mode\n"); for (;;) { if (redraw) { draw(display, mode, lock_flags); redraw = false; } al_wait_for_event(events, &event); if (event.type == ALLEGRO_EVENT_KEY_CHAR) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; if (event.keyboard.unichar == ' ') { mode = cycle_mode(mode); redraw = true; } else if (event.keyboard.unichar == 'w' || event.keyboard.unichar == 'W') { lock_flags = toggle_writeonly(lock_flags); redraw = true; } } else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { if (event.mouse.button == 1) { if (event.mouse.x < al_get_display_width(display) / 2) { mode = cycle_mode(mode); } else { lock_flags = toggle_writeonly(lock_flags); } redraw = true; } } } close_log(false); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_logo.c000066400000000000000000000401011473414355200170720ustar00rootroot00000000000000/* Demo program which creates a logo by direct pixel manipulation of * bitmaps. Also uses alpha blending to create a real-time flash * effect (likely not visible with displays using memory bitmaps as it * is too slow). */ #include #include #include #include #include #include #include #include "common.c" #ifdef ALLEGRO_MSVC #define snprintf _snprintf #endif static ALLEGRO_BITMAP *logo, *logo_flash; static int logo_x, logo_y; static ALLEGRO_FONT *font; static int cursor; static int selection; static bool regenerate = 0, editing = 0; static ALLEGRO_CONFIG *config; static ALLEGRO_COLOR white; static double anim; static float clamp(float x) { if (x < 0) return 0; if (x > 1) return 1; return x; } static char const *param_names[] = { "text", "font", "size", "shadow", "blur", "factor", "red", "green", "blue", NULL }; /* Note: To regenerate something close to the official Allegro logo, * you need to obtain the non-free "Utopia Regular Italic" font. Then * replace "DejaVuSans.ttf" with "putri.pfa" below. */ static char param_values[][256] = { "Allegro", "data/DejaVuSans.ttf", "140", "10", "2", "0.5", "1.1", "1.5", "5" }; /* Generates a bitmap with transparent background and the logo text. * The bitmap will have screen size. If 'bumpmap' is not NULL, it will * contain another bitmap which is a white, blurred mask of the logo * which we use for the flash effect. */ static ALLEGRO_BITMAP *generate_logo(char const *text, char const *fontname, int font_size, float shadow_offset, float blur_radius, float blur_factor, float light_red, float light_green, float light_blue, ALLEGRO_BITMAP **bumpmap) { ALLEGRO_COLOR transparent = al_map_rgba_f(0, 0, 0, 0); int xp, yp, w, h, i, j, x, y, br, bw, dw, dh; ALLEGRO_COLOR c; ALLEGRO_FONT *logofont; ALLEGRO_STATE state; ALLEGRO_BITMAP *blur, *light, *logo; int left, right, top, bottom; float cx, cy; dw = al_get_bitmap_width(al_get_target_bitmap()); dh = al_get_bitmap_height(al_get_target_bitmap()); cx = dw * 0.5; cy = dh * 0.5; logofont = al_load_font(fontname, -font_size, 0); al_get_text_dimensions(logofont, text, &xp, &yp, &w, &h); al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP | ALLEGRO_STATE_BLENDER); /* Cheap blur effect to create a bump map. */ blur = al_create_bitmap(dw, dh); al_set_target_bitmap(blur); al_clear_to_color(transparent); br = blur_radius; bw = br * 2 + 1; c = al_map_rgba_f(1, 1, 1, 1.0 / (bw * bw * blur_factor)); al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); for (i = -br; i <= br; i++) { for (j = -br; j <= br; j++) { al_draw_text(logofont, c, cx - xp * 0.5 - w * 0.5 + i, cy - yp * 0.5 - h * 0.5 + j, 0, text); } } left = cx - xp * 0.5 - w * 0.5 - br + xp; top = cy - yp * 0.5 - h * 0.5 - br + yp; right = left + w + br * 2; bottom = top + h + br * 2; if (left < 0) left = 0; if (top < 0) top = 0; if (right > dw - 1) right = dw - 1; if (bottom > dh - 1) bottom = dh - 1; /* Cheap light effect. */ light = al_create_bitmap(dw, dh); al_set_target_bitmap(light); al_clear_to_color(transparent); al_lock_bitmap(blur, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); al_lock_bitmap_region(light, left, top, 1 + right - left, 1 + bottom - top, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); for (y = top; y <= bottom; y++) { for (x = left; x <= right; x++) { float r1, g1, b1, a1; float r2, g2, b2, a2; float r, g, b, a; float d; ALLEGRO_COLOR c = al_get_pixel(blur, x, y); ALLEGRO_COLOR c1 = al_get_pixel(blur, x - 1, y - 1); ALLEGRO_COLOR c2 = al_get_pixel(blur, x + 1, y + 1); al_unmap_rgba_f(c, &r, &g, &b, &a); al_unmap_rgba_f(c1, &r1, &g1, &b1, &a1); al_unmap_rgba_f(c2, &r2, &g2, &b2, &a2); d = r2 - r1 + 0.5; r = clamp(d * light_red); g = clamp(d * light_green); b = clamp(d * light_blue); c = al_map_rgba_f(r, g, b, a); al_put_pixel(x, y, c); } } al_unlock_bitmap(light); al_unlock_bitmap(blur); if (bumpmap) *bumpmap = blur; else al_destroy_bitmap(blur); /* Create final logo */ logo = al_create_bitmap(dw, dh); al_set_target_bitmap(logo); al_clear_to_color(transparent); /* Draw a shadow. */ c = al_map_rgba_f(0, 0, 0, 0.5 / 9); al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); for (i = -1; i <= 1; i++) for (j = -1; j <= 1; j++) al_draw_text(logofont, c, cx - xp * 0.5 - w * 0.5 + shadow_offset + i, cy - yp * 0.5 - h * 0.5 + shadow_offset + j, 0, text); /* Then draw the lit text we made before on top. */ al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_bitmap(light, 0, 0, 0); al_destroy_bitmap(light); al_restore_state(&state); al_destroy_font(logofont); return logo; } /* Draw the checkerboard background. */ static void draw_background(void) { ALLEGRO_COLOR c[2]; int i, j; c[0] = al_map_rgba(0xaa, 0xaa, 0xaa, 0xff); c[1] = al_map_rgba(0x99, 0x99, 0x99, 0xff); for (i = 0; i < 640 / 16; i++) { for (j = 0; j < 480 / 16; j++) { al_draw_filled_rectangle(i * 16, j * 16, i * 16 + 16, j * 16 + 16, c[(i + j) & 1]); } } } /* Print out the current logo parameters. */ static void print_parameters(void) { int i; ALLEGRO_STATE state; ALLEGRO_COLOR normal = al_map_rgba_f(0, 0, 0, 1); ALLEGRO_COLOR light = al_map_rgba_f(0, 0, 1, 1); ALLEGRO_COLOR label = al_map_rgba_f(0.2, 0.2, 0.2, 1); int th; al_store_state(&state, ALLEGRO_STATE_BLENDER); th = al_get_font_line_height(font) + 3; for (i = 0; param_names[i]; i++) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(font, label, 2, 2 + i * th, 0, "%s", param_names[i]); } for (i = 0; param_names[i]; i++) { int y = 2 + i * th; al_draw_filled_rectangle(75, y, 375, y + th - 2, al_map_rgba_f(0.5, 0.5, 0.5, 0.5)); al_draw_textf(font, i == selection ? light : normal, 75, y, 0, "%s", param_values[i]); if (i == selection && editing && (((int)(al_get_time() * 2)) & 1)) { int x = 75 + al_get_text_width(font, param_values[i]); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_line(x, y, x, y + th, white, 0); } } al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(font, normal, 400, 2, 0, "%s", "R - Randomize"); al_draw_textf(font, normal, 400, 2 + th, 0, "%s", "S - Save as logo.png"); al_draw_textf(font, normal, 2, 480 - th * 2 - 2, 0, "%s", "To modify, press Return, then enter value, " "then Return again."); al_draw_textf(font, normal, 2, 480 - th - 2, 0, "%s", "Use cursor up/down to " "select the value to modify."); al_restore_state(&state); } static char const *rnum(float min, float max) { static char s[256]; double x = rand() / (double)RAND_MAX; x = min + x * (max - min); snprintf(s, sizeof s, "%.1f", x); return s; } static void randomize(void) { strcpy(param_values[3], rnum(2, 12)); strcpy(param_values[4], rnum(1, 8)); strcpy(param_values[5], rnum(0.1, 1)); strcpy(param_values[6], rnum(0, 5)); strcpy(param_values[7], rnum(0, 5)); strcpy(param_values[8], rnum(0, 5)); regenerate = true; } static void save(void) { al_save_bitmap("logo.png", logo); } static void mouse_click(int x, int y) { int th = al_get_font_line_height(font) + 3; int sel = (y - 2) / th; int i; if (x < 400) { for (i = 0; param_names[i]; i++) { if (sel == i) { selection = i; cursor = 0; editing = true; } } } else if (x < 500) { if (sel == 0) randomize(); if (sel == 1) save(); } } static void render(void) { double t = al_get_time(); if (regenerate) { al_destroy_bitmap(logo); al_destroy_bitmap(logo_flash); logo = NULL; regenerate = false; } if (!logo) { /* Generate a new logo. */ ALLEGRO_BITMAP *fullflash; ALLEGRO_BITMAP *fulllogo = generate_logo(param_values[0], param_values[1], strtol(param_values[2], NULL, 10), strtod(param_values[3], NULL), strtod(param_values[4], NULL), strtod(param_values[5], NULL), strtod(param_values[6], NULL), strtod(param_values[7], NULL), strtod(param_values[8], NULL), &fullflash); ALLEGRO_BITMAP *crop; int x, y, left = 640, top = 480, right = -1, bottom = -1; /* Crop out the non-transparent part. */ al_lock_bitmap(fulllogo, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); for (y = 0; y < 480; y++) { for (x = 0; x < 640; x++) { ALLEGRO_COLOR c = al_get_pixel(fulllogo, x, y); float r, g, b, a; al_unmap_rgba_f(c, &r, &g, &b, &a); if (a > 0) { if (x < left) left = x; if (y < top) top = y; if (x > right) right = x; if (y > bottom) bottom = y; } } } al_unlock_bitmap(fulllogo); if (left == 640) left = 0; if (top == 480) top = 0; if (right < left) right = left; if (bottom < top) bottom = top; crop = al_create_sub_bitmap(fulllogo, left, top, 1 + right - left, 1 + bottom - top); logo = al_clone_bitmap(crop); al_destroy_bitmap(crop); al_destroy_bitmap(fulllogo); crop = al_create_sub_bitmap(fullflash, left, top, 1 + right - left, 1 + bottom - top); logo_flash = al_clone_bitmap(crop); al_destroy_bitmap(crop); al_destroy_bitmap(fullflash); logo_x = left; logo_y = top; anim = t; } draw_background(); /* For half a second, display our flash animation. */ if (t - anim < 0.5) { ALLEGRO_STATE state; int i, j; float f = sin(ALLEGRO_PI * ((t - anim) / 0.5)); ALLEGRO_COLOR c = al_map_rgb_f(f * 0.3, f * 0.3, f * 0.3); al_store_state(&state, ALLEGRO_STATE_BLENDER); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_tinted_bitmap(logo, al_map_rgba_f(1, 1, 1, 1 - f), logo_x, logo_y, 0); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); for (j = -2; j <= 2; j += 2) { for (i = -2; i <= 2; i += 2) { al_draw_tinted_bitmap(logo_flash, c, logo_x + i, logo_y + j, 0); } } al_restore_state(&state); } else al_draw_bitmap(logo, logo_x, logo_y, 0); print_parameters(); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; int redraw = 0, i; bool quit = false; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not initialise Allegro\n"); } al_init_primitives_addon(); al_install_mouse(); al_init_image_addon(); al_init_font_addon(); al_init_ttf_addon(); init_platform_specific(); srand(time(NULL)); white = al_map_rgba_f(1, 1, 1, 1); display = al_create_display(640, 480); if (!display) { abort_example("Could not create display\n"); } al_set_window_title(display, "Allegro Logo Generator"); al_install_keyboard(); /* Read logo parameters from logo.ini (if it exists). */ config = al_load_config_file("logo.ini"); if (!config) config = al_create_config(); for (i = 0; param_names[i]; i++) { char const *value = al_get_config_value(config, "logo", param_names[i]); if (value) strncpy(param_values[i], value, sizeof(param_values[i])); } font = al_load_font("data/DejaVuSans.ttf", 12, 0); if (!font) { abort_example("Could not load font\n"); } timer = al_create_timer(1.0 / 60); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (!quit) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; if (event.type == ALLEGRO_EVENT_KEY_CHAR) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { quit = true; } else if (event.keyboard.keycode == ALLEGRO_KEY_ENTER) { if (editing) { regenerate = true; editing = false; } else { cursor = strlen(param_values[selection]); editing = true; } } else if (event.keyboard.keycode == ALLEGRO_KEY_UP) { if (selection > 0) { selection--; cursor = strlen(param_values[selection]); editing = false; } } else if (event.keyboard.keycode == ALLEGRO_KEY_DOWN) { if (param_names[selection + 1]) { selection++; cursor = strlen(param_values[selection]); editing = false; } } else { int c = event.keyboard.unichar; if (editing) { if (event.keyboard.keycode == ALLEGRO_KEY_BACKSPACE) { if (cursor > 0) { ALLEGRO_USTR *u = al_ustr_new(param_values[selection]); if (al_ustr_prev(u, &cursor)) { al_ustr_remove_chr(u, cursor); strncpy(param_values[selection], al_cstr(u), sizeof param_values[selection]); } al_ustr_free(u); } } else if (c >= 32) { ALLEGRO_USTR *u = al_ustr_new(param_values[selection]); cursor += al_ustr_set_chr(u, cursor, c); al_ustr_set_chr(u, cursor, 0); strncpy(param_values[selection], al_cstr(u), sizeof param_values[selection]); al_ustr_free(u); } } else { if (c == 'r') randomize(); if (c == 's') save(); } } } if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { if (event.mouse.button == 1) { mouse_click(event.mouse.x, event.mouse.y); } } if (event.type == ALLEGRO_EVENT_TIMER) redraw++; if (redraw && al_is_event_queue_empty(queue)) { redraw = 0; render(); al_flip_display(); } } /* Write modified parameters back to logo.ini. */ for (i = 0; param_names[i]; i++) { al_set_config_value(config, "logo", param_names[i], param_values[i]); } al_save_config_file("logo.ini", config); al_destroy_config(config); return 0; } allegro5-5.2.10.1/examples/ex_membmp.c000066400000000000000000000063261473414355200174220ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_image.h" #include "common.c" static void print(ALLEGRO_FONT *myfont, char *message, int x, int y) { al_draw_text(myfont, al_map_rgb(0, 0, 0), x+2, y+2, 0, message); al_draw_text(myfont, al_map_rgb(255, 255, 255), x, y, 0, message); } static bool test(ALLEGRO_BITMAP *bitmap, ALLEGRO_FONT *font, char *message) { ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; double start_time; long frames = 0; double fps = 0; char second_line[100]; bool quit = false; queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); start_time = al_get_time(); for (;;) { if (al_get_next_event(queue, &event)) { if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) { break; } if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { quit = true; break; } } } al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); /* Clear the backbuffer with red so we can tell if the bitmap does not * cover the entire backbuffer. */ al_clear_to_color(al_map_rgb(255, 0, 0)); al_draw_scaled_bitmap(bitmap, 0, 0, al_get_bitmap_width(bitmap), al_get_bitmap_height(bitmap), 0, 0, al_get_bitmap_width(al_get_target_bitmap()), al_get_bitmap_height(al_get_target_bitmap()), 0); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); /* Note this makes the memory buffer case much slower due to repeated * locking of the backbuffer. Officially you can't use al_lock_bitmap * to solve the problem either. */ print(font, message, 0, 0); sprintf(second_line, "%.1f FPS", fps); print(font, second_line, 0, al_get_font_line_height(font)+5); al_flip_display(); frames++; fps = (double)frames / (al_get_time() - start_time); } al_destroy_event_queue(queue); return quit; } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_FONT *accelfont; ALLEGRO_FONT *memfont; ALLEGRO_BITMAP *accelbmp; ALLEGRO_BITMAP *membmp; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_init_image_addon(); al_init_font_addon(); init_platform_specific(); display = al_create_display(640, 400); if (!display) { abort_example("Error creating display\n"); } accelfont = al_load_font("data/font.tga", 0, 0); if (!accelfont) { abort_example("font.tga not found\n"); } accelbmp = al_load_bitmap("data/mysha.pcx"); if (!accelbmp) { abort_example("mysha.pcx not found\n"); } al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); memfont = al_load_font("data/font.tga", 0, 0); membmp = al_load_bitmap("data/mysha.pcx"); for (;;) { if (test(membmp, memfont, "Memory bitmap (press SPACE key)")) break; if (test(accelbmp, accelfont, "Accelerated bitmap (press SPACE key)")) break; } return 0; } allegro5-5.2.10.1/examples/ex_memfile.c000066400000000000000000000053461473414355200175640ustar00rootroot00000000000000/* * Example program for the Allegro library. * * Test memfile addon. */ #include #ifdef _MSC_VER #pragma comment ( linker, "/SUBSYSTEM:CONSOLE") #endif #define ALLEGRO_USE_CONSOLE #include #include #include "common.c" int main(void) { ALLEGRO_FILE *memfile; char *data; int i; const int data_size = 1024; char buffer[50]; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); data = calloc(1, data_size); if (!data) abort_example("Out of memory.\n"); log_printf("Creating memfile\n"); memfile = al_open_memfile(data, data_size, "rw"); if (!memfile) { log_printf("Error opening memfile :(\n"); goto Error; } log_printf("Writing data to memfile\n"); for (i = 0; i < data_size/4; i++) { if (al_fwrite32le(memfile, i) < 4) { log_printf("Failed to write %i to memfile\n", i); goto Error; } } al_fseek(memfile, 0, ALLEGRO_SEEK_SET); log_printf("Reading and testing data from memfile\n"); for (i = 0; i < data_size/4; i++) { int32_t ret = al_fread32le(memfile); if (ret != i || al_feof(memfile)) { log_printf("Item %i failed to verify, got %i\n", i, ret); goto Error; } } if (al_feof(memfile)) { log_printf("EOF indicator prematurely set!\n"); goto Error; } /* testing the ungetc buffer */ al_fseek(memfile, 0, ALLEGRO_SEEK_SET); for (i = 0; al_fungetc(memfile, i) != EOF; ++i) { } log_printf("Length of ungetc buffer: %d\n", i); if (al_ftell(memfile) != -i) { log_printf("Current position is not correct. Expected -%d, but got %d\n", i, (int) al_ftell(memfile)); goto Error; } while (i--) { if (i != al_fgetc(memfile)) { log_printf("Failed to verify ungetc data.\n"); goto Error; } } if (al_ftell(memfile) != 0) { log_printf("Current position is not correct after reading back the ungetc buffer\n"); log_printf("Expected 0, but got %d\n", (int) al_ftell(memfile)); goto Error; } al_fputs(memfile, "legro rocks!"); al_fseek(memfile, 0, ALLEGRO_SEEK_SET); al_fungetc(memfile, 'l'); al_fungetc(memfile, 'A'); al_fgets(memfile, buffer, 15); if (strcmp(buffer, "Allegro rocks!")) { log_printf("Expected to see 'Allegro rocks!' but got '%s' instead.\n", buffer); log_printf("(Maybe the ungetc buffer isn't big enough.)\n"); goto Error; } log_printf("Done.\n"); al_fclose(memfile); free(data); close_log(true); return 0; Error: al_fclose(memfile); free(data); close_log(true); return 1; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_menu.c000066400000000000000000000253501473414355200171070ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_native_dialog.h" #include "allegro5/allegro_image.h" #include #include #include "common.c" /* The following is a list of menu item ids. They can be any non-zero, positive * integer. A menu item must have an id in order for it to generate an event. * Also, each menu item's id should be unique to get well defined results. */ enum { FILE_ID = 1, FILE_OPEN_ID, FILE_RESIZE_ID, FILE_FULLSCREEN_ID, FILE_MAXIMIZE_ID, FILE_FRAMELESS_ID, FILE_CLOSE_ID, FILE_EXIT_ID, DYNAMIC_ID, DYNAMIC_CHECKBOX_ID, DYNAMIC_DISABLED_ID, DYNAMIC_DELETE_ID, DYNAMIC_CREATE_ID, HELP_ABOUT_ID }; /* This is one way to define a menu. The entire system, nested menus and all, * can be defined by this single array. */ ALLEGRO_MENU_INFO main_menu_info[] = { ALLEGRO_START_OF_MENU("&File", FILE_ID), { "&Open", FILE_OPEN_ID, 0, NULL }, ALLEGRO_MENU_SEPARATOR, { "E&xit", FILE_EXIT_ID, 0, NULL }, ALLEGRO_END_OF_MENU, ALLEGRO_START_OF_MENU("&Dynamic Options", DYNAMIC_ID), { "&Checkbox", DYNAMIC_CHECKBOX_ID, ALLEGRO_MENU_ITEM_CHECKED, NULL }, { "&Disabled", DYNAMIC_DISABLED_ID, ALLEGRO_MENU_ITEM_DISABLED, NULL }, { "DELETE ME!", DYNAMIC_DELETE_ID, 0, NULL }, { "Click Me", DYNAMIC_CREATE_ID, 0, NULL }, ALLEGRO_END_OF_MENU, ALLEGRO_START_OF_MENU("&Help", 0), { "&About", HELP_ABOUT_ID, 0, NULL }, ALLEGRO_END_OF_MENU, ALLEGRO_END_OF_MENU }; /* This is the menu on the secondary windows. */ ALLEGRO_MENU_INFO child_menu_info[] = { ALLEGRO_START_OF_MENU("&File", 0), { "&Close", FILE_CLOSE_ID, 0, NULL }, ALLEGRO_END_OF_MENU, ALLEGRO_END_OF_MENU }; int main(int argc, char **argv) { const int initial_width = 320; const int initial_height = 200; int dcount = 0; ALLEGRO_DISPLAY *display; ALLEGRO_MENU *menu; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_TIMER *timer; bool redraw = true; bool menu_visible = true; ALLEGRO_MENU *pmenu; ALLEGRO_BITMAP *bg; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } if (!al_init_native_dialog_addon()) { abort_example("Could not init the native dialog addon.\n"); } al_init_image_addon(); al_install_keyboard(); al_install_mouse(); queue = al_create_event_queue(); #ifdef ALLEGRO_GTK_TOPLEVEL /* ALLEGRO_GTK_TOPLEVEL is necessary for menus with GTK. */ al_set_new_display_flags(ALLEGRO_RESIZABLE | ALLEGRO_GTK_TOPLEVEL); #else al_set_new_display_flags(ALLEGRO_RESIZABLE); #endif display = al_create_display(initial_width, initial_height); if (!display) { abort_example("Error creating display\n"); } al_set_window_title(display, "ex_menu - Main Window"); menu = al_build_menu(main_menu_info); if (!menu) { abort_example("Error creating menu\n"); } /* Add an icon to the Help/About item. Note that Allegro assumes ownership * of the bitmap. */ al_set_menu_item_icon(menu, HELP_ABOUT_ID, al_load_bitmap("data/icon.tga")); if (!al_set_display_menu(display, menu)) { /* Since the menu could not be attached to the window, then treat it as * a popup menu instead. */ pmenu = al_clone_menu_for_popup(menu); al_destroy_menu(menu); menu = pmenu; } else { /* Create a simple popup menu used when right clicking. */ pmenu = al_create_popup_menu(); if (pmenu) { al_append_menu_item(pmenu, "&Open", FILE_OPEN_ID, 0, NULL, NULL); al_append_menu_item(pmenu, "&Resize", FILE_RESIZE_ID, 0, NULL, NULL); al_append_menu_item(pmenu, "&Fullscreen window", FILE_FULLSCREEN_ID, 0, NULL, NULL); al_append_menu_item(pmenu, "Remove window fr&ame", FILE_FRAMELESS_ID, 0, NULL, NULL); al_append_menu_item(pmenu, "&Maximize window", FILE_MAXIMIZE_ID, 0, NULL, NULL); al_append_menu_item(pmenu, "E&xit", FILE_EXIT_ID, 0, NULL, NULL); } } timer = al_create_timer(1.0 / 60); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_default_menu_event_source()); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); bg = al_load_bitmap("data/mysha.pcx"); al_start_timer(timer); while (true) { ALLEGRO_EVENT event; if (redraw && al_is_event_queue_empty(queue)) { redraw = false; if (bg) { float t = al_get_timer_count(timer) * 0.1; float sw = al_get_bitmap_width(bg); float sh = al_get_bitmap_height(bg); float dw = al_get_display_width(display); float dh = al_get_display_height(display); float cx = dw/2; float cy = dh/2; dw *= 1.2 + 0.2 * cos(t); dh *= 1.2 + 0.2 * cos(1.1 * t); al_draw_scaled_bitmap(bg, 0, 0, sw, sh, cx - dw/2, cy - dh/2, dw, dh, 0); } al_flip_display(); } al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { if (event.display.source == display) { /* Closing the primary display */ break; } else { /* Closing a secondary display */ al_set_display_menu(event.display.source, NULL); al_destroy_display(event.display.source); } } else if (event.type == ALLEGRO_EVENT_MENU_CLICK) { /* data1: id * data2: display (could be null) * data3: menu (could be null) */ if (event.user.data2 == (intptr_t) display) { /* The main window. */ if (event.user.data1 == FILE_OPEN_ID) { ALLEGRO_DISPLAY *d = al_create_display(320, 240); if (d) { ALLEGRO_MENU *menu = al_build_menu(child_menu_info); al_set_display_menu(d, menu); al_clear_to_color(al_map_rgb(0,0,0)); al_flip_display(); al_register_event_source(queue, al_get_display_event_source(d)); al_set_target_backbuffer(display); al_set_window_title(d, "ex_menu - Child Window"); } } else if (event.user.data1 == DYNAMIC_CHECKBOX_ID) { al_set_menu_item_flags(menu, DYNAMIC_DISABLED_ID, al_get_menu_item_flags(menu, DYNAMIC_DISABLED_ID) ^ ALLEGRO_MENU_ITEM_DISABLED); al_set_menu_item_caption(menu, DYNAMIC_DISABLED_ID, (al_get_menu_item_flags(menu, DYNAMIC_DISABLED_ID) & ALLEGRO_MENU_ITEM_DISABLED) ? "&Disabled" : "&Enabled"); } else if (event.user.data1 == DYNAMIC_DELETE_ID) { al_remove_menu_item(menu, DYNAMIC_DELETE_ID); } else if (event.user.data1 == DYNAMIC_CREATE_ID) { if (dcount < 5) { char new_name[10]; ++dcount; if (dcount == 1) { /* append a separator */ al_append_menu_item(al_find_menu(menu, DYNAMIC_ID), NULL, 0, 0, NULL, NULL); } sprintf(new_name, "New #%d", dcount); al_append_menu_item(al_find_menu(menu, DYNAMIC_ID), new_name, 0, 0, NULL, NULL); if (dcount == 5) { /* disable the option */ al_set_menu_item_flags(menu, DYNAMIC_CREATE_ID, ALLEGRO_MENU_ITEM_DISABLED); } } } else if (event.user.data1 == HELP_ABOUT_ID) { al_show_native_message_box(display, "About", "ex_menu", "This is a sample program that shows how to use menus", "OK", 0); } else if (event.user.data1 == FILE_EXIT_ID) { break; } else if (event.user.data1 == FILE_RESIZE_ID) { int w = al_get_display_width(display) * 2; int h = al_get_display_height(display) * 2; if (w > 960) w = 960; if (h > 600) h = 600; al_resize_display(display, w, h); } else if (event.user.data1 == FILE_FULLSCREEN_ID) { int flags = al_get_display_flags(display); bool value = (flags & ALLEGRO_FULLSCREEN_WINDOW) ? true : false; al_set_display_flag(display, ALLEGRO_FULLSCREEN_WINDOW, !value); } else if (event.user.data1 == FILE_FRAMELESS_ID) { int flags = al_get_display_flags(display); bool value = (flags & ALLEGRO_FRAMELESS) ? true : false; al_set_display_flag(display, ALLEGRO_FRAMELESS, !value); } else if (event.user.data1 == FILE_MAXIMIZE_ID) { int flags = al_get_display_flags(display); bool value = (flags & ALLEGRO_MAXIMIZED) ? true : false; al_set_display_flag(display, ALLEGRO_MAXIMIZED, !value); } } else { /* The child window */ if (event.user.data1 == FILE_CLOSE_ID) { ALLEGRO_DISPLAY *d = (ALLEGRO_DISPLAY *) event.user.data2; if (d) { al_set_display_menu(d, NULL); al_destroy_display(d); } } } } else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { /* Popup a context menu on a right click. */ if (event.mouse.display == display && event.mouse.button == 2) { if (pmenu) { if (!al_popup_menu(pmenu, display)) { log_printf("Couldn't popup menu!\n"); } } } } else if (event.type == ALLEGRO_EVENT_KEY_CHAR) { /* Toggle the menu if the spacebar is pressed */ if (event.keyboard.display == display) { if (event.keyboard.unichar == ' ') { if (menu_visible) al_remove_display_menu(display); else al_set_display_menu(display, menu); menu_visible = !menu_visible; } } } else if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { al_acknowledge_resize(display); redraw = true; } else if (event.type == ALLEGRO_EVENT_TIMER) { redraw = true; } } /* You must remove the menu before destroying the display to free resources */ al_set_display_menu(display, NULL); return 0; } allegro5-5.2.10.1/examples/ex_mixer_chain.c000066400000000000000000000066471473414355200204410ustar00rootroot00000000000000/* * Example program for the Allegro library. * * Test chaining mixers to mixers. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_acodec.h" #include "common.c" char *default_files[] = {NULL, "data/haiku/water_0.ogg", "data/haiku/water_7.ogg"}; int main(int argc, char **argv) { ALLEGRO_VOICE *voice; ALLEGRO_MIXER *mixer; ALLEGRO_MIXER *submixer[2]; ALLEGRO_SAMPLE_INSTANCE *sample[2]; ALLEGRO_SAMPLE *sample_data[2]; float sample_time; float max_sample_time; int i; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); if (argc < 3) { log_printf("This example can be run from the command line.\nUsage: %s file1 file2\n", argv[0]); argv = default_files; argc = 3; } al_init_acodec_addon(); if (!al_install_audio()) { abort_example("Could not init sound!\n"); } voice = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); if (!voice) { abort_example("Could not create ALLEGRO_VOICE.\n"); } mixer = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); submixer[0] = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); submixer[1] = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); if (!mixer || !submixer[0] || !submixer[1]) { abort_example("al_create_mixer failed.\n"); } if (!al_attach_mixer_to_voice(mixer, voice)) { abort_example("al_attach_mixer_to_voice failed.\n"); } for (i = 0; i < 2; i++) { const char *filename = argv[i + 1]; sample_data[i] = al_load_sample(filename); if (!sample_data[i]) { abort_example("Could not load sample from '%s'!\n", filename); } sample[i] = al_create_sample_instance(NULL); if (!sample[i]) { abort_example("al_create_sample failed.\n"); } if (!al_set_sample(sample[i], sample_data[i])) { abort_example("al_set_sample_ptr failed.\n"); } if (!al_attach_sample_instance_to_mixer(sample[i], submixer[i])) { abort_example("al_attach_sample_instance_to_mixer failed.\n"); } if (!al_attach_mixer_to_mixer(submixer[i], mixer)) { abort_example("al_attach_mixer_to_mixer failed.\n"); } } /* Play sample in looping mode. */ for (i = 0; i < 2; i++) { al_set_sample_instance_playmode(sample[i], ALLEGRO_PLAYMODE_LOOP); al_play_sample_instance(sample[i]); } max_sample_time = al_get_sample_instance_time(sample[0]); sample_time = al_get_sample_instance_time(sample[1]); if (sample_time > max_sample_time) max_sample_time = sample_time; log_printf("Playing..."); al_rest(max_sample_time); al_set_sample_instance_gain(sample[0], 0.5); al_rest(max_sample_time); al_set_sample_instance_gain(sample[1], 0.25); al_rest(max_sample_time); al_stop_sample_instance(sample[0]); al_stop_sample_instance(sample[1]); log_printf("Done\n"); /* Free the memory allocated. */ for (i = 0; i < 2; i++) { al_set_sample(sample[i], NULL); al_destroy_sample(sample_data[i]); al_destroy_sample_instance(sample[i]); al_destroy_mixer(submixer[i]); } al_destroy_mixer(mixer); al_destroy_voice(voice); al_uninstall_audio(); close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_mixer_pp.c000066400000000000000000000121171473414355200177630ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * * This program demonstrates a simple use of mixer postprocessing callbacks. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_acodec.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_primitives.h" #include "common.c" #define FPS 60 static volatile float rms_l = 0.0; static volatile float rms_r = 0.0; static ALLEGRO_DISPLAY *display; static ALLEGRO_BITMAP *dbuf; static ALLEGRO_BITMAP *bmp; static float theta; static void update_meter(void *buf, unsigned int samples, void *data) { float *fbuf = (float *)buf; float sum_l = 0.0; float sum_r = 0.0; unsigned int i; (void)data; for (i = samples; i > 0; i--) { sum_l += fbuf[0] * fbuf[0]; sum_r += fbuf[1] * fbuf[1]; fbuf += 2; } rms_l = sqrt(sum_l / samples); rms_r = sqrt(sum_r / samples); } static void draw(void) { const float sw = al_get_bitmap_width(bmp); const float sh = al_get_bitmap_height(bmp); const float dw = al_get_bitmap_width(dbuf); const float dh = al_get_bitmap_height(dbuf); const float dx = dw / 2.0; const float dy = dh / 2.0; float db_l; float db_r; float db; float scale; float disp; /* Whatever looks okay. */ if (rms_l > 0.0 && rms_r > 0.0) { db_l = 20 * log10(rms_l / 20e-6); db_r = 20 * log10(rms_r / 20e-6); db = (db_l + db_r) / 2.0; scale = db / 20.0; disp = (rms_l + rms_r) * 200.0; } else { db_l = db_r = db = scale = disp = 0.0; } al_set_target_bitmap(dbuf); al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); al_draw_filled_rectangle(0, 0, al_get_bitmap_width(dbuf), al_get_bitmap_height(dbuf), al_map_rgba_f(0.8, 0.3, 0.1, 0.06)); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_tinted_scaled_rotated_bitmap(bmp, al_map_rgba_f(0.8, 0.3, 0.1, 0.2), sw/2.0, sh/2.0, dx, dy - disp, scale, scale, theta, 0); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_set_target_backbuffer(display); al_draw_bitmap(dbuf, 0, 0, 0); al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); al_draw_line(10, dh - db_l, 10, dh, al_map_rgb_f(1, 0.6, 0.2), 6); al_draw_line(20, dh - db_r, 20, dh, al_map_rgb_f(1, 0.6, 0.2), 6); al_flip_display(); theta -= (rms_l + rms_r) * 0.1; } static void main_loop(void) { ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; bool redraw = true; queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); theta = 0.0; for (;;) { if (redraw && al_is_event_queue_empty(queue)) { draw(); redraw = false; } if (!al_wait_for_event_timed(queue, &event, 1.0/FPS)) { redraw = true; continue; } if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } } al_destroy_event_queue(queue); } int main(int argc, char **argv) { const char *filename = "../demos/cosmic_protector/data/sfx/title_music.ogg"; ALLEGRO_VOICE *voice; ALLEGRO_MIXER *mixer; ALLEGRO_AUDIO_STREAM *stream; if (argc > 1) { filename = argv[1]; } if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_init_image_addon(); al_init_acodec_addon(); init_platform_specific(); al_install_keyboard(); display = al_create_display(640, 480); if (!display) { abort_example("Could not create display.\n"); } dbuf = al_create_bitmap(640, 480); bmp = al_load_bitmap("data/mysha.pcx"); if (!bmp) { abort_example("Could not load data/mysha.pcx\n"); } if (!al_install_audio()) { abort_example("Could not init sound.\n"); } voice = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); if (!voice) { abort_example("Could not create voice.\n"); } mixer = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); if (!mixer) { abort_example("Could not create mixer.\n"); } if (!al_attach_mixer_to_voice(mixer, voice)) { abort_example("al_attach_mixer_to_voice failed.\n"); } stream = al_load_audio_stream(filename, 4, 2048); if (!stream) { /* On Android we only pack this into the APK. */ stream = al_load_audio_stream("data/welcome.wav", 4, 2048); } if (!stream) { abort_example("Could not load '%s'\n", filename); } al_set_audio_stream_playmode(stream, ALLEGRO_PLAYMODE_LOOP); al_attach_audio_stream_to_mixer(stream, mixer); al_set_mixer_postprocess_callback(mixer, update_meter, NULL); main_loop(); al_destroy_audio_stream(stream); al_destroy_mixer(mixer); al_destroy_voice(voice); al_uninstall_audio(); al_destroy_bitmap(dbuf); al_destroy_bitmap(bmp); return 0; } allegro5-5.2.10.1/examples/ex_monitorinfo.c000066400000000000000000000020631473414355200205020ustar00rootroot00000000000000#include "allegro5/allegro.h" #include #include "common.c" int main(int argc, char **argv) { ALLEGRO_MONITOR_INFO info; int num_adapters; int i, j; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); num_adapters = al_get_num_video_adapters(); log_printf("%d adapters found...\n", num_adapters); for (i = 0; i < num_adapters; i++) { al_get_monitor_info(i, &info); log_printf("Adapter %d: ", i); int dpi = al_get_monitor_dpi(i); log_printf("(%d, %d) - (%d, %d) - dpi: %d\n", info.x1, info.y1, info.x2, info.y2, dpi); al_set_new_display_adapter(i); log_printf(" Available fullscreen display modes:\n"); for (j = 0; j < al_get_num_display_modes(); j++) { ALLEGRO_DISPLAY_MODE mode; al_get_display_mode(j, &mode); log_printf(" Mode %3d: %4d x %4d, %d Hz\n", j, mode.width, mode.height, mode.refresh_rate); } } close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_mouse.c000066400000000000000000000033641473414355200172740ustar00rootroot00000000000000#include #include "allegro5/allegro_image.h" #include #include "common.c" #define NUM_BUTTONS 3 static void draw_mouse_button(int but, bool down) { const int offset[NUM_BUTTONS] = {0, 70, 35}; ALLEGRO_COLOR grey; ALLEGRO_COLOR black; int x; int y; x = 400 + offset[but-1]; y = 130; grey = al_map_rgb(0xe0, 0xe0, 0xe0); black = al_map_rgb(0, 0, 0); al_draw_filled_rectangle(x, y, x + 27, y + 42, grey); al_draw_rectangle(x + 0.5, y + 0.5, x + 26.5, y + 41.5, black, 0); if (down) { al_draw_filled_rectangle(x + 2, y + 2, x + 25, y + 40, black); } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *cursor; ALLEGRO_MOUSE_STATE msestate; ALLEGRO_KEYBOARD_STATE kbdstate; int i; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_install_mouse(); al_install_keyboard(); al_init_image_addon(); init_platform_specific(); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } al_hide_mouse_cursor(display); cursor = al_load_bitmap("data/cursor.tga"); if (!cursor) { abort_example("Error loading cursor.tga\n"); } do { al_get_mouse_state(&msestate); al_get_keyboard_state(&kbdstate); al_clear_to_color(al_map_rgb(0xff, 0xff, 0xc0)); for (i = 1; i <= NUM_BUTTONS; i++) { draw_mouse_button(i, al_mouse_button_down(&msestate, i)); } al_draw_bitmap(cursor, msestate.x, msestate.y, 0); al_flip_display(); al_rest(0.005); } while (!al_key_down(&kbdstate, ALLEGRO_KEY_ESCAPE)); return 0; } allegro5-5.2.10.1/examples/ex_mouse_cursor.c000066400000000000000000000134561473414355200206740ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. */ #include #include #include "allegro5/allegro_image.h" #include "common.c" typedef struct { int system_cursor; const char *label; } CursorList; #define MARGIN_LEFT 20 #define MARGIN_TOP 20 #define NUM_CURSORS 20 CursorList cursor_list[NUM_CURSORS] = { { ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT, "DEFAULT" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW, "ARROW" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_BUSY, "BUSY" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_QUESTION, "QUESTION" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT, "EDIT" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE, "MOVE" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N, "RESIZE_N" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_W, "RESIZE_W" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_S, "RESIZE_S" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E, "RESIZE_E" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW, "RESIZE_NW" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_SW, "RESIZE_SW" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_SE, "RESIZE_SE" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE, "RESIZE_NE" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_PROGRESS, "PROGRESS" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_PRECISION, "PRECISION" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_LINK, "LINK" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_ALT_SELECT, "ALT_SELECT" }, { ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE, "UNAVAILABLE" }, { -1, "CUSTOM" } }; int current_cursor[2] = { 0, 0 }; static void draw_display(ALLEGRO_FONT *font) { int th; int i; al_clear_to_color(al_map_rgb(128, 128, 128)); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); th = al_get_font_line_height(font); for (i = 0; i < NUM_CURSORS; i++) { al_draw_text(font, al_map_rgba_f(0, 0, 0, 1), MARGIN_LEFT, MARGIN_TOP + i * th, 0, cursor_list[i].label); } i++; al_draw_text(font, al_map_rgba_f(0, 0, 0, 1), MARGIN_LEFT, MARGIN_TOP + i * th, 0, "Press S/H to show/hide cursor"); al_flip_display(); } static int hover(ALLEGRO_FONT *font, int y) { int th; int i; if (y < MARGIN_TOP) return -1; th = al_get_font_line_height(font); i = (y - MARGIN_TOP) / th; if (i < NUM_CURSORS) return i; return -1; } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display1; ALLEGRO_DISPLAY *display2; ALLEGRO_BITMAP *bmp; ALLEGRO_BITMAP *shrunk_bmp; ALLEGRO_MOUSE_CURSOR *custom_cursor; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_FONT *font; ALLEGRO_EVENT event; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_image_addon(); init_platform_specific(); if (!al_install_mouse()) { abort_example("Error installing mouse\n"); } if (!al_install_keyboard()) { abort_example("Error installing keyboard\n"); } al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS); display1 = al_create_display(400, 400); if (!display1) { abort_example("Error creating display1\n"); } display2 = al_create_display(400, 400); if (!display2) { abort_example("Error creating display2\n"); } bmp = al_load_bitmap("data/allegro.pcx"); if (!bmp) { abort_example("Error loading data/allegro.pcx\n"); } font = al_load_bitmap_font("data/fixed_font.tga"); if (!font) { abort_example("Error loading data/fixed_font.tga\n"); } shrunk_bmp = al_create_bitmap(32, 32); if (!shrunk_bmp) { abort_example("Error creating shrunk_bmp\n"); } al_set_target_bitmap(shrunk_bmp); al_draw_scaled_bitmap(bmp, 0, 0, al_get_bitmap_width(bmp), al_get_bitmap_height(bmp), 0, 0, 32, 32, 0); custom_cursor = al_create_mouse_cursor(shrunk_bmp, 0, 0); if (!custom_cursor) { abort_example("Error creating mouse cursor\n"); } al_set_target_bitmap(NULL); al_destroy_bitmap(shrunk_bmp); al_destroy_bitmap(bmp); shrunk_bmp = NULL; bmp = NULL; queue = al_create_event_queue(); if (!queue) { abort_example("Error creating event queue\n"); } al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_display_event_source(display1)); al_register_event_source(queue, al_get_display_event_source(display2)); al_set_target_backbuffer(display1); draw_display(font); al_set_target_backbuffer(display2); draw_display(font); while (1) { al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } if (event.type == ALLEGRO_EVENT_DISPLAY_EXPOSE) { al_set_target_backbuffer(event.display.source); draw_display(font); continue; } if (event.type == ALLEGRO_EVENT_KEY_CHAR) { switch (event.keyboard.unichar) { case 27: /* escape */ goto Quit; case 'h': al_hide_mouse_cursor(event.keyboard.display); break; case 's': al_show_mouse_cursor(event.keyboard.display); break; default: break; } } if (event.type == ALLEGRO_EVENT_MOUSE_AXES) { int dpy = (event.mouse.display == display1) ? 0 : 1; int i = hover(font, event.mouse.y); if (i >= 0 && current_cursor[dpy] != i) { if (cursor_list[i].system_cursor != -1) { al_set_system_mouse_cursor(event.mouse.display, cursor_list[i].system_cursor); } else { al_set_mouse_cursor(event.mouse.display, custom_cursor); } current_cursor[dpy] = i; } } } Quit: al_destroy_mouse_cursor(custom_cursor); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_mouse_events.c000066400000000000000000000123671473414355200206630ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_primitives.h" #include "common.c" #define NUM_BUTTONS 5 static int actual_buttons; static void draw_mouse_button(int but, bool down) { const int offset[NUM_BUTTONS] = {0, 70, 35, 105, 140}; ALLEGRO_COLOR grey; ALLEGRO_COLOR black; int x; int y; x = 400 + offset[but]; y = 130; grey = al_map_rgb(0xe0, 0xe0, 0xe0); black = al_map_rgb(0, 0, 0); al_draw_filled_rectangle(x, y, x + 27, y + 42, grey); al_draw_rectangle(x + 0.5, y + 0.5, x + 26.5, y + 41.5, black, 0); if (down) { al_draw_filled_rectangle(x + 2, y + 2, x + 25, y + 40, black); } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *cursor; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; ALLEGRO_FONT *font; int mx = 0; int my = 0; int mz = 0; int mw = 0; int mmx = 0; int mmy = 0; int mmz = 0; int mmw = 0; int precision = 1; bool in = true; bool buttons[NUM_BUTTONS] = {false}; int i; float p = 0.0; ALLEGRO_COLOR black; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_install_mouse(); al_install_keyboard(); al_init_image_addon(); al_init_font_addon(); init_platform_specific(); actual_buttons = al_get_mouse_num_buttons(); if (actual_buttons > NUM_BUTTONS) actual_buttons = NUM_BUTTONS; al_set_new_display_flags(ALLEGRO_RESIZABLE); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } // Resize the display - this is to excercise the resizing code wrt. // the cursor display boundary, which requires some special care on some // platforms (such as OSX). al_resize_display(display, 640*1.5, 480*1.5); al_hide_mouse_cursor(display); cursor = al_load_bitmap("data/cursor.tga"); if (!cursor) { abort_example("Error loading cursor.tga\n"); } font = al_load_font("data/fixed_font.tga", 1, 0); if (!font) { abort_example("data/fixed_font.tga not found\n"); } black = al_map_rgb_f(0, 0, 0); queue = al_create_event_queue(); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); while (1) { if (al_is_event_queue_empty(queue)) { al_clear_to_color(al_map_rgb(0xff, 0xff, 0xc0)); for (i = 0; i < actual_buttons; i++) { draw_mouse_button(i, buttons[i]); } al_draw_bitmap(cursor, mx, my, 0); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(font, black, 5, 5, 0, "dx %i, dy %i, dz %i, dw %i", mmx, mmy, mmz, mmw); al_draw_textf(font, black, 5, 25, 0, "x %i, y %i, z %i, w %i", mx, my, mz, mw); al_draw_textf(font, black, 5, 45, 0, "p = %g", p); al_draw_textf(font, black, 5, 65, 0, "%s", in ? "in" : "out"); al_draw_textf(font, black, 5, 85, 0, "wheel precision (PgUp/PgDn) %d", precision); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); mmx = mmy = mmz = 0; al_flip_display(); } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_MOUSE_AXES: mx = event.mouse.x; my = event.mouse.y; mz = event.mouse.z; mw = event.mouse.w; mmx = event.mouse.dx; mmy = event.mouse.dy; mmz = event.mouse.dz; mmw = event.mouse.dw; p = event.mouse.pressure; break; case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: if (event.mouse.button-1 < NUM_BUTTONS) { buttons[event.mouse.button-1] = true; } p = event.mouse.pressure; break; case ALLEGRO_EVENT_MOUSE_BUTTON_UP: if (event.mouse.button-1 < NUM_BUTTONS) { buttons[event.mouse.button-1] = false; } p = event.mouse.pressure; break; case ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY: in = true; break; case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY: in = false; break; case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { goto done; } break; case ALLEGRO_EVENT_KEY_CHAR: if (event.keyboard.keycode == ALLEGRO_KEY_PGUP) { precision++; al_set_mouse_wheel_precision(precision); } else if (event.keyboard.keycode == ALLEGRO_KEY_PGDN) { precision--; if (precision < 1) precision = 1; al_set_mouse_wheel_precision(precision); } break; case ALLEGRO_EVENT_DISPLAY_RESIZE: al_acknowledge_resize(event.display.source); break; case ALLEGRO_EVENT_DISPLAY_CLOSE: goto done; } } done: al_destroy_event_queue(queue); return 0; } /* vim: set sw=3 sts=3 et: */ allegro5-5.2.10.1/examples/ex_mouse_focus.c000066400000000000000000000046421473414355200204730ustar00rootroot00000000000000/* * Example program for the Allegro library. * * This program tests if the ALLEGRO_MOUSE_STATE `display' field * is set correctly. */ #include #include "allegro5/allegro.h" #include "common.c" static ALLEGRO_DISPLAY *display1; static ALLEGRO_DISPLAY *display2; static void redraw(ALLEGRO_COLOR color1, ALLEGRO_COLOR color2) { al_set_target_backbuffer(display1); al_clear_to_color(color1); al_flip_display(); al_set_target_backbuffer(display2); al_clear_to_color(color2); al_flip_display(); } int main(int argc, char **argv) { ALLEGRO_COLOR black; ALLEGRO_COLOR red; ALLEGRO_MOUSE_STATE mst0; ALLEGRO_MOUSE_STATE mst; ALLEGRO_KEYBOARD_STATE kst; (void)argc; (void)argv; if (!al_init()) { abort_example("Couldn't initialise Allegro.\n"); } if (!al_install_mouse()) { abort_example("Couldn't install mouse.\n"); } if (!al_install_keyboard()) { abort_example("Couldn't install keyboard.\n"); } display1 = al_create_display(300, 300); display2 = al_create_display(300, 300); if (!display1 || !display2) { al_destroy_display(display1); al_destroy_display(display2); abort_example("Couldn't open displays.\n"); } open_log(); log_printf("Move the mouse cursor over the displays\n"); black = al_map_rgb(0, 0, 0); red = al_map_rgb(255, 0, 0); memset(&mst0, 0, sizeof(mst0)); while (1) { al_get_mouse_state(&mst); if (mst.display != mst0.display || mst.x != mst0.x || mst.y != mst0.y) { if (mst.display == NULL) log_printf("Outside either display\n"); else if (mst.display == display1) log_printf("In display 1, x = %d, y = %d\n", mst.x, mst.y); else if (mst.display == display2) log_printf("In display 2, x = %d, y = %d\n", mst.x, mst.y); else { log_printf("Unknown display = %p, x = %d, y = %d\n", mst.display, mst.x, mst.y); } mst0 = mst; } if (mst.display == display1) { redraw(red, black); } else if (mst.display == display2) { redraw(black, red); } else { redraw(black, black); } al_rest(0.1); al_get_keyboard_state(&kst); if (al_key_down(&kst, ALLEGRO_KEY_ESCAPE)) { break; } } close_log(false); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_mouse_warp.c000066400000000000000000000067301473414355200203250ustar00rootroot00000000000000#include #include #include #include #include "common.c" int width = 640; int height = 480; int main(int argc, char **argv) { ALLEGRO_FONT *font; ALLEGRO_DISPLAY *display; ALLEGRO_EVENT_QUEUE *event_queue; ALLEGRO_EVENT event; bool right_button_down = false; bool redraw = true; int fake_x = 0, fake_y = 0; ALLEGRO_COLOR white; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); al_init_primitives_addon(); al_init_font_addon(); al_install_mouse(); al_install_keyboard(); al_set_new_display_flags(ALLEGRO_WINDOWED); display = al_create_display(width, height); if (!display) { abort_example("Could not create display.\n"); } memset(&event, 0, sizeof(event)); event_queue = al_create_event_queue(); al_register_event_source(event_queue, al_get_display_event_source(display)); al_register_event_source(event_queue, al_get_mouse_event_source()); al_register_event_source(event_queue, al_get_keyboard_event_source()); font = al_create_builtin_font(); white = al_map_rgb_f(1, 1, 1); while (1) { if (redraw && al_is_event_queue_empty(event_queue)) { int th = al_get_font_line_height(font); al_clear_to_color(al_map_rgb_f(0, 0, 0)); if (right_button_down) { al_draw_line(width / 2, height / 2, fake_x, fake_y, al_map_rgb_f(1, 0, 0), 1); al_draw_line(fake_x - 5, fake_y, fake_x + 5, fake_y, al_map_rgb_f(1, 1, 1), 2); al_draw_line(fake_x, fake_y - 5, fake_x, fake_y + 5, al_map_rgb_f(1, 1, 1), 2); } al_draw_textf(font, white, 0, 0, 0, "x: %i y: %i dx: %i dy %i", event.mouse.x, event.mouse.y, event.mouse.dx, event.mouse.dy); al_draw_textf(font, white, width / 2, height / 2 - th, ALLEGRO_ALIGN_CENTRE, "Left-Click to warp pointer to the middle once."); al_draw_textf(font, white, width / 2, height / 2, ALLEGRO_ALIGN_CENTRE, "Hold right mouse button to constantly move pointer to the middle."); al_flip_display(); redraw = false; } al_wait_for_event(event_queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; } if (event.type == ALLEGRO_EVENT_MOUSE_WARPED) { log_printf("Warp\n"); } if (event.type == ALLEGRO_EVENT_MOUSE_AXES) { if (right_button_down) { al_set_mouse_xy(display, width / 2, height / 2); fake_x += event.mouse.dx; fake_y += event.mouse.dy; } redraw = true; } if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { if (event.mouse.button == 1) al_set_mouse_xy(display, width / 2, height / 2); if (event.mouse.button == 2) { right_button_down = true; fake_x = width / 2; fake_y = height / 2; } } if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { if (event.mouse.button == 2) { right_button_down = false; } } } al_destroy_event_queue(event_queue); al_destroy_display(display); close_log(false); return 0; } allegro5-5.2.10.1/examples/ex_multisample.c000066400000000000000000000157051473414355200205020ustar00rootroot00000000000000/* This example demonstrates the effect of multi-sampling on primitives and * bitmaps. * * * In the window without multi-sampling, the edge of the colored lines will not * be anti-aliased - each pixel is either filled completely with the primitive * color or not at all. * * The same is true for bitmaps. They will always be drawn at the nearest * full-pixel position. However this is only true for the bitmap outline - * when texture filtering is enabled the texture itself will honor the sub-pixel * position. * * Therefore in the case with no multi-sampling but texture-filtering the * outer black edge will stutter in one-pixel steps while the inside edge will * be filtered and appear smooth. * * * In the multi-sampled version the colored lines will be anti-aliased. * * Same with the bitmaps. This means the bitmap outlines will always move in * smooth sub-pixel steps. However if texture filtering is turned off the * texels still are rounded to the next integer position. * * Therefore in the case where multi-sampling is enabled but texture-filtering * is not the outer bitmap edges will move smoothly but the inner will not. */ #include #include #include #include #include #include #include "common.c" static ALLEGRO_FONT *font, *font_ms; static ALLEGRO_BITMAP *bitmap_normal; static ALLEGRO_BITMAP *bitmap_filter; static ALLEGRO_BITMAP *bitmap_normal_ms; static ALLEGRO_BITMAP *bitmap_filter_ms; static float bitmap_x[8], bitmap_y[8]; static float bitmap_t; static ALLEGRO_BITMAP *create_bitmap(void) { const int checkers_size = 8; const int bitmap_size = 24; ALLEGRO_BITMAP *bitmap; ALLEGRO_LOCKED_REGION *locked; int x, y, p; unsigned char *rgba; bitmap = al_create_bitmap(bitmap_size, bitmap_size); locked = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ABGR_8888, 0); rgba = locked->data; p = locked->pitch; for (y = 0; y < bitmap_size; y++) { for (x = 0; x < bitmap_size; x++) { int c = (((x / checkers_size) + (y / checkers_size)) & 1) * 255; rgba[y * p + x * 4 + 0] = 0; rgba[y * p + x * 4 + 1] = 0; rgba[y * p + x * 4 + 2] = 0; rgba[y * p + x * 4 + 3] = c; } } al_unlock_bitmap(bitmap); return bitmap; } static void bitmap_move(void) { int i; bitmap_t++; for (i = 0; i < 8; i++) { float a = 2 * ALLEGRO_PI * i / 16; float s = sin((bitmap_t + i * 40) / 180 * ALLEGRO_PI); s *= 90; bitmap_x[i] = 100 + s * cos(a); bitmap_y[i] = 100 + s * sin(a); } } static void draw(ALLEGRO_BITMAP *bitmap, int y, char const *text) { int i; al_draw_text(font_ms, al_map_rgb(0, 0, 0), 0, y, 0, text); for (i = 0; i < 16; i++) { float a = 2 * ALLEGRO_PI * i / 16; ALLEGRO_COLOR c = al_color_hsv(i * 360 / 16, 1, 1); al_draw_line(150 + cos(a) * 10, y + 100 + sin(a) * 10, 150 + cos(a) * 90, y + 100 + sin(a) * 90, c, 3); } for (i = 0; i < 8; i++) { float a = 2 * ALLEGRO_PI * i / 16; int s = al_get_bitmap_width(bitmap); al_draw_rotated_bitmap(bitmap, s / 2, s / 2, 50 + bitmap_x[i], y + bitmap_y[i], a, 0); } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display, *ms_display; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_TIMER *timer; ALLEGRO_BITMAP *memory; char title[1024]; bool quit = false; bool redraw = true; int wx, wy; (void)argc; (void)argv; if (!al_init()) { abort_example("Couldn't initialise Allegro.\n"); } al_init_primitives_addon(); al_install_keyboard(); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); memory = create_bitmap(); /* Create the normal display. */ al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 0, ALLEGRO_REQUIRE); al_set_new_display_option(ALLEGRO_SAMPLES, 0, ALLEGRO_SUGGEST); display = al_create_display(300, 450); if (!display) { abort_example("Error creating display\n"); } al_set_window_title(display, "Normal"); /* Create bitmaps for the normal display. */ al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); bitmap_filter = al_clone_bitmap(memory); al_set_new_bitmap_flags(0); bitmap_normal = al_clone_bitmap(memory); font = al_create_builtin_font(); al_get_window_position(display, &wx, &wy); if (wx < 160) wx = 160; /* Create the multi-sampling display. */ al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_REQUIRE); al_set_new_display_option(ALLEGRO_SAMPLES, 4, ALLEGRO_SUGGEST); ms_display = al_create_display(300, 450); if (!ms_display) { abort_example("Multisampling not available.\n"); } sprintf(title, "Multisampling (%dx)", al_get_display_option( ms_display, ALLEGRO_SAMPLES)); al_set_window_title(ms_display, title); /* Create bitmaps for the multi-sampling display. */ al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); bitmap_filter_ms = al_clone_bitmap(memory); al_set_new_bitmap_flags(0); bitmap_normal_ms = al_clone_bitmap(memory); font_ms = al_create_builtin_font(); /* Move the windows next to each other, because some window manager * would put them on top of each other otherwise. */ al_set_window_position(display, wx - 160, wy); al_set_window_position(ms_display, wx + 160, wy); timer = al_create_timer(1.0 / 30.0); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_display_event_source(ms_display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (!quit) { ALLEGRO_EVENT event; /* Check for ESC key or close button event and quit in either case. */ al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: quit = true; break; case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) quit = true; break; case ALLEGRO_EVENT_TIMER: bitmap_move(); redraw = true; break; } if (redraw && al_is_event_queue_empty(queue)) { /* Draw the multi-sampled version into the first window. */ al_set_target_backbuffer(ms_display); al_clear_to_color(al_map_rgb_f(1, 1, 1)); draw(bitmap_filter_ms, 0, "filtered, multi-sample"); draw(bitmap_normal_ms, 250, "no filter, multi-sample"); al_flip_display(); /* Draw the normal version into the second window. */ al_set_target_backbuffer(display); al_clear_to_color(al_map_rgb_f(1, 1, 1)); draw(bitmap_filter, 0, "filtered"); draw(bitmap_normal, 250, "no filter"); al_flip_display(); redraw = false; } } return 0; } allegro5-5.2.10.1/examples/ex_multisample_target.c000066400000000000000000000152641473414355200220500ustar00rootroot00000000000000#define ALLEGRO_UNSTABLE #include #include #include #include #include #include #include #include "common.c" #define FPS 60 static struct Example { ALLEGRO_BITMAP *targets[4]; ALLEGRO_BITMAP *bitmap_normal; ALLEGRO_BITMAP *bitmap_filter; ALLEGRO_BITMAP *sub; ALLEGRO_FONT *font; float bitmap_x[8], bitmap_y[8]; float bitmap_t; int step_t, step_x, step_y; ALLEGRO_BITMAP *step[4]; bool update_step; } example; static ALLEGRO_BITMAP *create_bitmap(void) { const int checkers_size = 8; const int bitmap_size = 24; ALLEGRO_BITMAP *bitmap; ALLEGRO_LOCKED_REGION *locked; int x, y, p; unsigned char *rgba; bitmap = al_create_bitmap(bitmap_size, bitmap_size); locked = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ABGR_8888, 0); rgba = locked->data; p = locked->pitch; for (y = 0; y < bitmap_size; y++) { for (x = 0; x < bitmap_size; x++) { int c = (((x / checkers_size) + (y / checkers_size)) & 1) * 255; rgba[y * p + x * 4 + 0] = 0; rgba[y * p + x * 4 + 1] = 0; rgba[y * p + x * 4 + 2] = 0; rgba[y * p + x * 4 + 3] = c; } } al_unlock_bitmap(bitmap); return bitmap; } static void init(void) { al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); ALLEGRO_BITMAP *memory = create_bitmap(); al_set_new_bitmap_flags(0); al_set_new_bitmap_samples(0); example.targets[0] = al_create_bitmap(300, 200); example.targets[1] = al_create_bitmap(300, 200); al_set_new_bitmap_samples(4); example.targets[2] = al_create_bitmap(300, 200); example.targets[3] = al_create_bitmap(300, 200); al_set_new_bitmap_samples(0); al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); example.bitmap_filter = al_clone_bitmap(memory); al_set_new_bitmap_flags(0); example.bitmap_normal = al_clone_bitmap(memory); example.sub = al_create_sub_bitmap(memory, 0, 0, 30, 30); example.step[0] = al_create_bitmap(30, 30); example.step[1] = al_create_bitmap(30, 30); example.step[2] = al_create_bitmap(30, 30); example.step[3] = al_create_bitmap(30, 30); } static void bitmap_move(void) { int i; example.bitmap_t++; for (i = 0; i < 8; i++) { float a = 2 * ALLEGRO_PI * i / 16; float s = sin((example.bitmap_t + i * 40) / 180 * ALLEGRO_PI); s *= 90; example.bitmap_x[i] = 100 + s * cos(a); example.bitmap_y[i] = 100 + s * sin(a); } } static void draw(char const *text, ALLEGRO_BITMAP *bitmap) { int i; al_clear_to_color(al_color_name("white")); al_draw_text(example.font, al_map_rgb(0, 0, 0), 0, 0, 0, text); for (i = 0; i < 16; i++) { float a = 2 * ALLEGRO_PI * i / 16; ALLEGRO_COLOR c = al_color_hsv(i * 360 / 16, 1, 1); al_draw_line(100 + cos(a) * 10, 100 + sin(a) * 10, 100 + cos(a) * 90, 100 + sin(a) * 90, c, 3); } for (i = 0; i < 8; i++) { float a = 2 * ALLEGRO_PI * i / 16; int s = al_get_bitmap_width(bitmap); al_draw_rotated_bitmap(bitmap, s / 2, s / 2, example.bitmap_x[i], example.bitmap_y[i], a, 0); } } static void redraw(void) { al_set_target_bitmap(example.targets[1]); draw("filtered", example.bitmap_filter); al_set_target_bitmap(example.targets[0]); draw("no filter", example.bitmap_normal); al_set_target_bitmap(example.targets[3]); draw("filtered, multi-sample x4", example.bitmap_filter); al_set_target_bitmap(example.targets[2]); draw("no filter, multi-sample x4", example.bitmap_normal); float x = example.step_x; float y = example.step_y; if (example.update_step) { int i; for (i = 0; i < 4; i++) { al_set_target_bitmap(example.step[i]); al_reparent_bitmap(example.sub, example.targets[i], x, y, 30, 30); al_draw_bitmap(example.sub, 0, 0, 0); } example.update_step = false; } al_set_target_backbuffer(al_get_current_display()); al_clear_to_color(al_map_rgb_f(0.5, 0, 0)); al_draw_bitmap(example.targets[0], 20, 20, 0); al_draw_bitmap(example.targets[1], 20, 240, 0); al_draw_bitmap(example.targets[2], 340, 20, 0); al_draw_bitmap(example.targets[3], 340, 240, 0); al_draw_scaled_rotated_bitmap(example.step[0], 15, 15, 320 - 50, 220 - 50, 4, 4, 0, 0); al_draw_scaled_rotated_bitmap(example.step[1], 15, 15, 320 - 50, 440 - 50, 4, 4, 0, 0); al_draw_scaled_rotated_bitmap(example.step[2], 15, 15, 640 - 50, 220 - 50, 4, 4, 0, 0); al_draw_scaled_rotated_bitmap(example.step[3], 15, 15, 640 - 50, 440 - 50, 4, 4, 0, 0); } static void update(void) { bitmap_move(); if (example.step_t == 0) { example.step_x = example.bitmap_x[1] - 15; example.step_y = example.bitmap_y[1] - 15; example.step_t = 60; example.update_step = true; } example.step_t--; } int main(int argc, char **argv) { ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_DISPLAY *display; int w = 20 + 300 + 20 + 300 + 20, h = 20 + 200 + 20 + 200 + 20; bool done = false; bool need_redraw = true; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } if (!al_init_image_addon()) { abort_example("Failed to init IIO addon.\n"); } al_init_font_addon(); example.font = al_create_builtin_font(); al_init_primitives_addon(); init_platform_specific(); display = al_create_display(w, h); if (!display) { abort_example("Error creating display.\n"); } if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } init(); timer = al_create_timer(1.0 / FPS); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(display)); al_start_timer(timer); while (!done) { ALLEGRO_EVENT event; if (need_redraw) { redraw(); al_flip_display(); need_redraw = false; } while (true) { al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_CHAR: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_TIMER: update(); need_redraw = true; break; } if (al_is_event_queue_empty(queue)) break; } } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_multiwin.c000066400000000000000000000072131473414355200200110ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "common.c" const int W = 640; const int H = 400; int main(int argc, char **argv) { ALLEGRO_DISPLAY *display[2]; ALLEGRO_EVENT event; ALLEGRO_EVENT_QUEUE *events; ALLEGRO_BITMAP *pictures[2]; ALLEGRO_BITMAP *target; int width, height; int i; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); al_install_keyboard(); al_install_mouse(); al_init_image_addon(); events = al_create_event_queue(); al_set_new_display_flags(ALLEGRO_WINDOWED|ALLEGRO_RESIZABLE); /* Create two windows. */ display[0] = al_create_display(W, H); if (!display[0]) { abort_example("Error creating display\n"); } pictures[0] = al_load_bitmap("data/mysha.pcx"); if (!pictures[0]) { abort_example("failed to load mysha.pcx\n"); } display[1] = al_create_display(W, H); if (!display[1]) { abort_example("Error creating display\n"); } pictures[1] = al_load_bitmap("data/allegro.pcx"); if (!pictures[1]) { abort_example("failed to load allegro.pcx\n"); } /* This is only needed since we want to receive resize events. */ al_register_event_source(events, al_get_display_event_source(display[0])); al_register_event_source(events, al_get_display_event_source(display[1])); al_register_event_source(events, al_get_keyboard_event_source()); while (1) { /* read input */ while (!al_is_event_queue_empty(events)) { al_get_next_event(events, &event); if (event.type == ALLEGRO_EVENT_KEY_DOWN) { ALLEGRO_KEYBOARD_EVENT *key = &event.keyboard; if (key->keycode == ALLEGRO_KEY_ESCAPE) { goto done; } } if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { ALLEGRO_DISPLAY_EVENT *de = &event.display; al_acknowledge_resize(de->source); } if (event.type == ALLEGRO_EVENT_DISPLAY_SWITCH_IN) { log_printf("%p switching in\n", event.display.source); } if (event.type == ALLEGRO_EVENT_DISPLAY_SWITCH_OUT) { log_printf("%p switching out\n", event.display.source); } if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { int i; for (i = 0; i < 2; i++) { if (display[i] == event.display.source) display[i] = 0; } al_destroy_display(event.display.source); for (i = 0; i < 2; i++) { if (display[i]) goto not_done; } goto done; not_done: ; } } for (i = 0; i < 2; i++) { if (!display[i]) continue; target = al_get_backbuffer(display[i]); width = al_get_bitmap_width(target); height = al_get_bitmap_height(target); al_set_target_bitmap(target); al_draw_scaled_bitmap(pictures[0], 0, 0, al_get_bitmap_width(pictures[0]), al_get_bitmap_height(pictures[0]), 0, 0, width / 2, height, 0); al_draw_scaled_bitmap(pictures[1], 0, 0, al_get_bitmap_width(pictures[1]), al_get_bitmap_height(pictures[1]), width / 2, 0, width / 2, height, 0); al_flip_display(); } al_rest(0.001); } done: al_destroy_bitmap(pictures[0]); al_destroy_bitmap(pictures[1]); al_destroy_display(display[0]); al_destroy_display(display[1]); close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_native_filechooser.c000066400000000000000000000300771473414355200220150ustar00rootroot00000000000000/* * Example program for the Allegro library. * * The native file dialog addon only supports a blocking interface. This * example makes the blocking call from another thread, using a user event * source to communicate back to the main program. */ #define ALLEGRO_UNSTABLE #include #include #include #include #include #include #ifdef ALLEGRO_ANDROID #include #endif #include "common.c" /* To communicate from a separate thread, we need a user event. */ #define ASYNC_DIALOG_EVENT1 ALLEGRO_GET_EVENT_TYPE('e', 'N', 'F', '1') #define ASYNC_DIALOG_EVENT2 ALLEGRO_GET_EVENT_TYPE('e', 'N', 'F', '2') typedef struct { ALLEGRO_DISPLAY *display; ALLEGRO_FILECHOOSER *file_dialog; ALLEGRO_EVENT_SOURCE event_source; ALLEGRO_THREAD *thread; } AsyncDialog; ALLEGRO_TEXTLOG *textlog; static void message(char const *format, ...) { char str[1024]; va_list args; va_start(args, format); vsnprintf(str, sizeof str, format, args); va_end(args); al_append_native_text_log(textlog, "%s", str); } /* Our thread to show the native file dialog. */ static void *async_file_dialog_thread_func(ALLEGRO_THREAD *thread, void *arg) { AsyncDialog *data = arg; ALLEGRO_EVENT event; (void)thread; /* The next line is the heart of this example - we display the * native file dialog. */ al_show_native_file_dialog(data->display, data->file_dialog); /* We emit an event to let the main program know that the thread has * finished. */ event.user.type = ASYNC_DIALOG_EVENT1; al_emit_user_event(&data->event_source, &event, NULL); return NULL; } /* A thread to show the message boxes. */ static void *message_box_thread(ALLEGRO_THREAD *thread, void *arg) { AsyncDialog *data = arg; ALLEGRO_EVENT event; int button; (void)thread; button = al_show_native_message_box(data->display, "Warning", "Click Detected", "That does nothing. Stop clicking there.", "Oh no!|Don't press|Ok", ALLEGRO_MESSAGEBOX_WARN); if (button == 2) { button = al_show_native_message_box(data->display, "Error", "Hey!", "Stop it! I told you not to click there.", NULL, ALLEGRO_MESSAGEBOX_ERROR); } event.user.type = ASYNC_DIALOG_EVENT2; al_emit_user_event(&data->event_source, &event, NULL); return NULL; } /* Function to start the new thread. */ static AsyncDialog *spawn_async_file_dialog(ALLEGRO_DISPLAY *display, const char *initial_path, bool save) { AsyncDialog *data = malloc(sizeof *data); int flags = save ? ALLEGRO_FILECHOOSER_SAVE : ALLEGRO_FILECHOOSER_MULTIPLE; const char* title = save ? "Save (no files will be changed)" : "Choose files"; data->file_dialog = al_create_native_file_dialog( initial_path, title, NULL, flags); al_init_user_event_source(&data->event_source); data->display = display; data->thread = al_create_thread(async_file_dialog_thread_func, data); al_start_thread(data->thread); return data; } static AsyncDialog *spawn_async_message_dialog(ALLEGRO_DISPLAY *display) { AsyncDialog *data = calloc(1, sizeof *data); al_init_user_event_source(&data->event_source); data->display = display; data->thread = al_create_thread(message_box_thread, data); al_start_thread(data->thread); return data; } static void stop_async_dialog(AsyncDialog *data) { if (data) { al_destroy_thread(data->thread); al_destroy_user_event_source(&data->event_source); if (data->file_dialog) al_destroy_native_file_dialog(data->file_dialog); free(data); } } /* Helper function to display the result from a file dialog. */ static void show_files_list(ALLEGRO_FILECHOOSER *dialog, const ALLEGRO_FONT *font, ALLEGRO_COLOR info) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); int count = al_get_native_file_dialog_count(dialog); int th = al_get_font_line_height(font); float x = al_get_bitmap_width(target) / 2; float y = al_get_bitmap_height(target) / 2 - (count * th) / 2; int i; for (i = 0; i < count; i++) { const char *name = al_get_native_file_dialog_path(dialog, i); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(font, info, x, y + i * th, ALLEGRO_ALIGN_CENTRE, name, 0, 0); } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_FONT *font; ALLEGRO_COLOR background, active, inactive, info; AsyncDialog *old_dialog = NULL; AsyncDialog *cur_dialog = NULL; AsyncDialog *message_box = NULL; bool redraw = false; bool halt_drawing = false; bool close_log = false; int button; bool message_log = true; bool touch; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } if (!al_init_native_dialog_addon()) { abort_example("Could not init native dialog addon.\n"); } textlog = al_open_native_text_log("Log", 0); message("Starting up log window.\n"); al_init_image_addon(); al_init_font_addon(); background = al_color_name("white"); active = al_color_name("black"); inactive = al_color_name("gray"); info = al_color_name("red"); al_install_mouse(); touch = al_install_touch_input(); al_install_keyboard(); if (touch) { al_set_mouse_emulation_mode(ALLEGRO_MOUSE_EMULATION_5_0_x); } message("Creating window..."); #ifdef ALLEGRO_IPHONE al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW); #endif display = al_create_display(640, 480); if (!display) { message("failure.\n"); abort_example("Error creating display\n"); } message("success.\n"); #ifdef ALLEGRO_ANDROID al_android_set_apk_file_interface(); #endif message("Loading font '%s'...", "data/fixed_font.tga"); font = al_load_font("data/fixed_font.tga", 0, 0); if (!font) { message("failure.\n"); abort_example("Error loading data/fixed_font.tga\n"); } message("success.\n"); timer = al_create_timer(1.0 / 30); restart: message("Starting main loop.\n"); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); if (touch) { al_register_event_source(queue, al_get_touch_input_event_source()); al_register_event_source(queue, al_get_touch_input_mouse_emulation_event_source()); } al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); if (textlog) { al_register_event_source(queue, al_get_native_text_log_event_source( textlog)); } al_start_timer(timer); while (1) { float h = al_get_display_height(display); ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE && !cur_dialog) break; if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (!cur_dialog) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE || event.keyboard.keycode == ALLEGRO_KEY_BACK) break; } } /* When a mouse button is pressed, and no native dialog is * shown already, we show a new one. */ if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { message("Mouse clicked at %d,%d.\n", event.mouse.x, event.mouse.y); if (event.mouse.y > 30) { if (event.mouse.y > h - 30) { message_log = !message_log; if (message_log) { textlog = al_open_native_text_log("Log", 0); if (textlog) { al_register_event_source(queue, al_get_native_text_log_event_source(textlog)); } } else { close_log = true; } } else if (!message_box) { message_box = spawn_async_message_dialog(display); al_register_event_source(queue, &message_box->event_source); } } else if (!cur_dialog) { const char *last_path = NULL; bool save = event.mouse.x > al_get_display_width(display) / 2; /* If available, use the path from the last dialog as * initial path for the new one. */ if (old_dialog) { last_path = al_get_native_file_dialog_path( old_dialog->file_dialog, 0); } cur_dialog = spawn_async_file_dialog(display, last_path, save); al_register_event_source(queue, &cur_dialog->event_source); } } /* We receive this event from the other thread when the dialog is * closed. */ if (event.type == ASYNC_DIALOG_EVENT1) { al_unregister_event_source(queue, &cur_dialog->event_source); /* If files were selected, we replace the old files list. * Otherwise the dialog was cancelled, and we keep the old results. */ if (al_get_native_file_dialog_count(cur_dialog->file_dialog) > 0) { if (old_dialog) stop_async_dialog(old_dialog); old_dialog = cur_dialog; } else { stop_async_dialog(cur_dialog); } cur_dialog = NULL; } if (event.type == ASYNC_DIALOG_EVENT2) { al_unregister_event_source(queue, &message_box->event_source); stop_async_dialog(message_box); message_box = NULL; } if (event.type == ALLEGRO_EVENT_NATIVE_DIALOG_CLOSE) { close_log = true; } if (event.type == ALLEGRO_EVENT_TIMER) { redraw = true; } #ifdef ALLEGRO_ANDROID if (event.type == ALLEGRO_EVENT_DISPLAY_HALT_DRAWING) { message("Drawing halt"); halt_drawing = true; al_stop_timer(timer); al_acknowledge_drawing_halt(display); } if (event.type == ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING) { message("Drawing resume"); al_acknowledge_drawing_resume(display); al_resume_timer(timer); halt_drawing = false; } if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { message("Display resize"); al_acknowledge_resize(display); } #endif if (redraw && !halt_drawing && al_is_event_queue_empty(queue)) { float x = al_get_display_width(display) / 2; float y = 0; redraw = false; al_clear_to_color(background); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(font, cur_dialog ? inactive : active, x/2, y, ALLEGRO_ALIGN_CENTRE, "Open"); al_draw_textf(font, cur_dialog ? inactive : active, x/2*3, y, ALLEGRO_ALIGN_CENTRE, "Save"); al_draw_textf(font, cur_dialog ? inactive : active, x, h - 30, ALLEGRO_ALIGN_CENTRE, message_log ? "Close Message Log" : "Open Message Log"); if (old_dialog) show_files_list(old_dialog->file_dialog, font, info); al_flip_display(); } if (close_log && textlog) { close_log = false; message_log = false; al_unregister_event_source(queue, al_get_native_text_log_event_source(textlog)); al_close_native_text_log(textlog); textlog = NULL; } } message("Exiting.\n"); al_destroy_event_queue(queue); button = al_show_native_message_box(display, "Warning", "Are you sure?", "If you click yes then this example will inevitably close." " This is your last chance to rethink your decision." " Do you really want to quit?", NULL, ALLEGRO_MESSAGEBOX_YES_NO | ALLEGRO_MESSAGEBOX_QUESTION); if (button != 1) goto restart; stop_async_dialog(old_dialog); stop_async_dialog(cur_dialog); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_nodisplay.c000066400000000000000000000031421473414355200201400ustar00rootroot00000000000000/* Test that bitmap manipulation without a display works. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "common.c" int main(int argc, char **argv) { ALLEGRO_BITMAP *bmp; ALLEGRO_BITMAP *sprite; ALLEGRO_COLOR c1, c2, c3; bool rc; (void)argc; (void)argv; if (!al_init()) { abort_example("Error initialising Allegro\n"); } al_init_image_addon(); init_platform_specific(); sprite = al_load_bitmap("data/cursor.tga"); if (!sprite) { abort_example("Error loading data/cursor.tga\n"); } bmp = al_create_bitmap(256, 256); if (!bmp) { abort_example("Error creating bitmap\n"); } al_set_target_bitmap(bmp); c1 = al_map_rgb(255, 0, 0); c2 = al_map_rgb(0, 255, 0); c3 = al_map_rgb(0, 255, 255); al_clear_to_color(al_map_rgba(255, 0, 0, 128)); al_draw_bitmap(sprite, 0, 0, 0); al_draw_tinted_bitmap(sprite, c1, 64, 0, ALLEGRO_FLIP_HORIZONTAL); al_draw_tinted_bitmap(sprite, c2, 0, 64, ALLEGRO_FLIP_VERTICAL); al_draw_tinted_bitmap(sprite, c3, 64, 64, ALLEGRO_FLIP_HORIZONTAL | ALLEGRO_FLIP_VERTICAL); al_set_target_bitmap(NULL); rc = al_save_bitmap("ex_nodisplay_out.tga", bmp); if (rc) { #ifdef ALLEGRO_POPUP_EXAMPLES al_show_native_message_box(NULL, "ex_nodisplay_out", "", "Saved ex_nodisplay_out.tga", NULL, 0); #else printf("Saved ex_nodisplay_out.tga\n"); #endif } else { abort_example("Error saving ex_nodisplay_out.tga\n"); } al_destroy_bitmap(sprite); al_destroy_bitmap(bmp); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_noframe.c000066400000000000000000000050121473414355200175630ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include #include "common.c" int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *bitmap; ALLEGRO_EVENT_QUEUE *events; ALLEGRO_EVENT event; bool down = false; int down_x = 0, down_y = 0; ALLEGRO_TIMER *timer; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_mouse(); al_install_keyboard(); al_init_image_addon(); init_platform_specific(); al_set_new_display_flags(ALLEGRO_FRAMELESS); display = al_create_display(300, 200); if (!display) { abort_example("Error creating display\n"); } bitmap = al_load_bitmap("data/fakeamp.bmp"); if (!bitmap) { abort_example("Error loading fakeamp.bmp\n"); } timer = al_create_timer(1.0f/30.0f); events = al_create_event_queue(); al_register_event_source(events, al_get_mouse_event_source()); al_register_event_source(events, al_get_keyboard_event_source()); al_register_event_source(events, al_get_display_event_source(display)); al_register_event_source(events, al_get_timer_event_source(timer)); al_start_timer(timer); for (;;) { al_wait_for_event(events, &event); if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { if (event.mouse.button == 1 && event.mouse.x) { down = true; down_x = event.mouse.x; down_y = event.mouse.y; } if (event.mouse.button == 2) { al_set_display_flag(display, ALLEGRO_FRAMELESS, !(al_get_display_flags(display) & ALLEGRO_FRAMELESS)); } } else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { if (event.mouse.button == 1) { down = false; } } else if (event.type == ALLEGRO_EVENT_MOUSE_AXES) { if (down) { int cx, cy; if (al_get_mouse_cursor_position(&cx, &cy)) { al_set_window_position(display, cx - down_x, cy - down_y); } } } else if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } else if (event.type == ALLEGRO_EVENT_TIMER) { al_draw_bitmap(bitmap, 0, 0, 0); al_flip_display(); } } al_destroy_timer(timer); al_destroy_event_queue(events); al_destroy_display(display); return 0; } allegro5-5.2.10.1/examples/ex_ogre3d.cpp000066400000000000000000000302011473414355200176550ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * Windows support by AMCerasoli. * * This is a test program to see if Allegro can be used alongside the OGRE * graphics library. It currently only works on Linux/GLX and Windows. * To run, you will need to have OGRE plugins.cfg and resources.cfg files in * the current directory. * * Inputs: W A S D, mouse * * This code is based on the samples in the OGRE distribution. */ #include #include #ifdef ALLEGRO_WINDOWS #include #endif #include /* * Ogre 1.7 (and, optionally, earlier versions) uses the FreeImage library to * handle image loading. FreeImage bundles its own copies of common libraries * like libjpeg and libpng, which can conflict with the system copies of those * libraries that allegro_image uses. That means we can't use allegro_image * safely, nor any of the addons which depend on it. * * One solution would be to write a codec for Ogre that avoids FreeImage, or * write allegro_image handlers using FreeImage. The latter would probably be * easier and useful for other reasons. */ using namespace Ogre; const int WIDTH = 640; const int HEIGHT = 480; const float MOVE_SPEED = 1500.0; class Application { protected: Root *mRoot; RenderWindow *mWindow; SceneManager *mSceneMgr; Camera *mCamera; public: void setup(ALLEGRO_DISPLAY *display) { createRoot(); defineResources(); setupRenderSystem(); createRenderWindow(display); initializeResourceGroups(); chooseSceneManager(); createCamera(); createViewports(); createScene(); } Application() { mRoot = NULL; } ~Application() { delete mRoot; } private: void createRoot() { mRoot = new Root(); } void defineResources() { String secName, typeName, archName; ConfigFile cf; cf.load("resources.cfg"); ConfigFile::SectionIterator seci = cf.getSectionIterator(); while (seci.hasMoreElements()) { secName = seci.peekNextKey(); ConfigFile::SettingsMultiMap *settings = seci.getNext(); ConfigFile::SettingsMultiMap::iterator i; for (i = settings->begin(); i != settings->end(); ++i) { typeName = i->first; archName = i->second; ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName); } } } void setupRenderSystem() { if (!mRoot->restoreConfig() && !mRoot->showConfigDialog()) { throw Exception(52, "User canceled the config dialog!", "Application::setupRenderSystem()"); } } void createRenderWindow(ALLEGRO_DISPLAY *display) { int w = al_get_display_width(display); int h = al_get_display_height(display); // Initialise Ogre without creating a window. mRoot->initialise(false); Ogre::NameValuePairList misc; #ifdef ALLEGRO_WINDOWS unsigned long winHandle = reinterpret_cast(al_get_win_window_handle(display)); unsigned long winGlContext = reinterpret_cast(wglGetCurrentContext()); misc["externalWindowHandle"] = StringConverter::toString(winHandle); misc["externalGLContext"] = StringConverter::toString(winGlContext); misc["externalGLControl"] = String("True"); #else misc["currentGLContext"] = String("True"); #endif mWindow = mRoot->createRenderWindow("MainRenderWindow", w, h, false, &misc); } void initializeResourceGroups() { TextureManager::getSingleton().setDefaultNumMipmaps(5); ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); } virtual void chooseSceneManager() { mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "Default SceneManager"); } virtual void createCamera() { mCamera = mSceneMgr->createCamera("PlayerCam"); mCamera->setPosition(Vector3(-300, 300, -300)); mCamera->lookAt(Vector3(0, 0, 0)); mCamera->setNearClipDistance(5); } virtual void createViewports() { // Create one viewport, entire window. Viewport *vp = mWindow->addViewport(mCamera); vp->setBackgroundColour(ColourValue(0, 0.25, 0.5)); // Alter the camera aspect ratio to match the viewport. mCamera->setAspectRatio( Real(vp->getActualWidth()) / Real(vp->getActualHeight())); } virtual void createScene() = 0; public: void render() { const bool swap_buffers = false; mWindow->update(swap_buffers); mRoot->renderOneFrame(); al_flip_display(); } }; class Example : public Application { private: ALLEGRO_DISPLAY *display; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_TIMER *timer; double startTime; double lastRenderTime; double lastMoveTime; bool lmb; bool rmb; bool forward; bool back; bool left; bool right; float current_speed; Vector3 last_translate; public: Example(ALLEGRO_DISPLAY *display); ~Example(); void setup(); void mainLoop(); private: void createScene(); void moveCamera(double timestamp, Radian rot_x, Radian rot_y, Vector3 & translate); void animate(double now); void nextFrame(); }; Example::Example(ALLEGRO_DISPLAY *display) : display(display), queue(NULL), timer(NULL), startTime(0.0), lastRenderTime(0.0), lastMoveTime(0.0), lmb(false), rmb(false), forward(false), back(false), left(false), right(false), current_speed(0), last_translate(Vector3::ZERO) { } Example::~Example() { if (timer) al_destroy_timer(timer); if (queue) al_destroy_event_queue(queue); } void Example::createScene() { // Enable shadows. mSceneMgr->setAmbientLight(ColourValue(0.5, 0.25, 0.0)); //mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE); // slower mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE); // faster // Create the character. Entity *ent1 = mSceneMgr->createEntity("Ninja", "ninja.mesh"); ent1->setCastShadows(true); mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent1); AnimationState *anim1 = ent1->getAnimationState("Walk"); anim1->setLoop(true); anim1->setEnabled(true); // Create the ground. Plane plane(Vector3::UNIT_Y, 0); MeshManager::getSingleton().createPlane("ground", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 1500, 1500, 20, 20, true, 1, 5, 5, Vector3::UNIT_Z); Entity *ent2 = mSceneMgr->createEntity("GroundEntity", "ground"); ent2->setMaterialName("Examples/Rockwall"); ent2->setCastShadows(false); mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent2); // Create a light. Light *light = mSceneMgr->createLight("Light1"); light->setType(Light::LT_POINT); light->setPosition(Vector3(0, 150, 250)); light->setDiffuseColour(1.0, 1.0, 1.0); light->setSpecularColour(1.0, 0.0, 0.0); } void Example::setup() { Application::setup(display); const double BPS = 60.0; timer = al_create_timer(1.0 / BPS); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(display)); } void Example::mainLoop() { bool redraw = true; startTime = lastMoveTime = al_get_time(); al_start_timer(timer); for (;;) { ALLEGRO_EVENT event; if (al_is_event_queue_empty(queue) && redraw) { nextFrame(); redraw = false; } al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } Radian rot_x(0); Radian rot_y(0); Vector3 translate(Vector3::ZERO); switch (event.type) { case ALLEGRO_EVENT_TIMER: redraw = true; break; case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: if (event.mouse.button == 1) lmb = true; if (event.mouse.button == 2) rmb = true; break; case ALLEGRO_EVENT_MOUSE_BUTTON_UP: if (event.mouse.button == 1) lmb = false; if (event.mouse.button == 2) rmb = false; if (!lmb && !rmb) al_show_mouse_cursor(display); break; case ALLEGRO_EVENT_MOUSE_AXES: if (lmb) { rot_x = Degree(-event.mouse.dx * 0.13); rot_y = Degree(-event.mouse.dy * 0.13); } if (rmb) { translate.x = event.mouse.dx * 0.5; translate.y = event.mouse.dy * -0.5; } if (lmb || rmb) { al_hide_mouse_cursor(display); al_set_mouse_xy(display, al_get_display_width(display)/2, al_get_display_height(display)/2); } break; case ALLEGRO_EVENT_KEY_DOWN: case ALLEGRO_EVENT_KEY_UP: { const bool is_down = (event.type == ALLEGRO_EVENT_KEY_DOWN); if (event.keyboard.keycode == ALLEGRO_KEY_W) forward = is_down; if (event.keyboard.keycode == ALLEGRO_KEY_S) back = is_down; if (event.keyboard.keycode == ALLEGRO_KEY_A) left = is_down; if (event.keyboard.keycode == ALLEGRO_KEY_D) right = is_down; break; } case ALLEGRO_EVENT_DISPLAY_RESIZE: { al_acknowledge_resize(event.display.source); int w = al_get_display_width(display); int h = al_get_display_height(display); mWindow->resize(w, h); mCamera->setAspectRatio(Real(w) / Real(h)); redraw = true; break; } } moveCamera(event.any.timestamp, rot_x, rot_y, translate); } } void Example::moveCamera(double timestamp, Radian rot_x, Radian rot_y, Vector3 & translate) { const double time_since_move = timestamp - lastMoveTime; const float move_scale = MOVE_SPEED * time_since_move; if (forward) { translate.z = -move_scale; } if (back) { translate.z = move_scale; } if (left) { translate.x = -move_scale; } if (right) { translate.x = move_scale; } if (translate == Vector3::ZERO) { // Continue previous motion but dampen. translate = last_translate; current_speed -= time_since_move * 0.3; } else { // Ramp up. current_speed += time_since_move; } if (current_speed > 1.0) current_speed = 1.0; if (current_speed < 0.0) current_speed = 0.0; translate *= current_speed; mCamera->yaw(rot_x); mCamera->pitch(rot_y); mCamera->moveRelative(translate); last_translate = translate; lastMoveTime = timestamp; } void Example::animate(double now) { const double dt0 = now - startTime; const double dt = now - lastRenderTime; // Animate the character. Entity *ent = mSceneMgr->getEntity("Ninja"); AnimationState *anim = ent->getAnimationState("Walk"); anim->addTime(dt); // Move the light around. Light *light = mSceneMgr->getLight("Light1"); light->setPosition(Vector3(300 * cos(dt0), 300, 300 * sin(dt0))); } void Example::nextFrame() { const double now = al_get_time(); animate(now); render(); lastRenderTime = now; } int main(int argc, char *argv[]) { (void)argc; (void)argv; ALLEGRO_DISPLAY *display; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_install_mouse(); al_set_new_display_flags(ALLEGRO_OPENGL | ALLEGRO_RESIZABLE); display = al_create_display(WIDTH, HEIGHT); if (!display) { abort_example("Error creating display\n"); } al_set_window_title(display, "My window"); { Example app(display); app.setup(); app.mainLoop(); } al_uninstall_system(); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_opengl.c000066400000000000000000000115621473414355200174270ustar00rootroot00000000000000#define ALLEGRO_UNSTABLE #include #include #include #include #include "common.c" /* Simple example showing how to use an extension. It draws a yellow triangle * on red background onto a texture, then draws a quad with that texture. */ GLuint tex, fbo; bool no_fbo = false; static void draw_opengl(void) { double secs = al_get_time(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* Let's create a texture. It will only be visible if we cannot draw over * it with the framebuffer extension. */ if (!tex) { unsigned char *pixels = malloc(256 * 256 * 4); int x, y; for (y = 0; y < 256; y++) { for (x = 0; x < 256; x++) { unsigned char r = x, g = y, b = 0, a = 255; pixels[y * 256 * 4 + x * 4 + 0] = r; pixels[y * 256 * 4 + x * 4 + 1] = g; pixels[y * 256 * 4 + x * 4 + 2] = b; pixels[y * 256 * 4 + x * 4 + 3] = a; } } glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); free(pixels); } /* Let's create a framebuffer object. */ if (!fbo && !no_fbo) { /* Did Allegro discover the OpenGL extension for us? */ if (al_get_opengl_extension_list()->ALLEGRO_GL_EXT_framebuffer_object) { /* If yes, then it also filled in the function pointer. How nice. */ glGenFramebuffersEXT(1, &fbo); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); /* Attach the framebuffer object to our texture. */ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0); if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { no_fbo = true; } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } else { /* We are screwed, the extension is not available. */ no_fbo = true; } } /* Draw a yellow triangle on red background to the framebuffer object. */ if (fbo && !no_fbo) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); glPushAttrib(GL_VIEWPORT_BIT | GL_TRANSFORM_BIT); glViewport(0, 0, 256, 256); glClearColor(1, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, 256, 256, 0, -1, 1); glDisable(GL_TEXTURE_2D); glColor3f(1, 1, 0); glTranslatef(128, 128 + sin(secs * ALLEGRO_PI * 2 * 2) * 20, 0); glBegin(GL_TRIANGLES); glVertex2f(0, -100); glVertex2f(100, 0); glVertex2f(-100, 0); glEnd(); glPopMatrix(); glPopAttrib(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } /* Draw a quad with our texture. */ glClearColor(0, 0, 1, 1); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glTranslatef(320, 240, 0); glRotatef(secs * 360 / 4, 0, 0, 1); glColor3f(1, 1, 1); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(-100, -100); glTexCoord2f(1, 0); glVertex2f(+100, -100); glTexCoord2f(1, 1); glVertex2f(+100, +100); glTexCoord2f(0, 1); glVertex2f(-100, +100); glEnd(); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; int frames = 0; double start; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); al_install_keyboard(); al_set_new_display_flags(ALLEGRO_OPENGL); display = al_create_display(640, 480); if (!display) { abort_example("Could not create display.\n"); } queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); start = al_get_time(); while (true) { /* Check for ESC key or close button event and quit in either case. */ if (!al_is_event_queue_empty(queue)) { while (al_get_next_event(queue, &event)) { switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: goto done; case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) goto done; break; } } } draw_opengl(); al_flip_display(); frames++; } done: log_printf("%.1f FPS\n", frames / (al_get_time() - start)); al_destroy_event_queue(queue); al_destroy_display(display); close_log(true); return 0; } allegro5-5.2.10.1/examples/ex_opengl_pixel_shader.c000066400000000000000000000065751473414355200221660ustar00rootroot00000000000000#define ALLEGRO_UNSTABLE #include #include #include #include #include "common.c" GLhandleARB tinter; GLhandleARB tinter_shader; int main(int argc, char **argv) { float r = 0.5, g = 0.5, b = 1, ratio = 0; int dir = 1; ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *mysha; ALLEGRO_BITMAP *buffer; const char *tinter_shader_src[] = { "uniform sampler2D backBuffer;", "uniform float r;", "uniform float g;", "uniform float b;", "uniform float ratio;", "void main() {", " vec4 color;", " float avg, dr, dg, db;", " color = texture2D(backBuffer, gl_TexCoord[0].st);", " avg = (color.r + color.g + color.b) / 3.0;", " dr = avg * r;", " dg = avg * g;", " db = avg * b;", " color.r = color.r - (ratio * (color.r - dr));", " color.g = color.g - (ratio * (color.g - dg));", " color.b = color.b - (ratio * (color.b - db));", " gl_FragColor = color;", "}" }; const int TINTER_LEN = 18; double start; GLint loc; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro\n"); } al_install_keyboard(); al_init_image_addon(); al_set_new_display_flags(ALLEGRO_OPENGL); display = al_create_display(320, 200); if (!display) { abort_example("Error creating display\n"); } mysha = al_load_bitmap("data/mysha.pcx"); if (!mysha) { abort_example("Could not load image.\n"); } buffer = al_create_bitmap(320, 200); if (!al_have_opengl_extension("GL_EXT_framebuffer_object") && !al_have_opengl_extension("GL_ARB_fragment_shader")) { abort_example("Fragment shaders not supported.\n"); } tinter_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); glShaderSourceARB(tinter_shader, TINTER_LEN, tinter_shader_src, NULL); glCompileShaderARB(tinter_shader); tinter = glCreateProgramObjectARB(); glAttachObjectARB(tinter, tinter_shader); glLinkProgramARB(tinter); loc = glGetUniformLocationARB(tinter, "backBuffer"); glUniform1iARB(loc, al_get_opengl_texture(buffer)); start = al_get_time(); while (1) { double now, diff; ALLEGRO_KEYBOARD_STATE state; al_get_keyboard_state(&state); if (al_key_down(&state, ALLEGRO_KEY_ESCAPE)) { break; } now = al_get_time(); diff = now - start; start = now; ratio += diff * 0.5 * dir; if (dir < 0 && ratio < 0) { ratio = 0; dir = -dir; } else if (dir > 0 && ratio > 1) { ratio = 1; dir = -dir; } al_set_target_bitmap(buffer); glUseProgramObjectARB(tinter); loc = glGetUniformLocationARB(tinter, "ratio"); glUniform1fARB(loc, ratio); loc = glGetUniformLocationARB(tinter, "r"); glUniform1fARB(loc, r); loc = glGetUniformLocationARB(tinter, "g"); glUniform1fARB(loc, g); loc = glGetUniformLocationARB(tinter, "b"); glUniform1fARB(loc, b); al_draw_bitmap(mysha, 0, 0, 0); glUseProgramObjectARB(0); al_set_target_backbuffer(display); al_draw_bitmap(buffer, 0, 0, 0); al_flip_display(); al_rest(0.001); } glDetachObjectARB(tinter, tinter_shader); glDeleteObjectARB(tinter_shader); al_uninstall_system(); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_palette.c000066400000000000000000000220231473414355200175730ustar00rootroot00000000000000#include #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_color.h" /* Note: It should be easy using Cg or HLSL instead of GLSL - for the * 5.2 release we should make this a config option and implement all 3 * in any shader examples. */ #include "allegro5/allegro_opengl.h" #include "common.c" int pal_hex[256]; typedef struct { float x, y, angle, t; int flags, i, j; } Sprite; int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *bitmap, *background, *pal_bitmap; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; bool redraw = true; bool show_pal = false; ALLEGRO_SHADER *shader; float pals[7][3 * 256]; int i, j; float t = 0; Sprite sprite[8]; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_mouse(); al_install_keyboard(); al_init_image_addon(); init_platform_specific(); al_set_new_display_flags(ALLEGRO_PROGRAMMABLE_PIPELINE | ALLEGRO_OPENGL); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8); bitmap = al_load_bitmap_flags("data/alexlogo.bmp", ALLEGRO_KEEP_INDEX); if (!bitmap) { abort_example("alexlogo not found or failed to load\n"); } /* Create 8 sprites. */ for (i = 0; i < 8; i++) { Sprite *s = sprite + i; s->angle = ALLEGRO_PI * 2 * i / 8; s->x = 320 + sin(s->angle) * (64 + i * 16); s->y = 240 - cos(s->angle) * (64 + i * 16); s->flags = (i % 2) ? ALLEGRO_FLIP_HORIZONTAL : 0; s->t = i / 8.0; s->i = i % 6; s->j = (s->i + 1) % 6; } background = al_load_bitmap("data/bkg.png"); if (!bitmap) { abort_example("background not found or failed to load\n"); } /* Create 7 palettes with changed hue. */ for (j = 0; j < 7; j++) { for (i = 0; i < 256; i++) { float r, g, b, h, s, l; r = (pal_hex[i] >> 16) / 255.0; g = ((pal_hex[i] >> 8) & 255) / 255.0; b = (pal_hex[i] & 255) / 255.0; al_color_rgb_to_hsl(r, g, b, &h, &s, &l); h += j * 50; al_color_hsl_to_rgb(h, s, l, &r, &g, &b); pals[j][i * 3 + 0] = r; pals[j][i * 3 + 1] = g; pals[j][i * 3 + 2] = b; } } al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY); pal_bitmap = al_create_bitmap(255, 7); al_set_target_bitmap(pal_bitmap); for (int y = 0; y < 7; y++) { for (int x = 0; x < 256; x++) { float r = pals[y][x * 3 + 0] * 255.0; float g = pals[y][x * 3 + 1] * 255.0; float b = pals[y][x * 3 + 2] * 255.0; al_put_pixel(x, y, al_map_rgb(r,g,b)); } } al_set_target_backbuffer(display); shader = al_create_shader(ALLEGRO_SHADER_GLSL); if (!al_attach_shader_source(shader, ALLEGRO_VERTEX_SHADER, al_get_default_shader_source(ALLEGRO_SHADER_AUTO, ALLEGRO_VERTEX_SHADER))) { abort_example("al_attach_shader_source for vertex shader failed: %s\n", al_get_shader_log(shader)); } if (!al_attach_shader_source_file(shader, ALLEGRO_PIXEL_SHADER, "data/ex_shader_palette_pixel.glsl")) { abort_example("al_attach_shader_source_file for pixel shader failed: %s\n", al_get_shader_log(shader)); } if (!al_build_shader(shader)) abort_example("al_build_shader failed: %s\n", al_get_shader_log(shader)); al_use_shader(shader); timer = al_create_timer(1.0 / 60); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); al_set_shader_sampler("pal_tex", pal_bitmap, 1); log_printf("%s\n", "Press P to toggle displaying the palette"); while (1) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; if (event.type == ALLEGRO_EVENT_KEY_CHAR) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; if (event.keyboard.keycode == ALLEGRO_KEY_P) show_pal = !show_pal; } if (event.type == ALLEGRO_EVENT_TIMER) { redraw = true; t++; for (i = 0; i < 8; i++) { Sprite *s = sprite + i; int dir = s->flags ? 1 : -1; s->x += cos(s->angle) * 2 * dir; s->y += sin(s->angle) * 2 * dir; s->angle += ALLEGRO_PI / 180.0 * dir; } } if (redraw && al_is_event_queue_empty(queue)) { float pos = (int)t % 60 / 60.0; int p1 = (int)(t / 60) % 3; int p2 = (p1 + 1) % 3; redraw = false; al_clear_to_color(al_map_rgb_f(0, 0, 0)); al_set_shader_float("pal_set_1", p1 * 2); al_set_shader_float("pal_set_2", p2 * 2); al_set_shader_float("pal_interp", pos); if (background) al_draw_bitmap(background, 0, 0, 0); for (i = 0; i < 8; i++) { Sprite *s = sprite + 7 - i; float pos = (1 + sin((t / 60 + s->t) * 2 * ALLEGRO_PI)) / 2; al_set_shader_float("pal_set_1", s->i); al_set_shader_float("pal_set_2", s->j); al_set_shader_float("pal_interp", pos); al_draw_rotated_bitmap(bitmap, 64, 64, s->x, s->y, s->angle, s->flags); } { float sc = 0.5; al_set_shader_float("pal_set_1", (int)t % 20 > 15 ? 6 : 0); al_set_shader_float("pal_interp", 0); #define D al_draw_scaled_rotated_bitmap D(bitmap, 0, 0, 0, 0, sc, sc, 0, 0); D(bitmap, 0, 0, 640, 0, -sc, sc, 0, 0); D(bitmap, 0, 0, 0, 480, sc, -sc, 0, 0); D(bitmap, 0, 0, 640, 480, -sc, -sc, 0, 0); } if (show_pal) { al_use_shader(NULL); al_draw_scaled_bitmap(pal_bitmap, 0, 0, 255, 7, 0, 0, 255, 7*12, 0); al_use_shader(shader); } al_flip_display(); } } al_use_shader(NULL); al_destroy_bitmap(bitmap); al_destroy_shader(shader); return 0; } int pal_hex[256] = { 0xFF00FF, 0x000100, 0x060000, 0x040006, 0x000200, 0x000306, 0x010400, 0x030602, 0x02090C, 0x070A06, 0x020C14, 0x030F1A, 0x0F0E03, 0x0D0F0C, 0x071221, 0x0D1308, 0x0D1214, 0x121411, 0x12170E, 0x151707, 0x0A182B, 0x171816, 0x131B0C, 0x1A191C, 0x171D08, 0x081D35, 0x1A200E, 0x1D1F1C, 0x1D2013, 0x0E2139, 0x06233F, 0x17230E, 0x1C270E, 0x21260F, 0x0D2845, 0x0A294C, 0x1F2A12, 0x252724, 0x232B19, 0x222D15, 0x0C2F51, 0x0D2F57, 0x263012, 0x2B2D2B, 0x233314, 0x273617, 0x0D3764, 0x17355E, 0x2C3618, 0x2E3623, 0x333432, 0x2C3A15, 0x093D70, 0x333B17, 0x163C6A, 0x2F3D18, 0x323D24, 0x383A38, 0x30401B, 0x2F431C, 0x1E4170, 0x12447D, 0x154478, 0x3F403E, 0x34471A, 0x3D482C, 0x134B8B, 0x3A4D20, 0x184D86, 0x474846, 0x3A511D, 0x13549A, 0x3D5420, 0x195595, 0x0F57A3, 0x4E504D, 0x415925, 0x435B27, 0x485837, 0x125DA9, 0x485E24, 0x175FB2, 0x235DA3, 0x555754, 0x0565BD, 0x1C61B5, 0x2163B7, 0x2164B1, 0x49662A, 0x1268C1, 0x2365B9, 0x1769C3, 0x5E605D, 0x196BBE, 0x55673D, 0x1B6BC5, 0x2968BC, 0x246BB8, 0x526D2A, 0x0E73CC, 0x0E74C6, 0x246FC9, 0x2470C4, 0x56712E, 0x666865, 0x007DCE, 0x537530, 0x2A72CC, 0x55762B, 0x1B77D0, 0x1F77D8, 0x1E79CC, 0x2E74CF, 0x58782D, 0x2E75CA, 0x59792E, 0x2279D3, 0x5A7A2F, 0x3276D2, 0x6D6F6C, 0x1081D3, 0x137FDF, 0x237DC9, 0x5B7C30, 0x637848, 0x2A7DD7, 0x5E7F33, 0x2C7DDE, 0x2A80CD, 0x1D82E2, 0x1A85D1, 0x2B80D5, 0x747673, 0x2D82CF, 0x2F84D1, 0x3381E3, 0x2289D5, 0x3285D2, 0x2986EE, 0x2189ED, 0x4782C5, 0x3884DF, 0x4083D2, 0x3487D4, 0x278BD7, 0x298ADD, 0x67883B, 0x7B7D7A, 0x2A8CD9, 0x6C8653, 0x3289E2, 0x3889D7, 0x2C8DDA, 0x2E8FDB, 0x3D8CDA, 0x2F90DC, 0x338EE8, 0x3191DD, 0x3E8EDE, 0x3392DE, 0x838582, 0x709145, 0x3593E0, 0x4191D9, 0x3794E1, 0x698AB1, 0x4590E5, 0x3B93E6, 0x789158, 0x4594DC, 0x3C97E4, 0x4896DE, 0x4397EA, 0x3D9AE1, 0x8B8E8B, 0x409CE3, 0x4B99E1, 0x439CEA, 0x539AD6, 0x5898E2, 0x439EE5, 0x4E9BE4, 0x439FEC, 0x809C5F, 0x7C9E57, 0x45A0E7, 0x509FE1, 0x47A1E8, 0x599EDB, 0x48A2E9, 0x80A153, 0x4AA4EB, 0x959794, 0x5CA1DE, 0x51A3EF, 0x59A3E3, 0x4DA6ED, 0x4FA7EF, 0x51A8F0, 0x87A763, 0x5AA8EA, 0x53AAF2, 0x9C9E9B, 0x49AFF5, 0x56ACF5, 0x55AFF0, 0x8CAD67, 0x64ACE8, 0x60ADF0, 0x59AFF7, 0x6EACE2, 0x79A9E1, 0x63AFF2, 0x59B2F3, 0x90B162, 0xA6A8A5, 0x60B5F4, 0x94B56D, 0x99BC72, 0xAEB0AD, 0x74BBF2, 0x8DB8ED, 0x94B7E3, 0x8ABEEA, 0xA0C379, 0x82C0F2, 0xB6B8B5, 0xA3C77C, 0xA5C97E, 0xA9CA79, 0x8FC7F3, 0xBEC0BD, 0xA1C6E9, 0x97C9F0, 0xADD07E, 0xC8CAC7, 0xACD1F0, 0xB6CFF0, 0xB9D5ED, 0xD1D3D0, 0xBEDAF4, 0xD9DBD8, 0xC7E2FB, 0xCDE3F6, 0xE1E3E0, 0xE4E9EC, 0xDBEBF9, 0xEAECE9, 0xE7EFF8, 0xF1F3F0, 0xECF4FD, 0xF2F7FA, 0xF6F8F5, 0xF7FCFF, 0xFAFCF8, 0xFDFFFC,}; /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/examples/ex_path.c000066400000000000000000000044331473414355200170760ustar00rootroot00000000000000#include #include #include "common.c" int main(int argc, char **argv) { ALLEGRO_PATH *dyn = NULL; ALLEGRO_PATH *tostring = NULL; ALLEGRO_PATH *cloned = NULL; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); if (argc < 2) { ALLEGRO_PATH *exe = al_create_path(argv[0]); if (exe) { log_printf("This example needs to be run from the command line.\nUsage1: %s \n", al_get_path_filename(exe)); al_destroy_path(exe); } else { log_printf("This example needs to be run from the command line.\nUsage2: %s \n", argv[0]); } goto done; } dyn = al_create_path(argv[1]); if (!dyn) { log_printf("Failed to create path structure for '%s'.\n", argv[1]); } else { log_printf("dyn: drive=\"%s\", file=\"%s\"\n", al_get_path_drive(dyn), al_get_path_filename(dyn)); al_destroy_path(dyn); } tostring = al_create_path(argv[1]); if (!tostring) { log_printf("Failed to create path structure for tostring test\n"); } else { int i; log_printf("tostring: '%s'\n", al_path_cstr(tostring, '/')); log_printf("tostring: drive:'%s'", al_get_path_drive(tostring)); log_printf(" dirs:"); for (i = 0; i < al_get_path_num_components(tostring); i++) { if (i > 0) log_printf(","); log_printf(" '%s'", al_get_path_component(tostring, i)); } log_printf(" filename:'%s'\n", al_get_path_filename(tostring)); al_destroy_path(tostring); } /* FIXME: test out more of the al_path_ functions, ie: insert, remove, * concat, relative */ dyn = al_create_path(argv[1]); if(dyn) { cloned = al_clone_path(dyn); if(cloned) { log_printf("dyn: '%s'\n", al_path_cstr(dyn, '/')); al_make_path_canonical(cloned); log_printf("can: '%s'\n", al_path_cstr(cloned, '/')); al_destroy_path(dyn); al_destroy_path(cloned); } else { log_printf("failed to clone ALLEGRO_PATH :(\n"); al_destroy_path(dyn); } } else { log_printf("failed to create new ALLEGRO_PATH for cloning..."); } done: close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_path_test.c000066400000000000000000000410731473414355200201360ustar00rootroot00000000000000/* * Example program for the Allegro library. * * Stress test path routines. */ #include #include #include "common.c" #ifdef ALLEGRO_MSVC #pragma warning (disable: 4066) #endif typedef void (*test_t)(void); int error = 0; #define CHECK(x) \ do { \ bool ok = (bool)(x); \ if (!ok) { \ log_printf("FAIL %s\n", #x); \ error++; \ } else { \ log_printf("OK %s\n", #x); \ } \ } while (0) #define CHECK_EQ(x,y) CHECK(0 == strcmp(x, y)) /*---------------------------------------------------------------------------*/ /* Test al_create_path, al_get_path_num_components, al_get_path_component, * al_get_path_drive, al_get_path_filename, al_destroy_path. */ static void t1(void) { ALLEGRO_PATH *path; CHECK(path = al_create_path(NULL)); al_destroy_path(path); CHECK(path = al_create_path("")); CHECK(al_get_path_num_components(path) == 0); CHECK_EQ(al_get_path_drive(path), ""); CHECK_EQ(al_get_path_filename(path), ""); al_destroy_path(path); /* . is a directory component. */ CHECK(path = al_create_path(".")); CHECK(al_get_path_num_components(path) == 1); CHECK_EQ(al_get_path_component(path, 0), "."); CHECK_EQ(al_get_path_drive(path), ""); CHECK_EQ(al_get_path_filename(path), ""); al_destroy_path(path); /* .. is a directory component. */ CHECK(path = al_create_path("..")); CHECK(al_get_path_num_components(path) == 1); CHECK_EQ(al_get_path_component(path, 0), ".."); CHECK_EQ(al_get_path_drive(path), ""); CHECK_EQ(al_get_path_filename(path), ""); al_destroy_path(path); /* Relative path. */ CHECK(path = al_create_path("abc/def/..")); CHECK(al_get_path_num_components(path) == 3); CHECK_EQ(al_get_path_component(path, 0), "abc"); CHECK_EQ(al_get_path_component(path, 1), "def"); CHECK_EQ(al_get_path_component(path, 2), ".."); CHECK_EQ(al_get_path_drive(path), ""); CHECK_EQ(al_get_path_filename(path), ""); al_destroy_path(path); /* Absolute path. */ CHECK(path = al_create_path("/abc/def/..")); CHECK(al_get_path_num_components(path) == 4); CHECK_EQ(al_get_path_component(path, 0), ""); CHECK_EQ(al_get_path_component(path, 1), "abc"); CHECK_EQ(al_get_path_component(path, 2), "def"); CHECK_EQ(al_get_path_component(path, 3), ".."); CHECK_EQ(al_get_path_drive(path), ""); CHECK_EQ(al_get_path_filename(path), ""); al_destroy_path(path); /* Directories + filename. */ CHECK(path = al_create_path("/abc/def/ghi")); CHECK(al_get_path_num_components(path) == 3); CHECK_EQ(al_get_path_component(path, 0), ""); CHECK_EQ(al_get_path_component(path, 1), "abc"); CHECK_EQ(al_get_path_component(path, 2), "def"); CHECK_EQ(al_get_path_drive(path), ""); CHECK_EQ(al_get_path_filename(path), "ghi"); al_destroy_path(path); } /* Test parsing UNC paths. */ static void t2(void) { #ifdef ALLEGRO_WINDOWS ALLEGRO_PATH *path; /* The mixed slashes are deliberate. */ /* Good paths. */ CHECK(path = al_create_path("//server\\share name/dir/filename")); CHECK_EQ(al_get_path_drive(path), "//server"); CHECK(al_get_path_num_components(path) == 2); CHECK_EQ(al_get_path_component(path, 0), "share name"); CHECK_EQ(al_get_path_component(path, 1), "dir"); CHECK_EQ(al_get_path_filename(path), "filename"); al_destroy_path(path); /* Bad paths. */ CHECK(! al_create_path("//")); CHECK(! al_create_path("//filename")); CHECK(! al_create_path("///share/name/filename")); #else log_printf("Skipping Windows-only test...\n"); #endif } /* Test parsing drive letter paths. */ static void t3(void) { #ifdef ALLEGRO_WINDOWS ALLEGRO_PATH *path; /* The mixed slashes are deliberate. */ CHECK(path = al_create_path("c:abc\\def/ghi")); CHECK_EQ(al_get_path_drive(path), "c:"); CHECK(al_get_path_num_components(path) == 2); CHECK_EQ(al_get_path_component(path, 0), "abc"); CHECK_EQ(al_get_path_component(path, 1), "def"); CHECK_EQ(al_get_path_filename(path), "ghi"); CHECK_EQ(al_path_cstr(path, '\\'), "c:abc\\def\\ghi"); al_destroy_path(path); CHECK(path = al_create_path("c:\\abc/def\\ghi")); CHECK_EQ(al_get_path_drive(path), "c:"); CHECK(al_get_path_num_components(path) == 3); CHECK_EQ(al_get_path_component(path, 0), ""); CHECK_EQ(al_get_path_component(path, 1), "abc"); CHECK_EQ(al_get_path_component(path, 2), "def"); CHECK_EQ(al_get_path_filename(path), "ghi"); CHECK_EQ(al_path_cstr(path, '\\'), "c:\\abc\\def\\ghi"); al_destroy_path(path); #else log_printf("Skipping Windows-only test...\n"); #endif } /* Test al_append_path_component. */ static void t4(void) { ALLEGRO_PATH *path = al_create_path(NULL); CHECK(al_get_path_num_components(path) == 0); al_append_path_component(path, "abc"); al_append_path_component(path, "def"); al_append_path_component(path, "ghi"); CHECK(al_get_path_num_components(path) == 3); CHECK_EQ(al_get_path_component(path, 0), "abc"); CHECK_EQ(al_get_path_component(path, 1), "def"); CHECK_EQ(al_get_path_component(path, 2), "ghi"); CHECK_EQ(al_get_path_component(path, -1), "ghi"); CHECK_EQ(al_get_path_component(path, -2), "def"); CHECK_EQ(al_get_path_component(path, -3), "abc"); al_destroy_path(path); } /* Test al_replace_path_component. */ static void t5(void) { ALLEGRO_PATH *path = al_create_path(NULL); al_append_path_component(path, "abc"); al_append_path_component(path, "INKY"); al_append_path_component(path, "def"); al_append_path_component(path, "BLINKY"); al_append_path_component(path, "ghi"); CHECK(al_get_path_num_components(path) == 5); al_replace_path_component(path, 1, "PINKY"); al_replace_path_component(path, -2, "CLYDE"); CHECK(al_get_path_num_components(path) == 5); CHECK_EQ(al_get_path_component(path, 0), "abc"); CHECK_EQ(al_get_path_component(path, 1), "PINKY"); CHECK_EQ(al_get_path_component(path, 2), "def"); CHECK_EQ(al_get_path_component(path, 3), "CLYDE"); CHECK_EQ(al_get_path_component(path, 4), "ghi"); al_destroy_path(path); } /* Test al_remove_path_component. */ static void t6(void) { ALLEGRO_PATH *path = al_create_path(NULL); al_append_path_component(path, "abc"); al_append_path_component(path, "INKY"); al_append_path_component(path, "def"); al_append_path_component(path, "BLINKY"); al_append_path_component(path, "ghi"); CHECK(al_get_path_num_components(path) == 5); al_remove_path_component(path, 1); CHECK(al_get_path_num_components(path) == 4); al_remove_path_component(path, -2); CHECK(al_get_path_num_components(path) == 3); CHECK_EQ(al_get_path_component(path, 0), "abc"); CHECK_EQ(al_get_path_component(path, 1), "def"); CHECK_EQ(al_get_path_component(path, 2), "ghi"); al_destroy_path(path); } /* Test al_insert_path_component. */ static void t7(void) { ALLEGRO_PATH *path = al_create_path("INKY/BLINKY/"); al_insert_path_component(path, 0, "abc"); al_insert_path_component(path, 2, "def"); al_insert_path_component(path, 4, "ghi"); CHECK(al_get_path_num_components(path) == 5); CHECK_EQ(al_get_path_component(path, 0), "abc"); CHECK_EQ(al_get_path_component(path, 1), "INKY"); CHECK_EQ(al_get_path_component(path, 2), "def"); CHECK_EQ(al_get_path_component(path, 3), "BLINKY"); CHECK_EQ(al_get_path_component(path, 4), "ghi"); al_destroy_path(path); } /* Test al_get_path_tail, al_drop_path_tail. */ static void t8(void) { ALLEGRO_PATH *path = al_create_path(NULL); CHECK(! al_get_path_tail(path)); al_append_path_component(path, "abc"); al_append_path_component(path, "def"); al_append_path_component(path, "ghi"); CHECK_EQ(al_get_path_tail(path), "ghi"); al_drop_path_tail(path); CHECK_EQ(al_get_path_tail(path), "def"); al_drop_path_tail(path); al_drop_path_tail(path); CHECK(! al_get_path_tail(path)); /* Drop tail from already empty path. */ al_drop_path_tail(path); CHECK(! al_get_path_tail(path)); al_destroy_path(path); } /* Test al_set_path_drive, al_set_path_filename, al_path_cstr. */ static void t9(void) { ALLEGRO_PATH *path = al_create_path(NULL); CHECK_EQ(al_path_cstr(path, '/'), ""); /* Drive letters. */ al_set_path_drive(path, "c:"); CHECK_EQ(al_path_cstr(path, '/'), "c:"); CHECK_EQ(al_get_path_drive(path), "c:"); al_set_path_drive(path, "d:"); CHECK_EQ(al_path_cstr(path, '/'), "d:"); /* Plus directory components. */ al_append_path_component(path, "abc"); al_append_path_component(path, "def"); CHECK_EQ(al_path_cstr(path, '/'), "d:abc/def/"); /* Plus filename. */ al_set_path_filename(path, "uvw"); CHECK_EQ(al_path_cstr(path, '/'), "d:abc/def/uvw"); CHECK_EQ(al_get_path_filename(path), "uvw"); /* Replace filename. */ al_set_path_filename(path, "xyz"); CHECK_EQ(al_path_cstr(path, '/'), "d:abc/def/xyz"); /* Remove drive. */ al_set_path_drive(path, NULL); CHECK_EQ(al_path_cstr(path, '/'), "abc/def/xyz"); /* Remove filename. */ al_set_path_filename(path, NULL); CHECK_EQ(al_path_cstr(path, '/'), "abc/def/"); al_destroy_path(path); } /* Test al_join_paths. */ static void t10(void) { ALLEGRO_PATH *path1; ALLEGRO_PATH *path2; /* Both empty. */ path1 = al_create_path(NULL); path2 = al_create_path(NULL); al_join_paths(path1, path2); CHECK_EQ(al_path_cstr(path1, '/'), ""); al_destroy_path(path1); al_destroy_path(path2); /* Both just filenames. */ path1 = al_create_path("file1"); path2 = al_create_path("file2"); al_join_paths(path1, path2); CHECK_EQ(al_path_cstr(path1, '/'), "file2"); al_destroy_path(path1); al_destroy_path(path2); /* Both relative paths. */ path1 = al_create_path("dir1a/dir1b/file1"); path2 = al_create_path("dir2a/dir2b/file2"); al_join_paths(path1, path2); CHECK_EQ(al_path_cstr(path1, '/'), "dir1a/dir1b/dir2a/dir2b/file2"); al_destroy_path(path1); al_destroy_path(path2); #ifdef ALLEGRO_WINDOWS /* Both relative paths with drive letters. */ path1 = al_create_path("d:dir1a/dir1b/file1"); path2 = al_create_path("e:dir2a/dir2b/file2"); al_join_paths(path1, path2); CHECK_EQ(al_path_cstr(path1, '/'), "d:dir1a/dir1b/dir2a/dir2b/file2"); al_destroy_path(path1); al_destroy_path(path2); #endif /* Path1 absolute, path2 relative. */ path1 = al_create_path("/dir1a/dir1b/file1"); path2 = al_create_path("dir2a/dir2b/file2"); al_join_paths(path1, path2); CHECK_EQ(al_path_cstr(path1, '/'), "/dir1a/dir1b/dir2a/dir2b/file2"); al_destroy_path(path1); al_destroy_path(path2); /* Both paths absolute. */ path1 = al_create_path("/dir1a/dir1b/file1"); path2 = al_create_path("/dir2a/dir2b/file2"); al_join_paths(path1, path2); CHECK_EQ(al_path_cstr(path1, '/'), "/dir1a/dir1b/file1"); al_destroy_path(path1); al_destroy_path(path2); } /* Test al_rebase_path. */ static void t11(void) { ALLEGRO_PATH *path1; ALLEGRO_PATH *path2; /* Both empty. */ path1 = al_create_path(NULL); path2 = al_create_path(NULL); al_rebase_path(path1, path2); CHECK_EQ(al_path_cstr(path2, '/'), ""); al_destroy_path(path1); al_destroy_path(path2); /* Both just filenames. */ path1 = al_create_path("file1"); path2 = al_create_path("file2"); al_rebase_path(path1, path2); CHECK_EQ(al_path_cstr(path2, '/'), "file2"); al_destroy_path(path1); al_destroy_path(path2); /* Both relative paths. */ path1 = al_create_path("dir1a/dir1b/file1"); path2 = al_create_path("dir2a/dir2b/file2"); al_rebase_path(path1, path2); CHECK_EQ(al_path_cstr(path2, '/'), "dir1a/dir1b/dir2a/dir2b/file2"); al_destroy_path(path1); al_destroy_path(path2); #ifdef ALLEGRO_WINDOWS /* Both relative paths with drive letters. */ path1 = al_create_path("d:dir1a/dir1b/file1"); path2 = al_create_path("e:dir2a/dir2b/file2"); al_rebase_path(path1, path2); CHECK_EQ(al_path_cstr(path2, '/'), "d:dir1a/dir1b/dir2a/dir2b/file2"); al_destroy_path(path1); al_destroy_path(path2); #endif /* Path1 absolute, path2 relative. */ path1 = al_create_path("/dir1a/dir1b/file1"); path2 = al_create_path("dir2a/dir2b/file2"); al_rebase_path(path1, path2); CHECK_EQ(al_path_cstr(path2, '/'), "/dir1a/dir1b/dir2a/dir2b/file2"); al_destroy_path(path1); al_destroy_path(path2); /* Both paths absolute. */ path1 = al_create_path("/dir1a/dir1b/file1"); path2 = al_create_path("/dir2a/dir2b/file2"); al_rebase_path(path1, path2); CHECK_EQ(al_path_cstr(path2, '/'), "/dir2a/dir2b/file2"); al_destroy_path(path1); al_destroy_path(path2); } /* Test al_set_path_extension, al_get_path_extension. */ static void t12(void) { ALLEGRO_PATH *path = al_create_path(NULL); /* Get null extension. */ CHECK_EQ(al_get_path_extension(path), ""); /* Set extension on null filename. */ CHECK(! al_set_path_extension(path, "ext")); CHECK_EQ(al_get_path_filename(path), ""); /* Set extension on extension-less filename. */ al_set_path_filename(path, "abc"); CHECK(al_set_path_extension(path, ".ext")); CHECK_EQ(al_get_path_filename(path), "abc.ext"); /* Replacing extension. */ al_set_path_filename(path, "abc.def"); CHECK(al_set_path_extension(path, ".ext")); CHECK_EQ(al_get_path_filename(path), "abc.ext"); CHECK_EQ(al_get_path_extension(path), ".ext"); /* Filename with multiple dots. */ al_set_path_filename(path, "abc.def.ghi"); CHECK(al_set_path_extension(path, ".ext")); CHECK_EQ(al_get_path_filename(path), "abc.def.ext"); CHECK_EQ(al_get_path_extension(path), ".ext"); al_destroy_path(path); } /* Test al_get_path_basename. */ static void t13(void) { ALLEGRO_PATH *path = al_create_path(NULL); /* No filename. */ al_set_path_filename(path, NULL); CHECK_EQ(al_get_path_basename(path), ""); /* No extension. */ al_set_path_filename(path, "abc"); CHECK_EQ(al_get_path_basename(path), "abc"); /* Filename with a single dot. */ al_set_path_filename(path, "abc.ext"); CHECK_EQ(al_get_path_basename(path), "abc"); /* Filename with multiple dots. */ al_set_path_filename(path, "abc.def.ghi"); CHECK_EQ(al_get_path_basename(path), "abc.def"); al_destroy_path(path); } /* Test al_clone_path. */ static void t14(void) { ALLEGRO_PATH *path1; ALLEGRO_PATH *path2; path1 = al_create_path("/abc/def/ghi"); path2 = al_clone_path(path1); CHECK_EQ(al_path_cstr(path1, '/'), al_path_cstr(path2, '/')); al_replace_path_component(path2, 2, "DEF"); al_set_path_filename(path2, "GHI"); CHECK_EQ(al_path_cstr(path1, '/'), "/abc/def/ghi"); CHECK_EQ(al_path_cstr(path2, '/'), "/abc/DEF/GHI"); al_destroy_path(path1); al_destroy_path(path2); } static void t15(void) { /* nothing */ log_printf("Skipping empty test...\n"); } static void t16(void) { /* nothing */ log_printf("Skipping empty test...\n"); } /* Test al_make_path_canonical. */ static void t17(void) { ALLEGRO_PATH *path; path = al_create_path("/../.././abc/./def/../../ghi/jkl"); CHECK(al_make_path_canonical(path)); CHECK(al_get_path_num_components(path) == 6); CHECK_EQ(al_path_cstr(path, '/'), "/abc/def/../../ghi/jkl"); al_destroy_path(path); path = al_create_path("../.././abc/./def/../../ghi/jkl"); CHECK(al_make_path_canonical(path)); CHECK(al_get_path_num_components(path) == 7); CHECK_EQ(al_path_cstr(path, '/'), "../../abc/def/../../ghi/jkl"); al_destroy_path(path); } /*---------------------------------------------------------------------------*/ const test_t all_tests[] = { NULL, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17 }; #define NUM_TESTS (int)(sizeof(all_tests) / sizeof(all_tests[0])) int main(int argc, char **argv) { int i; if (!al_init()) { abort_example("Could not initialise Allegro.\n"); } open_log(); if (argc < 2) { for (i = 1; i < NUM_TESTS; i++) { log_printf("# t%d\n\n", i); all_tests[i](); log_printf("\n"); } } else { i = atoi(argv[1]); if (i > 0 && i < NUM_TESTS) { all_tests[i](); } } log_printf("Done\n"); close_log(true); if (error) { exit(EXIT_FAILURE); } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_physfs.c000066400000000000000000000104601473414355200174530ustar00rootroot00000000000000/* * Example program for Allegro library. * * Demonstrate PhysicsFS addon. */ #include #include #include #include #include #include "common.c" static void show_image(ALLEGRO_BITMAP *bmp) { ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); while (true) { al_draw_bitmap(bmp, 0, 0, 0); al_flip_display(); al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } } al_destroy_event_queue(queue); } static void print_file(ALLEGRO_FS_ENTRY *entry) { int mode = al_get_fs_entry_mode(entry); time_t now = time(NULL); time_t atime = al_get_fs_entry_atime(entry); time_t ctime = al_get_fs_entry_ctime(entry); time_t mtime = al_get_fs_entry_mtime(entry); const char *name = al_get_fs_entry_name(entry); off_t size = al_get_fs_entry_size(entry); log_printf("%-36s %s%s%s%s%s%s %8u %8u %8u %8u\n", name, mode & ALLEGRO_FILEMODE_READ ? "r" : ".", mode & ALLEGRO_FILEMODE_WRITE ? "w" : ".", mode & ALLEGRO_FILEMODE_EXECUTE ? "x" : ".", mode & ALLEGRO_FILEMODE_HIDDEN ? "h" : ".", mode & ALLEGRO_FILEMODE_ISFILE ? "f" : ".", mode & ALLEGRO_FILEMODE_ISDIR ? "d" : ".", (unsigned)(now - ctime), (unsigned)(now - mtime), (unsigned)(now - atime), (unsigned)size); } static void listdir(ALLEGRO_FS_ENTRY *entry) { ALLEGRO_FS_ENTRY *next; al_open_directory(entry); while (1) { next = al_read_directory(entry); if (!next) break; print_file(next); if (al_get_fs_entry_mode(next) & ALLEGRO_FILEMODE_ISDIR) listdir(next); al_destroy_fs_entry(next); } al_close_directory(entry); } static bool add_main_zipfile(void) { ALLEGRO_PATH *exe; const char *ext; const char *zipfile; bool ret; /* On Android we treat the APK itself as the zip file. */ exe = al_get_standard_path(ALLEGRO_EXENAME_PATH); ext = al_get_path_extension(exe); if (0 == strcmp(ext, ".apk")) { zipfile = al_path_cstr(exe, '/'); } else { zipfile = "data/ex_physfs.zip"; } if (PHYSFS_mount(zipfile, NULL, 1)) { ret = true; } else { log_printf("Could load the zip file: %s\n", zipfile); ret = false; } al_destroy_path(exe); return ret; } int main(int argc, char *argv[]) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *bmp; ALLEGRO_FS_ENTRY *entry; int i; if (!al_init()) { abort_example("Could not init Allegro\n"); } al_init_image_addon(); al_install_keyboard(); open_log_monospace(); /* Set up PhysicsFS. */ if (!PHYSFS_init(argv[0])) { abort_example("Could not init PhysFS\n"); } // This creates a ~/.allegro directory, which is very annoying to say the // least - and no need for it in this example. // if (!PHYSFS_setSaneConfig("allegro", "ex_physfs", NULL, 0, 0)) // return 1; if (!add_main_zipfile()) { abort_example("Could not add zip file\n"); } for (i = 1; i < argc; i++) { if (!PHYSFS_mount(argv[i], NULL, 1)) { abort_example("Couldn't add %s\n", argv[i]); } } display = al_create_display(640, 480); if (!display) { abort_example("Error creating display.\n"); } /* Make future calls to al_fopen() on this thread go to the PhysicsFS * backend. */ al_set_physfs_file_interface(); /* List the contents of our example zip recursively. */ log_printf("%-36s %-6s %8s %8s %8s %8s\n", "name", "flags", "ctime", "mtime", "atime", "size"); log_printf( "------------------------------------ " "------ " "-------- " "-------- " "-------- " "--------\n"); entry = al_create_fs_entry(""); listdir(entry); al_destroy_fs_entry(entry); bmp = al_load_bitmap("02.bmp"); if (!bmp) { /* Fallback for Android. */ bmp = al_load_bitmap("assets/data/alexlogo.bmp"); } if (bmp) { show_image(bmp); al_destroy_bitmap(bmp); } PHYSFS_deinit(); close_log(false); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_pixelformat.cpp000066400000000000000000000161231473414355200210330ustar00rootroot00000000000000/* * Simple (incomplete) test of pixel format conversions. * * This should be made comprehensive. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_primitives.h" #include "nihgui.hpp" #include "common.c" typedef struct FORMAT { int format; char const *name; } FORMAT; const FORMAT formats[ALLEGRO_NUM_PIXEL_FORMATS] = { {ALLEGRO_PIXEL_FORMAT_ANY, "any"}, {ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA, "no alpha"}, {ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA, "alpha"}, {ALLEGRO_PIXEL_FORMAT_ANY_15_NO_ALPHA, "15"}, {ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA, "16"}, {ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA, "16 alpha"}, {ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA, "24"}, {ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA, "32"}, {ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA, "32 alpha"}, {ALLEGRO_PIXEL_FORMAT_ARGB_8888, "ARGB8888"}, {ALLEGRO_PIXEL_FORMAT_RGBA_8888, "RGBA8888"}, {ALLEGRO_PIXEL_FORMAT_ARGB_4444, "ARGB4444"}, {ALLEGRO_PIXEL_FORMAT_RGB_888, "RGB888"}, {ALLEGRO_PIXEL_FORMAT_RGB_565, "RGB565"}, {ALLEGRO_PIXEL_FORMAT_RGB_555, "RGB555"}, {ALLEGRO_PIXEL_FORMAT_RGBA_5551, "RGBA5551"}, {ALLEGRO_PIXEL_FORMAT_ARGB_1555, "ARGB1555"}, {ALLEGRO_PIXEL_FORMAT_ABGR_8888, "ABGR8888"}, {ALLEGRO_PIXEL_FORMAT_XBGR_8888, "XBGR8888"}, {ALLEGRO_PIXEL_FORMAT_BGR_888, "BGR888"}, {ALLEGRO_PIXEL_FORMAT_BGR_565, "BGR565"}, {ALLEGRO_PIXEL_FORMAT_BGR_555, "BGR555"}, {ALLEGRO_PIXEL_FORMAT_RGBX_8888, "RGBX8888"}, {ALLEGRO_PIXEL_FORMAT_XRGB_8888, "XRGB8888"}, {ALLEGRO_PIXEL_FORMAT_ABGR_F32, "ABGR32F"}, {ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, "ABGR(LE)"}, {ALLEGRO_PIXEL_FORMAT_RGBA_4444, "RGBA4444"}, {ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8, "SINGLE_CHANNEL_8"}, {ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1, "RGBA_DXT1"}, {ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3, "RGBA_DXT3"}, {ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5, "RGBA_DXT5"}, }; #define NUM_FORMATS ALLEGRO_NUM_PIXEL_FORMATS const char *get_format_name(ALLEGRO_BITMAP *bmp) { if (!bmp) return "none"; int format = al_get_bitmap_format(bmp); for (unsigned i = 0; i < NUM_FORMATS; i++) { if (formats[i].format == format) return formats[i].name; } return "unknown"; } class Prog { private: Dialog d; Label source_label; Label dest_label; List source_list; List dest_list; Label true_formats; ToggleButton use_memory_button; ToggleButton enable_timing_button; Label time_label; const char* bmp_filename; public: Prog(const Theme & theme, ALLEGRO_DISPLAY *display, const char* bmp_filename); void run(); private: void draw_sample(); }; Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display, const char* bmp_filename) : d(Dialog(theme, display, 20, 30)), source_label(Label("Source")), dest_label(Label("Destination")), source_list(List()), dest_list(List()), true_formats(Label("")), use_memory_button(ToggleButton("Use memory bitmaps")), enable_timing_button(ToggleButton("Enable timing")), time_label(Label("")), bmp_filename(bmp_filename) { d.add(source_label, 11, 0, 4, 1); d.add(source_list, 11, 1, 4, 27); d.add(dest_label, 15, 0, 4, 1); d.add(dest_list, 15, 1, 4, 27); d.add(true_formats, 0, 20, 10, 1); d.add(use_memory_button, 0, 24, 10, 2); d.add(enable_timing_button, 0, 26, 10, 2); d.add(time_label, 0, 22, 10, 1); for (unsigned i = 0; i < NUM_FORMATS; i++) { source_list.append_item(formats[i].name); dest_list.append_item(formats[i].name); } } void Prog::run() { d.prepare(); while (!d.is_quit_requested()) { if (d.is_draw_requested()) { al_clear_to_color(al_map_rgb(128, 128, 128)); draw_sample(); d.draw(); al_flip_display(); } d.run_step(true); } } void Prog::draw_sample() { const int i = source_list.get_cur_value(); const int j = dest_list.get_cur_value(); ALLEGRO_BITMAP *bitmap1; ALLEGRO_BITMAP *bitmap2; bool use_memory = use_memory_button.get_pushed(); bool enable_timing = enable_timing_button.get_pushed(); int bmp_w = 128; int bmp_h = 128; if (use_memory) al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); else al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP); al_set_new_bitmap_format(formats[i].format); bitmap1 = al_load_bitmap(bmp_filename); if (!bitmap1) { log_printf("Could not load image %s, bitmap format = %d\n", bmp_filename, formats[i].format); } else { bmp_w = al_get_bitmap_width(bitmap1); bmp_h = al_get_bitmap_height(bitmap1); } al_set_new_bitmap_format(formats[j].format); bitmap2 = al_create_bitmap(bmp_w, bmp_h); if (!bitmap2) { log_printf("Could not create bitmap, format = %d\n", formats[j].format); } if (bitmap1 && bitmap2) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); al_set_target_bitmap(bitmap2); al_clear_to_color(al_map_rgb(128, 128, 128)); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); if (enable_timing) { double t0, t1; char str[256]; int frames = 0; t0 = al_get_time(); log_printf("Timing...\n"); do { al_draw_bitmap(bitmap1, 0, 0, 0); frames++; t1 = al_get_time(); } while (t1 - t0 < 0.25); log_printf(" ...done.\n"); sprintf(str, "%.0f FPS", (double)frames / (t1 - t0)); time_label.set_text(str); } else { al_draw_bitmap(bitmap1, 0, 0, 0); time_label.set_text(""); } al_set_target_bitmap(target); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_bitmap(bitmap2, 0, 0, 0); } else { al_draw_line(0, 0, 320, 200, al_map_rgb_f(1, 0, 0), 0); al_draw_line(0, 200, 320, 0, al_map_rgb_f(1, 0, 0), 0); } std::string s = get_format_name(bitmap1); s += " -> "; s += get_format_name(bitmap2); true_formats.set_text(s); al_destroy_bitmap(bitmap1); al_destroy_bitmap(bitmap2); } int main(int argc, char *argv[]) { ALLEGRO_DISPLAY *display; ALLEGRO_FONT *font; const char* bmp_filename = "data/allegro.pcx"; if (argc > 1) { bmp_filename = argv[1]; } if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); al_init_primitives_addon(); al_init_image_addon(); al_init_font_addon(); init_platform_specific(); al_install_keyboard(); al_install_mouse(); al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(800, 600); if (!display) { abort_example("Error creating display\n"); } //log_printf("Display format = %d\n", al_get_display_format()); font = al_load_font("data/fixed_font.tga", 0, 0); if (!font) { abort_example("Failed to load data/fixed_font.tga\n"); } /* Don't remove these braces. */ { Theme theme(font); Prog prog(theme, display, bmp_filename); prog.run(); } al_destroy_font(font); close_log(false); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_polygon.c000066400000000000000000000311031473414355200176230ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * * This program tests the polygon routines in the primitives addon. */ #define ALLEGRO_UNSTABLE #include #include #include #include #include #include "common.c" #define MAX_VERTICES 64 #define MAX_POLYGONS 9 #define RADIUS 5 enum { MODE_POLYLINE = 0, MODE_POLYGON, MODE_FILLED_POLYGON, MODE_FILLED_HOLES, MODE_MAX }; enum AddHole { NOT_ADDING_HOLE, NEW_HOLE, GROW_HOLE }; typedef struct Vertex Vertex; struct Vertex { float x; float y; }; struct Example { ALLEGRO_DISPLAY *display; ALLEGRO_FONT *font; ALLEGRO_FONT *fontbmp; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_BITMAP *dbuf; ALLEGRO_COLOR bg; ALLEGRO_COLOR fg; Vertex vertices[MAX_VERTICES]; int vertex_polygon[MAX_VERTICES]; int vertex_count; int cur_vertex; /* -1 = none */ int cur_polygon; int mode; ALLEGRO_LINE_CAP cap_style; ALLEGRO_LINE_JOIN join_style; float thickness; float miter_limit; bool software; float zoom; float scroll_x, scroll_y; enum AddHole add_hole; }; static struct Example ex; static void reset(void) { ex.vertex_count = 0; ex.cur_vertex = -1; ex.cur_polygon = 0; ex.cap_style = ALLEGRO_LINE_CAP_NONE; ex.join_style = ALLEGRO_LINE_JOIN_NONE; ex.thickness = 1.0f; ex.miter_limit = 1.0f; ex.software = false; ex.zoom = 1; ex.scroll_x = 0; ex.scroll_y = 0; ex.add_hole = NOT_ADDING_HOLE; } static void transform(float *x, float *y) { *x /= ex.zoom; *y /= ex.zoom; *x -= ex.scroll_x; *y -= ex.scroll_y; } static int hit_vertex(int mx, int my) { int i; for (i = 0; i < ex.vertex_count; i++) { int dx = ex.vertices[i].x - mx; int dy = ex.vertices[i].y - my; int dd = dx*dx + dy*dy; if (dd <= RADIUS * RADIUS) return i; } return -1; } static void lclick(int mx, int my) { ex.cur_vertex = hit_vertex(mx, my); if (ex.cur_vertex < 0 && ex.vertex_count < MAX_VERTICES) { int i = ex.vertex_count++; ex.vertices[i].x = mx; ex.vertices[i].y = my; ex.cur_vertex = i; if (ex.add_hole == NEW_HOLE && ex.cur_polygon < MAX_POLYGONS) { ex.cur_polygon++; ex.add_hole = GROW_HOLE; } ex.vertex_polygon[i] = ex.cur_polygon; } } static void rclick(int mx, int my) { const int i = hit_vertex(mx, my); if (i >= 0 && ex.add_hole == NOT_ADDING_HOLE) { ex.vertex_count--; memmove(&ex.vertices[i], &ex.vertices[i + 1], sizeof(Vertex) * (ex.vertex_count - i)); memmove(&ex.vertex_polygon[i], &ex.vertex_polygon[i + 1], sizeof(int) * (ex.vertex_count - i)); } ex.cur_vertex = -1; } static void drag(int mx, int my) { if (ex.cur_vertex >= 0) { ex.vertices[ex.cur_vertex].x = mx; ex.vertices[ex.cur_vertex].y = my; } } static void scroll(int mx, int my) { ex.scroll_x += mx; ex.scroll_y += my; } static const char *join_style_to_string(ALLEGRO_LINE_JOIN x) { switch (x) { case ALLEGRO_LINE_JOIN_NONE: return "NONE"; case ALLEGRO_LINE_JOIN_BEVEL: return "BEVEL"; case ALLEGRO_LINE_JOIN_ROUND: return "ROUND"; case ALLEGRO_LINE_JOIN_MITER: return "MITER"; default: return "unknown"; } } static const char *cap_style_to_string(ALLEGRO_LINE_CAP x) { switch (x) { case ALLEGRO_LINE_CAP_NONE: return "NONE"; case ALLEGRO_LINE_CAP_SQUARE: return "SQUARE"; case ALLEGRO_LINE_CAP_ROUND: return "ROUND"; case ALLEGRO_LINE_CAP_TRIANGLE: return "TRIANGLE"; case ALLEGRO_LINE_CAP_CLOSED: return "CLOSED"; default: return "unknown"; } } static ALLEGRO_FONT *choose_font(void) { return (ex.software) ? ex.fontbmp : ex.font; } static void draw_vertices(void) { ALLEGRO_FONT *f = choose_font(); ALLEGRO_COLOR vertc = al_map_rgba_f(0.7, 0, 0, 0.7); ALLEGRO_COLOR textc = al_map_rgba_f(0, 0, 0, 0.7); int i; for (i = 0; i < ex.vertex_count; i++) { float x = ex.vertices[i].x; float y = ex.vertices[i].y; al_draw_filled_circle(x, y, RADIUS, vertc); al_draw_textf(f, textc, x + RADIUS, y + RADIUS, 0, "%d", i); } } static void compute_polygon_vertex_counts( int polygon_vertex_count[MAX_POLYGONS + 1]) { int i; /* This also implicitly terminates the array with a zero. */ memset(polygon_vertex_count, 0, sizeof(int) * (MAX_POLYGONS + 1)); for (i = 0; i < ex.vertex_count; i++) { const int poly = ex.vertex_polygon[i]; polygon_vertex_count[poly]++; } } static void draw_all(void) { ALLEGRO_FONT *f = choose_font(); ALLEGRO_COLOR textc = al_map_rgb(0, 0, 0); float texth = al_get_font_line_height(f) * 1.5; float textx = 5; float texty = 5; ALLEGRO_TRANSFORM t; ALLEGRO_COLOR holec; al_clear_to_color(ex.bg); al_identity_transform(&t); al_translate_transform(&t, ex.scroll_x, ex.scroll_y); al_scale_transform(&t, ex.zoom, ex.zoom); al_use_transform(&t); if (ex.mode == MODE_POLYLINE) { if (ex.vertex_count >= 2) { al_draw_polyline( (float *)ex.vertices, sizeof(Vertex), ex.vertex_count, ex.join_style, ex.cap_style, ex.fg, ex.thickness, ex.miter_limit); } } else if (ex.mode == MODE_FILLED_POLYGON) { if (ex.vertex_count >= 2) { al_draw_filled_polygon( (float *)ex.vertices, ex.vertex_count, ex.fg); } } else if (ex.mode == MODE_POLYGON) { if (ex.vertex_count >= 2) { al_draw_polygon( (float *)ex.vertices, ex.vertex_count, ex.join_style, ex.fg, ex.thickness, ex.miter_limit); } } else if (ex.mode == MODE_FILLED_HOLES) { if (ex.vertex_count >= 2) { int polygon_vertex_count[MAX_POLYGONS + 1]; compute_polygon_vertex_counts(polygon_vertex_count); al_draw_filled_polygon_with_holes( (float *)ex.vertices, polygon_vertex_count, ex.fg); } } draw_vertices(); al_identity_transform(&t); al_use_transform(&t); if (ex.mode == MODE_POLYLINE) { al_draw_textf(f, textc, textx, texty, 0, "al_draw_polyline (SPACE)"); texty += texth; } else if (ex.mode == MODE_FILLED_POLYGON) { al_draw_textf(f, textc, textx, texty, 0, "al_draw_filled_polygon (SPACE)"); texty += texth; } else if (ex.mode == MODE_POLYGON) { al_draw_textf(f, textc, textx, texty, 0, "al_draw_polygon (SPACE)"); texty += texth; } else if (ex.mode == MODE_FILLED_HOLES) { al_draw_textf(f, textc, textx, texty, 0, "al_draw_filled_polygon_with_holes (SPACE)"); texty += texth; } al_draw_textf(f, textc, textx, texty, 0, "Line join style: %s (J)", join_style_to_string(ex.join_style)); texty += texth; al_draw_textf(f, textc, textx, texty, 0, "Line cap style: %s (C)", cap_style_to_string(ex.cap_style)); texty += texth; al_draw_textf(f, textc, textx, texty, 0, "Line thickness: %.2f (+/-)", ex.thickness); texty += texth; al_draw_textf(f, textc, textx, texty, 0, "Miter limit: %.2f ([/])", ex.miter_limit); texty += texth; al_draw_textf(f, textc, textx, texty, 0, "Zoom: %.2f (wheel)", ex.zoom); texty += texth; al_draw_textf(f, textc, textx, texty, 0, "%s (S)", (ex.software ? "Software rendering" : "Hardware rendering")); texty += texth; al_draw_textf(f, textc, textx, texty, 0, "Reset (R)"); texty += texth; if (ex.add_hole == NOT_ADDING_HOLE) holec = textc; else if (ex.add_hole == GROW_HOLE) holec = al_map_rgb(200, 0, 0); else holec = al_map_rgb(0, 200, 0); al_draw_textf(f, holec, textx, texty, 0, "Add Hole (%d) (H)", ex.cur_polygon); texty += texth; } /* Print vertices in a format for the test suite. */ static void print_vertices(void) { int i; for (i = 0; i < ex.vertex_count; i++) { log_printf("v%-2d= %.2f, %.2f\n", i, ex.vertices[i].x, ex.vertices[i].y); } log_printf("\n"); } int main(int argc, char **argv) { ALLEGRO_EVENT event; bool have_touch_input; bool mdown = false; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); if (!al_init_primitives_addon()) { abort_example("Could not init primitives.\n"); } al_init_font_addon(); al_install_mouse(); al_install_keyboard(); have_touch_input = al_install_touch_input(); ex.display = al_create_display(800, 600); if (!ex.display) { abort_example("Error creating display\n"); } ex.font = al_create_builtin_font(); if (!ex.font) { abort_example("Error creating builtin font\n"); } al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); ex.dbuf = al_create_bitmap(800, 600); ex.fontbmp = al_create_builtin_font(); if (!ex.fontbmp) { abort_example("Error creating builtin font\n"); } ex.queue = al_create_event_queue(); al_register_event_source(ex.queue, al_get_keyboard_event_source()); al_register_event_source(ex.queue, al_get_mouse_event_source()); al_register_event_source(ex.queue, al_get_display_event_source(ex.display)); if (have_touch_input) { al_register_event_source(ex.queue, al_get_touch_input_event_source()); al_register_event_source(ex.queue, al_get_touch_input_mouse_emulation_event_source()); } ex.bg = al_map_rgba_f(1, 1, 0.9, 1); ex.fg = al_map_rgba_f(0, 0.5, 1, 1); reset(); for (;;) { if (al_is_event_queue_empty(ex.queue)) { if (ex.software) { al_set_target_bitmap(ex.dbuf); draw_all(); al_set_target_backbuffer(ex.display); al_draw_bitmap(ex.dbuf, 0, 0, 0); } else { al_set_target_backbuffer(ex.display); draw_all(); } al_flip_display(); } al_wait_for_event(ex.queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; if (event.type == ALLEGRO_EVENT_KEY_CHAR) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; switch (toupper(event.keyboard.unichar)) { case ' ': if (++ex.mode >= MODE_MAX) ex.mode = 0; break; case 'J': if (++ex.join_style > ALLEGRO_LINE_JOIN_MITER) ex.join_style = ALLEGRO_LINE_JOIN_NONE; break; case 'C': if (++ex.cap_style > ALLEGRO_LINE_CAP_CLOSED) ex.cap_style = ALLEGRO_LINE_CAP_NONE; break; case '+': ex.thickness += 0.25f; break; case '-': ex.thickness -= 0.25f; if (ex.thickness <= 0.0f) ex.thickness = 0.0f; break; case '[': ex.miter_limit -= 0.1f; if (ex.miter_limit < 0.0f) ex.miter_limit = 0.0f; break; case ']': ex.miter_limit += 0.1f; if (ex.miter_limit >= 10.0f) ex.miter_limit = 10.0f; break; case 'S': ex.software = !ex.software; break; case 'R': reset(); break; case 'P': print_vertices(); break; case 'H': ex.add_hole = NEW_HOLE; break; } } if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { float x = event.mouse.x, y = event.mouse.y; transform(&x, &y); if (event.mouse.button == 1) lclick(x, y); if (event.mouse.button == 2) rclick(x, y); if (event.mouse.button == 3) mdown = true; } if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { ex.cur_vertex = -1; if (event.mouse.button == 3) mdown = false; } if (event.type == ALLEGRO_EVENT_MOUSE_AXES) { float x = event.mouse.x, y = event.mouse.y; transform(&x, &y); if (mdown) scroll(event.mouse.dx, event.mouse.dy); else drag(x, y); ex.zoom *= pow(0.9, event.mouse.dz); } } al_destroy_display(ex.display); close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_premulalpha.c000066400000000000000000000106211473414355200204500ustar00rootroot00000000000000#include #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "common.c" int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *tex1, *tex2; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; bool redraw = true; ALLEGRO_LOCKED_REGION *lock; ALLEGRO_FONT *font; unsigned char *p; int x, y; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_font_addon(); al_install_mouse(); al_install_keyboard(); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } font = al_create_builtin_font(); tex1 = al_create_bitmap(8, 8); lock = al_lock_bitmap(tex1, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_WRITEONLY); p = lock->data; for (y = 0; y < 8; y++) { unsigned char *lp = p; for (x = 0; x < 8; x++) { if (x == 0 || y == 0 || x == 7 || y == 7) { p[0] = 0; p[1] = 0; p[2] = 0; p[3] = 0; } else { p[0] = 0; p[1] = 255; p[2] = 0; p[3] = 255; } p += 4; } p = lp + lock->pitch; } al_unlock_bitmap(tex1); al_set_new_bitmap_flags(ALLEGRO_MAG_LINEAR); tex2 = al_clone_bitmap(tex1); timer = al_create_timer(1.0 / 30); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (1) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; } if (event.type == ALLEGRO_EVENT_TIMER) redraw = true; if (redraw && al_is_event_queue_empty(queue)) { float x = 8, y = 60; float a, t = al_get_time(); float th = al_get_font_line_height(font); ALLEGRO_COLOR color = al_map_rgb_f(0, 0, 0); ALLEGRO_COLOR color2 = al_map_rgb_f(1, 0, 0); ALLEGRO_COLOR color3 = al_map_rgb_f(0, 0.5, 0); t /= 10; a = t - floor(t); a *= 2 * ALLEGRO_PI; redraw = false; al_clear_to_color(al_map_rgb_f(0.5, 0.6, 1)); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(font, color, x, y, 0, "not premultiplied"); al_draw_textf(font, color, x, y + th, 0, "no filtering"); al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); al_draw_scaled_rotated_bitmap(tex1, 4, 4, x + 320, y, 8, 8, a, 0); y += 120; al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(font, color, x, y, 0, "not premultiplied"); al_draw_textf(font, color, x, y + th, 0, "mag linear filtering"); al_draw_textf(font, color2, x + 400, y, 0, "wrong dark border"); al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); al_draw_scaled_rotated_bitmap(tex2, 4, 4, x + 320, y, 8, 8, a, 0); y += 120; al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(font, color, x, y, 0, "premultiplied alpha"); al_draw_textf(font, color, x, y + th, 0, "no filtering"); al_draw_textf(font, color, x + 400, y, 0, "no difference"); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_scaled_rotated_bitmap(tex1, 4, 4, x + 320, y, 8, 8, a, 0); y += 120; al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(font, color, x, y, 0, "premultiplied alpha"); al_draw_textf(font, color, x, y + th, 0, "mag linear filtering"); al_draw_textf(font, color3, x + 400, y, 0, "correct color"); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_scaled_rotated_bitmap(tex2, 4, 4, x + 320, y, 8, 8, a, 0); al_flip_display(); } } al_destroy_font(font); al_destroy_bitmap(tex1); al_destroy_bitmap(tex2); return 0; } allegro5-5.2.10.1/examples/ex_prim.c000066400000000000000000000734131473414355200171150ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * A sampler of the primitive addon. * All primitives are rendered using the additive blender, so overdraw will manifest itself as overly bright pixels. * * * By Pavel Sountsov. * * See readme.txt for copyright information. */ #define ALLEGRO_UNSTABLE #include #include #include #include #include #include #include "common.c" typedef void (*Screen)(int); int ScreenW = 800, ScreenH = 600; #define NUM_SCREENS 12 #define ROTATE_SPEED 0.0001f Screen Screens[NUM_SCREENS]; const char *ScreenName[NUM_SCREENS]; ALLEGRO_FONT* Font; ALLEGRO_TRANSFORM Identity; ALLEGRO_BITMAP* Buffer; ALLEGRO_BITMAP* Texture; ALLEGRO_COLOR solid_white; int Soft = 0; int Blend = 1; float Speed = ROTATE_SPEED; float Theta; int Background = 1; float Thickness = 0; ALLEGRO_TRANSFORM MainTrans; enum MODE { INIT, LOGIC, DRAW, DEINIT }; typedef struct { ALLEGRO_COLOR color; short u, v; short x, y; int junk[6]; } CUSTOM_VERTEX; static void CustomVertexFormatPrimitives(int mode) { static CUSTOM_VERTEX vtx[4]; static ALLEGRO_VERTEX_DECL* decl; if (mode == INIT) { int ii = 0; ALLEGRO_VERTEX_ELEMENT elems[] = { {ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_SHORT_2, offsetof(CUSTOM_VERTEX, x)}, {ALLEGRO_PRIM_TEX_COORD_PIXEL, ALLEGRO_PRIM_SHORT_2, offsetof(CUSTOM_VERTEX, u)}, {ALLEGRO_PRIM_COLOR_ATTR, 0, offsetof(CUSTOM_VERTEX, color)}, {0, 0, 0} }; decl = al_create_vertex_decl(elems, sizeof(CUSTOM_VERTEX)); for (ii = 0; ii < 4; ii++) { float x, y; x = 200 * cosf((float)ii / 4.0f * 2 * ALLEGRO_PI); y = 200 * sinf((float)ii / 4.0f * 2 * ALLEGRO_PI); vtx[ii].x = x; vtx[ii].y = y; vtx[ii].u = 64 * x / 100; vtx[ii].v = 64 * y / 100; vtx[ii].color = al_map_rgba_f(1, 1, 1, 1); } } else if (mode == LOGIC) { Theta += Speed; al_build_transform(&MainTrans, ScreenW / 2, ScreenH / 2, 1, 1, Theta); } else if (mode == DRAW) { if (Blend) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); else al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_use_transform(&MainTrans); al_draw_prim(vtx, decl, Texture, 0, 4, ALLEGRO_PRIM_TRIANGLE_FAN); al_use_transform(&Identity); } } static void TexturePrimitives(int mode) { static ALLEGRO_VERTEX vtx[13]; static ALLEGRO_VERTEX vtx2[13]; if (mode == INIT) { int ii = 0; ALLEGRO_COLOR color; for (ii = 0; ii < 13; ii++) { float x, y; x = 200 * cosf((float)ii / 13.0f * 2 * ALLEGRO_PI); y = 200 * sinf((float)ii / 13.0f * 2 * ALLEGRO_PI); color = al_map_rgb((ii + 1) % 3 * 64, (ii + 2) % 3 * 64, (ii) % 3 * 64); vtx[ii].x = x; vtx[ii].y = y; vtx[ii].z = 0; vtx2[ii].x = 0.1 * x; vtx2[ii].y = 0.1 * y; vtx[ii].u = 64 * x / 100; vtx[ii].v = 64 * y / 100; vtx2[ii].u = 64 * x / 100; vtx2[ii].v = 64 * y / 100; if(ii < 10) vtx[ii].color = al_map_rgba_f(1, 1, 1, 1); else vtx[ii].color = color; vtx2[ii].color = vtx[ii].color; } } else if (mode == LOGIC) { Theta += Speed; al_build_transform(&MainTrans, ScreenW / 2, ScreenH / 2, 1, 1, Theta); } else if (mode == DRAW) { if (Blend) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); else al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_use_transform(&MainTrans); al_draw_prim(vtx, 0, Texture, 0, 4, ALLEGRO_PRIM_LINE_LIST); al_draw_prim(vtx, 0, Texture, 4, 9, ALLEGRO_PRIM_LINE_STRIP); al_draw_prim(vtx, 0, Texture, 9, 13, ALLEGRO_PRIM_LINE_LOOP); al_draw_prim(vtx2, 0, Texture, 0, 13, ALLEGRO_PRIM_POINT_LIST); al_use_transform(&Identity); } } static void FilledTexturePrimitives(int mode) { static ALLEGRO_VERTEX vtx[21]; if (mode == INIT) { int ii = 0; for (ii = 0; ii < 21; ii++) { float x, y; ALLEGRO_COLOR color; if (ii % 2 == 0) { x = 150 * cosf((float)ii / 20 * 2 * ALLEGRO_PI); y = 150 * sinf((float)ii / 20 * 2 * ALLEGRO_PI); } else { x = 200 * cosf((float)ii / 20 * 2 * ALLEGRO_PI); y = 200 * sinf((float)ii / 20 * 2 * ALLEGRO_PI); } if (ii == 0) { x = y = 0; } color = al_map_rgb((7 * ii + 1) % 3 * 64, (2 * ii + 2) % 3 * 64, (ii) % 3 * 64); vtx[ii].x = x; vtx[ii].y = y; vtx[ii].z = 0; vtx[ii].u = 64 * x / 100; vtx[ii].v = 64 * y / 100; if(ii < 10) vtx[ii].color = al_map_rgba_f(1, 1, 1, 1); else vtx[ii].color = color; } } else if (mode == LOGIC) { Theta += Speed; al_build_transform(&MainTrans, ScreenW / 2, ScreenH / 2, 1, 1, Theta); } else if (mode == DRAW) { if (Blend) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); else al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_use_transform(&MainTrans); al_draw_prim(vtx, 0, Texture, 0, 6, ALLEGRO_PRIM_TRIANGLE_FAN); al_draw_prim(vtx, 0, Texture, 7, 13, ALLEGRO_PRIM_TRIANGLE_LIST); al_draw_prim(vtx, 0, Texture, 14, 20, ALLEGRO_PRIM_TRIANGLE_STRIP); al_use_transform(&Identity); } } static void FilledPrimitives(int mode) { static ALLEGRO_VERTEX vtx[21]; if (mode == INIT) { int ii = 0; for (ii = 0; ii < 21; ii++) { float x, y; ALLEGRO_COLOR color; if (ii % 2 == 0) { x = 150 * cosf((float)ii / 20 * 2 * ALLEGRO_PI); y = 150 * sinf((float)ii / 20 * 2 * ALLEGRO_PI); } else { x = 200 * cosf((float)ii / 20 * 2 * ALLEGRO_PI); y = 200 * sinf((float)ii / 20 * 2 * ALLEGRO_PI); } if (ii == 0) { x = y = 0; } color = al_map_rgb((7 * ii + 1) % 3 * 64, (2 * ii + 2) % 3 * 64, (ii) % 3 * 64); vtx[ii].x = x; vtx[ii].y = y; vtx[ii].z = 0; vtx[ii].color = color; } } else if (mode == LOGIC) { Theta += Speed; al_build_transform(&MainTrans, ScreenW / 2, ScreenH / 2, 1, 1, Theta); } else if (mode == DRAW) { if (Blend) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); else al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_use_transform(&MainTrans); al_draw_prim(vtx, 0, 0, 0, 6, ALLEGRO_PRIM_TRIANGLE_FAN); al_draw_prim(vtx, 0, 0, 7, 13, ALLEGRO_PRIM_TRIANGLE_LIST); al_draw_prim(vtx, 0, 0, 14, 20, ALLEGRO_PRIM_TRIANGLE_STRIP); al_use_transform(&Identity); } } static void IndexedFilledPrimitives(int mode) { static ALLEGRO_VERTEX vtx[21]; static int indices1[] = {12, 13, 14, 16, 17, 18}; static int indices2[] = {6, 7, 8, 9, 10, 11}; static int indices3[] = {0, 1, 2, 3, 4, 5}; if (mode == INIT) { int ii = 0; for (ii = 0; ii < 21; ii++) { float x, y; ALLEGRO_COLOR color; if (ii % 2 == 0) { x = 150 * cosf((float)ii / 20 * 2 * ALLEGRO_PI); y = 150 * sinf((float)ii / 20 * 2 * ALLEGRO_PI); } else { x = 200 * cosf((float)ii / 20 * 2 * ALLEGRO_PI); y = 200 * sinf((float)ii / 20 * 2 * ALLEGRO_PI); } if (ii == 0) { x = y = 0; } color = al_map_rgb((7 * ii + 1) % 3 * 64, (2 * ii + 2) % 3 * 64, (ii) % 3 * 64); vtx[ii].x = x; vtx[ii].y = y; vtx[ii].z = 0; vtx[ii].color = color; } } else if (mode == LOGIC) { int ii; Theta += Speed; for (ii = 0; ii < 6; ii++) { indices1[ii] = ((int)al_get_time() + ii) % 20 + 1; indices2[ii] = ((int)al_get_time() + ii + 6) % 20 + 1; if (ii > 0) indices3[ii] = ((int)al_get_time() + ii + 12) % 20 + 1; } al_build_transform(&MainTrans, ScreenW / 2, ScreenH / 2, 1, 1, Theta); } else if (mode == DRAW) { if (Blend) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); else al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_use_transform(&MainTrans); al_draw_indexed_prim(vtx, 0, 0, indices1, 6, ALLEGRO_PRIM_TRIANGLE_LIST); al_draw_indexed_prim(vtx, 0, 0, indices2, 6, ALLEGRO_PRIM_TRIANGLE_STRIP); al_draw_indexed_prim(vtx, 0, 0, indices3, 6, ALLEGRO_PRIM_TRIANGLE_FAN); al_use_transform(&Identity); } } static void HighPrimitives(int mode) { if (mode == INIT) { } else if (mode == LOGIC) { Theta += Speed; al_build_transform(&MainTrans, ScreenW / 2, ScreenH / 2, 1, 1, Theta); } else if (mode == DRAW) { float points[8] = { -300, -200, 700, 200, -700, 200, 300, -200 }; if (Blend) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); else al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_use_transform(&MainTrans); al_draw_line(-300, -200, 300, 200, al_map_rgba_f(0, 0.5, 0.5, 1), Thickness); al_draw_triangle(-150, -250, 0, 250, 150, -250, al_map_rgba_f(0.5, 0, 0.5, 1), Thickness); al_draw_rectangle(-300, -200, 300, 200, al_map_rgba_f(0.5, 0, 0, 1), Thickness); al_draw_rounded_rectangle(-200, -125, 200, 125, 50, 100, al_map_rgba_f(0.2, 0.2, 0, 1), Thickness); al_draw_ellipse(0, 0, 300, 150, al_map_rgba_f(0, 0.5, 0.5, 1), Thickness); al_draw_elliptical_arc(-20, 0, 300, 200, -ALLEGRO_PI / 2, -ALLEGRO_PI, al_map_rgba_f(0.25, 0.25, 0.5, 1), Thickness); al_draw_arc(0, 0, 200, -ALLEGRO_PI / 2, ALLEGRO_PI, al_map_rgba_f(0.5, 0.25, 0, 1), Thickness); al_draw_spline(points, al_map_rgba_f(0.1, 0.2, 0.5, 1), Thickness); al_draw_pieslice(0, 25, 150, ALLEGRO_PI * 3 / 4, -ALLEGRO_PI / 2, al_map_rgba_f(0.4, 0.3, 0.1, 1), Thickness); al_use_transform(&Identity); } } static void HighFilledPrimitives(int mode) { if (mode == INIT) { } else if (mode == LOGIC) { Theta += Speed; al_build_transform(&MainTrans, ScreenW / 2, ScreenH / 2, 1, 1, Theta); } else if (mode == DRAW) { if (Blend) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); else al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_use_transform(&MainTrans); al_draw_filled_triangle(-100, -100, -150, 200, 100, 200, al_map_rgb_f(0.5, 0.7, 0.3)); al_draw_filled_rectangle(20, -50, 200, 50, al_map_rgb_f(0.3, 0.2, 0.6)); al_draw_filled_ellipse(-250, 0, 100, 150, al_map_rgb_f(0.3, 0.3, 0.3)); al_draw_filled_rounded_rectangle(50, -250, 350, -75, 50, 70, al_map_rgb_f(0.4, 0.2, 0)); al_draw_filled_pieslice(200, 125, 50, ALLEGRO_PI / 4, 3 * ALLEGRO_PI / 2, al_map_rgb_f(0.3, 0.3, 0.1)); al_use_transform(&Identity); } } static void TransformationsPrimitives(int mode) { float t = al_get_time(); if (mode == INIT) { } else if (mode == LOGIC) { Theta += Speed; al_build_transform(&MainTrans, ScreenW / 2, ScreenH / 2, sinf(t / 5), cosf(t / 5), Theta); } else if (mode == DRAW) { float points[8] = { -300, -200, 700, 200, -700, 200, 300, -200 }; if (Blend) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); else al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_use_transform(&MainTrans); al_draw_line(-300, -200, 300, 200, al_map_rgba_f(0, 0.5, 0.5, 1), Thickness); al_draw_triangle(-150, -250, 0, 250, 150, -250, al_map_rgba_f(0.5, 0, 0.5, 1), Thickness); al_draw_rectangle(-300, -200, 300, 200, al_map_rgba_f(0.5, 0, 0, 1), Thickness); al_draw_rounded_rectangle(-200, -125, 200, 125, 50, 100, al_map_rgba_f(0.2, 0.2, 0, 1), Thickness); al_draw_ellipse(0, 0, 300, 150, al_map_rgba_f(0, 0.5, 0.5, 1), Thickness); al_draw_elliptical_arc(-20, 0, 300, 200, -ALLEGRO_PI / 2, -ALLEGRO_PI, al_map_rgba_f(0.25, 0.25, 0.5, 1), Thickness); al_draw_arc(0, 0, 200, -ALLEGRO_PI / 2, ALLEGRO_PI, al_map_rgba_f(0.5, 0.25, 0, 1), Thickness); al_draw_spline(points, al_map_rgba_f(0.1, 0.2, 0.5, 1), Thickness); al_draw_pieslice(0, 25, 150, ALLEGRO_PI * 3 / 4, -ALLEGRO_PI / 2, al_map_rgba_f(0.4, 0.3, 0.1, 1), Thickness); al_use_transform(&Identity); } } static void LowPrimitives(int mode) { static ALLEGRO_VERTEX vtx[13]; static ALLEGRO_VERTEX vtx2[13]; if (mode == INIT) { int ii = 0; ALLEGRO_COLOR color; for (ii = 0; ii < 13; ii++) { float x, y; x = 200 * cosf((float)ii / 13.0f * 2 * ALLEGRO_PI); y = 200 * sinf((float)ii / 13.0f * 2 * ALLEGRO_PI); color = al_map_rgb((ii + 1) % 3 * 64, (ii + 2) % 3 * 64, (ii) % 3 * 64); vtx[ii].x = x; vtx[ii].y = y; vtx[ii].z = 0; vtx2[ii].x = 0.1 * x; vtx2[ii].y = 0.1 * y; vtx[ii].color = color; vtx2[ii].color = color; } } else if (mode == LOGIC) { Theta += Speed; al_build_transform(&MainTrans, ScreenW / 2, ScreenH / 2, 1, 1, Theta); } else if (mode == DRAW) { if (Blend) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); else al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_use_transform(&MainTrans); al_draw_prim(vtx, 0, 0, 0, 4, ALLEGRO_PRIM_LINE_LIST); al_draw_prim(vtx, 0, 0, 4, 9, ALLEGRO_PRIM_LINE_STRIP); al_draw_prim(vtx, 0, 0, 9, 13, ALLEGRO_PRIM_LINE_LOOP); al_draw_prim(vtx2, 0, 0, 0, 13, ALLEGRO_PRIM_POINT_LIST); al_use_transform(&Identity); } } static void IndexedPrimitives(int mode) { static int indices1[] = {0, 1, 3, 4}; static int indices2[] = {5, 6, 7, 8}; static int indices3[] = {9, 10, 11, 12}; static ALLEGRO_VERTEX vtx[13]; static ALLEGRO_VERTEX vtx2[13]; if (mode == INIT) { int ii = 0; ALLEGRO_COLOR color; for (ii = 0; ii < 13; ii++) { float x, y; x = 200 * cosf((float)ii / 13.0f * 2 * ALLEGRO_PI); y = 200 * sinf((float)ii / 13.0f * 2 * ALLEGRO_PI); color = al_map_rgb((ii + 1) % 3 * 64, (ii + 2) % 3 * 64, (ii) % 3 * 64); vtx[ii].x = x; vtx[ii].y = y; vtx[ii].z = 0; vtx2[ii].x = 0.1 * x; vtx2[ii].y = 0.1 * y; vtx[ii].color = color; vtx2[ii].color = color; } } else if (mode == LOGIC) { int ii; Theta += Speed; for (ii = 0; ii < 4; ii++) { indices1[ii] = ((int)al_get_time() + ii) % 13; indices2[ii] = ((int)al_get_time() + ii + 4) % 13; indices3[ii] = ((int)al_get_time() + ii + 8) % 13; } al_build_transform(&MainTrans, ScreenW / 2, ScreenH / 2, 1, 1, Theta); } else if (mode == DRAW) { if (Blend) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); else al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_use_transform(&MainTrans); al_draw_indexed_prim(vtx, 0, 0, indices1, 4, ALLEGRO_PRIM_LINE_LIST); al_draw_indexed_prim(vtx, 0, 0, indices2, 4, ALLEGRO_PRIM_LINE_STRIP); al_draw_indexed_prim(vtx, 0, 0, indices3, 4, ALLEGRO_PRIM_LINE_LOOP); al_draw_indexed_prim(vtx2, 0, 0, indices3, 4, ALLEGRO_PRIM_POINT_LIST); al_use_transform(&Identity); } } static void VertexBuffers(int mode) { static ALLEGRO_VERTEX vtx[13]; static ALLEGRO_VERTEX vtx2[13]; static ALLEGRO_VERTEX_BUFFER* vbuff; static ALLEGRO_VERTEX_BUFFER* vbuff2; static bool no_soft; static bool no_soft2; if (mode == INIT) { int ii = 0; ALLEGRO_COLOR color; for (ii = 0; ii < 13; ii++) { float x, y; x = 200 * cosf((float)ii / 13.0f * 2 * ALLEGRO_PI); y = 200 * sinf((float)ii / 13.0f * 2 * ALLEGRO_PI); color = al_map_rgb((ii + 1) % 3 * 64, (ii + 2) % 3 * 64, (ii) % 3 * 64); vtx[ii].x = x; vtx[ii].y = y; vtx[ii].z = 0; vtx2[ii].x = 0.1 * x; vtx2[ii].y = 0.1 * y; vtx[ii].color = color; vtx2[ii].color = color; } vbuff = al_create_vertex_buffer(0, vtx, 13, ALLEGRO_PRIM_BUFFER_READWRITE); if (!vbuff) { vbuff = al_create_vertex_buffer(0, vtx, 13, 0); no_soft = true; } else { no_soft = false; } vbuff2 = al_create_vertex_buffer(0, vtx2, 13, ALLEGRO_PRIM_BUFFER_READWRITE); if (!vbuff2) { vbuff2 = al_create_vertex_buffer(0, vtx2, 13, 0); no_soft2 = true; } else { no_soft2 = false; } } else if (mode == LOGIC) { Theta += Speed; al_build_transform(&MainTrans, ScreenW / 2, ScreenH / 2, 1, 1, Theta); } else if (mode == DRAW) { if (Blend) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); else al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_use_transform(&MainTrans); if (vbuff && !(Soft && no_soft)) { al_draw_vertex_buffer(vbuff, 0, 0, 4, ALLEGRO_PRIM_LINE_LIST); al_draw_vertex_buffer(vbuff, 0, 4, 9, ALLEGRO_PRIM_LINE_STRIP); al_draw_vertex_buffer(vbuff, 0, 9, 13, ALLEGRO_PRIM_LINE_LOOP); } else { al_draw_text(Font, al_map_rgb_f(1, 1, 1), 0, -40, 0, "Vertex buffers not supported"); } if (vbuff2 && !(Soft && no_soft2)) { al_draw_vertex_buffer(vbuff2, 0, 0, 13, ALLEGRO_PRIM_POINT_LIST); } else { al_draw_text(Font, al_map_rgb_f(1, 1, 1), 0, 40, 0, "Vertex buffers not supported"); } al_use_transform(&Identity); } else if (mode == DEINIT) { al_destroy_vertex_buffer(vbuff); al_destroy_vertex_buffer(vbuff2); } } static void IndexedBuffers(int mode) { static ALLEGRO_VERTEX_BUFFER* vbuff; static ALLEGRO_INDEX_BUFFER* ibuff; static bool soft = true; if (mode == INIT) { int ii; ALLEGRO_COLOR color; ALLEGRO_VERTEX* vtx; int flags = ALLEGRO_PRIM_BUFFER_READWRITE; vbuff = al_create_vertex_buffer(NULL, NULL, 13, ALLEGRO_PRIM_BUFFER_READWRITE); if (vbuff == NULL) { vbuff = al_create_vertex_buffer(NULL, NULL, 13, 0); soft = false; flags = 0; } ibuff = al_create_index_buffer(sizeof(short), NULL, 8, flags); if (vbuff) { vtx = al_lock_vertex_buffer(vbuff, 0, 13, ALLEGRO_LOCK_WRITEONLY); for (ii = 0; ii < 13; ii++) { float x, y; x = 200 * cosf((float)ii / 13.0f * 2 * ALLEGRO_PI); y = 200 * sinf((float)ii / 13.0f * 2 * ALLEGRO_PI); color = al_map_rgb((ii + 1) % 3 * 64, (ii + 2) % 3 * 64, (ii) % 3 * 64); vtx[ii].x = x; vtx[ii].y = y; vtx[ii].z = 0; vtx[ii].color = color; } al_unlock_vertex_buffer(vbuff); } } else if (mode == LOGIC) { if (ibuff) { int ii; int t = (int)al_get_time(); short* indices = al_lock_index_buffer(ibuff, 0, 8, ALLEGRO_LOCK_WRITEONLY); for (ii = 0; ii < 8; ii++) { indices[ii] = (t + ii) % 13; } al_unlock_index_buffer(ibuff); } Theta += Speed; al_build_transform(&MainTrans, ScreenW / 2, ScreenH / 2, 1, 1, Theta); } else if (mode == DRAW) { if (Blend) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); else al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_use_transform(&MainTrans); if(!(Soft && !soft) && vbuff && ibuff) { al_draw_indexed_buffer(vbuff, NULL, ibuff, 0, 4, ALLEGRO_PRIM_LINE_LIST); al_draw_indexed_buffer(vbuff, NULL, ibuff, 4, 8, ALLEGRO_PRIM_LINE_STRIP); } else { al_draw_text(Font, al_map_rgb_f(1, 1, 1), 0, 0, 0, "Indexed buffers not supported"); } al_use_transform(&Identity); } else if (mode == DEINIT) { al_destroy_vertex_buffer(vbuff); al_destroy_index_buffer(ibuff); } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP* bkg; ALLEGRO_COLOR black; ALLEGRO_EVENT_QUEUE *queue; bool use_shader = false; if (argc > 1) { if (strcmp(argv[1], "--shader") == 0) { use_shader = true; } else { abort_example("Invalid command line option: %s", argv[1]); } } // Initialize Allegro 5 and addons if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_image_addon(); al_init_font_addon(); al_init_primitives_addon(); init_platform_specific(); if (use_shader) { al_set_new_display_flags(ALLEGRO_PROGRAMMABLE_PIPELINE); } // Create a window to display things on: 640x480 pixels display = al_create_display(ScreenW, ScreenH); if (!display) { abort_example("Error creating display.\n"); } // Install the keyboard handler if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } if (!al_install_mouse()) { abort_example("Error installing mouse.\n"); } // Load a font Font = al_load_font("data/fixed_font.tga", 0, 0); if (!Font) { abort_example("Error loading \"data/fixed_font.tga\".\n"); } solid_white = al_map_rgba_f(1, 1, 1, 1); bkg = al_load_bitmap("data/bkg.png"); al_set_new_bitmap_wrap(ALLEGRO_BITMAP_WRAP_CLAMP, ALLEGRO_BITMAP_WRAP_MIRROR); Texture = al_load_bitmap("data/texture.tga"); // Make and set some color to draw with black = al_map_rgba_f(0.0, 0.0, 0.0, 1.0); // Start the event queue to handle keyboard input and our timer queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_mouse_event_source()); al_set_window_title(display, "Primitives Example"); { int refresh_rate = 60; int frames_done = 0; double time_diff = al_get_time(); double fixed_timestep = 1.0f / refresh_rate; double real_time = al_get_time(); double game_time = al_get_time(); int ii; int cur_screen = 0; bool done = false; int clip = 0; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *timer_queue; int old; timer = al_create_timer(ALLEGRO_BPS_TO_SECS(refresh_rate)); al_start_timer(timer); timer_queue = al_create_event_queue(); al_register_event_source(timer_queue, al_get_timer_event_source(timer)); old = al_get_new_bitmap_flags(); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); Buffer = al_create_bitmap(ScreenW, ScreenH); al_set_new_bitmap_flags(old); al_identity_transform(&Identity); Screens[0] = LowPrimitives; Screens[1] = IndexedPrimitives; Screens[2] = HighPrimitives; Screens[3] = TransformationsPrimitives; Screens[4] = FilledPrimitives; Screens[5] = IndexedFilledPrimitives; Screens[6] = HighFilledPrimitives; Screens[7] = TexturePrimitives; Screens[8] = FilledTexturePrimitives; Screens[9] = CustomVertexFormatPrimitives; Screens[10] = VertexBuffers; Screens[11] = IndexedBuffers; ScreenName[0] = "Low Level Primitives"; ScreenName[1] = "Indexed Primitives"; ScreenName[2] = "High Level Primitives"; ScreenName[3] = "Transformations"; ScreenName[4] = "Low Level Filled Primitives"; ScreenName[5] = "Indexed Filled Primitives"; ScreenName[6] = "High Level Filled Primitives"; ScreenName[7] = "Textured Primitives"; ScreenName[8] = "Filled Textured Primitives"; ScreenName[9] = "Custom Vertex Format"; ScreenName[10] = "Vertex Buffers"; ScreenName[11] = "Indexed Buffers"; for (ii = 0; ii < NUM_SCREENS; ii++) { Screens[ii](INIT); Screens[ii](LOGIC); } while (!done) { double frame_duration = al_get_time() - real_time; al_rest(fixed_timestep - frame_duration); //rest at least fixed_dt frame_duration = al_get_time() - real_time; real_time = al_get_time(); if (real_time - game_time > frame_duration) { //eliminate excess overflow game_time += fixed_timestep * floor((real_time - game_time) / fixed_timestep); } while (real_time - game_time >= 0) { ALLEGRO_EVENT key_event; double start_time = al_get_time(); game_time += fixed_timestep; Screens[cur_screen](LOGIC); while (al_get_next_event(queue, &key_event)) { switch (key_event.type) { case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: { cur_screen++; if (cur_screen >= NUM_SCREENS) { cur_screen = 0; } break; } case ALLEGRO_EVENT_DISPLAY_CLOSE: { done = true; break; } case ALLEGRO_EVENT_KEY_CHAR: { switch (key_event.keyboard.keycode) { case ALLEGRO_KEY_ESCAPE: { done = true; break; } case ALLEGRO_KEY_S: { Soft = !Soft; time_diff = al_get_time(); frames_done = 0; break; } case ALLEGRO_KEY_C: { clip = !clip; time_diff = al_get_time(); frames_done = 0; break; } case ALLEGRO_KEY_L: { Blend = !Blend; time_diff = al_get_time(); frames_done = 0; break; } case ALLEGRO_KEY_B: { Background = !Background; time_diff = al_get_time(); frames_done = 0; break; } case ALLEGRO_KEY_LEFT: { Speed -= ROTATE_SPEED; break; } case ALLEGRO_KEY_RIGHT: { Speed += ROTATE_SPEED; break; } case ALLEGRO_KEY_PGUP: { Thickness += 0.5f; if (Thickness < 1.0f) Thickness = 1.0f; break; } case ALLEGRO_KEY_PGDN: { Thickness -= 0.5f; if (Thickness < 1.0f) Thickness = 0.0f; break; } case ALLEGRO_KEY_UP: { cur_screen++; if (cur_screen >= NUM_SCREENS) { cur_screen = 0; } break; } case ALLEGRO_KEY_SPACE: { Speed = 0; break; } case ALLEGRO_KEY_DOWN: { cur_screen--; if (cur_screen < 0) { cur_screen = NUM_SCREENS - 1; } break; } } } } } if (al_get_time() - start_time >= fixed_timestep) { //break if we start taking too long break; } } al_clear_to_color(black); if (Soft == 1) { al_set_target_bitmap(Buffer); al_clear_to_color(black); } if (Background && bkg) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_draw_scaled_bitmap(bkg, 0, 0, al_get_bitmap_width(bkg), al_get_bitmap_height(bkg), 0, 0, ScreenW, ScreenH, 0); } if (clip == 1) { al_set_clipping_rectangle(ScreenW / 2, ScreenH / 2, ScreenW / 2, ScreenH / 2); } Screens[cur_screen](DRAW); al_set_clipping_rectangle(0, 0, ScreenW, ScreenH); if (Soft == 1) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_set_target_backbuffer(display); al_draw_bitmap(Buffer, 0, 0, 0); } al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(Font, solid_white, ScreenW / 2, ScreenH - 20, ALLEGRO_ALIGN_CENTRE, "%s", ScreenName[cur_screen]); al_draw_textf(Font, solid_white, 0, 0, 0, "FPS: %f", (float)frames_done / (al_get_time() - time_diff)); al_draw_textf(Font, solid_white, 0, 20, 0, "Change Screen (Up/Down). Esc to Quit."); al_draw_textf(Font, solid_white, 0, 40, 0, "Rotation (Left/Right/Space): %f", Speed); al_draw_textf(Font, solid_white, 0, 60, 0, "Thickness (PgUp/PgDown): %f", Thickness); al_draw_textf(Font, solid_white, 0, 80, 0, "Software (S): %d", Soft); al_draw_textf(Font, solid_white, 0, 100, 0, "Blending (L): %d", Blend); al_draw_textf(Font, solid_white, 0, 120, 0, "Background (B): %d", Background); al_draw_textf(Font, solid_white, 0, 140, 0, "Clip (C): %d", clip); al_flip_display(); frames_done++; } for (ii = 0; ii < NUM_SCREENS; ii++) Screens[ii](DEINIT); } return 0; } allegro5-5.2.10.1/examples/ex_prim_shader.c000066400000000000000000000143751473414355200204450ustar00rootroot00000000000000#include #include #include #define ALLEGRO_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/allegro_primitives.h" #include "common.c" typedef struct { float x, y; float nx, ny, nz; } CUSTOM_VERTEX; #define RING_SIZE 25 #define SPHERE_RADIUS 150.1 #define SCREEN_WIDTH 640 #define SCREEN_HEIGHT 480 #define NUM_RINGS (SCREEN_WIDTH / RING_SIZE + 1) #define NUM_SEGMENTS 64 #define NUM_VERTICES (NUM_RINGS * NUM_SEGMENTS * 6) #define FIRST_OUTSIDE_RING ((int)(SPHERE_RADIUS / RING_SIZE)) static void setup_vertex(CUSTOM_VERTEX* vtx, int ring, int segment, bool inside) { float len; float x, y, z; x = ring * RING_SIZE * cosf(2 * ALLEGRO_PI * segment / NUM_SEGMENTS); y = ring * RING_SIZE * sinf(2 * ALLEGRO_PI * segment / NUM_SEGMENTS); vtx->x = x + SCREEN_WIDTH / 2; vtx->y = y + SCREEN_HEIGHT / 2; if (inside) { /* This comes from the definition of the normal vector as the * gradient of the 3D surface. */ z = sqrtf(SPHERE_RADIUS * SPHERE_RADIUS - x * x - y * y); vtx->nx = x / z; vtx->ny = y / z; } else { vtx->nx = 0; vtx->ny = 0; } vtx->nz = 1.0; len = sqrtf(vtx->nx * vtx->nx + vtx->ny * vtx->ny + vtx->nz * vtx->nz); vtx->nx /= len; vtx->ny /= len; vtx->nz /= len; } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; bool redraw = true; ALLEGRO_SHADER *shader; ALLEGRO_VERTEX_DECL *vertex_decl; ALLEGRO_VERTEX_ELEMENT vertex_elems[] = { {ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, offsetof(CUSTOM_VERTEX, x)}, {ALLEGRO_PRIM_USER_ATTR, ALLEGRO_PRIM_FLOAT_3, offsetof(CUSTOM_VERTEX, nx)}, {0, 0, 0} }; CUSTOM_VERTEX vertices[NUM_VERTICES]; bool quit = false; const char* vertex_shader_file; const char* pixel_shader_file; int vertex_idx = 0; int ring, segment; float diffuse_color[4] = {0.1, 0.1, 0.7, 1.0}; float light_position[3] = {0, 0, 100}; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_mouse(); al_install_keyboard(); al_install_touch_input(); if (!al_init_primitives_addon()) { abort_example("Could not init primitives addon.\n"); } init_platform_specific(); al_set_new_display_flags(ALLEGRO_PROGRAMMABLE_PIPELINE); display = al_create_display(SCREEN_WIDTH, SCREEN_HEIGHT); if (!display) { abort_example("Error creating display.\n"); } vertex_decl = al_create_vertex_decl(vertex_elems, sizeof(CUSTOM_VERTEX)); if (!vertex_decl) { abort_example("Error creating vertex declaration.\n"); } /* Computes a "spherical" bump ring. The z coordinate is not actually set * appropriately as this is a 2D example, but the normal vectors are computed * correctly for the light shading effect. */ for (ring = 0; ring < NUM_RINGS; ring++) { for (segment = 0; segment < NUM_SEGMENTS; segment++) { bool inside = ring < FIRST_OUTSIDE_RING; setup_vertex(&vertices[vertex_idx + 0], ring + 0, segment + 0, inside); setup_vertex(&vertices[vertex_idx + 1], ring + 0, segment + 1, inside); setup_vertex(&vertices[vertex_idx + 2], ring + 1, segment + 0, inside); setup_vertex(&vertices[vertex_idx + 3], ring + 1, segment + 0, inside); setup_vertex(&vertices[vertex_idx + 4], ring + 0, segment + 1, inside); setup_vertex(&vertices[vertex_idx + 5], ring + 1, segment + 1, inside); vertex_idx += 6; } } shader = al_create_shader(ALLEGRO_SHADER_AUTO); if (!shader) { abort_example("Failed to create shader."); } if (al_get_shader_platform(shader) == ALLEGRO_SHADER_GLSL) { vertex_shader_file = "data/ex_prim_shader_vertex.glsl"; pixel_shader_file = "data/ex_prim_shader_pixel.glsl"; } else { vertex_shader_file = "data/ex_prim_shader_vertex.hlsl"; pixel_shader_file = "data/ex_prim_shader_pixel.hlsl"; } if (!al_attach_shader_source_file(shader, ALLEGRO_VERTEX_SHADER, vertex_shader_file)) { abort_example("al_attach_shader_source_file for vertex shader failed: %s\n", al_get_shader_log(shader)); } if (!al_attach_shader_source_file(shader, ALLEGRO_PIXEL_SHADER, pixel_shader_file)) { abort_example("al_attach_shader_source_file for pixel shader failed: %s\n", al_get_shader_log(shader)); } if (!al_build_shader(shader)) { abort_example("al_build_shader for link failed: %s\n", al_get_shader_log(shader)); } al_use_shader(shader); al_set_shader_float_vector("diffuse_color", 4, diffuse_color, 1); /* alpha controls shininess, and 25 is very shiny */ al_set_shader_float("alpha", 25); timer = al_create_timer(1.0 / 60); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); if (al_is_touch_input_installed()) { al_register_event_source(queue, al_get_touch_input_mouse_emulation_event_source()); } al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (!quit) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: quit = true; break; case ALLEGRO_EVENT_MOUSE_AXES: light_position[0] = event.mouse.x; light_position[1] = event.mouse.y; break; case ALLEGRO_EVENT_KEY_CHAR: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) quit = true; break; case ALLEGRO_EVENT_TIMER: redraw = true; break; } if (redraw && al_is_event_queue_empty(queue)) { al_clear_to_color(al_map_rgb_f(0, 0, 0)); al_set_shader_float_vector("light_position", 3, light_position, 1); al_draw_prim(vertices, vertex_decl, NULL, 0, NUM_VERTICES, ALLEGRO_PRIM_TRIANGLE_LIST); al_flip_display(); redraw = false; } } al_use_shader(NULL); al_destroy_shader(shader); al_destroy_vertex_decl(vertex_decl); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_prim_wrap.c000066400000000000000000000242731473414355200201460ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Bitmap wrapping options. * * See readme.txt for copyright information. */ #define ALLEGRO_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_primitives.h" #include "common.c" typedef enum { TRIANGLES, POINTS, LINES, NUM_TYPES, } PRIM_TYPE; static void draw_square(ALLEGRO_BITMAP* texture, float x, float y, float w, float h, int prim_type) { ALLEGRO_COLOR c = al_map_rgb_f(1, 1, 1); switch (prim_type) { case TRIANGLES: { ALLEGRO_VERTEX vtxs[4] = { /* x y z u v c */ {x, y, 0., -2 * w, -2 * h, c}, {x + 5 * w, y, 0., 3 * w, -2 * h, c}, {x + 5 * w, y + 5 * h, 0., 3 * w, 3 * h, c}, {x, y + 5 * h, 0., -2 * w, 3 * h, c}, }; al_draw_prim(vtxs, NULL, texture, 0, 4, ALLEGRO_PRIM_TRIANGLE_FAN); break; } case POINTS: { #define POINTS_N 32 float d = POINTS_N - 1; ALLEGRO_VERTEX vtxs[POINTS_N * POINTS_N]; for (int iy = 0; iy < POINTS_N; iy++) { for (int ix = 0; ix < POINTS_N; ix++) { ALLEGRO_VERTEX *v = &vtxs[iy * POINTS_N + ix]; v->x = x + 5. * w * (float)ix / d; v->y = y + 5. * h * (float)iy / d; v->z = 0.; v->u = -2 * w + 5. * w * (float)ix / d; v->v = -2 * h + 5. * h * (float)iy / d; v->color = c; } } al_draw_prim(vtxs, NULL, texture, 0, POINTS_N * POINTS_N, ALLEGRO_PRIM_POINT_LIST); break; } case LINES: { #define LINES_N 32 float d = LINES_N - 1; ALLEGRO_VERTEX vtxs[2 * LINES_N * 2]; for (int iy = 0; iy < LINES_N; iy++) { for (int ix = 0; ix < 2; ix++) { ALLEGRO_VERTEX *v = &vtxs[ix + 2 * iy]; v->x = x + 5. * w * (float)ix; v->y = y + 5. * h * (float)iy / d; v->z = 0.; v->u = -2 * w + 5. * w * (float)ix; v->v = -2 * h + 5. * h * (float)iy / d; v->color = c; } } for (int iy = 0; iy < 2; iy++) { for (int ix = 0; ix < LINES_N; ix++) { ALLEGRO_VERTEX *v = &vtxs[2 * ix + iy + 2 * LINES_N]; v->x = x + 5. * w * (float)ix / d; v->y = y + 5. * h * (float)iy; v->z = 0.; v->u = -2 * w + 5. * w * (float)ix / d; v->v = -2 * h + 5. * h * (float)iy; v->color = c; } } al_draw_prim(vtxs, NULL, texture, 0, 4 * LINES_N, ALLEGRO_PRIM_LINE_LIST); break; } } } int main(int argc, char **argv) { (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_mouse(); al_install_keyboard(); al_init_image_addon(); al_init_font_addon(); al_init_primitives_addon(); init_platform_specific(); bool allow_shader = false; bool use_shader = false; if (argc > 1 && strcmp(argv[1], "--shader") == 0) { allow_shader = true; } if (allow_shader) al_set_new_display_flags(ALLEGRO_PROGRAMMABLE_PIPELINE); ALLEGRO_DISPLAY *display = al_create_display(1024, 1024); if (!display) abort_example("Error creating display\n"); ALLEGRO_BITMAP *bitmap = al_load_bitmap("data/texture2.tga"); if (!bitmap) abort_example("Could not load 'data/texture2.tga'.\n"); ALLEGRO_BITMAP_WRAP wrap_settings[4] = { ALLEGRO_BITMAP_WRAP_DEFAULT, ALLEGRO_BITMAP_WRAP_REPEAT, ALLEGRO_BITMAP_WRAP_CLAMP, ALLEGRO_BITMAP_WRAP_MIRROR, }; const char* wrap_names[4] = { "DEFAULT", "REPEAT", "CLAMP", "MIRROR", }; const char* prim_names[NUM_TYPES] = { "TRIANGLES", "POINTS", "LINES", }; ALLEGRO_BITMAP *bitmaps[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { al_set_new_bitmap_wrap(wrap_settings[i], wrap_settings[j]); bitmaps[i][j] = al_clone_bitmap(bitmap); } } ALLEGRO_FONT *font = al_create_builtin_font(); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); ALLEGRO_BITMAP *memory_buffer = al_create_bitmap(al_get_display_width(display), al_get_display_height(display)); al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP); ALLEGRO_BITMAP *display_buffer = al_get_backbuffer(display); ALLEGRO_SHADER *shader = NULL; if (allow_shader) { shader = al_create_shader(ALLEGRO_SHADER_AUTO); if (!shader) abort_example("Error creating shader.\n"); const char* pixel_file; if (al_get_shader_platform(shader) == ALLEGRO_SHADER_GLSL) { #ifdef ALLEGRO_CFG_SHADER_GLSL pixel_file = "data/ex_bitmap_wrap_pixel.glsl"; #endif } else { #ifdef ALLEGRO_CFG_SHADER_HLSL pixel_file = "data/ex_bitmap_wrap_pixel.hlsl"; #endif } if (!pixel_file) { abort_example("No shader source\n"); } if (!al_attach_shader_source(shader, ALLEGRO_VERTEX_SHADER, al_get_default_shader_source(ALLEGRO_SHADER_AUTO, ALLEGRO_VERTEX_SHADER))) { abort_example("al_attach_shader_source for vertex shader failed: %s\n", al_get_shader_log(shader)); } if (!al_attach_shader_source_file(shader, ALLEGRO_PIXEL_SHADER, pixel_file)) abort_example("al_attach_shader_source_file for pixel shader failed: %s\n", al_get_shader_log(shader)); if (!al_build_shader(shader)) abort_example("al_build_shader failed: %s\n", al_get_shader_log(shader)); } ALLEGRO_TIMER *timer = al_create_timer(1.0 / 60); ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); bool redraw = true; bool software = false; PRIM_TYPE prim_type = TRIANGLES; bool quit = false; while (!quit) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; if (event.type == ALLEGRO_EVENT_KEY_CHAR) { switch (event.keyboard.keycode) { case ALLEGRO_KEY_ESCAPE: quit = true; break; case ALLEGRO_KEY_S: software = !software; break; case ALLEGRO_KEY_R: if (allow_shader) use_shader = !use_shader; break; case ALLEGRO_KEY_P: prim_type = (prim_type + 1) % NUM_TYPES; break; } } if (event.type == ALLEGRO_EVENT_TIMER) { redraw = true; } if (redraw && al_is_event_queue_empty(queue)) { redraw = false; al_clear_to_color(al_map_rgb_f(0, 0, 0)); int offt_x = 64; int offt_y = 64; int spacing = 16; int bw = al_get_bitmap_width(bitmap); int bh = al_get_bitmap_height(bitmap); int w = spacing + 5 * bw; int h = spacing + 5 * bh; if (software && !use_shader) { al_set_target_bitmap(memory_buffer); al_clear_to_color(al_map_rgb_f(0, 0, 0)); } else { al_set_target_bitmap(display_buffer); } al_draw_textf(font, al_map_rgb_f(1., 1., 0.5), 16, 16, ALLEGRO_ALIGN_LEFT, "(S)oftware: %s", (software && !use_shader) ? "On" : "Off"); al_draw_textf(font, al_map_rgb_f(1., 1., 0.5), 16, 32, ALLEGRO_ALIGN_LEFT, "Shade(r) (--shader to enable): %s", use_shader ? "On" : "Off"); al_draw_textf(font, al_map_rgb_f(1., 1., 0.5), 16, 48, ALLEGRO_ALIGN_LEFT, "(P)rimitive type: %s", prim_names[prim_type]); for (int i = 0; i < 4; i++) { al_draw_text(font, al_map_rgb_f(1., 0.5, 1.), offt_x + spacing + w * i + w / 2, 64, ALLEGRO_ALIGN_CENTRE, wrap_names[i]); for (int j = 0; j < 4; j++) { if (i == 0) { al_draw_text(font, al_map_rgb_f(1., 0.5, 1.), 16, offt_y + spacing + h * j + h / 2, ALLEGRO_ALIGN_LEFT, wrap_names[j]); } if (use_shader) { al_use_shader(shader); // Note that this part will look different in D3D and OpenGL. // In GL, the wrapping is attached to textures, so // when sampling twice from the same texture they must // share the same wrapping mode. This runs into an // issue with the primitives addon which attempts to // change it on the fly. To get consistent behavior, // use the non-default wrapping mode. al_set_shader_sampler("tex2", bitmaps[i][j], 1); draw_square(bitmaps[i][j], offt_x + spacing + w * i, offt_y + spacing + h * j, bw, bh, prim_type); al_use_shader(NULL); } else { draw_square(bitmaps[i][j], offt_x + spacing + w * i, offt_y + spacing + h * j, bw, bh, prim_type); } } } if (software && !use_shader) { al_set_target_bitmap(display_buffer); al_draw_bitmap(memory_buffer, 0, 0, 0); } al_flip_display(); } } al_destroy_bitmap(bitmap); al_destroy_bitmap(memory_buffer); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { al_destroy_bitmap(bitmaps[i][j]); } } al_destroy_font(font); return 0; } /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/examples/ex_projection.c000066400000000000000000000160361473414355200203200ustar00rootroot00000000000000#include #include #include #include "common.c" /* How far has the text been scrolled. */ static float scroll_y; /* Total length of the scrolling text in pixels. */ static int text_length; /* The Alex logo. */ static ALLEGRO_BITMAP *logo; /* The star particle. */ static ALLEGRO_BITMAP *particle; /* The font we use for everything. */ static ALLEGRO_FONT *font; /* Local pseudo-random number generator. */ static int rnd(int *seed) { *seed = (*seed + 1) * 1103515245 + 12345; return ((*seed >> 16) & 0xffff); } /* Load a bitmap or font and exit with a message if it's missing. */ static void *load(char const *path, char const *type, ...) { void *data = NULL; va_list args; va_start(args, type); if (!strcmp(type, "bitmap")) { data = al_load_bitmap(path); } else if (!strcmp(type, "font")) { int size = va_arg(args, int); int flags = va_arg(args, int); data = al_load_font(path, size, flags); } va_end(args); if (!data) { abort_example("Could not load %s %s", type, path); } return data; } /* Print fading text. */ static int print(ALLEGRO_FONT *font, float x, float y, float r, float g, float b, float fade, char const *text) { float c = 1 + (y - fade) / 360 / 2.0; if (c > 1) c = 1; if (c < 0) c = 0; al_draw_text(font, al_map_rgba_f(c * r, c * g, c * b, c), x, y, ALLEGRO_ALIGN_CENTER, text); return y + al_get_font_line_height(font); } /* Set up a perspective transform. We make the screen span * 180 vertical units with square pixel aspect and 90° vertical * FoV. */ static void setup_3d_projection(ALLEGRO_TRANSFORM *projection) { ALLEGRO_DISPLAY *display = al_get_current_display(); int dw = al_get_display_width(display); int dh = al_get_display_height(display); al_perspective_transform(projection, -180 * dw / dh, -180, 180, 180 * dw / dh, 180, 3000); al_use_projection_transform(projection); } /* 3D transformations make it very easy to draw a starfield. */ static void draw_stars(void) { ALLEGRO_TRANSFORM projection; int seed; int i; al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); seed = 0; for (i = 0; i < 100; i++) { const int x = rnd(&seed); const int y = rnd(&seed); const int z = rnd(&seed); al_identity_transform(&projection); al_translate_transform_3d(&projection, 0, 0, -2000 + ((int)scroll_y * 1000 / text_length + z) % 2000 - 180); setup_3d_projection(&projection); al_draw_bitmap(particle, x % 4000 - 2000, y % 2000 - 1000, 0); } } /* The main part of this example. */ static void draw_scrolling_text(void) { ALLEGRO_TRANSFORM projection; int bw = al_get_bitmap_width(logo); int bh = al_get_bitmap_height(logo); float x, y, c; al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_identity_transform(&projection); /* First, we scroll the text in in the y direction (inside the x/z * plane) and move it away from the camera (in the z direction). * We move it as far as half the display height to get a vertical * FOV of 90 degrees. */ al_translate_transform_3d(&projection, 0, -scroll_y, -180); /* Then we tilt it backwards 30 degrees. */ al_rotate_transform_3d(&projection, 1, 0, 0, 30 * ALLEGRO_PI / 180.0); /* And finally move it down so the 0 position ends up * at the bottom of the screen. */ al_translate_transform_3d(&projection, 0, 180, 0); setup_3d_projection(&projection); x = 0; y = 0; c = 1 + (y - scroll_y) / 360 / 2.0; if (c < 0) c = 0; al_draw_tinted_bitmap(logo, al_map_rgba_f(c, c, c, c), x - bw / 2, y, 0); y += bh; #define T(str) (y = print(font, x, y, 1, 0.9, 0.3, scroll_y, (str))); T("Allegro 5") T("") T("It is a period of game programming.") T("Game coders have won their first") T("victory against the evil") T("General Protection Fault.") T("") T("During the battle, hackers managed") T("to steal the secret source to the") T("General's ultimate weapon,") T("the ACCESS VIOLATION, a kernel") T("exception with enough power to") T("destroy an entire program.") T("") T("Pursued by sinister bugs the") T("Allegro developers race home") T("aboard their library to save") T("all game programmers and restore") T("freedom to the open source world.") #undef T } static void draw_intro_text(void) { ALLEGRO_TRANSFORM projection; int fade; int fh = al_get_font_line_height(font); if (scroll_y < 50) fade = (50 - scroll_y) * 12; else fade = (scroll_y - 50) * 4; al_identity_transform(&projection); al_translate_transform_3d(&projection, 0, -scroll_y / 3, -181); setup_3d_projection(&projection); print(font, 0, 0, 0, 0.9, 1, fade, "A long time ago, in a galaxy"); print(font, 0, 0 + fh, 0, 0.9, 1, fade, "not too far away..."); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; int redraw = 0; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_image_addon(); al_init_font_addon(); al_init_ttf_addon(); init_platform_specific(); al_install_keyboard(); al_set_new_display_flags(ALLEGRO_RESIZABLE); display = al_create_display(640, 360); if (!display) { abort_example("Error creating display\n"); } al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR | ALLEGRO_MIPMAP); font = load("data/DejaVuSans.ttf", "font", 40, 0); logo = load("data/alexlogo.png", "bitmap"); particle = load("data/haiku/air_effect.png", "bitmap"); al_convert_mask_to_alpha(logo, al_map_rgb(255, 0, 255)); text_length = al_get_bitmap_height(logo) + 19 * al_get_font_line_height(font); timer = al_create_timer(1.0 / 60); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (true) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; else if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { al_acknowledge_resize(display); } else if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } else if (event.type == ALLEGRO_EVENT_TIMER) { scroll_y++; if (scroll_y > text_length * 2) scroll_y -= text_length * 2; redraw = 1; } if (redraw && al_is_event_queue_empty(queue)) { ALLEGRO_COLOR black = al_map_rgba_f(0, 0, 0, 1); al_clear_to_color(black); draw_stars(); draw_scrolling_text(); draw_intro_text(); al_flip_display(); redraw = 0; } } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_projection2.c000066400000000000000000000143701473414355200204010ustar00rootroot00000000000000#include #include #include #include #include #include "common.c" static void draw_pyramid(ALLEGRO_BITMAP* texture, float x, float y, float z, float theta) { ALLEGRO_COLOR c = al_map_rgb_f(1, 1, 1); ALLEGRO_TRANSFORM t; ALLEGRO_VERTEX vtx[5] = { /* x y z u v c */ { 0, 1, 0, 0, 64, c}, {-1, -1, -1, 0, 0, c}, { 1, -1, -1, 64, 64, c}, { 1, -1, 1, 64, 0, c}, {-1, -1, 1, 64, 64, c}, }; int indices[12] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 1 }; al_identity_transform(&t); al_rotate_transform_3d(&t, 0, 1, 0, theta); al_translate_transform_3d(&t, x, y, z); al_use_transform(&t); al_draw_indexed_prim(vtx, NULL, texture, indices, 12, ALLEGRO_PRIM_TRIANGLE_LIST); } static void set_perspective_transform(ALLEGRO_BITMAP* bmp) { ALLEGRO_TRANSFORM p; float aspect_ratio = (float)al_get_bitmap_height(bmp) / al_get_bitmap_width(bmp); al_set_target_bitmap(bmp); al_identity_transform(&p); al_perspective_transform(&p, -1, aspect_ratio, 1, 1, -aspect_ratio, 1000); al_use_projection_transform(&p); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_BITMAP *texture; ALLEGRO_BITMAP *display_sub_persp; ALLEGRO_BITMAP *display_sub_ortho; ALLEGRO_BITMAP *buffer; ALLEGRO_FONT *font; bool redraw = false; bool quit = false; bool fullscreen = false; bool background = false; int display_flags = ALLEGRO_RESIZABLE; float theta = 0; if (argc > 1) { if(strcmp(argv[1], "--use-shaders") == 0) { display_flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; } else { abort_example("Unknown command line argument: %s\n", argv[1]); } } if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_image_addon(); al_init_primitives_addon(); al_init_font_addon(); init_platform_specific(); al_install_keyboard(); al_set_new_display_flags(display_flags); al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 16, ALLEGRO_SUGGEST); /* Load everything as a POT bitmap to make sure the projection stuff works * with mismatched backing texture and bitmap sizes. */ al_set_new_display_option(ALLEGRO_SUPPORT_NPOT_BITMAP, 0, ALLEGRO_REQUIRE); display = al_create_display(800, 600); if (!display) { abort_example("Error creating display\n"); } al_set_window_constraints(display, 256, 512, 0, 0); al_apply_window_constraints(display, true); set_perspective_transform(al_get_backbuffer(display)); /* This bitmap is a sub-bitmap of the display, and has a perspective transformation. */ display_sub_persp = al_create_sub_bitmap(al_get_backbuffer(display), 0, 0, 256, 256); set_perspective_transform(display_sub_persp); /* This bitmap is a sub-bitmap of the display, and has a orthographic transformation. */ display_sub_ortho = al_create_sub_bitmap(al_get_backbuffer(display), 0, 0, 256, 512); /* This bitmap has a perspective transformation, purposefully non-POT */ buffer = al_create_bitmap(200, 200); set_perspective_transform(buffer); timer = al_create_timer(1.0 / 60); font = al_create_builtin_font(); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR | ALLEGRO_MIPMAP); texture = al_load_bitmap("data/bkg.png"); if (!texture) { abort_example("Could not load data/bkg.png"); } al_start_timer(timer); while (!quit) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: quit = true; break; case ALLEGRO_EVENT_DISPLAY_RESIZE: al_acknowledge_resize(display); set_perspective_transform(al_get_backbuffer(display)); break; case ALLEGRO_EVENT_KEY_DOWN: switch (event.keyboard.keycode) { case ALLEGRO_KEY_ESCAPE: quit = true; break; case ALLEGRO_KEY_SPACE: fullscreen = !fullscreen; al_set_display_flag(display, ALLEGRO_FULLSCREEN_WINDOW, fullscreen); set_perspective_transform(al_get_backbuffer(display)); break; } break; case ALLEGRO_EVENT_TIMER: redraw = true; theta = fmod(theta + 0.05, 2 * ALLEGRO_PI); break; case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING: background = true; al_acknowledge_drawing_halt(display); al_stop_timer(timer); break; case ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING: background = false; al_acknowledge_drawing_resume(display); al_start_timer(timer); break; } if (!background && redraw && al_is_event_queue_empty(queue)) { al_set_target_backbuffer(display); al_set_render_state(ALLEGRO_DEPTH_TEST, 1); al_clear_to_color(al_map_rgb_f(0, 0, 0)); al_clear_depth_buffer(1000); draw_pyramid(texture, 0, 0, -4, theta); al_set_target_bitmap(buffer); al_set_render_state(ALLEGRO_DEPTH_TEST, 1); al_clear_to_color(al_map_rgb_f(0, 0.1, 0.1)); al_clear_depth_buffer(1000); draw_pyramid(texture, 0, 0, -4, theta); al_set_target_bitmap(display_sub_persp); al_set_render_state(ALLEGRO_DEPTH_TEST, 1); al_clear_to_color(al_map_rgb_f(0, 0, 0.25)); al_clear_depth_buffer(1000); draw_pyramid(texture, 0, 0, -4, theta); al_set_target_bitmap(display_sub_ortho); al_set_render_state(ALLEGRO_DEPTH_TEST, 0); al_draw_text(font, al_map_rgb_f(1, 1, 1), 128, 16, ALLEGRO_ALIGN_CENTER, "Press Space to toggle fullscreen"); al_draw_bitmap(buffer, 0, 256, 0); al_flip_display(); redraw = false; } } return 0; } allegro5-5.2.10.1/examples/ex_record.c000066400000000000000000000260171473414355200174220ustar00rootroot00000000000000/* ex_record * * Press spacebar to begin and stop recording. Press 'p' to play back the * previous recording. Up to five minutes of audio will be recorded. * * The raw sample data is saved to a temporary file and played back via * an audio stream. Thus, minimal memory is used regardless of the length of * recording. * * When recording, it's important to keep the distinction between bytes and * samples. A sample is only exactly one byte long if it is 8-bit and mono. * Otherwise it is multiple bytes. The recording functions always work with * sample counts. However, when using things like memcpy() or fwrite(), you * will be working with bytes. */ #define ALLEGRO_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_primitives.h" #include "allegro5/allegro_acodec.h" #include "common.c" /* Comment out the following line to use 16-bit audio */ #define WANT_8_BIT_DEPTH /* The following constants are needed so that the rest of the code can * work independent from the audio depth. Both 8-bit and 16-bit should be * supported by all devices, so in your own programs you probably can get by * with just supporting one or the other. */ #ifdef WANT_8_BIT_DEPTH const ALLEGRO_AUDIO_DEPTH audio_depth = ALLEGRO_AUDIO_DEPTH_UINT8; typedef uint8_t* audio_buffer_t; const uint8_t sample_center = 128; const int8_t min_sample_val = 0x80; const int8_t max_sample_val = 0x7f; const int sample_range = 0xff; const int sample_size = 1; #else const ALLEGRO_AUDIO_DEPTH audio_depth = ALLEGRO_AUDIO_DEPTH_INT16; typedef int16_t* audio_buffer_t; const int16_t sample_center = 0; const int16_t min_sample_val = 0x8000; const int16_t max_sample_val = 0x7fff; const int sample_range = 0xffff; const int sample_size = 2; #endif /* How many samples do we want to process at one time? Let's pick a multiple of the width of the screen so that the visualization graph is easy to draw. */ const unsigned int samples_per_fragment = 320 * 4; /* Frequency is the quality of audio. (Samples per second.) Higher quality consumes more memory. For speech, numbers as low as 8000 can be good enough. 44100 is often used for high quality recording. */ const unsigned int frequency = 22050; const unsigned int max_seconds_to_record = 60 * 5; /* The playback buffer specs don't need to match the recording sizes. * The values here are slightly large to help make playback more smooth. */ const unsigned int playback_fragment_count = 4; const unsigned int playback_samples_per_fragment = 4096; int main(int argc, char **argv) { ALLEGRO_AUDIO_RECORDER *r; ALLEGRO_AUDIO_STREAM *s; ALLEGRO_EVENT_QUEUE *q; ALLEGRO_DISPLAY *d; ALLEGRO_FILE *fp = NULL; ALLEGRO_PATH *tmp_path = NULL; int prev = 0; bool is_recording = false; int n = 0; /* number of samples written to disk */ (void) argc; (void) argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } if (!al_init_primitives_addon()) { abort_example("Unable to initialize primitives addon"); } if (!al_install_keyboard()) { abort_example("Unable to install keyboard"); } if (!al_install_audio()) { abort_example("Unable to initialize audio addon"); } if (!al_init_acodec_addon()) { abort_example("Unable to initialize acodec addon"); } /* Note: increasing the number of channels will break this demo. Other * settings can be changed by modifying the constants at the top of the * file. */ r = al_create_audio_recorder(1000, samples_per_fragment, frequency, audio_depth, ALLEGRO_CHANNEL_CONF_1); if (!r) { abort_example("Unable to create audio recorder"); } s = al_create_audio_stream(playback_fragment_count, playback_samples_per_fragment, frequency, audio_depth, ALLEGRO_CHANNEL_CONF_1); if (!s) { abort_example("Unable to create audio stream"); } al_reserve_samples(0); al_set_audio_stream_playing(s, false); al_attach_audio_stream_to_mixer(s, al_get_default_mixer()); q = al_create_event_queue(); /* Note: the following two options are referring to pixel samples, and have * nothing to do with audio samples. */ al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST); al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST); d = al_create_display(320, 256); if (!d) { abort_example("Error creating display\n"); } al_set_window_title(d, "SPACE to record. P to playback."); al_register_event_source(q, al_get_audio_recorder_event_source(r)); al_register_event_source(q, al_get_audio_stream_event_source(s)); al_register_event_source(q, al_get_display_event_source(d)); al_register_event_source(q, al_get_keyboard_event_source()); al_start_audio_recorder(r); while (true) { ALLEGRO_EVENT e; al_wait_for_event(q, &e); if (e.type == ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT) { /* We received an incoming fragment from the microphone. In this * example, the recorder is constantly recording even when we aren't * saving to disk. The display is updated every time a new fragment * comes in, because it makes things more simple. If the fragments * are coming in faster than we can update the screen, then it will be * a problem. */ ALLEGRO_AUDIO_RECORDER_EVENT *re = al_get_audio_recorder_event(&e); audio_buffer_t input = (audio_buffer_t) re->buffer; int sample_count = re->samples; const int R = sample_count / 320; int i, gain = 0; /* Calculate the volume, and display it regardless if we are actively * recording to disk. */ for (i = 0; i < sample_count; ++i) { if (gain < abs(input[i] - sample_center)) gain = abs(input[i] - sample_center); } al_clear_to_color(al_map_rgb(0,0,0)); if (is_recording) { /* Save raw bytes to disk. Assumes everything is written * succesfully. */ if (fp && n < frequency / (float) samples_per_fragment * max_seconds_to_record) { al_fwrite(fp, input, sample_count * sample_size); ++n; } /* Draw a pathetic visualization. It draws exactly one fragment * per frame. This means the visualization is dependent on the * various parameters. A more thorough implementation would use this * event to copy the new data into a circular buffer that holds a * few seconds of audio. The graphics routine could then always * draw that last second of audio, which would cause the * visualization to appear constant across all different settings. */ for (i = 0; i < 320; ++i) { int j, c = 0; /* Take the average of R samples so it fits on the screen */ for (j = i * R; j < i * R + R && j < sample_count; ++j) { c += input[j] - sample_center; } c /= R; /* Draws a line from the previous sample point to the next */ al_draw_line(i - 1, 128 + ((prev - min_sample_val) / (float) sample_range) * 256 - 128, i, 128 + ((c - min_sample_val) / (float) sample_range) * 256 - 128, al_map_rgb(255,255,255), 1.2); prev = c; } } /* draw volume bar */ al_draw_filled_rectangle((gain / (float) max_sample_val) * 320, 251, 0, 256, al_map_rgba(0, 255, 0, 128)); al_flip_display(); } else if (e.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT) { /* This event is received when we are playing back the audio clip. * See ex_saw.c for an example dedicated to playing streams. */ if (fp) { audio_buffer_t output = al_get_audio_stream_fragment(s); if (output) { /* Fill the buffer from the data we have recorded into the file. * If an error occurs (or end of file) then silence out the * remainder of the buffer and stop the playback. */ const size_t bytes_to_read = playback_samples_per_fragment * sample_size; size_t bytes_read = 0, i; do { bytes_read += al_fread(fp, (uint8_t *)output + bytes_read, bytes_to_read - bytes_read); } while (bytes_read < bytes_to_read && !al_feof(fp) && !al_ferror(fp)); /* silence out unused part of buffer (end of file) */ for (i = bytes_read / sample_size; i < bytes_to_read / sample_size; ++i) { output[i] = sample_center; } al_set_audio_stream_fragment(s, output); if (al_ferror(fp) || al_feof(fp)) { al_drain_audio_stream(s); al_fclose(fp); fp = NULL; } } } } else if (e.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } else if (e.type == ALLEGRO_EVENT_KEY_CHAR) { if (e.keyboard.unichar == 27) { /* pressed ESC */ break; } else if (e.keyboard.unichar == ' ') { if (!is_recording) { /* Start the recording */ is_recording = true; if (al_get_audio_stream_playing(s)) { al_drain_audio_stream(s); } /* Reuse the same temp file for all recordings */ if (!tmp_path) { fp = al_make_temp_file("alrecXXX.raw", &tmp_path); } else { if (fp) al_fclose(fp); fp = al_fopen(al_path_cstr(tmp_path, '/'), "w"); } n = 0; } else { is_recording = false; if (fp) { al_fclose(fp); fp = NULL; } } } else if (e.keyboard.unichar == 'p') { /* Play the previously recorded wav file */ if (!is_recording) { if (tmp_path) { fp = al_fopen(al_path_cstr(tmp_path, '/'), "r"); if (fp) { al_set_audio_stream_playing(s, true); } } } } } } /* clean up */ al_destroy_audio_recorder(r); al_destroy_audio_stream(s); if (fp) al_fclose(fp); if (tmp_path) { al_remove_filename(al_path_cstr(tmp_path, '/')); al_destroy_path(tmp_path); } return 0; } allegro5-5.2.10.1/examples/ex_record_name.c000066400000000000000000000223021473414355200204130ustar00rootroot00000000000000/* ex_record_name * * This example automatically detects when you say your name and creates a * sample (maximum of three seconds). Pressing any key (other than ESC) will * play it back. */ #define ALLEGRO_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_acodec.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_primitives.h" #include "common.c" int main(int argc, char *argv[]) { ALLEGRO_DISPLAY *display; ALLEGRO_FONT *font; ALLEGRO_AUDIO_RECORDER *recorder; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_TIMER *timer; int font_height; /* Frequency is the number of samples per second. */ const int frequency = 44100; const int channels = 2; /* The latency is used to determine the size of the fragment buffer. More accurately, it represents approximately how many seconds will pass between fragment events. (There may be overhead latency from the OS or driver the adds a fixed amount of latency on top of Allegro's.) For this example, the latency should be kept relatively low since each fragment is processed in its entirety. Increasing the latency would increase the size of the fragment, which would decrease the accuracy of the code that processes the fragment. But if it's too low, then it will cut out too quickly. (If the example were more thoroughly written, the latency setting wouldn't actually change how the voice detection worked.) */ const float latency = 0.10; const int max_seconds = 3; /* number of seconds of voice recording */ int16_t *name_buffer; /* stores up to max_seconds of audio */ int16_t *name_buffer_pos; /* points to the current recorded position */ int16_t *name_buffer_end; /* points to the end of the buffer */ float gain = 0.0f; /* 0.0 (quiet) - 1.0 (loud) */ float begin_gain = 0.3f; /* when to begin recording */ bool is_recording = false; ALLEGRO_SAMPLE *spl = NULL; (void) argc; (void) argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } if (!al_install_audio()) { abort_example("Unable to initialize audio addon\n"); } if (!al_init_acodec_addon()) { abort_example("Unable to initialize acoded addon\n"); } if (!al_init_image_addon()) { abort_example("Unable to initialize image addon\n"); } if (!al_init_primitives_addon()) { abort_example("Unable to initialize primitives addon\n"); } al_init_font_addon(); al_install_keyboard(); font = al_load_bitmap_font("data/bmpfont.tga"); if (!font) { abort_example("Unable to load data/a4_font.tga\n"); } font_height = al_get_font_line_height(font); /* WARNING: This demo assumes an audio depth of INT16 and two channels. Changing those values will break the demo. Nothing here really needs to be changed. If you want to fiddle with things, adjust the constants at the beginning of the program. */ recorder = al_create_audio_recorder( 5 / latency, /* five seconds of buffer space */ frequency * latency, /* configure the fragment size to give us the given latency in seconds */ frequency, /* samples per second (higher => better quality) */ ALLEGRO_AUDIO_DEPTH_INT16, /* 2-byte sample size */ ALLEGRO_CHANNEL_CONF_2 /* stereo */ ); if (!recorder) { abort_example("Unable to create audio recorder\n"); } display = al_create_display(640, 480); if (!display) { abort_example("Unable to create display\n"); } /* Used to play back the voice recording. */ al_reserve_samples(1); /* store up to three seconds */ name_buffer = al_calloc(channels * frequency * max_seconds, sizeof(int16_t)); name_buffer_pos = name_buffer; name_buffer_end = name_buffer + channels * frequency * max_seconds; queue = al_create_event_queue(); timer = al_create_timer(1 / 60.0); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_audio_recorder_event_source(recorder)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_keyboard_event_source()); al_start_timer(timer); al_start_audio_recorder(recorder); while (true) { ALLEGRO_EVENT event; bool do_draw = false; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE || (event.type == ALLEGRO_EVENT_KEY_UP && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)) { break; } else if (event.type == ALLEGRO_EVENT_KEY_CHAR) { if (spl && event.keyboard.unichar != 27) { al_play_sample(spl, 1.0, 0.0, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL); } } else if (event.type == ALLEGRO_EVENT_TIMER) { do_draw = true; } else if (event.type == ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT && recorder != NULL) { /* Because the recording happens in a different thread (and simply because we are queuing up events), it's quite possible to receive (process) a fragment event after the recorder has been stopped or destroyed. Thus, it is important to somehow check that the recorder is still valid, as we are doing above. */ ALLEGRO_AUDIO_RECORDER_EVENT *re = al_get_audio_recorder_event(&event); int16_t *buffer = re->buffer; int16_t low = 0, high = 0; unsigned int i; /* Calculate the volume by comparing the highest and lowest points. This entire section assumes we are using fairly small fragment size (low latency). If a large fragment size were used, then we'd have to inspect smaller portions of it at a time to more accurately deterine when recording started and stopped. */ for (i = 0; i < channels * re->samples; ++i) { if (buffer[i] < low) low = buffer[i]; else if (buffer[i] > high) high = buffer[i]; } gain = gain * 0.25 + ((float) (high - low) / 0xffff) * 0.75; /* Set arbitrary thresholds for beginning and stopping recording. This probably should be calibrated by determining how loud the ambient noise is. */ if (!is_recording && gain >= begin_gain && name_buffer_pos == name_buffer) is_recording = true; else if (is_recording && gain <= 0.10) is_recording = false; if (is_recording) { /* Copy out of the fragment buffer into our own buffer that holds the name. */ int samples_to_copy = channels * re->samples; /* Don't overfill up our name buffer... */ if (samples_to_copy > name_buffer_end - name_buffer_pos) samples_to_copy = name_buffer_end - name_buffer_pos; if (samples_to_copy) { /* must multiply by two, since we are using 16-bit samples */ memcpy(name_buffer_pos, re->buffer, samples_to_copy * 2); } name_buffer_pos += samples_to_copy; if (name_buffer_pos >= name_buffer_end) { is_recording = false; } } if (!is_recording && name_buffer_pos != name_buffer && !spl) { /* finished recording, but haven't created the sample yet */ spl = al_create_sample(name_buffer, name_buffer_pos - name_buffer, frequency, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2, false); /* We no longer need the recorder. Destroying it is the only way to unlock the device. */ al_destroy_audio_recorder(recorder); recorder = NULL; } } if (do_draw) { al_clear_to_color(al_map_rgb(0,0,0)); if (!spl) { const char *msg = "Say Your Name"; int width = al_get_text_width(font, msg); al_draw_text(font, al_map_rgb(255,255,255), 320, 240 - font_height / 2, ALLEGRO_ALIGN_CENTRE, msg ); /* draw volume meter */ al_draw_filled_rectangle(320 - width / 2, 242 + font_height / 2, (320 - width / 2) + (gain * width), 242 + font_height, al_map_rgb(0,255,0) ); /* draw target line that triggers recording */ al_draw_line((320 - width / 2) + (begin_gain * width), 242 + font_height / 2, (320 - width / 2) + (begin_gain * width), 242 + font_height, al_map_rgb(255,255,0), 1.0 ); } else { al_draw_text(font, al_map_rgb(255,255,255), 320, 240 - font_height / 2, ALLEGRO_ALIGN_CENTRE, "Press Any Key"); } al_flip_display(); } } if (recorder) { al_destroy_audio_recorder(recorder); } al_free(name_buffer); return 0; } allegro5-5.2.10.1/examples/ex_reparent.c000066400000000000000000000100301473414355200177500ustar00rootroot00000000000000#include #include #include #include #include #include "common.c" #define FPS 60 struct Example { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *glyphs[2]; ALLEGRO_BITMAP *sub; int i; int p; } example; /* Draw the parent bitmaps. */ static void draw_glyphs(void) { int x = 0, y = 0; al_clear_to_color(al_map_rgb_f(0, 0, 0)); al_draw_bitmap(example.glyphs[0], 0, 0, 0); al_draw_bitmap(example.glyphs[1], 0, 32 * 6, 0); if (example.p == 1) y = 32 * 6; x += al_get_bitmap_x(example.sub); y += al_get_bitmap_y(example.sub); al_draw_filled_rectangle(x, y, x + al_get_bitmap_width(example.sub), y + al_get_bitmap_height(example.sub), al_map_rgba_f(0.5, 0, 0, 0.5)); } static void redraw(void) { int i; draw_glyphs(); /* Here we draw example.sub, which is never re-created, just * re-parented. */ for (i = 0; i < 8; i++) { al_draw_scaled_rotated_bitmap(example.sub, 0, 0, i * 100, 32 * 6 + 33 * 5 + 4, 2.0, 2.0, ALLEGRO_PI / 4 * i / 8, 0); } } static void update(void) { /* Re-parent out sub bitmap, jumping from glyph to glyph. */ int i; example.i++; i = (example.i / 4) % (16 * 6 + 20 * 5); if (i < 16 * 6) { example.p = 0; al_reparent_bitmap(example.sub, example.glyphs[0], (i % 16) * 32, (i / 16) * 32, 32, 32); } else { example.p = 1; i -= 16 * 6; al_reparent_bitmap(example.sub, example.glyphs[1], (i % 20) * 37, (i / 20) * 33, 37, 33); } } static void init(void) { /* We create out sub bitmap once then use it throughout the * program, re-parenting as needed. */ example.sub = al_create_sub_bitmap(example.glyphs[0], 0, 0, 32, 32); } int main(int argc, char **argv) { ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; int w = 800, h = 600; bool done = false; bool need_redraw = true; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } if (!al_init_image_addon()) { abort_example("Failed to init IIO addon.\n"); } al_init_primitives_addon(); init_platform_specific(); al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); al_set_new_display_flags(ALLEGRO_RESIZABLE); example.display = al_create_display(w, h); if (!example.display) { abort_example("Error creating display.\n"); } if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } example.glyphs[0] = al_load_bitmap("data/font.tga"); if (!example.glyphs[0]) { abort_example("Error loading data/font.tga\n"); } example.glyphs[1] = al_load_bitmap("data/bmpfont.tga"); if (!example.glyphs[1]) { abort_example("Error loading data/bmpfont.tga\n"); } init(); timer = al_create_timer(1.0 / FPS); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source( example.display)); al_start_timer(timer); while (!done) { ALLEGRO_EVENT event; w = al_get_display_width(example.display); h = al_get_display_height(example.display); if (need_redraw && al_is_event_queue_empty(queue)) { redraw(); al_flip_display(); need_redraw = false; } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_CHAR: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_DISPLAY_RESIZE: al_acknowledge_resize(event.display.source); break; case ALLEGRO_EVENT_TIMER: update(); need_redraw = true; break; } } return 0; } allegro5-5.2.10.1/examples/ex_resample_test.c000066400000000000000000000113031473414355200210030ustar00rootroot00000000000000/* Resamping test. Probably should integreate into test_driver somehow */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "common.c" #define SAMPLES_PER_BUFFER 1024 #define N 2 int frequency[N]; double samplepos[N]; ALLEGRO_AUDIO_STREAM *stream[N]; ALLEGRO_DISPLAY *display; float waveform[640], waveform_buffer[640]; static void mainloop(void) { ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_TIMER *timer; float *buf; double pitch = 440; int i, si; int n = 0; bool redraw = false; for (i = 0; i < N; i++) { frequency[i] = 22050 * pow(2, i / (double)N); stream[i] = al_create_audio_stream(4, SAMPLES_PER_BUFFER, frequency[i], ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_1); if (!stream[i]) { abort_example("Could not create stream.\n"); } if (!al_attach_audio_stream_to_mixer(stream[i], al_get_default_mixer())) { abort_example("Could not attach stream to mixer.\n"); } } queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); for (i = 0; i < N; i++) { al_register_event_source(queue, al_get_audio_stream_event_source(stream[i])); } #ifdef ALLEGRO_POPUP_EXAMPLES if (textlog) { al_register_event_source(queue, al_get_native_text_log_event_source(textlog)); } #endif log_printf("Generating %d sine waves of different sampling quality\n", N); log_printf("If Allegro's resampling is correct there should be little variation\n", N); timer = al_create_timer(1.0 / 60); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(display)); al_start_timer(timer); while (n < 60 * frequency[0] / SAMPLES_PER_BUFFER * N) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT) { for (si = 0; si < N; si++) { buf = al_get_audio_stream_fragment(stream[si]); if (!buf) { continue; } for (i = 0; i < SAMPLES_PER_BUFFER; i++) { double t = samplepos[si]++ / (double)frequency[si]; buf[i] = sin(t * pitch * ALLEGRO_PI * 2) / N; } if (!al_set_audio_stream_fragment(stream[si], buf)) { log_printf("Error setting stream fragment.\n"); } n++; log_printf("%d", si); if ((n % 60) == 0) log_printf("\n"); } } if (event.type == ALLEGRO_EVENT_TIMER) { redraw = true; } if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } #ifdef ALLEGRO_POPUP_EXAMPLES if (event.type == ALLEGRO_EVENT_NATIVE_DIALOG_CLOSE) { break; } #endif if (redraw &&al_is_event_queue_empty(queue)) { ALLEGRO_COLOR c = al_map_rgb(0, 0, 0); int i; al_clear_to_color(al_map_rgb_f(1, 1, 1)); for (i = 0; i < 640; i++) { al_draw_pixel(i, 50 + waveform[i] * 50, c); } al_flip_display(); redraw = false; } } for (si = 0; si < N; si++) { al_drain_audio_stream(stream[si]); } log_printf("\n"); al_destroy_event_queue(queue); } static void update_waveform(void *buf, unsigned int samples, void *data) { static int pos; float *fbuf = (float *)buf; int i; int n = samples; (void)data; /* Yes, we could do something more advanced, but an oscilloscope of the * first 640 samples of each buffer is enough for our purpose here. */ if (n > 640) n = 640; for (i = 0; i < n; i++) { waveform_buffer[pos++] = fbuf[i * 2]; if (pos == 640) { memcpy(waveform, waveform_buffer, 640 * sizeof(float)); pos = 0; break; } } } int main(int argc, char **argv) { int i; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); open_log(); display = al_create_display(640, 100); if (!display) { abort_example("Could not create display.\n"); } if (!al_install_audio()) { abort_example("Could not init sound.\n"); } al_reserve_samples(N); al_set_mixer_postprocess_callback(al_get_default_mixer(), update_waveform, NULL); mainloop(); close_log(false); for (i = 0; i < N; i++) { al_destroy_audio_stream(stream[i]); } al_uninstall_audio(); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_resize.c000066400000000000000000000044721473414355200174460ustar00rootroot00000000000000#include "allegro5/allegro.h" #include #include "common.c" static void redraw(void) { ALLEGRO_COLOR black, white; int w, h; white = al_map_rgba_f(1, 1, 1, 1); black = al_map_rgba_f(0, 0, 0, 1); al_clear_to_color(white); w = al_get_bitmap_width(al_get_target_bitmap()); h = al_get_bitmap_height(al_get_target_bitmap()); al_draw_line(0, h, w / 2, 0, black, 0); al_draw_line(w / 2, 0, w, h, black, 0); al_draw_line(w / 4, h / 2, 3 * w / 4, h / 2, black, 0); al_flip_display(); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *events; ALLEGRO_EVENT event; int rs = 100; bool resize = false; (void)argc; (void)argv; /* Initialize Allegro and create an event queue. */ if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); events = al_create_event_queue(); /* Setup a display driver and register events from it. */ al_set_new_display_flags(ALLEGRO_RESIZABLE); display = al_create_display(rs, rs); if (!display) { abort_example("Could not create display.\n"); } al_register_event_source(events, al_get_display_event_source(display)); timer = al_create_timer(0.1); al_start_timer(timer); /* Setup a keyboard driver and register events from it. */ al_install_keyboard(); al_register_event_source(events, al_get_keyboard_event_source()); al_register_event_source(events, al_get_timer_event_source(timer)); /* Display a pulsating window until a key or the closebutton is pressed. */ redraw(); while (true) { if (resize) { int s; rs += 10; if (rs == 300) rs = 100; s = rs; if (s > 200) s = 400 - s; al_resize_display(display, s, s); redraw(); resize = false; } al_wait_for_event(events, &event); if (event.type == ALLEGRO_EVENT_TIMER) { resize = true; } else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } else if (event.type == ALLEGRO_EVENT_KEY_DOWN) { break; } } return 0; } /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/examples/ex_resize2.c000066400000000000000000000064741473414355200175340ustar00rootroot00000000000000/* * Test program for Allegro. * * Resizing the window currently shows broken behaviour. */ #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_font.h" #include #include "common.c" int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *bmp; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; ALLEGRO_FONT *font; bool redraw; bool halt_drawing; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_init_image_addon(); al_init_font_addon(); al_set_config_value(al_get_system_config(), "osx", "allow_live_resize", "false"); al_set_new_display_flags(ALLEGRO_RESIZABLE | ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(640, 480); if (!display) { abort_example("Unable to set any graphic mode\n"); } al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); bmp = al_load_bitmap("data/mysha.pcx"); if (!bmp) { abort_example("Unable to load image\n"); } font = al_create_builtin_font(); queue = al_create_event_queue(); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_keyboard_event_source()); redraw = true; halt_drawing = false; while (true) { if (!halt_drawing && redraw && al_is_event_queue_empty(queue)) { al_clear_to_color(al_map_rgb(255, 0, 0)); al_draw_scaled_bitmap(bmp, 0, 0, al_get_bitmap_width(bmp), al_get_bitmap_height(bmp), 0, 0, al_get_display_width(display), al_get_display_height(display), 0); al_draw_multiline_textf(font, al_map_rgb(255, 255, 0), 0, 0, 640, al_get_font_line_height(font), 0, "size: %d x %d\n" "maximized: %s\n" "+ key to maximize\n" "- key to un-maximize", al_get_display_width(display), al_get_display_height(display), al_get_display_flags(display) & ALLEGRO_MAXIMIZED ? "yes" : "no"); al_flip_display(); redraw = false; } al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { al_acknowledge_resize(event.display.source); redraw = true; } if (event.type == ALLEGRO_EVENT_DISPLAY_EXPOSE) { redraw = true; } if (event.type == ALLEGRO_EVENT_DISPLAY_HALT_DRAWING) { halt_drawing = true; al_acknowledge_drawing_halt(display); } if (event.type == ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING) { halt_drawing = false; al_acknowledge_drawing_resume(display); } if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } if (event.type == ALLEGRO_EVENT_KEY_CHAR && event.keyboard.unichar == '+') { al_set_display_flag(display, ALLEGRO_MAXIMIZED, true); } if (event.type == ALLEGRO_EVENT_KEY_CHAR && event.keyboard.unichar == '-') { al_set_display_flag(display, ALLEGRO_MAXIMIZED, false); } if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } } al_destroy_bitmap(bmp); al_destroy_display(display); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_rotate.c000066400000000000000000000112541473414355200174370ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. */ #include #include "allegro5/allegro_image.h" #include #include "common.c" int main(int argc, char **argv) { const int display_w = 640; const int display_h = 480; ALLEGRO_DISPLAY *dpy; ALLEGRO_BITMAP *buf; ALLEGRO_BITMAP *bmp; ALLEGRO_BITMAP *mem_bmp; ALLEGRO_BITMAP *src_bmp; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; double theta = 0; double k = 1.0; int mode = 0; bool wide_mode = false; bool mem_src_mode = false; bool trans_mode = false; int flags = 0; bool clip_mode = false; ALLEGRO_COLOR trans; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_init_image_addon(); init_platform_specific(); open_log(); log_printf("Press 'w' to toggle wide mode.\n"); log_printf("Press 's' to toggle memory source bitmap.\n"); log_printf("Press space to toggle drawing to backbuffer or off-screen bitmap.\n"); log_printf("Press 't' to toggle translucency.\n"); log_printf("Press 'h' to toggle horizontal flipping.\n"); log_printf("Press 'v' to toggle vertical flipping.\n"); log_printf("Press 'c' to toggle clipping.\n"); log_printf("\n"); dpy = al_create_display(display_w, display_h); if (!dpy) { abort_example("Unable to set any graphic mode\n"); } buf = al_create_bitmap(display_w, display_h); if (!buf) { abort_example("Unable to create buffer\n\n"); } bmp = al_load_bitmap("data/mysha.pcx"); if (!bmp) { abort_example("Unable to load image\n"); } al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); mem_bmp = al_load_bitmap("data/mysha.pcx"); if (!mem_bmp) { abort_example("Unable to load image\n"); } queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); while (true) { if (al_get_next_event(queue, &event)) { if (event.type == ALLEGRO_EVENT_KEY_CHAR) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; if (event.keyboard.unichar == ' ') { mode = !mode; if (mode == 0) log_printf("Drawing to off-screen buffer\n"); else log_printf("Drawing to display backbuffer\n"); } if (event.keyboard.unichar == 'w') wide_mode = !wide_mode; if (event.keyboard.unichar == 's') { mem_src_mode = !mem_src_mode; if (mem_src_mode) log_printf("Source is memory bitmap\n"); else log_printf("Source is display bitmap\n"); } if (event.keyboard.unichar == 't') trans_mode = !trans_mode; if (event.keyboard.unichar == 'h') flags ^= ALLEGRO_FLIP_HORIZONTAL; if (event.keyboard.unichar == 'v') flags ^= ALLEGRO_FLIP_VERTICAL; if (event.keyboard.unichar == 'c') clip_mode = !clip_mode; } } /* * mode 0 = draw scaled to off-screen buffer before * blitting to display backbuffer * mode 1 = draw scaled to display backbuffer */ if (mode == 0) { al_set_target_bitmap(buf); } else { al_set_target_backbuffer(dpy); } src_bmp = (mem_src_mode) ? mem_bmp : bmp; k = (wide_mode) ? 2.0 : 1.0; al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); trans = al_map_rgba_f(1, 1, 1, 1); if (mode == 0) al_clear_to_color(al_map_rgba_f(1, 0, 0, 1)); else al_clear_to_color(al_map_rgba_f(0, 0, 1, 1)); if (trans_mode) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); trans = al_map_rgba_f(1, 1, 1, 0.5); } if (clip_mode) { al_set_clipping_rectangle(50, 50, display_w - 100, display_h - 100); } else { al_set_clipping_rectangle(0, 0, display_w, display_h); } al_draw_tinted_scaled_rotated_bitmap(src_bmp, trans, 50, 50, display_w/2, display_h/2, k, k, theta, flags); if (mode == 0) { al_set_target_backbuffer(dpy); al_set_clipping_rectangle(0, 0, display_w, display_h); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_draw_bitmap(buf, 0, 0, 0); } al_flip_display(); al_rest(0.01); theta -= 0.01; } al_destroy_bitmap(bmp); al_destroy_bitmap(mem_bmp); al_destroy_bitmap(buf); close_log(false); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_saw.c000066400000000000000000000056131473414355200167350ustar00rootroot00000000000000/* Recreate exstream.c from A4. */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "common.c" #define SAMPLES_PER_BUFFER 1024 static void saw(ALLEGRO_AUDIO_STREAM *stream) { ALLEGRO_EVENT_QUEUE *queue; int8_t *buf; int pitch = 0x10000; int val = 0; int i; int n = 200; queue = al_create_event_queue(); al_register_event_source(queue, al_get_audio_stream_event_source(stream)); #ifdef ALLEGRO_POPUP_EXAMPLES if (textlog) { al_register_event_source(queue, al_get_native_text_log_event_source(textlog)); } #endif log_printf("Generating saw wave...\n"); while (n > 0) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT) { buf = al_get_audio_stream_fragment(stream); if (!buf) { /* This is a normal condition you must deal with. */ continue; } for (i = 0; i < SAMPLES_PER_BUFFER; i++) { /* Crude saw wave at maximum amplitude. Please keep this compatible * to the A4 example so we know when something has broken for now. * * It would be nice to have a better example with user interface * and some simple synth effects. */ buf[i] = ((val >> 16) & 0xff); val += pitch; pitch++; } if (!al_set_audio_stream_fragment(stream, buf)) { log_printf("Error setting stream fragment.\n"); } n--; if ((n % 10) == 0) { log_printf("."); fflush(stdout); } } #ifdef ALLEGRO_POPUP_EXAMPLES if (event.type == ALLEGRO_EVENT_NATIVE_DIALOG_CLOSE) { break; } #endif } al_drain_audio_stream(stream); log_printf("\n"); al_destroy_event_queue(queue); } int main(int argc, char **argv) { ALLEGRO_AUDIO_STREAM *stream; void *buf; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } if (!al_install_audio()) { abort_example("Could not init sound.\n"); } al_reserve_samples(0); stream = al_create_audio_stream(8, SAMPLES_PER_BUFFER, 22050, ALLEGRO_AUDIO_DEPTH_UINT8, ALLEGRO_CHANNEL_CONF_1); while ((buf = al_get_audio_stream_fragment(stream))) { al_fill_silence(buf, SAMPLES_PER_BUFFER, ALLEGRO_AUDIO_DEPTH_UINT8, ALLEGRO_CHANNEL_CONF_1); al_set_audio_stream_fragment(stream, buf); } if (!stream) { abort_example("Could not create stream.\n"); } if (!al_attach_audio_stream_to_mixer(stream, al_get_default_mixer())) { abort_example("Could not attach stream to mixer.\n"); } open_log(); saw(stream); close_log(false); al_destroy_audio_stream(stream); al_uninstall_audio(); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_scale.c000066400000000000000000000115041473414355200172260ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. */ #include #include "allegro5/allegro_image.h" #include #include "common.c" int main(int argc, char **argv) { const int display_w = 640; const int display_h = 480; ALLEGRO_DISPLAY *dpy; ALLEGRO_BITMAP *buf; ALLEGRO_BITMAP *bmp; ALLEGRO_BITMAP *mem_bmp; ALLEGRO_BITMAP *src_bmp; int bmp_w; int bmp_h; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; double theta = 0; double k = 1.0; int mode = 0; bool wide_mode = false; bool mem_src_mode = false; bool trans_mode = false; int flags = 0; bool clip_mode = false; ALLEGRO_COLOR tint; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_init_image_addon(); init_platform_specific(); open_log(); log_printf("Press 'w' to toggle wide mode.\n"); log_printf("Press 's' to toggle memory source bitmap.\n"); log_printf("Press space to toggle drawing to backbuffer or off-screen bitmap.\n"); log_printf("Press 't' to toggle translucency.\n"); log_printf("Press 'h' to toggle horizontal flipping.\n"); log_printf("Press 'v' to toggle vertical flipping.\n"); log_printf("Press 'c' to toggle clipping.\n"); log_printf("\n"); dpy = al_create_display(display_w, display_h); if (!dpy) { abort_example("Unable to set any graphic mode\n"); } buf = al_create_bitmap(display_w, display_h); if (!buf) { abort_example("Unable to create buffer\n\n"); } bmp = al_load_bitmap("data/mysha.pcx"); if (!bmp) { abort_example("Unable to load image\n"); } al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); mem_bmp = al_load_bitmap("data/mysha.pcx"); if (!mem_bmp) { abort_example("Unable to load image\n"); } bmp_w = al_get_bitmap_width(bmp); bmp_h = al_get_bitmap_height(bmp); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); while (true) { if (al_get_next_event(queue, &event)) { if (event.type == ALLEGRO_EVENT_KEY_CHAR) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; if (event.keyboard.unichar == ' ') { mode = !mode; if (mode == 0) log_printf("Drawing to off-screen buffer\n"); else log_printf("Drawing to display backbuffer\n"); } if (event.keyboard.unichar == 'w') wide_mode = !wide_mode; if (event.keyboard.unichar == 's') { mem_src_mode = !mem_src_mode; if (mem_src_mode) log_printf("Source is memory bitmap\n"); else log_printf("Source is display bitmap\n"); } if (event.keyboard.unichar == 't') trans_mode = !trans_mode; if (event.keyboard.unichar == 'h') flags ^= ALLEGRO_FLIP_HORIZONTAL; if (event.keyboard.unichar == 'v') flags ^= ALLEGRO_FLIP_VERTICAL; if (event.keyboard.unichar == 'c') clip_mode = !clip_mode; } } /* * mode 0 = draw scaled to off-screen buffer before * blitting to display backbuffer * mode 1 = draw scaled to display backbuffer */ if (mode == 0) { al_set_target_bitmap(buf); } else { al_set_target_backbuffer(dpy); } src_bmp = (mem_src_mode) ? mem_bmp : bmp; k = (wide_mode) ? 2.0 : 1.0; al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); tint = al_map_rgba_f(1, 1, 1, 1); if (mode == 0) al_clear_to_color(al_map_rgba_f(1, 0, 0, 1)); else al_clear_to_color(al_map_rgba_f(0, 0, 1, 1)); if (trans_mode) { al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); tint = al_map_rgba_f(1, 1, 1, 0.5); } if (clip_mode) { al_set_clipping_rectangle(50, 50, display_w - 100, display_h - 100); } else { al_set_clipping_rectangle(0, 0, display_w, display_h); } al_draw_tinted_scaled_bitmap(src_bmp, tint, 0, 0, bmp_w, bmp_h, display_w/2, display_h/2, k * cos(theta) * display_w/2, k * sin(theta) * display_h/2, flags); if (mode == 0) { al_set_target_backbuffer(dpy); al_set_clipping_rectangle(0, 0, display_w, display_h); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_draw_bitmap(buf, 0, 0, 0); } al_flip_display(); al_rest(0.01); theta += 0.01; } al_destroy_bitmap(bmp); al_destroy_bitmap(mem_bmp); al_destroy_bitmap(buf); close_log(false); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_shader.cpp000066400000000000000000000076371473414355200177610ustar00rootroot00000000000000#include #include "allegro5/allegro5.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_primitives.h" /* The ALLEGRO_CFG_* defines are actually internal to Allegro so don't use them * in your own programs. */ #ifdef ALLEGRO_CFG_D3D #include "allegro5/allegro_direct3d.h" #endif #ifdef ALLEGRO_CFG_OPENGL #include "allegro5/allegro_opengl.h" #endif #include "common.c" static int display_flags = 0; static void parse_args(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { if (0 == strcmp(argv[i], "--opengl")) { display_flags = ALLEGRO_OPENGL; continue; } #ifdef ALLEGRO_CFG_D3D if (0 == strcmp(argv[i], "--d3d")) { display_flags = ALLEGRO_DIRECT3D; continue; } #endif abort_example("Unrecognised argument: %s\n", argv[i]); } } static void choose_shader_source(ALLEGRO_SHADER *shader, char const **vsource, char const **psource) { ALLEGRO_SHADER_PLATFORM platform = al_get_shader_platform(shader); if (platform == ALLEGRO_SHADER_HLSL) { *vsource = "data/ex_shader_vertex.hlsl"; *psource = "data/ex_shader_pixel.hlsl"; } else if (platform == ALLEGRO_SHADER_GLSL) { *vsource = "data/ex_shader_vertex.glsl"; *psource = "data/ex_shader_pixel.glsl"; } else { /* Shouldn't happen. */ *vsource = NULL; *psource = NULL; } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *bmp; ALLEGRO_SHADER *shader; const char *vsource; const char *psource; parse_args(argc, argv); if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_init_image_addon(); init_platform_specific(); al_set_new_display_flags(ALLEGRO_PROGRAMMABLE_PIPELINE | display_flags); display = al_create_display(640, 480); if (!display) { abort_example("Could not create display.\n"); } bmp = al_load_bitmap("data/mysha.pcx"); if (!bmp) { abort_example("Could not load bitmap.\n"); } shader = al_create_shader(ALLEGRO_SHADER_AUTO); if (!shader) { abort_example("Could not create shader.\n"); } choose_shader_source(shader, &vsource, &psource); if (!vsource|| !psource) { abort_example("Could not load source files.\n"); } if (!al_attach_shader_source_file(shader, ALLEGRO_VERTEX_SHADER, vsource)) { abort_example("al_attach_shader_source_file failed: %s\n", al_get_shader_log(shader)); } if (!al_attach_shader_source_file(shader, ALLEGRO_PIXEL_SHADER, psource)) { abort_example("al_attach_shader_source_file failed: %s\n", al_get_shader_log(shader)); } if (!al_build_shader(shader)) { abort_example("al_build_shader failed: %s\n", al_get_shader_log(shader)); } al_use_shader(shader); float tints[12] = { 4.0, 0.0, 1.0, 0.0, 4.0, 1.0, 1.0, 0.0, 4.0, 4.0, 4.0, 1.0 }; while (1) { ALLEGRO_KEYBOARD_STATE s; al_get_keyboard_state(&s); if (al_key_down(&s, ALLEGRO_KEY_ESCAPE)) break; al_clear_to_color(al_map_rgb(140, 40, 40)); al_set_shader_float_vector("tint", 3, &tints[0], 1); al_draw_bitmap(bmp, 0, 0, 0); al_set_shader_float_vector("tint", 3, &tints[3], 1); al_draw_bitmap(bmp, 320, 0, 0); al_set_shader_float_vector("tint", 3, &tints[6], 1); al_draw_bitmap(bmp, 0, 240, 0); /* Draw the last one transformed */ ALLEGRO_TRANSFORM trans, backup; al_copy_transform(&backup, al_get_current_transform()); al_identity_transform(&trans); al_translate_transform(&trans, 320, 240); al_set_shader_float_vector("tint", 3, &tints[9], 1); al_use_transform(&trans); al_draw_bitmap(bmp, 0, 0, 0); al_use_transform(&backup); al_flip_display(); al_rest(0.01); } al_use_shader(NULL); al_destroy_shader(shader); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_shader_multitex.c000066400000000000000000000102471473414355200213430ustar00rootroot00000000000000#include #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_opengl.h" #include "common.c" static ALLEGRO_BITMAP *load_bitmap(char const *filename) { ALLEGRO_BITMAP *bitmap = al_load_bitmap(filename); if (!bitmap) abort_example("%s not found or failed to load\n", filename); return bitmap; } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *bitmap[2]; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; bool redraw = true; ALLEGRO_SHADER *shader; int t = 0; const char* pixel_file = NULL; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_mouse(); al_install_keyboard(); al_init_image_addon(); init_platform_specific(); al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR | ALLEGRO_MIPMAP); al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST); al_set_new_display_option(ALLEGRO_SAMPLES, 4, ALLEGRO_SUGGEST); al_set_new_display_flags(ALLEGRO_PROGRAMMABLE_PIPELINE); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } bitmap[0]= load_bitmap("data/mysha.pcx"); bitmap[1]= load_bitmap("data/obp.jpg"); shader = al_create_shader(ALLEGRO_SHADER_AUTO); if (!shader) abort_example("Error creating shader.\n"); if (al_get_shader_platform(shader) == ALLEGRO_SHADER_GLSL) { #ifdef ALLEGRO_CFG_SHADER_GLSL pixel_file = "data/ex_shader_multitex_pixel.glsl"; #endif } else { #ifdef ALLEGRO_CFG_SHADER_HLSL pixel_file = "data/ex_shader_multitex_pixel.hlsl"; #endif } if (!pixel_file) { abort_example("No shader source\n"); } if (!al_attach_shader_source(shader, ALLEGRO_VERTEX_SHADER, al_get_default_shader_source(ALLEGRO_SHADER_AUTO, ALLEGRO_VERTEX_SHADER))) { abort_example("al_attach_shader_source for vertex shader failed: %s\n", al_get_shader_log(shader)); } if (!al_attach_shader_source_file(shader, ALLEGRO_PIXEL_SHADER, pixel_file)) abort_example("al_attach_shader_source_file for pixel shader failed: %s\n", al_get_shader_log(shader)); if (!al_build_shader(shader)) abort_example("al_build_shader failed: %s\n", al_get_shader_log(shader)); al_use_shader(shader); timer = al_create_timer(1.0 / 60); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (1) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; if (event.type == ALLEGRO_EVENT_KEY_CHAR) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) break; } if (event.type == ALLEGRO_EVENT_TIMER) { redraw = true; t++; } if (redraw && al_is_event_queue_empty(queue)) { int dw, dh; double scale = 1 + 100 * (1 + sin(t * ALLEGRO_PI * 2 / 60 / 10)); double angle = ALLEGRO_PI * 2 * t / 60 / 15; double x = 120 - 20 * cos(ALLEGRO_PI * 2 * t / 60 / 25); double y = 120 - 20 * sin(ALLEGRO_PI * 2 * t / 60 / 25); dw = al_get_display_width(display); dh = al_get_display_height(display); redraw = false; al_clear_to_color(al_map_rgb_f(0, 0, 0)); /* We set a second bitmap for texture unit 1. Unit 0 will have * the normal texture which al_draw_*_bitmap will set up for us. * We then draw the bitmap like normal, except it will use the * custom shader. */ al_set_shader_sampler("tex2", bitmap[1], 1); al_draw_scaled_rotated_bitmap(bitmap[0], x, y, dw / 2, dh / 2, scale, scale, angle, 0); al_flip_display(); } } al_use_shader(NULL); al_destroy_bitmap(bitmap[0]); al_destroy_bitmap(bitmap[1]); al_destroy_shader(shader); return 0; } /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/examples/ex_shader_target.c000066400000000000000000000104621473414355200207550ustar00rootroot00000000000000/* * Example program for the Allegro library. * * Test that shaders are applied per target bitmap. */ #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "common.c" static const int MAX_REGION = 4; static float tints[12] = { 4.0, 0.0, 1.0, 0.0, 4.0, 1.0, 1.0, 0.0, 4.0, 4.0, 4.0, 1.0 }; static void choose_shader_source(ALLEGRO_SHADER_PLATFORM platform, char const **vsource, char const **psource) { if (platform == ALLEGRO_SHADER_HLSL) { *vsource = "data/ex_shader_vertex.hlsl"; *psource = "data/ex_shader_pixel.hlsl"; } else if (platform == ALLEGRO_SHADER_GLSL) { *vsource = "data/ex_shader_vertex.glsl"; *psource = "data/ex_shader_pixel.glsl"; } else { /* Shouldn't happen. */ *vsource = NULL; *psource = NULL; } } static ALLEGRO_BITMAP *make_region(ALLEGRO_BITMAP *parent, int x, int y, int w, int h, ALLEGRO_SHADER *shader) { ALLEGRO_BITMAP *sub = al_create_sub_bitmap(parent, x, y, w, h); if (sub) { al_set_target_bitmap(sub); al_use_shader(shader); /* Not bothering to restore old target bitmap. */ } return sub; } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *image; ALLEGRO_BITMAP *backbuffer; ALLEGRO_BITMAP *region[4]; ALLEGRO_SHADER *shader; const char *vsource; const char *psource; ALLEGRO_TRANSFORM t; int i; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_init_image_addon(); init_platform_specific(); al_set_new_display_flags(ALLEGRO_PROGRAMMABLE_PIPELINE); display = al_create_display(640, 480); if (!display) { abort_example("Could not create display.\n"); } image = al_load_bitmap("data/mysha.pcx"); if (!image) { abort_example("Could not load image.\n"); } /* Create the shader. */ shader = al_create_shader(ALLEGRO_SHADER_AUTO); if (!shader) { abort_example("Could not create shader.\n"); } choose_shader_source(al_get_shader_platform(shader), &vsource, &psource); if (!vsource|| !psource) { abort_example("Could not load source files.\n"); } if (!al_attach_shader_source_file(shader, ALLEGRO_VERTEX_SHADER, vsource)) { abort_example("al_attach_shader_source_file failed: %s\n", al_get_shader_log(shader)); } if (!al_attach_shader_source_file(shader, ALLEGRO_PIXEL_SHADER, psource)) { abort_example("al_attach_shader_source_file failed: %s\n", al_get_shader_log(shader)); } if (!al_build_shader(shader)) { abort_example("al_build_shader failed: %s\n", al_get_shader_log(shader)); } /* Create four sub-bitmaps of the backbuffer sharing a shader. */ backbuffer = al_get_backbuffer(display); region[0] = make_region(backbuffer, 0, 0, 320, 200, shader); region[1] = make_region(backbuffer, 320, 0, 320, 200, shader); region[2] = make_region(backbuffer, 0, 240, 320, 200, shader); region[3] = make_region(backbuffer, 320, 240, 320, 200, shader); if (!region[0] || !region[1] || !region[2] || !region[3]) { abort_example("make_region failed\n"); } /* Apply a transformation to the last region (the current target). */ al_identity_transform(&t); al_scale_transform(&t, 2.0, 2.0); al_translate_transform(&t, -160, -100); al_use_transform(&t); for (;;) { ALLEGRO_KEYBOARD_STATE s; al_get_keyboard_state(&s); if (al_key_down(&s, ALLEGRO_KEY_ESCAPE)) break; for (i = 0; i < MAX_REGION; i++) { /* When we change the target bitmap, the shader that was last used on * that bitmap is automatically in effect. All of our region * sub-bitmaps use the same shader so we need to set the tint variable * each time, as it was clobbered when drawing to the previous region. */ al_set_target_bitmap(region[i]); al_set_shader_float_vector("tint", 3, &tints[i * 3], 1); al_draw_bitmap(image, 0, 0, 0); } al_set_target_backbuffer(display); al_draw_tinted_bitmap(image, al_map_rgba_f(0.5, 0.5, 0.5, 0.5), 320/2, 240/2, 0); al_flip_display(); } al_set_target_backbuffer(display); al_use_shader(NULL); al_destroy_shader(shader); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_stream_file.c000066400000000000000000000071731473414355200204400ustar00rootroot00000000000000/* * An example program that plays a file from the disk using Allegro5 * streaming API. The file is being read in small chunks and played on the * sound device instead of being loaded at once. * * usage: ./ex_stream_file file.[wav,ogg...] ... * * by Milan Mimica */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_acodec.h" #include "common.c" /* Attaches the stream directly to a voice. Streamed file's and voice's sample * rate, channels and depth must match. */ //#define BYPASS_MIXER char *default_files[] = {NULL, "../demos/skater/data/menu/skate2.ogg"}; int main(int argc, char **argv) { int i; ALLEGRO_VOICE* voice; ALLEGRO_MIXER* mixer; bool loop = false; int arg_start = 1; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); if (argc < 2) { log_printf("This example can be run from the command line.\n"); log_printf("Usage: %s [--loop] {audio_files}\n", argv[0]); argv = default_files; argc = 2; } if (strcmp(argv[1], "--loop") == 0) { loop = true; arg_start = 2; } al_init_acodec_addon(); if (!al_install_audio()) { abort_example("Could not init sound!\n"); } voice = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); if (!voice) { abort_example("Could not create ALLEGRO_VOICE.\n"); } log_printf("Voice created.\n"); #ifndef BYPASS_MIXER mixer = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); if (!mixer) { abort_example("Could not create ALLEGRO_MIXER.\n"); } log_printf("Mixer created.\n"); if (!al_attach_mixer_to_voice(mixer, voice)) { abort_example("al_attach_mixer_to_voice failed.\n"); } #endif for (i = arg_start; i < argc; ++i) { ALLEGRO_AUDIO_STREAM* stream; const char* filename = argv[i]; bool playing = true; ALLEGRO_EVENT event; ALLEGRO_EVENT_QUEUE* queue = al_create_event_queue(); stream = al_load_audio_stream(filename, 4, 2048); if (!stream) { /* If it is not packed, e.g. on Android or iOS. */ if (!strcmp(filename, default_files[1])) { stream = al_load_audio_stream("data/welcome.wav", 4, 2048); } } if (!stream) { log_printf("Could not create an ALLEGRO_AUDIO_STREAM from '%s'!\n", filename); continue; } log_printf("Stream created from '%s'.\n", filename); if (loop) { al_set_audio_stream_playmode(stream, loop ? ALLEGRO_PLAYMODE_LOOP : ALLEGRO_PLAYMODE_ONCE); } al_register_event_source(queue, al_get_audio_stream_event_source(stream)); #ifndef BYPASS_MIXER if (!al_attach_audio_stream_to_mixer(stream, mixer)) { log_printf("al_attach_audio_stream_to_mixer failed.\n"); continue; } #else if (!al_attach_audio_stream_to_voice(stream, voice)) { abort_example("al_attach_audio_stream_to_voice failed.\n"); } #endif log_printf("Playing %s ... Waiting for stream to finish ", filename); do { al_wait_for_event(queue, &event); if(event.type == ALLEGRO_EVENT_AUDIO_STREAM_FINISHED) playing = false; } while (playing); log_printf("\n"); al_destroy_event_queue(queue); al_destroy_audio_stream(stream); } log_printf("Done\n"); #ifndef BYPASS_MIXER al_destroy_mixer(mixer); #endif al_destroy_voice(voice); al_uninstall_audio(); close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_stream_seek.c000066400000000000000000000216661473414355200204530ustar00rootroot00000000000000/* * Example program for the Allegro library, by Todd Cope. * * Stream seeking. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_acodec.h" #include "allegro5/allegro_primitives.h" #include "common.c" ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_FONT *basic_font = NULL; ALLEGRO_AUDIO_STREAM *music_stream = NULL; const char *stream_filename = "data/welcome.wav"; float slider_pos = 0.0; float loop_start, loop_end; int mouse_button[16] = {0}; bool exiting = false; static void initialize(void) { if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); al_init_primitives_addon(); al_init_image_addon(); al_init_font_addon(); if (!al_install_keyboard()) { abort_example("Could not init keyboard!\n"); } if (!al_install_mouse()) { abort_example("Could not init mouse!\n"); } al_init_acodec_addon(); if (!al_install_audio()) { abort_example("Could not init sound!\n"); } if (!al_reserve_samples(16)) { abort_example("Could not set up voice and mixer.\n"); } init_platform_specific(); display = al_create_display(640, 252); if (!display) { abort_example("Could not create display!\n"); } basic_font = al_load_font("data/font.tga", 0, 0); if (!basic_font) { abort_example("Could not load font!\n"); } timer = al_create_timer(1.000 / 30); if (!timer) { abort_example("Could not init timer!\n"); } queue = al_create_event_queue(); if (!queue) { abort_example("Could not create event queue!\n"); } al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); } static void logic(void) { /* calculate the position of the slider */ double w = al_get_display_width(display) - 20; double pos = al_get_audio_stream_position_secs(music_stream); double len = al_get_audio_stream_length_secs(music_stream); slider_pos = w * (pos / len); } static void print_time(int x, int y, float t) { int hours, minutes; hours = (int)t / 3600; t -= hours * 3600; minutes = (int)t / 60; t -= minutes * 60; al_draw_textf(basic_font, al_map_rgb(255, 255, 255), x, y, 0, "%02d:%02d:%05.2f", hours, minutes, t); } static void render(void) { double pos = al_get_audio_stream_position_secs(music_stream); double length = al_get_audio_stream_length_secs(music_stream); double w = al_get_display_width(display) - 20; double loop_start_pos = w * (loop_start / length); double loop_end_pos = w * (loop_end / length); ALLEGRO_COLOR c = al_map_rgb(255, 255, 255); al_clear_to_color(al_map_rgb(64, 64, 128)); /* render "music player" */ al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_draw_textf(basic_font, c, 0, 0, 0, "Playing %s", stream_filename); print_time(8, 24, pos); al_draw_textf(basic_font, c, 100, 24, 0, "/"); print_time(110, 24, length); al_draw_filled_rectangle(10.0, 48.0 + 7.0, 10.0 + w, 48.0 + 9.0, al_map_rgb(0, 0, 0)); al_draw_line(10.0 + loop_start_pos, 46.0, 10.0 + loop_start_pos, 66.0, al_map_rgb(0, 168, 128), 0); al_draw_line(10.0 + loop_end_pos, 46.0, 10.0 + loop_end_pos, 66.0, al_map_rgb(255, 0, 0), 0); al_draw_filled_rectangle(10.0 + slider_pos - 2.0, 48.0, 10.0 + slider_pos + 2.0, 64.0, al_map_rgb(224, 224, 224)); /* show help */ al_draw_textf(basic_font, c, 0, 96, 0, "Drag the slider to seek."); al_draw_textf(basic_font, c, 0, 120, 0, "Middle-click to set loop start."); al_draw_textf(basic_font, c, 0, 144, 0, "Right-click to set loop end."); al_draw_textf(basic_font, c, 0, 168, 0, "Left/right arrows to seek."); al_draw_textf(basic_font, c, 0, 192, 0, "Space to pause."); al_draw_textf(basic_font, c, 0, 216, 0, "R to rewind."); al_flip_display(); } static void myexit(void) { bool playing; playing = al_get_audio_stream_playing(music_stream); if (playing && music_stream) al_drain_audio_stream(music_stream); al_destroy_audio_stream(music_stream); } static void maybe_fiddle_sliders(int mx, int my) { double seek_pos; double w = al_get_display_width(display) - 20; if (!(mx >= 10 && mx < 10 + w && my >= 48 && my < 64)) { return; } seek_pos = al_get_audio_stream_length_secs(music_stream) * ((mx - 10) / w); if (mouse_button[1]) { al_seek_audio_stream_secs(music_stream, seek_pos); } else if (mouse_button[2]) { if (al_set_audio_stream_loop_secs(music_stream, loop_start, seek_pos)) { loop_end = seek_pos; } } else if (mouse_button[3]) { if (al_set_audio_stream_loop_secs(music_stream, seek_pos, loop_end)) { loop_start = seek_pos; } } } static void event_handler(const ALLEGRO_EVENT * event) { int i; switch (event->type) { /* Was the X button on the window pressed? */ case ALLEGRO_EVENT_DISPLAY_CLOSE: exiting = true; break; /* Was a key pressed? */ case ALLEGRO_EVENT_KEY_CHAR: if (event->keyboard.keycode == ALLEGRO_KEY_LEFT) { double pos = al_get_audio_stream_position_secs(music_stream); pos -= 5.0; if (pos < 0.0) pos = 0.0; al_seek_audio_stream_secs(music_stream, pos); } else if (event->keyboard.keycode == ALLEGRO_KEY_RIGHT) { double pos = al_get_audio_stream_position_secs(music_stream); pos += 5.0; if (!al_seek_audio_stream_secs(music_stream, pos)) log_printf("seek error!\n"); } else if (event->keyboard.keycode == ALLEGRO_KEY_R) { if (!al_rewind_audio_stream(music_stream)) { log_printf("rewind error!\n"); } } else if (event->keyboard.keycode == ALLEGRO_KEY_SPACE) { bool playing; playing = al_get_audio_stream_playing(music_stream); playing = !playing; al_set_audio_stream_playing(music_stream, playing); } else if (event->keyboard.keycode == ALLEGRO_KEY_ESCAPE) { exiting = true; } break; case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: mouse_button[event->mouse.button] = 1; maybe_fiddle_sliders(event->mouse.x, event->mouse.y); break; case ALLEGRO_EVENT_MOUSE_AXES: maybe_fiddle_sliders(event->mouse.x, event->mouse.y); break; case ALLEGRO_EVENT_MOUSE_BUTTON_UP: mouse_button[event->mouse.button] = 0; break; case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY: for (i = 0; i < 16; i++) mouse_button[i] = 0; break; /* Is it time for the next timer tick? */ case ALLEGRO_EVENT_TIMER: logic(); render(); break; case ALLEGRO_EVENT_AUDIO_STREAM_FINISHED: log_printf("Stream finished.\n"); break; } } int main(int argc, char *argv[]) { ALLEGRO_CONFIG *config; ALLEGRO_EVENT event; unsigned buffer_count; unsigned samples; const char *s; ALLEGRO_PLAYMODE playmode = ALLEGRO_PLAYMODE_LOOP; initialize(); if (argc > 1) { stream_filename = argv[1]; } buffer_count = 0; samples = 0; config = al_load_config_file("ex_stream_seek.cfg"); if (config) { if ((s = al_get_config_value(config, "", "buffer_count"))) { buffer_count = atoi(s); } if ((s = al_get_config_value(config, "", "samples"))) { samples = atoi(s); } if ((s = al_get_config_value(config, "", "playmode"))) { if (!strcmp(s, "loop")) { playmode = ALLEGRO_PLAYMODE_LOOP; } else if (!strcmp(s, "once")) { playmode = ALLEGRO_PLAYMODE_ONCE; } else if (!strcmp(s, "loop_once")) { playmode = ALLEGRO_PLAYMODE_LOOP_ONCE; } } al_destroy_config(config); } if (buffer_count == 0) { buffer_count = 4; } if (samples == 0) { samples = 1024; } music_stream = al_load_audio_stream(stream_filename, buffer_count, samples); if (!music_stream) { abort_example("Stream error!\n"); } al_register_event_source(queue, al_get_audio_stream_event_source(music_stream)); loop_start = 0.0; loop_end = al_get_audio_stream_length_secs(music_stream); al_set_audio_stream_loop_secs(music_stream, loop_start, loop_end); al_set_audio_stream_playmode(music_stream, playmode); al_attach_audio_stream_to_mixer(music_stream, al_get_default_mixer()); al_start_timer(timer); while (!exiting) { al_wait_for_event(queue, &event); event_handler(&event); } myexit(); al_destroy_display(display); close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_subbitmap.c000066400000000000000000000217151473414355200201320ustar00rootroot00000000000000/* * Example program for the Allegro library. * * This program blitting to/from sub-bitmaps. * */ #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include #include "common.c" #define MIN(x,y) (((x) < (y)) ? (x) : (y)) #define MAX(x,y) (((x) > (y)) ? (x) : (y)) #define CLAMP(x,y,z) MAX((x), MIN((y), (z))) typedef enum { PLAIN_BLIT, SCALED_BLIT } Mode; enum { SRC_WIDTH = 640, SRC_HEIGHT = 480, SRC_X = 160, SRC_Y = 120, DST_WIDTH = 640, DST_HEIGHT = 480 }; ALLEGRO_DISPLAY *src_display; ALLEGRO_DISPLAY *dst_display; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_BITMAP *src_bmp; int src_x1 = SRC_X; int src_y1 = SRC_Y; int src_x2 = SRC_X + 319; int src_y2 = SRC_Y + 199; int dst_x1 = 0; int dst_y1 = 0; int dst_x2 = DST_WIDTH-1; int dst_y2 = DST_HEIGHT-1; Mode mode = PLAIN_BLIT; int draw_flags = 0; int main(int argc, char **argv) { ALLEGRO_BITMAP *src_subbmp[2] = {NULL, NULL}; ALLEGRO_BITMAP *dst_subbmp[2] = {NULL, NULL}; ALLEGRO_EVENT event; bool mouse_down; bool recreate_subbitmaps; bool redraw; bool use_memory; const char *image_filename = NULL; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_init_image_addon(); init_platform_specific(); open_log(); al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS); src_display = al_create_display(SRC_WIDTH, SRC_HEIGHT); if (!src_display) { abort_example("Error creating display\n"); } al_set_window_title(src_display, "Source"); dst_display = al_create_display(DST_WIDTH, DST_HEIGHT); if (!dst_display) { abort_example("Error creating display\n"); } al_set_window_title(dst_display, "Destination"); { int i; for (i = 1; i < argc; ++i) { if (!image_filename) image_filename = argv[i]; else abort_example("Unknown argument: %s\n", argv[i]); } if (!image_filename) { image_filename = "data/mysha.pcx"; } } src_bmp = al_load_bitmap(image_filename); if (!src_bmp) { abort_example("Could not load image file\n"); } src_x2 = src_x1 + al_get_bitmap_width(src_bmp); src_y2 = src_y1 + al_get_bitmap_height(src_bmp); al_install_keyboard(); al_install_mouse(); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_display_event_source(src_display)); al_register_event_source(queue, al_get_display_event_source(dst_display)); mouse_down = false; recreate_subbitmaps = true; redraw = true; use_memory = false; log_printf("Highlight sub-bitmap regions with left mouse button.\n"); log_printf("Press 'm' to toggle memory bitmaps.\n"); log_printf("Press '1' to perform plain blits.\n"); log_printf("Press 's' to perform scaled blits.\n"); log_printf("Press 'h' to flip horizontally.\n"); log_printf("Press 'v' to flip vertically.\n"); while (true) { if (recreate_subbitmaps) { int l, r, t, b, sw, sh; al_destroy_bitmap(src_subbmp[0]); al_destroy_bitmap(dst_subbmp[0]); al_destroy_bitmap(src_subbmp[1]); al_destroy_bitmap(dst_subbmp[1]); l = MIN(src_x1, src_x2); r = MAX(src_x1, src_x2); t = MIN(src_y1, src_y2); b = MAX(src_y1, src_y2); l -= SRC_X; t -= SRC_Y; r -= SRC_X; b -= SRC_Y; src_subbmp[0] = al_create_sub_bitmap(src_bmp, l, t, r - l + 1, b - t + 1); sw = al_get_bitmap_width(src_subbmp[0]); sh = al_get_bitmap_height(src_subbmp[0]); src_subbmp[1] = al_create_sub_bitmap(src_subbmp[0], 2, 2, sw - 4, sh - 4); l = MIN(dst_x1, dst_x2); r = MAX(dst_x1, dst_x2); t = MIN(dst_y1, dst_y2); b = MAX(dst_y1, dst_y2); al_set_target_backbuffer(dst_display); dst_subbmp[0] = al_create_sub_bitmap(al_get_backbuffer(dst_display), l, t, r - l + 1, b - t + 1); dst_subbmp[1] = al_create_sub_bitmap(dst_subbmp[0], 2, 2, r - l - 3, b - t - 3); recreate_subbitmaps = false; } if (redraw && al_is_event_queue_empty(queue)) { al_set_target_backbuffer(dst_display); al_clear_to_color(al_map_rgb(0, 0, 0)); al_set_target_bitmap(dst_subbmp[1]); switch (mode) { case PLAIN_BLIT: { al_draw_bitmap(src_subbmp[1], 0, 0, draw_flags); break; } case SCALED_BLIT: { al_draw_scaled_bitmap(src_subbmp[1], 0, 0, al_get_bitmap_width(src_subbmp[1]), al_get_bitmap_height(src_subbmp[1]), 0, 0, al_get_bitmap_width(dst_subbmp[1]), al_get_bitmap_height(dst_subbmp[1]), draw_flags); break; } } #define SWAP_GREATER(f1, f2) { \ if (f1 > f2) { \ float tmp = f1; \ f1 = f2; \ f2 = tmp; \ } \ } { /* pixel center is at 0.5/0.5 */ float x = dst_x1 + 0.5; float y = dst_y1 + 0.5; float x_ = dst_x2 + 0.5; float y_ = dst_y2 + 0.5; SWAP_GREATER(x, x_) SWAP_GREATER(y, y_) al_set_target_backbuffer(dst_display); al_draw_rectangle(x, y, x_, y_, al_map_rgb(0, 255, 255), 0); al_draw_rectangle(x + 2, y + 2, x_ - 2, y_ - 2, al_map_rgb(255, 255, 0), 0); al_flip_display(); } { /* pixel center is at 0.5/0.5 */ float x = src_x1 + 0.5; float y = src_y1 + 0.5; float x_ = src_x2 + 0.5; float y_ = src_y2 + 0.5; SWAP_GREATER(x, x_) SWAP_GREATER(y, y_) al_set_target_backbuffer(src_display); al_clear_to_color(al_map_rgb(0, 0, 0)); al_draw_bitmap(src_bmp, SRC_X, SRC_Y, 0); al_draw_rectangle(x, y, x_, y_, al_map_rgb(0, 255, 255), 0); al_draw_rectangle(x + 2, y + 2, x_ - 2, y_ - 2, al_map_rgb(255, 255, 0), 0); al_flip_display(); } #undef SWAP_GREATER redraw = false; } al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } if (event.type == ALLEGRO_EVENT_KEY_CHAR) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } if (event.keyboard.unichar == '1') { mode = PLAIN_BLIT; redraw = true; } else if (event.keyboard.unichar == 's') { mode = SCALED_BLIT; redraw = true; } else if (event.keyboard.unichar == 'h') { draw_flags ^= ALLEGRO_FLIP_HORIZONTAL; redraw = true; } else if (event.keyboard.unichar == 'v') { draw_flags ^= ALLEGRO_FLIP_VERTICAL; redraw = true; } else if (event.keyboard.unichar == 'm') { ALLEGRO_BITMAP *temp = src_bmp; use_memory = !use_memory; log_printf("Using a %s bitmap.\n", use_memory ? "memory" : "video"); al_set_new_bitmap_flags(use_memory ? ALLEGRO_MEMORY_BITMAP : ALLEGRO_VIDEO_BITMAP); src_bmp = al_clone_bitmap(temp); al_destroy_bitmap(temp); redraw = true; recreate_subbitmaps = true; } } else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN && event.mouse.button == 1) { if (event.mouse.display == src_display) { src_x1 = src_x2 = event.mouse.x; src_y1 = src_y2 = event.mouse.y; } else if (event.mouse.display == dst_display) { dst_x1 = dst_x2 = event.mouse.x; dst_y1 = dst_y2 = event.mouse.y; } mouse_down = true; redraw = true; } else if (event.type == ALLEGRO_EVENT_MOUSE_AXES) { if (mouse_down) { if (event.mouse.display == src_display) { src_x2 = event.mouse.x; src_y2 = event.mouse.y; } else if (event.mouse.display == dst_display) { dst_x2 = event.mouse.x; dst_y2 = event.mouse.y; } redraw = true; } } else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP && event.mouse.button == 1) { mouse_down = false; recreate_subbitmaps = true; redraw = true; } else if (event.type == ALLEGRO_EVENT_DISPLAY_EXPOSE) { redraw = true; } } al_destroy_event_queue(queue); close_log(false); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_synth.cpp000066400000000000000000000271641473414355200176550ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * * Something like the start of a synthesizer. */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_audio.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_primitives.h" #include "allegro5/allegro_ttf.h" #include "nihgui.hpp" #include "common.c" #define PI (ALLEGRO_PI) #define TWOPI (2.0 * PI) #define SAMPLES_PER_BUFFER (1024) #define STREAM_FREQUENCY (44100) const double dt = 1.0 / STREAM_FREQUENCY; enum Waveform { WAVEFORM_NONE, WAVEFORM_SINE, WAVEFORM_SQUARE, WAVEFORM_TRIANGLE, WAVEFORM_SAWTOOTH }; /* forward declarations */ static void generate_wave(Waveform type, float *buf, size_t samples, double t, float frequency, float phase); static void sine(float *buf, size_t samples, double t, float frequency, float phase); static void square(float *buf, size_t samples, double t, float frequency, float phase); static void triangle(float *buf, size_t samples, double t, float frequency, float phase); static void sawtooth(float *buf, size_t samples, double t, float frequency, float phase); /* globals */ ALLEGRO_FONT *font_gui; ALLEGRO_AUDIO_STREAM *streams[5]; bool saving = false; ALLEGRO_FILE *save_fp = NULL; static void generate_wave(Waveform type, float *buf, size_t samples, double t, float frequency, float phase) { switch (type) { case WAVEFORM_NONE: for (unsigned i = 0; i < samples; i++) { buf[i] = 0.0; } break; case WAVEFORM_SINE: sine(buf, samples, t, frequency, phase); break; case WAVEFORM_SQUARE: square(buf, samples, t, frequency, phase); break; case WAVEFORM_TRIANGLE: triangle(buf, samples, t, frequency, phase); break; case WAVEFORM_SAWTOOTH: sawtooth(buf, samples, t, frequency, phase); break; } } static void sine(float *buf, size_t samples, double t, float frequency, float phase) { const double w = TWOPI * frequency; unsigned i; for (i = 0; i < samples; i++) { double ti = t + i * dt; buf[i] = sin(w * ti + phase); } } static void square(float *buf, size_t samples, double t, float frequency, float phase) { const double w = TWOPI * frequency; unsigned i; for (i = 0; i < samples; i++) { double ti = t + i * dt; double x = sin(w * ti + phase); buf[i] = (x >= 0.0) ? 1.0 : -1.0; } } static void triangle(float *buf, size_t samples, double t, float frequency, float phase) { const double w = TWOPI * frequency; unsigned i; for (i = 0; i < samples; i++) { double tx = w * (t + i * dt) + PI/2.0 + phase; double tu = fmod(tx/PI, 2.0); if (tu <= 1.0) buf[i] = (1.0 - 2.0 * tu); else buf[i] = (-1.0 + 2.0 * (tu - 1.0)); } } static void sawtooth(float *buf, size_t samples, double t, float frequency, float phase) { const double w = TWOPI * frequency; unsigned i; for (i = 0; i < samples; i++) { double tx = w * (t + i * dt) + PI + phase; double tu = fmod(tx/PI, 2.0); buf[i] = (-1.0 + tu); } } static void mixer_pp_callback(void *buf, unsigned int samples, void *userdata) { ALLEGRO_MIXER *mixer = (ALLEGRO_MIXER *)userdata; int nch; int sample_size; if (!saving) return; switch (al_get_mixer_channels(mixer)) { case ALLEGRO_CHANNEL_CONF_1: nch = 1; break; case ALLEGRO_CHANNEL_CONF_2: nch = 2; break; default: /* Not supported. */ return; } sample_size = al_get_audio_depth_size(al_get_mixer_depth(mixer)); al_fwrite(save_fp, buf, nch * samples * sample_size); } class Group { private: List list; Label freq_label; HSlider freq_slider; Label freq_val_label; Label phase_label; HSlider phase_slider; Label phase_val_label; Label gain_label; HSlider gain_slider; Label pan_label; HSlider pan_slider; double t; float last_gain; float last_pan; public: Group(); void add_to_dialog(Dialog & d, int x, int y); void update_labels(); void generate(float *buf, size_t samples); bool get_gain_if_changed(float *gain); bool get_pan_if_changed(float *pan); private: float get_frequency() const; float get_phase() const; }; Group::Group() : freq_label(Label("f")), freq_slider(220, 1000), phase_label(Label("φ")), phase_slider((int)(100 * PI), (int)(2 * 100 * PI)), /* -π .. π */ gain_label(Label("Gain")), gain_slider(33, 100), /* 0.0 .. 1.0 */ pan_label(Label("Pan")), pan_slider(100, 200), /* -1.0 .. 1.0 */ t(0.0), last_gain(-10000), last_pan(-10000) { /* Order must correspond with Waveform. */ list.append_item("Off"); list.append_item("Sine"); list.append_item("Square"); list.append_item("Triangle"); list.append_item("Sawtooth"); } void Group::add_to_dialog(Dialog & d, int x, int y) { d.add(list, x, y, 4, 4); d.add(freq_label, x+4, y, 2, 1); d.add(freq_slider, x+6, y, 20, 1); d.add(freq_val_label, x+26, y, 4, 1); d.add(phase_label, x+4, y+1, 2, 1); d.add(phase_slider, x+6, y+1, 20, 1); d.add(phase_val_label, x+26, y+1, 4, 1); d.add(gain_label, x+4, y+2, 2, 1); d.add(gain_slider, x+6, y+2, 20, 1); d.add(pan_label, x+4, y+3, 2, 1); d.add(pan_slider, x+6, y+3, 20, 1); } void Group::update_labels() { char buf[32]; float frequency = get_frequency(); float phase = get_phase(); sprintf(buf, "%4.0f Hz", frequency); freq_val_label.set_text(buf); sprintf(buf, "%.2f π", phase/PI); phase_val_label.set_text(buf); } void Group::generate(float *buf, size_t samples) { Waveform type = (Waveform) list.get_cur_value(); float frequency = get_frequency(); float phase = get_phase(); generate_wave(type, buf, samples, t, frequency, phase); t += dt * samples; } float Group::get_frequency() const { return freq_slider.get_cur_value(); } float Group::get_phase() const { return phase_slider.get_cur_value() / 100.0 - PI; } bool Group::get_gain_if_changed(float *gain) { *gain = gain_slider.get_cur_value() / 100.0; bool changed = (last_gain != *gain); last_gain = *gain; return changed; } bool Group::get_pan_if_changed(float *pan) { *pan = pan_slider.get_cur_value() / 100.0 - 1.0; bool changed = (last_pan != *pan); last_pan = *pan; return changed; } class SaveButton : public ToggleButton { public: SaveButton() : ToggleButton("Save raw") {} void on_click(int mx, int my); }; void SaveButton::on_click(int, int) { if (saving) { log_printf("Stopped saving waveform.\n"); saving = false; return; } if (!save_fp) { save_fp = al_fopen("ex_synth.raw", "wb"); } if (save_fp) { log_printf("Started saving waveform.\n"); saving = true; } } class Prog : public EventHandler { private: Dialog d; Group group1; Group group2; Group group3; Group group4; Group group5; SaveButton save_button; public: Prog(const Theme & theme, ALLEGRO_DISPLAY *display); virtual ~Prog() {} void run(); void handle_event(const ALLEGRO_EVENT & event); }; Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) : d(Dialog(theme, display, 30, 26)), save_button(SaveButton()) { group1.add_to_dialog(d, 1, 1); group2.add_to_dialog(d, 1, 6); group3.add_to_dialog(d, 1, 11); group4.add_to_dialog(d, 1, 16); group5.add_to_dialog(d, 1, 21); d.add(save_button, 27, 25, 3, 1); } void Prog::run() { d.prepare(); for (int i = 0; i < 5; i++) d.register_event_source(al_get_audio_stream_event_source(streams[i])); d.set_event_handler(this); while (!d.is_quit_requested()) { if (d.is_draw_requested()) { group1.update_labels(); group2.update_labels(); group3.update_labels(); group4.update_labels(); group5.update_labels(); al_clear_to_color(al_map_rgb(128, 128, 128)); d.draw(); al_flip_display(); } d.run_step(true); } } void Prog::handle_event(const ALLEGRO_EVENT & event) { if (event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT) { ALLEGRO_AUDIO_STREAM *stream; Group *group; void *buf; float gain; float pan; stream = (ALLEGRO_AUDIO_STREAM *) event.any.source; buf = al_get_audio_stream_fragment(stream); if (!buf) { /* This is a normal condition that you must deal with. */ return; } if (stream == streams[0]) group = &group1; else if (stream == streams[1]) group = &group2; else if (stream == streams[2]) group = &group3; else if (stream == streams[3]) group = &group4; else if (stream == streams[4]) group = &group5; else group = NULL; ALLEGRO_ASSERT(group); if (group) { group->generate((float *) buf, SAMPLES_PER_BUFFER); if (group->get_gain_if_changed(&gain)) { al_set_audio_stream_gain(stream, gain); } if (group->get_pan_if_changed(&pan)) { al_set_audio_stream_pan(stream, pan); } } if (!al_set_audio_stream_fragment(stream, buf)) { log_printf("Error setting stream fragment.\n"); } } } int main(int argc, char *argv[]) { ALLEGRO_DISPLAY *display; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); al_install_keyboard(); al_install_mouse(); al_init_primitives_addon(); al_init_font_addon(); al_init_ttf_addon(); init_platform_specific(); al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(800, 600); if (!display) { abort_example("Unable to create display\n"); } al_set_window_title(display, "Synthesiser of sorts"); font_gui = al_load_ttf_font("data/DejaVuSans.ttf", 12, 0); if (!font_gui) { abort_example("Failed to load font\n"); } if (!al_install_audio()) { abort_example("Could not init sound!\n"); } if (!al_reserve_samples(0)) { abort_example("Could not set up voice and mixer.\n"); } size_t buffers = 8; unsigned samples = SAMPLES_PER_BUFFER; unsigned freq = STREAM_FREQUENCY; void *buf; ALLEGRO_AUDIO_DEPTH depth = ALLEGRO_AUDIO_DEPTH_FLOAT32; ALLEGRO_CHANNEL_CONF ch = ALLEGRO_CHANNEL_CONF_1; ALLEGRO_MIXER *mixer = al_get_default_mixer(); for (int i = 0; i < 5; i++) { streams[i] = al_create_audio_stream(buffers, samples, freq, depth, ch); if (!streams[i]) { abort_example("Could not create stream.\n"); } while ((buf = al_get_audio_stream_fragment(streams[i]))) { al_fill_silence(buf, samples, depth, ch); al_set_audio_stream_fragment(streams[i], buf); } if (!al_attach_audio_stream_to_mixer(streams[i], mixer)) { abort_example("Could not attach stream to mixer.\n"); } } al_set_mixer_postprocess_callback(mixer, mixer_pp_callback, mixer); /* Prog is destroyed at the end of this scope. */ { Theme theme(font_gui); Prog prog(theme, display); prog.run(); } for (int i = 0; i < 5; i++) { al_destroy_audio_stream(streams[i]); } al_uninstall_audio(); al_destroy_font(font_gui); al_fclose(save_fp); close_log(false); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_threads.c000066400000000000000000000127651473414355200176030ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * * In this example, each thread handles its own window and event queue. */ #include #include #include #include "common.c" #define MAX_THREADS 100 #define MAX_BACKGROUNDS 10 #define MAX_SQUARES 25 typedef struct Background { double rmax; double gmax; double bmax; } Background; typedef struct Square { float cx, cy; float dx, dy; float size, dsize; float rot, drot; float life, dlife; } Square; static float rand01(void) { return (rand() % 10000) / 10000.0; } static float rand11(void) { return (-10000 + (rand() % 20000)) / 20000.0; } static void gen_square(Square *sq, int w, int h) { sq->cx = rand() % w; sq->cy = rand() % h; sq->dx = 3.0 * rand11(); sq->dy = 3.0 * rand11(); sq->size = 10 + (rand() % 10); sq->dsize = rand11(); sq->rot = ALLEGRO_PI * rand01(); sq->drot = rand11() / 3.0; sq->life = 0.0; sq->dlife = (ALLEGRO_PI / 100.0) + (ALLEGRO_PI / 30.0) * rand01(); } static void animate_square(Square *sq) { sq->cx += sq->dx; sq->cy += sq->dy; sq->size += sq->dsize; sq->rot += sq->drot; sq->life += sq->dlife; if (sq->size < 1.0 || sq->life > ALLEGRO_PI) { ALLEGRO_BITMAP *bmp = al_get_target_bitmap(); gen_square(sq, al_get_bitmap_width(bmp), al_get_bitmap_height(bmp)); } } static void draw_square(Square *sq) { ALLEGRO_TRANSFORM trans; float alpha; float size; ALLEGRO_COLOR tint; al_build_transform(&trans, sq->cx, sq->cy, 1.0, 1.0, sq->rot); al_use_transform(&trans); alpha = sin(sq->life); al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_ONE); tint = al_map_rgba_f(0.5, 0.3, 0, alpha); size = sq->size; al_draw_filled_rounded_rectangle(-size, -size, size, size, 3, 3, tint); size *= 1.1; al_draw_rounded_rectangle(-size, -size, size, size, 3, 3, tint, 2); } static void *thread_func(ALLEGRO_THREAD *thr, void *arg) { const int INITIAL_WIDTH = 300; const int INITIAL_HEIGHT = 300; const Background *background = (Background *) arg; ALLEGRO_DISPLAY *display; ALLEGRO_EVENT_QUEUE *queue = NULL; ALLEGRO_TIMER *timer = NULL; ALLEGRO_EVENT event; ALLEGRO_STATE state; Square squares[MAX_SQUARES]; double theta = 0.0; bool redraw = true; int i; (void)thr; al_set_new_display_flags(ALLEGRO_RESIZABLE); display = al_create_display(INITIAL_WIDTH, INITIAL_HEIGHT); if (!display) { goto Quit; } queue = al_create_event_queue(); if (!queue) { goto Quit; } timer = al_create_timer(0.1); if (!timer) { goto Quit; } al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); for (i = 0; i < MAX_SQUARES; i++) { gen_square(&squares[i], INITIAL_WIDTH, INITIAL_HEIGHT); } al_start_timer(timer); while (true) { if (al_is_event_queue_empty(queue) && redraw) { double r = 0.7 + 0.3 * (sin(theta) + 1.0) / 2.0; ALLEGRO_COLOR c = al_map_rgb_f( background->rmax * r, background->gmax * r, background->bmax * r ); al_clear_to_color(c); al_store_state(&state, ALLEGRO_STATE_BLENDER | ALLEGRO_STATE_TRANSFORM); for (i = 0; i < MAX_SQUARES; i++) { draw_square(&squares[i]); } al_restore_state(&state); al_flip_display(); redraw = false; } al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_TIMER) { for (i = 0; i < MAX_SQUARES; i++) { animate_square(&squares[i]); } theta += 0.1; redraw = true; } else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } else if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } else if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { al_acknowledge_resize(event.display.source); } } Quit: if (timer) { al_destroy_timer(timer); } if (queue) { al_destroy_event_queue(queue); } if (display) { al_destroy_display(display); } return NULL; } int main(int argc, char **argv) { ALLEGRO_THREAD *thread[MAX_THREADS]; Background background[MAX_BACKGROUNDS] = { { 1.0, 0.5, 0.5 }, { 0.5, 1.0, 0.5 }, { 0.5, 0.5, 1.0 }, { 1.0, 1.0, 0.5 }, { 0.5, 1.0, 1.0 }, { 1.0, 0.7, 0.5 }, { 0.5, 1.0, 0.7 }, { 0.7, 0.5, 1.0 }, { 1.0, 0.7, 0.5 }, { 0.5, 0.7, 1.0 } }; int num_threads; int i; if (argc > 1) { num_threads = strtol(argv[1], NULL, 10); if (num_threads > MAX_THREADS) num_threads = MAX_THREADS; else if (num_threads < 1) num_threads = 1; } else { num_threads = 3; } if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_install_keyboard(); al_install_mouse(); for (i = 0; i < num_threads; i++) { thread[i] = al_create_thread(thread_func, &background[i % MAX_BACKGROUNDS]); } for (i = 0; i < num_threads; i++) { al_start_thread(thread[i]); } for (i = 0; i < num_threads; i++) { al_join_thread(thread[i], NULL); al_destroy_thread(thread[i]); } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_threads2.c000066400000000000000000000243621473414355200176610ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * * In this example, threads render to their own memory buffers, while the * main thread handles events and drawing (copying from the memory buffers * to the display). * * Click on an image to pause its thread. */ #include #include #include "common.c" /* feel free to bump these up */ #define NUM_THREADS 9 #define IMAGES_PER_ROW 3 /* size of each fractal image */ #define W 120 #define H 120 typedef struct ThreadInfo { ALLEGRO_BITMAP *bitmap; ALLEGRO_MUTEX *mutex; ALLEGRO_COND *cond; bool is_paused; int random_seed; double target_x, target_y; } ThreadInfo; typedef struct Viewport { double centre_x; double centre_y; double x_extent; double y_extent; double zoom; } Viewport; static ThreadInfo thread_info[NUM_THREADS]; unsigned char sin_lut[256]; static double cabs2(double re, double im) { return re*re + im*im; } static int mandel(double cre, double cim, int MAX_ITER) { const float Z_MAX2 = 4.0; double zre = cre, zim = cim; int iter; for (iter = 0; iter < MAX_ITER; iter++) { double z1re, z1im; z1re = zre * zre - zim * zim; z1im = 2 * zre * zim; z1re += cre; z1im += cim; if (cabs2(z1re, z1im) > Z_MAX2) { return iter + 1; /* outside set */ } zre = z1re; zim = z1im; } return 0; /* inside set */ } /* local_rand: * Simple rand() replacement with guaranteed randomness in the lower 16 bits. * We just need a RNG with a thread-safe interface. */ static int local_rand(int *seed) { const int LOCAL_RAND_MAX = 0xFFFF; *seed = (*seed + 1) * 1103515245 + 12345; return ((*seed >> 16) & LOCAL_RAND_MAX); } static void random_palette(unsigned char palette[256][3], int *seed) { unsigned char rmax = 128 + local_rand(seed) % 128; unsigned char gmax = 128 + local_rand(seed) % 128; unsigned char bmax = 128 + local_rand(seed) % 128; int i; for (i = 0; i < 256; i++) { palette[i][0] = rmax * i / 256; palette[i][1] = gmax * i / 256; palette[i][2] = bmax * i / 256; } } static void draw_mandel_line(ALLEGRO_BITMAP *bitmap, const Viewport *viewport, unsigned char palette[256][3], const int y) { ALLEGRO_LOCKED_REGION *lr; unsigned char *rgb; double xlower, ylower; double xscale, yscale; double im; double re; int w, h; int x; int n = 512 / pow(2, viewport->zoom); w = al_get_bitmap_width(bitmap); h = al_get_bitmap_height(bitmap); if (!(lr = al_lock_bitmap_region(bitmap, 0, y, w, 1, ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA, ALLEGRO_LOCK_WRITEONLY))) { abort_example("draw_mandel_line: al_lock_bitmap_region failed\n"); } xlower = viewport->centre_x - viewport->x_extent / 2.0 * viewport->zoom; ylower = viewport->centre_y - viewport->y_extent / 2.0 * viewport->zoom; xscale = viewport->x_extent / w * viewport->zoom; yscale = viewport->y_extent / h * viewport->zoom; re = xlower; im = ylower + y * yscale; rgb = lr->data; for (x = 0; x < w; x++) { int i = mandel(re, im, n); int v = sin_lut[(int)(i * 64 / n)]; rgb[0] = palette[v][0]; rgb[1] = palette[v][1]; rgb[2] = palette[v][2]; rgb += 3; re += xscale; } al_unlock_bitmap(bitmap); } static void *thread_func(ALLEGRO_THREAD *thr, void *arg) { ThreadInfo *info = (ThreadInfo *) arg; Viewport viewport; unsigned char palette[256][3]; int y, h; y = 0; h = al_get_bitmap_height(info->bitmap); viewport.centre_x = info->target_x; viewport.centre_y = info->target_y; viewport.x_extent = 3.0; viewport.y_extent = 3.0; viewport.zoom = 1.0; info->target_x = 0; info->target_y = 0; while (!al_get_thread_should_stop(thr)) { al_lock_mutex(info->mutex); while (info->is_paused) { al_wait_cond(info->cond, info->mutex); /* We might be awoken because the program is terminating. */ if (al_get_thread_should_stop(thr)) { break; } } if (!info->is_paused) { if (y == 0) { random_palette(palette, &info->random_seed); } draw_mandel_line(info->bitmap, &viewport, palette, y); y++; if (y >= h) { double z = viewport.zoom; y = 0; viewport.centre_x += z * viewport.x_extent * info->target_x; viewport.centre_y += z * viewport.y_extent * info->target_y; info->target_x = 0; info->target_y = 0; viewport.zoom *= 0.99; } } al_unlock_mutex(info->mutex); al_rest(0); } return NULL; } static void show_images(void) { int x = 0; int y = 0; int i; al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); for (i = 0; i < NUM_THREADS; i++) { /* for lots of threads, this is not good enough */ al_lock_mutex(thread_info[i].mutex); al_draw_bitmap(thread_info[i].bitmap, x * W, y * H, 0); al_unlock_mutex(thread_info[i].mutex); x++; if (x == IMAGES_PER_ROW) { x = 0; y++; } } al_flip_display(); } static void set_target(int n, double x, double y) { thread_info[n].target_x = x; thread_info[n].target_y = y; } static void toggle_pausedness(int n) { ThreadInfo *info = &thread_info[n]; al_lock_mutex(info->mutex); info->is_paused = !info->is_paused; al_broadcast_cond(info->cond); al_unlock_mutex(info->mutex); } int main(int argc, char **argv) { ALLEGRO_THREAD *thread[NUM_THREADS]; ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; bool need_draw; int i; (void)argc; (void)argv; for (i = 0; i < 256; i++) { sin_lut[i] = 128 + (int) (127.0 * sin(i / 8.0)); } if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_install_mouse(); display = al_create_display(W * IMAGES_PER_ROW, H * NUM_THREADS / IMAGES_PER_ROW); if (!display) { abort_example("Error creating display\n"); } timer = al_create_timer(1.0/3); if (!timer) { abort_example("Error creating timer\n"); } queue = al_create_event_queue(); if (!queue) { abort_example("Error creating event queue\n"); } al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); /* Note: * Right now, A5 video displays can only be accessed from the thread which * created them (at least for OpenGL). To lift this restriction, we could * keep track of the current OpenGL context for each thread and make all * functions accessing the display check for it.. not sure it's worth the * additional complexity though. */ al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_RGB_888); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); for (i = 0; i < NUM_THREADS; i++) { thread_info[i].bitmap = al_create_bitmap(W, H); if (!thread_info[i].bitmap) { goto Error; } thread_info[i].mutex = al_create_mutex(); if (!thread_info[i].mutex) { goto Error; } thread_info[i].cond = al_create_cond(); if (!thread_info[i].cond) { goto Error; } thread_info[i].is_paused = false; thread_info[i].random_seed = i; thread[i] = al_create_thread(thread_func, &thread_info[i]); if (!thread[i]) { goto Error; } } set_target(0, -0.56062033041600878303, -0.56064322926933807256); set_target(1, -0.57798076669230014080, -0.63449861991138123418); set_target(2, 0.36676836392830602929, -0.59081385302214906030); set_target(3, -1.48319283039401317303, -0.00000000200514696273); set_target(4, -0.74052910500707636032, 0.18340899525730713915); set_target(5, 0.25437906525768350097, -0.00046678223345789554); set_target(6, -0.56062033041600878303, 0.56064322926933807256); set_target(7, -0.57798076669230014080, 0.63449861991138123418); set_target(8, 0.36676836392830602929, 0.59081385302214906030); for (i = 0; i < NUM_THREADS; i++) { al_start_thread(thread[i]); } al_start_timer(timer); need_draw = true; while (true) { if (need_draw && al_is_event_queue_empty(queue)) { show_images(); need_draw = false; } al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_TIMER) { need_draw = true; } else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { int n = (event.mouse.y / H) * IMAGES_PER_ROW + (event.mouse.x / W); if (n < NUM_THREADS) { double x = event.mouse.x - (event.mouse.x / W) * W; double y = event.mouse.y - (event.mouse.y / H) * H; /* Center to the mouse click position. */ if (thread_info[n].is_paused) { thread_info[n].target_x = x / W - 0.5; thread_info[n].target_y = y / H - 0.5; } toggle_pausedness(n); } } else if (event.type == ALLEGRO_EVENT_DISPLAY_EXPOSE) { need_draw = true; } else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } else if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } need_draw = true; } } for (i = 0; i < NUM_THREADS; i++) { /* Set the flag to stop the thread. The thread might be waiting on a * condition variable, so signal the condition to force it to wake up. */ al_set_thread_should_stop(thread[i]); al_lock_mutex(thread_info[i].mutex); al_broadcast_cond(thread_info[i].cond); al_unlock_mutex(thread_info[i].mutex); /* al_destroy_thread() implicitly joins the thread, so this call is not * strictly necessary. */ al_join_thread(thread[i], NULL); al_destroy_thread(thread[i]); } al_destroy_event_queue(queue); al_destroy_timer(timer); al_destroy_display(display); return 0; Error: return 1; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_timedwait.c000066400000000000000000000065611473414355200201350ustar00rootroot00000000000000/* * Example program for the Allegro library, by Peter Wang. * * Test timed version of al_wait_for_event(). */ #include #include #include "common.c" static bool test_relative_timeout(ALLEGRO_FONT *font, ALLEGRO_EVENT_QUEUE *queue); static bool test_absolute_timeout(ALLEGRO_FONT *font, ALLEGRO_EVENT_QUEUE *queue); int main(int argc, char **argv) { ALLEGRO_DISPLAY *dpy; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_FONT *font; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } if (!al_init_font_addon()) { abort_example("Could not init Font addon.\n"); } al_install_keyboard(); dpy = al_create_display(640, 480); if (!dpy) { abort_example("Could not create a display.\n"); } font = al_create_builtin_font(); if (!font) { abort_example("Could not create builtin font.\n"); } queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(dpy)); while (true) { if (!test_relative_timeout(font, queue)) break; if (!test_absolute_timeout(font, queue)) break; } return 0; } static bool test_relative_timeout(ALLEGRO_FONT *font, ALLEGRO_EVENT_QUEUE *queue) { ALLEGRO_EVENT event; float shade = 0.1; while (true) { if (al_wait_for_event_timed(queue, &event, 0.1)) { if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { return true; } else { shade = 0.0; } } else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { return false; } } else { /* timed out */ shade += 0.1; if (shade > 1.0) shade = 1.0; } al_clear_to_color(al_map_rgba_f(0.5 * shade, 0.25 * shade, shade, 0)); al_draw_textf(font, al_map_rgb_f(1., 1., 1.), 320, 240, ALLEGRO_ALIGN_CENTRE, "Relative timeout (%.2f)", shade); al_draw_text(font, al_map_rgb_f(1., 1., 1.), 320, 260, ALLEGRO_ALIGN_CENTRE, "Esc to move on, Space to restart."); al_flip_display(); } } static bool test_absolute_timeout(ALLEGRO_FONT *font, ALLEGRO_EVENT_QUEUE *queue) { ALLEGRO_TIMEOUT timeout; ALLEGRO_EVENT event; float shade = 0.1; bool ret; while (true) { al_init_timeout(&timeout, 0.1); while ((ret = al_wait_for_event_until(queue, &event, &timeout))) { if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { return true; } else { shade = 0.; } } else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { return false; } } if (!ret) { /* timed out */ shade += 0.1; if (shade > 1.0) shade = 1.0; } al_clear_to_color(al_map_rgba_f(shade, 0.5 * shade, 0.25 * shade, 0)); al_draw_textf(font, al_map_rgb_f(1., 1., 1.), 320, 240, ALLEGRO_ALIGN_CENTRE, "Absolute timeout (%.2f)", shade); al_draw_text(font, al_map_rgb_f(1., 1., 1.), 320, 260, ALLEGRO_ALIGN_CENTRE, "Esc to move on, Space to restart."); al_flip_display(); } } /* vi: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_timer.c000066400000000000000000000115711473414355200172630ustar00rootroot00000000000000/* A test of timer events. Since both al_get_time() as well as the timer * events may be the source of inaccuracy, it doesn't tell a lot. */ #include #include #include #include #include #include #include "common.c" /* A structure holding all variables of our example program. */ struct Example { ALLEGRO_FONT *myfont; /* Our font. */ ALLEGRO_EVENT_QUEUE *queue; /* Our events queue. */ double FPS; /* How often to update per second. */ int x[4]; bool first_tick; double this_time, prev_time, accum_time; double min_diff, max_diff, second_spread; double second; double timer_events; double timer_error; double timestamp; } ex; /* Initialize the example. */ static void init(void) { ex.FPS = 50; ex.first_tick = true; ex.myfont = al_create_builtin_font(); if (!ex.myfont) { abort_example("Error creating builtin font\n"); } } /* Cleanup. Always a good idea. */ static void cleanup(void) { al_destroy_font(ex.myfont); ex.myfont = NULL; } /* Print some text. */ static void print(int x, int y, char const *format, ...) { va_list list; char message[1024]; va_start(list, format); vsnprintf(message, sizeof message, format, list); va_end(list); /* Actual text. */ al_draw_text(ex.myfont, al_map_rgb_f(0, 0, 0), x, y, 0, message); } /* Draw our example scene. */ static void draw(void) { int h, y, i; double cur_time, event_overhead, total_error; cur_time = al_get_time(); event_overhead = cur_time - ex.timestamp; total_error = event_overhead + ex.timer_error; h = al_get_font_line_height(ex.myfont); al_clear_to_color(al_map_rgb_f(1, 1, 1)); print(0, 0, "%.9f target for %.0f Hz Timer", 1.0 / ex.FPS, ex.FPS); print(0, h, "%.9f now", ex.this_time - ex.prev_time); print(0, 2 * h, "%.9f accum over one second", ex.accum_time / ex.timer_events); print(0, 3 * h, "%.9f min", ex.min_diff); print(0, 4 * h, "%.9f max", ex.max_diff); print(300, 3.5 * h, "%.9f (max - min)", ex.second_spread); print(300, 4.5 * h, "%.9f (timer error)", ex.timer_error); print(300, 5.5 * h ,"%.9f (event overhead)", event_overhead); print(300, 6.5 * h, "%.9f (total error)" , total_error); y = 240; for (i = 0; i < 4; i++) { al_draw_filled_rectangle(ex.x[i], y + i * 60, ex.x[i] + (1 << i), y + i * 60 + 60, al_map_rgb(1, 0, 0)); } } /* Called a fixed amount of times per second. */ static void tick(ALLEGRO_TIMER_EVENT* timer_event) { int i; ex.this_time = al_get_time(); if (ex.first_tick) { ex.first_tick = false; } else { double duration; if (ex.this_time - ex.second >= 1) { ex.second = ex.this_time; ex.accum_time = 0; ex.timer_events = 0; ex.second_spread = ex.max_diff - ex.min_diff; ex.max_diff = 0; ex.min_diff = 1; } duration = ex.this_time - ex.prev_time; if (duration < ex.min_diff) ex.min_diff = duration; if (duration > ex.max_diff) ex.max_diff = duration; ex.accum_time += duration; ex.timer_events++; ex.timer_error = timer_event->error; ex.timestamp = timer_event->timestamp; } draw(); al_flip_display(); for (i = 0; i < 4; i++) { ex.x[i] += 1 << i; ex.x[i] %= 640; } ex.prev_time = ex.this_time; } /* Run our test. */ static void run(void) { ALLEGRO_EVENT event; while (1) { al_wait_for_event(ex.queue, &event); switch (event.type) { /* Was the X button on the window pressed? */ case ALLEGRO_EVENT_DISPLAY_CLOSE: return; /* Was a key pressed? */ case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) return; break; /* Is it time for the next timer tick? */ case ALLEGRO_EVENT_TIMER: tick(&event.timer); break; } } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_install_keyboard(); al_install_mouse(); al_init_font_addon(); display = al_create_display(640, 480); if (!display) { abort_example("Could not create display.\n"); } init(); timer = al_create_timer(1.000 / ex.FPS); ex.queue = al_create_event_queue(); al_register_event_source(ex.queue, al_get_keyboard_event_source()); al_register_event_source(ex.queue, al_get_mouse_event_source()); al_register_event_source(ex.queue, al_get_display_event_source(display)); al_register_event_source(ex.queue, al_get_timer_event_source(timer)); al_start_timer(timer); run(); al_destroy_event_queue(ex.queue); cleanup(); return 0; } allegro5-5.2.10.1/examples/ex_timer_pause.c000066400000000000000000000041041473414355200204520ustar00rootroot00000000000000/* A test of pausing/resuming a timer. * * 1. Create two 5s long timers. * 2. Let each run for 2s, then stop each for 2s. * 3. Call al_resume_timer on timer1 and al_start_timer on timer2 * 4. Wait for timer events * * timer1 should finish before timer2, as it was resumed rather than restarted. */ #include #include #include "common.c" /* Run our test. */ int main(int argc, char **argv) { const double duration = 5; // timer lasts for 5 seconds const double pre_pause = 2; // how long to wait before pausing const double pause = 2; // how long to pause timer for ALLEGRO_TIMER *timer1 = NULL; ALLEGRO_TIMER *timer2 = NULL; ALLEGRO_EVENT_QUEUE *queue = NULL; ALLEGRO_EVENT ev; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } printf("Creating a pair of %2.0fs timers\n", duration); queue = al_create_event_queue(); timer1 = al_create_timer(duration); timer2 = al_create_timer(duration); al_register_event_source(queue, al_get_timer_event_source(timer1)); al_register_event_source(queue, al_get_timer_event_source(timer2)); printf("Starting both timers at: %2.2fs\n", al_get_time() * 100); al_start_timer(timer1); al_start_timer(timer2); al_rest(pre_pause); printf("Pausing timers at: %2.2fs\n", al_get_time() * 100); al_stop_timer(timer1); al_stop_timer(timer2); al_rest(pause); printf("Resume timer1 at: %2.2fs\n", al_get_time() * 100); al_resume_timer(timer1); printf("Restart timer2 at: %2.2fs\n", al_get_time() * 100); al_start_timer(timer2); al_wait_for_event(queue, &ev); printf("Timer%d finished at: %2.2fs\n", al_get_timer_event_source(timer1) == ev.any.source ? 1 : 2, al_get_time() * 100); al_wait_for_event(queue, &ev); printf("Timer%d finished at: %2.2fs\n", al_get_timer_event_source(timer1) == ev.any.source ? 1 : 2, al_get_time() * 100); al_destroy_event_queue(queue); al_destroy_timer(timer1); al_destroy_timer(timer2); return 0; } allegro5-5.2.10.1/examples/ex_touch_input.c000066400000000000000000000060601473414355200205010ustar00rootroot00000000000000#include #include #include "common.c" #define MAX_TOUCHES 16 typedef struct TOUCH TOUCH; struct TOUCH { int id; int x; int y; }; static void draw_touches(int num, TOUCH touches[]) { int i; for (i = 0; i < num; i++) { int x = touches[i].x; int y = touches[i].y; al_draw_circle(x, y, 50, al_map_rgb(255, 0, 0), 4); } } static int find_index(int id, int num, TOUCH touches[]) { int i; for (i = 0; i < num; i++) { if (touches[i].id == id) { return i; } } return -1; } int main(int argc, char **argv) { int num_touches = 0; bool quit = false; bool background = false; TOUCH touches[MAX_TOUCHES]; ALLEGRO_DISPLAY *display; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); if (!al_install_touch_input()) { abort_example("Could not init touch input.\n"); } display = al_create_display(800, 600); if (!display) { abort_example("Error creating display\n"); } queue = al_create_event_queue(); al_register_event_source(queue, al_get_touch_input_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); while (!quit) { if (!background && al_is_event_queue_empty(queue)) { al_clear_to_color(al_map_rgb(255, 255, 255)); draw_touches(num_touches, touches); al_flip_display(); } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: quit = true; break; case ALLEGRO_EVENT_TOUCH_BEGIN: { int i = num_touches; if (num_touches < MAX_TOUCHES) { touches[i].id = event.touch.id; touches[i].x = event.touch.x; touches[i].y = event.touch.y; num_touches++; } break; } case ALLEGRO_EVENT_TOUCH_END: { int i = find_index(event.touch.id, num_touches, touches); if (i >= 0 && i < num_touches) { touches[i] = touches[num_touches - 1]; num_touches--; } break; } case ALLEGRO_EVENT_TOUCH_MOVE: { int i = find_index(event.touch.id, num_touches, touches); if (i >= 0) { touches[i].x = event.touch.x; touches[i].y = event.touch.y; } break; } case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING: background = true; al_acknowledge_drawing_halt(event.display.source); break; case ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING: background = false; al_acknowledge_drawing_resume(event.display.source); break; case ALLEGRO_EVENT_DISPLAY_RESIZE: al_acknowledge_resize(event.display.source); break; } } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_transform.c000066400000000000000000000151711473414355200201560ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_primitives.h" #include #include "common.c" int main(int argc, char **argv) { const char *filename; ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *buffer, *bitmap, *subbitmap, *buffer_subbitmap; ALLEGRO_BITMAP *overlay; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_TRANSFORM transform; bool software = false; bool redraw = false; bool blend = false; bool use_subbitmap = true; int w, h; ALLEGRO_FONT* font; ALLEGRO_FONT* soft_font; if (argc > 1) { filename = argv[1]; } else { filename = "data/mysha.pcx"; } if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_primitives_addon(); al_install_mouse(); al_install_keyboard(); al_init_image_addon(); al_init_font_addon(); init_platform_specific(); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display\n"); } subbitmap = al_create_sub_bitmap(al_get_backbuffer(display), 50, 50, 640 - 50, 480 - 50); overlay = al_create_sub_bitmap(al_get_backbuffer(display), 100, 100, 300, 50); al_set_window_title(display, filename); bitmap = al_load_bitmap(filename); if (!bitmap) { abort_example("%s not found or failed to load\n", filename); } font = al_load_font("data/bmpfont.tga", 0, 0); if (!font) { abort_example("data/bmpfont.tga not found or failed to load\n"); } al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); buffer = al_create_bitmap(640, 480); buffer_subbitmap = al_create_sub_bitmap(buffer, 50, 50, 640 - 50, 480 - 50); soft_font = al_load_font("data/bmpfont.tga", 0, 0); if (!soft_font) { abort_example("data/bmpfont.tga not found or failed to load\n"); } timer = al_create_timer(1.0 / 60); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); w = al_get_bitmap_width(bitmap); h = al_get_bitmap_height(bitmap); al_set_target_bitmap(overlay); al_identity_transform(&transform); al_rotate_transform(&transform, -0.06); al_use_transform(&transform); while (1) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_S) { software = !software; if (software) { /* Restore identity transform on display bitmap. */ ALLEGRO_TRANSFORM identity; al_identity_transform(&identity); al_use_transform(&identity); } } else if (event.keyboard.keycode == ALLEGRO_KEY_L) { blend = !blend; } else if (event.keyboard.keycode == ALLEGRO_KEY_B) { use_subbitmap = !use_subbitmap; } else if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } } if (event.type == ALLEGRO_EVENT_TIMER) redraw = true; if (redraw && al_is_event_queue_empty(queue)) { double t = 3.0 + al_get_time(); ALLEGRO_COLOR tint; redraw = false; al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); if(blend) tint = al_map_rgba_f(0.5, 0.5, 0.5, 0.5); else tint = al_map_rgba_f(1, 1, 1, 1); if(software) { if(use_subbitmap) { al_set_target_bitmap(buffer); al_clear_to_color(al_map_rgb_f(1, 0, 0)); al_set_target_bitmap(buffer_subbitmap); } else { al_set_target_bitmap(buffer); } } else { if(use_subbitmap) { al_set_target_backbuffer(display); al_clear_to_color(al_map_rgb_f(1, 0, 0)); al_set_target_bitmap(subbitmap); } else { al_set_target_backbuffer(display); } } /* Set the transformation on the target bitmap. */ al_identity_transform(&transform); al_translate_transform(&transform, -640 / 2, -480 / 2); al_scale_transform(&transform, 0.15 + sin(t / 5), 0.15 + cos(t / 5)); al_rotate_transform(&transform, t / 50); al_translate_transform(&transform, 640 / 2, 480 / 2); al_use_transform(&transform); /* Draw some stuff */ al_clear_to_color(al_map_rgb_f(0, 0, 0)); al_draw_tinted_bitmap(bitmap, tint, 0, 0, 0); al_draw_tinted_scaled_bitmap(bitmap, tint, w / 4, h / 4, w / 2, h / 2, w, 0, w / 2, h / 4, 0);//ALLEGRO_FLIP_HORIZONTAL); al_draw_tinted_bitmap_region(bitmap, tint, w / 4, h / 4, w / 2, h / 2, 0, h, ALLEGRO_FLIP_VERTICAL); al_draw_tinted_scaled_rotated_bitmap(bitmap, tint, w / 2, h / 2, w + w / 2, h + h / 2, 0.7, 0.7, 0.3, 0); al_draw_pixel(w + w / 2, h + h / 2, al_map_rgb_f(0, 1, 0)); al_put_pixel(w + w / 2 + 2, h + h / 2 + 2, al_map_rgb_f(0, 1, 1)); al_draw_circle(w, h, 50, al_map_rgb_f(1, 0.5, 0), 3); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); if(software) { al_draw_text(soft_font, al_map_rgba_f(1, 1, 1, 1), 640 / 2, 430, ALLEGRO_ALIGN_CENTRE, "Software Rendering"); al_set_target_backbuffer(display); al_draw_bitmap(buffer, 0, 0, 0); } else { al_draw_text(font, al_map_rgba_f(1, 1, 1, 1), 640 / 2, 430, ALLEGRO_ALIGN_CENTRE, "Hardware Rendering"); } /* Each target bitmap has its own transformation matrix, so this * overlay is unaffected by the transformations set earlier. */ al_set_target_bitmap(overlay); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE); al_draw_text(font, al_map_rgba_f(1, 1, 0, 1), 0, 10, ALLEGRO_ALIGN_LEFT, "hello!"); al_set_target_backbuffer(display); al_flip_display(); } } al_destroy_bitmap(bitmap); return 0; } /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/examples/ex_ttf.c000066400000000000000000000263601473414355200167420ustar00rootroot00000000000000#define ALLEGRO_UNSTABLE #include #include #include #include #include #include "common.c" #define MAX_RANGES 256 const char *font_file = "data/DejaVuSans.ttf"; struct Example { double fps; ALLEGRO_FONT *f1, *f2, *f3, *f4, *f5, *f6; ALLEGRO_FONT *f_alex; ALLEGRO_CONFIG *config; int ranges_count; } ex; static void print_ranges(ALLEGRO_FONT *f) { int ranges[MAX_RANGES * 2]; int count; int i; count = al_get_font_ranges(f, MAX_RANGES, ranges); for (i = 0; i < count; i++) { int begin = ranges[i * 2]; int end = ranges[i * 2 + 1]; log_printf("range %3d: %08x-%08x (%d glyph%s)\n", i, begin, end, 1 + end - begin, begin == end ? "" : "s"); } } static const char *get_string(const char *key) { const char *v = al_get_config_value(ex.config, "", key); return (v) ? v : key; } static int ustr_at(ALLEGRO_USTR *string, int index) { return al_ustr_get(string, al_ustr_offset(string, index)); } static void render(void) { ALLEGRO_COLOR white = al_map_rgba_f(1, 1, 1, 1); ALLEGRO_COLOR black = al_map_rgba_f(0, 0, 0, 1); ALLEGRO_COLOR red = al_map_rgba_f(1, 0, 0, 1); ALLEGRO_COLOR green = al_map_rgba_f(0, 0.5, 0, 1); ALLEGRO_COLOR blue = al_map_rgba_f(0.1, 0.2, 1, 1); ALLEGRO_COLOR purple = al_map_rgba_f(0.3, 0.1, 0.2, 1); int x, y, w, h, as, de, xpos, ypos; unsigned int index; int target_w, target_h; ALLEGRO_USTR_INFO info, sub_info; const ALLEGRO_USTR *u; ALLEGRO_USTR *tulip = al_ustr_new("Tulip"); ALLEGRO_USTR *dimension_text = al_ustr_new("Tulip"); ALLEGRO_USTR *vertical_text = al_ustr_new("Rose."); ALLEGRO_USTR *dimension_label = al_ustr_new("(dimensions)"); int prev_cp = -1; al_clear_to_color(white); al_hold_bitmap_drawing(true); al_draw_textf(ex.f1, black, 50, 20, 0, "Tulip (kerning)"); al_draw_textf(ex.f2, black, 50, 80, 0, "Tulip (no kerning)"); x = 50; y = 140; for (index = 0; index < al_ustr_length(dimension_text); index ++) { int cp = ustr_at(dimension_text, index); int bbx, bby, bbw, bbh; al_get_glyph_dimensions(ex.f2, cp, &bbx, &bby, &bbw, &bbh); al_draw_rectangle(x + bbx + 0.5, y + bby + 0.5, x + bbx + bbw - 0.5, y + bby + bbh - 0.5, blue, 1); al_draw_rectangle(x + 0.5, y + 0.5, x + bbx + bbw - 0.5, y + bby + bbh - 0.5, green, 1); al_draw_glyph(ex.f2, purple, x, y, cp); x += al_get_glyph_advance(ex.f2, cp, ALLEGRO_NO_KERNING); } al_draw_line(50.5, y+0.5, x+0.5, y+0.5, red, 1); for (index = 0; index < al_ustr_length(dimension_label); index++) { int cp = ustr_at(dimension_label, index); ALLEGRO_GLYPH g; if (al_get_glyph(ex.f2, prev_cp, cp, &g)) { al_draw_tinted_bitmap_region(g.bitmap, black, g.x, g.y, g.w, g.h, x + 10 + g.kerning + g.offset_x, y + g.offset_y, 0); x += g.advance; } prev_cp = cp; } al_draw_textf(ex.f3, black, 50, 200, 0, "This font has a size of 12 pixels, " "the one above has 48 pixels."); al_hold_bitmap_drawing(false); al_hold_bitmap_drawing(true); al_draw_textf(ex.f3, red, 50, 220, 0, "The color can simply be changed.🐊← fallback glyph"); al_hold_bitmap_drawing(false); al_hold_bitmap_drawing(true); al_draw_textf(ex.f3, green, 50, 240, 0, "Some unicode symbols:"); al_draw_textf(ex.f3, green, 50, 260, 0, "%s", get_string("symbols1")); al_draw_textf(ex.f3, green, 50, 280, 0, "%s", get_string("symbols2")); al_draw_textf(ex.f3, green, 50, 300, 0, "%s", get_string("symbols3")); #define OFF(x) al_ustr_offset(u, x) #define SUB(x, y) al_ref_ustr(&sub_info, u, OFF(x), OFF(y)) u = al_ref_cstr(&info, get_string("substr1")); al_draw_ustr(ex.f3, green, 50, 320, 0, SUB(0, 6)); u = al_ref_cstr(&info, get_string("substr2")); al_draw_ustr(ex.f3, green, 50, 340, 0, SUB(7, 11)); u = al_ref_cstr(&info, get_string("substr3")); al_draw_ustr(ex.f3, green, 50, 360, 0, SUB(4, 11)); u = al_ref_cstr(&info, get_string("substr4")); al_draw_ustr(ex.f3, green, 50, 380, 0, SUB(0, 11)); al_draw_textf(ex.f5, black, 50, 395, 0, "forced monochrome"); ALLEGRO_TRANSFORM t; al_identity_transform(&t); al_rotate_transform(&t, al_get_time()); al_translate_transform(&t, 550, 300); al_use_transform(&t); al_draw_textf(ex.f6, black, 0, -al_get_font_line_height(ex.f6) / 2, ALLEGRO_ALIGN_CENTRE, "T"); al_identity_transform(&t); al_use_transform(&t); /* Glyph rendering tests. */ al_draw_textf(ex.f3, red, 50, 410, 0, "Glyph adv Tu: %d, draw: ", al_get_glyph_advance(ex.f3, 'T', 'u')); x = 50; y = 425; for (index = 0; index < al_ustr_length(tulip); index ++) { int cp = ustr_at(tulip, index); /* Use al_get_glyph_advance for the stride, with no kerning. */ al_draw_glyph(ex.f3, red, x, y, cp); x += al_get_glyph_advance(ex.f3, cp, ALLEGRO_NO_KERNING); } x = 50; y = 440; /* First draw a red string using al_draw_text, that should be hidden * completely by the same text drawing in green per glyph * using al_draw_glyph and al_get_glyph_advance below. */ al_draw_ustr(ex.f3, red, x, y, 0, tulip); for (index = 0; index < al_ustr_length(tulip); index ++) { int cp = ustr_at(tulip, index); int ncp = (index < (al_ustr_length(tulip) - 1)) ? ustr_at(tulip, index + 1) : ALLEGRO_NO_KERNING; /* Use al_get_glyph_advance for the stride and apply kerning. */ al_draw_glyph(ex.f3, green, x, y, cp); x += al_get_glyph_advance(ex.f3, cp, ncp); } x = 50; y = 466; al_draw_ustr(ex.f3, red, x, y, 0, tulip); for (index = 0; index < al_ustr_length(tulip); index ++) { int cp = ustr_at(tulip, index); int bbx, bby, bbw, bbh; al_get_glyph_dimensions(ex.f3, cp, &bbx, &bby, &bbw, &bbh); al_draw_glyph(ex.f3, blue, x, y, cp); x += bbx + bbw; } x = 10; y = 30; for (index = 0; index < al_ustr_length(vertical_text); index ++) { int bbx, bby, bbw, bbh; int cp = ustr_at(vertical_text, index); /* Use al_get_glyph_dimensions for the height to apply. */ al_get_glyph_dimensions(ex.f3, cp, &bbx, &bby, &bbw, &bbh); al_draw_glyph(ex.f3, green, x, y, cp); y += bby; y += bbh; } x = 30; y = 30; for (index = 0; index < al_ustr_length(vertical_text); index ++) { int bbx, bby, bbw, bbh; int cp = ustr_at(vertical_text, index); /* Use al_get_glyph_dimensions for the height to apply, here bby is * omited for the wrong result. */ al_get_glyph_dimensions(ex.f3, cp, &bbx, &bby, &bbw, &bbh); al_draw_glyph(ex.f3, red, x, y, cp); y += bbh; } al_hold_bitmap_drawing(false); target_w = al_get_bitmap_width(al_get_target_bitmap()); target_h = al_get_bitmap_height(al_get_target_bitmap()); xpos = target_w - 10; ypos = target_h - 10; al_get_text_dimensions(ex.f4, "Allegro", &x, &y, &w, &h); as = al_get_font_ascent(ex.f4); de = al_get_font_descent(ex.f4); xpos -= w; ypos -= h; x += xpos; y += ypos; al_draw_rectangle(x, y, x + w - 0.5, y + h - 0.5, black, 0); al_draw_line(x+0.5, y + as + 0.5, x + w - 0.5, y + as + 0.5, black, 0); al_draw_line(x + 0.5, y + as + de + 0.5, x + w - 0.5, y + as + de + 0.5, black, 0); al_hold_bitmap_drawing(true); al_draw_textf(ex.f4, blue, xpos, ypos, 0, "Allegro"); al_hold_bitmap_drawing(false); al_hold_bitmap_drawing(true); al_draw_textf(ex.f3, black, target_w, 0, ALLEGRO_ALIGN_RIGHT, "%.1f FPS", ex.fps); al_draw_textf(ex.f3, black, 0, 0, 0, "%s: %d unicode ranges", font_file, ex.ranges_count); al_hold_bitmap_drawing(false); } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; int redraw = 0; double t = 0; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log_monospace(); al_init_primitives_addon(); al_install_mouse(); al_init_font_addon(); al_init_ttf_addon(); al_init_image_addon(); init_platform_specific(); #ifdef ALLEGRO_IPHONE al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW); #endif display = al_create_display(640, 480); if (!display) { abort_example("Could not create display.\n"); } al_install_keyboard(); if (argc >= 2) { font_file = argv[1]; } ex.f1 = al_load_font(font_file, 48, 0); ex.f2 = al_load_font(font_file, 48, ALLEGRO_TTF_NO_KERNING); ex.f3 = al_load_font(font_file, 12, 0); /* Specifying negative values means we specify the glyph height * in pixels, not the usual font size. */ ex.f4 = al_load_font(font_file, -140, 0); ex.f5 = al_load_font(font_file, 12, ALLEGRO_TTF_MONOCHROME); al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); ex.f6 = al_load_font(font_file, -140, 0); al_set_new_bitmap_flags(0); { int ranges[] = {0x1F40A, 0x1F40A}; ALLEGRO_BITMAP *icon = al_load_bitmap("data/icon.png"); if (!icon) { abort_example("Couldn't load data/icon.png.\n"); } ALLEGRO_BITMAP *glyph = al_create_bitmap(50, 50); al_set_target_bitmap(glyph); al_clear_to_color(al_map_rgba_f(0, 0, 0, 0)); al_draw_rectangle(0.5, 0.5, 49.5, 49.5, al_map_rgb_f(1, 1, 0), 1); al_draw_bitmap(icon, 1, 1, 0); al_set_target_backbuffer(display); ex.f_alex = al_grab_font_from_bitmap(glyph, 1, ranges); } if (!ex.f1 || !ex.f2 || !ex.f3 || !ex.f4 || !ex.f_alex) { abort_example("Could not load font: %s\n", font_file); } al_set_fallback_font(ex.f3, ex.f_alex); ex.ranges_count = al_get_font_ranges(ex.f1, 0, NULL); print_ranges(ex.f1); ex.config = al_load_config_file("data/ex_ttf.ini"); if (!ex.config) { abort_example("Could not data/ex_ttf.ini\n"); } timer = al_create_timer(1.0 / 60); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (true) { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } if (event.type == ALLEGRO_EVENT_TIMER) redraw++; while (redraw > 0 && al_is_event_queue_empty(queue)) { double dt; redraw--; dt = al_get_time(); render(); dt = al_get_time() - dt; t = 0.99 * t + 0.01 * dt; ex.fps = 1.0 / t; al_flip_display(); } } al_destroy_font(ex.f1); al_destroy_font(ex.f2); al_destroy_font(ex.f3); al_destroy_font(ex.f4); al_destroy_font(ex.f5); al_destroy_config(ex.config); close_log(false); return 0; } /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/examples/ex_user_events.c000066400000000000000000000060671473414355200205110ustar00rootroot00000000000000/* * Example program for the Allegro library. */ #include #include "allegro5/allegro.h" #include "common.c" #define MY_SIMPLE_EVENT_TYPE ALLEGRO_GET_EVENT_TYPE('m', 's', 'e', 't') #define MY_COMPLEX_EVENT_TYPE ALLEGRO_GET_EVENT_TYPE('m', 'c', 'e', 't') /* Just some fantasy event, supposedly used in an RPG - it's just to show that * in practice, the 4 user fields we have now never will be enough. */ typedef struct MY_EVENT { int id; int type; /* For example "attack" or "buy". */ int x, y, z; /* Position in the game world the event takes place. */ int server_time; /* Game time in ticks the event takes place. */ int source_unit_id; /* E.g. attacker or seller. */ int destination_unit_id; /* E.g. defender of buyer. */ int item_id; /* E.g. weapon used or item sold. */ int amount; /* Gold the item is sold for. */ } MY_EVENT; static MY_EVENT *new_event(int id) { MY_EVENT *event = calloc(1, sizeof *event); event->id = id; return event; } static void my_event_dtor(ALLEGRO_USER_EVENT *event) { log_printf("my_event_dtor: %p\n", (void *) event->data1); free((void *) event->data1); } int main(int argc, char **argv) { ALLEGRO_TIMER *timer; ALLEGRO_EVENT_SOURCE user_src; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT user_event; ALLEGRO_EVENT event; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } timer = al_create_timer(0.5); if (!timer) { abort_example("Could not install timer.\n"); } open_log(); al_init_user_event_source(&user_src); queue = al_create_event_queue(); al_register_event_source(queue, &user_src); al_register_event_source(queue, al_get_timer_event_source(timer)); al_start_timer(timer); while (true) { al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_TIMER) { int n = event.timer.count; log_printf("Got timer event %d\n", n); user_event.user.type = MY_SIMPLE_EVENT_TYPE; user_event.user.data1 = n; al_emit_user_event(&user_src, &user_event, NULL); user_event.user.type = MY_COMPLEX_EVENT_TYPE; user_event.user.data1 = (intptr_t)new_event(n); al_emit_user_event(&user_src, &user_event, my_event_dtor); } else if (event.type == MY_SIMPLE_EVENT_TYPE) { int n = (int) event.user.data1; ALLEGRO_ASSERT(event.user.source == &user_src); al_unref_user_event(&event.user); log_printf("Got simple user event %d\n", n); if (n == 5) { break; } } else if (event.type == MY_COMPLEX_EVENT_TYPE) { MY_EVENT *my_event = (void *)event.user.data1; ALLEGRO_ASSERT(event.user.source == &user_src); log_printf("Got complex user event %d\n", my_event->id); al_unref_user_event(&event.user); } } al_destroy_user_event_source(&user_src); al_destroy_event_queue(queue); al_destroy_timer(timer); log_printf("Done.\n"); close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_utf8.c000066400000000000000000001031101473414355200170200ustar00rootroot00000000000000/* * Example program for the Allegro library. * * Test UTF-8 string routines. */ /* TODO: we should also be checking on inputs with surrogate characters * (which are not allowed) */ #include #include #include #include #include "common.c" #ifdef ALLEGRO_MSVC #pragma warning (disable: 4066) #endif /* Some unicode characters */ #define U_ae 0x00e6 /* æ */ #define U_i_acute 0x00ed /* í */ #define U_eth 0x00f0 /* ð */ #define U_o_dia 0x00f6 /* ö */ #define U_thorn 0x00fe /* þ */ #define U_z_bar 0x01b6 /* ƶ */ #define U_schwa 0x0259 /* ə */ #define U_beta 0x03b2 /* β */ #define U_1d08 0x1d08 /* ᴈ */ #define U_1ff7 0x1ff7 /* ῷ */ #define U_2051 0x2051 /* ⁑ */ #define U_euro 0x20ac /* € */ typedef void (*test_t)(void); int error = 0; #define CHECK(x) \ do { \ bool ok = (x); \ if (!ok) { \ log_printf("FAIL %s\n", #x); \ error++; \ } else { \ log_printf("OK %s\n", #x); \ } \ } while (0) /* Test that we can create and destroy strings and get their data and size. */ static void t1(void) { ALLEGRO_USTR *us1 = al_ustr_new(""); ALLEGRO_USTR *us2 = al_ustr_new("áƵ"); CHECK(0 == strcmp(al_cstr(us1), "")); CHECK(0 == strcmp(al_cstr(us2), "áƵ")); CHECK(4 == al_ustr_size(us2)); al_ustr_free(us1); al_ustr_free(us2); } static void t2(void) { CHECK(0 == al_ustr_size(al_ustr_empty_string())); CHECK(0 == strcmp(al_cstr(al_ustr_empty_string()), "")); } /* Test that we make strings which reference other C strings. */ /* No memory needs to be freed. */ static void t3(void) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us = al_ref_cstr(&info, "A static string."); CHECK(0 == strcmp(al_cstr(us), "A static string.")); } /* Test that we can make strings which reference arbitrary memory blocks. */ /* No memory needs to be freed. */ static void t4(void) { const char s[] = "This contains an embedded NUL: \0 <-- here"; ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us = al_ref_buffer(&info, s, sizeof(s)); CHECK(al_ustr_size(us) == sizeof(s)); CHECK(0 == memcmp(al_cstr(us), s, sizeof(s))); } /* Test that we can make strings which reference (parts of) other strings. */ static void t5(void) { ALLEGRO_USTR *us1; const ALLEGRO_USTR *us2; ALLEGRO_USTR_INFO us2_info; us1 = al_ustr_new("aábdðeéfghiíjklmnoóprstuúvxyýþæö"); us2 = al_ref_ustr(&us2_info, us1, 36, 36 + 4); CHECK(0 == memcmp(al_cstr(us2), "þæ", al_ustr_size(us2))); /* Start pos underflow */ us2 = al_ref_ustr(&us2_info, us1, -10, 7); CHECK(0 == memcmp(al_cstr(us2), "aábdð", al_ustr_size(us2))); /* End pos overflow */ us2 = al_ref_ustr(&us2_info, us1, 36, INT_MAX); CHECK(0 == memcmp(al_cstr(us2), "þæö", al_ustr_size(us2))); /* Start > end */ us2 = al_ref_ustr(&us2_info, us1, 36 + 4, 36); CHECK(0 == al_ustr_size(us2)); al_ustr_free(us1); } /* Test al_ustr_dup. */ static void t6(void) { ALLEGRO_USTR *us1 = al_ustr_new("aábdðeéfghiíjklmnoóprstuúvxyýþæö"); ALLEGRO_USTR *us2 = al_ustr_dup(us1); CHECK(al_ustr_size(us1) == al_ustr_size(us2)); CHECK(0 == memcmp(al_cstr(us1), al_cstr(us2), al_ustr_size(us1))); al_ustr_free(us1); al_ustr_free(us2); } /* Test al_ustr_dup_substr. */ static void t7(void) { ALLEGRO_USTR *us1; ALLEGRO_USTR *us2; us1 = al_ustr_new("aábdðeéfghiíjklmnoóprstuúvxyýþæö"); /* Cut out part of a string. Check for NUL terminator. */ us2 = al_ustr_dup_substr(us1, 36, 36 + 4); CHECK(al_ustr_size(us2) == 4); CHECK(0 == strcmp(al_cstr(us2), "þæ")); al_ustr_free(us2); /* Under and overflow */ us2 = al_ustr_dup_substr(us1, INT_MIN, INT_MAX); CHECK(al_ustr_size(us2) == al_ustr_size(us1)); CHECK(0 == strcmp(al_cstr(us2), al_cstr(us1))); al_ustr_free(us2); /* Start > end */ us2 = al_ustr_dup_substr(us1, INT_MAX, INT_MIN); CHECK(0 == al_ustr_size(us2)); al_ustr_free(us2); al_ustr_free(us1); } /* Test al_ustr_append, al_ustr_append_cstr. */ static void t8(void) { ALLEGRO_USTR *us1 = al_ustr_new("aábdðeéfghiíjklm"); ALLEGRO_USTR *us2 = al_ustr_new("noóprstuú"); CHECK(al_ustr_append(us1, us2)); CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjklmnoóprstuú")); CHECK(al_ustr_append_cstr(us1, "vxyýþæö")); CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjklmnoóprstuúvxyýþæö")); al_ustr_free(us1); al_ustr_free(us2); } /* Test al_ustr_append with aliased strings. */ static void t9(void) { ALLEGRO_USTR *us1; ALLEGRO_USTR_INFO us2_info; const ALLEGRO_USTR *us2; /* Append a string to itself. */ us1 = al_ustr_new("aábdðeéfghiíjklm"); CHECK(al_ustr_append(us1, us1)); CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjklmaábdðeéfghiíjklm")); al_ustr_free(us1); /* Append a substring of a string to itself. */ us1 = al_ustr_new("aábdðeéfghiíjklm"); us2 = al_ref_ustr(&us2_info, us1, 5, 5 + 11); /* ð...í */ CHECK(al_ustr_append(us1, us2)); CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjklmðeéfghií")); al_ustr_free(us1); } /* Test al_ustr_equal. */ static void t10(void) { ALLEGRO_USTR *us1; ALLEGRO_USTR *us2; const ALLEGRO_USTR *us3; ALLEGRO_USTR_INFO us3_info; const char us3_data[] = "aábdð\0eéfgh"; us1 = al_ustr_new("aábdð"); us2 = al_ustr_dup(us1); us3 = al_ref_buffer(&us3_info, us3_data, sizeof(us3_data)); CHECK(al_ustr_equal(us1, us2)); CHECK(!al_ustr_equal(us1, al_ustr_empty_string())); /* Check comparison doesn't stop at embedded NUL. */ CHECK(!al_ustr_equal(us1, us3)); al_ustr_free(us1); al_ustr_free(us2); } /* Test al_ustr_insert. */ static void t11(void) { ALLEGRO_USTR *us1; ALLEGRO_USTR *us2; size_t sz; /* Insert in middle. */ us1 = al_ustr_new("aábdðeéfghiíjkprstuúvxyýþæö"); us2 = al_ustr_new("lmnoó"); al_ustr_insert(us1, 18, us2); CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjklmnoóprstuúvxyýþæö")); /* Insert into itself. */ al_ustr_insert(us2, 3, us2); CHECK(0 == strcmp(al_cstr(us2), "lmnlmnoóoó")); /* Insert before start (not allowed). */ CHECK(!al_ustr_insert(us2, -1, us2)); /* Insert past end (will be padded with NULs). */ sz = al_ustr_size(us2); al_ustr_insert(us2, sz + 3, us2); CHECK(al_ustr_size(us2) == sz + sz + 3); CHECK(0 == memcmp(al_cstr(us2), "lmnlmnoóoó\0\0\0lmnlmnoóoó", sz + sz + 3)); al_ustr_free(us1); al_ustr_free(us2); } /* Test al_ustr_insert_cstr. */ static void t12(void) { ALLEGRO_USTR *us1 = al_ustr_new("aábeéf"); CHECK(al_ustr_insert_cstr(us1, 4, "dð")); CHECK(0 == strcmp(al_cstr(us1), "aábdðeéf")); al_ustr_free(us1); } /* Test al_ustr_remove_range. */ static void t13(void) { ALLEGRO_USTR *us1 = al_ustr_new("aábdðeéfghiíjkprstuúvxyýþæö"); /* Remove from middle of string. */ CHECK(al_ustr_remove_range(us1, 5, 30)); CHECK(0 == strcmp(al_cstr(us1), "aábdþæö")); /* Removing past end. */ CHECK(al_ustr_remove_range(us1, 100, 120)); CHECK(0 == strcmp(al_cstr(us1), "aábdþæö")); /* Start > End. */ CHECK(! al_ustr_remove_range(us1, 3, 0)); CHECK(0 == strcmp(al_cstr(us1), "aábdþæö")); al_ustr_free(us1); } /* Test al_ustr_truncate. */ static void t14(void) { ALLEGRO_USTR *us1 = al_ustr_new("aábdðeéfghiíjkprstuúvxyýþæö"); /* Truncate from middle of string. */ CHECK(al_ustr_truncate(us1, 30)); CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjkprstuúvxyý")); /* Truncate past end (allowed). */ CHECK(al_ustr_truncate(us1, 100)); CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjkprstuúvxyý")); /* Truncate before start (not allowed). */ CHECK(! al_ustr_truncate(us1, -1)); CHECK(0 == strcmp(al_cstr(us1), "aábdðeéfghiíjkprstuúvxyý")); al_ustr_free(us1); } /* Test whitespace trim functions. */ static void t15(void) { ALLEGRO_USTR *us1 = al_ustr_new(" \f\n\r\t\vhello \f\n\r\t\v"); ALLEGRO_USTR *us2 = al_ustr_new(" \f\n\r\t\vhello \f\n\r\t\v"); CHECK(al_ustr_ltrim_ws(us1)); CHECK(0 == strcmp(al_cstr(us1), "hello \f\n\r\t\v")); CHECK(al_ustr_rtrim_ws(us1)); CHECK(0 == strcmp(al_cstr(us1), "hello")); CHECK(al_ustr_trim_ws(us2)); CHECK(0 == strcmp(al_cstr(us2), "hello")); al_ustr_free(us1); al_ustr_free(us2); } /* Test whitespace trim functions (edge cases). */ static void t16(void) { ALLEGRO_USTR *us1; /* Check return value when passed empty strings. */ us1 = al_ustr_new(""); CHECK(al_ustr_ltrim_ws(us1)); CHECK(al_ustr_rtrim_ws(us1)); CHECK(al_ustr_trim_ws(us1)); al_ustr_free(us1); /* Check nothing bad happens if the whole string is whitespace. */ us1 = al_ustr_new(" \f\n\r\t\v"); CHECK(al_ustr_ltrim_ws(us1)); CHECK(al_ustr_size(us1) == 0); al_ustr_free(us1); us1 = al_ustr_new(" \f\n\r\t\v"); CHECK(al_ustr_rtrim_ws(us1)); CHECK(al_ustr_size(us1) == 0); al_ustr_free(us1); us1 = al_ustr_new(" \f\n\r\t\v"); CHECK(al_ustr_trim_ws(us1)); CHECK(al_ustr_size(us1) == 0); al_ustr_free(us1); } /* Test al_utf8_width. */ static void t17(void) { CHECK(al_utf8_width(0x000000) == 1); CHECK(al_utf8_width(0x00007f) == 1); CHECK(al_utf8_width(0x000080) == 2); CHECK(al_utf8_width(0x0007ff) == 2); CHECK(al_utf8_width(0x000800) == 3); CHECK(al_utf8_width(0x00ffff) == 3); CHECK(al_utf8_width(0x010000) == 4); CHECK(al_utf8_width(0x10ffff) == 4); /* These are illegal. */ CHECK(al_utf8_width(0x110000) == 0); CHECK(al_utf8_width(0xffffff) == 0); } /* Test al_utf8_encode. */ static void t18(void) { char buf[4]; CHECK(al_utf8_encode(buf, 0) == 1); CHECK(0 == memcmp(buf, "\x00", 1)); CHECK(al_utf8_encode(buf, 0x7f) == 1); CHECK(0 == memcmp(buf, "\x7f", 1)); CHECK(al_utf8_encode(buf, 0x80) == 2); CHECK(0 == memcmp(buf, "\xC2\x80", 2)); CHECK(al_utf8_encode(buf, 0x7ff) == 2); CHECK(0 == memcmp(buf, "\xDF\xBF", 2)); CHECK(al_utf8_encode(buf, 0x000800) == 3); CHECK(0 == memcmp(buf, "\xE0\xA0\x80", 3)); CHECK(al_utf8_encode(buf, 0x00ffff) == 3); CHECK(0 == memcmp(buf, "\xEF\xBF\xBF", 3)); CHECK(al_utf8_encode(buf, 0x010000) == 4); CHECK(0 == memcmp(buf, "\xF0\x90\x80\x80", 4)); CHECK(al_utf8_encode(buf, 0x10ffff) == 4); CHECK(0 == memcmp(buf, "\xF4\x8f\xBF\xBF", 4)); /* These are illegal. */ CHECK(al_utf8_encode(buf, 0x110000) == 0); CHECK(al_utf8_encode(buf, 0xffffff) == 0); } /* Test al_ustr_insert_chr. */ static void t19(void) { ALLEGRO_USTR *us = al_ustr_new(""); CHECK(al_ustr_insert_chr(us, 0, 'a') == 1); CHECK(al_ustr_insert_chr(us, 0, U_ae) == 2); CHECK(al_ustr_insert_chr(us, 2, U_euro) == 3); CHECK(0 == strcmp(al_cstr(us), "æ€a")); /* Past end. */ CHECK(al_ustr_insert_chr(us, 8, U_o_dia) == 2); CHECK(0 == memcmp(al_cstr(us), "æ€a\0\0ö", 9)); /* Invalid code points. */ CHECK(al_ustr_insert_chr(us, 0, -1) == 0); CHECK(al_ustr_insert_chr(us, 0, 0x110000) == 0); al_ustr_free(us); } /* Test al_ustr_append_chr. */ static void t20(void) { ALLEGRO_USTR *us = al_ustr_new(""); CHECK(al_ustr_append_chr(us, 'a') == 1); CHECK(al_ustr_append_chr(us, U_ae) == 2); CHECK(al_ustr_append_chr(us, U_euro) == 3); CHECK(0 == strcmp(al_cstr(us), "aæ€")); /* Invalid code points. */ CHECK(al_ustr_append_chr(us, -1) == 0); CHECK(al_ustr_append_chr(us, 0x110000) == 0); al_ustr_free(us); } /* Test al_ustr_get. */ static void t21(void) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us; us = al_ref_buffer(&info, "", 1); CHECK(al_ustr_get(us, 0) == 0); us = al_ref_cstr(&info, "\x7f"); CHECK(al_ustr_get(us, 0) == 0x7f); us = al_ref_cstr(&info, "\xC2\x80"); CHECK(al_ustr_get(us, 0) == 0x80); us = al_ref_cstr(&info, "\xDF\xBf"); CHECK(al_ustr_get(us, 0) == 0x7ff); us = al_ref_cstr(&info, "\xE0\xA0\x80"); CHECK(al_ustr_get(us, 0) == 0x800); us = al_ref_cstr(&info, "\xEF\xBF\xBF"); CHECK(al_ustr_get(us, 0) == 0xffff); us = al_ref_cstr(&info, "\xF0\x90\x80\x80"); CHECK(al_ustr_get(us, 0) == 0x010000); us = al_ref_cstr(&info, "\xF4\x8F\xBF\xBF"); CHECK(al_ustr_get(us, 0) == 0x10ffff); } /* Test al_ustr_get on invalid sequences. */ static void t22(void) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us; /* Empty string. */ al_set_errno(0); CHECK(al_ustr_get(al_ustr_empty_string(), 0) < 0); CHECK(al_get_errno() == ERANGE); /* 5-byte sequence. */ us = al_ref_cstr(&info, "\xf8\x88\x80\x80\x80"); al_set_errno(0); CHECK(al_ustr_get(us, 0) < 0); CHECK(al_get_errno() == EILSEQ); /* Start in trail byte. */ us = al_ref_cstr(&info, "ð"); al_set_errno(0); CHECK(al_ustr_get(us, 1) < 0); CHECK(al_get_errno() == EILSEQ); /* Truncated 3-byte sequence. */ us = al_ref_cstr(&info, "\xEF\xBF"); al_set_errno(0); CHECK(al_ustr_get(us, 0) < 0); CHECK(al_get_errno() == EILSEQ); } /* Test al_ustr_get on invalid sequences (part 2). */ /* Get more ideas for tests from * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt */ static void t23(void) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us; /* Examples of an overlong ASCII character */ us = al_ref_cstr(&info, "\xc0\xaf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xe0\x80\xaf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf0\x80\x80\xaf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf8\x80\x80\x80\xaf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xfc\x80\x80\x80\x80\xaf"); CHECK(al_ustr_get(us, 0) < 0); /* Maximum overlong sequences */ us = al_ref_cstr(&info, "\xc1\xbf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xe0\x9f\xbf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf0\x8f\xbf\xbf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf8\x87\xbf\xbf\xbf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xfc\x83\xbf\xbf\xbf\xbf"); CHECK(al_ustr_get(us, 0) < 0); /* Overlong representation of the NUL character */ us = al_ref_cstr(&info, "\xc0\x80"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xe0\x80\x80"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf0\x80\x80"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf8\x80\x80\x80"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xfc\x80\x80\x80\x80"); CHECK(al_ustr_get(us, 0) < 0); } /* Test al_ustr_next. */ static void t24(void) { const char str[] = "a\0þ€\xf4\x8f\xbf\xbf"; ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us = al_ref_buffer(&info, str, sizeof(str) - 1); int pos = 0; CHECK(al_ustr_next(us, &pos)); /* a */ CHECK(pos == 1); CHECK(al_ustr_next(us, &pos)); /* NUL */ CHECK(pos == 2); CHECK(al_ustr_next(us, &pos)); /* þ */ CHECK(pos == 4); CHECK(al_ustr_next(us, &pos)); /* € */ CHECK(pos == 7); CHECK(al_ustr_next(us, &pos)); /* U+10FFFF */ CHECK(pos == 11); CHECK(! al_ustr_next(us, &pos)); /* end */ CHECK(pos == 11); } /* Test al_ustr_next with invalid input. */ static void t25(void) { const char str[] = "þ\xf4\x8f\xbf."; ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us = al_ref_buffer(&info, str, sizeof(str) - 1); int pos; /* Starting in middle of a sequence. */ pos = 1; CHECK(al_ustr_next(us, &pos)); CHECK(pos == 2); /* Unexpected end of 4-byte sequence. */ CHECK(al_ustr_next(us, &pos)); CHECK(pos == 5); } /* Test al_ustr_prev. */ static void t26(void) { ALLEGRO_USTR *us = al_ustr_new("aþ€\xf4\x8f\xbf\xbf"); int pos = al_ustr_size(us); CHECK(al_ustr_prev(us, &pos)); /* U+10FFFF */ CHECK(pos == 6); CHECK(al_ustr_prev(us, &pos)); /* € */ CHECK(pos == 3); CHECK(al_ustr_prev(us, &pos)); /* þ */ CHECK(pos == 1); CHECK(al_ustr_prev(us, &pos)); /* a */ CHECK(pos == 0); CHECK(!al_ustr_prev(us, &pos)); /* begin */ CHECK(pos == 0); al_ustr_free(us); } /* Test al_ustr_length. */ static void t27(void) { ALLEGRO_USTR *us = al_ustr_new("aþ€\xf4\x8f\xbf\xbf"); CHECK(0 == al_ustr_length(al_ustr_empty_string())); CHECK(4 == al_ustr_length(us)); al_ustr_free(us); } /* Test al_ustr_offset. */ static void t28(void) { ALLEGRO_USTR *us = al_ustr_new("aþ€\xf4\x8f\xbf\xbf"); CHECK(al_ustr_offset(us, 0) == 0); CHECK(al_ustr_offset(us, 1) == 1); CHECK(al_ustr_offset(us, 2) == 3); CHECK(al_ustr_offset(us, 3) == 6); CHECK(al_ustr_offset(us, 4) == 10); CHECK(al_ustr_offset(us, 5) == 10); CHECK(al_ustr_offset(us, -1) == 6); CHECK(al_ustr_offset(us, -2) == 3); CHECK(al_ustr_offset(us, -3) == 1); CHECK(al_ustr_offset(us, -4) == 0); CHECK(al_ustr_offset(us, -5) == 0); al_ustr_free(us); } /* Test al_ustr_get_next. */ static void t29(void) { ALLEGRO_USTR *us = al_ustr_new("aþ€"); int pos; pos = 0; CHECK(al_ustr_get_next(us, &pos) == 'a'); CHECK(al_ustr_get_next(us, &pos) == U_thorn); CHECK(al_ustr_get_next(us, &pos) == U_euro); CHECK(al_ustr_get_next(us, &pos) == -1); CHECK(pos == (int) al_ustr_size(us)); /* Start in the middle of þ. */ pos = 2; CHECK(al_ustr_get_next(us, &pos) == -2); CHECK(al_ustr_get_next(us, &pos) == U_euro); al_ustr_free(us); } /* Test al_ustr_prev_get. */ static void t30(void) { ALLEGRO_USTR *us = al_ustr_new("aþ€"); int pos; pos = al_ustr_size(us); CHECK(al_ustr_prev_get(us, &pos) == U_euro); CHECK(al_ustr_prev_get(us, &pos) == U_thorn); CHECK(al_ustr_prev_get(us, &pos) == 'a'); CHECK(al_ustr_prev_get(us, &pos) == -1); /* Start in the middle of þ. */ pos = 2; CHECK(al_ustr_prev_get(us, &pos) == U_thorn); al_ustr_free(us); } /* Test al_ustr_find_chr. */ static void t31(void) { ALLEGRO_USTR *us = al_ustr_new("aábdðeéfghiíaábdðeéfghií"); /* Find ASCII. */ CHECK(al_ustr_find_chr(us, 0, 'e') == 7); CHECK(al_ustr_find_chr(us, 7, 'e') == 7); /* start_pos is inclusive */ CHECK(al_ustr_find_chr(us, 8, 'e') == 23); CHECK(al_ustr_find_chr(us, 0, '.') == -1); /* Find non-ASCII. */ CHECK(al_ustr_find_chr(us, 0, U_eth) == 5); CHECK(al_ustr_find_chr(us, 5, U_eth) == 5); /* start_pos is inclusive */ CHECK(al_ustr_find_chr(us, 6, U_eth) == 21); CHECK(al_ustr_find_chr(us, 0, U_z_bar) == -1); al_ustr_free(us); } /* Test al_ustr_rfind_chr. */ static void t32(void) { ALLEGRO_USTR *us = al_ustr_new("aábdðeéfghiíaábdðeéfghií"); int end = al_ustr_size(us); /* Find ASCII. */ CHECK(al_ustr_rfind_chr(us, end, 'e') == 23); CHECK(al_ustr_rfind_chr(us, 23, 'e') == 7); /* end_pos exclusive */ CHECK(al_ustr_rfind_chr(us, end, '.') == -1); /* Find non-ASCII. */ CHECK(al_ustr_rfind_chr(us, end, U_i_acute) == 30); CHECK(al_ustr_rfind_chr(us, end - 1, U_i_acute) == 14); /* end_pos exclusive */ CHECK(al_ustr_rfind_chr(us, end, U_z_bar) == -1); al_ustr_free(us); } /* Test al_ustr_find_set, al_ustr_find_set_cstr. */ static void t33(void) { ALLEGRO_USTR *us = al_ustr_new("aábdðeéfghiíaábdðeéfghií"); /* al_ustr_find_set_cstr is s simple wrapper for al_ustr_find_set * so we test using that. */ /* Find ASCII. */ CHECK(al_ustr_find_set_cstr(us, 0, "gfe") == 7); CHECK(al_ustr_find_set_cstr(us, 7, "gfe") == 7); /* start_pos inclusive */ CHECK(al_ustr_find_set_cstr(us, 0, "") == -1); CHECK(al_ustr_find_set_cstr(us, 0, "xyz") == -1); /* Find non-ASCII. */ CHECK(al_ustr_find_set_cstr(us, 0, "éðf") == 5); CHECK(al_ustr_find_set_cstr(us, 5, "éðf") == 5); /* start_pos inclusive */ CHECK(al_ustr_find_set_cstr(us, 0, "ẋỹƶ") == -1); al_ustr_free(us); } /* Test al_ustr_find_set, al_ustr_find_set_cstr (invalid values). */ static void t34(void) { ALLEGRO_USTR *us = al_ustr_new("a\x80ábdðeéfghií"); /* Invalid byte sequence in search string. */ CHECK(al_ustr_find_set_cstr(us, 0, "gfe") == 8); /* Invalid byte sequence in accept set. */ CHECK(al_ustr_find_set_cstr(us, 0, "é\x80ðf") == 6); al_ustr_free(us); } /* Test al_ustr_find_cset, al_ustr_find_cset_cstr. */ static void t35(void) { ALLEGRO_USTR *us; /* al_ustr_find_cset_cstr is s simple wrapper for al_ustr_find_cset * so we test using that. */ /* Find ASCII. */ us = al_ustr_new("alphabetagamma"); CHECK(al_ustr_find_cset_cstr(us, 0, "alphbet") == 9); CHECK(al_ustr_find_cset_cstr(us, 9, "alphbet") == 9); CHECK(al_ustr_find_cset_cstr(us, 0, "") == -1); CHECK(al_ustr_find_cset_cstr(us, 0, "alphbetgm") == -1); al_ustr_free(us); /* Find non-ASCII. */ us = al_ustr_new("αλφαβεταγαμμα"); CHECK(al_ustr_find_cset_cstr(us, 0, "αλφβετ") == 16); CHECK(al_ustr_find_cset_cstr(us, 16, "αλφβετ") == 16); CHECK(al_ustr_find_cset_cstr(us, 0, "αλφβετγμ") == -1); al_ustr_free(us); } /* Test al_ustr_find_cset, al_ustr_find_set_cstr (invalid values). */ static void t36(void) { ALLEGRO_USTR *us = al_ustr_new("a\x80ábdðeéfghií"); /* Invalid byte sequence in search string. */ CHECK(al_ustr_find_cset_cstr(us, 0, "aábd") == 6); /* Invalid byte sequence in reject set. */ CHECK(al_ustr_find_cset_cstr(us, 0, "a\x80ábd") == 6); al_ustr_free(us); } /* Test al_ustr_find_str, al_ustr_find_cstr. */ static void t37(void) { ALLEGRO_USTR *us = al_ustr_new("aábdðeéfghiíaábdðeéfghií"); /* al_ustr_find_cstr is s simple wrapper for al_ustr_find_str * so we test using that. */ CHECK(al_ustr_find_cstr(us, 0, "") == 0); CHECK(al_ustr_find_cstr(us, 10, "") == 10); CHECK(al_ustr_find_cstr(us, 0, "ábd") == 1); CHECK(al_ustr_find_cstr(us, 10, "ábd") == 17); CHECK(al_ustr_find_cstr(us, 0, "ábz") == -1); al_ustr_free(us); } /* Test al_ustr_rfind_str, al_ustr_rfind_cstr. */ static void t38(void) { ALLEGRO_USTR *us = al_ustr_new("aábdðeéfghiíaábdðeéfghií"); int end = al_ustr_size(us); /* al_ustr_find_cstr is s simple wrapper for al_ustr_find_str * so we test using that. */ CHECK(al_ustr_rfind_cstr(us, 0, "") == 0); CHECK(al_ustr_rfind_cstr(us, 1, "") == 1); CHECK(al_ustr_rfind_cstr(us, end, "hií") == end - 4); CHECK(al_ustr_rfind_cstr(us, end - 1, "hií") == 12); CHECK(al_ustr_rfind_cstr(us, end, "ábz") == -1); al_ustr_free(us); } /* Test al_ustr_new_from_buffer, al_cstr_dup. */ static void t39(void) { const char s1[] = "Корабът ми на въздушна възглавница\0е пълен със змиорки"; ALLEGRO_USTR *us; char *s2; us = al_ustr_new_from_buffer(s1, sizeof(s1) - 1); /* missing NUL term. */ s2 = al_cstr_dup(us); al_ustr_free(us); CHECK(0 == strcmp(s1, s2)); CHECK(0 == memcmp(s1, s2, sizeof(s1))); /* including NUL terminator */ al_free(s2); } /* Test al_ustr_assign, al_ustr_assign_cstr. */ static void t40(void) { ALLEGRO_USTR *us1 = al_ustr_new("我隻氣墊船裝滿晒鱔"); ALLEGRO_USTR *us2 = al_ustr_new("Τὸ χόβερκράφτ μου εἶναι γεμᾶτο χέλια"); CHECK(al_ustr_assign(us1, us2)); CHECK(0 == strcmp(al_cstr(us1), "Τὸ χόβερκράφτ μου εἶναι γεμᾶτο χέλια")); CHECK(al_ustr_assign_cstr(us1, "私のホバークラフトは鰻でいっぱいです")); CHECK(54 == al_ustr_size(us1)); al_ustr_free(us1); al_ustr_free(us2); } /* Test al_ustr_assign_cstr. */ static void t41(void) { ALLEGRO_USTR *us1 = al_ustr_new("Моја лебдилица је пуна јегуља"); ALLEGRO_USTR *us2 = al_ustr_new(""); CHECK(al_ustr_assign_substr(us2, us1, 9, 27)); CHECK(0 == strcmp(al_cstr(us2), "лебдилица")); /* Start > End */ CHECK(al_ustr_assign_substr(us2, us1, 9, 0)); CHECK(0 == strcmp(al_cstr(us2), "")); /* Start, end out of bounds */ CHECK(al_ustr_assign_substr(us2, us1, -INT_MAX, INT_MAX)); CHECK(0 == strcmp(al_cstr(us2), "Моја лебдилица је пуна јегуља")); al_ustr_free(us1); al_ustr_free(us2); } /* Test al_ustr_set_chr. */ static void t42(void) { ALLEGRO_USTR *us = al_ustr_new("abcdef"); /* Same size (ASCII). */ CHECK(al_ustr_set_chr(us, 1, 'B') == 1); CHECK(0 == strcmp(al_cstr(us), "aBcdef")); CHECK(6 == al_ustr_size(us)); /* Enlarge to 2-bytes. */ CHECK(al_ustr_set_chr(us, 1, U_beta) == 2); CHECK(0 == strcmp(al_cstr(us), "aβcdef")); CHECK(7 == al_ustr_size(us)); /* Enlarge to 3-bytes. */ CHECK(al_ustr_set_chr(us, 5, U_1d08) == 3); CHECK(0 == strcmp(al_cstr(us), "aβcdᴈf")); CHECK(9 == al_ustr_size(us)); /* Reduce to 2-bytes. */ CHECK(al_ustr_set_chr(us, 5, U_schwa) == 2); CHECK(0 == strcmp(al_cstr(us), "aβcdəf")); CHECK(8 == al_ustr_size(us)); /* Set at end of string. */ CHECK(al_ustr_set_chr(us, al_ustr_size(us), U_1ff7) == 3); CHECK(0 == strcmp(al_cstr(us), "aβcdəfῷ")); CHECK(11 == al_ustr_size(us)); /* Set past end of string. */ CHECK(al_ustr_set_chr(us, al_ustr_size(us) + 2, U_2051) == 3); CHECK(0 == memcmp(al_cstr(us), "aβcdəfῷ\0\0⁑", 16)); CHECK(16 == al_ustr_size(us)); /* Set before start of string (not allowed). */ CHECK(al_ustr_set_chr(us, -1, U_2051) == 0); CHECK(16 == al_ustr_size(us)); al_ustr_free(us); } /* Test al_ustr_remove_chr. */ static void t43(void) { ALLEGRO_USTR *us = al_ustr_new("«aβῷ»"); CHECK(al_ustr_remove_chr(us, 2)); CHECK(0 == strcmp(al_cstr(us), "«βῷ»")); CHECK(al_ustr_remove_chr(us, 2)); CHECK(0 == strcmp(al_cstr(us), "«ῷ»")); CHECK(al_ustr_remove_chr(us, 2)); CHECK(0 == strcmp(al_cstr(us), "«»")); /* Not at beginning of code point. */ CHECK(! al_ustr_remove_chr(us, 1)); /* Out of bounds. */ CHECK(! al_ustr_remove_chr(us, -1)); CHECK(! al_ustr_remove_chr(us, al_ustr_size(us))); al_ustr_free(us); } /* Test al_ustr_replace_range. */ static void t44(void) { ALLEGRO_USTR *us1 = al_ustr_new("Šis kungs par visu samaksās"); ALLEGRO_USTR *us2 = al_ustr_new("ī kundze"); CHECK(al_ustr_replace_range(us1, 2, 10, us2)); CHECK(0 == strcmp(al_cstr(us1), "Šī kundze par visu samaksās")); /* Insert into itself. */ CHECK(al_ustr_replace_range(us1, 5, 11, us1)); CHECK(0 == strcmp(al_cstr(us1), "Šī Šī kundze par visu samaksās par visu samaksās")); al_ustr_free(us1); al_ustr_free(us2); } /* Test al_ustr_replace_range (part 2). */ static void t45(void) { ALLEGRO_USTR *us1 = al_ustr_new("abcdef"); ALLEGRO_USTR *us2 = al_ustr_new("ABCDEF"); /* Start1 < 0 [not allowed] */ CHECK(! al_ustr_replace_range(us1, -1, 1, us2)); /* Start1 > end(us1) [padded] */ CHECK(al_ustr_replace_range(us1, 8, 100, us2)); CHECK(0 == memcmp(al_cstr(us1), "abcdef\0\0ABCDEF", 15)); /* Start1 > end1 [not allowed] */ CHECK(! al_ustr_replace_range(us1, 8, 1, us2)); CHECK(0 == memcmp(al_cstr(us1), "abcdef\0\0ABCDEF", 15)); al_ustr_free(us1); al_ustr_free(us2); } extern bool call_vappendf(ALLEGRO_USTR *us, const char *fmt, ...); /* Test al_ustr_newf, al_ustr_appendf, al_ustr_vappendf. */ static void t46(void) { ALLEGRO_USTR *us; us = al_ustr_newf("%s %c %.2f %.02d", "hõljuk", 'c', ALLEGRO_PI, 42); CHECK(0 == strcmp(al_cstr(us), "hõljuk c 3.14 42")); CHECK(al_ustr_appendf(us, " %s", "Luftchüssiboot")); CHECK(0 == strcmp(al_cstr(us), "hõljuk c 3.14 42 Luftchüssiboot")); CHECK(call_vappendf(us, " %s", "χόβερκράφτ")); CHECK(0 == strcmp(al_cstr(us), "hõljuk c 3.14 42 Luftchüssiboot χόβερκράφτ")); al_ustr_free(us); us = al_ustr_new(""); call_vappendf(us, "%s", "test"); CHECK(0 == strcmp(al_cstr(us), "test")); al_ustr_free(us); } bool call_vappendf(ALLEGRO_USTR *us, const char *fmt, ...) { va_list ap; bool rc; va_start(ap, fmt); rc = al_ustr_vappendf(us, fmt, ap); va_end(ap); return rc; } /* Test al_ustr_compare, al_ustr_ncompare. */ static void t47(void) { ALLEGRO_USTR_INFO i1; ALLEGRO_USTR_INFO i2; CHECK(al_ustr_compare( al_ref_cstr(&i1, "Thú mỏ vịt"), al_ref_cstr(&i2, "Thú mỏ vịt")) == 0); CHECK(al_ustr_compare( al_ref_cstr(&i1, "Thú mỏ vị"), al_ref_cstr(&i2, "Thú mỏ vịt")) < 0); CHECK(al_ustr_compare( al_ref_cstr(&i1, "Thú mỏ vịt"), al_ref_cstr(&i2, "Thú mỏ vit")) > 0); CHECK(al_ustr_compare( al_ref_cstr(&i1, "abc"), al_ref_cstr(&i2, "abc\001")) < 0); CHECK(al_ustr_compare( al_ref_cstr(&i1, "abc\001"), al_ref_cstr(&i2, "abc")) > 0); CHECK(al_ustr_ncompare( al_ref_cstr(&i1, "Thú mỏ vịt"), al_ref_cstr(&i2, "Thú mỏ vit"), 8) == 0); CHECK(al_ustr_ncompare( al_ref_cstr(&i1, "Thú mỏ vịt"), al_ref_cstr(&i2, "Thú mỏ vit"), 9) > 0); CHECK(al_ustr_ncompare( al_ref_cstr(&i1, "Thú mỏ vịt"), al_ref_cstr(&i2, "platypus"), 0) == 0); CHECK(al_ustr_ncompare( al_ref_cstr(&i1, "abc"), al_ref_cstr(&i2, "abc\001"), 4) < 0); CHECK(al_ustr_ncompare( al_ref_cstr(&i1, "abc\001"), al_ref_cstr(&i2, "abc"), 4) > 0); } /* Test al_ustr_has_prefix, al_ustr_has_suffix. */ static void t48(void) { ALLEGRO_USTR_INFO i1; const ALLEGRO_USTR *us1 = al_ref_cstr(&i1, "Thú mỏ vịt"); /* The _cstr versions are simple wrappers around the real functions so its * okay to test them only. */ CHECK(al_ustr_has_prefix_cstr(us1, "")); CHECK(al_ustr_has_prefix_cstr(us1, "Thú")); CHECK(! al_ustr_has_prefix_cstr(us1, "Thú mỏ vịt.")); CHECK(al_ustr_has_suffix_cstr(us1, "")); CHECK(al_ustr_has_suffix_cstr(us1, "vịt")); CHECK(! al_ustr_has_suffix_cstr(us1, "Thú mỏ vịt.")); } /* Test al_ustr_find_replace, al_ustr_find_replace_cstr. */ static void t49(void) { ALLEGRO_USTR *us; ALLEGRO_USTR_INFO findi; ALLEGRO_USTR_INFO repli; const ALLEGRO_USTR *find; const ALLEGRO_USTR *repl; us = al_ustr_new("aábdðeéfghiíaábdðeéfghií"); find = al_ref_cstr(&findi, "ðeéf"); repl = al_ref_cstr(&repli, "deef"); CHECK(al_ustr_find_replace(us, 0, find, repl)); CHECK(0 == strcmp(al_cstr(us), "aábddeefghiíaábddeefghií")); find = al_ref_cstr(&findi, "aá"); repl = al_ref_cstr(&repli, "AÁ"); CHECK(al_ustr_find_replace(us, 14, find, repl)); CHECK(0 == strcmp(al_cstr(us), "aábddeefghiíAÁbddeefghií")); CHECK(al_ustr_find_replace_cstr(us, 0, "dd", "đ")); CHECK(0 == strcmp(al_cstr(us), "aábđeefghiíAÁbđeefghií")); /* Not allowed */ find = al_ustr_empty_string(); CHECK(! al_ustr_find_replace(us, 0, find, repl)); CHECK(0 == strcmp(al_cstr(us), "aábđeefghiíAÁbđeefghií")); al_ustr_free(us); } /* Test UTF-16 conversion. */ static void t50(void) { ALLEGRO_USTR *us; char utf8[] = "⅛-note: 𝅘𝅥𝅮, domino: 🁡"; uint16_t *utf16; size_t s; uint16_t little[8]; /* Only native byte order supported right now, so have to specify * elements as uint16_t and not as char. */ uint16_t utf16_ref[] = { 0x215b, 0x002d, 0x006e, 0x006f, 0x0074, 0x0065, 0x003a, 0x0020, 0xd834, 0xdd60, 0x002c, 0x0020, 0x0064, 0x006f, 0x006d, 0x0069, 0x006e, 0x006f, 0x003a, 0x0020, 0xd83c, 0xdc61, 0x0000}; uint16_t truncated[] = { 0x215b, 0x002d, 0x006e, 0x006f, 0x0074, 0x0065, 0x003a, 0x0000}; us = al_ustr_new_from_utf16(utf16_ref); CHECK(20 == al_ustr_length(us)); CHECK(0 == strcmp(utf8, al_cstr(us))); al_ustr_free(us); us = al_ustr_new(utf8); s = al_ustr_size_utf16(us); CHECK(46 == s); utf16 = malloc(s); al_ustr_encode_utf16(us, utf16, s); CHECK(0 == memcmp(utf16, utf16_ref, s)); free(utf16); s = al_ustr_encode_utf16(us, little, sizeof little); CHECK(16 == s); CHECK(0 == memcmp(truncated, little, s)); al_ustr_free(us); } /* Test al_ustr_to_buffer */ static void t51(void) { char str[256]; const ALLEGRO_USTR *us; ALLEGRO_USTR_INFO info; us = al_ref_buffer(&info, "Allegro", 3); al_ustr_to_buffer(us, str, 10); CHECK(0 == memcmp(str, "All", 4)); al_ustr_to_buffer(us, str, 4); CHECK(0 == memcmp(str, "All", 4)); al_ustr_to_buffer(us, str, 3); CHECK(0 == memcmp(str, "Al", 3)); } /*---------------------------------------------------------------------------*/ const test_t all_tests[] = { NULL, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, t21, t22, t23, t24, t25, t26, t27, t28, t29, t30, t31, t32, t33, t34, t35, t36, t37, t38, t39, t40, t41, t42, t43, t44, t45, t46, t47, t48, t49, t50, t51 }; #define NUM_TESTS (int)(sizeof(all_tests) / sizeof(all_tests[0])) int main(int argc, char **argv) { int i; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log_monospace(); if (argc < 2) { for (i = 1; i < NUM_TESTS; i++) { log_printf("# t%d\n\n", i); all_tests[i](); log_printf("\n"); } } else { i = atoi(argv[1]); if (i > 0 && i < NUM_TESTS) { all_tests[i](); } } log_printf("Done\n"); close_log(true); if (error) { exit(EXIT_FAILURE); } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_vertex_buffer.c000066400000000000000000000154411473414355200210110ustar00rootroot00000000000000/* An example comparing different ways of drawing polygons, including usage of * vertex buffers. */ #include #include #include #include #include "common.c" #define FPS 60 #define FRAME_TAU 60 #define NUM_VERTICES 4096 typedef struct METHOD METHOD; struct METHOD { float x; float y; ALLEGRO_VERTEX_BUFFER *vbuff; ALLEGRO_VERTEX *vertices; const char *name; int flags; double frame_average; }; static ALLEGRO_COLOR get_color(size_t ii) { double t = al_get_time(); double frac = (float)(ii) / NUM_VERTICES; #define THETA(period) ((t / (period) + frac) * 2 * ALLEGRO_PI) return al_map_rgb_f(sin(THETA(5.0)) / 2 + 1, cos(THETA(1.1)) / 2 + 1, sin(THETA(3.4) / 2) / 2 + 1); } static void draw_method(METHOD *md, ALLEGRO_FONT *font, ALLEGRO_VERTEX* new_vertices) { ALLEGRO_TRANSFORM t; double start_time; double new_fps; ALLEGRO_COLOR c; al_identity_transform(&t); al_translate_transform(&t, md->x, md->y); al_use_transform(&t); al_draw_textf(font, al_map_rgb_f(1, 1, 1), 0, -50, ALLEGRO_ALIGN_CENTRE, "%s%s", md->name, md->flags & ALLEGRO_PRIM_BUFFER_READWRITE ? "+read/write" : "+write-only"); start_time = al_get_time(); if (md->vbuff) { if (new_vertices) { void* lock_mem = al_lock_vertex_buffer(md->vbuff, 0, NUM_VERTICES, ALLEGRO_LOCK_WRITEONLY); memcpy(lock_mem, new_vertices, sizeof(ALLEGRO_VERTEX) * NUM_VERTICES); al_unlock_vertex_buffer(md->vbuff); } al_draw_vertex_buffer(md->vbuff, 0, 0, NUM_VERTICES, ALLEGRO_PRIM_TRIANGLE_STRIP); } else if (md->vertices) { al_draw_prim(md->vertices, 0, 0, 0, NUM_VERTICES, ALLEGRO_PRIM_TRIANGLE_STRIP); } /* Force the completion of the previous commands by reading from screen */ c = al_get_pixel(al_get_backbuffer(al_get_current_display()), 0, 0); (void)c; new_fps = 1.0 / (al_get_time() - start_time); md->frame_average += (new_fps - md->frame_average) / FRAME_TAU; if (md->vbuff || md->vertices) { al_draw_textf(font, al_map_rgb_f(1, 0, 0), 0, 0, ALLEGRO_ALIGN_CENTRE, "%.1e FPS", md->frame_average); } else { al_draw_text(font, al_map_rgb_f(1, 0, 0), 0, 0, ALLEGRO_ALIGN_CENTRE, "N/A"); } al_identity_transform(&t); al_use_transform(&t); } int main(int argc, char **argv) { ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_DISPLAY *display; ALLEGRO_FONT *font; int w = 640, h = 480; bool done = false; bool need_redraw = true; bool background = false; bool dynamic_buffers = false; size_t num_methods; int num_x = 3; int num_y = 3; int spacing_x = 200; int spacing_y = 150; size_t ii; ALLEGRO_VERTEX* vertices; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } al_init_font_addon(); al_init_primitives_addon(); #ifdef ALLEGRO_IPHONE al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW); #endif al_set_new_display_option(ALLEGRO_SUPPORTED_ORIENTATIONS, ALLEGRO_DISPLAY_ORIENTATION_ALL, ALLEGRO_SUGGEST); display = al_create_display(w, h); if (!display) { abort_example("Error creating display.\n"); } w = al_get_display_width(display); h = al_get_display_height(display); al_install_keyboard(); font = al_create_builtin_font(); timer = al_create_timer(1.0 / FPS); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(display)); vertices = al_malloc(sizeof(ALLEGRO_VERTEX) * NUM_VERTICES); al_calculate_arc(&vertices[0].x, sizeof(ALLEGRO_VERTEX), 0, 0, 80, 30, 0, 2 * ALLEGRO_PI, 10, NUM_VERTICES / 2); for (ii = 0; ii < NUM_VERTICES; ii++) { vertices[ii].z = 0; vertices[ii].color = get_color(ii); } { #define GETX(n) ((w - (num_x - 1) * spacing_x) / 2 + n * spacing_x) #define GETY(n) ((h - (num_y - 1) * spacing_y) / 2 + n * spacing_y) METHOD methods[] = { {GETX(1), GETY(0), 0, vertices, "No buffer", 0, 0}, {GETX(0), GETY(1), 0, 0, "STREAM", ALLEGRO_PRIM_BUFFER_STREAM | ALLEGRO_PRIM_BUFFER_READWRITE, 0}, {GETX(1), GETY(1), 0, 0, "STATIC", ALLEGRO_PRIM_BUFFER_STATIC | ALLEGRO_PRIM_BUFFER_READWRITE, 0}, {GETX(2), GETY(1), 0, 0, "DYNAMIC", ALLEGRO_PRIM_BUFFER_STREAM | ALLEGRO_PRIM_BUFFER_READWRITE, 0}, {GETX(0), GETY(2), 0, 0, "STREAM", ALLEGRO_PRIM_BUFFER_STREAM, 0}, {GETX(1), GETY(2), 0, 0, "STATIC", ALLEGRO_PRIM_BUFFER_STATIC, 0}, {GETX(2), GETY(2), 0, 0, "DYNAMIC", ALLEGRO_PRIM_BUFFER_DYNAMIC, 0} }; num_methods = sizeof(methods) / sizeof(METHOD); for (ii = 0; ii < num_methods; ii++) { METHOD* md = &methods[ii]; md->frame_average = 1; if (!md->vertices) md->vbuff = al_create_vertex_buffer(0, vertices, NUM_VERTICES, md->flags); } al_start_timer(timer); while (!done) { ALLEGRO_EVENT event; if (!background && need_redraw && al_is_event_queue_empty(queue)) { al_clear_to_color(al_map_rgb_f(0, 0, 0.2)); for (ii = 0; ii < num_methods; ii++) draw_method(&methods[ii], font, dynamic_buffers ? vertices : 0); al_draw_textf(font, al_map_rgb_f(1, 1, 1), 10, 10, 0, "Dynamic (D): %s", dynamic_buffers ? "yes" : "no"); al_flip_display(); need_redraw = false; } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; else if(event.keyboard.keycode == ALLEGRO_KEY_D) dynamic_buffers = !dynamic_buffers; break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING: background = true; al_acknowledge_drawing_halt(event.display.source); break; case ALLEGRO_EVENT_DISPLAY_RESIZE: al_acknowledge_resize(event.display.source); break; case ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING: background = false; break; case ALLEGRO_EVENT_TIMER: for (ii = 0; ii < NUM_VERTICES; ii++) vertices[ii].color = get_color(ii); need_redraw = true; break; } } for (ii = 0; ii < num_methods; ii++) al_destroy_vertex_buffer(methods[ii].vbuff); al_destroy_font(font); al_free(vertices); } return 0; } allegro5-5.2.10.1/examples/ex_video.c000066400000000000000000000172111473414355200172460ustar00rootroot00000000000000#include #include #include #include #include #include #include "common.c" static ALLEGRO_DISPLAY *screen; static ALLEGRO_FONT *font; static char const *filename; static float zoom = 0; static void video_display(ALLEGRO_VIDEO *video) { /* Videos often do not use square pixels - these return the scaled dimensions * of the video frame. */ float scaled_w = al_get_video_scaled_width(video); float scaled_h = al_get_video_scaled_height(video); /* Get the currently visible frame of the video, based on clock * time. */ ALLEGRO_BITMAP *frame = al_get_video_frame(video); int w, h, x, y; ALLEGRO_COLOR tc = al_map_rgba_f(0, 0, 0, 0.5); ALLEGRO_COLOR bc = al_map_rgba_f(0.5, 0.5, 0.5, 0.5); double p; if (!frame) return; if (zoom == 0) { /* Always make the video fit into the window. */ h = al_get_display_height(screen); w = (int)(h * scaled_w / scaled_h); if (w > al_get_display_width(screen)) { w = al_get_display_width(screen); h = (int)(w * scaled_h / scaled_w); } } else { w = (int)scaled_w; h = (int)scaled_h; } x = (al_get_display_width(screen) - w) / 2; y = (al_get_display_height(screen) - h) / 2; /* Display the frame. */ al_draw_scaled_bitmap(frame, 0, 0, al_get_bitmap_width(frame), al_get_bitmap_height(frame), x, y, w, h, 0); /* Show some video information. */ al_draw_filled_rounded_rectangle(4, 4, al_get_display_width(screen) - 4, 4 + 14 * 4, 8, 8, bc); p = al_get_video_position(video, ALLEGRO_VIDEO_POSITION_ACTUAL); al_draw_textf(font, tc, 8, 8 , 0, "%s", filename); al_draw_textf(font, tc, 8, 8 + 13, 0, "%3d:%02d (V: %+5.2f A: %+5.2f)", (int)(p / 60), ((int)p) % 60, al_get_video_position(video, ALLEGRO_VIDEO_POSITION_VIDEO_DECODE) - p, al_get_video_position(video, ALLEGRO_VIDEO_POSITION_AUDIO_DECODE) - p); al_draw_textf(font, tc, 8, 8 + 13 * 2, 0, "video rate %.02f (%dx%d, aspect %.1f) audio rate %.0f", al_get_video_fps(video), al_get_bitmap_width(frame), al_get_bitmap_height(frame), scaled_w / scaled_h, al_get_video_audio_rate(video)); al_draw_textf(font, tc, 8, 8 + 13 * 3, 0, "playing: %s", al_is_video_playing(video) ? "true" : "false"); al_flip_display(); al_clear_to_color(al_map_rgb(0, 0, 0)); } int main(int argc, char *argv[]) { ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; ALLEGRO_TIMER *timer; ALLEGRO_VIDEO *video; bool fullscreen = false; bool redraw = true; bool use_frame_events = false; int filename_arg_idx = 1; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); if (argc < 2) { log_printf("This example needs to be run from the command line.\n" "Usage: %s [--use-frame-events] \n", argv[0]); goto done; } /* If use_frame_events is false, we use a fixed FPS timer. If the video is * displayed in a game this probably makes most sense. In a * dedicated video player you probably want to listen to * ALLEGRO_EVENT_VIDEO_FRAME_SHOW events and only redraw whenever one * arrives - to reduce possible jitter and save CPU. */ if (argc == 3 && strcmp(argv[1], "--use-frame-events") == 0) { use_frame_events = true; filename_arg_idx++; } if (!al_init_video_addon()) { abort_example("Could not initialize the video addon.\n"); } al_init_font_addon(); al_install_keyboard(); al_install_audio(); al_reserve_samples(1); al_init_primitives_addon(); timer = al_create_timer(1.0 / 60); al_set_new_display_flags(ALLEGRO_RESIZABLE); al_set_new_display_option(ALLEGRO_VSYNC, 1, ALLEGRO_SUGGEST); screen = al_create_display(640, 480); if (!screen) { abort_example("Could not set video mode - exiting\n"); } font = al_create_builtin_font(); if (!font) { abort_example("No font.\n"); } al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); filename = argv[filename_arg_idx]; video = al_open_video(filename); if (!video) { abort_example("Cannot read %s.\n", filename); } log_printf("video FPS: %f\n", al_get_video_fps(video)); log_printf("video audio rate: %f\n", al_get_video_audio_rate(video)); log_printf( "keys:\n" "Space: Play/Pause\n" "cursor right/left: seek 10 seconds\n" "cursor up/down: seek one minute\n" "F: toggle fullscreen\n" "1: disable scaling\n" "S: scale to window\n"); queue = al_create_event_queue(); al_register_event_source(queue, al_get_video_event_source(video)); al_register_event_source(queue, al_get_display_event_source(screen)); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_keyboard_event_source()); al_start_video(video, al_get_default_mixer()); al_start_timer(timer); for (;;) { double incr; if (redraw && al_event_queue_is_empty(queue)) { video_display(video); redraw = false; } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_DOWN: switch (event.keyboard.keycode) { case ALLEGRO_KEY_SPACE: al_set_video_playing(video, !al_is_video_playing(video)); break; case ALLEGRO_KEY_ESCAPE: al_close_video(video); goto done; break; case ALLEGRO_KEY_LEFT: incr = -10.0; goto do_seek; case ALLEGRO_KEY_RIGHT: incr = 10.0; goto do_seek; case ALLEGRO_KEY_UP: incr = 60.0; goto do_seek; case ALLEGRO_KEY_DOWN: incr = -60.0; goto do_seek; do_seek: al_seek_video(video, al_get_video_position(video, ALLEGRO_VIDEO_POSITION_ACTUAL) + incr); break; case ALLEGRO_KEY_F: fullscreen = !fullscreen; al_set_display_flag(screen, ALLEGRO_FULLSCREEN_WINDOW, fullscreen); break; case ALLEGRO_KEY_1: zoom = 1; break; case ALLEGRO_KEY_S: zoom = 0; break; default: break; } break; case ALLEGRO_EVENT_DISPLAY_RESIZE: al_acknowledge_resize(screen); al_clear_to_color(al_map_rgb(0, 0, 0)); break; case ALLEGRO_EVENT_TIMER: /* display_time += 1.0 / 60; if (display_time >= video_time) { video_time = display_time + video_refresh_timer(is); }*/ if (!use_frame_events) { redraw = true; } break; case ALLEGRO_EVENT_DISPLAY_CLOSE: al_close_video(video); goto done; break; case ALLEGRO_EVENT_VIDEO_FRAME_SHOW: if (use_frame_events) { redraw = true; } break; case ALLEGRO_EVENT_VIDEO_FINISHED: log_printf("video finished\n"); break; default: break; } } done: al_destroy_display(screen); close_log(true); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_vsync.c000066400000000000000000000142051473414355200173020ustar00rootroot00000000000000/* Tests vsync. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_primitives.h" #include "common.c" int vsync, fullscreen, frequency, bar_width; static int option(ALLEGRO_CONFIG *config, char *name, int v) { char const *value; char str[256]; value = al_get_config_value(config, "settings", name); if (value) v = strtol(value, NULL, 0); sprintf(str, "%d", v); al_set_config_value(config, "settings", name, str); return v; } static bool display_warning(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_FONT *font) { ALLEGRO_EVENT event; ALLEGRO_DISPLAY *display = al_get_current_display(); float x = al_get_display_width(display) / 2.0; float h = al_get_font_line_height(font); ALLEGRO_COLOR white = al_map_rgb_f(1, 1, 1); for (;;) { // Convert from 200 px on 480px high screen to same relative position // gtiven actual display height. float y = 5/12.0 * al_get_display_height(display); al_clear_to_color(al_map_rgb(0, 0, 0)); al_draw_text(font, white, x, y, ALLEGRO_ALIGN_CENTRE, "Do not continue if you suffer from photosensitive epilepsy"); al_draw_text(font, white, x, y + 15, ALLEGRO_ALIGN_CENTRE, "or simply hate sliding bars."); al_draw_text(font, white, x, y + 40, ALLEGRO_ALIGN_CENTRE, "Press Escape to quit or Enter to continue."); y += 100; al_draw_text(font, white, x, y, ALLEGRO_ALIGN_CENTRE, "Parameters from ex_vsync.ini:"); y += h; al_draw_textf(font, white, x, y, ALLEGRO_ALIGN_CENTRE, "vsync: %d", vsync); y += h; al_draw_textf(font, white, x, y, ALLEGRO_ALIGN_CENTRE, "fullscreen: %d", fullscreen); y += h; al_draw_textf(font, white, x, y, ALLEGRO_ALIGN_CENTRE, "frequency: %d", frequency); y += h; al_draw_textf(font, white, x, y, ALLEGRO_ALIGN_CENTRE, "bar width: %d", bar_width); al_flip_display(); al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { return true; } if (event.keyboard.keycode == ALLEGRO_KEY_ENTER) { return false; } } if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { return true; } } } int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_FONT *font; ALLEGRO_CONFIG *config; ALLEGRO_EVENT_QUEUE *queue; bool write = false; bool quit; bool right = true; int bar_position = 0; int step_size = 3; int display_width; int display_height; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_init_font_addon(); al_init_primitives_addon(); al_init_image_addon(); al_install_keyboard(); al_install_mouse(); /* Read parameters from ex_vsync.ini. */ config = al_load_config_file("ex_vsync.ini"); if (!config) { config = al_create_config(); write = true; } /* 0 -> Driver chooses. * 1 -> Force vsync on. * 2 -> Force vsync off. */ vsync = option(config, "vsync", 0); fullscreen = option(config, "fullscreen", 0); frequency = option(config, "frequency", 0); bar_width = option(config, "bar_width", 10); /* Write the file back (so a template is generated on first run). */ if (write) { al_save_config_file("ex_vsync.ini", config); } al_destroy_config(config); /* Vsync 1 means force on, 2 means forced off. */ if (vsync) al_set_new_display_option(ALLEGRO_VSYNC, vsync, ALLEGRO_SUGGEST); /* Force fullscreen mode. */ if (fullscreen) { al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW); /* Set a monitor frequency. */ if (frequency) al_set_new_display_refresh_rate(frequency); } display = al_create_display(640, 480); if (!display) { abort_example("Error creating display.\n"); } font = al_load_font("data/a4_font.tga", 0, 0); if (!font) { abort_example("Failed to load a4_font.tga\n"); } queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_mouse_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); quit = display_warning(queue, font); al_flush_event_queue(queue); display_width = al_get_display_width(display); display_height = al_get_display_height(display); while (!quit) { ALLEGRO_EVENT event; /* With vsync, this will appear as a bar moving smoothly left to right. * Without vsync, it will appear that there are many bars moving left to right. * More importantly, if you view it in fullscreen, the slanting of the bar will * appear more exaggerated as it is now much taller. */ if (right) { bar_position += step_size; } else { bar_position -= step_size; } if (right && bar_position >= display_width - bar_width) { bar_position = display_width - bar_width; right = false; } else if (!right && bar_position <= 0) { bar_position = 0; right = true; } al_clear_to_color(al_map_rgb(0,0,0)); al_draw_filled_rectangle(bar_position, 0, bar_position + bar_width - 1, display_height - 1, al_map_rgb_f(1., 1., 1.)); al_flip_display(); while (al_get_next_event(queue, &event)) { switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: quit = true; break; case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) quit = true; } } /* Let's not go overboard and limit flipping at 1000 Hz. Without * this my system locks up and requires a hard reboot :P */ /* * Limiting this to 500hz so the bar doesn't move too fast. We're * no longer in epilepsy mode (I hope). */ al_rest(.002); } al_destroy_font(font); al_destroy_event_queue(queue); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_window_constraints.c000066400000000000000000000106241473414355200220770ustar00rootroot00000000000000/* * Test program for Allegro. * * Constrains the window to a minimum and or maximum. */ #include "allegro5/allegro.h" #include "allegro5/allegro_image.h" #include "allegro5/allegro_font.h" #include "common.c" int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *bmp; ALLEGRO_FONT *f; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_EVENT event; bool redraw; int min_w, min_h, max_w, max_h; int ret_min_w, ret_min_h, ret_max_w, ret_max_h; bool constr_min_w, constr_min_h, constr_max_w, constr_max_h; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); al_init_image_addon(); al_init_font_addon(); al_set_new_display_flags(ALLEGRO_RESIZABLE | ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(640, 480); if (!display) { abort_example("Unable to set any graphic mode\n"); } bmp = al_load_bitmap("data/mysha.pcx"); if (!bmp) { abort_example("Unable to load image\n"); } f = al_load_font("data/a4_font.tga", 0, 0); if (!f) { abort_example("Failed to load a4_font.tga\n"); } min_w = 640; min_h = 480; max_w = 800; max_h = 600; constr_min_w = constr_min_h = constr_max_w = constr_max_h = true; if (!al_set_window_constraints( display, constr_min_w ? min_w : 0, constr_min_h ? min_h : 0, constr_max_w ? max_w : 0, constr_max_h ? max_h : 0)) { abort_example("Unable to set window constraints.\n"); } al_apply_window_constraints(display, true); queue = al_create_event_queue(); al_register_event_source(queue, al_get_display_event_source(display)); al_register_event_source(queue, al_get_keyboard_event_source()); redraw = true; while (true) { if (redraw && al_is_event_queue_empty(queue)) { al_clear_to_color(al_map_rgb(255, 0, 0)); al_draw_scaled_bitmap(bmp, 0, 0, al_get_bitmap_width(bmp), al_get_bitmap_height(bmp), 0, 0, al_get_display_width(display), al_get_display_height(display), 0); /* Display screen resolution */ al_draw_textf(f, al_map_rgb(255, 255, 255), 0, 0, 0, "Resolution: %dx%d", al_get_display_width(display), al_get_display_height(display)); if (!al_get_window_constraints(display, &ret_min_w, &ret_min_h, &ret_max_w, &ret_max_h)) { abort_example("Unable to get window constraints\n"); } al_draw_textf(f, al_map_rgb(255, 255, 255), 0, al_get_font_line_height(f), 0, "Min Width: %d, Min Height: %d, Max Width: %d, Max Height: %d", ret_min_w, ret_min_h, ret_max_w, ret_max_h); al_draw_textf(f, al_map_rgb(255, 255, 255), 0, al_get_font_line_height(f) * 2,0, "Toggle Restriction: Min Width: Z, Min Height: X, Max Width: C, Max Height: V"); al_flip_display(); redraw = false; } al_wait_for_event(queue, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { al_acknowledge_resize(event.display.source); redraw = true; } if (event.type == ALLEGRO_EVENT_DISPLAY_EXPOSE) { redraw = true; } if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } else if (event.keyboard.keycode == ALLEGRO_KEY_Z) { constr_min_w = ! constr_min_w; } else if (event.keyboard.keycode == ALLEGRO_KEY_X) { constr_min_h = ! constr_min_h; } else if (event.keyboard.keycode == ALLEGRO_KEY_C) { constr_max_w = ! constr_max_w; } else if (event.keyboard.keycode == ALLEGRO_KEY_V) { constr_max_h = ! constr_max_h; } redraw = true; if (!al_set_window_constraints(display, constr_min_w ? min_w : 0, constr_min_h ? min_h : 0, constr_max_w ? max_w : 0, constr_max_h ? max_h : 0)) { abort_example("Unable to set window constraints.\n"); } al_apply_window_constraints(display, true); } if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } } al_destroy_bitmap(bmp); al_destroy_display(display); return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_window_maximized.c000066400000000000000000000124241473414355200215170ustar00rootroot00000000000000/* * ex_window_maximized.c - create the maximized, resizable window. * Press SPACE to change constraints. */ #include #include #include #include #include #include #include "common.c" #define DISPLAY_W 640 #define DISPLAY_H 480 /* comment out to use GTK backend */ /* #define USE_GTK */ static void draw_information(ALLEGRO_DISPLAY *display, ALLEGRO_FONT *font, ALLEGRO_COLOR color); static bool use_constraints; extern int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_FONT *font; bool done = false; bool redraw = true; use_constraints = true; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } if (!al_init_primitives_addon()) { abort_example("Failed to init primitives addon.\n"); } if (!al_init_image_addon()) { abort_example("Failed to init image addon.\n"); } if (!al_init_font_addon()) { abort_example("Failed to init font addon.\n"); } if (!al_init_native_dialog_addon()) { abort_example("Failed to init native dialog addon.\n"); } al_set_new_display_flags(ALLEGRO_WINDOWED #if defined(USE_GTK) && !defined(_WIN32) | ALLEGRO_GTK_TOPLEVEL #endif | ALLEGRO_RESIZABLE | ALLEGRO_MAXIMIZED | ALLEGRO_GENERATE_EXPOSE_EVENTS); /* creating really small display */ display = al_create_display(DISPLAY_W / 3, DISPLAY_H / 3); if (!display) { abort_example("Error creating display.\n"); } /* set lower limits for constraints only */ if(!al_set_window_constraints(display, DISPLAY_W / 2, DISPLAY_H / 2, 0, 0)) abort_example("Unable to set window constraints.\n"); al_apply_window_constraints(display, use_constraints); if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_display_event_source(display)); ALLEGRO_COLOR color_1 = al_map_rgb(255, 127, 0); ALLEGRO_COLOR color_2 = al_map_rgb(0, 255, 0); ALLEGRO_COLOR *color = &color_1; ALLEGRO_COLOR color_text = al_map_rgb(0, 0, 0); font = al_create_builtin_font(); while (!done) { ALLEGRO_EVENT event; if (redraw && al_is_event_queue_empty(queue)) { redraw = false; int x2 = al_get_display_width(display) - 10; int y2 = al_get_display_height(display) - 10; al_clear_to_color(al_map_rgb(0, 0, 0)); al_draw_filled_rectangle(10, 10, x2, y2, *color); draw_information(display, font, color_text); al_flip_display(); } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; break; case ALLEGRO_EVENT_KEY_UP: if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) { redraw = true; if (color == &color_1) { if (!al_set_window_constraints(display, 0, 0, DISPLAY_W, DISPLAY_H)) { abort_example("Unable to set window constraints.\n"); } color = &color_2; } else { if (!al_set_window_constraints(display, DISPLAY_W / 2, DISPLAY_H / 2, 0, 0)) { abort_example("Unable to set window constraints.\n"); } color = &color_1; } al_apply_window_constraints(display, use_constraints); } else if (event.keyboard.keycode == ALLEGRO_KEY_ENTER) { redraw = true; use_constraints = !use_constraints; al_apply_window_constraints(display, use_constraints); } break; case ALLEGRO_EVENT_DISPLAY_RESIZE: al_acknowledge_resize(event.display.source); redraw = true; break; case ALLEGRO_EVENT_DISPLAY_EXPOSE: redraw = true; break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; } /* switch (event.type) { */ } al_destroy_font(font); return 0; } static void draw_information(ALLEGRO_DISPLAY *display, ALLEGRO_FONT *font, ALLEGRO_COLOR color) { int min_w, min_h, max_w, max_h; al_draw_textf(font, color, 20, 20, 0, "Hotkeys:"); al_draw_textf(font, color, 30, 30, 0, "enabled/disable constraints: ENTER"); al_draw_textf(font, color, 30, 40, 0, "change constraints: SPACE"); al_draw_textf(font, color, 20, 50, 0, "Resolution: %dx%d", al_get_display_width(display), al_get_display_height(display)); if (al_get_window_constraints(display, &min_w, &min_h, &max_w, &max_h)) { al_draw_textf(font, color, 20, 60, 0, "Constraints: %s", use_constraints ? "Enabled" : "Disabled"); al_draw_textf(font, color, 20, 70, 0, "min_w = %d min_h = %d", min_w, min_h); al_draw_textf(font, color, 20, 80, 0, "max_w = %d max_h = %d", max_w, max_h); } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_window_title.c000066400000000000000000000051441473414355200206520ustar00rootroot00000000000000/* An example showing how to set the title of a window, by Beoran. */ #include #include #include #include "common.c" #define INTERVAL 1.0 float bmp_x = 200; float bmp_y = 200; float bmp_dx = 96; float bmp_dy = 96; int bmp_flag = 0; #define NEW_WINDOW_TITLE "A Custom Window Title. Press space to start changing it." #define TITLE_SIZE 256 int main(int argc, char **argv) { ALLEGRO_DISPLAY *display; ALLEGRO_TIMER *timer; ALLEGRO_EVENT_QUEUE *queue; ALLEGRO_FONT *font; int step = 0; const char *text; char title[TITLE_SIZE] = ""; bool done = false; bool redraw = true; (void)argc; (void)argv; if (!al_init()) { abort_example("Failed to init Allegro.\n"); } if (!al_init_image_addon()) { abort_example("Failed to init IIO addon.\n"); } al_init_font_addon(); init_platform_specific(); text = NEW_WINDOW_TITLE; al_set_new_window_title(NEW_WINDOW_TITLE); display = al_create_display(640, 480); if (!display) { abort_example("Error creating display.\n"); } if (!al_install_keyboard()) { abort_example("Error installing keyboard.\n"); } font = al_load_font("data/fixed_font.tga", 0, 0); if (!font) { abort_example("Error loading data/fixed_font.tga\n"); } text = al_get_new_window_title(); timer = al_create_timer(INTERVAL); queue = al_create_event_queue(); al_register_event_source(queue, al_get_keyboard_event_source()); al_register_event_source(queue, al_get_timer_event_source(timer)); al_register_event_source(queue, al_get_display_event_source(display)); while (!done) { ALLEGRO_EVENT event; if (redraw && al_is_event_queue_empty(queue)) { al_clear_to_color(al_map_rgb_f(0, 0, 0)); al_draw_text(font, al_map_rgba_f(1, 1, 1, 0.5), 0, 0, 0, text); al_flip_display(); redraw = false; } al_wait_for_event(queue, &event); switch (event.type) { case ALLEGRO_EVENT_KEY_DOWN: if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) done = true; else if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) al_start_timer(timer); break; case ALLEGRO_EVENT_DISPLAY_CLOSE: done = true; break; case ALLEGRO_EVENT_TIMER: redraw = true; step++; sprintf(title, "Title: %d", step); text = title; al_set_window_title(display, title); break; } } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/ex_windows.c000066400000000000000000000145571473414355200176440ustar00rootroot00000000000000#define ALLEGRO_UNSTABLE #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" #include #include #include "common.c" const int W = 400; const int H = 200; int main(int argc, char **argv) { ALLEGRO_DISPLAY *displays[2]; ALLEGRO_MONITOR_INFO *info; int adapter_count; int x, y; int jump_x[2], jump_y[2], jump_adapter[2]; ALLEGRO_FONT *myfont; ALLEGRO_EVENT_QUEUE *events; ALLEGRO_EVENT event; ALLEGRO_TIMER *timer; int i; (void)argc; (void)argv; srand(time(NULL)); if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_mouse(); al_install_keyboard(); al_init_font_addon(); open_log(); adapter_count = al_get_num_video_adapters(); if (adapter_count == 0) { abort_example("No adapters found!\n"); } info = malloc(adapter_count * sizeof(ALLEGRO_MONITOR_INFO)); for (i = 0; i < adapter_count; i++) { al_get_monitor_info(i, &info[i]); log_printf("Monitor %d: %d %d - %d %d\n", i, info[i].x1, info[i].y1, info[i].x2, info[i].y2); } // center the first window ALLEGRO_MONITOR_INFO init_info = info[0]; x = (init_info.x1 + init_info.x2 - W) / 2; y = (init_info.y1 + init_info.y2 - H) / 2; jump_x[0] = x; jump_y[0] = y; jump_adapter[0] = 0; al_set_new_window_position(x, y); al_set_new_window_title("Window 1"); al_set_new_display_flags(ALLEGRO_RESIZABLE); displays[0] = al_create_display(W, H); // use the default position for the second window jump_x[1] = INT_MAX; jump_y[1] = INT_MAX; jump_adapter[1] = 0; al_set_new_window_position(INT_MAX, INT_MAX); al_set_new_window_title("Window 2"); displays[1] = al_create_display(W, H); if (!displays[0] || !displays[1]) { abort_example("Could not create displays.\n"); } myfont = al_create_builtin_font(); timer = al_create_timer(1 / 60.); events = al_create_event_queue(); al_register_event_source(events, al_get_mouse_event_source()); al_register_event_source(events, al_get_display_event_source(displays[0])); al_register_event_source(events, al_get_display_event_source(displays[1])); al_register_event_source(events, al_get_timer_event_source(timer)); al_register_event_source(events, al_get_keyboard_event_source()); bool redraw = true; al_start_timer(timer); while (true) { if (al_is_event_queue_empty(events) && redraw) { for (i = 0; i < 2; i++) { int dx, dy, dw, dh; al_set_target_backbuffer(displays[i]); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); if (i == 0) al_clear_to_color(al_map_rgb(255, 0, 255)); else al_clear_to_color(al_map_rgb(155, 255, 0)); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); al_get_window_position(displays[i], &dx, &dy); dw = al_get_display_width(displays[i]); dh = al_get_display_height(displays[i]); al_draw_textf(myfont, al_map_rgb(0, 0, 0), dw / 2, dh / 2 - 30, ALLEGRO_ALIGN_CENTRE, "Location: %d %d (adapter %d)", dx, dy, al_get_display_adapter(displays[i])); if (jump_x[i] != INT_MAX && jump_y[i] != INT_MAX) { al_draw_textf(myfont, al_map_rgb(0, 0, 0), dw / 2, dh / 2 - 15, ALLEGRO_ALIGN_CENTRE, "Last jumped to: %d %d (adapter %d)", jump_x[i], jump_y[i], jump_adapter[i]); } else { al_draw_textf(myfont, al_map_rgb(0, 0, 0), dw / 2, dh / 2 - 15, ALLEGRO_ALIGN_CENTRE, "Last placed to default position (adapter %d)", jump_adapter[i]); } al_draw_textf(myfont, al_map_rgb(0, 0, 0), dw / 2, dh / 2 + 0, ALLEGRO_ALIGN_CENTRE, "Size: %dx%d", dw, dh); int bl = 0, bt = 0; bool b = al_get_window_borders(displays[i], &bl, &bt, NULL, NULL); if (b) al_draw_textf(myfont, al_map_rgb(0, 0, 0), dw / 2, dh / 2 + 15, ALLEGRO_ALIGN_CENTRE, "Borders: left=%d top=%d", bl, bt); else al_draw_textf(myfont, al_map_rgb(0, 0, 0), dw / 2, dh / 2 + 15, ALLEGRO_ALIGN_CENTRE, "Borders: unknown"); al_draw_textf(myfont, al_map_rgb(0, 0, 0), dw / 2, dh / 2 + 30, ALLEGRO_ALIGN_CENTRE, "Click left to jump!"); al_draw_textf(myfont, al_map_rgb(0, 0, 0), dw / 2, dh / 2 + 45, ALLEGRO_ALIGN_CENTRE, "Click right to swap!"); al_flip_display(); } redraw = false; } al_wait_for_event(events, &event); if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { if (event.mouse.button == 1) { int a = rand() % adapter_count; int w = info[a].x2 - info[a].x1; int h = info[a].y2 - info[a].y1; int margin = 20; int i = event.mouse.display == displays[0] ? 0 : 1; x = margin + info[a].x1 + (rand() % (w - W - 2 * margin)); y = margin + info[a].y1 + (rand() % (h - H - 2 * margin)); jump_x[i] = x; jump_y[i] = y; jump_adapter[i] = a; log_printf("moving window %d to %d/%d\n", 1 + i, x, y); al_set_window_position(event.mouse.display, x, y); } else { log_printf("swapping windows\n"); al_get_window_position(displays[0], jump_x + 1, jump_y + 1); al_get_window_position(displays[1], jump_x, jump_y); al_set_window_position(displays[0], jump_x[0], jump_y[0]); al_set_window_position(displays[1], jump_x[1], jump_y[1]); } } else if (event.type == ALLEGRO_EVENT_KEY_DOWN) { if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) { al_get_window_position(event.keyboard.display, &x, &y); int i = event.mouse.display == displays[0] ? 0 : 1; jump_x[i] = x; jump_y[i] = y; al_set_window_position(event.keyboard.display, x, y); } } else if (event.type == ALLEGRO_EVENT_TIMER) { redraw = true; } else if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { al_acknowledge_resize(event.display.source); } } al_destroy_event_queue(events); al_destroy_display(displays[0]); al_destroy_display(displays[1]); free(info); close_log(true); return 0; } allegro5-5.2.10.1/examples/ex_winfull.c000066400000000000000000000032121473414355200176140ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "common.c" int main(int argc, char **argv) { ALLEGRO_DISPLAY *win, *full; ALLEGRO_EVENT_QUEUE *events; ALLEGRO_EVENT event; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } al_install_keyboard(); if (al_get_num_video_adapters() < 2) { abort_example("This example requires multiple video adapters.\n"); } al_set_new_display_adapter(1); al_set_new_display_flags(ALLEGRO_WINDOWED); win = al_create_display(640, 480); if (!win) { abort_example("Error creating windowed display on adapter 1 " "(do you have multiple adapters?)\n"); } al_set_new_display_adapter(0); al_set_new_display_flags(ALLEGRO_FULLSCREEN); full = al_create_display(640, 480); if (!full) { abort_example("Error creating fullscreen display on adapter 0\n"); } events = al_create_event_queue(); al_register_event_source(events, al_get_keyboard_event_source()); while (1) { while (!al_is_event_queue_empty(events)) { al_get_next_event(events, &event); if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) goto done; } al_set_target_backbuffer(full); al_clear_to_color(al_map_rgb(rand()%255, rand()%255, rand()%255)); al_flip_display(); al_set_target_backbuffer(win); al_clear_to_color(al_map_rgb(rand()%255, rand()%255, rand()%255)); al_flip_display(); al_rest(0.5); } done: al_destroy_event_queue(events); al_destroy_display(win); al_destroy_display(full); return 0; } allegro5-5.2.10.1/examples/nihgui.cpp000066400000000000000000000461011473414355200172670ustar00rootroot00000000000000/* * This is a GUI for example programs that require GUI-style interaction. * It's intended to be as simple and transparent as possible (simplistic, * even). */ #include #include #include #define ALLEGRO_UNSTABLE #include #include #include #include "nihgui.hpp" #define CLAMP(x,y,z) (std::max)(x, (std::min)(y, z)) namespace { class SaveState { ALLEGRO_STATE state; public: SaveState(int save=ALLEGRO_STATE_ALL) { al_store_state(&state, save); } ~SaveState() { al_restore_state(&state); } }; class UString { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *ustr; public: UString(const ALLEGRO_USTR *s, int first, int end = -1) { if (end == -1) end = al_ustr_size(s); ustr = al_ref_ustr(&info, s, first, end); } // Conversion operator const ALLEGRO_USTR *() const { return ustr; } }; }; /*---------------------------------------------------------------------------*/ Theme::Theme(const ALLEGRO_FONT *font) { this->bg = al_map_rgb(255, 255, 255); this->fg = al_map_rgb(0, 0, 0); this->highlight = al_map_rgb(128, 128, 255); this->font = font; } /*---------------------------------------------------------------------------*/ Widget::Widget(): grid_x(0), grid_y(0), grid_w(0), grid_h(0), dialog(NULL), x1(0), y1(0), x2(0), y2(0), disabled(false) { } void Widget::configure(int xsize, int ysize, int x_padding, int y_padding) { this->x1 = xsize * this->grid_x + x_padding; this->y1 = ysize * this->grid_y + y_padding; this->x2 = xsize * (this->grid_x + this->grid_w) - x_padding - 1; this->y2 = ysize * (this->grid_y + this->grid_h) - y_padding - 1; } bool Widget::contains(int x, int y) { return (x >= this->x1 && y >= this->y1 && x <= this->x2 && y <= this->y2); } /*---------------------------------------------------------------------------*/ Dialog::Dialog(const Theme & theme, ALLEGRO_DISPLAY *display, int grid_m, int grid_n): theme(theme), display(display), grid_m(grid_m), grid_n(grid_n), x_padding(1), y_padding(1), draw_requested(true), quit_requested(false), mouse_over_widget(NULL), mouse_down_widget(NULL), key_widget(NULL), event_handler(NULL) { this->event_queue = al_create_event_queue(); al_register_event_source(this->event_queue, al_get_keyboard_event_source()); al_register_event_source(this->event_queue, al_get_mouse_event_source()); al_register_event_source(this->event_queue, al_get_display_event_source(display)); if (al_is_touch_input_installed()) { al_register_event_source(this->event_queue, al_get_touch_input_mouse_emulation_event_source()); } } Dialog::~Dialog() { this->display = NULL; al_destroy_event_queue(this->event_queue); this->event_queue = NULL; } void Dialog::set_padding(int x_padding, int y_padding) { this->x_padding = x_padding; this->y_padding = y_padding; } void Dialog::add(Widget & widget, int grid_x, int grid_y, int grid_w, int grid_h) { widget.grid_x = grid_x; widget.grid_y = grid_y; widget.grid_w = grid_w; widget.grid_h = grid_h; this->all_widgets.push_back(&widget); widget.dialog = this; } void Dialog::prepare() { this->configure_all(); /* XXX this isn't working right in X. The mouse position is reported as * (0,0) initially, until the mouse pointer is moved. */ ALLEGRO_MOUSE_STATE mst; al_get_mouse_state(&mst); this->check_mouse_over(mst.x, mst.y); } void Dialog::configure_all() { const int xsize = al_get_display_width(display) / this->grid_m; const int ysize = al_get_display_height(display) / this->grid_n; for (std::list::iterator it = this->all_widgets.begin(); it != this->all_widgets.end(); ++it) { (*it)->configure(xsize, ysize, this->x_padding, this->y_padding); } } void Dialog::run_step(bool block) { ALLEGRO_EVENT event; if (block) { al_wait_for_event(event_queue, NULL); } while (al_get_next_event(event_queue, &event)) { switch (event.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: this->request_quit(); break; case ALLEGRO_EVENT_KEY_CHAR: on_key_down(event.keyboard); break; case ALLEGRO_EVENT_MOUSE_AXES: on_mouse_axes(event.mouse); break; case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: on_mouse_button_down(event.mouse); break; case ALLEGRO_EVENT_MOUSE_BUTTON_UP: on_mouse_button_up(event.mouse); break; case ALLEGRO_EVENT_DISPLAY_EXPOSE: this->request_draw(); break; default: if (event_handler) { event_handler->handle_event(event); } break; } } } void Dialog::on_key_down(const ALLEGRO_KEYBOARD_EVENT & event) { if (event.display != this->display) { return; } // XXX think of something better when we need it if (event.keycode == ALLEGRO_KEY_ESCAPE) { this->request_quit(); } if (this->key_widget) { this->key_widget->on_key_down(event); } } void Dialog::on_mouse_axes(const ALLEGRO_MOUSE_EVENT & event) { const int mx = event.x; const int my = event.y; if (event.display != this->display) { return; } if (this->mouse_down_widget) { this->mouse_down_widget->on_mouse_button_hold(mx, my); return; } this->check_mouse_over(mx, my); } void Dialog::check_mouse_over(int mx, int my) { if (this->mouse_over_widget && this->mouse_over_widget->contains(mx, my)) { /* no change */ return; } for (std::list::iterator it = this->all_widgets.begin(); it != this->all_widgets.end(); ++it) { if ((*it)->contains(mx, my) && (*it)->want_mouse_focus()) { this->mouse_over_widget = (*it); this->mouse_over_widget->got_mouse_focus(); return; } } if (this->mouse_over_widget) { this->mouse_over_widget->lost_mouse_focus(); this->mouse_over_widget = NULL; } } void Dialog::on_mouse_button_down(const ALLEGRO_MOUSE_EVENT & event) { if (event.button != 1) return; /* With touch input we may not receive mouse axes event before the touch * so we must check which widget the touch is over. */ this->check_mouse_over(event.x, event.y); if (!this->mouse_over_widget) return; this->mouse_down_widget = this->mouse_over_widget; this->mouse_down_widget->on_mouse_button_down(event.x, event.y); /* transfer key focus */ if (this->mouse_down_widget != this->key_widget) { if (this->key_widget) { this->key_widget->lost_key_focus(); this->key_widget = NULL; } if (this->mouse_down_widget->want_key_focus()) { this->key_widget = this->mouse_down_widget; this->key_widget->got_key_focus(); } } } void Dialog::on_mouse_button_up(const ALLEGRO_MOUSE_EVENT & event) { if (event.button != 1) return; if (!this->mouse_down_widget) return; this->mouse_down_widget->on_mouse_button_up(event.x, event.y); if (this->mouse_down_widget->contains(event.x, event.y)) { this->mouse_down_widget->on_click(event.x, event.y); } this->mouse_down_widget = NULL; } void Dialog::request_quit() { this->quit_requested = true; } bool Dialog::is_quit_requested() const { return this->quit_requested; } void Dialog::request_draw() { this->draw_requested = true; } bool Dialog::is_draw_requested() const { return this->draw_requested; } void Dialog::draw() { int cx, cy, cw, ch; al_get_clipping_rectangle(&cx, &cy, &cw, &ch); for (std::list::iterator it = this->all_widgets.begin(); it != this->all_widgets.end(); ++it) { Widget *wid = (*it); al_set_clipping_rectangle(wid->x1, wid->y1, wid->width(), wid->height()); wid->draw(); } al_set_clipping_rectangle(cx, cy, cw, ch); this->draw_requested = false; } const Theme & Dialog::get_theme() const { return this->theme; } void Dialog::register_event_source(ALLEGRO_EVENT_SOURCE *source) { al_register_event_source(this->event_queue, source); } void Dialog::set_event_handler(EventHandler *event_handler) { this->event_handler = event_handler; } /*---------------------------------------------------------------------------*/ Label::Label(std::string text, bool centred) : text(text), centred(centred) { } void Label::draw() { const Theme & theme = this->dialog->get_theme(); SaveState state; ALLEGRO_COLOR fg = theme.fg; if (is_disabled()) { fg = al_map_rgb(64, 64, 64); } al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); if (centred) { al_draw_text(theme.font, fg, (this->x1 + this->x2 + 1)/2, this->y1, ALLEGRO_ALIGN_CENTRE, this->text.c_str()); } else { al_draw_text(theme.font, fg, this->x1, this->y1, 0, this->text.c_str()); } } void Label::set_text(std::string new_text) { this->text = new_text; } bool Label::want_mouse_focus() { return false; } /*---------------------------------------------------------------------------*/ Button::Button(std::string text): text(text), pushed(false) { } void Button::on_mouse_button_down(int mx, int my) { (void)mx; (void)my; if (is_disabled()) return; this->pushed = true; dialog->request_draw(); } void Button::on_mouse_button_up(int mx, int my) { (void)mx; (void)my; if (is_disabled()) return; this->pushed = false; dialog->request_draw(); } void Button::draw() { const Theme & theme = this->dialog->get_theme(); ALLEGRO_COLOR fg; ALLEGRO_COLOR bg; SaveState state; double y; if (this->pushed) { fg = theme.bg; bg = theme.fg; } else { fg = theme.fg; bg = theme.bg; } if (is_disabled()) { bg = al_map_rgb(64, 64, 64); } al_draw_filled_rectangle(this->x1, this->y1, this->x2, this->y2, bg); al_draw_rectangle(this->x1 + 0.5, this->y1 + 0.5, this->x2 - 0.5, this->y2 - 0.5, fg, 0); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); /* Center the text vertically in the button, taking the font size * into consideration. */ y = (this->y1 + this->y2 - al_get_font_line_height(theme.font) - 1) / 2; al_draw_text(theme.font, fg, (this->x1 + this->x2 + 1)/2, y, ALLEGRO_ALIGN_CENTRE, this->text.c_str()); } bool Button::get_pushed() { return pushed; } /*---------------------------------------------------------------------------*/ ToggleButton::ToggleButton(std::string text) : Button(text) { } void ToggleButton::on_mouse_button_down(int mx, int my) { (void)mx; (void)my; if (is_disabled()) return; set_pushed(!this->pushed); } void ToggleButton::on_mouse_button_up(int mx, int my) { (void)mx; (void)my; if (is_disabled()) return; } void ToggleButton::set_pushed(bool pushed) { if (this->pushed != pushed) { this->pushed = pushed; if (dialog) dialog->request_draw(); } } /*---------------------------------------------------------------------------*/ const std::string List::empty_string; List::List(int initial_selection) : selected_item(initial_selection) { } bool List::want_key_focus() { return !is_disabled(); } void List::on_key_down(const ALLEGRO_KEYBOARD_EVENT & event) { if (is_disabled()) return; switch (event.keycode) { case ALLEGRO_KEY_DOWN: if (selected_item < items.size() - 1) { selected_item++; dialog->request_draw(); } break; case ALLEGRO_KEY_UP: if (selected_item > 0) { selected_item--; dialog->request_draw(); } break; } } void List::on_click(int mx, int my) { if (is_disabled()) return; const Theme & theme = dialog->get_theme(); unsigned int i = (my - this->y1) / al_get_font_line_height(theme.font); if (i < this->items.size()) { this->selected_item = i; dialog->request_draw(); } (void)mx; (void)my; } void List::draw() { const Theme & theme = dialog->get_theme(); SaveState state; ALLEGRO_COLOR bg = theme.bg; if (is_disabled()) { bg = al_map_rgb(64, 64, 64); } al_draw_filled_rectangle(x1 + 1, y1 + 1, x2 - 1, y2 - 1, bg); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); const int font_height = al_get_font_line_height(theme.font); for (unsigned i = 0; i < items.size(); i++) { int yi = y1 + i * font_height; if (i == selected_item) { al_draw_filled_rectangle(x1 + 1, yi, x2 - 1, yi + font_height - 1, theme.highlight); } al_draw_text(theme.font, theme.fg, x1, yi, 0, items.at(i).c_str()); } } void List::clear_items() { this->items.clear(); this->selected_item = 0; } void List::append_item(std::string text) { this->items.push_back(text); } const std::string & List::get_selected_item_text() const { if (this->selected_item < this->items.size()) return this->items.at(this->selected_item); else return List::empty_string; } int List::get_cur_value() const { return this->selected_item; } /*---------------------------------------------------------------------------*/ VSlider::VSlider(int cur_value, int max_value) : cur_value(cur_value), max_value(max_value) { } void VSlider::on_mouse_button_down(int mx, int my) { if (is_disabled()) return; this->on_mouse_button_hold(mx, my); } void VSlider::on_mouse_button_hold(int mx, int my) { if (is_disabled()) return; double r = (double) (this->y2 - 1 - my) / (this->height() - 2); r = CLAMP(0.0, r, 1.0); cur_value = (int) (r * max_value); dialog->request_draw(); (void)mx; } void VSlider::draw() { const Theme & theme = dialog->get_theme(); ALLEGRO_COLOR bg = theme.fg; float left = x1 + 0.5, top = y1 + 0.5; float right = x2 + 0.5, bottom = y2 + 0.5; SaveState state; if (is_disabled()) { bg = al_map_rgb(64, 64, 64); } al_draw_rectangle(left, top, right, bottom, bg, 1); double ratio = (double) this->cur_value / (double) this->max_value; int ypos = (int) (bottom - 0.5 - (int) (ratio * (height() - 7))); al_draw_filled_rectangle(left + 0.5, ypos - 5, right - 0.5, ypos, theme.fg); } int VSlider::get_cur_value() const { return this->cur_value; } int VSlider::get_max_value() const { return this->max_value; } void VSlider::set_cur_value(int v) { this->cur_value = v; } /*---------------------------------------------------------------------------*/ HSlider::HSlider(int cur_value, int max_value) : cur_value(cur_value), max_value(max_value) { } void HSlider::on_mouse_button_down(int mx, int my) { if (is_disabled()) return; this->on_mouse_button_hold(mx, my); } void HSlider::on_mouse_button_hold(int mx, int my) { if (is_disabled()) return; double r = (double) (mx - 1 - this->x1) / (this->width() - 2); r = CLAMP(0.0, r, 1.0); cur_value = (int) (r * max_value); dialog->request_draw(); (void)my; } void HSlider::draw() { const Theme & theme = dialog->get_theme(); const int cy = (y1 + y2) / 2; SaveState state; ALLEGRO_COLOR bg = theme.bg; if (is_disabled()) { bg = al_map_rgb(64, 64, 64); } al_draw_filled_rectangle(x1, y1, x2, y2, bg); al_draw_line(x1, cy, x2, cy, theme.fg, 0); double ratio = (double) this->cur_value / (double) this->max_value; int xpos = x1 + (int) (ratio * (width() - 2)); al_draw_filled_rectangle(xpos - 2, y1, xpos + 2, y2, theme.fg); } int HSlider::get_cur_value() const { return this->cur_value; } int HSlider::get_max_value() const { return this->max_value; } void HSlider::set_cur_value(int v) { this->cur_value = v; } /*---------------------------------------------------------------------------*/ TextEntry::TextEntry(const char *initial_text) : focused(false), cursor_pos(0), left_pos(0) { text = al_ustr_new(initial_text); } TextEntry::~TextEntry() { al_ustr_free(text); } bool TextEntry::want_key_focus() { return !is_disabled(); } void TextEntry::got_key_focus() { this->focused = true; dialog->request_draw(); } void TextEntry::lost_key_focus() { this->focused = false; dialog->request_draw(); } void TextEntry::on_key_down(const ALLEGRO_KEYBOARD_EVENT & event) { if (is_disabled()) return; switch (event.keycode) { case ALLEGRO_KEY_LEFT: al_ustr_prev(text, &cursor_pos); break; case ALLEGRO_KEY_RIGHT: al_ustr_next(text, &cursor_pos); break; case ALLEGRO_KEY_HOME: cursor_pos = 0; break; case ALLEGRO_KEY_END: cursor_pos = al_ustr_size(text); break; case ALLEGRO_KEY_DELETE: al_ustr_remove_chr(text, cursor_pos); break; case ALLEGRO_KEY_BACKSPACE: if (al_ustr_prev(text, &cursor_pos)) al_ustr_remove_chr(text, cursor_pos); break; default: if (event.unichar >= ' ') { al_ustr_insert_chr(text, cursor_pos, event.unichar); cursor_pos += al_utf8_width(event.unichar); } break; } maybe_scroll(); dialog->request_draw(); } void TextEntry::maybe_scroll() { const Theme & theme = dialog->get_theme(); if (cursor_pos < left_pos + 3) { if (cursor_pos < 3) left_pos = 0; else left_pos = cursor_pos - 3; } else { for (;;) { const int tw = al_get_ustr_width(theme.font, UString(text, left_pos, cursor_pos)); if (x1 + tw + CURSOR_WIDTH < x2) { break; } al_ustr_next(text, &left_pos); } } } void TextEntry::draw() { const Theme & theme = dialog->get_theme(); SaveState state; ALLEGRO_COLOR bg = theme.bg; if (is_disabled()) { bg = al_map_rgb(64, 64, 64); } al_draw_filled_rectangle(x1, y1, x2, y2, bg); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); if (!focused) { al_draw_ustr(theme.font, theme.fg, x1, y1, 0, UString(text, left_pos)); } else { int x = x1; if (cursor_pos > 0) { UString sub(text, left_pos, cursor_pos); al_draw_ustr(theme.font, theme.fg, x1, y1, 0, sub); x += al_get_ustr_width(theme.font, sub); } if ((unsigned) cursor_pos == al_ustr_size(text)) { al_draw_filled_rectangle(x, y1, x + CURSOR_WIDTH, y1 + al_get_font_line_height(theme.font), theme.fg); } else { int post_cursor = cursor_pos; al_ustr_next(text, &post_cursor); UString sub(text, cursor_pos, post_cursor); int subw = al_get_ustr_width(theme.font, sub); al_draw_filled_rectangle(x, y1, x + subw, y1 + al_get_font_line_height(theme.font), theme.fg); al_draw_ustr(theme.font, theme.bg, x, y1, 0, sub); x += subw; al_draw_ustr(theme.font, theme.fg, x, y1, 0, UString(text, post_cursor)); } } } const char *TextEntry::get_text() { return al_cstr(text); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/examples/nihgui.hpp000066400000000000000000000144701473414355200173000ustar00rootroot00000000000000#ifndef __included_nihgui_hpp #define __included_nihgui_hpp #include #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_font.h" class Theme; class Dialog; class Widget; class Theme { public: ALLEGRO_COLOR bg; ALLEGRO_COLOR fg; ALLEGRO_COLOR highlight; const ALLEGRO_FONT *font; // Null font is fine if you don't use a widget that requires text. explicit Theme(const ALLEGRO_FONT *font=NULL); }; class Widget { private: int grid_x; int grid_y; int grid_w; int grid_h; protected: Dialog *dialog; int x1; int y1; int x2; int y2; bool disabled; public: Widget(); virtual ~Widget() {} void configure(int xsize, int ysize, int x_padding, int y_padding); virtual bool contains(int x, int y); unsigned int width() { return x2 - x1 + 1; } unsigned int height() { return y2 - y1 + 1; } virtual bool want_mouse_focus() { return true; } virtual void got_mouse_focus() {} virtual void lost_mouse_focus() {} virtual void on_mouse_button_down(int mx, int my) { (void)mx; (void)my; } virtual void on_mouse_button_hold(int mx, int my) { (void)mx; (void)my; } virtual void on_mouse_button_up(int mx, int my) { (void)mx; (void)my; } virtual void on_click(int mx, int my) { (void)mx; (void)my; } virtual bool want_key_focus() { return false; } virtual void got_key_focus() {} virtual void lost_key_focus() {} virtual void on_key_down(const ALLEGRO_KEYBOARD_EVENT & event) { (void)event; } virtual void draw() = 0; virtual void set_disabled(bool value) { disabled = value; } virtual bool is_disabled() { return disabled; } friend class Dialog; }; class EventHandler { public: virtual ~EventHandler() {} virtual void handle_event(const ALLEGRO_EVENT & event) = 0; }; class Dialog { private: const Theme & theme; ALLEGRO_DISPLAY * display; ALLEGRO_EVENT_QUEUE *event_queue; int grid_m; int grid_n; int x_padding; int y_padding; bool draw_requested; bool quit_requested; std::list all_widgets; Widget * mouse_over_widget; Widget * mouse_down_widget; Widget * key_widget; EventHandler * event_handler; public: Dialog(const Theme & theme, ALLEGRO_DISPLAY *display, int grid_m, int grid_n); ~Dialog(); void set_padding(int x_padding, int y_padding); void add(Widget & widget, int grid_x, int grid_y, int grid_w, int grid_h); void prepare(); void run_step(bool block); void request_quit(); bool is_quit_requested() const; void request_draw(); bool is_draw_requested() const; void draw(); const Theme & get_theme() const; void register_event_source(ALLEGRO_EVENT_SOURCE *source); void set_event_handler(EventHandler *handler); private: void configure_all(); void on_key_down(const ALLEGRO_KEYBOARD_EVENT & event); void on_mouse_axes(const ALLEGRO_MOUSE_EVENT & event); void check_mouse_over(int mx, int my); void on_mouse_button_down(const ALLEGRO_MOUSE_EVENT & event); void on_mouse_button_up(const ALLEGRO_MOUSE_EVENT & event); }; /*---------------------------------------------------------------------------*/ class Label : public Widget { private: std::string text; bool centred; public: Label(std::string text="", bool centred=true); void set_text(std::string text); virtual void draw(); virtual bool want_mouse_focus(); }; class Button : public Widget { protected: std::string text; bool pushed; public: explicit Button(std::string text); virtual void on_mouse_button_down(int mx, int my); virtual void on_mouse_button_up(int mx, int my); virtual void draw(); bool get_pushed(); }; class ToggleButton : public Button { public: explicit ToggleButton(std::string text); virtual void on_mouse_button_down(int mx, int my); virtual void on_mouse_button_up(int mx, int my); void set_pushed(bool pushed); }; class List : public Widget { private: static const std::string empty_string; std::vector items; unsigned int selected_item; public: List(int initial_selection = 0); virtual bool want_key_focus(); virtual void on_key_down(const ALLEGRO_KEYBOARD_EVENT & event); virtual void on_click(int mx, int my); virtual void draw(); void clear_items(); void append_item(std::string text); const std::string & get_selected_item_text() const; int get_cur_value() const; }; class VSlider : public Widget { private: int cur_value; int max_value; public: VSlider(int cur_value = 0, int max_value = 1); virtual void on_mouse_button_down(int mx, int my); virtual void on_mouse_button_hold(int mx, int my); virtual void draw(); int get_max_value() const; int get_cur_value() const; void set_cur_value(int v); }; class HSlider : public Widget { private: int cur_value; int max_value; public: HSlider(int cur_value = 0, int max_value = 1); virtual void on_mouse_button_down(int mx, int my); virtual void on_mouse_button_hold(int mx, int my); virtual void draw(); int get_max_value() const; int get_cur_value() const; void set_cur_value(int v); }; class TextEntry : public Widget { private: static const int CURSOR_WIDTH = 8; ALLEGRO_USTR *text; bool focused; int cursor_pos; int left_pos; public: explicit TextEntry(const char *initial_text=""); ~TextEntry(); virtual bool want_key_focus(); virtual void got_key_focus(); virtual void lost_key_focus(); virtual void on_key_down(const ALLEGRO_KEYBOARD_EVENT & event); virtual void draw(); const char * get_text(); private: void maybe_scroll(); }; #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/000077500000000000000000000000001473414355200151035ustar00rootroot00000000000000allegro5-5.2.10.1/include/allegro5/000077500000000000000000000000001473414355200166155ustar00rootroot00000000000000allegro5-5.2.10.1/include/allegro5/alcompat.h000066400000000000000000000011501473414355200205630ustar00rootroot00000000000000#ifndef __al_included_allegro5_alcompat_h #define __al_included_allegro5_alcompat_h #ifdef __cplusplus extern "C" { #endif #define ALLEGRO_DST_COLOR (ALLEGRO_DEST_COLOR) #define ALLEGRO_INVERSE_DST_COLOR (ALLEGRO_INVERSE_DEST_COLOR) #define al_convert_bitmaps() (al_convert_memory_bitmaps()) #define al_current_time() (al_get_time()) #define al_event_queue_is_empty(q) (al_is_event_queue_empty(q)) #define al_toggle_display_flag(d, f, o) (al_set_display_flag((d), (f), (o))) #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/allegro.h000066400000000000000000000041731473414355200204200ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Main header file for the entire Allegro library. * (separate modules can be included from the allegro/ directory) * * By Shawn Hargreaves. * * Vincent Penquerc'h split the original allegro.h into separate headers. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_allegro_h #define __al_included_allegro5_allegro_h #include "allegro5/base.h" #include "allegro5/altime.h" #include "allegro5/bitmap.h" #include "allegro5/bitmap_draw.h" #include "allegro5/bitmap_io.h" #include "allegro5/bitmap_lock.h" #include "allegro5/blender.h" #include "allegro5/clipboard.h" #include "allegro5/color.h" #include "allegro5/config.h" #include "allegro5/cpu.h" #include "allegro5/debug.h" #include "allegro5/display.h" #include "allegro5/drawing.h" #include "allegro5/error.h" #include "allegro5/events.h" #include "allegro5/file.h" #include "allegro5/fixed.h" #include "allegro5/fmaths.h" #include "allegro5/fshook.h" #include "allegro5/fullscreen_mode.h" #include "allegro5/haptic.h" #include "allegro5/joystick.h" #include "allegro5/keyboard.h" #include "allegro5/memory.h" #include "allegro5/monitor.h" #include "allegro5/mouse.h" #include "allegro5/mouse_cursor.h" #include "allegro5/path.h" #include "allegro5/render_state.h" #include "allegro5/shader.h" #include "allegro5/system.h" #include "allegro5/threads.h" #include "allegro5/timer.h" #include "allegro5/tls.h" #include "allegro5/touch_input.h" #include "allegro5/transformations.h" #include "allegro5/utf8.h" #ifndef ALLEGRO_NO_COMPATIBILITY #include "allegro5/alcompat.h" #endif #ifdef ALLEGRO_EXTRA_HEADER #include ALLEGRO_EXTRA_HEADER #endif #endif allegro5-5.2.10.1/include/allegro5/allegro5.h000066400000000000000000000000261473414355200204760ustar00rootroot00000000000000#include "allegro.h" allegro5-5.2.10.1/include/allegro5/allegro_android.h000066400000000000000000000022721473414355200221160ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * */ #ifndef A5_ANDROID_ALLEGRO_H #define A5_ANDROID_ALLEGRO_H #include #ifdef __cplusplus extern "C" { #endif /* * Public android-related API */ void al_android_set_apk_file_interface(void); const char *al_android_get_os_version(void); void al_android_set_apk_fs_interface(void); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) JNIEnv *al_android_get_jni_env(void); jobject al_android_get_activity(void); int al_android_open_fd(const char *uri, const char *mode); #endif /* XXX decide if this should be public */ void _al_android_set_capture_volume_keys(ALLEGRO_DISPLAY *display, bool onoff); #ifdef __cplusplus } #endif #endif /* A5_ANDROID_ALLEGRO_H */ allegro5-5.2.10.1/include/allegro5/allegro_direct3d.h000066400000000000000000000037051473414355200222010ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Header file for Direct3D specific API. * * By Milan Mimica. * */ #ifndef __al_included_allegro5_allegro_direct3d_h #define __al_included_allegro5_allegro_direct3d_h #include #if defined ALLEGRO_CFG_D3DX9 && defined __cplusplus #include #endif #include "allegro5/base.h" #include "allegro5/display.h" #include "allegro5/bitmap.h" /* Display creation flag. */ #define ALLEGRO_DIRECT3D ALLEGRO_DIRECT3D_INTERNAL #ifdef __cplusplus extern "C" { #endif /* * Public Direct3D-related API */ AL_FUNC(LPDIRECT3DDEVICE9, al_get_d3d_device, (ALLEGRO_DISPLAY *)); AL_FUNC(LPDIRECT3DTEXTURE9, al_get_d3d_system_texture, (ALLEGRO_BITMAP *)); AL_FUNC(LPDIRECT3DTEXTURE9, al_get_d3d_video_texture, (ALLEGRO_BITMAP *)); AL_FUNC(bool, al_have_d3d_non_pow2_texture_support, (void)); AL_FUNC(bool, al_have_d3d_non_square_texture_support, (void)); AL_FUNC(void, al_get_d3d_texture_position, (ALLEGRO_BITMAP *bitmap, int *u, int *v)); AL_FUNC(bool, al_get_d3d_texture_size, (ALLEGRO_BITMAP *bitmap, int *width, int *height)); AL_FUNC(bool, al_is_d3d_device_lost, (ALLEGRO_DISPLAY *display)); AL_FUNC(void, al_set_d3d_device_release_callback, (void (*callback)(ALLEGRO_DISPLAY *display))); AL_FUNC(void, al_set_d3d_device_restore_callback, (void (*callback)(ALLEGRO_DISPLAY *display))); #ifdef __cplusplus } #endif #endif /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/allegro_iphone.h000066400000000000000000000022101473414355200217500ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * */ #ifndef A5_IPHONE_ALLEGRO_H #define A5_IPHONE_ALLEGRO_H #ifdef __cplusplus extern "C" { #endif /* * Public iPhone-related API */ enum ALLEGRO_IPHONE_STATUSBAR_ORIENTATION { ALLEGRO_IPHONE_STATUSBAR_ORIENTATION_PORTRAIT = 0, ALLEGRO_IPHONE_STATUSBAR_ORIENTATION_PORTRAIT_UPSIDE_DOWN, ALLEGRO_IPHONE_STATUSBAR_ORIENTATION_LANDSCAPE_RIGHT, ALLEGRO_IPHONE_STATUSBAR_ORIENTATION_LANDSCAPE_LEFT }; AL_FUNC(void, al_iphone_set_statusbar_orientation, (int orientation)); AL_FUNC(double, al_iphone_get_last_shake_time, (void)); AL_FUNC(float, al_iphone_get_battery_level, (void)); #ifdef __cplusplus } #endif #endif /* A5_IPONE_ALLEGRO_H */ allegro5-5.2.10.1/include/allegro5/allegro_iphone_objc.h000066400000000000000000000015451473414355200227570ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * */ #ifndef A5_IPHONE_ALLEGRO_OBJC_H #define A5_IPHONE_ALLEGRO_OBJC_H /* * Public Objective-C iPhone-related API */ #ifdef __cplusplus extern "C" { #endif AL_FUNC(UIWindow *, al_iphone_get_window, (ALLEGRO_DISPLAY *d)); AL_FUNC(UIView *, al_iphone_get_view, (ALLEGRO_DISPLAY *d)); #ifdef __cplusplus } #endif #endif /* A5_IPHONE_ALLEGRO_OBJC_H */ allegro5-5.2.10.1/include/allegro5/allegro_opengl.h000066400000000000000000000145651473414355200217720ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Main header file for all OpenGL drivers. * * By Milan Mimica. * */ #ifndef __al_included_allegro5_allegro_opengl_h #define __al_included_allegro5_allegro_opengl_h #ifdef __cplusplus extern "C" { #endif #if defined(ALLEGRO_WINDOWS) #include #endif #if defined ALLEGRO_IPHONE #ifdef ALLEGRO_CFG_OPENGLES1 #include #include #elif defined(ALLEGRO_CFG_OPENGLES3) #include #include #elif defined(ALLEGRO_CFG_OPENGLES2) #include #include #endif #ifdef ALLEGRO_CFG_OPENGLES1 /* Apple defines OES versions for these - however the separated alpha ones * don't seem to work on the device and just crash. */ #define glBlendEquation glBlendEquationOES #define glBlendFuncSeparate glBlendFuncSeparateOES #define glBlendEquationSeparate glBlendEquationSeparateOES #define glRenderbufferStorageMultisampleEXT glRenderbufferStorageMultisampleAPPLE #ifdef GL_FUNC_ADD #undef GL_FUNC_ADD #undef GL_FUNC_SUBTRACT #undef GL_FUNC_REVERSE_SUBTRACT #endif #define GL_FUNC_ADD GL_FUNC_ADD_OES #define GL_FUNC_SUBTRACT GL_FUNC_SUBTRACT_OES #define GL_FUNC_REVERSE_SUBTRACT GL_FUNC_REVERSE_SUBTRACT_OES #elif defined(ALLEGRO_CFG_OPENGLES3) #define glRenderbufferStorageMultisampleEXT glRenderbufferStorageMultisample #endif #elif defined(ALLEGRO_MACOSX) || defined(__APPLE__) #include #include #include #ifndef GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES #endif #elif defined(ALLEGRO_CFG_OPENGLES1) #include #include #define GL_FUNC_ADD GL_FUNC_ADD_OES #define GL_FUNC_SUBTRACT GL_FUNC_SUBTRACT_OES #define GL_FUNC_REVERSE_SUBTRACT GL_FUNC_REVERSE_SUBTRACT_OES #define GL_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_OES #define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER_OES #define GL_RENDERBUFFER_EXT GL_RENDERBUFFER_OES #define glBlendEquation glBlendEquationOES #define glBlendFuncSeparate glBlendFuncSeparateOES #define glBlendEquationSeparate glBlendEquationSeparateOES #define glGenerateMipmapEXT glGenerateMipmapOES #define glBindFramebufferEXT glBindFramebufferOES #define glDeleteFramebuffersEXT glDeleteFramebuffersOES #define GL_DEPTH_COMPONENT16 GL_DEPTH_COMPONENT16_OES #define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES #define GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_OES #define GL_FRAMEBUFFER GL_FRAMEBUFFER_OES #elif defined(ALLEGRO_CFG_OPENGLES3) #include #include // TODO: should defines from GLES2 be there as well? // Answer: according to the Khronos OpenGL ES Registry, the extension header // file of OpenGL ES 3.x is actually . Note that GLES 3.x is // backwards-compatible with GLES2. See https://registry.khronos.org/OpenGL/ // TODO: Also, how does it relate to src/opengl/ogl_helpers.h ? // Answer: redefinition of a constant #include #define glRenderbufferStorageMultisampleEXT glRenderbufferStorageMultisample #elif defined(ALLEGRO_CFG_OPENGLES2) #include #include #define GL_RGBA8 GL_RGBA8_OES #define GL_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING #define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER #define glGenerateMipmapEXT glGenerateMipmap #define glBindFramebufferEXT glBindFramebuffer #define glDeleteFramebuffersEXT glDeleteFramebuffers #else /* HACK: Prevent both Mesa and SGI's broken headers from screwing us */ #define __glext_h_ #define __gl_glext_h_ #define __glxext_h_ #define __glx_glxext_h_ #include #undef __glext_h_ #undef __gl_glext_h_ #undef __glxext_h_ #undef __glx_glxext_h_ #endif #ifdef ALLEGRO_RASPBERRYPI #include #include #endif #include "allegro5/bitmap.h" #include "allegro5/display.h" #include "allegro5/shader.h" #include "allegro5/opengl/gl_ext.h" #ifdef ALLEGRO_WINDOWS /* Missing #defines from Mingw */ #ifndef PFD_SWAP_LAYER_BUFFERS #define PFD_SWAP_LAYER_BUFFERS 0x00000800 #endif #ifndef PFD_GENERIC_ACCELERATED #define PFD_GENERIC_ACCELERATED 0x00001000 #endif #ifndef PFD_SUPPORT_DIRECTDRAW #define PFD_SUPPORT_DIRECTDRAW 0x00002000 #endif #ifndef CDS_FULLSCREEN #define CDS_FULLSCREEN 0x00000004 #endif #ifndef ENUM_CURRENT_SETTINGS #define ENUM_CURRENT_SETTINGS ((DWORD)-1) #endif #endif /* ALLEGRO_WINDOWS */ #if defined ALLEGRO_WINDOWS #define ALLEGRO_DEFINE_PROC_TYPE(type, name, args) \ typedef type (APIENTRY * name) args; #else #define ALLEGRO_DEFINE_PROC_TYPE(type, name, args) \ typedef type (*name) args; #endif /* * Public OpenGL-related API */ /* ALLEGRO_OPENGL_VARIANT */ typedef enum ALLEGRO_OPENGL_VARIANT { ALLEGRO_DESKTOP_OPENGL = 0, ALLEGRO_OPENGL_ES } ALLEGRO_OPENGL_VARIANT; AL_FUNC(uint32_t, al_get_opengl_version, (void)); AL_FUNC(bool, al_have_opengl_extension, (const char *extension)); AL_FUNC(void*, al_get_opengl_proc_address, (const char *name)); AL_FUNC(ALLEGRO_OGL_EXT_LIST*, al_get_opengl_extension_list, (void)); AL_FUNC(GLuint, al_get_opengl_texture, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(void, al_remove_opengl_fbo, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(GLuint, al_get_opengl_fbo, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(bool, al_get_opengl_texture_size, (ALLEGRO_BITMAP *bitmap, int *w, int *h)); AL_FUNC(void, al_get_opengl_texture_position, (ALLEGRO_BITMAP *bitmap, int *u, int *v)); AL_FUNC(GLuint, al_get_opengl_program_object, (ALLEGRO_SHADER *shader)); AL_FUNC(void, al_set_current_opengl_context, (ALLEGRO_DISPLAY *display)); AL_FUNC(int, al_get_opengl_variant, (void)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/allegro_osx.h000066400000000000000000000014001473414355200212770ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * */ #ifndef A5_OSX_ALLEGRO_H #define A5_OSX_ALLEGRO_H /* * Public Objective-C OSX-related API */ #ifdef __cplusplus extern "C" { #endif AL_FUNC(NSWindow *, al_osx_get_window, (ALLEGRO_DISPLAY *d)); #ifdef __cplusplus } #endif #endif /* A5_OSX_ALLEGRO_H */ allegro5-5.2.10.1/include/allegro5/allegro_windows.h000066400000000000000000000026501473414355200221700ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Header file for Windows specific API. * * By Trent Gamblin. * */ #ifndef __al_included_allegro5_allegro_windows_h #define __al_included_allegro5_allegro_windows_h #include #include "allegro5/base.h" #include "allegro5/display.h" #ifdef __cplusplus extern "C" { #endif /* * Public Windows-related API */ AL_FUNC(HWND, al_get_win_window_handle, (ALLEGRO_DISPLAY *display)); AL_FUNC(bool, al_win_add_window_callback, (ALLEGRO_DISPLAY *display, bool (*callback)(ALLEGRO_DISPLAY *display, UINT message, WPARAM wparam, LPARAM lparam, LRESULT *result, void *userdata), void *userdata)); AL_FUNC(bool, al_win_remove_window_callback, (ALLEGRO_DISPLAY *display, bool (*callback)(ALLEGRO_DISPLAY *display, UINT message, WPARAM wparam, LPARAM lparam, LRESULT *result, void *userdata), void *userdata)); #ifdef __cplusplus } #endif #endif /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/allegro_x.h000066400000000000000000000021421473414355200207410ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Header file for X specific functionality. * * By Robert MacGregor. * */ #ifndef __al_included_allegro5_allegro_x_h #define __al_included_allegro5_allegro_x_h #include #include "allegro5/base.h" #include "allegro5/display.h" #ifdef __cplusplus extern "C" { #endif /* * Public X-related API */ AL_FUNC(XID, al_get_x_window_id, (ALLEGRO_DISPLAY *display)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) AL_FUNC(bool, al_x_set_initial_icon, (ALLEGRO_BITMAP *bitmap)); #endif #ifdef __cplusplus } #endif #endif /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/altime.h000066400000000000000000000007661473414355200202520ustar00rootroot00000000000000#ifndef __al_included_allegro5_altime_h #define __al_included_allegro5_altime_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_TIMEOUT */ typedef struct ALLEGRO_TIMEOUT ALLEGRO_TIMEOUT; struct ALLEGRO_TIMEOUT { uint64_t __pad1__; uint64_t __pad2__; }; AL_FUNC(double, al_get_time, (void)); AL_FUNC(void, al_rest, (double seconds)); AL_FUNC(void, al_init_timeout, (ALLEGRO_TIMEOUT *timeout, double seconds)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/base.h000066400000000000000000000054741473414355200177120ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Base header, defines basic stuff needed by pretty much * everything else. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_base_h #define __al_included_allegro5_base_h #ifndef ALLEGRO_NO_STD_HEADERS #include #ifdef _MSC_VER /* enable posix for limits.h and only limits.h enabling it for all msvc headers will potentially disable a lot of commonly used msvcrt functions */ #define _POSIX_ #include #undef _POSIX_ #else #include #endif #include #include #include #include #include #include #endif #if (defined DEBUGMODE) && (defined FORTIFY) #include #endif #if (defined DEBUGMODE) && (defined DMALLOC) #include #endif #include "allegro5/internal/alconfig.h" #ifdef __cplusplus extern "C" { #endif #define ALLEGRO_VERSION 5 #define ALLEGRO_SUB_VERSION 2 #define ALLEGRO_WIP_VERSION 10 #ifdef ALLEGRO_UNSTABLE /* 1 << 31 represented as a signed int to match the arg type of * al_install_system. */ #define ALLEGRO_UNSTABLE_BIT _ALLEGRO_UNSTABLE_BIT_SET #else #define ALLEGRO_UNSTABLE_BIT 0 #endif /* Not sure we need it, but since ALLEGRO_VERSION_STR contains it: * 0 = GIT * 1 = first release * 2... = hotfixes? * * Note x.y.z (= x.y.z.0) has release number 1, and x.y.z.1 has release * number 2, just to confuse you. */ #define ALLEGRO_RELEASE_NUMBER 1 #define ALLEGRO_VERSION_STR "5.2.10" #define ALLEGRO_DATE_STR "2024" #define ALLEGRO_DATE 20241126 /* yyyymmdd */ #define ALLEGRO_VERSION_INT \ ((ALLEGRO_VERSION << 24) | (ALLEGRO_SUB_VERSION << 16) | \ (ALLEGRO_WIP_VERSION << 8) | ALLEGRO_RELEASE_NUMBER | \ ALLEGRO_UNSTABLE_BIT) AL_FUNC(uint32_t, al_get_allegro_version, (void)); AL_FUNC(int, al_run_main, (int argc, char **argv, int (*)(int, char **))); /*******************************************/ /************ Some global stuff ************/ /*******************************************/ /* Type: ALLEGRO_PI */ #define ALLEGRO_PI 3.14159265358979323846 #define AL_ID(a,b,c,d) (((a)<<24) | ((b)<<16) | ((c)<<8) | (d)) #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/bitmap.h000066400000000000000000000111351473414355200202430ustar00rootroot00000000000000#ifndef __al_included_allegro5_bitmap_h #define __al_included_allegro5_bitmap_h #include "allegro5/color.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_BITMAP */ typedef struct ALLEGRO_BITMAP ALLEGRO_BITMAP; #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) /* Enum: ALLEGRO_BITMAP_WRAP */ typedef enum ALLEGRO_BITMAP_WRAP { ALLEGRO_BITMAP_WRAP_DEFAULT = 0, ALLEGRO_BITMAP_WRAP_REPEAT = 1, ALLEGRO_BITMAP_WRAP_CLAMP = 2, ALLEGRO_BITMAP_WRAP_MIRROR = 3, } ALLEGRO_BITMAP_WRAP; #endif /* * Bitmap flags */ enum { ALLEGRO_MEMORY_BITMAP = 0x0001, _ALLEGRO_KEEP_BITMAP_FORMAT = 0x0002, /* now a bitmap loader flag */ ALLEGRO_FORCE_LOCKING = 0x0004, /* no longer honoured */ ALLEGRO_NO_PRESERVE_TEXTURE = 0x0008, _ALLEGRO_ALPHA_TEST = 0x0010, /* now a render state flag */ _ALLEGRO_INTERNAL_OPENGL = 0x0020, ALLEGRO_MIN_LINEAR = 0x0040, ALLEGRO_MAG_LINEAR = 0x0080, ALLEGRO_MIPMAP = 0x0100, _ALLEGRO_NO_PREMULTIPLIED_ALPHA = 0x0200, /* now a bitmap loader flag */ ALLEGRO_VIDEO_BITMAP = 0x0400, ALLEGRO_CONVERT_BITMAP = 0x1000 }; AL_FUNC(void, al_set_new_bitmap_format, (int format)); AL_FUNC(void, al_set_new_bitmap_flags, (int flags)); AL_FUNC(int, al_get_new_bitmap_format, (void)); AL_FUNC(int, al_get_new_bitmap_flags, (void)); AL_FUNC(void, al_add_new_bitmap_flag, (int flag)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) AL_FUNC(int, al_get_new_bitmap_depth, (void)); AL_FUNC(void, al_set_new_bitmap_depth, (int depth)); AL_FUNC(int, al_get_new_bitmap_samples, (void)); AL_FUNC(void, al_set_new_bitmap_samples, (int samples)); AL_FUNC(void, al_get_new_bitmap_wrap, (ALLEGRO_BITMAP_WRAP *u, ALLEGRO_BITMAP_WRAP *v)); AL_FUNC(void, al_set_new_bitmap_wrap, (ALLEGRO_BITMAP_WRAP u, ALLEGRO_BITMAP_WRAP v)); #endif AL_FUNC(int, al_get_bitmap_width, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(int, al_get_bitmap_height, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(int, al_get_bitmap_format, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(int, al_get_bitmap_flags, (ALLEGRO_BITMAP *bitmap)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) AL_FUNC(int, al_get_bitmap_depth, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(int, al_get_bitmap_samples, (ALLEGRO_BITMAP *bitmap)); #endif AL_FUNC(ALLEGRO_BITMAP*, al_create_bitmap, (int w, int h)); AL_FUNC(void, al_destroy_bitmap, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(void, al_put_pixel, (int x, int y, ALLEGRO_COLOR color)); AL_FUNC(void, al_put_blended_pixel, (int x, int y, ALLEGRO_COLOR color)); AL_FUNC(ALLEGRO_COLOR, al_get_pixel, (ALLEGRO_BITMAP *bitmap, int x, int y)); /* Masking */ AL_FUNC(void, al_convert_mask_to_alpha, (ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR mask_color)); /* Blending */ #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) AL_FUNC(ALLEGRO_COLOR, al_get_bitmap_blend_color, (void)); AL_FUNC(void, al_get_bitmap_blender, (int *op, int *src, int *dst)); AL_FUNC(void, al_get_separate_bitmap_blender, (int *op, int *src, int *dst, int *alpha_op, int *alpha_src, int *alpha_dst)); AL_FUNC(void, al_set_bitmap_blend_color, (ALLEGRO_COLOR color)); AL_FUNC(void, al_set_bitmap_blender, (int op, int src, int dst)); AL_FUNC(void, al_set_separate_bitmap_blender, (int op, int src, int dst, int alpha_op, int alpha_src, int alpha_dst)); AL_FUNC(void, al_reset_bitmap_blender, (void)); #endif /* Clipping */ AL_FUNC(void, al_set_clipping_rectangle, (int x, int y, int width, int height)); AL_FUNC(void, al_reset_clipping_rectangle, (void)); AL_FUNC(void, al_get_clipping_rectangle, (int *x, int *y, int *w, int *h)); /* Sub bitmaps */ AL_FUNC(ALLEGRO_BITMAP *, al_create_sub_bitmap, (ALLEGRO_BITMAP *parent, int x, int y, int w, int h)); AL_FUNC(bool, al_is_sub_bitmap, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(ALLEGRO_BITMAP *, al_get_parent_bitmap, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(int, al_get_bitmap_x, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(int, al_get_bitmap_y, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(void, al_reparent_bitmap, (ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP *parent, int x, int y, int w, int h)); /* Miscellaneous */ AL_FUNC(ALLEGRO_BITMAP *, al_clone_bitmap, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(void, al_convert_bitmap, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(void, al_convert_memory_bitmaps, (void)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) AL_FUNC(void, al_backup_dirty_bitmap, (ALLEGRO_BITMAP *bitmap)); #endif #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/bitmap_draw.h000066400000000000000000000040641473414355200212630ustar00rootroot00000000000000#ifndef __al_included_allegro5_bitmap_draw_h #define __al_included_allegro5_bitmap_draw_h #include "allegro5/bitmap.h" #ifdef __cplusplus extern "C" { #endif /* Flags for the blitting functions */ enum { ALLEGRO_FLIP_HORIZONTAL = 0x00001, ALLEGRO_FLIP_VERTICAL = 0x00002 }; /* Blitting */ AL_FUNC(void, al_draw_bitmap, (ALLEGRO_BITMAP *bitmap, float dx, float dy, int flags)); AL_FUNC(void, al_draw_bitmap_region, (ALLEGRO_BITMAP *bitmap, float sx, float sy, float sw, float sh, float dx, float dy, int flags)); AL_FUNC(void, al_draw_scaled_bitmap, (ALLEGRO_BITMAP *bitmap, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, int flags)); AL_FUNC(void, al_draw_rotated_bitmap, (ALLEGRO_BITMAP *bitmap, float cx, float cy, float dx, float dy, float angle, int flags)); AL_FUNC(void, al_draw_scaled_rotated_bitmap, (ALLEGRO_BITMAP *bitmap, float cx, float cy, float dx, float dy, float xscale, float yscale, float angle, int flags)); /* Tinted blitting */ AL_FUNC(void, al_draw_tinted_bitmap, (ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float dx, float dy, int flags)); AL_FUNC(void, al_draw_tinted_bitmap_region, (ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, float dx, float dy, int flags)); AL_FUNC(void, al_draw_tinted_scaled_bitmap, (ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, int flags)); AL_FUNC(void, al_draw_tinted_rotated_bitmap, (ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float cx, float cy, float dx, float dy, float angle, int flags)); AL_FUNC(void, al_draw_tinted_scaled_rotated_bitmap, (ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float cx, float cy, float dx, float dy, float xscale, float yscale, float angle, int flags)); AL_FUNC(void, al_draw_tinted_scaled_rotated_bitmap_region, ( ALLEGRO_BITMAP *bitmap, float sx, float sy, float sw, float sh, ALLEGRO_COLOR tint, float cx, float cy, float dx, float dy, float xscale, float yscale, float angle, int flags)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/bitmap_io.h000066400000000000000000000040351473414355200207330ustar00rootroot00000000000000#ifndef __al_included_allegro5_bitmap_io_h #define __al_included_allegro5_bitmap_io_h #include "allegro5/bitmap.h" #include "allegro5/file.h" #ifdef __cplusplus extern "C" { #endif /* * Bitmap loader flag */ enum { ALLEGRO_KEEP_BITMAP_FORMAT = 0x0002, /* was a bitmap flag in 5.0 */ ALLEGRO_NO_PREMULTIPLIED_ALPHA = 0x0200, /* was a bitmap flag in 5.0 */ ALLEGRO_KEEP_INDEX = 0x0800 }; typedef ALLEGRO_BITMAP *(*ALLEGRO_IIO_LOADER_FUNCTION)(const char *filename, int flags); typedef ALLEGRO_BITMAP *(*ALLEGRO_IIO_FS_LOADER_FUNCTION)(ALLEGRO_FILE *fp, int flags); typedef bool (*ALLEGRO_IIO_SAVER_FUNCTION)(const char *filename, ALLEGRO_BITMAP *bitmap); typedef bool (*ALLEGRO_IIO_FS_SAVER_FUNCTION)(ALLEGRO_FILE *fp, ALLEGRO_BITMAP *bitmap); typedef bool (*ALLEGRO_IIO_IDENTIFIER_FUNCTION)(ALLEGRO_FILE *f); AL_FUNC(bool, al_register_bitmap_loader, (const char *ext, ALLEGRO_IIO_LOADER_FUNCTION loader)); AL_FUNC(bool, al_register_bitmap_saver, (const char *ext, ALLEGRO_IIO_SAVER_FUNCTION saver)); AL_FUNC(bool, al_register_bitmap_loader_f, (const char *ext, ALLEGRO_IIO_FS_LOADER_FUNCTION fs_loader)); AL_FUNC(bool, al_register_bitmap_saver_f, (const char *ext, ALLEGRO_IIO_FS_SAVER_FUNCTION fs_saver)); AL_FUNC(bool, al_register_bitmap_identifier, (const char *ext, ALLEGRO_IIO_IDENTIFIER_FUNCTION identifier)); AL_FUNC(ALLEGRO_BITMAP *, al_load_bitmap, (const char *filename)); AL_FUNC(ALLEGRO_BITMAP *, al_load_bitmap_flags, (const char *filename, int flags)); AL_FUNC(ALLEGRO_BITMAP *, al_load_bitmap_f, (ALLEGRO_FILE *fp, const char *ident)); AL_FUNC(ALLEGRO_BITMAP *, al_load_bitmap_flags_f, (ALLEGRO_FILE *fp, const char *ident, int flags)); AL_FUNC(bool, al_save_bitmap, (const char *filename, ALLEGRO_BITMAP *bitmap)); AL_FUNC(bool, al_save_bitmap_f, (ALLEGRO_FILE *fp, const char *ident, ALLEGRO_BITMAP *bitmap)); AL_FUNC(char const *, al_identify_bitmap_f, (ALLEGRO_FILE *fp)); AL_FUNC(char const *, al_identify_bitmap, (char const *filename)); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/bitmap_lock.h000066400000000000000000000022021473414355200212460ustar00rootroot00000000000000#ifndef __al_included_allegro5_bitmap_lock_h #define __al_included_allegro5_bitmap_lock_h #include "allegro5/bitmap.h" #ifdef __cplusplus extern "C" { #endif /* * Locking flags */ enum { ALLEGRO_LOCK_READWRITE = 0, ALLEGRO_LOCK_READONLY = 1, ALLEGRO_LOCK_WRITEONLY = 2 }; /* Type: ALLEGRO_LOCKED_REGION */ typedef struct ALLEGRO_LOCKED_REGION ALLEGRO_LOCKED_REGION; struct ALLEGRO_LOCKED_REGION { void *data; int format; int pitch; int pixel_size; }; AL_FUNC(ALLEGRO_LOCKED_REGION*, al_lock_bitmap, (ALLEGRO_BITMAP *bitmap, int format, int flags)); AL_FUNC(ALLEGRO_LOCKED_REGION*, al_lock_bitmap_region, (ALLEGRO_BITMAP *bitmap, int x, int y, int width, int height, int format, int flags)); AL_FUNC(ALLEGRO_LOCKED_REGION*, al_lock_bitmap_blocked, (ALLEGRO_BITMAP *bitmap, int flags)); AL_FUNC(ALLEGRO_LOCKED_REGION*, al_lock_bitmap_region_blocked, (ALLEGRO_BITMAP *bitmap, int x_block, int y_block, int width_block, int height_block, int flags)); AL_FUNC(void, al_unlock_bitmap, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(bool, al_is_bitmap_locked, (ALLEGRO_BITMAP *bitmap)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/blender.h000066400000000000000000000024601473414355200204030ustar00rootroot00000000000000#ifndef __al_included_allegro5_blender_h #define __al_included_allegro5_blender_h #include "allegro5/base.h" #include "allegro5/color.h" #ifdef __cplusplus extern "C" { #endif /* * Blending modes */ enum ALLEGRO_BLEND_MODE { ALLEGRO_ZERO = 0, ALLEGRO_ONE = 1, ALLEGRO_ALPHA = 2, ALLEGRO_INVERSE_ALPHA = 3, ALLEGRO_SRC_COLOR = 4, ALLEGRO_DEST_COLOR = 5, ALLEGRO_INVERSE_SRC_COLOR = 6, ALLEGRO_INVERSE_DEST_COLOR = 7, ALLEGRO_CONST_COLOR = 8, ALLEGRO_INVERSE_CONST_COLOR = 9, ALLEGRO_NUM_BLEND_MODES }; enum ALLEGRO_BLEND_OPERATIONS { ALLEGRO_ADD = 0, ALLEGRO_SRC_MINUS_DEST = 1, ALLEGRO_DEST_MINUS_SRC = 2, ALLEGRO_NUM_BLEND_OPERATIONS }; AL_FUNC(void, al_set_blender, (int op, int source, int dest)); AL_FUNC(void, al_set_blend_color, (ALLEGRO_COLOR color)); AL_FUNC(void, al_get_blender, (int *op, int *source, int *dest)); AL_FUNC(ALLEGRO_COLOR, al_get_blend_color, (void)); AL_FUNC(void, al_set_separate_blender, (int op, int source, int dest, int alpha_op, int alpha_source, int alpha_dest)); AL_FUNC(void, al_get_separate_blender, (int *op, int *source, int *dest, int *alpha_op, int *alpha_src, int *alpha_dest)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/clipboard.h000066400000000000000000000021471473414355200207310ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Clipboard handling. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_clipboard_h #define __al_included_allegro5_clipboard_h #include "allegro5/base.h" #include "allegro5/display.h" #include "allegro5/utf8.h" #ifdef __cplusplus extern "C" { #endif AL_FUNC(char *, al_get_clipboard_text, (ALLEGRO_DISPLAY *display)); AL_FUNC(bool, al_set_clipboard_text, (ALLEGRO_DISPLAY *display, const char *text)); AL_FUNC(bool, al_clipboard_has_text, (ALLEGRO_DISPLAY *display)); #ifdef __cplusplus } #endif #endif /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ allegro5-5.2.10.1/include/allegro5/color.h000066400000000000000000000064741473414355200201170ustar00rootroot00000000000000#ifndef __al_included_allegro5_color_h #define __al_included_allegro5_color_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_COLOR */ typedef struct ALLEGRO_COLOR ALLEGRO_COLOR; struct ALLEGRO_COLOR { float r, g, b, a; }; /* Enum: ALLEGRO_PIXEL_FORMAT */ typedef enum ALLEGRO_PIXEL_FORMAT { ALLEGRO_PIXEL_FORMAT_ANY = 0, ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA = 1, ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA = 2, ALLEGRO_PIXEL_FORMAT_ANY_15_NO_ALPHA = 3, ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA = 4, ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA = 5, ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA = 6, ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA = 7, ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA = 8, ALLEGRO_PIXEL_FORMAT_ARGB_8888 = 9, ALLEGRO_PIXEL_FORMAT_RGBA_8888 = 10, ALLEGRO_PIXEL_FORMAT_ARGB_4444 = 11, ALLEGRO_PIXEL_FORMAT_RGB_888 = 12, /* 24 bit format */ ALLEGRO_PIXEL_FORMAT_RGB_565 = 13, ALLEGRO_PIXEL_FORMAT_RGB_555 = 14, ALLEGRO_PIXEL_FORMAT_RGBA_5551 = 15, ALLEGRO_PIXEL_FORMAT_ARGB_1555 = 16, ALLEGRO_PIXEL_FORMAT_ABGR_8888 = 17, ALLEGRO_PIXEL_FORMAT_XBGR_8888 = 18, ALLEGRO_PIXEL_FORMAT_BGR_888 = 19, /* 24 bit format */ ALLEGRO_PIXEL_FORMAT_BGR_565 = 20, ALLEGRO_PIXEL_FORMAT_BGR_555 = 21, ALLEGRO_PIXEL_FORMAT_RGBX_8888 = 22, ALLEGRO_PIXEL_FORMAT_XRGB_8888 = 23, ALLEGRO_PIXEL_FORMAT_ABGR_F32 = 24, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE = 25, ALLEGRO_PIXEL_FORMAT_RGBA_4444 = 26, ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 = 27, ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1 = 28, ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3 = 29, ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5 = 30, ALLEGRO_NUM_PIXEL_FORMATS } ALLEGRO_PIXEL_FORMAT; /* Pixel mapping */ AL_FUNC(ALLEGRO_COLOR, al_map_rgb, (unsigned char r, unsigned char g, unsigned char b)); AL_FUNC(ALLEGRO_COLOR, al_map_rgba, (unsigned char r, unsigned char g, unsigned char b, unsigned char a)); AL_FUNC(ALLEGRO_COLOR, al_map_rgb_f, (float r, float g, float b)); AL_FUNC(ALLEGRO_COLOR, al_map_rgba_f, (float r, float g, float b, float a)); AL_FUNC(ALLEGRO_COLOR, al_premul_rgba, (unsigned char r, unsigned char g, unsigned char b, unsigned char a)); AL_FUNC(ALLEGRO_COLOR, al_premul_rgba_f, (float r, float g, float b, float a)); /* Pixel unmapping */ AL_FUNC(void, al_unmap_rgb, (ALLEGRO_COLOR color, unsigned char *r, unsigned char *g, unsigned char *b)); AL_FUNC(void, al_unmap_rgba, (ALLEGRO_COLOR color, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a)); AL_FUNC(void, al_unmap_rgb_f, (ALLEGRO_COLOR color, float *r, float *g, float *b)); AL_FUNC(void, al_unmap_rgba_f, (ALLEGRO_COLOR color, float *r, float *g, float *b, float *a)); /* Pixel formats */ AL_FUNC(int, al_get_pixel_size, (int format)); AL_FUNC(int, al_get_pixel_format_bits, (int format)); AL_FUNC(int, al_get_pixel_block_size, (int format)); AL_FUNC(int, al_get_pixel_block_width, (int format)); AL_FUNC(int, al_get_pixel_block_height, (int format)); #ifdef __cplusplus } #endif #endif /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/config.h000066400000000000000000000041161473414355200202350ustar00rootroot00000000000000#ifndef __al_included_allegro5_config_h #define __al_included_allegro5_config_h #include "allegro5/file.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_CONFIG */ typedef struct ALLEGRO_CONFIG ALLEGRO_CONFIG; /* Type: ALLEGRO_CONFIG_SECTION */ typedef struct ALLEGRO_CONFIG_SECTION ALLEGRO_CONFIG_SECTION; /* Type: ALLEGRO_CONFIG_ENTRY */ typedef struct ALLEGRO_CONFIG_ENTRY ALLEGRO_CONFIG_ENTRY; AL_FUNC(ALLEGRO_CONFIG *, al_create_config, (void)); AL_FUNC(void, al_add_config_section, (ALLEGRO_CONFIG *config, const char *name)); AL_FUNC(void, al_set_config_value, (ALLEGRO_CONFIG *config, const char *section, const char *key, const char *value)); AL_FUNC(void, al_add_config_comment, (ALLEGRO_CONFIG *config, const char *section, const char *comment)); AL_FUNC(const char*, al_get_config_value, (const ALLEGRO_CONFIG *config, const char *section, const char *key)); AL_FUNC(ALLEGRO_CONFIG*, al_load_config_file, (const char *filename)); AL_FUNC(ALLEGRO_CONFIG*, al_load_config_file_f, (ALLEGRO_FILE *filename)); AL_FUNC(bool, al_save_config_file, (const char *filename, const ALLEGRO_CONFIG *config)); AL_FUNC(bool, al_save_config_file_f, (ALLEGRO_FILE *file, const ALLEGRO_CONFIG *config)); AL_FUNC(void, al_merge_config_into, (ALLEGRO_CONFIG *master, const ALLEGRO_CONFIG *add)); AL_FUNC(ALLEGRO_CONFIG *, al_merge_config, (const ALLEGRO_CONFIG *cfg1, const ALLEGRO_CONFIG *cfg2)); AL_FUNC(void, al_destroy_config, (ALLEGRO_CONFIG *config)); AL_FUNC(bool, al_remove_config_section, (ALLEGRO_CONFIG *config, char const *section)); AL_FUNC(bool, al_remove_config_key, (ALLEGRO_CONFIG *config, char const *section, char const *key)); AL_FUNC(char const *, al_get_first_config_section, (ALLEGRO_CONFIG const *config, ALLEGRO_CONFIG_SECTION **iterator)); AL_FUNC(char const *, al_get_next_config_section, (ALLEGRO_CONFIG_SECTION **iterator)); AL_FUNC(char const *, al_get_first_config_entry, (ALLEGRO_CONFIG const *config, char const *section, ALLEGRO_CONFIG_ENTRY **iterator)); AL_FUNC(char const *, al_get_next_config_entry, (ALLEGRO_CONFIG_ENTRY **iterator)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/cpu.h000066400000000000000000000016501473414355200175570ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * CPU and system information handling. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_cpu_h #define __al_included_allegro5_cpu_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif AL_FUNC(int, al_get_cpu_count, (void)); AL_FUNC(int, al_get_ram_size, (void)); #ifdef __cplusplus } #endif #endif /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ allegro5-5.2.10.1/include/allegro5/debug.h000066400000000000000000000066111473414355200200600ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Debug facilities. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_debug_h #define __al_included_allegro5_debug_h #include #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif AL_FUNC(bool, _al_trace_prefix, (char const *channel, int level, char const *file, int line, char const *function)); AL_PRINTFUNC(void, _al_trace_suffix, (const char *msg, ...), 1, 2); #if defined(DEBUGMODE) || defined(ALLEGRO_CFG_RELEASE_LOGGING) /* Must not be used with a trailing semicolon. */ #ifdef ALLEGRO_GCC #define ALLEGRO_DEBUG_CHANNEL(x) \ static char const *__al_debug_channel __attribute__((unused)) = x; #else #define ALLEGRO_DEBUG_CHANNEL(x) \ static char const *__al_debug_channel = x; #endif #define ALLEGRO_TRACE_CHANNEL_LEVEL(channel, level) \ !_al_trace_prefix(channel, level, __FILE__, __LINE__, __func__) \ ? (void)0 : _al_trace_suffix #else #define ALLEGRO_TRACE_CHANNEL_LEVEL(channel, x) 1 ? (void) 0 : _al_trace_suffix #define ALLEGRO_DEBUG_CHANNEL(x) #endif #define ALLEGRO_TRACE_LEVEL(x) ALLEGRO_TRACE_CHANNEL_LEVEL(__al_debug_channel, x) #define ALLEGRO_DEBUG ALLEGRO_TRACE_LEVEL(0) #define ALLEGRO_INFO ALLEGRO_TRACE_LEVEL(1) #define ALLEGRO_WARN ALLEGRO_TRACE_LEVEL(2) #define ALLEGRO_ERROR ALLEGRO_TRACE_LEVEL(3) /* Run-time assertions. */ AL_FUNCPTR(void, _al_user_assert_handler, (char const *expr, char const *file, int line, char const *func)); AL_FUNC(void, al_register_assert_handler, (void (*handler)(char const *expr, char const *file, int line, char const *func))); AL_FUNC(void, al_register_trace_handler, (void (*handler)(char const *))); #ifdef __clang_analyzer__ /* Clang doesn't understand _al_user_assert_handler, so we simplify the * definition for analysis purposes. */ #define ALLEGRO_ASSERT(e) assert(e) #else #ifdef NDEBUG #define ALLEGRO_ASSERT(e) ((void)(0 && (e))) #else #define ALLEGRO_ASSERT(e) \ ((e) ? (void) 0 \ : (_al_user_assert_handler) ? \ _al_user_assert_handler(#e, __FILE__, __LINE__, __func__) \ : assert(e)) #endif #endif /* Compile time assertions. */ #define ALLEGRO_ASSERT_CONCAT_(a, b) a##b #define ALLEGRO_ASSERT_CONCAT(a, b) ALLEGRO_ASSERT_CONCAT_(a, b) #define ALLEGRO_STATIC_ASSERT(module, e) \ struct ALLEGRO_ASSERT_CONCAT(static_assert_##module##_line_, __LINE__) \ { unsigned int bf : !!(e); } /* We are lazy and use just ASSERT while Allegro itself is compiled. */ #ifdef ALLEGRO_LIB_BUILD #define ASSERT(x) ALLEGRO_ASSERT(x) #endif #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/display.h000066400000000000000000000167011473414355200204400ustar00rootroot00000000000000#ifndef __al_included_allegro5_display_h #define __al_included_allegro5_display_h #include "allegro5/bitmap.h" #include "allegro5/color.h" #include "allegro5/events.h" #ifdef __cplusplus extern "C" { #endif /* Possible bit combinations for the flags parameter of al_create_display. */ enum { ALLEGRO_WINDOWED = 1 << 0, ALLEGRO_FULLSCREEN = 1 << 1, ALLEGRO_OPENGL = 1 << 2, ALLEGRO_DIRECT3D_INTERNAL = 1 << 3, ALLEGRO_RESIZABLE = 1 << 4, ALLEGRO_FRAMELESS = 1 << 5, ALLEGRO_NOFRAME = ALLEGRO_FRAMELESS, /* older synonym */ ALLEGRO_GENERATE_EXPOSE_EVENTS = 1 << 6, ALLEGRO_OPENGL_3_0 = 1 << 7, ALLEGRO_OPENGL_FORWARD_COMPATIBLE = 1 << 8, ALLEGRO_FULLSCREEN_WINDOW = 1 << 9, ALLEGRO_MINIMIZED = 1 << 10, ALLEGRO_PROGRAMMABLE_PIPELINE = 1 << 11, ALLEGRO_GTK_TOPLEVEL_INTERNAL = 1 << 12, ALLEGRO_MAXIMIZED = 1 << 13, ALLEGRO_OPENGL_ES_PROFILE = 1 << 14, #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) ALLEGRO_OPENGL_CORE_PROFILE = 1 << 15, ALLEGRO_DRAG_AND_DROP = 1 << 16, #endif }; /* Possible parameters for al_set_display_option. * Make sure to update ALLEGRO_EXTRA_DISPLAY_SETTINGS if you modify * anything here. */ enum ALLEGRO_DISPLAY_OPTIONS { ALLEGRO_RED_SIZE = 0, ALLEGRO_GREEN_SIZE = 1, ALLEGRO_BLUE_SIZE = 2, ALLEGRO_ALPHA_SIZE = 3, ALLEGRO_RED_SHIFT = 4, ALLEGRO_GREEN_SHIFT = 5, ALLEGRO_BLUE_SHIFT = 6, ALLEGRO_ALPHA_SHIFT = 7, ALLEGRO_ACC_RED_SIZE = 8, ALLEGRO_ACC_GREEN_SIZE = 9, ALLEGRO_ACC_BLUE_SIZE = 10, ALLEGRO_ACC_ALPHA_SIZE = 11, ALLEGRO_STEREO = 12, ALLEGRO_AUX_BUFFERS = 13, ALLEGRO_COLOR_SIZE = 14, ALLEGRO_DEPTH_SIZE = 15, ALLEGRO_STENCIL_SIZE = 16, ALLEGRO_SAMPLE_BUFFERS = 17, ALLEGRO_SAMPLES = 18, ALLEGRO_RENDER_METHOD = 19, ALLEGRO_FLOAT_COLOR = 20, ALLEGRO_FLOAT_DEPTH = 21, ALLEGRO_SINGLE_BUFFER = 22, ALLEGRO_SWAP_METHOD = 23, ALLEGRO_COMPATIBLE_DISPLAY = 24, ALLEGRO_UPDATE_DISPLAY_REGION = 25, ALLEGRO_VSYNC = 26, ALLEGRO_MAX_BITMAP_SIZE = 27, ALLEGRO_SUPPORT_NPOT_BITMAP = 28, ALLEGRO_CAN_DRAW_INTO_BITMAP = 29, ALLEGRO_SUPPORT_SEPARATE_ALPHA = 30, ALLEGRO_AUTO_CONVERT_BITMAPS = 31, ALLEGRO_SUPPORTED_ORIENTATIONS = 32, ALLEGRO_OPENGL_MAJOR_VERSION = 33, ALLEGRO_OPENGL_MINOR_VERSION = 34, ALLEGRO_DEFAULT_SHADER_PLATFORM = 35, ALLEGRO_DISPLAY_OPTIONS_COUNT }; enum { ALLEGRO_DONTCARE, ALLEGRO_REQUIRE, ALLEGRO_SUGGEST }; /* Bitflags so they can be used for the ALLEGRO_SUPPORTED_ORIENTATIONS option. */ enum ALLEGRO_DISPLAY_ORIENTATION { ALLEGRO_DISPLAY_ORIENTATION_UNKNOWN = 0, ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES = 1, ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES = 2, ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES = 4, ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES = 8, ALLEGRO_DISPLAY_ORIENTATION_PORTRAIT = 5, ALLEGRO_DISPLAY_ORIENTATION_LANDSCAPE = 10, ALLEGRO_DISPLAY_ORIENTATION_ALL = 15, ALLEGRO_DISPLAY_ORIENTATION_FACE_UP = 16, ALLEGRO_DISPLAY_ORIENTATION_FACE_DOWN = 32 }; /* Formally part of the primitives addon. */ enum { _ALLEGRO_PRIM_MAX_USER_ATTR = 10 }; /* Type: ALLEGRO_DISPLAY */ typedef struct ALLEGRO_DISPLAY ALLEGRO_DISPLAY; /* Enum: ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE */ #define ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE 255 AL_FUNC(void, al_set_new_display_refresh_rate, (int refresh_rate)); AL_FUNC(void, al_set_new_display_flags, (int flags)); AL_FUNC(int, al_get_new_display_refresh_rate, (void)); AL_FUNC(int, al_get_new_display_flags, (void)); AL_FUNC(void, al_set_new_window_title, (const char *title)); AL_FUNC(const char *, al_get_new_window_title, (void)); AL_FUNC(int, al_get_display_width, (ALLEGRO_DISPLAY *display)); AL_FUNC(int, al_get_display_height, (ALLEGRO_DISPLAY *display)); AL_FUNC(int, al_get_display_format, (ALLEGRO_DISPLAY *display)); AL_FUNC(int, al_get_display_refresh_rate, (ALLEGRO_DISPLAY *display)); AL_FUNC(int, al_get_display_flags, (ALLEGRO_DISPLAY *display)); AL_FUNC(int, al_get_display_orientation, (ALLEGRO_DISPLAY* display)); AL_FUNC(bool, al_set_display_flag, (ALLEGRO_DISPLAY *display, int flag, bool onoff)); AL_FUNC(ALLEGRO_DISPLAY*, al_create_display, (int w, int h)); AL_FUNC(void, al_destroy_display, (ALLEGRO_DISPLAY *display)); AL_FUNC(ALLEGRO_DISPLAY*, al_get_current_display, (void)); AL_FUNC(void, al_set_target_bitmap, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(void, al_set_target_backbuffer, (ALLEGRO_DISPLAY *display)); AL_FUNC(ALLEGRO_BITMAP*, al_get_backbuffer, (ALLEGRO_DISPLAY *display)); AL_FUNC(ALLEGRO_BITMAP*, al_get_target_bitmap, (void)); AL_FUNC(bool, al_acknowledge_resize, (ALLEGRO_DISPLAY *display)); AL_FUNC(bool, al_resize_display, (ALLEGRO_DISPLAY *display, int width, int height)); AL_FUNC(void, al_flip_display, (void)); AL_FUNC(void, al_update_display_region, (int x, int y, int width, int height)); AL_FUNC(bool, al_is_compatible_bitmap, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(bool, al_wait_for_vsync, (void)); AL_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_display_event_source, (ALLEGRO_DISPLAY *display)); AL_FUNC(void, al_set_display_icon, (ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *icon)); AL_FUNC(void, al_set_display_icons, (ALLEGRO_DISPLAY *display, int num_icons, ALLEGRO_BITMAP *icons[])); /* Stuff for multihead/window management */ AL_FUNC(int, al_get_new_display_adapter, (void)); AL_FUNC(void, al_set_new_display_adapter, (int adapter)); AL_FUNC(int, al_get_display_adapter, (ALLEGRO_DISPLAY *display)); AL_FUNC(void, al_set_new_window_position, (int x, int y)); AL_FUNC(void, al_get_new_window_position, (int *x, int *y)); AL_FUNC(void, al_set_window_position, (ALLEGRO_DISPLAY *display, int x, int y)); AL_FUNC(void, al_get_window_position, (ALLEGRO_DISPLAY *display, int *x, int *y)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) AL_FUNC(bool, al_get_window_borders, (ALLEGRO_DISPLAY *display, int *left, int *top, int *right, int *bottom)); #endif AL_FUNC(bool, al_set_window_constraints, (ALLEGRO_DISPLAY *display, int min_w, int min_h, int max_w, int max_h)); AL_FUNC(bool, al_get_window_constraints, (ALLEGRO_DISPLAY *display, int *min_w, int *min_h, int *max_w, int *max_h)); AL_FUNC(void, al_apply_window_constraints, (ALLEGRO_DISPLAY *display, bool onoff)); AL_FUNC(void, al_set_window_title, (ALLEGRO_DISPLAY *display, const char *title)); /* Defined in display_settings.c */ AL_FUNC(void, al_set_new_display_option, (int option, int value, int importance)); AL_FUNC(int, al_get_new_display_option, (int option, int *importance)); AL_FUNC(void, al_reset_new_display_options, (void)); AL_FUNC(void, al_set_display_option, (ALLEGRO_DISPLAY *display, int option, int value)); AL_FUNC(int, al_get_display_option, (ALLEGRO_DISPLAY *display, int option)); /*Deferred drawing*/ AL_FUNC(void, al_hold_bitmap_drawing, (bool hold)); AL_FUNC(bool, al_is_bitmap_drawing_held, (void)); /* Miscellaneous */ AL_FUNC(void, al_acknowledge_drawing_halt, (ALLEGRO_DISPLAY *display)); AL_FUNC(void, al_acknowledge_drawing_resume, (ALLEGRO_DISPLAY *display)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) AL_FUNC(void, al_backup_dirty_bitmaps, (ALLEGRO_DISPLAY *display)); #endif #ifdef __cplusplus } #endif #endif /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/drawing.h000066400000000000000000000006621473414355200204250ustar00rootroot00000000000000#ifndef __al_included_allegro5_drawing_h #define __al_included_allegro5_drawing_h #include "allegro5/color.h" #ifdef __cplusplus extern "C" { #endif /* Drawing primitives */ AL_FUNC(void, al_clear_to_color, (ALLEGRO_COLOR color)); AL_FUNC(void, al_clear_depth_buffer, (float x)); AL_FUNC(void, al_draw_pixel, (float x, float y, ALLEGRO_COLOR color)); #ifdef __cplusplus } #endif #endif /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/error.h000066400000000000000000000016271473414355200201250ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Error handling. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_error_h #define __al_included_allegro5_error_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif AL_FUNC(int, al_get_errno, (void)); AL_FUNC(void, al_set_errno, (int errnum)); #ifdef __cplusplus } #endif #endif /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ allegro5-5.2.10.1/include/allegro5/events.h000066400000000000000000000201231473414355200202700ustar00rootroot00000000000000#ifndef __al_included_allegro5_events_h #define __al_included_allegro5_events_h #include "allegro5/altime.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_EVENT_TYPE */ typedef unsigned int ALLEGRO_EVENT_TYPE; enum { ALLEGRO_EVENT_JOYSTICK_AXIS = 1, ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN = 2, ALLEGRO_EVENT_JOYSTICK_BUTTON_UP = 3, ALLEGRO_EVENT_JOYSTICK_CONFIGURATION = 4, ALLEGRO_EVENT_KEY_DOWN = 10, ALLEGRO_EVENT_KEY_CHAR = 11, ALLEGRO_EVENT_KEY_UP = 12, ALLEGRO_EVENT_MOUSE_AXES = 20, ALLEGRO_EVENT_MOUSE_BUTTON_DOWN = 21, ALLEGRO_EVENT_MOUSE_BUTTON_UP = 22, ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY = 23, ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY = 24, ALLEGRO_EVENT_MOUSE_WARPED = 25, ALLEGRO_EVENT_TIMER = 30, ALLEGRO_EVENT_DISPLAY_EXPOSE = 40, ALLEGRO_EVENT_DISPLAY_RESIZE = 41, ALLEGRO_EVENT_DISPLAY_CLOSE = 42, ALLEGRO_EVENT_DISPLAY_LOST = 43, ALLEGRO_EVENT_DISPLAY_FOUND = 44, ALLEGRO_EVENT_DISPLAY_SWITCH_IN = 45, ALLEGRO_EVENT_DISPLAY_SWITCH_OUT = 46, ALLEGRO_EVENT_DISPLAY_ORIENTATION = 47, ALLEGRO_EVENT_DISPLAY_HALT_DRAWING = 48, ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING = 49, ALLEGRO_EVENT_TOUCH_BEGIN = 50, ALLEGRO_EVENT_TOUCH_END = 51, ALLEGRO_EVENT_TOUCH_MOVE = 52, ALLEGRO_EVENT_TOUCH_CANCEL = 53, ALLEGRO_EVENT_DISPLAY_CONNECTED = 60, ALLEGRO_EVENT_DISPLAY_DISCONNECTED = 61, ALLEGRO_EVENT_DROP = 62, }; /* Function: ALLEGRO_EVENT_TYPE_IS_USER * * 1 <= n < 512 - builtin events * 512 <= n < 1024 - reserved user events (for addons) * 1024 <= n - unreserved user events */ #define ALLEGRO_EVENT_TYPE_IS_USER(t) ((t) >= 512) /* Function: ALLEGRO_GET_EVENT_TYPE */ #define ALLEGRO_GET_EVENT_TYPE(a, b, c, d) AL_ID(a, b, c, d) /* Type: ALLEGRO_EVENT_SOURCE */ typedef struct ALLEGRO_EVENT_SOURCE ALLEGRO_EVENT_SOURCE; struct ALLEGRO_EVENT_SOURCE { int __pad[32]; }; /* * Event structures * * All event types have the following fields in common. * * type -- the type of event this is * timestamp -- when this event was generated * source -- which event source generated this event * * For people writing event sources: The common fields must be at the * very start of each event structure, i.e. put _AL_EVENT_HEADER at the * front. */ #define _AL_EVENT_HEADER(srctype) \ ALLEGRO_EVENT_TYPE type; \ srctype *source; \ double timestamp; typedef struct ALLEGRO_ANY_EVENT { _AL_EVENT_HEADER(ALLEGRO_EVENT_SOURCE) } ALLEGRO_ANY_EVENT; typedef struct ALLEGRO_DISPLAY_EVENT { _AL_EVENT_HEADER(struct ALLEGRO_DISPLAY) int x, y; int width, height; int orientation; } ALLEGRO_DISPLAY_EVENT; typedef struct ALLEGRO_JOYSTICK_EVENT { _AL_EVENT_HEADER(struct ALLEGRO_JOYSTICK) struct ALLEGRO_JOYSTICK *id; int stick; int axis; float pos; int button; } ALLEGRO_JOYSTICK_EVENT; typedef struct ALLEGRO_KEYBOARD_EVENT { _AL_EVENT_HEADER(struct ALLEGRO_KEYBOARD) struct ALLEGRO_DISPLAY *display; /* the window the key was pressed in */ int keycode; /* the physical key pressed */ int unichar; /* unicode character or negative */ unsigned int modifiers; /* bitfield */ bool repeat; /* auto-repeated or not */ } ALLEGRO_KEYBOARD_EVENT; typedef struct ALLEGRO_MOUSE_EVENT { _AL_EVENT_HEADER(struct ALLEGRO_MOUSE) struct ALLEGRO_DISPLAY *display; /* (display) Window the event originate from * (x, y) Primary mouse position * (z) Mouse wheel position (1D 'wheel'), or, * (w, z) Mouse wheel position (2D 'ball') * (pressure) The pressure applied, for stylus (0 or 1 for normal mouse) */ int x, y, z, w; int dx, dy, dz, dw; unsigned int button; float pressure; } ALLEGRO_MOUSE_EVENT; typedef struct ALLEGRO_TIMER_EVENT { _AL_EVENT_HEADER(struct ALLEGRO_TIMER) int64_t count; double error; } ALLEGRO_TIMER_EVENT; typedef struct ALLEGRO_TOUCH_EVENT { _AL_EVENT_HEADER(struct ALLEGRO_TOUCH_INPUT) struct ALLEGRO_DISPLAY *display; /* (id) Identifier of the event, always positive number. * (x, y) Touch position on the screen in 1:1 resolution. * (dx, dy) Relative touch position. * (primary) True, if touch is a primary one (usually first one). */ int id; float x, y; float dx, dy; bool primary; } ALLEGRO_TOUCH_EVENT; /* Type: ALLEGRO_USER_EVENT */ typedef struct ALLEGRO_USER_EVENT ALLEGRO_USER_EVENT; struct ALLEGRO_USER_EVENT { _AL_EVENT_HEADER(struct ALLEGRO_EVENT_SOURCE) struct ALLEGRO_USER_EVENT_DESCRIPTOR *__internal__descr; intptr_t data1; intptr_t data2; intptr_t data3; intptr_t data4; }; typedef struct ALLEGRO_DROP_EVENT { _AL_EVENT_HEADER(struct ALLEGRO_DISPLAY) int x, y; int row; bool is_file; char *text; bool is_complete; } ALLEGRO_DROP_EVENT; /* Type: ALLEGRO_EVENT */ typedef union ALLEGRO_EVENT ALLEGRO_EVENT; union ALLEGRO_EVENT { /* This must be the same as the first field of _AL_EVENT_HEADER. */ ALLEGRO_EVENT_TYPE type; /* `any' is to allow the user to access the other fields which are * common to all event types, without using some specific type * structure. */ ALLEGRO_ANY_EVENT any; ALLEGRO_DISPLAY_EVENT display; ALLEGRO_JOYSTICK_EVENT joystick; ALLEGRO_KEYBOARD_EVENT keyboard; ALLEGRO_MOUSE_EVENT mouse; ALLEGRO_TIMER_EVENT timer; ALLEGRO_TOUCH_EVENT touch; ALLEGRO_USER_EVENT user; ALLEGRO_DROP_EVENT drop; }; /* Event sources */ AL_FUNC(void, al_init_user_event_source, (ALLEGRO_EVENT_SOURCE *)); AL_FUNC(void, al_destroy_user_event_source, (ALLEGRO_EVENT_SOURCE *)); /* The second argument is ALLEGRO_EVENT instead of ALLEGRO_USER_EVENT * to prevent users passing a pointer to a too-short structure. */ AL_FUNC(bool, al_emit_user_event, (ALLEGRO_EVENT_SOURCE *, ALLEGRO_EVENT *, void (*dtor)(ALLEGRO_USER_EVENT *))); AL_FUNC(void, al_unref_user_event, (ALLEGRO_USER_EVENT *)); AL_FUNC(void, al_set_event_source_data, (ALLEGRO_EVENT_SOURCE*, intptr_t data)); AL_FUNC(intptr_t, al_get_event_source_data, (const ALLEGRO_EVENT_SOURCE*)); /* Event queues */ /* Type: ALLEGRO_EVENT_QUEUE */ typedef struct ALLEGRO_EVENT_QUEUE ALLEGRO_EVENT_QUEUE; AL_FUNC(ALLEGRO_EVENT_QUEUE*, al_create_event_queue, (void)); AL_FUNC(void, al_destroy_event_queue, (ALLEGRO_EVENT_QUEUE*)); AL_FUNC(bool, al_is_event_source_registered, (ALLEGRO_EVENT_QUEUE *, ALLEGRO_EVENT_SOURCE *)); AL_FUNC(void, al_register_event_source, (ALLEGRO_EVENT_QUEUE*, ALLEGRO_EVENT_SOURCE*)); AL_FUNC(void, al_unregister_event_source, (ALLEGRO_EVENT_QUEUE*, ALLEGRO_EVENT_SOURCE*)); AL_FUNC(void, al_pause_event_queue, (ALLEGRO_EVENT_QUEUE*, bool)); AL_FUNC(bool, al_is_event_queue_paused, (const ALLEGRO_EVENT_QUEUE*)); AL_FUNC(bool, al_is_event_queue_empty, (ALLEGRO_EVENT_QUEUE*)); AL_FUNC(bool, al_get_next_event, (ALLEGRO_EVENT_QUEUE*, ALLEGRO_EVENT *ret_event)); AL_FUNC(bool, al_peek_next_event, (ALLEGRO_EVENT_QUEUE*, ALLEGRO_EVENT *ret_event)); AL_FUNC(bool, al_drop_next_event, (ALLEGRO_EVENT_QUEUE*)); AL_FUNC(void, al_flush_event_queue, (ALLEGRO_EVENT_QUEUE*)); AL_FUNC(void, al_wait_for_event, (ALLEGRO_EVENT_QUEUE*, ALLEGRO_EVENT *ret_event)); AL_FUNC(bool, al_wait_for_event_timed, (ALLEGRO_EVENT_QUEUE*, ALLEGRO_EVENT *ret_event, float secs)); AL_FUNC(bool, al_wait_for_event_until, (ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT *ret_event, ALLEGRO_TIMEOUT *timeout)); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/file.h000066400000000000000000000075431473414355200177160ustar00rootroot00000000000000#ifndef __al_included_allegro5_file_h #define __al_included_allegro5_file_h #include "allegro5/base.h" #include "allegro5/path.h" #include "allegro5/utf8.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_FILE */ typedef struct ALLEGRO_FILE ALLEGRO_FILE; /* Type: ALLEGRO_FILE_INTERFACE */ typedef struct ALLEGRO_FILE_INTERFACE { AL_METHOD(void *, fi_fopen, (const char *path, const char *mode)); AL_METHOD(bool, fi_fclose, (ALLEGRO_FILE *handle)); AL_METHOD(size_t, fi_fread, (ALLEGRO_FILE *f, void *ptr, size_t size)); AL_METHOD(size_t, fi_fwrite, (ALLEGRO_FILE *f, const void *ptr, size_t size)); AL_METHOD(bool, fi_fflush, (ALLEGRO_FILE *f)); AL_METHOD(int64_t, fi_ftell, (ALLEGRO_FILE *f)); AL_METHOD(bool, fi_fseek, (ALLEGRO_FILE *f, int64_t offset, int whence)); AL_METHOD(bool, fi_feof, (ALLEGRO_FILE *f)); AL_METHOD(int, fi_ferror, (ALLEGRO_FILE *f)); AL_METHOD(const char *, fi_ferrmsg, (ALLEGRO_FILE *f)); AL_METHOD(void, fi_fclearerr, (ALLEGRO_FILE *f)); AL_METHOD(int, fi_fungetc, (ALLEGRO_FILE *f, int c)); AL_METHOD(off_t, fi_fsize, (ALLEGRO_FILE *f)); } ALLEGRO_FILE_INTERFACE; /* Enum: ALLEGRO_SEEK */ typedef enum ALLEGRO_SEEK { ALLEGRO_SEEK_SET = 0, ALLEGRO_SEEK_CUR, ALLEGRO_SEEK_END } ALLEGRO_SEEK; /* The basic operations. */ AL_FUNC(ALLEGRO_FILE*, al_fopen, (const char *path, const char *mode)); AL_FUNC(ALLEGRO_FILE*, al_fopen_interface, (const ALLEGRO_FILE_INTERFACE *vt, const char *path, const char *mode)); AL_FUNC(ALLEGRO_FILE*, al_create_file_handle, (const ALLEGRO_FILE_INTERFACE *vt, void *userdata)); AL_FUNC(bool, al_fclose, (ALLEGRO_FILE *f)); AL_FUNC(size_t, al_fread, (ALLEGRO_FILE *f, void *ptr, size_t size)); AL_FUNC(size_t, al_fwrite, (ALLEGRO_FILE *f, const void *ptr, size_t size)); AL_FUNC(bool, al_fflush, (ALLEGRO_FILE *f)); AL_FUNC(int64_t, al_ftell, (ALLEGRO_FILE *f)); AL_FUNC(bool, al_fseek, (ALLEGRO_FILE *f, int64_t offset, int whence)); AL_FUNC(bool, al_feof, (ALLEGRO_FILE *f)); AL_FUNC(int, al_ferror, (ALLEGRO_FILE *f)); AL_FUNC(const char *, al_ferrmsg, (ALLEGRO_FILE *f)); AL_FUNC(void, al_fclearerr, (ALLEGRO_FILE *f)); AL_FUNC(int, al_fungetc, (ALLEGRO_FILE *f, int c)); AL_FUNC(int64_t, al_fsize, (ALLEGRO_FILE *f)); /* Convenience functions. */ AL_FUNC(int, al_fgetc, (ALLEGRO_FILE *f)); AL_FUNC(int, al_fputc, (ALLEGRO_FILE *f, int c)); AL_FUNC(int16_t, al_fread16le, (ALLEGRO_FILE *f)); AL_FUNC(int16_t, al_fread16be, (ALLEGRO_FILE *f)); AL_FUNC(size_t, al_fwrite16le, (ALLEGRO_FILE *f, int16_t w)); AL_FUNC(size_t, al_fwrite16be, (ALLEGRO_FILE *f, int16_t w)); AL_FUNC(int32_t, al_fread32le, (ALLEGRO_FILE *f)); AL_FUNC(int32_t, al_fread32be, (ALLEGRO_FILE *f)); AL_FUNC(size_t, al_fwrite32le, (ALLEGRO_FILE *f, int32_t l)); AL_FUNC(size_t, al_fwrite32be, (ALLEGRO_FILE *f, int32_t l)); AL_FUNC(char*, al_fgets, (ALLEGRO_FILE *f, char * const p, size_t max)); AL_FUNC(ALLEGRO_USTR *, al_fget_ustr, (ALLEGRO_FILE *f)); AL_FUNC(int, al_fputs, (ALLEGRO_FILE *f, const char *p)); AL_FUNC(int, al_fprintf, (ALLEGRO_FILE *f, const char *format, ...)); AL_FUNC(int, al_vfprintf, (ALLEGRO_FILE *f, const char* format, va_list args)); /* Specific to stdio backend. */ AL_FUNC(ALLEGRO_FILE*, al_fopen_fd, (int fd, const char *mode)); AL_FUNC(ALLEGRO_FILE*, al_make_temp_file, (const char *tmpl, ALLEGRO_PATH **ret_path)); /* Specific to slices. */ AL_FUNC(ALLEGRO_FILE*, al_fopen_slice, (ALLEGRO_FILE *fp, size_t initial_size, const char *mode)); /* Thread-local state. */ AL_FUNC(const ALLEGRO_FILE_INTERFACE *, al_get_new_file_interface, (void)); AL_FUNC(void, al_set_new_file_interface, (const ALLEGRO_FILE_INTERFACE * file_interface)); AL_FUNC(void, al_set_standard_file_interface, (void)); /* ALLEGRO_FILE field accessors */ AL_FUNC(void *, al_get_file_userdata, (ALLEGRO_FILE *f)); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/fixed.h000066400000000000000000000016321473414355200200670ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Fixed point type. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_fixed_h #define __al_included_allegro5_fixed_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif /* Type: al_fixed */ typedef int32_t al_fixed; AL_VAR(const al_fixed, al_fixtorad_r); AL_VAR(const al_fixed, al_radtofix_r); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/fmaths.h000066400000000000000000000022501473414355200202470ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Fixed point math routines. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_fmaths_h #define __al_included_allegro5_fmaths_h #include "allegro5/base.h" #include "allegro5/fixed.h" #ifdef __cplusplus extern "C" { #endif AL_FUNC(al_fixed, al_fixsqrt, (al_fixed x)); AL_FUNC(al_fixed, al_fixhypot, (al_fixed x, al_fixed y)); AL_FUNC(al_fixed, al_fixatan, (al_fixed x)); AL_FUNC(al_fixed, al_fixatan2, (al_fixed y, al_fixed x)); AL_ARRAY(al_fixed, _al_fix_cos_tbl); AL_ARRAY(al_fixed, _al_fix_tan_tbl); AL_ARRAY(al_fixed, _al_fix_acos_tbl); #ifdef __cplusplus } #endif #include "allegro5/inline/fmaths.inl" #endif allegro5-5.2.10.1/include/allegro5/fshook.h000066400000000000000000000126371473414355200202700ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * File System Hooks. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_fshook_h #define __al_included_allegro5_fshook_h #include "allegro5/base.h" #include "allegro5/file.h" #include "allegro5/path.h" #ifdef ALLEGRO_HAVE_SYS_TYPES_H #include #else /* 4 Gig max offsets if sys/types doesn't exist. */ typedef unsigned int off_t; #endif #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_FS_ENTRY */ typedef struct ALLEGRO_FS_ENTRY ALLEGRO_FS_ENTRY; struct ALLEGRO_FS_ENTRY { struct ALLEGRO_FS_INTERFACE const *vtable; }; /* Enum: ALLEGRO_FILE_MODE */ typedef enum ALLEGRO_FILE_MODE { ALLEGRO_FILEMODE_READ = 1, ALLEGRO_FILEMODE_WRITE = 1 << 1, ALLEGRO_FILEMODE_EXECUTE = 1 << 2, ALLEGRO_FILEMODE_HIDDEN = 1 << 3, ALLEGRO_FILEMODE_ISFILE = 1 << 4, ALLEGRO_FILEMODE_ISDIR = 1 << 5 } ALLEGRO_FILE_MODE; #ifndef EOF #define EOF (-1) #endif /* Type: ALLEGRO_FS_INTERFACE */ typedef struct ALLEGRO_FS_INTERFACE ALLEGRO_FS_INTERFACE; struct ALLEGRO_FS_INTERFACE { AL_METHOD(ALLEGRO_FS_ENTRY *, fs_create_entry, (const char *path)); AL_METHOD(void, fs_destroy_entry, (ALLEGRO_FS_ENTRY *e)); AL_METHOD(const char *, fs_entry_name, (ALLEGRO_FS_ENTRY *e)); AL_METHOD(bool, fs_update_entry, (ALLEGRO_FS_ENTRY *e)); AL_METHOD(uint32_t, fs_entry_mode, (ALLEGRO_FS_ENTRY *e)); AL_METHOD(time_t, fs_entry_atime, (ALLEGRO_FS_ENTRY *e)); AL_METHOD(time_t, fs_entry_mtime, (ALLEGRO_FS_ENTRY *e)); AL_METHOD(time_t, fs_entry_ctime, (ALLEGRO_FS_ENTRY *e)); AL_METHOD(off_t, fs_entry_size, (ALLEGRO_FS_ENTRY *e)); AL_METHOD(bool, fs_entry_exists, (ALLEGRO_FS_ENTRY *e)); AL_METHOD(bool, fs_remove_entry, (ALLEGRO_FS_ENTRY *e)); AL_METHOD(bool, fs_open_directory, (ALLEGRO_FS_ENTRY *e)); AL_METHOD(ALLEGRO_FS_ENTRY *, fs_read_directory,(ALLEGRO_FS_ENTRY *e)); AL_METHOD(bool, fs_close_directory, (ALLEGRO_FS_ENTRY *e)); AL_METHOD(bool, fs_filename_exists, (const char *path)); AL_METHOD(bool, fs_remove_filename, (const char *path)); AL_METHOD(char *, fs_get_current_directory, (void)); AL_METHOD(bool, fs_change_directory, (const char *path)); AL_METHOD(bool, fs_make_directory, (const char *path)); AL_METHOD(ALLEGRO_FILE *, fs_open_file, (ALLEGRO_FS_ENTRY *e, const char *mode)); }; AL_FUNC(ALLEGRO_FS_ENTRY *, al_create_fs_entry, (const char *path)); AL_FUNC(void, al_destroy_fs_entry, (ALLEGRO_FS_ENTRY *e)); AL_FUNC(const char *, al_get_fs_entry_name,(ALLEGRO_FS_ENTRY *e)); AL_FUNC(bool, al_update_fs_entry, (ALLEGRO_FS_ENTRY *e)); AL_FUNC(uint32_t, al_get_fs_entry_mode,(ALLEGRO_FS_ENTRY *e)); AL_FUNC(time_t, al_get_fs_entry_atime,(ALLEGRO_FS_ENTRY *e)); AL_FUNC(time_t, al_get_fs_entry_mtime,(ALLEGRO_FS_ENTRY *e)); AL_FUNC(time_t, al_get_fs_entry_ctime,(ALLEGRO_FS_ENTRY *e)); AL_FUNC(off_t, al_get_fs_entry_size,(ALLEGRO_FS_ENTRY *e)); AL_FUNC(bool, al_fs_entry_exists, (ALLEGRO_FS_ENTRY *e)); AL_FUNC(bool, al_remove_fs_entry, (ALLEGRO_FS_ENTRY *e)); AL_FUNC(bool, al_open_directory, (ALLEGRO_FS_ENTRY *e)); AL_FUNC(ALLEGRO_FS_ENTRY *, al_read_directory, (ALLEGRO_FS_ENTRY *e)); AL_FUNC(bool, al_close_directory, (ALLEGRO_FS_ENTRY *e)); AL_FUNC(bool, al_filename_exists, (const char *path)); AL_FUNC(bool, al_remove_filename, (const char *path)); AL_FUNC(char *, al_get_current_directory, (void)); AL_FUNC(bool, al_change_directory, (const char *path)); AL_FUNC(bool, al_make_directory, (const char *path)); AL_FUNC(ALLEGRO_FILE *, al_open_fs_entry, (ALLEGRO_FS_ENTRY *e, const char *mode)); /* Helper function for iterating over a directory using a callback. */ /* Type: ALLEGRO_FOR_EACH_FS_ENTRY_RESULT */ typedef enum ALLEGRO_FOR_EACH_FS_ENTRY_RESULT { ALLEGRO_FOR_EACH_FS_ENTRY_ERROR = -1, ALLEGRO_FOR_EACH_FS_ENTRY_OK = 0, ALLEGRO_FOR_EACH_FS_ENTRY_SKIP = 1, ALLEGRO_FOR_EACH_FS_ENTRY_STOP = 2 } ALLEGRO_FOR_EACH_FS_ENTRY_RESULT; AL_FUNC(int, al_for_each_fs_entry, (ALLEGRO_FS_ENTRY *dir, int (*callback)(ALLEGRO_FS_ENTRY *entry, void *extra), void *extra)); /* Thread-local state. */ AL_FUNC(const ALLEGRO_FS_INTERFACE *, al_get_fs_interface, (void)); AL_FUNC(void, al_set_fs_interface, (const ALLEGRO_FS_INTERFACE *vtable)); AL_FUNC(void, al_set_standard_fs_interface, (void)); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/fullscreen_mode.h000066400000000000000000000010611473414355200221320ustar00rootroot00000000000000#ifndef __al_included_allegro5_fullscreen_mode_h #define __al_included_allegro5_fullscreen_mode_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_DISPLAY_MODE */ typedef struct ALLEGRO_DISPLAY_MODE { int width; int height; int format; int refresh_rate; } ALLEGRO_DISPLAY_MODE; AL_FUNC(int, al_get_num_display_modes, (void)); AL_FUNC(ALLEGRO_DISPLAY_MODE*, al_get_display_mode, (int index, ALLEGRO_DISPLAY_MODE *mode)); #ifdef __cplusplus } #endif #endif /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/haptic.h000066400000000000000000000163451473414355200202470ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Haptic (that is, force feedback) routines for Allegro. * * By Beoran. * * See LICENSE.txt for copyright information. */ #ifndef __al_included_allegro5_haptic_h #define __al_included_allegro5_haptic_h #include "allegro5/base.h" #include "allegro5/display.h" #include "allegro5/events.h" #include "allegro5/joystick.h" #include "allegro5/keyboard.h" #include "allegro5/mouse.h" #include "allegro5/touch_input.h" #ifdef __cplusplus extern "C" { #endif #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) /* Enum: ALLEGRO_HAPTIC_CONSTANTS */ enum ALLEGRO_HAPTIC_CONSTANTS { ALLEGRO_HAPTIC_RUMBLE = 1 << 0, ALLEGRO_HAPTIC_PERIODIC = 1 << 1, ALLEGRO_HAPTIC_CONSTANT = 1 << 2, ALLEGRO_HAPTIC_SPRING = 1 << 3, ALLEGRO_HAPTIC_FRICTION = 1 << 4, ALLEGRO_HAPTIC_DAMPER = 1 << 5, ALLEGRO_HAPTIC_INERTIA = 1 << 6, ALLEGRO_HAPTIC_RAMP = 1 << 7, ALLEGRO_HAPTIC_SQUARE = 1 << 8, ALLEGRO_HAPTIC_TRIANGLE = 1 << 9, ALLEGRO_HAPTIC_SINE = 1 << 10, ALLEGRO_HAPTIC_SAW_UP = 1 << 11, ALLEGRO_HAPTIC_SAW_DOWN = 1 << 12, ALLEGRO_HAPTIC_CUSTOM = 1 << 13, ALLEGRO_HAPTIC_GAIN = 1 << 14, ALLEGRO_HAPTIC_ANGLE = 1 << 15, ALLEGRO_HAPTIC_RADIUS = 1 << 16, ALLEGRO_HAPTIC_AZIMUTH = 1 << 17, ALLEGRO_HAPTIC_AUTOCENTER= 1 << 18, }; /* Type: ALLEGRO_HAPTIC */ typedef struct ALLEGRO_HAPTIC ALLEGRO_HAPTIC; /* Direction of a haptic effect. Angle is a value between 0 and 2*M_PI. * An angle 0 means oriented towards the user, M_PI is away from the user * (towards the screen). Angle is only supported if the device capabilities * include ALLEGRO_HAPTIC_ANGLE. * * Radius (if supported) is the distance of the effect from the user as a * value between 0 and 1. Normally it is zero. Radius is only supported if the * device capabilities include ALLEGRO_HAPTIC_RADIUS. * * Azimuth is the angle of elevation, between -M_PI/2 and M_PI/2. * Zero points to the horizontal plane, -M_PI/2 points down, and M_PI/2 points * up. Azimuth is only supported if the device capabilities include * ALLEGRO_HAPTIC_AZIMUTH. */ struct ALLEGRO_HAPTIC_DIRECTION { double angle; double radius; double azimuth; }; /* In all of the following structs, the doubles that express duration * represent time in seconds. The double that represent levels of intensity * are between 0.0 and 1.0. */ /* Delay to start the replay and duration of the replay, expressed in seconds. */ struct ALLEGRO_HAPTIC_REPLAY { double length; double delay; }; /* Envelope of the effect. */ struct ALLEGRO_HAPTIC_ENVELOPE { double attack_length; double attack_level; double fade_length; double fade_level; }; /* Constant effect. Level is between 0.0 and 1.0. */ struct ALLEGRO_HAPTIC_CONSTANT_EFFECT { double level; struct ALLEGRO_HAPTIC_ENVELOPE envelope; }; /* Ramp effect. Both start_level and end level are between 0.0 and 1.0. */ struct ALLEGRO_HAPTIC_RAMP_EFFECT { double start_level; double end_level; struct ALLEGRO_HAPTIC_ENVELOPE envelope; }; /* Condition effect. */ struct ALLEGRO_HAPTIC_CONDITION_EFFECT { double right_saturation; double left_saturation; double right_coeff; double left_coeff; double deadband; double center; }; /* Periodic (wave) effect. */ struct ALLEGRO_HAPTIC_PERIODIC_EFFECT { int waveform; double period; double magnitude; double offset; double phase; struct ALLEGRO_HAPTIC_ENVELOPE envelope; int custom_len; double *custom_data; }; /* Simple rumble effect with a magnitude between 0.0 and 1.0 for both * the strong and the weak rumble motors in the haptic device. */ struct ALLEGRO_HAPTIC_RUMBLE_EFFECT { double strong_magnitude; double weak_magnitude; }; union ALLEGRO_HAPTIC_EFFECT_UNION { struct ALLEGRO_HAPTIC_CONSTANT_EFFECT constant; struct ALLEGRO_HAPTIC_RAMP_EFFECT ramp; struct ALLEGRO_HAPTIC_PERIODIC_EFFECT periodic; struct ALLEGRO_HAPTIC_CONDITION_EFFECT condition; struct ALLEGRO_HAPTIC_RUMBLE_EFFECT rumble; }; /* Type: ALLEGRO_HAPTIC_EFFECT */ struct ALLEGRO_HAPTIC_EFFECT { int type; struct ALLEGRO_HAPTIC_DIRECTION direction; struct ALLEGRO_HAPTIC_REPLAY replay; union ALLEGRO_HAPTIC_EFFECT_UNION data; }; typedef struct ALLEGRO_HAPTIC_EFFECT ALLEGRO_HAPTIC_EFFECT; /* Type: ALLEGRO_HAPTIC_EFFECT_ID */ typedef struct ALLEGRO_HAPTIC_EFFECT_ID ALLEGRO_HAPTIC_EFFECT_ID; struct ALLEGRO_HAPTIC_EFFECT_ID { ALLEGRO_HAPTIC *_haptic; int _id; int _handle; void * _pointer; double _effect_duration; bool _playing; double _start_time; double _end_time; void * driver; }; AL_FUNC(bool, al_install_haptic, (void)); AL_FUNC(void, al_uninstall_haptic, (void)); AL_FUNC(bool, al_is_haptic_installed, (void)); AL_FUNC(bool, al_is_mouse_haptic, (ALLEGRO_MOUSE *)); AL_FUNC(bool, al_is_joystick_haptic, (ALLEGRO_JOYSTICK *)); AL_FUNC(bool, al_is_keyboard_haptic, (ALLEGRO_KEYBOARD *)); AL_FUNC(bool, al_is_display_haptic, (ALLEGRO_DISPLAY *)); AL_FUNC(bool, al_is_touch_input_haptic, (ALLEGRO_TOUCH_INPUT *)); AL_FUNC(ALLEGRO_HAPTIC *, al_get_haptic_from_mouse, (ALLEGRO_MOUSE *)); AL_FUNC(ALLEGRO_HAPTIC *, al_get_haptic_from_joystick, (ALLEGRO_JOYSTICK *)); AL_FUNC(ALLEGRO_HAPTIC *, al_get_haptic_from_keyboard, (ALLEGRO_KEYBOARD *)); AL_FUNC(ALLEGRO_HAPTIC *, al_get_haptic_from_display, (ALLEGRO_DISPLAY *)); AL_FUNC(ALLEGRO_HAPTIC *, al_get_haptic_from_touch_input, (ALLEGRO_TOUCH_INPUT *)); AL_FUNC(bool, al_release_haptic, (ALLEGRO_HAPTIC *)); AL_FUNC(bool, al_is_haptic_active, (ALLEGRO_HAPTIC *)); AL_FUNC(int, al_get_haptic_capabilities, (ALLEGRO_HAPTIC *)); AL_FUNC(bool, al_is_haptic_capable, (ALLEGRO_HAPTIC *, int)); AL_FUNC(bool, al_set_haptic_gain, (ALLEGRO_HAPTIC *, double)); AL_FUNC(double, al_get_haptic_gain, (ALLEGRO_HAPTIC *)); AL_FUNC(bool, al_set_haptic_autocenter, (ALLEGRO_HAPTIC *, double)); AL_FUNC(double, al_get_haptic_autocenter, (ALLEGRO_HAPTIC *)); AL_FUNC(int, al_get_max_haptic_effects, (ALLEGRO_HAPTIC *)); AL_FUNC(bool, al_is_haptic_effect_ok, (ALLEGRO_HAPTIC *, ALLEGRO_HAPTIC_EFFECT *)); AL_FUNC(bool, al_upload_haptic_effect, (ALLEGRO_HAPTIC *, ALLEGRO_HAPTIC_EFFECT *, ALLEGRO_HAPTIC_EFFECT_ID *)); AL_FUNC(bool, al_play_haptic_effect, (ALLEGRO_HAPTIC_EFFECT_ID *, int)); AL_FUNC(bool, al_upload_and_play_haptic_effect, (ALLEGRO_HAPTIC *, ALLEGRO_HAPTIC_EFFECT *, ALLEGRO_HAPTIC_EFFECT_ID *, int)); AL_FUNC(bool, al_stop_haptic_effect, (ALLEGRO_HAPTIC_EFFECT_ID *)); AL_FUNC(bool, al_is_haptic_effect_playing, (ALLEGRO_HAPTIC_EFFECT_ID *)); AL_FUNC(bool, al_release_haptic_effect, (ALLEGRO_HAPTIC_EFFECT_ID *)); AL_FUNC(double, al_get_haptic_effect_duration, (ALLEGRO_HAPTIC_EFFECT *)); AL_FUNC(bool, al_rumble_haptic, (ALLEGRO_HAPTIC *, double, double, ALLEGRO_HAPTIC_EFFECT_ID *)); #endif #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/inline/000077500000000000000000000000001473414355200200735ustar00rootroot00000000000000allegro5-5.2.10.1/include/allegro5/inline/fmaths.inl000066400000000000000000000123451473414355200220660ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Fixed point math inline functions (generic C). * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_inline_fmaths_inl #define __al_included_allegro5_inline_fmaths_inl #include "allegro5/error.h" #ifdef __cplusplus extern "C" { #endif /* al_ftofix and al_fixtof are used in generic C versions of al_fixmul and al_fixdiv */ AL_INLINE(al_fixed, al_ftofix, (double x), { if (x > 32767.0) { al_set_errno(ERANGE); return 0x7FFFFFFF; } if (x < -32767.0) { al_set_errno(ERANGE); return -0x7FFFFFFF; } return (al_fixed)(x * 65536.0 + (x < 0 ? -0.5 : 0.5)); }) AL_INLINE(double, al_fixtof, (al_fixed x), { return (double)x / 65536.0; }) AL_INLINE(al_fixed, al_fixadd, (al_fixed x, al_fixed y), { al_fixed result = x + y; if (result >= 0) { if ((x < 0) && (y < 0)) { al_set_errno(ERANGE); return -0x7FFFFFFF; } else return result; } else { if ((x > 0) && (y > 0)) { al_set_errno(ERANGE); return 0x7FFFFFFF; } else return result; } }) AL_INLINE(al_fixed, al_fixsub, (al_fixed x, al_fixed y), { al_fixed result = x - y; if (result >= 0) { if ((x < 0) && (y > 0)) { al_set_errno(ERANGE); return -0x7FFFFFFF; } else return result; } else { if ((x > 0) && (y < 0)) { al_set_errno(ERANGE); return 0x7FFFFFFF; } else return result; } }) /* In benchmarks conducted circa May 2005 we found that, in the main: * - IA32 machines performed faster with one implementation; * - AMD64 and G4 machines performed faster with another implementation. * * Benchmarks were mainly done with differing versions of gcc. * Results varied with other compilers, optimisation levels, etc. * so this is not optimal, though a tenable compromise. * * Note that the following implementation are NOT what were benchmarked. * We had forgotten to put in overflow detection in those versions. * If you don't need overflow detection then previous versions in the * CVS tree might be worth looking at. * * PS. Don't move the #ifs inside the AL_INLINE; BCC doesn't like it. */ #if defined ALLEGRO_I386 AL_INLINE(al_fixed, al_fixmul, (al_fixed x, al_fixed y), { return al_ftofix(al_fixtof(x) * al_fixtof(y)); }) #else AL_INLINE(al_fixed, al_fixmul, (al_fixed x, al_fixed y), { int64_t lx = x; int64_t ly = y; int64_t lres = (lx*ly); if (lres > 0x7FFFFFFF0000LL) { al_set_errno(ERANGE); return 0x7FFFFFFF; } else if (lres < -0x7FFFFFFF0000LL) { al_set_errno(ERANGE); return 0x80000000; } else { return (al_fixed) (lres >> 16); } }) #endif /* al_fixmul() C implementations */ #if defined ALLEGRO_CFG_NO_FPU AL_INLINE(al_fixed, al_fixdiv, (al_fixed x, al_fixed y), { int64_t lres = x; if (y == 0) { al_set_errno(ERANGE); return (x < 0) ? -0x7FFFFFFF : 0x7FFFFFFF; } lres <<= 16; lres /= y; if (lres > 0x7FFFFFFF) { al_set_errno(ERANGE); return 0x7FFFFFFF; } else if (lres < -0x7FFFFFFF) { al_set_errno(ERANGE); return 0x80000000; } else { return (al_fixed)(lres); } }) #else AL_INLINE(al_fixed, al_fixdiv, (al_fixed x, al_fixed y), { if (y == 0) { al_set_errno(ERANGE); return (x < 0) ? -0x7FFFFFFF : 0x7FFFFFFF; } else return al_ftofix(al_fixtof(x) / al_fixtof(y)); }) #endif AL_INLINE(int, al_fixfloor, (al_fixed x), { /* (x >> 16) is not portable */ if (x >= 0) return (x >> 16); else return ~((~x) >> 16); }) AL_INLINE(int, al_fixceil, (al_fixed x), { if (x > 0x7FFF0000) { al_set_errno(ERANGE); return 0x7FFF; } return al_fixfloor(x + 0xFFFF); }) AL_INLINE(al_fixed, al_itofix, (int x), { return x << 16; }) AL_INLINE(int, al_fixtoi, (al_fixed x), { return al_fixfloor(x) + ((x & 0x8000) >> 15); }) AL_INLINE(al_fixed, al_fixcos, (al_fixed x), { return _al_fix_cos_tbl[((x + 0x4000) >> 15) & 0x1FF]; }) AL_INLINE(al_fixed, al_fixsin, (al_fixed x), { return _al_fix_cos_tbl[((x - 0x400000 + 0x4000) >> 15) & 0x1FF]; }) AL_INLINE(al_fixed, al_fixtan, (al_fixed x), { return _al_fix_tan_tbl[((x + 0x4000) >> 15) & 0xFF]; }) AL_INLINE(al_fixed, al_fixacos, (al_fixed x), { if ((x < -65536) || (x > 65536)) { al_set_errno(EDOM); return 0; } return _al_fix_acos_tbl[(x+65536+127)>>8]; }) AL_INLINE(al_fixed, al_fixasin, (al_fixed x), { if ((x < -65536) || (x > 65536)) { al_set_errno(EDOM); return 0; } return 0x00400000 - _al_fix_acos_tbl[(x+65536+127)>>8]; }) #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/internal/000077500000000000000000000000001473414355200204315ustar00rootroot00000000000000allegro5-5.2.10.1/include/allegro5/internal/aintern.h000066400000000000000000000030241473414355200222410ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Some definitions for internal use by the library code. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_aintern_h #define __al_included_allegro5_aintern_h #ifndef __al_included_allegro5_allegro_h #error must include allegro5/allegro.h first #endif #ifdef __cplusplus extern "C" { #endif #define _ALLEGRO_MIN(x,y) (((x) < (y)) ? (x) : (y)) #define _ALLEGRO_MAX(x,y) (((x) > (y)) ? (x) : (y)) #define _ALLEGRO_CLAMP(x,y,z) _ALLEGRO_MAX((x), _ALLEGRO_MIN((y), (z))) int _al_get_least_multiple(int val, int mul); /* message stuff */ #define ALLEGRO_MESSAGE_SIZE 4096 /* various libc stuff */ AL_FUNC(void *, _al_sane_realloc, (void *ptr, size_t size)); AL_FUNC(char *, _al_sane_strncpy, (char *dest, const char *src, size_t n)); #define _AL_RAND_MAX 0xFFFF AL_FUNC(void, _al_srand, (int seed)); AL_FUNC(int, _al_rand, (void)); AL_FUNC(int, _al_stricmp, (const char *s1, const char *s2)); #define _AL_INCHES_PER_MM 0.039370 #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_aatree.h000066400000000000000000000012311473414355200235600ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_aatree_h #define __al_included_allegro5_aintern_aatree_h typedef struct _AL_AATREE _AL_AATREE; struct _AL_AATREE { int level; _AL_AATREE *left; _AL_AATREE *right; const void *key; void *value; }; typedef int (*_al_cmp_t)(const void *a, const void *b); _AL_AATREE *_al_aa_insert(_AL_AATREE *T, const void *key, void *value, _al_cmp_t compare); void *_al_aa_search(const _AL_AATREE *T, const void *key, _al_cmp_t compare); _AL_AATREE *_al_aa_delete(_AL_AATREE *T, const void *key, _al_cmp_t compare, void **ret_value); void _al_aa_free(_AL_AATREE *T); #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_android.h000066400000000000000000000265501473414355200237520ustar00rootroot00000000000000#ifndef ALLEGRO_AINTERN_ANDROID_H #define ALLEGRO_AINTERN_ANDROID_H #include "allegro5/allegro.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/allegro_opengl.h" #include typedef struct ALLEGRO_SYSTEM_ANDROID { ALLEGRO_SYSTEM system; } ALLEGRO_SYSTEM_ANDROID; typedef struct ALLEGRO_DISPLAY_ANDROID { ALLEGRO_DISPLAY display; jobject surface_object; ALLEGRO_COND *cond; ALLEGRO_MUTEX *mutex; bool created; bool recreate; bool first_run; bool resize_acknowledge; bool resize_acknowledge2; bool halt_acknowledge; bool resumed; bool failed; bool is_destroy_display; } ALLEGRO_DISPLAY_ANDROID; ALLEGRO_SYSTEM_INTERFACE *_al_system_android_interface(void); const ALLEGRO_FILE_INTERFACE *_al_get_apk_file_vtable(void); ALLEGRO_DISPLAY_INTERFACE *_al_get_android_display_driver(void); ALLEGRO_KEYBOARD_DRIVER *_al_get_android_keyboard_driver(void); ALLEGRO_MOUSE_DRIVER *_al_get_android_mouse_driver(void); ALLEGRO_TOUCH_INPUT_DRIVER *_al_get_android_touch_input_driver(void); int _al_android_get_display_orientation(void); #define _jni_checkException(env) \ __jni_checkException(env, __FILE__, __FUNCTION__, __LINE__) void __jni_checkException(JNIEnv *env, const char *file, const char *fname, int line); #define _jni_call(env, rett, method, args...) \ ({ \ rett ret = (*env)->method(env, ##args); \ _jni_checkException(env); \ ret; \ }) #define _jni_callv(env, method, args...) \ ({ \ (*env)->method(env, ##args); \ _jni_checkException(env); \ }) #define _jni_callBooleanMethodV(env, obj, name, sig, args...) \ ({ \ jclass class_id = _jni_call(env, jclass, GetObjectClass, obj); \ jmethodID method_id = _jni_call(env, jmethodID, GetMethodID, class_id, \ name, sig); \ bool ret = false; \ if (method_id == NULL) { \ ALLEGRO_DEBUG("couldn't find method %s", name); \ } \ else { \ ret = _jni_call(env, bool, CallBooleanMethod, obj, method_id, \ ##args); \ } \ _jni_callv(env, DeleteLocalRef, class_id); \ ret; \ }) jobject _jni_callObjectMethod(JNIEnv *env, jobject object, const char *name, const char *sig); jobject _jni_callObjectMethodV(JNIEnv *env, jobject object, const char *name, const char *sig, ...); ALLEGRO_USTR *_jni_getString(JNIEnv *env, jstring str_obj); ALLEGRO_USTR *_jni_callStringMethod(JNIEnv *env, jobject obj, const char *name, const char *sig); jobject _jni_callStaticObjectMethodV(JNIEnv *env, jclass class_id, const char *name, const char *sig, ...); jint _jni_callStaticIntMethodV(JNIEnv *env, jclass cls, const char *name, const char *sig, ...); #define _jni_callIntMethodV(env, obj, name, sig, args...) \ ({ \ jclass class_id = _jni_call(env, jclass, GetObjectClass, obj); \ jmethodID method_id = _jni_call(env, jmethodID, GetMethodID, class_id, \ name, sig); \ int ret = -1; \ if (method_id == NULL) { \ ALLEGRO_DEBUG("couldn't find method %s", #name); \ } \ else { \ ret = _jni_call(env, int, CallIntMethod, obj, method_id, ##args); \ } \ _jni_callv(env, DeleteLocalRef, class_id); \ ret; \ }) #define _jni_callIntMethod(env, obj, name) \ _jni_callIntMethodV(env, obj, name, "()I") #define _jni_callLongMethodV(env, obj, name, sig, args...) \ ({ \ jclass class_id = _jni_call(env, jclass, GetObjectClass, obj); \ jmethodID method_id = _jni_call(env, jmethodID, GetMethodID, class_id, \ name, sig); \ long ret = -1; \ if (method_id == NULL) { \ ALLEGRO_DEBUG("couldn't find method %s", name); \ } \ else { \ ret = _jni_call(env, long, CallLongMethod, obj, method_id, ##args); \ } \ _jni_callv(env, DeleteLocalRef, class_id); \ ret; \ }) #define _jni_callLongMethod(env, obj, name) \ _jni_callLongMethodV(env, obj, name, "()J"); #define _jni_callVoidMethodV(env, obj, name, sig, args...) \ ({ \ jclass class_id = _jni_call(env, jclass, GetObjectClass, obj); \ jmethodID method_id = _jni_call(env, jmethodID, GetMethodID, class_id, \ name, sig); \ if (method_id == NULL) { \ ALLEGRO_ERROR("couldn't find method %s", name); \ } else { \ _jni_callv(env, CallVoidMethod, obj, method_id, ##args); \ } \ _jni_callv(env, DeleteLocalRef, class_id); \ }) #define _jni_callVoidMethod(env, obj, name) \ _jni_callVoidMethodV(env, obj, name, "()V"); AL_VAR(struct ALLEGRO_JOYSTICK_DRIVER, _al_android_joystick_driver); void _al_android_create_surface(JNIEnv *env, bool post); void _al_android_destroy_surface(JNIEnv *env, jobject obj, bool post); ALLEGRO_BITMAP *_al_android_load_image_f(ALLEGRO_FILE *fh, int flags); ALLEGRO_BITMAP *_al_android_load_image(const char *filename, int flags); jobject _al_android_activity_object(void); jclass _al_android_input_stream_class(void); jclass _al_android_apk_stream_class(void); jclass _al_android_image_loader_class(void); jclass _al_android_clipboard_class(void); jclass _al_android_apk_fs_class(void); void _al_android_generate_mouse_event(unsigned int type, int x, int y, unsigned int button, ALLEGRO_DISPLAY *d); void _al_android_mouse_get_state(ALLEGRO_MOUSE_STATE *ret_state); void _al_android_generate_accelerometer_event(float x, float y, float z); void _al_android_generate_joystick_axis_event(int index, int stick, int axis, float value); void _al_android_generate_joystick_button_event(int index, int button, bool down); GLint _al_android_get_curr_fbo(void); void _al_android_set_curr_fbo(GLint fbo); bool _al_android_is_os_2_1(void); void _al_android_thread_created(void); void _al_android_thread_ended(void); void _al_android_set_jnienv(JNIEnv *jnienv); JNIEnv *_al_android_get_jnienv(void); bool _al_android_is_paused(void); void _al_android_add_clipboard_functions(ALLEGRO_DISPLAY_INTERFACE *vt); #define ALLEGRO_ANDROID_PACKAGE_NAME org_liballeg_android #define ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "org/liballeg/android" #define JNI_FUNC_PASTER(ret, cls, name, params, x) \ JNIEXPORT ret JNICALL Java_ ## x ## _ ## cls ## _ ## name params #define JNI_FUNC_EVALUATOR(ret, cls, name, params, x) \ JNI_FUNC_PASTER(ret, cls, name, params, x) #define JNI_FUNC(ret, cls, name, params) \ JNI_FUNC_EVALUATOR(ret, cls, name, params, ALLEGRO_ANDROID_PACKAGE_NAME) /* Functions called from Java code. */ extern JNI_FUNC(bool, AllegroActivity, nativeOnCreate, (JNIEnv *env, jobject obj)); extern JNI_FUNC(void, AllegroActivity, nativeOnDestroy, (JNIEnv *env, jobject obj)); extern JNI_FUNC(void, AllegroActivity, nativeOnOrientationChange, (JNIEnv *env, jobject obj, int orientation, bool init)); extern JNI_FUNC(void, AllegroActivity, nativeOnPause, (JNIEnv *env, jobject obj)); extern JNI_FUNC(void, AllegroActivity, nativeOnResume, (JNIEnv *env, jobject obj)); extern JNI_FUNC(void, AllegroSurface, nativeOnCreate, (JNIEnv *env, jobject obj)); extern JNI_FUNC(bool, AllegroSurface, nativeOnDestroy, (JNIEnv *env, jobject obj)); extern JNI_FUNC(void, AllegroSurface, nativeOnChange, (JNIEnv *env, jobject obj, jint format, jint width, jint height)); extern JNI_FUNC(int, AllegroInputStream, nativeRead, (JNIEnv *env, jobject obj, jlong handle, jbyteArray array, int offset, int length)); extern JNI_FUNC(void, AllegroInputStream, nativeClose, (JNIEnv *env, jobject obj, jlong handle)); extern JNI_FUNC(void, KeyListener, nativeOnKeyDown, (JNIEnv *env, jobject obj, jint scancode, jint unichar)); extern JNI_FUNC(void, KeyListener, nativeOnKeyUp, (JNIEnv *env, jobject obj, jint scancode)); extern JNI_FUNC(void, KeyListener, nativeOnKeyChar, (JNIEnv *env, jobject obj, jint scancode, jint unichar)); extern JNI_FUNC(void, TouchListener, nativeOnTouch, (JNIEnv *env, jobject obj, jint id, jint action, jfloat x, jfloat y, jboolean primary)); extern JNI_FUNC(void, Sensors, nativeOnAccel, (JNIEnv *env, jobject obj, jint id, jfloat x, jfloat y, jfloat z)); extern JNI_FUNC(void, AllegroSurface, nativeOnJoystickAxis, (JNIEnv *env, jobject obj, jint index, jint stick, jint axis, jfloat value)); extern JNI_FUNC(void, AllegroSurface, nativeOnJoystickButton, (JNIEnv *env, jobject obj, jint index, jint button, jboolean down)); extern JNI_FUNC(void, KeyListener, nativeOnJoystickButton, (JNIEnv *env, jobject obj, jint index, jint button, jboolean down)); extern JNI_FUNC(void, AllegroActivity, nativeSendJoystickConfigurationEvent, (JNIEnv *env, jobject obj)); #endif /* ALLEGRO_AINTERN_ANDROID_H */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_atomicops.h000066400000000000000000000060151473414355200243220ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_atomicops_h #define __al_included_allegro5_aintern_atomicops_h #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) /* gcc 4.1 and above have builtin atomic operations. */ typedef int _AL_ATOMIC; AL_INLINE(_AL_ATOMIC, _al_fetch_and_add1, (volatile _AL_ATOMIC *ptr), { return __sync_fetch_and_add(ptr, 1); }) AL_INLINE(_AL_ATOMIC, _al_sub1_and_fetch, (volatile _AL_ATOMIC *ptr), { return __sync_sub_and_fetch(ptr, 1); }) #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) /* gcc, x86 or x86-64 */ typedef int _AL_ATOMIC; #define __al_fetch_and_add(ptr, value, result) \ __asm__ __volatile__ ( \ "lock; xaddl %0, %1" \ : "=r" (result), "=m" (*ptr) \ : "0" (value), "m" (*ptr) \ : "memory" \ ) AL_INLINE(_AL_ATOMIC, _al_fetch_and_add1, (volatile _AL_ATOMIC *ptr), { _AL_ATOMIC result; __al_fetch_and_add(ptr, 1, result); return result; }) AL_INLINE(_AL_ATOMIC, _al_sub1_and_fetch, (volatile _AL_ATOMIC *ptr), { _AL_ATOMIC old; __al_fetch_and_add(ptr, -1, old); return old - 1; }) #elif defined(_MSC_VER) && _M_IX86 >= 400 /* MSVC, x86 */ /* MinGW supports these too, but we already have asm code above. */ typedef LONG _AL_ATOMIC; AL_INLINE(_AL_ATOMIC, _al_fetch_and_add1, (volatile _AL_ATOMIC *ptr), { return InterlockedIncrement(ptr) - 1; }) AL_INLINE(_AL_ATOMIC, _al_sub1_and_fetch, (volatile _AL_ATOMIC *ptr), { return InterlockedDecrement(ptr); }) #elif defined(ALLEGRO_HAVE_OSATOMIC_H) /* OS X, GCC < 4.1 * These functions only work on Tiger (10.4) and above. * FIXME: Apple's manpage says these functions take volatile int* * arguments, but at least the 10.4 SDK seems to prototype them as * taking int * - should the volatile qualifier be removed from the * wrapper functions in this case? (EG) */ #include typedef int32_t _AL_ATOMIC; AL_INLINE(_AL_ATOMIC, _al_fetch_and_add1, (volatile _AL_ATOMIC *ptr), { return OSAtomicIncrement32Barrier((_AL_ATOMIC *)ptr) - 1; }) AL_INLINE(_AL_ATOMIC, _al_sub1_and_fetch, (volatile _AL_ATOMIC *ptr), { return OSAtomicDecrement32Barrier((_AL_ATOMIC *)ptr); }) #else /* Hope for the best? */ #warning Atomic operations undefined for your compiler/architecture. typedef int _AL_ATOMIC; AL_INLINE(_AL_ATOMIC, _al_fetch_and_add1, (volatile _AL_ATOMIC *ptr), { return (*ptr)++; }) AL_INLINE(_AL_ATOMIC, _al_sub1_and_fetch, (volatile _AL_ATOMIC *ptr), { return --(*ptr); }) #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_bitmap.h000066400000000000000000000136701473414355200236050ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_bitmap_h #define __al_included_allegro5_aintern_bitmap_h #include "allegro5/bitmap.h" #include "allegro5/bitmap_lock.h" #include "allegro5/display.h" #include "allegro5/render_state.h" #include "allegro5/transformations.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_list.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_BITMAP_INTERFACE ALLEGRO_BITMAP_INTERFACE; struct ALLEGRO_BITMAP { ALLEGRO_BITMAP_INTERFACE *vt; /* * When this is a sub-bitmap, these are inherited from the parent. Don't * access them directly, but use al_get_bitmap_format/flags or * _al_get_bitmap_display unless you are super sure this is not a sub-bitmap * (e.g. when you're creating a new bitmap). */ int _format; int _flags; int _depth; int _samples; ALLEGRO_DISPLAY *_display; ALLEGRO_BITMAP_WRAP _wrap_u; ALLEGRO_BITMAP_WRAP _wrap_v; /* What format is used for the backing memory * (can be different from _format, for e.g. compressed bitmaps) */ int _memory_format; int w, h; /* * The number of bytes between a pixel at (x,y) and (x,y+1). * This is larger than w * pixel_size if there is padding between lines. */ int pitch; /* * clip left, right, top, bottom * Clip anything outside of this. cr/cb are exclusive, that is (0, 0, 1, 1) * is the single pixel spawning a rectangle from floating point 0/0 to 1/1 - * or in other words, the single pixel 0/0. * * There is always confusion as to whether cr/cb are exclusive, leading to * subtle bugs. The suffixes are supposed to help with that. */ int cl; int cr_excl; int ct; int cb_excl; /* * Locking info. * * These values represent the actual locking dimensions, which may be different * from what was passed in to al_lock_bitmap_region. This is transparent to the * user, but the internal drawing functions must take this into account. To * that end, use this lock_data parameter value and NOT the one in locked_region. * * locked - locked or not? * lock_x/y - top left of the locked region * lock_w/h - width and height of the locked region * lock_flags - flags the region was locked with * lock_data - the pointer to the real locked data (see above) * locked_region - a copy of the locked rectangle */ bool locked; int lock_x; int lock_y; int lock_w; int lock_h; void* lock_data; int lock_flags; ALLEGRO_LOCKED_REGION locked_region; /* Transformation for this bitmap */ ALLEGRO_TRANSFORM transform; ALLEGRO_TRANSFORM inverse_transform; bool inverse_transform_dirty; ALLEGRO_TRANSFORM proj_transform; /* Blender for this bitmap (if not set, use TLS) */ bool use_bitmap_blender; ALLEGRO_BLENDER blender; /* Shader applied to this bitmap. Set this field with * _al_set_bitmap_shader_field to maintain invariants. */ ALLEGRO_SHADER *shader; /* Info for sub-bitmaps */ ALLEGRO_BITMAP *parent; int xofs; int yofs; /* A memory copy of the bitmap data. May be NULL for an empty bitmap. */ unsigned char *memory; /* Extra data for display bitmaps, like texture id and so on. */ void *extra; _AL_LIST_ITEM *dtor_item; /* set_target_bitmap and lock_bitmap mark bitmaps as dirty for preservation */ bool dirty; }; struct ALLEGRO_BITMAP_INTERFACE { int id; void (*draw_bitmap_region)(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint,float sx, float sy, float sw, float sh, int flags); /* After the memory-copy of the bitmap has been modified, need to call this * to update the display-specific copy. E.g. with an OpenGL driver, this * might create/update a texture. Returns false on failure. */ bool (*upload_bitmap)(ALLEGRO_BITMAP *bitmap); void (*update_clipping_rectangle)(ALLEGRO_BITMAP *bitmap); void (*destroy_bitmap)(ALLEGRO_BITMAP *bitmap); ALLEGRO_LOCKED_REGION * (*lock_region)(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int format, int flags); void (*unlock_region)(ALLEGRO_BITMAP *bitmap); ALLEGRO_LOCKED_REGION * (*lock_compressed_region)(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int flags); void (*unlock_compressed_region)(ALLEGRO_BITMAP *bitmap); /* Used to update any dangling pointers the bitmap driver might keep. */ void (*bitmap_pointer_changed)(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP *old); /* Back up texture to system RAM */ void (*backup_dirty_bitmap)(ALLEGRO_BITMAP *bitmap); }; ALLEGRO_BITMAP *_al_create_bitmap_params(ALLEGRO_DISPLAY *current_display, int w, int h, int format, int flags, int depth, int samples); AL_FUNC(ALLEGRO_DISPLAY*, _al_get_bitmap_display, (ALLEGRO_BITMAP *bitmap)); AL_FUNC(void, _al_get_bitmap_wrap, (ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_WRAP *wrap_u, ALLEGRO_BITMAP_WRAP *wrap_v)); extern void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS] [ALLEGRO_NUM_PIXEL_FORMATS])(const void *, int, void *, int, int, int, int, int, int, int); /* Bitmap conversion */ void _al_convert_bitmap_data( const void *src, int src_format, int src_pitch, void *dst, int dst_format, int dst_pitch, int sx, int sy, int dx, int dy, int width, int height); void _al_copy_bitmap_data( const void *src, int src_pitch, void *dst, int dst_pitch, int sx, int sy, int dx, int dy, int width, int height, int format); /* Bitmap type conversion */ void _al_init_convert_bitmap_list(void); void _al_register_convert_bitmap(ALLEGRO_BITMAP *bitmap); void _al_unregister_convert_bitmap(ALLEGRO_BITMAP *bitmap); void _al_convert_to_display_bitmap(ALLEGRO_BITMAP *bitmap); void _al_convert_to_memory_bitmap(ALLEGRO_BITMAP *bitmap); /* Simple bitmap drawing */ void _al_put_pixel(ALLEGRO_BITMAP *bitmap, int x, int y, ALLEGRO_COLOR color); /* Bitmap I/O */ void _al_init_iio_table(void); int _al_get_bitmap_memory_format(ALLEGRO_BITMAP *bitmap); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_blend.h000066400000000000000000000162101473414355200234060ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_blend_h #define __al_included_allegro5_aintern_blend_h #include "allegro5/internal/aintern.h" #ifdef __cplusplus extern "C" { #endif #ifdef __GNUC__ #define _AL_ALWAYS_INLINE inline __attribute__((always_inline)) #else #define _AL_ALWAYS_INLINE INLINE #endif #define _AL_DEST_IS_ZERO \ (dst_mode == ALLEGRO_ZERO && dst_alpha == ALLEGRO_ZERO && \ op != ALLEGRO_DEST_MINUS_SRC && op_alpha != ALLEGRO_DEST_MINUS_SRC) #define _AL_SRC_NOT_MODIFIED \ (src_mode == ALLEGRO_ONE && src_alpha == ALLEGRO_ONE) #define _AL_SRC_NOT_MODIFIED_TINT_WHITE \ (_AL_SRC_NOT_MODIFIED && \ tint.r == 1.0f && tint.g == 1.0f && tint.b == 1.0f && tint.a == 1.0f) #ifndef _AL_NO_BLEND_INLINE_FUNC /* Only cares about alpha blending modes. */ static _AL_ALWAYS_INLINE float get_alpha_factor(enum ALLEGRO_BLEND_MODE operation, float src_alpha, float dst_alpha, ALLEGRO_COLOR* const_alpha) { switch (operation) { case ALLEGRO_ZERO: return 0; case ALLEGRO_ONE: return 1; case ALLEGRO_ALPHA: return src_alpha; case ALLEGRO_INVERSE_ALPHA: return 1 - src_alpha; case ALLEGRO_SRC_COLOR: return src_alpha; case ALLEGRO_DEST_COLOR: return dst_alpha; case ALLEGRO_INVERSE_SRC_COLOR: return 1 - src_alpha; case ALLEGRO_INVERSE_DEST_COLOR: return 1 - dst_alpha; case ALLEGRO_CONST_COLOR: return const_alpha->a; case ALLEGRO_INVERSE_CONST_COLOR: return 1 - const_alpha->a; default: ASSERT(false); return 0; /* silence warning in release build */ } } /* Puts the blending factor in an ALLEGRO_COLOR object. */ static _AL_ALWAYS_INLINE void get_factor(enum ALLEGRO_BLEND_MODE operation, const ALLEGRO_COLOR *source, const ALLEGRO_COLOR *dest, ALLEGRO_COLOR *constcol, ALLEGRO_COLOR *factor) { switch (operation) { case ALLEGRO_ZERO: factor->r = factor->g = factor->b = factor->a = 0; break; case ALLEGRO_ONE: factor->r = factor->g = factor->b = factor->a = 1; break; case ALLEGRO_ALPHA: factor->r = factor->g = factor->b = factor->a = source->a; break; case ALLEGRO_INVERSE_ALPHA: factor->r = factor->g = factor->b = factor->a = 1 - source->a; break; case ALLEGRO_SRC_COLOR: *factor = *source; break; case ALLEGRO_DEST_COLOR: *factor = *dest; break; case ALLEGRO_INVERSE_SRC_COLOR: factor->r = 1 - source->r; factor->g = 1 - source->g; factor->b = 1 - source->b; factor->a = 1 - source->a; break; case ALLEGRO_INVERSE_DEST_COLOR: factor->r = 1 - dest->r; factor->g = 1 - dest->g; factor->b = 1 - dest->b; factor->a = 1 - dest->a; break; case ALLEGRO_CONST_COLOR: *factor = *constcol; break; case ALLEGRO_INVERSE_CONST_COLOR: factor->r = 1 - constcol->r; factor->g = 1 - constcol->g; factor->b = 1 - constcol->b; factor->a = 1 - constcol->a; break; default: ASSERT(false); factor->r = factor->g = factor->b = factor->a = 0; break; } } /* Only call this if the blend modes are one of: * ALLEGRO_ONE, ALLEGRO_ZERO, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA */ static _AL_ALWAYS_INLINE void _al_blend_alpha_inline( const ALLEGRO_COLOR *scol, const ALLEGRO_COLOR *dcol, int op, int src_, int dst_, int aop, int asrc_, int adst_, ALLEGRO_COLOR *constcol, ALLEGRO_COLOR *result) { float asrc, adst; float src, dst; result->r = scol->r; result->g = scol->g; result->b = scol->b; result->a = scol->a; asrc = get_alpha_factor(asrc_, scol->a, dcol->a, constcol); adst = get_alpha_factor(adst_, scol->a, dcol->a, constcol); src = get_alpha_factor(src_, scol->a, dcol->a, constcol); dst = get_alpha_factor(dst_, scol->a, dcol->a, constcol); #define BLEND(c, src, dst) \ result->c = OP(result->c * src, dcol->c * dst); switch (op) { case ALLEGRO_ADD: #define OP(x, y) _ALLEGRO_MIN(1, x + y) BLEND(r, src, dst) BLEND(g, src, dst) BLEND(b, src, dst) #undef OP break; case ALLEGRO_SRC_MINUS_DEST: #define OP(x, y) _ALLEGRO_MAX(0, x - y) BLEND(r, src, dst) BLEND(g, src, dst) BLEND(b, src, dst) #undef OP break; case ALLEGRO_DEST_MINUS_SRC: #define OP(x, y) _ALLEGRO_MAX(0, y - x) BLEND(r, src, dst) BLEND(g, src, dst) BLEND(b, src, dst) #undef OP break; } switch (aop) { case ALLEGRO_ADD: #define OP(x, y) _ALLEGRO_MIN(1, x + y) BLEND(a, asrc, adst) #undef OP break; case ALLEGRO_SRC_MINUS_DEST: #define OP(x, y) _ALLEGRO_MAX(0, x - y) BLEND(a, asrc, adst) #undef OP break; case ALLEGRO_DEST_MINUS_SRC: #define OP(x, y) _ALLEGRO_MAX(0, y - x) BLEND(a, asrc, adst) #undef OP break; } #undef BLEND } /* call this for general blending. its a little slower than just using alpha */ static _AL_ALWAYS_INLINE void _al_blend_inline( const ALLEGRO_COLOR *scol, const ALLEGRO_COLOR *dcol, int op, int src_, int dst_, int aop, int asrc_, int adst_, ALLEGRO_COLOR *constcol, ALLEGRO_COLOR *result) { float asrc, adst; ALLEGRO_COLOR src, dst; result->r = scol->r; result->g = scol->g; result->b = scol->b; result->a = scol->a; asrc = get_alpha_factor(asrc_, scol->a, dcol->a, constcol); adst = get_alpha_factor(adst_, scol->a, dcol->a, constcol); get_factor(src_, scol, dcol, constcol, &src); get_factor(dst_, scol, dcol, constcol, &dst); #define BLEND(c, src, dst) \ result->c = OP(result->c * src.c, dcol->c * dst.c); switch (op) { case ALLEGRO_ADD: #define OP(x, y) _ALLEGRO_MIN(1, x + y) BLEND(r, src, dst) BLEND(g, src, dst) BLEND(b, src, dst) #undef OP break; case ALLEGRO_SRC_MINUS_DEST: #define OP(x, y) _ALLEGRO_MAX(0, x - y) BLEND(r, src, dst) BLEND(g, src, dst) BLEND(b, src, dst) #undef OP break; case ALLEGRO_DEST_MINUS_SRC: #define OP(x, y) _ALLEGRO_MAX(0, y - x) BLEND(r, src, dst) BLEND(g, src, dst) BLEND(b, src, dst) #undef OP break; } #undef BLEND #define BLEND(c, src, dst) \ result->c = OP(result->c * src, dcol->c * dst); switch (aop) { case ALLEGRO_ADD: #define OP(x, y) _ALLEGRO_MIN(1, x + y) BLEND(a, asrc, adst) #undef OP break; case ALLEGRO_SRC_MINUS_DEST: #define OP(x, y) _ALLEGRO_MAX(0, x - y) BLEND(a, asrc, adst) #undef OP break; case ALLEGRO_DEST_MINUS_SRC: #define OP(x, y) _ALLEGRO_MAX(0, y - x) BLEND(a, asrc, adst) #undef OP break; } #undef BLEND } #endif void _al_blend_memory(ALLEGRO_COLOR *src_color, ALLEGRO_BITMAP *dest, int dx, int dy, ALLEGRO_COLOR *result); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_config.h000066400000000000000000000011631473414355200235700ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_config_h #define __al_included_allegro5_aintern_config_h #include "allegro5/internal/aintern_aatree.h" struct ALLEGRO_CONFIG_ENTRY { bool is_comment; ALLEGRO_USTR *key; /* comment if is_comment is true */ ALLEGRO_USTR *value; ALLEGRO_CONFIG_ENTRY *prev, *next; }; struct ALLEGRO_CONFIG_SECTION { ALLEGRO_USTR *name; ALLEGRO_CONFIG_ENTRY *head; ALLEGRO_CONFIG_ENTRY *last; _AL_AATREE *tree; ALLEGRO_CONFIG_SECTION *prev, *next; }; struct ALLEGRO_CONFIG { ALLEGRO_CONFIG_SECTION *head; ALLEGRO_CONFIG_SECTION *last; _AL_AATREE *tree; }; #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_debug.h000066400000000000000000000003641473414355200234130ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_debug_h #define __al_included_allegro5_aintern_debug_h #ifdef __cplusplus extern "C" { #endif void _al_configure_logging(void); void _al_shutdown_logging(void); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_direct3d.h000066400000000000000000000053321473414355200240260ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_direct3d_h #define __al_included_allegro5_aintern_direct3d_h #include "allegro5/platform/alplatf.h" #include "allegro5/allegro_direct3d.h" #include "allegro5/platform/aintwin.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_BITMAP_EXTRA_D3D { /* Driver specifics. */ unsigned int texture_w; unsigned int texture_h; LPDIRECT3DTEXTURE9 video_texture; LPDIRECT3DTEXTURE9 system_texture; int system_format; bool initialized; bool is_backbuffer; D3DLOCKED_RECT locked_rect; struct ALLEGRO_DISPLAY_D3D *display; IDirect3DSurface9 *render_target; bool dirty; } ALLEGRO_BITMAP_EXTRA_D3D; typedef struct ALLEGRO_DISPLAY_D3D { ALLEGRO_DISPLAY_WIN win_display; /* This must be the first member. */ bool es_inited; /* Driver specifics */ LPDIRECT3DDEVICE9 device; LPDIRECT3DSURFACE9 render_target; bool do_reset; bool reset_done; bool reset_success; ALLEGRO_BITMAP backbuffer_bmp; ALLEGRO_BITMAP_EXTRA_D3D backbuffer_bmp_extra; /* Contains the target video bitmap for this display. */ ALLEGRO_BITMAP* target_bitmap; bool device_lost; bool suppress_lost_events; bool faux_fullscreen; bool supports_separate_alpha_blend; TCHAR *device_name; int format; D3DFORMAT depth_stencil_format; int samples; bool single_buffer; bool vsync; int blender_state_op; int blender_state_src; int blender_state_dst; int blender_state_alpha_op; int blender_state_alpha_src; int blender_state_alpha_dst; RECT scissor_state; #ifdef ALLEGRO_CFG_SHADER_HLSL LPD3DXEFFECT effect; #endif } ALLEGRO_DISPLAY_D3D; AL_FUNC(void, _al_d3d_set_blender, (ALLEGRO_DISPLAY_D3D *disp)); AL_FUNC(void, _al_set_d3d_sampler_state, (IDirect3DDevice9* device, int sampler, ALLEGRO_BITMAP* bitmap, bool prim_default)); void _al_d3d_destroy_bitmap(ALLEGRO_BITMAP *bitmap); void _al_d3d_update_render_state(ALLEGRO_DISPLAY *display); #ifdef ALLEGRO_CFG_SHADER_HLSL bool _al_hlsl_set_projview_matrix(LPD3DXEFFECT effect, const ALLEGRO_TRANSFORM *t); #endif #ifdef ALLEGRO_CFG_D3DX9 typedef HRESULT (WINAPI *_ALLEGRO_D3DXLSFLSPROC)(LPDIRECT3DSURFACE9, const PALETTEENTRY*, const RECT*, LPDIRECT3DSURFACE9, const PALETTEENTRY*, const RECT*, DWORD, D3DCOLOR); typedef HRESULT (WINAPI *_ALLEGRO_D3DXCREATEEFFECTPROC)(LPDIRECT3DDEVICE9, LPCVOID, UINT, CONST D3DXMACRO*, LPD3DXINCLUDE, DWORD, LPD3DXEFFECTPOOL, LPD3DXEFFECT*, LPD3DXBUFFER*); bool _al_load_d3dx9_module(); void _al_unload_d3dx9_module(); extern _ALLEGRO_D3DXLSFLSPROC _al_imp_D3DXLoadSurfaceFromSurface; extern _ALLEGRO_D3DXCREATEEFFECTPROC _al_imp_D3DXCreateEffect; #endif #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_display.h000066400000000000000000000152141473414355200237720ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_display_h #define __al_included_allegro5_aintern_display_h #include "allegro5/allegro.h" #include "allegro5/transformations.h" #include "allegro5/display.h" #include "allegro5/bitmap.h" #include "allegro5/internal/aintern_events.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_DISPLAY_INTERFACE ALLEGRO_DISPLAY_INTERFACE; struct ALLEGRO_DISPLAY_INTERFACE { int id; ALLEGRO_DISPLAY *(*create_display)(int w, int h); void (*destroy_display)(ALLEGRO_DISPLAY *display); bool (*set_current_display)(ALLEGRO_DISPLAY *d); void (*unset_current_display)(ALLEGRO_DISPLAY *d); void (*clear)(ALLEGRO_DISPLAY *d, ALLEGRO_COLOR *color); void (*draw_pixel)(ALLEGRO_DISPLAY *d, float x, float y, ALLEGRO_COLOR *color); void (*flip_display)(ALLEGRO_DISPLAY *d); void (*update_display_region)(ALLEGRO_DISPLAY *d, int x, int y, int width, int height); bool (*acknowledge_resize)(ALLEGRO_DISPLAY *d); bool (*resize_display)(ALLEGRO_DISPLAY *d, int width, int height); void (*quick_size)(ALLEGRO_DISPLAY *d); int (*get_orientation)(ALLEGRO_DISPLAY *d); ALLEGRO_BITMAP *(*create_bitmap)(ALLEGRO_DISPLAY *d, int w, int h, int format, int flags); void (*set_target_bitmap)(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap); ALLEGRO_BITMAP *(*get_backbuffer)(ALLEGRO_DISPLAY *d); bool (*is_compatible_bitmap)(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap); void (*switch_out)(ALLEGRO_DISPLAY *display); void (*switch_in)(ALLEGRO_DISPLAY *display); void (*draw_memory_bitmap_region)(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap, float sx, float sy, float sw, float sh, int flags); bool (*wait_for_vsync)(ALLEGRO_DISPLAY *display); bool (*set_mouse_cursor)(ALLEGRO_DISPLAY *display, ALLEGRO_MOUSE_CURSOR *cursor); bool (*set_system_mouse_cursor)(ALLEGRO_DISPLAY *display, ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id); bool (*show_mouse_cursor)(ALLEGRO_DISPLAY *display); bool (*hide_mouse_cursor)(ALLEGRO_DISPLAY *display); void (*set_icons)(ALLEGRO_DISPLAY *display, int num_icons, ALLEGRO_BITMAP *bitmap[]); void (*set_window_position)(ALLEGRO_DISPLAY *display, int x, int y); void (*get_window_position)(ALLEGRO_DISPLAY *display, int *x, int *y); bool (*get_window_borders)(ALLEGRO_DISPLAY *display, int *left, int *top, int *right, int *bottom); bool (*set_window_constraints)(ALLEGRO_DISPLAY *display, int min_w, int min_h, int max_w, int max_h); bool (*get_window_constraints)(ALLEGRO_DISPLAY *display, int *min_w, int *min_h, int *max_w, int *max_h); bool (*set_display_flag)(ALLEGRO_DISPLAY *display, int flag, bool onoff); void (*set_window_title)(ALLEGRO_DISPLAY *display, const char *title); void (*flush_vertex_cache)(ALLEGRO_DISPLAY *d); void* (*prepare_vertex_cache)(ALLEGRO_DISPLAY *d, int num_new_vertices); void (*update_transformation)(ALLEGRO_DISPLAY* d, ALLEGRO_BITMAP *target); /* Unused */ void (*shutdown)(void); void (*acknowledge_drawing_halt)(ALLEGRO_DISPLAY *d); void (*acknowledge_drawing_resume)(ALLEGRO_DISPLAY *d); void (*set_display_option)(ALLEGRO_DISPLAY *display, int option, int val); void (*clear_depth_buffer)(ALLEGRO_DISPLAY *display, float x); void (*update_render_state)(ALLEGRO_DISPLAY *display); char *(*get_clipboard_text)(ALLEGRO_DISPLAY *display); bool (*set_clipboard_text)(ALLEGRO_DISPLAY *display, const char *text); bool (*has_clipboard_text)(ALLEGRO_DISPLAY *display); /* Issue #725 */ void (*apply_window_constraints)(ALLEGRO_DISPLAY *display, bool onoff); }; struct ALLEGRO_OGL_EXTRAS; typedef struct ALLEGRO_BLENDER { int blend_op; int blend_source; int blend_dest; int blend_alpha_op; int blend_alpha_source; int blend_alpha_dest; ALLEGRO_COLOR blend_color; } ALLEGRO_BLENDER; typedef struct _ALLEGRO_RENDER_STATE { int write_mask; int depth_test, depth_function; int alpha_test, alpha_function, alpha_test_value; } _ALLEGRO_RENDER_STATE; /* These are settings Allegro itself doesn't really care about on its * own, but which users may want to specify for a display anyway. */ ALLEGRO_STATIC_ASSERT(aintern_display, ALLEGRO_DISPLAY_OPTIONS_COUNT <= 64); typedef struct { int64_t required, suggested; /* Bitfields. */ int settings[ALLEGRO_DISPLAY_OPTIONS_COUNT]; /* These are come in handy when creating a context. */ void *info; int index, score; } ALLEGRO_EXTRA_DISPLAY_SETTINGS; struct ALLEGRO_DISPLAY { /* Must be first, so the display can be used as event source. */ ALLEGRO_EVENT_SOURCE es; ALLEGRO_DISPLAY_INTERFACE *vt; int refresh_rate; int flags; int w, h; int min_w, min_h; int max_w, max_h; int backbuffer_format; /* ALLEGRO_PIXELFORMAT */ ALLEGRO_EXTRA_DISPLAY_SETTINGS extra_settings; struct ALLEGRO_OGL_EXTRAS *ogl_extras; /* A list of bitmaps created for this display, sub-bitmaps not included. */ _AL_VECTOR bitmaps; int num_cache_vertices; bool cache_enabled; int vertex_cache_size; void* vertex_cache; uintptr_t cache_texture; ALLEGRO_BLENDER cur_blender; ALLEGRO_SHADER* default_shader; ALLEGRO_TRANSFORM projview_transform; _ALLEGRO_RENDER_STATE render_state; _AL_VECTOR display_invalidated_callbacks; _AL_VECTOR display_validated_callbacks; /* Issue #725 */ bool use_constraints; }; int _al_score_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds, ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref); void _al_fill_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds); void _al_set_color_components(int format, ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds, int importance); int _al_deduce_color_format(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds); int _al_display_settings_sorter(const void *p0, const void *p1); int _al_get_suggested_display_option(ALLEGRO_DISPLAY *d, int option, int default_value); /* This is called from the primitives addon and for shaders. */ AL_FUNC(void, _al_add_display_invalidated_callback, (ALLEGRO_DISPLAY *display, void (*display_invalidated)(ALLEGRO_DISPLAY*))); AL_FUNC(void, _al_add_display_validated_callback, (ALLEGRO_DISPLAY *display, void (*display_validated)(ALLEGRO_DISPLAY*))); AL_FUNC(void, _al_remove_display_invalidated_callback, (ALLEGRO_DISPLAY *display, void (*display_invalidated)(ALLEGRO_DISPLAY*))); AL_FUNC(void, _al_remove_display_validated_callback, (ALLEGRO_DISPLAY *display, void (*display_validated)(ALLEGRO_DISPLAY*))); /* Defined in tls.c */ bool _al_set_current_display_only(ALLEGRO_DISPLAY *display); void _al_set_new_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS *settings); ALLEGRO_EXTRA_DISPLAY_SETTINGS *_al_get_new_display_settings(void); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_driver.h000066400000000000000000000006221473414355200236150ustar00rootroot00000000000000#ifndef __al_included_allegro5_internal_aintern_driver_h #define __al_included_allegro5_internal_aintern_driver_h typedef struct _AL_DRIVER_INFO /* info about a hardware driver */ { int id; /* integer ID */ void *driver; /* the driver structure */ int autodetect; /* set to allow autodetection */ } _AL_DRIVER_INFO; #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_dtor.h000066400000000000000000000020151473414355200232700ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_dtor_h #define __al_included_allegro5_aintern_dtor_h #include "allegro5/internal/aintern_list.h" #ifdef __cplusplus extern "C" { #endif typedef struct _AL_DTOR_LIST _AL_DTOR_LIST; AL_FUNC(_AL_DTOR_LIST *, _al_init_destructors, (void)); AL_FUNC(void, _al_push_destructor_owner, (void)); AL_FUNC(void, _al_pop_destructor_owner, (void)); AL_FUNC(void, _al_run_destructors, (_AL_DTOR_LIST *dtors)); AL_FUNC(void, _al_shutdown_destructors, (_AL_DTOR_LIST *dtors)); AL_FUNC(_AL_LIST_ITEM*, _al_register_destructor, (_AL_DTOR_LIST *dtors, char const *name, void *object, void (*func)(void*))); AL_FUNC(void, _al_unregister_destructor, (_AL_DTOR_LIST *dtors, _AL_LIST_ITEM* dtor_item)); AL_FUNC(void, _al_foreach_destructor, (_AL_DTOR_LIST *dtors, void (*callback)(void *object, void (*func)(void *), void *udata), void *userdata)); #ifdef __cplusplus } #endif #endif /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_events.h000066400000000000000000000023561473414355200236340ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_events_h #define __al_included_allegro5_aintern_events_h #include "allegro5/internal/aintern_thread.h" #include "allegro5/internal/aintern_vector.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_EVENT_SOURCE_REAL ALLEGRO_EVENT_SOURCE_REAL; struct ALLEGRO_EVENT_SOURCE_REAL { _AL_MUTEX mutex; _AL_VECTOR queues; intptr_t data; }; typedef struct ALLEGRO_USER_EVENT_DESCRIPTOR { void (*dtor)(ALLEGRO_USER_EVENT *event); int refcount; } ALLEGRO_USER_EVENT_DESCRIPTOR; void _al_init_events(void); void _al_event_source_init(ALLEGRO_EVENT_SOURCE*); void _al_event_source_free(ALLEGRO_EVENT_SOURCE*); void _al_event_source_lock(ALLEGRO_EVENT_SOURCE*); void _al_event_source_unlock(ALLEGRO_EVENT_SOURCE*); void _al_event_source_on_registration_to_queue(ALLEGRO_EVENT_SOURCE*, ALLEGRO_EVENT_QUEUE*); void _al_event_source_on_unregistration_from_queue(ALLEGRO_EVENT_SOURCE*, ALLEGRO_EVENT_QUEUE*); bool _al_event_source_needs_to_generate_event(ALLEGRO_EVENT_SOURCE*); void _al_event_source_emit_event(ALLEGRO_EVENT_SOURCE *, ALLEGRO_EVENT*); void _al_event_queue_push_event(ALLEGRO_EVENT_QUEUE*, const ALLEGRO_EVENT*); #ifdef __cplusplus } #endif #endif /* vi ts=8 sts=3 sw=3 et */ allegro5-5.2.10.1/include/allegro5/internal/aintern_exitfunc.h000066400000000000000000000006631473414355200241540ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_exitfunc_h #define __al_included_allegro5_aintern_exitfunc_h #ifdef __cplusplus extern "C" { #endif /* list of functions to call at program cleanup */ AL_FUNC(void, _al_add_exit_func, (AL_METHOD(void, func, (void)), const char *desc)); AL_FUNC(void, _al_remove_exit_func, (AL_METHOD(void, func, (void)))); AL_FUNC(void, _al_run_exit_funcs, (void)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_file.h000066400000000000000000000007051473414355200232430ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_file_h #define __al_included_allegro5_aintern_file_h #ifdef __cplusplus extern "C" { #endif extern const ALLEGRO_FILE_INTERFACE _al_file_interface_stdio; #define ALLEGRO_UNGETC_SIZE 16 struct ALLEGRO_FILE { const ALLEGRO_FILE_INTERFACE *vtable; void *userdata; unsigned char ungetc[ALLEGRO_UNGETC_SIZE]; int ungetc_len; }; #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_float.h000066400000000000000000000011101473414355200234200ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_float_h #define __al_included_allegro5_aintern_float_h /* This file used to contain a tricky function that sped up float->int * conversions on x86 machines when the SSE instruction CVTTSS2SI wasn't * available (or when SSE wasn't enabled in the compiler). * * However, it performed rounding instead of truncating like (int)f, which * did cause problems. If an alternative is found we could define this * macro once again. */ #define _al_fast_float_to_int(f) ((int)(f)) #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_fshook.h000066400000000000000000000015301473414355200236120ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Internal File System Hook support. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_aintern_fshook_h #define __al_included_allegro5_aintern_fshook_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif extern struct ALLEGRO_FS_INTERFACE _al_fs_interface_stdio; #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_gp2xwiz.h000066400000000000000000000030101473414355200237260ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_gp2xwiz_h #define __al_included_allegro5_aintern_gp2xwiz_h #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/platform/aintwiz.h" #include "allegro5/internal/aintern_opengl.h" #include typedef struct ALLEGRO_SYSTEM_GP2XWIZ ALLEGRO_SYSTEM_GP2XWIZ; typedef struct ALLEGRO_DISPLAY_GP2XWIZ_OGL ALLEGRO_DISPLAY_GP2XWIZ_OGL; typedef struct ALLEGRO_DISPLAY_GP2XWIZ_FB ALLEGRO_DISPLAY_GP2XWIZ_FB; struct ALLEGRO_SYSTEM_GP2XWIZ { ALLEGRO_SYSTEM system; /* This must be the first member, we "derive" from it. */ ALLEGRO_EXTRA_DISPLAY_SETTINGS extras; }; /* This is our version of ALLEGRO_DISPLAY with driver specific extra data. */ struct ALLEGRO_DISPLAY_GP2XWIZ_OGL { ALLEGRO_DISPLAY display; /* This must be the first member. */ EGLDisplay egl_display; EGLConfig egl_config; EGLContext egl_context; EGLSurface egl_surface; NativeWindowType hNativeWnd; }; /* This is our version of ALLEGRO_DISPLAY with driver specific extra data. */ struct ALLEGRO_DISPLAY_GP2XWIZ_FB { ALLEGRO_DISPLAY display; /* This must be the first member. */ ALLEGRO_BITMAP *backbuffer; /* * We create the backbuffer bitmap then points it's ->memory at * lc_fb1 (initialized with libcastor. This is a backup of the * ->memory as created by al_create_bitmap. */ unsigned char *screen_mem; }; #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_haptic.h000066400000000000000000000062221473414355200235740ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_haptic_h #define __al_included_allegro5_aintern_haptic_h #include "allegro5/haptic.h" #include "allegro5/internal/aintern_driver.h" #include "allegro5/internal/aintern_events.h" #ifdef __cplusplus extern "C" { #endif #if defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) typedef struct ALLEGRO_HAPTIC_DRIVER { int hapdrv_id; const char *hapdrv_name; const char *hapdrv_desc; const char *hapdrv_ascii_name; AL_METHOD(bool, init_haptic, (void)); AL_METHOD(void, exit_haptic, (void)); AL_METHOD(bool, is_mouse_haptic, (ALLEGRO_MOUSE *)); AL_METHOD(bool, is_joystick_haptic, (ALLEGRO_JOYSTICK *)); AL_METHOD(bool, is_keyboard_haptic, (ALLEGRO_KEYBOARD *)); AL_METHOD(bool, is_display_haptic, (ALLEGRO_DISPLAY *)); AL_METHOD(bool, is_touch_input_haptic, (ALLEGRO_TOUCH_INPUT *)); AL_METHOD(ALLEGRO_HAPTIC *, get_from_mouse, (ALLEGRO_MOUSE *)); AL_METHOD(ALLEGRO_HAPTIC *, get_from_joystick, (ALLEGRO_JOYSTICK *)); AL_METHOD(ALLEGRO_HAPTIC *, get_from_keyboard, (ALLEGRO_KEYBOARD *)); AL_METHOD(ALLEGRO_HAPTIC *, get_from_display, (ALLEGRO_DISPLAY *)); AL_METHOD(ALLEGRO_HAPTIC *, get_from_touch_input, (ALLEGRO_TOUCH_INPUT *)); AL_METHOD(bool, get_active, (ALLEGRO_HAPTIC *)); AL_METHOD(int, get_capabilities, (ALLEGRO_HAPTIC *)); AL_METHOD(double, get_gain, (ALLEGRO_HAPTIC *)); AL_METHOD(bool, set_gain, (ALLEGRO_HAPTIC *, double)); AL_METHOD(int, get_max_effects, (ALLEGRO_HAPTIC *)); AL_METHOD(bool, is_effect_ok, (ALLEGRO_HAPTIC *, ALLEGRO_HAPTIC_EFFECT *)); AL_METHOD(bool, upload_effect, (ALLEGRO_HAPTIC *, ALLEGRO_HAPTIC_EFFECT *, ALLEGRO_HAPTIC_EFFECT_ID *)); AL_METHOD(bool, play_effect, (ALLEGRO_HAPTIC_EFFECT_ID *, int)); AL_METHOD(bool, stop_effect, (ALLEGRO_HAPTIC_EFFECT_ID *)); AL_METHOD(bool, is_effect_playing, (ALLEGRO_HAPTIC_EFFECT_ID *)); AL_METHOD(bool, release_effect, (ALLEGRO_HAPTIC_EFFECT_ID *)); AL_METHOD(bool, release, (ALLEGRO_HAPTIC *)); AL_METHOD(double, get_autocenter, (ALLEGRO_HAPTIC *)); AL_METHOD(bool, set_autocenter, (ALLEGRO_HAPTIC *, double)); } ALLEGRO_HAPTIC_DRIVER; enum ALLEGRO_HAPTIC_PARENT { _AL_HAPTIC_FROM_JOYSTICK = 1, _AL_HAPTIC_FROM_MOUSE, _AL_HAPTIC_FROM_KEYBOARD, _AL_HAPTIC_FROM_DISPLAY, _AL_HAPTIC_FROM_TOUCH_INPUT }; /* haptic has a driver field for per-device drivers on some platforms. */ struct ALLEGRO_HAPTIC { enum ALLEGRO_HAPTIC_PARENT from; void *device; double gain; double autocenter; ALLEGRO_HAPTIC_DRIVER *driver; }; /* Haptic driver list. */ extern const _AL_DRIVER_INFO _al_haptic_driver_list[]; /* Macros for constructing the driver list */ #define _AL_BEGIN_HAPTIC_DRIVER_LIST \ const _AL_DRIVER_INFO _al_haptic_driver_list[] = \ { #define _AL_END_HAPTIC_DRIVER_LIST \ { 0, NULL, false } \ }; #else /* Forward declare it for ALLEGRO_SYSTEM_INTERFACE. */ typedef struct ALLEGRO_HAPTIC_DRIVER ALLEGRO_HAPTIC_DRIVER; #endif #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_iphone.h000066400000000000000000000056221473414355200236110ustar00rootroot00000000000000#ifndef ALLEGRO_INTERNAL_IPHONE #define ALLEGRO_INTERNAL_IPHONE #include "allegro5/allegro.h" #include #include typedef struct ALLEGRO_SYSTEM_IPHONE { ALLEGRO_SYSTEM system; ALLEGRO_MUTEX *mutex; ALLEGRO_COND *cond; bool has_shutdown, wants_shutdown; int visuals_count; ALLEGRO_EXTRA_DISPLAY_SETTINGS **visuals; } ALLEGRO_SYSTEM_IPHONE; typedef struct ALLEGRO_DISPLAY_IPHONE_EXTRA ALLEGRO_DISPLAY_IPHONE_EXTRA; typedef struct ALLEGRO_DISPLAY_IPHONE { ALLEGRO_DISPLAY display; ALLEGRO_DISPLAY_IPHONE_EXTRA *extra; } ALLEGRO_DISPLAY_IPHONE; void _al_iphone_init_path(void); bool _al_iphone_add_view(ALLEGRO_DISPLAY *d); void _al_iphone_make_view_current(ALLEGRO_DISPLAY *display); void _al_iphone_flip_view(ALLEGRO_DISPLAY *display); void _al_iphone_reset_framebuffer(ALLEGRO_DISPLAY *display); void _al_iphone_recreate_framebuffer(ALLEGRO_DISPLAY *); void _al_iphone_destroy_screen(ALLEGRO_DISPLAY *display); ALLEGRO_SYSTEM_INTERFACE *_al_get_iphone_system_interface(void); ALLEGRO_DISPLAY_INTERFACE *_al_get_iphone_display_interface(void); ALLEGRO_KEYBOARD_DRIVER *_al_get_iphone_keyboard_driver(void); ALLEGRO_MOUSE_DRIVER *_al_get_iphone_mouse_driver(void); ALLEGRO_TOUCH_INPUT_DRIVER *_al_get_iphone_touch_input_driver(void); ALLEGRO_JOYSTICK_DRIVER *_al_get_iphone_joystick_driver(void); void _al_iphone_setup_opengl_view(ALLEGRO_DISPLAY *d, bool manage_backbuffer); //void _al_iphone_generate_mouse_event(unsigned int type, // int x, int y, unsigned int button, ALLEGRO_DISPLAY *d); //void _al_iphone_generate_touch_event(unsigned int type, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *d); void _al_iphone_update_visuals(void); void _al_iphone_accelerometer_control(int frequency); void _al_iphone_generate_joystick_event(float x, float y, float z); void _al_iphone_await_termination(void); void _al_iphone_get_screen_size(int adapter, int *w, int *h); int _al_iphone_get_num_video_adapters(void); int _al_iphone_get_orientation(); void _al_iphone_translate_from_screen(ALLEGRO_DISPLAY *d, int *x, int *y); void _al_iphone_translate_to_screen(ALLEGRO_DISPLAY *d, int *x, int *y); void _al_iphone_clip(ALLEGRO_BITMAP const *bitmap, int x_1, int y_1, int x_2, int y_2); void _al_iphone_touch_input_handle_begin(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp); void _al_iphone_touch_input_handle_end(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp); void _al_iphone_touch_input_handle_move(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp); void _al_iphone_touch_input_handle_cancel(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp); void _al_iphone_disconnect(ALLEGRO_DISPLAY *display); void _al_iphone_add_clipboard_functions(ALLEGRO_DISPLAY_INTERFACE *vt); #endif // ALLEGRO_INTERNAL_IPHONE allegro5-5.2.10.1/include/allegro5/internal/aintern_joystick.h000066400000000000000000000045461473414355200241720ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_joystick_h #define __al_included_allegro5_aintern_joystick_h #include "allegro5/internal/aintern_driver.h" #include "allegro5/internal/aintern_events.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_JOYSTICK_DRIVER { int joydrv_id; const char *joydrv_name; const char *joydrv_desc; const char *joydrv_ascii_name; AL_METHOD(bool, init_joystick, (void)); AL_METHOD(void, exit_joystick, (void)); AL_METHOD(bool, reconfigure_joysticks, (void)); AL_METHOD(int, num_joysticks, (void)); AL_METHOD(ALLEGRO_JOYSTICK *, get_joystick, (int joyn)); AL_METHOD(void, release_joystick, (ALLEGRO_JOYSTICK *joy)); AL_METHOD(void, get_joystick_state, (ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state)); AL_METHOD(const char *, get_name, (ALLEGRO_JOYSTICK *joy)); AL_METHOD(bool, get_active, (ALLEGRO_JOYSTICK *joy)); } ALLEGRO_JOYSTICK_DRIVER; extern _AL_DRIVER_INFO _al_joystick_driver_list[]; /* macros for constructing the driver list */ #define _AL_BEGIN_JOYSTICK_DRIVER_LIST \ _AL_DRIVER_INFO _al_joystick_driver_list[] = \ { #define _AL_END_JOYSTICK_DRIVER_LIST \ { 0, NULL, false } \ }; /* information about a single joystick axis */ typedef struct _AL_JOYSTICK_AXIS_INFO { char *name; } _AL_JOYSTICK_AXIS_INFO; /* information about one or more axis (a slider or directional control) */ typedef struct _AL_JOYSTICK_STICK_INFO { int flags; /* bit-field */ int num_axes; _AL_JOYSTICK_AXIS_INFO axis[_AL_MAX_JOYSTICK_AXES]; char *name; } _AL_JOYSTICK_STICK_INFO; /* information about a joystick button */ typedef struct _AL_JOYSTICK_BUTTON_INFO { const char *name; } _AL_JOYSTICK_BUTTON_INFO; /* information about an entire joystick */ typedef struct _AL_JOYSTICK_INFO { int num_sticks; int num_buttons; _AL_JOYSTICK_STICK_INFO stick[_AL_MAX_JOYSTICK_STICKS]; _AL_JOYSTICK_BUTTON_INFO button[_AL_MAX_JOYSTICK_BUTTONS]; } _AL_JOYSTICK_INFO; /* Joystick has a driver field for per-device drivers, * needed on some platforms. */ struct ALLEGRO_JOYSTICK { _AL_JOYSTICK_INFO info; ALLEGRO_JOYSTICK_DRIVER * driver; }; void _al_generate_joystick_event(ALLEGRO_EVENT *event); #ifdef __cplusplus } #endif #endif /* vi ts=8 sts=3 sw=3 et */ allegro5-5.2.10.1/include/allegro5/internal/aintern_keyboard.h000066400000000000000000000035511473414355200241260ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_keyboard_h #define __al_included_allegro5_aintern_keyboard_h #include "allegro5/internal/aintern_driver.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_KEYBOARD_DRIVER { int keydrv_id; const char *keydrv_name; const char *keydrv_desc; const char *keydrv_ascii_name; AL_METHOD(bool, init_keyboard, (void)); AL_METHOD(void, exit_keyboard, (void)); AL_METHOD(ALLEGRO_KEYBOARD*, get_keyboard, (void)); AL_METHOD(bool, set_keyboard_leds, (int leds)); AL_METHOD(const char *, keycode_to_name, (int keycode)); AL_METHOD(void, get_keyboard_state, (ALLEGRO_KEYBOARD_STATE *ret_state)); AL_METHOD(void, clear_keyboard_state, (void)); } ALLEGRO_KEYBOARD_DRIVER; extern _AL_DRIVER_INFO _al_keyboard_driver_list[]; extern const char *_al_keyboard_common_names[]; int _al_parse_key_binding(const char *s, unsigned int *modifiers); struct ALLEGRO_KEYBOARD { ALLEGRO_EVENT_SOURCE es; }; /* Helpers for AL_KEYBOARD_STATE structures. */ #define _AL_KEYBOARD_STATE_KEY_DOWN(STATE, KEYCODE) \ (((STATE).__key_down__internal__[(KEYCODE) / 32] & (1 << ((KEYCODE) % 32)))\ ? true : false) #define _AL_KEYBOARD_STATE_SET_KEY_DOWN(STATE, KEYCODE) \ do { \ int kc = (KEYCODE); \ (STATE).__key_down__internal__[kc / 32] |= (1 << (kc % 32)); \ } while (0) #define _AL_KEYBOARD_STATE_CLEAR_KEY_DOWN(STATE, KEYCODE) \ do { \ int kc = (KEYCODE); \ (STATE).__key_down__internal__[kc / 32] &= ~(1 << (kc % 32)); \ } while (0) #ifdef __cplusplus } #endif #endif /* vi ts=8 sts=3 sw=3 et */ allegro5-5.2.10.1/include/allegro5/internal/aintern_list.h000066400000000000000000000061441473414355200233020ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_list_h #define __al_included_allegro5_aintern_list_h #ifdef __cplusplus extern "C" { #endif typedef struct _AL_LIST _AL_LIST; typedef struct _AL_LIST_ITEM _AL_LIST_ITEM; typedef void (*_AL_LIST_DTOR)(void* userdata); typedef void (*_AL_LIST_ITEM_DTOR)(void* value, void* userdata); AL_FUNC(_AL_LIST*, _al_list_create, (void)); AL_FUNC(_AL_LIST*, _al_list_create_static, (size_t capacity)); AL_FUNC(void, _al_list_destroy, (_AL_LIST* list)); AL_FUNC(void, _al_list_set_dtor, (_AL_LIST* list, _AL_LIST_DTOR dtor)); AL_FUNC(_AL_LIST_DTOR, _al_list_get_dtor, (_AL_LIST* list)); AL_FUNC(_AL_LIST_ITEM*, _al_list_push_front, (_AL_LIST* list, void* data)); AL_FUNC(_AL_LIST_ITEM*, _al_list_push_front_ex, (_AL_LIST* list, void* data, _AL_LIST_ITEM_DTOR dtor)); AL_FUNC(_AL_LIST_ITEM*, _al_list_push_back, (_AL_LIST* list, void* data)); AL_FUNC(_AL_LIST_ITEM*, _al_list_push_back_ex, (_AL_LIST* list, void* data, _AL_LIST_ITEM_DTOR dtor)); AL_FUNC(void, _al_list_pop_front, (_AL_LIST* list)); AL_FUNC(void, _al_list_pop_back, (_AL_LIST* list)); AL_FUNC(_AL_LIST_ITEM*, _al_list_insert_after, (_AL_LIST* list, _AL_LIST_ITEM* where, void* data)); AL_FUNC(_AL_LIST_ITEM*, _al_list_insert_after_ex, (_AL_LIST* list, _AL_LIST_ITEM* where, void* data, _AL_LIST_ITEM_DTOR dtor)); AL_FUNC(_AL_LIST_ITEM*, _al_list_insert_before, (_AL_LIST* list, _AL_LIST_ITEM* where, void* data)); AL_FUNC(_AL_LIST_ITEM*, _al_list_insert_before_ex, (_AL_LIST* list, _AL_LIST_ITEM* where, void* data, _AL_LIST_ITEM_DTOR dtor)); AL_FUNC(void, _al_list_erase, (_AL_LIST* list, _AL_LIST_ITEM* item)); AL_FUNC(void, _al_list_clear, (_AL_LIST* list)); AL_FUNC(void, _al_list_remove, (_AL_LIST* list, void* data)); AL_FUNC(bool, _al_list_is_empty, (_AL_LIST* list)); AL_FUNC(bool, _al_list_contains, (_AL_LIST* list, void* data)); AL_FUNC(_AL_LIST_ITEM*, _al_list_find_first, (_AL_LIST* list, void* data)); AL_FUNC(_AL_LIST_ITEM*, _al_list_find_last, (_AL_LIST* list, void* data)); AL_FUNC(_AL_LIST_ITEM*, _al_list_find_after, (_AL_LIST* list, _AL_LIST_ITEM* where, void* data)); AL_FUNC(_AL_LIST_ITEM*, _al_list_find_before, (_AL_LIST* list, _AL_LIST_ITEM* where, void* data)); AL_FUNC(size_t, _al_list_size, (_AL_LIST* list)); AL_FUNC(_AL_LIST_ITEM*, _al_list_at, (_AL_LIST* list, size_t index)); AL_FUNC(_AL_LIST_ITEM*, _al_list_front, (_AL_LIST* list)); AL_FUNC(_AL_LIST_ITEM*, _al_list_back, (_AL_LIST* list)); AL_FUNC(_AL_LIST_ITEM*, _al_list_next, (_AL_LIST* list, _AL_LIST_ITEM* item)); AL_FUNC(_AL_LIST_ITEM*, _al_list_previous, (_AL_LIST* list, _AL_LIST_ITEM* item)); AL_FUNC(_AL_LIST_ITEM*, _al_list_next_circular, (_AL_LIST* list, _AL_LIST_ITEM* item)); AL_FUNC(_AL_LIST_ITEM*, _al_list_previous_circular, (_AL_LIST* list, _AL_LIST_ITEM* item)); AL_FUNC(void*, _al_list_item_data, (_AL_LIST_ITEM* item)); AL_FUNC(void, _al_list_item_set_dtor, (_AL_LIST_ITEM* item, _AL_LIST_ITEM_DTOR dtor)); AL_FUNC(_AL_LIST_ITEM_DTOR, _al_list_item_get_dtor, (_AL_LIST_ITEM* item)); AL_FUNC(void, _al_list_set_user_data, (_AL_LIST* list, void* user_data)); AL_FUNC(void*, _al_list_get_user_data, (_AL_LIST* list)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_ljoynu.h000066400000000000000000000027751473414355200236550ustar00rootroot00000000000000#ifndef __al_included_allegro_aintern_ljoynu_h #define __al_included_allegro_aintern_ljoynu_h #include "allegro5/joystick.h" #include "allegro5/internal/aintern_joystick.h" /* XXX reconsider what needs to be exposed after the haptics driver is in */ /* State transitions: * unused -> born * born -> alive * born -> dying * active -> dying * dying -> unused */ typedef enum { LJOY_STATE_UNUSED, LJOY_STATE_BORN, LJOY_STATE_ALIVE, LJOY_STATE_DYING } CONFIG_STATE; #define ACTIVE_STATE(st) \ ((st) == LJOY_STATE_ALIVE || (st) == LJOY_STATE_DYING) /* Map a Linux joystick axis number to an Allegro (stick,axis) pair * Uses the input event interface's numbering where ABS_MISC = 0x28, * so that is the maximum of allowed axes on Linux. */ #define TOTAL_JOYSTICK_AXES (0x28) typedef struct { int stick; int axis; /* XXX reconsider what fields are required after the haptics driver is in */ int value; int min; int max; int fuzz; int flat; } AXIS_MAPPING; /* Map a Linux input button code to button number on the Allegro joystick. */ typedef struct { int ev_code; } BUTTON_MAPPING; typedef struct ALLEGRO_JOYSTICK_LINUX { ALLEGRO_JOYSTICK parent; int config_state; bool marked; int fd; ALLEGRO_USTR *device_name; AXIS_MAPPING axis_mapping[TOTAL_JOYSTICK_AXES]; BUTTON_MAPPING button_mapping[_AL_MAX_JOYSTICK_BUTTONS]; ALLEGRO_JOYSTICK_STATE joystate; char name[100]; } ALLEGRO_JOYSTICK_LINUX; #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_memblit.h000066400000000000000000000005501473414355200237530ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_memblit_h #define __al_included_allegro5_aintern_memblit_h #ifdef __cplusplus extern "C" { #endif void _al_draw_bitmap_region_memory(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, int sx, int sy, int sw, int sh, int dx, int dy, int flags); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_memdraw.h000066400000000000000000000006001473414355200237520ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_memdraw_h #define __al_included_allegro5_aintern_memdraw_h #ifdef __cplusplus extern "C" { #endif void _al_clear_bitmap_by_locking(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR *color); void _al_draw_pixel_memory(ALLEGRO_BITMAP *bmp, float x, float y, ALLEGRO_COLOR *color); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_mouse.h000066400000000000000000000020061473414355200234500ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_mouse_h #define __al_included_allegro5_aintern_mouse_h #include "allegro5/internal/aintern_driver.h" #include "allegro5/internal/aintern_events.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_MOUSE_DRIVER { int msedrv_id; const char *msedrv_name; const char *msedrv_desc; const char *msedrv_ascii_name; AL_METHOD(bool, init_mouse, (void)); AL_METHOD(void, exit_mouse, (void)); AL_METHOD(ALLEGRO_MOUSE*, get_mouse, (void)); AL_METHOD(unsigned int, get_mouse_num_buttons, (void)); AL_METHOD(unsigned int, get_mouse_num_axes, (void)); AL_METHOD(bool, set_mouse_xy, (ALLEGRO_DISPLAY *display, int x, int y)); AL_METHOD(bool, set_mouse_axis, (int which, int value)); AL_METHOD(void, get_mouse_state, (ALLEGRO_MOUSE_STATE *ret_state)); } ALLEGRO_MOUSE_DRIVER; extern _AL_DRIVER_INFO _al_mouse_driver_list[]; struct ALLEGRO_MOUSE { ALLEGRO_EVENT_SOURCE es; }; #ifdef __cplusplus } #endif #endif /* vi ts=8 sts=3 sw=3 et */ allegro5-5.2.10.1/include/allegro5/internal/aintern_opengl.h000066400000000000000000000173741473414355200236220ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_opengl_h #define __al_included_allegro5_aintern_opengl_h #include "allegro5/opengl/gl_ext.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_display.h" #ifdef __cplusplus extern "C" { #endif enum { _ALLEGRO_OPENGL_VERSION_0 = 0, /* dummy */ _ALLEGRO_OPENGL_VERSION_1_0 = 0x01000000, _ALLEGRO_OPENGL_VERSION_1_1 = 0x01010000, _ALLEGRO_OPENGL_VERSION_1_2 = 0x01020000, _ALLEGRO_OPENGL_VERSION_1_2_1 = 0x01020100, _ALLEGRO_OPENGL_VERSION_1_3 = 0x01030000, _ALLEGRO_OPENGL_VERSION_1_4 = 0x01040000, _ALLEGRO_OPENGL_VERSION_1_5 = 0x01050000, _ALLEGRO_OPENGL_VERSION_2_0 = 0x02000000, _ALLEGRO_OPENGL_VERSION_2_1 = 0x02010000, _ALLEGRO_OPENGL_VERSION_3_0 = 0x03000000, _ALLEGRO_OPENGL_VERSION_3_1 = 0x03010000, _ALLEGRO_OPENGL_VERSION_3_2 = 0x03020000, _ALLEGRO_OPENGL_VERSION_3_3 = 0x03030000, _ALLEGRO_OPENGL_VERSION_4_0 = 0x04000000 }; #define ALLEGRO_MAX_OPENGL_FBOS 8 enum { FBO_INFO_UNUSED = 0, FBO_INFO_TRANSIENT = 1, /* may be destroyed for another bitmap */ FBO_INFO_PERSISTENT = 2 /* exclusive to the owner bitmap */ }; typedef struct ALLEGRO_FBO_BUFFERS { /* It is not easy to determine the best lifetime for these. Unlike * FBOs they are heavy objects and re-creating them can be costly. * However if we make them part of ALLEGRO_BITMAP_EXTRA_OPENGL * below, there is no way to release them. I.e. if you create * many bitmaps in the beginning of your game and need depth and/or * multisampling for them, the only way to free the buffers would be * to copy those bitmaps and then destroy them. * * By tying them to the FBO struct, there is a limit of how many * buffers Allegro will create before recycling them. This will * work very well in the case where you only have one or a few * bitmaps you regularly draw into. */ GLuint depth_buffer; int dw, dh, depth; GLuint multisample_buffer; int mw, mh, samples; } ALLEGRO_FBO_BUFFERS; typedef struct ALLEGRO_FBO_INFO { int fbo_state; GLuint fbo; ALLEGRO_FBO_BUFFERS buffers; ALLEGRO_BITMAP *owner; double last_use_time; } ALLEGRO_FBO_INFO; typedef struct ALLEGRO_BITMAP_EXTRA_OPENGL { /* Driver specifics. */ int true_w; int true_h; GLuint texture; /* 0 means, not uploaded yet. */ ALLEGRO_FBO_INFO *fbo_info; /* When an OpenGL bitmap is locked, the locked region is usually backed by a * temporary memory buffer pointed to by lock_buffer. * * On GLES, a locked backbuffer may be backed by a texture bitmap pointed to * by lock_proxy instead, and lock_buffer is NULL. Upon unlocking the proxy * bitmap is drawn onto the backbuffer. */ unsigned char *lock_buffer; ALLEGRO_BITMAP *lock_proxy; float left, top, right, bottom; /* Texture coordinates. */ bool is_backbuffer; /* This is not a real bitmap, but the backbuffer. */ } ALLEGRO_BITMAP_EXTRA_OPENGL; typedef struct OPENGL_INFO { uint32_t version; /* OpenGL version */ int max_texture_size; /* Maximum texture size */ int is_voodoo3_and_under; /* Special cases for Voodoo 1-3 */ int is_voodoo; /* Special cases for Voodoo cards */ int is_matrox_g200; /* Special cases for Matrox G200 boards */ int is_ati_rage_pro; /* Special cases for ATI Rage Pro boards */ int is_ati_radeon_7000; /* Special cases for ATI Radeon 7000 */ int is_ati_r200_chip; /* Special cases for ATI card with chip R200 */ int is_mesa_driver; /* Special cases for MESA */ int is_intel_hd_graphics_3000; } OPENGL_INFO; typedef struct ALLEGRO_OGL_VARLOCS { /* Cached shader variable locations. */ GLint pos_loc; GLint color_loc; GLint projview_matrix_loc; GLint texcoord_loc; GLint use_tex_loc; GLint tex_loc; GLint use_tex_matrix_loc; GLint tex_matrix_loc; GLint alpha_test_loc; GLint alpha_func_loc; GLint alpha_test_val_loc; GLint user_attr_loc[_ALLEGRO_PRIM_MAX_USER_ATTR]; } ALLEGRO_OGL_VARLOCS; typedef struct ALLEGRO_OGL_EXTRAS { /* A list of extensions supported by Allegro, for this context. */ ALLEGRO_OGL_EXT_LIST *extension_list; /* A list of extension API, loaded by Allegro, for this context. */ ALLEGRO_OGL_EXT_API *extension_api; /* Various info about OpenGL implementation. */ OPENGL_INFO ogl_info; ALLEGRO_BITMAP *opengl_target; ALLEGRO_BITMAP *backbuffer; /* True if display resources are shared among displays. */ bool is_shared; ALLEGRO_FBO_INFO fbos[ALLEGRO_MAX_OPENGL_FBOS]; /* In non-programmable pipe mode this should be zero. * In programmable pipeline mode this should be non-zero. */ GLuint program_object; ALLEGRO_OGL_VARLOCS varlocs; /* For OpenGL 3.0+ we use a single vao and vbo. */ GLuint vao, vbo; } ALLEGRO_OGL_EXTRAS; typedef struct ALLEGRO_OGL_BITMAP_VERTEX { float x, y, z; float tx, ty; float r, g, b, a; } ALLEGRO_OGL_BITMAP_VERTEX; /* extensions */ int _al_ogl_look_for_an_extension(const char *name, const GLubyte *extensions); void _al_ogl_set_extensions(ALLEGRO_OGL_EXT_API *ext); void _al_ogl_manage_extensions(ALLEGRO_DISPLAY *disp); void _al_ogl_unmanage_extensions(ALLEGRO_DISPLAY *disp); /* bitmap */ int _al_ogl_get_glformat(int format, int component); ALLEGRO_BITMAP *_al_ogl_create_bitmap(ALLEGRO_DISPLAY *d, int w, int h, int format, int flags); void _al_ogl_upload_bitmap_memory(ALLEGRO_BITMAP *bitmap, int format, void *ptr); /* locking */ #ifndef ALLEGRO_CFG_OPENGLES ALLEGRO_LOCKED_REGION *_al_ogl_lock_region_new(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int format, int flags); void _al_ogl_unlock_region_new(ALLEGRO_BITMAP *bitmap); #else ALLEGRO_LOCKED_REGION *_al_ogl_lock_region_gles(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int format, int flags); void _al_ogl_unlock_region_gles(ALLEGRO_BITMAP *bitmap); #endif int _al_ogl_pixel_alignment(int pixel_size, bool compressed); /* framebuffer objects */ GLint _al_ogl_bind_framebuffer(GLint fbo); void _al_ogl_reset_fbo_info(ALLEGRO_FBO_INFO *info); bool _al_ogl_create_persistent_fbo(ALLEGRO_BITMAP *bitmap); ALLEGRO_FBO_INFO *_al_ogl_persist_fbo(ALLEGRO_DISPLAY *display, ALLEGRO_FBO_INFO *transient_fbo_info); void _al_ogl_setup_fbo(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap); bool _al_ogl_setup_fbo_non_backbuffer(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap); void _al_ogl_del_fbo(ALLEGRO_FBO_INFO *info); /* common driver */ void _al_ogl_setup_gl(ALLEGRO_DISPLAY *d); void _al_ogl_set_target_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap); void _al_ogl_unset_target_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap); void _al_ogl_finalize_fbo(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap); void _al_ogl_setup_bitmap_clipping(const ALLEGRO_BITMAP *bitmap); ALLEGRO_BITMAP *_al_ogl_get_backbuffer(ALLEGRO_DISPLAY *d); ALLEGRO_BITMAP* _al_ogl_create_backbuffer(ALLEGRO_DISPLAY *disp); void _al_ogl_destroy_backbuffer(ALLEGRO_BITMAP *b); bool _al_ogl_resize_backbuffer(ALLEGRO_BITMAP *b, int w, int h); void _al_opengl_backup_dirty_bitmaps(ALLEGRO_DISPLAY *d, bool flip); /* draw */ struct ALLEGRO_DISPLAY_INTERFACE; void _al_ogl_add_drawing_functions(struct ALLEGRO_DISPLAY_INTERFACE *vt); AL_FUNC(bool, _al_opengl_set_blender, (ALLEGRO_DISPLAY *disp)); AL_FUNC(char const *, _al_gl_error_string, (GLenum e)); void _al_ogl_update_render_state(ALLEGRO_DISPLAY *display); /* shader */ #ifdef ALLEGRO_CFG_SHADER_GLSL bool _al_glsl_set_projview_matrix(GLint projview_matrix_loc, const ALLEGRO_TRANSFORM *t); void _al_glsl_init_shaders(void); void _al_glsl_shutdown_shaders(void); void _al_glsl_unuse_shaders(void); #endif #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_osxclipboard.h000066400000000000000000000005211473414355200250110ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_osxclipboard_h #define __al_included_allegro5_aintern_osxclipboard_h #include "allegro5/internal/aintern_display.h" #ifdef __cplusplus extern "C" { #endif void _al_osx_add_clipboard_functions(ALLEGRO_DISPLAY_INTERFACE *vt); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_path.h000066400000000000000000000005031473414355200232540ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_path_h #define __al_included_allegro5_aintern_path_h struct ALLEGRO_PATH { ALLEGRO_USTR *drive; ALLEGRO_USTR *filename; _AL_VECTOR segments; /* vector of ALLEGRO_USTR * */ ALLEGRO_USTR *basename; ALLEGRO_USTR *full_string; }; #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_pixels.h000066400000000000000000001124611473414355200236330ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_pixels_h #define __al_included_allegro5_aintern_pixels_h #include "allegro5/internal/aintern_float.h" #ifdef __cplusplus extern "C" { #endif #define _AL_MAP_RGBA(_color, _r, _g, _b, _a) \ do { \ (_color).r = _al_u8_to_float[_r]; \ (_color).g = _al_u8_to_float[_g]; \ (_color).b = _al_u8_to_float[_b]; \ (_color).a = _al_u8_to_float[_a]; \ } while (0) #define _AL_INLINE_GET_PIXEL(format, data, color, advance) \ do { \ switch (format) { \ case ALLEGRO_PIXEL_FORMAT_ARGB_8888: { \ uint32_t _gp_pixel = *(uint32_t *)(data); \ _AL_MAP_RGBA(color, \ (_gp_pixel & 0x00FF0000) >> 16, \ (_gp_pixel & 0x0000FF00) >> 8, \ (_gp_pixel & 0x000000FF) >> 0, \ (_gp_pixel & 0xFF000000) >> 24); \ if (advance) \ data += 4; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_RGBA_8888: { \ uint32_t _gp_pixel = *(uint32_t *)(data); \ _AL_MAP_RGBA(color, \ (_gp_pixel & 0xFF000000) >> 24, \ (_gp_pixel & 0x00FF0000) >> 16, \ (_gp_pixel & 0x0000FF00) >> 8, \ (_gp_pixel & 0x000000FF) >> 0); \ if (advance) \ data += 4; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_ARGB_4444: { \ uint16_t _gp_pixel = *(uint16_t *)(data); \ _AL_MAP_RGBA(color, \ _al_rgb_scale_4[(_gp_pixel & 0x0F00) >> 8], \ _al_rgb_scale_4[(_gp_pixel & 0x00F0) >> 4], \ _al_rgb_scale_4[(_gp_pixel & 0x000F)], \ _al_rgb_scale_4[(_gp_pixel & 0xF000) >> 12]); \ if (advance) \ data += 2; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_RGB_888: { \ uint32_t _gp_pixel = _AL_READ3BYTES(data); \ _AL_MAP_RGBA(color, \ (_gp_pixel & 0xFF0000) >> 16, \ (_gp_pixel & 0x00FF00) >> 8, \ (_gp_pixel & 0x0000FF) >> 0, \ 255); \ if (advance) \ data += 3; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_RGB_565: { \ uint16_t _gp_pixel = *(uint16_t *)(data); \ _AL_MAP_RGBA(color, \ _al_rgb_scale_5[(_gp_pixel & 0xF800) >> 11], \ _al_rgb_scale_6[(_gp_pixel & 0x07E0) >> 5], \ _al_rgb_scale_5[(_gp_pixel & 0x001F)], \ 255); \ if (advance) \ data += 2; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_RGB_555: { \ uint16_t _gp_pixel = *(uint16_t *)(data); \ _AL_MAP_RGBA(color, \ _al_rgb_scale_5[(_gp_pixel & 0x7C00) >> 10], \ _al_rgb_scale_5[(_gp_pixel & 0x03E0) >> 5], \ _al_rgb_scale_5[(_gp_pixel & 0x001F)], \ 255); \ if (advance) \ data += 2; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_RGBA_5551: { \ uint16_t _gp_pixel = *(uint16_t *)(data); \ _AL_MAP_RGBA(color, \ _al_rgb_scale_5[(_gp_pixel & 0xF800) >> 11], \ _al_rgb_scale_5[(_gp_pixel & 0x07C0) >> 6], \ _al_rgb_scale_5[(_gp_pixel & 0x003E) >> 1], \ _al_rgb_scale_1[_gp_pixel & 1]); \ if (advance) \ data += 2; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_ARGB_1555: { \ uint16_t _gp_pixel = *(uint16_t *)(data); \ _AL_MAP_RGBA(color, \ _al_rgb_scale_5[(_gp_pixel & 0x7C00) >> 10], \ _al_rgb_scale_5[(_gp_pixel & 0x03E0) >> 5], \ _al_rgb_scale_5[(_gp_pixel & 0x001F)], \ _al_rgb_scale_1[(_gp_pixel & 0x8000) >> 15]); \ if (advance) \ data += 2; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_ABGR_8888: { \ uint32_t _gp_pixel = *(uint32_t *)(data); \ _AL_MAP_RGBA(color, \ (_gp_pixel & 0x000000FF) >> 0, \ (_gp_pixel & 0x0000FF00) >> 8, \ (_gp_pixel & 0x00FF0000) >> 16, \ (_gp_pixel & 0xFF000000) >> 24); \ if (advance) \ data += 4; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_XBGR_8888: { \ uint32_t _gp_pixel = *(uint32_t *)(data); \ _AL_MAP_RGBA(color, \ (_gp_pixel & 0x000000FF) >> 0, \ (_gp_pixel & 0x0000FF00) >> 8, \ (_gp_pixel & 0x00FF0000) >> 16, \ 255); \ if (advance) \ data += 4; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_BGR_888: { \ uint32_t _gp_pixel = _AL_READ3BYTES(data); \ _AL_MAP_RGBA(color, \ (_gp_pixel & 0x000000FF) >> 0, \ (_gp_pixel & 0x0000FF00) >> 8, \ (_gp_pixel & 0x00FF0000) >> 16, \ 255); \ if (advance) \ data += 4; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_BGR_565: { \ uint16_t _gp_pixel = *(uint16_t *)(data); \ _AL_MAP_RGBA(color, \ _al_rgb_scale_5[(_gp_pixel & 0x001F)], \ _al_rgb_scale_6[(_gp_pixel & 0x07E0) >> 5], \ _al_rgb_scale_5[(_gp_pixel & 0xF800) >> 11], \ 255); \ if (advance) \ data += 2; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_BGR_555: { \ uint16_t _gp_pixel = *(uint16_t *)(data); \ _AL_MAP_RGBA(color, \ _al_rgb_scale_5[(_gp_pixel & 0x001F)], \ _al_rgb_scale_5[(_gp_pixel & 0x03E0) >> 5], \ _al_rgb_scale_5[(_gp_pixel & 0x7C00) >> 10], \ 255); \ if (advance) \ data += 2; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_RGBX_8888: { \ uint32_t _gp_pixel = *(uint32_t *)(data); \ _AL_MAP_RGBA(color, \ (_gp_pixel & 0xFF000000) >> 24, \ (_gp_pixel & 0x00FF0000) >> 16, \ (_gp_pixel & 0x0000FF00) >> 8, \ 255); \ if (advance) \ data += 4; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_XRGB_8888: { \ uint32_t _gp_pixel = *(uint32_t *)(data); \ _AL_MAP_RGBA(color, \ (_gp_pixel & 0x00FF0000) >> 16, \ (_gp_pixel & 0x0000FF00) >> 8, \ (_gp_pixel & 0x000000FF), \ 255); \ if (advance) \ data += 4; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_ABGR_F32: { \ float *f = (float *)data; \ color.r = f[0]; \ color.g = f[1]; \ color.b = f[2]; \ color.a = f[3]; \ if (advance) \ data += 4 * sizeof(float); \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE: { \ uint8_t *p = (uint8_t *)data; \ _AL_MAP_RGBA(color, *p, *(p + 1), *(p + 2), *(p + 3)); \ if (advance) \ data += 4; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_RGBA_4444: { \ uint16_t _gp_pixel = *(uint16_t *)(data); \ _AL_MAP_RGBA(color, \ _al_rgb_scale_4[(_gp_pixel & 0xF000) >> 12], \ _al_rgb_scale_4[(_gp_pixel & 0x0F00) >> 8], \ _al_rgb_scale_4[(_gp_pixel & 0x00F0) >> 4], \ _al_rgb_scale_4[(_gp_pixel & 0x000F)]); \ if (advance) \ data += 2; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8: { \ uint8_t c = *(uint8_t *)(data); \ _AL_MAP_RGBA(color, c, c, c, 255); \ if (advance) \ data += 2; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_ANY: \ case ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_15_NO_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA: \ ALLEGRO_ERROR("INLINE_GET got fake pixel format: %d\n", format); \ abort(); \ break; \ \ case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1: \ case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3: \ case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5: \ ALLEGRO_ERROR("INLINE_GET got compressed format: %d\n", format); \ abort(); \ break; \ \ case ALLEGRO_NUM_PIXEL_FORMATS: \ default: \ ALLEGRO_ERROR("INLINE_GET got non pixel format: %d\n", format); \ abort(); \ break; \ } \ } while (0) #define _AL_INLINE_PUT_PIXEL(format, data, color, advance) \ do { \ uint32_t _pp_pixel; \ switch (format) { \ case ALLEGRO_PIXEL_FORMAT_ARGB_8888: \ _pp_pixel = _al_fast_float_to_int(color.a * 255) << 24; \ _pp_pixel |= _al_fast_float_to_int(color.r * 255) << 16; \ _pp_pixel |= _al_fast_float_to_int(color.g * 255) << 8; \ _pp_pixel |= _al_fast_float_to_int(color.b * 255); \ *(uint32_t *)(data) = _pp_pixel; \ if (advance) \ data += 4; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_RGBA_8888: \ _pp_pixel = _al_fast_float_to_int(color.r * 255) << 24; \ _pp_pixel |= _al_fast_float_to_int(color.g * 255) << 16; \ _pp_pixel |= _al_fast_float_to_int(color.b * 255) << 8; \ _pp_pixel |= _al_fast_float_to_int(color.a * 255); \ *(uint32_t *)(data) = _pp_pixel; \ if (advance) \ data += 4; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_ARGB_4444: \ _pp_pixel = _al_fast_float_to_int(color.a * 15) << 12; \ _pp_pixel |= _al_fast_float_to_int(color.r * 15) << 8; \ _pp_pixel |= _al_fast_float_to_int(color.g * 15) << 4; \ _pp_pixel |= _al_fast_float_to_int(color.b * 15); \ *(uint16_t *)(data) = _pp_pixel; \ if (advance) \ data += 2; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_RGB_888: \ _pp_pixel = _al_fast_float_to_int(color.r * 255) << 16; \ _pp_pixel |= _al_fast_float_to_int(color.g * 255) << 8; \ _pp_pixel |= _al_fast_float_to_int(color.b * 255); \ _AL_WRITE3BYTES(data, _pp_pixel); \ if (advance) \ data += 3; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_RGB_565: \ _pp_pixel = _al_fast_float_to_int(color.r * 0x1f) << 11; \ _pp_pixel |= _al_fast_float_to_int(color.g * 0x3f) << 5; \ _pp_pixel |= _al_fast_float_to_int(color.b * 0x1f); \ *(uint16_t *)(data) = _pp_pixel; \ if (advance) \ data += 2; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_RGB_555: \ _pp_pixel = _al_fast_float_to_int(color.r * 0x1f) << 10; \ _pp_pixel |= _al_fast_float_to_int(color.g * 0x1f) << 5; \ _pp_pixel |= _al_fast_float_to_int(color.b * 0x1f); \ *(uint16_t *)(data) = _pp_pixel; \ if (advance) \ data += 2; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_RGBA_5551: \ _pp_pixel = _al_fast_float_to_int(color.r * 0x1f) << 11; \ _pp_pixel |= _al_fast_float_to_int(color.g * 0x1f) << 6; \ _pp_pixel |= _al_fast_float_to_int(color.b * 0x1f) << 1; \ _pp_pixel |= _al_fast_float_to_int(color.a); \ *(uint16_t *)(data) = _pp_pixel; \ if (advance) \ data += 2; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_ARGB_1555: \ _pp_pixel = _al_fast_float_to_int(color.a) << 15; \ _pp_pixel |= _al_fast_float_to_int(color.r * 0x1f) << 10; \ _pp_pixel |= _al_fast_float_to_int(color.g * 0x1f) << 5; \ _pp_pixel |= _al_fast_float_to_int(color.b * 0x1f); \ *(uint16_t *)(data) = _pp_pixel; \ if (advance) \ data += 2; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_ABGR_8888: \ _pp_pixel = _al_fast_float_to_int(color.a * 0xff) << 24; \ _pp_pixel |= _al_fast_float_to_int(color.b * 0xff) << 16; \ _pp_pixel |= _al_fast_float_to_int(color.g * 0xff) << 8; \ _pp_pixel |= _al_fast_float_to_int(color.r * 0xff); \ *(uint32_t *)(data) = _pp_pixel; \ if (advance) \ data += 4; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_XBGR_8888: \ _pp_pixel = 0xff000000; \ _pp_pixel |= _al_fast_float_to_int(color.b * 0xff) << 16; \ _pp_pixel |= _al_fast_float_to_int(color.g * 0xff) << 8; \ _pp_pixel |= _al_fast_float_to_int(color.r * 0xff); \ *(uint32_t *)(data) = _pp_pixel; \ if (advance) \ data += 4; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_BGR_888: \ _pp_pixel = _al_fast_float_to_int(color.b * 0xff) << 16; \ _pp_pixel |= _al_fast_float_to_int(color.g * 0xff) << 8; \ _pp_pixel |= _al_fast_float_to_int(color.r * 0xff); \ _AL_WRITE3BYTES(data, _pp_pixel); \ if (advance) \ data += 3; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_BGR_565: \ _pp_pixel = _al_fast_float_to_int(color.b * 0x1f) << 11; \ _pp_pixel |= _al_fast_float_to_int(color.g * 0x3f) << 5; \ _pp_pixel |= _al_fast_float_to_int(color.r * 0x1f); \ *(uint16_t *)(data) = _pp_pixel; \ if (advance) \ data += 2; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_BGR_555: \ _pp_pixel = _al_fast_float_to_int(color.b * 0x1f) << 10; \ _pp_pixel |= _al_fast_float_to_int(color.g * 0x1f) << 5; \ _pp_pixel |= _al_fast_float_to_int(color.r * 0x1f); \ *(uint16_t *)(data) = _pp_pixel; \ if (advance) \ data += 2; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_RGBX_8888: \ _pp_pixel = 0xff; \ _pp_pixel |= _al_fast_float_to_int(color.r * 0xff) << 24; \ _pp_pixel |= _al_fast_float_to_int(color.g * 0xff) << 16; \ _pp_pixel |= _al_fast_float_to_int(color.b * 0xff) << 8; \ *(uint32_t *)(data) = _pp_pixel; \ if (advance) \ data += 4; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_XRGB_8888: \ _pp_pixel = 0xff000000; \ _pp_pixel |= _al_fast_float_to_int(color.r * 0xff) << 16; \ _pp_pixel |= _al_fast_float_to_int(color.g * 0xff) << 8; \ _pp_pixel |= _al_fast_float_to_int(color.b * 0xff); \ *(uint32_t *)(data) = _pp_pixel; \ if (advance) \ data += 4; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_ABGR_F32: { \ float *f = (float *)data; \ f[0] = color.r; \ f[1] = color.g; \ f[2] = color.b; \ f[3] = color.a; \ if (advance) \ data += 4 * sizeof(float); \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE: \ *((uint8_t *)data + 0) = _al_fast_float_to_int(color.r * 0xff); \ *((uint8_t *)data + 1) = _al_fast_float_to_int(color.g * 0xff); \ *((uint8_t *)data + 2) = _al_fast_float_to_int(color.b * 0xff); \ *((uint8_t *)data + 3) = _al_fast_float_to_int(color.a * 0xff); \ if (advance) \ data += 4; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_RGBA_4444: \ _pp_pixel = _al_fast_float_to_int(color.a * 15); \ _pp_pixel |= _al_fast_float_to_int(color.r * 15) << 12; \ _pp_pixel |= _al_fast_float_to_int(color.g * 15) << 8; \ _pp_pixel |= _al_fast_float_to_int(color.b * 15) << 4; \ *(uint16_t *)(data) = _pp_pixel; \ if (advance) \ data += 2; \ break; \ \ case ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8: { \ uint8_t c = color.r; \ *(uint8_t *)data = c; \ if (advance) \ data += 3; \ break; \ } \ \ case ALLEGRO_PIXEL_FORMAT_ANY: \ case ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_15_NO_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA: \ case ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA: \ ALLEGRO_ERROR("INLINE_PUT got fake _pp_pixel format: %d\n", format); \ abort(); \ break; \ \ case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1: \ case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3: \ case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5: \ ALLEGRO_ERROR("INLINE_PUT got compressed format: %d\n", format); \ abort(); \ break; \ \ case ALLEGRO_NUM_PIXEL_FORMATS: \ ALLEGRO_ERROR("INLINE_PUT got non _pp_pixel format: %d\n", format); \ abort(); \ break; \ } \ } while (0) AL_ARRAY(int, _al_rgb_scale_1); AL_ARRAY(int, _al_rgb_scale_4); AL_ARRAY(int, _al_rgb_scale_5); AL_ARRAY(int, _al_rgb_scale_6); AL_ARRAY(float, _al_u8_to_float); AL_FUNC(bool, _al_pixel_format_has_alpha, (int format)); AL_FUNC(bool, _al_pixel_format_is_real, (int format)); AL_FUNC(bool, _al_pixel_format_is_video_only, (int format)); AL_FUNC(bool, _al_pixel_format_is_compressed, (int format)); AL_FUNC(int, _al_get_real_pixel_format, (ALLEGRO_DISPLAY *display, int format)); AL_FUNC(char const*, _al_pixel_format_name, (ALLEGRO_PIXEL_FORMAT format)); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_raspberrypi.h000066400000000000000000000034471473414355200246740ustar00rootroot00000000000000#ifndef _ALLEGRO_INTERNAL_RASPBERRYPI_SYSTEM #define _ALLEGRO_INTERNAL_RASPBERRYPI_SYSTEM #include "allegro5/allegro.h" #include #include #include #include typedef struct ALLEGRO_SYSTEM_RASPBERRYPI { ALLEGRO_SYSTEM system; Display *x11display; _AL_MUTEX lock; /* thread lock for whenever we access internals. */ _AL_THREAD thread; /* background thread. */ ALLEGRO_DISPLAY *mouse_grab_display; /* Best effort: may be inaccurate. */ bool inhibit_screensaver; /* Should we inhibit the screensaver? */ Atom AllegroAtom; } ALLEGRO_SYSTEM_RASPBERRYPI; typedef struct ALLEGRO_DISPLAY_RASPBERRYPI_EXTRA ALLEGRO_DISPLAY_RASPBERRYPI_EXTRA; typedef struct ALLEGRO_DISPLAY_RASPBERRYPI { ALLEGRO_DISPLAY display; ALLEGRO_DISPLAY_RASPBERRYPI_EXTRA *extra; Window window; /* Physical size of display in pixels (gets scaled) */ int screen_width, screen_height; /* Cursor stuff */ bool mouse_warp; uint32_t *cursor_data; int cursor_width; int cursor_height; int cursor_offset_x, cursor_offset_y; Atom wm_delete_window_atom; } ALLEGRO_DISPLAY_RASPBERRYPI; typedef struct ALLEGRO_MOUSE_CURSOR_RASPBERRYPI { ALLEGRO_BITMAP *bitmap; } ALLEGRO_MOUSE_CURSOR_RASPBERRYPI; ALLEGRO_SYSTEM_INTERFACE *_al_system_raspberrypi_driver(void); ALLEGRO_DISPLAY_INTERFACE *_al_get_raspberrypi_display_interface(void); void _al_raspberrypi_get_screen_info(int *dx, int *dy, int *screen_width, int *screen_height); bool _al_evdev_set_mouse_range(int x1, int y1, int x2, int y2); // used by console mouse driver void _al_raspberrypi_get_mouse_scale_ratios(float *x, float *y); // used by X mouse driver ALLEGRO_MOUSE_DRIVER _al_mousedrv_linux_evdev; #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_shader.h000066400000000000000000000051741473414355200235770ustar00rootroot00000000000000#ifndef __al_included_allegro5_internal_aintern_shader_h #define __al_included_allegro5_internal_aintern_shader_h #include "allegro5/internal/aintern_list.h" #include "allegro5/internal/aintern_vector.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_SHADER_INTERFACE ALLEGRO_SHADER_INTERFACE; struct ALLEGRO_SHADER_INTERFACE { bool (*attach_shader_source)(ALLEGRO_SHADER *shader, ALLEGRO_SHADER_TYPE type, const char *source); bool (*build_shader)(ALLEGRO_SHADER *shader); bool (*use_shader)(ALLEGRO_SHADER *shader, ALLEGRO_DISPLAY *dpy, bool set_projview_matrix_from_display); void (*unuse_shader)(ALLEGRO_SHADER *shader, ALLEGRO_DISPLAY *dpy); void (*destroy_shader)(ALLEGRO_SHADER *shader); void (*on_lost_device)(ALLEGRO_SHADER *shader); void (*on_reset_device)(ALLEGRO_SHADER *shader); bool (*set_shader_sampler)(ALLEGRO_SHADER *shader, const char *name, ALLEGRO_BITMAP *bitmap, int unit); bool (*set_shader_matrix)(ALLEGRO_SHADER *shader, const char *name, const ALLEGRO_TRANSFORM *matrix); bool (*set_shader_int)(ALLEGRO_SHADER *shader, const char *name, int i); bool (*set_shader_float)(ALLEGRO_SHADER *shader, const char *name, float f); bool (*set_shader_int_vector)(ALLEGRO_SHADER *shader, const char *name, int elem_size, const int *i, int num_elems); bool (*set_shader_float_vector)(ALLEGRO_SHADER *shader, const char *name, int elem_size, const float *f, int num_elems); bool (*set_shader_bool)(ALLEGRO_SHADER *shader, const char *name, bool b); }; struct ALLEGRO_SHADER { ALLEGRO_USTR *vertex_copy; ALLEGRO_USTR *pixel_copy; ALLEGRO_USTR *log; ALLEGRO_SHADER_PLATFORM platform; ALLEGRO_SHADER_INTERFACE *vt; _AL_VECTOR bitmaps; /* of ALLEGRO_BITMAP pointers */ _AL_LIST_ITEM *dtor_item; }; /* In most cases you should use _al_set_bitmap_shader_field. */ void _al_set_bitmap_shader_field(ALLEGRO_BITMAP *bmp, ALLEGRO_SHADER *shader); void _al_register_shader_bitmap(ALLEGRO_SHADER *shader, ALLEGRO_BITMAP *bmp); void _al_unregister_shader_bitmap(ALLEGRO_SHADER *shader, ALLEGRO_BITMAP *bmp); ALLEGRO_SHADER *_al_create_default_shader(ALLEGRO_DISPLAY *display); #ifdef ALLEGRO_CFG_SHADER_GLSL ALLEGRO_SHADER *_al_create_shader_glsl(ALLEGRO_SHADER_PLATFORM platform); void _al_set_shader_glsl(ALLEGRO_DISPLAY *display, ALLEGRO_SHADER *shader); #endif #ifdef ALLEGRO_CFG_SHADER_HLSL ALLEGRO_SHADER *_al_create_shader_hlsl(ALLEGRO_SHADER_PLATFORM platform, int shader_model); void _al_set_shader_hlsl(ALLEGRO_DISPLAY *display, ALLEGRO_SHADER *shader); #endif #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_system.h000066400000000000000000000056521473414355200236560ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_system_h #define __al_included_allegro5_aintern_system_h #include "allegro5/system.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_haptic.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/internal/aintern_mouse.h" #include "allegro5/internal/aintern_touch_input.h" #include "allegro5/internal/aintern_vector.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_SYSTEM_INTERFACE ALLEGRO_SYSTEM_INTERFACE; struct ALLEGRO_SYSTEM_INTERFACE { ALLEGRO_SYSTEM_ID id; ALLEGRO_SYSTEM *(*initialize)(int flags); ALLEGRO_DISPLAY_INTERFACE *(*get_display_driver)(void); ALLEGRO_KEYBOARD_DRIVER *(*get_keyboard_driver)(void); ALLEGRO_MOUSE_DRIVER *(*get_mouse_driver)(void); ALLEGRO_TOUCH_INPUT_DRIVER *(*get_touch_input_driver)(void); ALLEGRO_JOYSTICK_DRIVER *(*get_joystick_driver)(void); ALLEGRO_HAPTIC_DRIVER *(*get_haptic_driver)(void); int (*get_num_display_modes)(void); ALLEGRO_DISPLAY_MODE *(*get_display_mode)(int index, ALLEGRO_DISPLAY_MODE *mode); void (*shutdown_system)(void); int (*get_num_video_adapters)(void); bool (*get_monitor_info)(int adapter, ALLEGRO_MONITOR_INFO *info); int (*get_monitor_refresh_rate)(int adapter); int (*get_monitor_dpi)(int adapter); ALLEGRO_MOUSE_CURSOR *(*create_mouse_cursor)(ALLEGRO_BITMAP *bmp, int x_focus, int y_focus); void (*destroy_mouse_cursor)(ALLEGRO_MOUSE_CURSOR *cursor); bool (*get_cursor_position)(int *ret_x, int *ret_y); bool (*grab_mouse)(ALLEGRO_DISPLAY *display); bool (*ungrab_mouse)(void); ALLEGRO_PATH *(*get_path)(int id); bool (*inhibit_screensaver)(bool inhibit); void (*thread_init)(ALLEGRO_THREAD *thread); void (*thread_exit)(ALLEGRO_THREAD *thread); void *(*open_library)(const char *filename); void *(*import_symbol)(void *library, const char *symbol); void (*close_library)(void *handle); void (*heartbeat)(void); void (*heartbeat_init)(void); double (*get_time)(void); void (*rest)(double seconds); void (*init_timeout)(ALLEGRO_TIMEOUT *timeout, double seconds); }; struct ALLEGRO_SYSTEM { ALLEGRO_SYSTEM_INTERFACE *vt; _AL_VECTOR displays; /* Keep a list of all displays attached to us. */ ALLEGRO_PATH *user_exe_path; int mouse_wheel_precision; int min_bitmap_size; bool installed; }; void _al_register_system_interfaces(void); extern _AL_VECTOR _al_system_interfaces; AL_VAR(_AL_DTOR_LIST *, _al_dtor_list); AL_FUNC(void *, _al_open_library, (const char *filename)); AL_FUNC(void *, _al_import_symbol, (void *library, const char *symbol)); AL_FUNC(void, _al_close_library, (void *library)); AL_FUNC(uint32_t, _al_get_joystick_compat_version, (void)); AL_FUNC(uint32_t, _al_get_keyboard_compat_version, (void)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_thread.h000066400000000000000000000026441473414355200235770ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_thread_h #define __al_included_allegro5_aintern_thread_h #include ALLEGRO_INTERNAL_THREAD_HEADER #ifdef __cplusplus extern "C" { #endif typedef struct _AL_THREAD _AL_THREAD; typedef struct _AL_MUTEX _AL_MUTEX; typedef struct _AL_COND _AL_COND; void _al_thread_create(_AL_THREAD*, void (*proc)(_AL_THREAD*, void*), void *arg); void _al_thread_create_with_stacksize(_AL_THREAD*, void (*proc)(_AL_THREAD*, void*), void *arg, size_t stacksize); void _al_thread_set_should_stop(_AL_THREAD *); /* static inline bool _al_get_thread_should_stop(_AL_THREAD *); */ void _al_thread_join(_AL_THREAD*); void _al_thread_detach(_AL_THREAD*); void _al_mutex_init(_AL_MUTEX*); void _al_mutex_init_recursive(_AL_MUTEX*); void _al_mutex_destroy(_AL_MUTEX*); /* static inline void _al_mutex_lock(_AL_MUTEX*); */ /* static inline void _al_mutex_unlock(_AL_MUTEX*); */ /* All 5 functions below are declared inline in aintuthr.h. * FIXME: Why are they all inline? And if they have to be, why not treat them * the same as the two functions above? */ #ifdef ALLEGRO_WINDOWS void _al_cond_init(_AL_COND*); void _al_cond_destroy(_AL_COND*); void _al_cond_wait(_AL_COND*, _AL_MUTEX*); void _al_cond_broadcast(_AL_COND*); void _al_cond_signal(_AL_COND*); #endif int _al_cond_timedwait(_AL_COND*, _AL_MUTEX*, const ALLEGRO_TIMEOUT *timeout); #ifdef __cplusplus } #endif #endif /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_timer.h000066400000000000000000000005121473414355200234400ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_timer_h #define __al_included_allegro5_aintern_timer_h #ifdef __cplusplus extern "C" { #endif void _al_init_timers(void); int _al_get_active_timers_count(void); double _al_timer_thread_handle_tick(double interval); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_tls.h000066400000000000000000000005041473414355200231230ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_tls_h #define __al_included_allegro5_aintern_tls_h #ifdef __cplusplus extern "C" { #endif void _al_tls_init_once(void); void _al_reinitialize_tls_values(void); int *_al_tls_get_dtor_owner_count(void); #ifdef __cplusplus } #endif #endif /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_touch_input.h000066400000000000000000000016121473414355200246630ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_touch_input_h #define __al_included_allegro5_aintern_touch_input_h #include "allegro5/internal/aintern_driver.h" #include "allegro5/internal/aintern_events.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_TOUCH_INPUT_DRIVER { int id; AL_METHOD(bool, init_touch_input, (void)); AL_METHOD(void, exit_touch_input, (void)); AL_METHOD(ALLEGRO_TOUCH_INPUT*, get_touch_input, (void)); AL_METHOD(void, get_touch_input_state, (ALLEGRO_TOUCH_INPUT_STATE *ret_state)); AL_METHOD(void, set_mouse_emulation_mode, (int mode)); AL_METHOD(int, get_mouse_emulation_mode, (void)); } ALLEGRO_TOUCH_INPUT_DRIVER; struct ALLEGRO_TOUCH_INPUT { ALLEGRO_EVENT_SOURCE es; ALLEGRO_EVENT_SOURCE mouse_emulation_es; int mouse_emulation_mode; }; extern _AL_DRIVER_INFO _al_touch_input_driver_list[]; #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_transform.h000066400000000000000000000003151473414355200243340ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_transform_h #define __al_included_allegro5_aintern_transform_h bool _al_transform_is_translation(const ALLEGRO_TRANSFORM* trans, float *dx, float *dy); #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_tri_soft.h000066400000000000000000000014641473414355200241600ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_tri_soft_h #define __al_included_allegro5_aintern_tri_soft_h struct ALLEGRO_BITMAP; /* Duplicated in allegro_primitives.h */ #ifndef _ALLEGRO_VERTEX_DEFINED #define _ALLEGRO_VERTEX_DEFINED typedef struct ALLEGRO_VERTEX ALLEGRO_VERTEX; struct ALLEGRO_VERTEX { float x, y, z; float u, v; ALLEGRO_COLOR color; }; #endif AL_FUNC(void, _al_triangle_2d, (ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, ALLEGRO_VERTEX* v3)); AL_FUNC(void, _al_draw_soft_triangle, ( ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, ALLEGRO_VERTEX* v3, uintptr_t state, void (*init)(uintptr_t, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*), void (*first)(uintptr_t, int, int, int, int), void (*step)(uintptr_t, int), void (*draw)(uintptr_t, int, int, int))); #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_vector.h000066400000000000000000000031271473414355200236270ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_vector_h #define __al_included_allegro5_aintern_vector_h #ifdef __cplusplus extern "C" { #endif typedef struct _AL_VECTOR { /* private */ size_t _itemsize; char* _items; /* total size == (size + unused) * itemsize */ size_t _size; size_t _unused; } _AL_VECTOR; #define _AL_VECTOR_INITIALIZER(typ) { sizeof(typ), 0, 0, 0 } AL_FUNC(void, _al_vector_init, (_AL_VECTOR*, size_t itemsize)); AL_INLINE(size_t, _al_vector_size, (const _AL_VECTOR *vec), { return vec->_size; }) AL_INLINE(bool, _al_vector_is_empty, (const _AL_VECTOR *vec), { ASSERT(vec); return vec->_size == 0 ? true : false; }) AL_INLINE(bool, _al_vector_is_nonempty, (const _AL_VECTOR *vec), { ASSERT(vec); return !_al_vector_is_empty(vec); }) AL_FUNC(void*, _al_vector_ref, (const _AL_VECTOR*, unsigned int index)); AL_FUNC(void*, _al_vector_ref_front, (const _AL_VECTOR*)); AL_FUNC(void*, _al_vector_ref_back, (const _AL_VECTOR*)); AL_FUNC(bool, _al_vector_append_array, (_AL_VECTOR *vec, unsigned int num, const void *arr)); AL_FUNC(void*, _al_vector_alloc_back, (_AL_VECTOR*)); AL_FUNC(void*, _al_vector_alloc_mid, (_AL_VECTOR*, unsigned int index)); AL_FUNC(int, _al_vector_find, (const _AL_VECTOR*, const void *ptr_item)); AL_FUNC(bool, _al_vector_contains, (const _AL_VECTOR*, const void *ptr_item)); AL_FUNC(void, _al_vector_delete_at, (_AL_VECTOR*, unsigned int index)); AL_FUNC(bool, _al_vector_find_and_delete, (_AL_VECTOR*, const void *ptr_item)); AL_FUNC(void, _al_vector_free, (_AL_VECTOR*)); #ifdef __cplusplus } #endif #endif /* vi ts=8 sts=3 sw=3 et */ allegro5-5.2.10.1/include/allegro5/internal/aintern_wclipboard.h000066400000000000000000000005151473414355200244510ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_wclipboard_h #define __al_included_allegro5_aintern_wclipboard_h #include "allegro5/internal/aintern_display.h" #ifdef __cplusplus extern "C" { #endif void _al_win_add_clipboard_functions(ALLEGRO_DISPLAY_INTERFACE *vt); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_wjoyall.h000066400000000000000000000010501473414355200237770ustar00rootroot00000000000000#ifndef __al_included_allegro_aintern_wjoydxnu_h #define __al_included_allegro_aintern_wjoydxnu_h /** Part of the Windows joystick wrapper driver * types are shared here for use by the haptic susbystem. */ typedef struct ALLEGRO_JOYSTICK_WINDOWS_ALL { ALLEGRO_JOYSTICK parent; /* must be first */ bool active; int index; ALLEGRO_JOYSTICK * handle; ALLEGRO_JOYSTICK_DRIVER * driver; } ALLEGRO_JOYSTICK_WINDOWS_ALL; #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_wjoydxnu.h000066400000000000000000000047541473414355200242230ustar00rootroot00000000000000#ifndef __al_included_allegro_aintern_wjoydxnu_h #define __al_included_allegro_aintern_wjoydxnu_h /** Part of the Windows DirectInput joystick * types are shared here for use by the haptic susbystem. */ /* arbitrary limit */ #define MAX_JOYSTICKS 32 /* these limits are from DIJOYSTICK_STATE in dinput.h */ #define MAX_SLIDERS 2 #define MAX_POVS 4 #define MAX_BUTTONS 32 /* the number of joystick events that DirectInput is told to buffer */ #define DEVICE_BUFFER_SIZE 128 /* make sure all the constants add up */ /* the first two sticks are (x,y,z) and (rx,ry,rz) */ ALLEGRO_STATIC_ASSERT(wjoydxnu, _AL_MAX_JOYSTICK_STICKS >= (2 + MAX_SLIDERS + MAX_POVS)); ALLEGRO_STATIC_ASSERT(wjoydxnu, _AL_MAX_JOYSTICK_BUTTONS >= MAX_BUTTONS); #define GUID_EQUAL(a, b) (0 == memcmp(&(a), &(b), sizeof(GUID))) typedef enum { STATE_UNUSED, STATE_BORN, STATE_ALIVE, STATE_DYING } CONFIG_STATE; #define ACTIVE_STATE(st) \ ((st) == STATE_ALIVE || (st) == STATE_DYING) /* helper structure to record information through object_enum_callback */ #define NAME_LEN 128 typedef struct { bool have_x; TCHAR name_x[NAME_LEN]; bool have_y; TCHAR name_y[NAME_LEN]; bool have_z; TCHAR name_z[NAME_LEN]; bool have_rx; TCHAR name_rx[NAME_LEN]; bool have_ry; TCHAR name_ry[NAME_LEN]; bool have_rz; TCHAR name_rz[NAME_LEN]; int num_sliders; TCHAR name_slider[MAX_SLIDERS][NAME_LEN]; int num_povs; TCHAR name_pov[MAX_POVS][NAME_LEN]; int num_buttons; TCHAR name_button[MAX_BUTTONS][NAME_LEN]; } CAPS_AND_NAMES; /* map a DirectInput axis to an Allegro (stick,axis) pair */ typedef struct { int stick, axis; } AXIS_MAPPING; typedef struct ALLEGRO_JOYSTICK_DIRECTX { ALLEGRO_JOYSTICK parent; /* must be first */ CONFIG_STATE config_state; bool marked; LPDIRECTINPUTDEVICE2 device; GUID guid; GUID product_guid; HANDLE waker_event; ALLEGRO_JOYSTICK_STATE joystate; AXIS_MAPPING x_mapping; AXIS_MAPPING y_mapping; AXIS_MAPPING z_mapping; AXIS_MAPPING rx_mapping; AXIS_MAPPING ry_mapping; AXIS_MAPPING rz_mapping; AXIS_MAPPING slider_mapping[MAX_SLIDERS]; int pov_mapping_stick[MAX_POVS]; char name[80]; char all_names[512]; /* button/stick/axis names with NUL terminators */ } ALLEGRO_JOYSTICK_DIRECTX; #ifdef __cplusplus extern "C" { #endif void _al_win_joystick_dinput_trigger_enumeration(void); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_wjoyxi.h000066400000000000000000000024661473414355200236630ustar00rootroot00000000000000#ifndef __al_included_allegro_aintern_wjoydxnu_h #define __al_included_allegro_aintern_wjoydxnu_h /** Part of the Windows XInput joystick * types are shared here for use by the haptic susbystem. */ /* XInput supports only up to 4 joysticks.*/ #define MAX_JOYSTICKS 4 /* XInput joystics always have up to 14 buttons, 2 triggers which are mapped to sliders, and 2 pairs of 2 axes. */ #define MAX_BUTTONS 14 #define MAX_TRIGGERS 2 #define MAX_AXES 2 #define MAX_STICKS 4 /* make sure all the constants add up */ /* the first two sticks are (x,y,z) and (rx,ry,rz) */ ALLEGRO_STATIC_ASSERT(wjoydxnu, _AL_MAX_JOYSTICK_STICKS >= (2 + MAX_TRIGGERS + MAX_STICKS)); ALLEGRO_STATIC_ASSERT(wjoydxnu, _AL_MAX_JOYSTICK_BUTTONS >= MAX_BUTTONS); typedef enum { STATE_UNUSED, STATE_ACTIVE, } CONFIG_STATE; #define ACTIVE_STATE(st) \ ((st) == STATE_ACTIVE) typedef struct ALLEGRO_JOYSTICK_XINPUT { ALLEGRO_JOYSTICK parent; /* must be first */ bool active; ALLEGRO_JOYSTICK_STATE joystate; DWORD index; XINPUT_STATE state; XINPUT_CAPABILITIES capabilities; XINPUT_VIBRATION vibration; char name[80]; char all_names[512]; /* button/stick/axis names with NUL terminators */ } ALLEGRO_JOYSTICK_XINPUT; #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_wunicode.h000066400000000000000000000032071473414355200241410ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_wunicode_h #define __al_included_allegro5_aintern_wunicode_h #ifdef ALLEGRO_WINDOWS #include #ifdef __cplusplus extern "C" { #endif AL_FUNC(wchar_t *, _al_win_ustr_to_utf16, (const ALLEGRO_USTR *u)); AL_FUNC(char *, _al_win_ustr_to_ansi, (const ALLEGRO_USTR *u)); AL_FUNC(wchar_t *, _al_win_utf8_to_utf16, (const char *us)); AL_FUNC(char *, _al_win_utf16_to_utf8, (const wchar_t *ws)); AL_FUNC(char *, _al_win_utf8_to_ansi, (const char* us)); AL_FUNC(char *, _al_win_ansi_to_utf8, (const char *s)); AL_FUNC(char *, _al_win_copy_utf16_to_utf8, (char* us, const wchar_t* ws, size_t uslen)); // wslen is number of wide characters, not bytes. AL_FUNC(char *, _al_win_copy_utf8_to_utf16, (wchar_t* ws, const char *us, size_t wslen)); AL_FUNC(char *, _al_win_copy_ansi_to_utf8, (char* us, const char *s, size_t uslen)); AL_FUNC(char *, _al_win_copy_utf8_to_ansi, (char* s, const char *us, size_t slen)); #ifdef UNICODE #define _twin_tchar_strlen wcslen #define _twin_ustr_to_tchar _al_win_ustr_to_utf16 #define _twin_utf8_to_tchar _al_win_utf8_to_utf16 #define _twin_tchar_to_utf8 _al_win_utf16_to_utf8 #define _twin_copy_tchar_to_utf8 _al_win_copy_utf16_to_utf8 #define _twin_copy_utf8_to_tchar _al_win_copy_utf8_to_utf16 #else #define _twin_tchar_strlen strlen #define _twin_ustr_to_tchar _al_win_ustr_to_ansi #define _twin_utf8_to_tchar _al_win_utf8_to_ansi #define _twin_tchar_to_utf8 _al_win_ansi_to_utf8 #define _twin_copy_tchar_to_utf8 _al_win_copy_ansi_to_utf8 #define _twin_copy_utf8_to_tchar _al_win_copy_utf8_to_ansi #endif #ifdef __cplusplus } #endif #endif #endif /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_x.h000066400000000000000000000003501473414355200225670ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_x_h #define __al_included_allegro5_aintern_x_h #include typedef struct ALLEGRO_SYSTEM_XGLX ALLEGRO_SYSTEM_XGLX; typedef struct ALLEGRO_DISPLAY_XGLX ALLEGRO_DISPLAY_XGLX; #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_xclipboard.h000066400000000000000000000007251473414355200244550ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xclipboard_h #define __al_included_allegro5_aintern_xclipboard_h #include "allegro5/internal/aintern_display.h" void _al_xwin_display_selection_notify(ALLEGRO_DISPLAY *display, XSelectionEvent *xselection); void _al_xwin_display_selection_request(ALLEGRO_DISPLAY *display, XSelectionRequestEvent *xselectionrequest); void _al_xwin_add_clipboard_functions(ALLEGRO_DISPLAY_INTERFACE *vt); #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_xcursor.h000066400000000000000000000011611473414355200240260ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xcursor_h #define __al_included_allegro5_aintern_xcursor_h #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR #include #endif #include "allegro5/internal/aintern_display.h" typedef struct ALLEGRO_MOUSE_CURSOR_XWIN ALLEGRO_MOUSE_CURSOR_XWIN; struct ALLEGRO_MOUSE_CURSOR_XWIN { Cursor cursor; }; ALLEGRO_MOUSE_CURSOR *_al_xwin_create_mouse_cursor(ALLEGRO_BITMAP *bmp, int x_focus, int y_focus); void _al_xwin_destroy_mouse_cursor(ALLEGRO_MOUSE_CURSOR *cursor); void _al_xwin_add_cursor_functions(ALLEGRO_DISPLAY_INTERFACE *vt); #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_xdisplay.h000066400000000000000000000075401473414355200241650ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xdisplay_h #define __al_included_allegro5_aintern_xdisplay_h /* XXX The Raspberry Pi port does not use GLX. It currently substitutes its own * ALLEGRO_DISPLAY_RASPBERRYPI for ALLEGRO_DISPLAY_XGLX by a macro renaming * hack. */ #ifndef ALLEGRO_RASPBERRYPI #include #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_x.h" typedef struct ALLEGRO_DISPLAY_XGLX_GTK ALLEGRO_DISPLAY_XGLX_GTK; typedef struct ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE; /* This is our version of ALLEGRO_DISPLAY with driver specific extra data. */ struct ALLEGRO_DISPLAY_XGLX { /* This must be the first member. */ ALLEGRO_DISPLAY display; /* Driver specifics. */ const struct ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE *overridable_vt; Window window; int xscreen; /* X Screen ID */ int adapter; /* allegro virtual adapter id/index */ GLXWindow glxwindow; GLXContext context; Atom wm_delete_window_atom; XVisualInfo *xvinfo; /* Used when selecting the X11 visual to use. */ GLXFBConfig *fbc; /* Used when creating the OpenGL context. */ int glx_version; /* 130 means 1 major and 3 minor, aka 1.3 */ /* Points to a structure if this display is contained by a GTK top-level * window, otherwise it is NULL. */ ALLEGRO_DISPLAY_XGLX_GTK *gtk; /* If our window is embedded by the XEmbed protocol, this gives * the window ID of the embedder; Otherwise None. */ Window embedder_window; _AL_COND mapped; /* Condition variable to wait for mapping a window. */ bool is_mapped; /* Set to true when mapped. */ int resize_count; /* Increments when resized. */ bool programmatic_resize; /* Set while programmatic resize in progress. */ /* Cursor for this window. */ Cursor invisible_cursor; Cursor current_cursor; bool cursor_hidden; /* Icon for this window. */ Pixmap icon, icon_mask; /* Desktop position. */ int x, y; bool need_initial_position_adjust; int border_left, border_right, border_top, border_bottom; bool borders_known; /* al_set_mouse_xy implementation */ bool mouse_warp; _AL_COND selectioned; /* Condition variable to wait for a selection event a window. */ bool is_selectioned; /* Set to true when selection event received. */ }; void _al_display_xglx_await_resize(ALLEGRO_DISPLAY *d, int old_resize_count, bool delay_hack); void _al_xglx_display_configure(ALLEGRO_DISPLAY *d, int x, int y, int width, int height, bool setglxy); void _al_xglx_display_configure_event(ALLEGRO_DISPLAY *d, XEvent *event); void _al_xwin_display_switch_handler(ALLEGRO_DISPLAY *d, XFocusChangeEvent *event); void _al_xwin_display_switch_handler_inner(ALLEGRO_DISPLAY *d, bool focus_in); void _al_xwin_display_expose(ALLEGRO_DISPLAY *display, XExposeEvent *xevent); /* An ad-hoc interface to allow the GTK backend to override some of the * normal X display interface implementation. */ struct ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE { bool (*create_display_hook)(ALLEGRO_DISPLAY *d, int w, int h); void (*destroy_display_hook)(ALLEGRO_DISPLAY *d, bool is_last); bool (*resize_display)(ALLEGRO_DISPLAY *d, int w, int h); void (*set_window_title)(ALLEGRO_DISPLAY *display, const char *title); void (*set_fullscreen_window)(ALLEGRO_DISPLAY *display, bool onoff); void (*set_window_position)(ALLEGRO_DISPLAY *display, int x, int y); bool (*set_window_constraints)(ALLEGRO_DISPLAY *display, int min_w, int min_h, int max_w, int max_h); bool (*set_display_flag)(ALLEGRO_DISPLAY *display, int flag, bool onoff); void (*check_maximized)(ALLEGRO_DISPLAY *display); }; bool _al_xwin_set_gtk_display_overridable_interface(uint32_t check_version, const ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE *vt); #endif /* !ALLEGRO_RASPBERRYPI */ #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_xdnd.h000066400000000000000000000014471473414355200232650ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xdnd_h #define __al_included_allegro5_aintern_xdnd_h typedef struct { Atom XdndEnter; Atom XdndPosition; Atom XdndStatus; Atom XdndTypeList; Atom XdndActionCopy; Atom XdndDrop; Atom XdndFinished; Atom XdndSelection; Atom XdndLeave; Atom PRIMARY; Atom xdnd_req; Window xdnd_source; } DndInfo; void _al_display_xglx_init_dnd_atoms(ALLEGRO_SYSTEM_XGLX *s); void _al_xwin_accept_drag_and_drop(ALLEGRO_DISPLAY *display, bool accept); bool _al_display_xglx_handle_drag_and_drop(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *allegro_display, XEvent *event); bool _al_display_xglx_handle_drag_and_drop_selection(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *allegro_display, XEvent *xevent); #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_xembed.h000066400000000000000000000021541473414355200235700ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xembed_h #define __al_included_allegro5_aintern_xembed_h /* From XEmbed Protocol Specification version 0.5 */ /* http://standards.freedesktop.org/xembed-spec/latest/index.html */ /* Flags for _XEMBED_INFO */ #define XEMBED_MAPPED (1 << 0) /* XEMBED messages */ #define XEMBED_EMBEDDED_NOTIFY 0 #define XEMBED_WINDOW_ACTIVATE 1 #define XEMBED_WINDOW_DEACTIVATE 2 #define XEMBED_REQUEST_FOCUS 3 #define XEMBED_FOCUS_IN 4 #define XEMBED_FOCUS_OUT 5 #define XEMBED_FOCUS_NEXT 6 #define XEMBED_FOCUS_PREV 7 /* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */ #define XEMBED_MODALITY_ON 10 #define XEMBED_MODALITY_OFF 11 #define XEMBED_REGISTER_ACCELERATOR 12 #define XEMBED_UNREGISTER_ACCELERATOR 13 #define XEMBED_ACTIVATE_ACCELERATOR 14 /* Details for XEMBED_FOCUS_IN: */ #define XEMBED_FOCUS_CURRENT 0 #define XEMBED_FOCUS_FIRST 1 #define XEMBED_FOCUS_LAST 2 #endif /* vim: set sts=4 sw=4 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_xevents.h000066400000000000000000000004401473414355200240140ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xevents_h #define __al_included_allegro5_aintern_xevents_h #include "allegro5/internal/aintern_thread.h" void _al_xwin_background_thread(_AL_THREAD *self, void *arg); void _al_display_xglx_closebutton(ALLEGRO_DISPLAY *d, XEvent *xevent); #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_xfullscreen.h000066400000000000000000000060051473414355200246550ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xfullscreen_h #define __al_included_allegro5_aintern_xfullscreen_h /* fullscreen and multi monitor stuff */ typedef struct _ALLEGRO_XGLX_MMON_INTERFACE _ALLEGRO_XGLX_MMON_INTERFACE; struct _ALLEGRO_XGLX_MMON_INTERFACE { int (*get_num_display_modes)(ALLEGRO_SYSTEM_XGLX *s, int adapter); ALLEGRO_DISPLAY_MODE *(*get_display_mode)(ALLEGRO_SYSTEM_XGLX *s, int, int, ALLEGRO_DISPLAY_MODE*); bool (*set_mode)(ALLEGRO_SYSTEM_XGLX *, ALLEGRO_DISPLAY_XGLX *, int, int, int, int); void (*store_mode)(ALLEGRO_SYSTEM_XGLX *); void (*restore_mode)(ALLEGRO_SYSTEM_XGLX *, int); void (*get_display_offset)(ALLEGRO_SYSTEM_XGLX *, int, int *, int *); int (*get_num_adapters)(ALLEGRO_SYSTEM_XGLX *); bool (*get_monitor_info)(ALLEGRO_SYSTEM_XGLX *, int, ALLEGRO_MONITOR_INFO *); int (*get_default_adapter)(ALLEGRO_SYSTEM_XGLX *); int (*get_adapter)(ALLEGRO_SYSTEM_XGLX *, ALLEGRO_DISPLAY_XGLX *); int (*get_xscreen)(ALLEGRO_SYSTEM_XGLX *, int); void (*post_setup)(ALLEGRO_SYSTEM_XGLX *, ALLEGRO_DISPLAY_XGLX *); void (*handle_xevent)(ALLEGRO_SYSTEM_XGLX *, ALLEGRO_DISPLAY_XGLX *, XEvent *e); }; extern _ALLEGRO_XGLX_MMON_INTERFACE _al_xglx_mmon_interface; int _al_xsys_mheadx_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s); int _al_xsys_mheadx_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter); void _al_xsys_get_active_window_center(ALLEGRO_SYSTEM_XGLX *s, int *x, int *y); void _al_xsys_mmon_exit(ALLEGRO_SYSTEM_XGLX *s); int _al_xglx_get_num_display_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter); ALLEGRO_DISPLAY_MODE *_al_xglx_get_display_mode( ALLEGRO_SYSTEM_XGLX *s, int adapter, int index, ALLEGRO_DISPLAY_MODE *mode); bool _al_xglx_fullscreen_set_mode(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, int w, int h, int format, int refresh_rate); void _al_xglx_store_video_mode(ALLEGRO_SYSTEM_XGLX *s); void _al_xglx_restore_video_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter); void _al_xglx_fullscreen_to_display(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d); void _al_xglx_set_fullscreen_window(ALLEGRO_DISPLAY *display, int value); void _al_xglx_get_display_offset(ALLEGRO_SYSTEM_XGLX *s, int adapter, int *x, int *y); int _al_xglx_fullscreen_select_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int w, int h, int format, int refresh_rate); bool _al_xglx_get_monitor_info(ALLEGRO_SYSTEM_XGLX *s, int adapter, ALLEGRO_MONITOR_INFO *info); int _al_xglx_get_num_video_adapters(ALLEGRO_SYSTEM_XGLX *s); int _al_xglx_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s); int _al_xglx_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter); void _al_xglx_set_above(ALLEGRO_DISPLAY *display, int value); int _al_xglx_get_adapter(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, bool recalc); void _al_xglx_handle_mmon_event(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, XEvent *e); #ifdef ALLEGRO_XWINDOWS_WITH_XRANDR void _al_xsys_xrandr_init(ALLEGRO_SYSTEM_XGLX *s); void _al_xsys_xrandr_exit(ALLEGRO_SYSTEM_XGLX *s); #endif /* ALLEGRO_XWINDOWS_WITH_XRANDR */ #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_xglx_config.h000066400000000000000000000004161473414355200246320ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xglx_h #define __al_included_allegro5_aintern_xglx_h #include "allegro5/internal/aintern_x.h" void _al_xglx_config_select_visual(ALLEGRO_DISPLAY_XGLX *glx); bool _al_xglx_config_create_context(ALLEGRO_DISPLAY_XGLX *glx); #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_xkeyboard.h000066400000000000000000000006241473414355200243140ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xkeyboard_h #define __al_included_allegro5_aintern_xkeyboard_h #include "allegro5/internal/aintern_keyboard.h" ALLEGRO_KEYBOARD_DRIVER *_al_xwin_keyboard_driver(void); void _al_xwin_keyboard_handler(XKeyEvent *event, ALLEGRO_DISPLAY *display); void _al_xwin_keyboard_switch_handler(ALLEGRO_DISPLAY *display, bool focus_in); #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_xmouse.h000066400000000000000000000011471473414355200236450ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xmouse_h #define __al_included_allegro5_aintern_xmouse_h #include "allegro5/internal/aintern_mouse.h" ALLEGRO_MOUSE_DRIVER *_al_xwin_mouse_driver(void); void _al_xwin_mouse_button_press_handler(int button, ALLEGRO_DISPLAY *display); void _al_xwin_mouse_button_release_handler(int button, ALLEGRO_DISPLAY *d); void _al_xwin_mouse_motion_notify_handler(int x, int y, ALLEGRO_DISPLAY *d); void _al_xwin_mouse_switch_handler(ALLEGRO_DISPLAY *display, const XCrossingEvent *event); bool _al_xwin_grab_mouse(ALLEGRO_DISPLAY *display); bool _al_xwin_ungrab_mouse(void); #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_xsystem.h000066400000000000000000000060631473414355200240430ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xsystem_h #define __al_included_allegro5_aintern_xsystem_h #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE #include #endif #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA #include #endif #ifdef ALLEGRO_XWINDOWS_WITH_XRANDR #include #endif #ifdef ALLEGRO_XWINDOWS_WITH_XSCREENSAVER #include #endif #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_xdnd.h" /* This is our version of ALLEGRO_SYSTEM with driver specific extra data. */ struct ALLEGRO_SYSTEM_XGLX { /* This must be the first member, we "derive" from it. */ ALLEGRO_SYSTEM system; /* Driver specifics. */ /* X11 is not thread-safe. But we use a separate thread to handle X11 events. * Plus, users may call OpenGL commands in the main thread, and we have no * way to enforce locking for them. * The only solution seems to be two X11 display connections. One to do our * input handling, and one for OpenGL graphics. * * Note: these may be NULL if we are not connected to an X server, for * headless command-line tools. We don't have a separate "null" system * driver. */ /* The X11 display. You *MUST* only access this from one * thread at a time, use the mutex lock below to ensure it. */ Display *x11display; /* Another X11 display we use for graphics. You *MUST* * only use this in the main thread. */ Display *gfxdisplay; Atom AllegroAtom; Atom XEmbedAtom; /* drag and drop support */ DndInfo dnd_info; /* Background thread to process X events. * Not used if GTK main loop is used. */ bool have_xevents_thread; _AL_THREAD xevents_thread; _AL_MUTEX lock; /* thread lock for whenever we access internals. */ // FIXME: One condition variable really would be enough. _AL_COND resized; /* Condition variable to wait for resizing a window. */ ALLEGRO_DISPLAY *mouse_grab_display; /* Best effort: may be inaccurate. */ int toggle_mouse_grab_keycode; /* Disabled if zero */ unsigned int toggle_mouse_grab_modifiers; bool inhibit_screensaver; /* Should we inhibit the screensaver? */ bool screen_saver_query_available; bool mmon_interface_inited; #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA int xinerama_available; int xinerama_screen_count; XineramaScreenInfo *xinerama_screen_info; #endif #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE /* For VidMode extension. */ int xfvm_available; int xfvm_screen_count; struct { int mode_count; XF86VidModeModeInfo **modes; XF86VidModeModeInfo *original_mode; } *xfvm_screen; #endif #ifdef ALLEGRO_XWINDOWS_WITH_XRANDR int xrandr_available; int xrandr_event_base; _AL_VECTOR xrandr_screens; _AL_VECTOR xrandr_adaptermap; #endif /* Used to keep track of how many adapters are in use, so the multi-head * code can bail if we try to use more than one. */ int adapter_use_count; int adapter_map[32]; /* XXX magic constant */ }; #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/aintern_xtouch.h000066400000000000000000000003701473414355200236340ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xtouch_h #define __al_included_allegro5_aintern_xtouch_h #include "allegro5/internal/aintern_touch_input.h" void _al_x_handle_touch_event(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, XEvent *e); #endif allegro5-5.2.10.1/include/allegro5/internal/aintern_xwindow.h000066400000000000000000000013241473414355200240210ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintern_xwindow_h #define __al_included_allegro5_aintern_xwindow_h void _al_xwin_set_size_hints(ALLEGRO_DISPLAY *d, int x_off, int y_off); void _al_xwin_reset_size_hints(ALLEGRO_DISPLAY *d); void _al_xwin_set_fullscreen_window(ALLEGRO_DISPLAY *display, int value); void _al_xwin_set_above(ALLEGRO_DISPLAY *display, int value); void _al_xwin_set_frame(ALLEGRO_DISPLAY *display, bool frame_on); void _al_xwin_set_icons(ALLEGRO_DISPLAY *d, int num_icons, ALLEGRO_BITMAP *bitmaps[]); void _al_xwin_maximize(ALLEGRO_DISPLAY *d, bool maximized); void _al_xwin_check_maximized(ALLEGRO_DISPLAY *display); void _al_xwin_get_borders(ALLEGRO_DISPLAY *display); #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/internal/alconfig.h000066400000000000000000000173051473414355200223720ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration defines. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ /* for backward compatibility */ #ifdef USE_CONSOLE #define ALLEGRO_NO_MAGIC_MAIN #define ALLEGRO_USE_CONSOLE #endif /* include platform-specific stuff */ #include "allegro5/platform/alplatf.h" #if defined ALLEGRO_WATCOM #include "allegro5/platform/alwatcom.h" #elif defined ALLEGRO_MINGW32 #include "allegro5/platform/almngw32.h" #elif defined ALLEGRO_BCC32 #include "allegro5/platform/albcc32.h" #elif defined ALLEGRO_MSVC #include "allegro5/platform/almsvc.h" #elif defined ALLEGRO_IPHONE #include "allegro5/platform/aliphonecfg.h" #elif defined ALLEGRO_MACOSX #include "allegro5/platform/alosxcfg.h" #elif defined ALLEGRO_ANDROID #include "allegro5/platform/alandroidcfg.h" #elif defined ALLEGRO_RASPBERRYPI #include "allegro5/platform/alraspberrypicfg.h" #elif defined ALLEGRO_UNIX #include "allegro5/platform/alucfg.h" #elif defined ALLEGRO_SDL #include "allegro5/platform/allegro_sdl_config.h" #else #error platform not supported #endif #include "allegro5/platform/astdint.h" #include "allegro5/platform/astdbool.h" /* 1 << 31 represented as a signed int */ #define _ALLEGRO_UNSTABLE_BIT_SET INT32_MIN /* special definitions for the GCC compiler */ #ifdef __GNUC__ #define ALLEGRO_GCC #ifndef AL_INLINE #ifdef __cplusplus #define AL_INLINE(type, name, args, code) \ static inline type name args; \ static inline type name args code /* Needed if this header is included by C99 code, as * "extern __inline__" in C99 exports a new global function. */ #elif __GNUC_STDC_INLINE__ #define AL_INLINE(type, name, args, code) \ extern __inline__ __attribute__((__gnu_inline__)) type name args; \ extern __inline__ __attribute__((__gnu_inline__)) type name args code #else #define AL_INLINE(type, name, args, code) \ extern __inline__ type name args; \ extern __inline__ type name args code #endif #endif #ifndef AL_INLINE_STATIC #ifdef __cplusplus #define AL_INLINE_STATIC(type, name, args, code) \ AL_INLINE(type, name, args, code) #else #define AL_INLINE_STATIC(type, name, args, code) \ static __inline__ type name args; \ static __inline__ type name args code #endif #endif #define AL_PRINTFUNC(type, name, args, a, b) AL_FUNC(type, name, args) __attribute__ ((format (printf, a, b))) #ifndef INLINE #define INLINE __inline__ #endif #ifndef ZERO_SIZE_ARRAY #if __GNUC__ < 3 #define ZERO_SIZE_ARRAY(type, name) __extension__ type name[0] #else #define ZERO_SIZE_ARRAY(type, name) type name[] /* ISO C99 flexible array members */ #endif #endif #ifdef ALLEGRO_GUESS_INTTYPES_OK #define int64_t signed long long #define uint64_t unsigned long long #endif #ifdef __i386__ #define ALLEGRO_I386 #endif #ifdef __amd64__ #define ALLEGRO_AMD64 #endif #ifdef __arm__ #define ALLEGRO_ARM #endif #ifndef AL_FUNC_DEPRECATED #if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) #define AL_FUNC_DEPRECATED(type, name, args) AL_FUNC(__attribute__ ((deprecated)) type, name, args) #define AL_PRINTFUNC_DEPRECATED(type, name, args, a, b) AL_PRINTFUNC(__attribute__ ((deprecated)) type, name, args, a, b) #define AL_INLINE_DEPRECATED(type, name, args, code) AL_INLINE(__attribute__ ((deprecated)) type, name, args, code) #endif #endif #ifndef AL_ALIAS #define AL_ALIAS(DECL, CALL) \ static __attribute__((unused)) __inline__ DECL \ { \ return CALL; \ } #endif #ifndef AL_ALIAS_VOID_RET #define AL_ALIAS_VOID_RET(DECL, CALL) \ static __attribute__((unused)) __inline__ void DECL \ { \ CALL; \ } #endif #endif /* the rest of this file fills in some default definitions of language * features and helper functions, which are conditionalised so they will * only be included if none of the above headers defined custom versions. */ #ifndef INLINE #define INLINE #endif #ifndef ZERO_SIZE_ARRAY #define ZERO_SIZE_ARRAY(type, name) type name[] #endif #ifndef AL_VAR #define AL_VAR(type, name) extern type name #endif #ifndef AL_ARRAY #define AL_ARRAY(type, name) extern type name[] #endif #ifndef AL_FUNC #define AL_FUNC(type, name, args) type name args #endif #ifndef AL_PRINTFUNC #define AL_PRINTFUNC(type, name, args, a, b) AL_FUNC(type, name, args) #endif #ifndef AL_METHOD #define AL_METHOD(type, name, args) type (*name) args #endif #ifndef AL_FUNCPTR #define AL_FUNCPTR(type, name, args) extern type (*name) args #endif #ifndef AL_FUNCPTRARRAY #define AL_FUNCPTRARRAY(type, name, args) extern type (*name[]) args #endif #ifndef AL_INLINE #define AL_INLINE(type, name, args, code) type name args; #endif #ifndef AL_FUNC_DEPRECATED #define AL_FUNC_DEPRECATED(type, name, args) AL_FUNC(type, name, args) #define AL_PRINTFUNC_DEPRECATED(type, name, args, a, b) AL_PRINTFUNC(type, name, args, a, b) #define AL_INLINE_DEPRECATED(type, name, args, code) AL_INLINE(type, name, args, code) #endif #ifndef AL_ALIAS #define AL_ALIAS(DECL, CALL) \ static INLINE DECL \ { \ return CALL; \ } #endif #ifndef AL_ALIAS_VOID_RET #define AL_ALIAS_VOID_RET(DECL, CALL) \ static INLINE void DECL \ { \ CALL; \ } #endif #ifdef __cplusplus extern "C" { #endif /* endian-independent 3-byte accessor macros */ #ifdef ALLEGRO_LITTLE_ENDIAN #define _AL_READ3BYTES(p) ((*(unsigned char *)(p)) \ | (*((unsigned char *)(p) + 1) << 8) \ | (*((unsigned char *)(p) + 2) << 16)) #define _AL_WRITE3BYTES(p,c) ((*(unsigned char *)(p) = (c)), \ (*((unsigned char *)(p) + 1) = (c) >> 8), \ (*((unsigned char *)(p) + 2) = (c) >> 16)) #elif defined ALLEGRO_BIG_ENDIAN #define _AL_READ3BYTES(p) ((*(unsigned char *)(p) << 16) \ | (*((unsigned char *)(p) + 1) << 8) \ | (*((unsigned char *)(p) + 2))) #define _AL_WRITE3BYTES(p,c) ((*(unsigned char *)(p) = (c) >> 16), \ (*((unsigned char *)(p) + 1) = (c) >> 8), \ (*((unsigned char *)(p) + 2) = (c))) #else #error endianess not defined #endif #ifdef __cplusplus } #endif allegro5-5.2.10.1/include/allegro5/internal/bstrlib.h000066400000000000000000000363101473414355200222460ustar00rootroot00000000000000/* * This source file has had its exported symbols prefixed with _al_ or _AL_ * for the Allegro project. */ /* * This source file is part of the _al_bstring string library. This code was * written by Paul Hsieh in 2002-2008, and is covered by the BSD open source * license and the GPL. Refer to the accompanying documentation for details * on usage and license. */ /* * bstrlib.c * * This file is the core module for implementing the _al_bstring functions. */ #ifndef _AL_BSTRLIB_INCLUDE #define _AL_BSTRLIB_INCLUDE #ifdef __cplusplus extern "C" { #endif #include #include #include #include #if !defined (BSTRLIB_VSNP_OK) && !defined (BSTRLIB_NOVSNP) # if defined (__TURBOC__) && !defined (__BORLANDC__) # define BSTRLIB_NOVSNP # endif #endif #define _AL_BSTR_ERR (-1) #define _AL_BSTR_OK (0) #define _AL_BSTR_BS_BUFF_LENGTH_GET (0) typedef struct _al_tagbstring * _al_bstring; typedef const struct _al_tagbstring * _al_const_bstring; /* Copy functions */ #define _al_cstr2bstr _al_bfromcstr extern _al_bstring _al_bfromcstr (const char * str); extern _al_bstring _al_bfromcstralloc (int mlen, const char * str); extern _al_bstring _al_blk2bstr (const void * blk, int len); extern char * _al_bstr2cstr (_al_const_bstring s, char z); extern int _al_bcstrfree (char * s); extern _al_bstring _al_bstrcpy (_al_const_bstring b1); extern int _al_bassign (_al_bstring a, _al_const_bstring b); extern int _al_bassignmidstr (_al_bstring a, _al_const_bstring b, int left, int len); extern int _al_bassigncstr (_al_bstring a, const char * str); extern int _al_bassignblk (_al_bstring a, const void * s, int len); /* Destroy function */ extern int _al_bdestroy (_al_bstring b); /* Space allocation hinting functions */ extern int _al_balloc (_al_bstring s, int len); extern int _al_ballocmin (_al_bstring b, int len); /* Substring extraction */ extern _al_bstring _al_bmidstr (_al_const_bstring b, int left, int len); /* Various standard manipulations */ extern int _al_bconcat (_al_bstring b0, _al_const_bstring b1); extern int _al_bconchar (_al_bstring b0, char c); extern int _al_bcatcstr (_al_bstring b, const char * s); extern int _al_bcatblk (_al_bstring b, const void * s, int len); extern int _al_binsert (_al_bstring s1, int pos, _al_const_bstring s2, unsigned char fill); extern int _al_binsertch (_al_bstring s1, int pos, int len, unsigned char fill); extern int _al_breplace (_al_bstring b1, int pos, int len, _al_const_bstring b2, unsigned char fill); extern int _al_bdelete (_al_bstring s1, int pos, int len); extern int _al_bsetstr (_al_bstring b0, int pos, _al_const_bstring b1, unsigned char fill); extern int _al_btrunc (_al_bstring b, int n); /* Scan/search functions */ extern int _al_bstricmp (_al_const_bstring b0, _al_const_bstring b1); extern int _al_bstrnicmp (_al_const_bstring b0, _al_const_bstring b1, int n); extern int _al_biseqcaseless (_al_const_bstring b0, _al_const_bstring b1); extern int _al_bisstemeqcaselessblk (_al_const_bstring b0, const void * blk, int len); extern int _al_biseq (_al_const_bstring b0, _al_const_bstring b1); extern int _al_bisstemeqblk (_al_const_bstring b0, const void * blk, int len); extern int _al_biseqcstr (_al_const_bstring b, const char * s); extern int _al_biseqcstrcaseless (_al_const_bstring b, const char * s); extern int _al_bstrcmp (_al_const_bstring b0, _al_const_bstring b1); extern int _al_bstrncmp (_al_const_bstring b0, _al_const_bstring b1, int n); extern int _al_binstr (_al_const_bstring s1, int pos, _al_const_bstring s2); extern int _al_binstrr (_al_const_bstring s1, int pos, _al_const_bstring s2); extern int _al_binstrcaseless (_al_const_bstring s1, int pos, _al_const_bstring s2); extern int _al_binstrrcaseless (_al_const_bstring s1, int pos, _al_const_bstring s2); extern int _al_bstrchrp (_al_const_bstring b, int c, int pos); extern int _al_bstrrchrp (_al_const_bstring b, int c, int pos); #define _al_bstrchr(b,c) _al_bstrchrp ((b), (c), 0) #define _al_bstrrchr(b,c) _al_bstrrchrp ((b), (c), _al_blength(b)-1) extern int _al_binchr (_al_const_bstring b0, int pos, _al_const_bstring b1); extern int _al_binchrr (_al_const_bstring b0, int pos, _al_const_bstring b1); extern int _al_bninchr (_al_const_bstring b0, int pos, _al_const_bstring b1); extern int _al_bninchrr (_al_const_bstring b0, int pos, _al_const_bstring b1); extern int _al_bfindreplace (_al_bstring b, _al_const_bstring find, _al_const_bstring repl, int pos); extern int _al_bfindreplacecaseless (_al_bstring b, _al_const_bstring find, _al_const_bstring repl, int pos); /* List of string container functions */ struct _al_bstrList { int qty, mlen; _al_bstring * entry; }; extern struct _al_bstrList * _al_bstrListCreate (void); extern int _al_bstrListDestroy (struct _al_bstrList * sl); extern int _al_bstrListAlloc (struct _al_bstrList * sl, int msz); extern int _al_bstrListAllocMin (struct _al_bstrList * sl, int msz); /* String split and join functions */ extern struct _al_bstrList * _al_bsplit (_al_const_bstring str, unsigned char splitChar); extern struct _al_bstrList * _al_bsplits (_al_const_bstring str, _al_const_bstring splitStr); extern struct _al_bstrList * _al_bsplitstr (_al_const_bstring str, _al_const_bstring splitStr); extern _al_bstring _al_bjoin (const struct _al_bstrList * bl, _al_const_bstring sep); extern int _al_bsplitcb (_al_const_bstring str, unsigned char splitChar, int pos, int (* cb) (void * parm, int ofs, int len), void * parm); extern int _al_bsplitscb (_al_const_bstring str, _al_const_bstring splitStr, int pos, int (* cb) (void * parm, int ofs, int len), void * parm); extern int _al_bsplitstrcb (_al_const_bstring str, _al_const_bstring splitStr, int pos, int (* cb) (void * parm, int ofs, int len), void * parm); /* Miscellaneous functions */ extern int _al_bpattern (_al_bstring b, int len); extern int _al_btoupper (_al_bstring b); extern int _al_btolower (_al_bstring b); extern int _al_bltrimws (_al_bstring b); extern int _al_brtrimws (_al_bstring b); extern int _al_btrimws (_al_bstring b); #if !defined (BSTRLIB_NOVSNP) extern _al_bstring _al_bformat (const char * fmt, ...); extern int _al_bformata (_al_bstring b, const char * fmt, ...); extern int _al_bassignformat (_al_bstring b, const char * fmt, ...); extern int _al_bvcformata (_al_bstring b, int count, const char * fmt, va_list arglist); #define _al_bvformata(ret, b, fmt, lastarg) { \ _al_bstring bstrtmp_b = (b); \ const char * bstrtmp_fmt = (fmt); \ int bstrtmp_r = _AL_BSTR_ERR, bstrtmp_sz = 16; \ for (;;) { \ va_list bstrtmp_arglist; \ va_start (bstrtmp_arglist, lastarg); \ bstrtmp_r = _al_bvcformata (bstrtmp_b, bstrtmp_sz, bstrtmp_fmt, bstrtmp_arglist); \ va_end (bstrtmp_arglist); \ if (bstrtmp_r >= 0) { /* Everything went ok */ \ bstrtmp_r = _AL_BSTR_OK; \ break; \ } else if (-bstrtmp_r <= bstrtmp_sz) { /* A real error? */ \ bstrtmp_r = _AL_BSTR_ERR; \ break; \ } \ bstrtmp_sz = -bstrtmp_r; /* Doubled or target size */ \ } \ ret = bstrtmp_r; \ } #endif typedef int (*_al_bNgetc) (void *parm); typedef size_t (* _al_bNread) (void *buff, size_t elsize, size_t nelem, void *parm); /* Input functions */ extern _al_bstring _al_bgets (_al_bNgetc getcPtr, void * parm, char terminator); extern _al_bstring _al_bread (_al_bNread readPtr, void * parm); extern int _al_bgetsa (_al_bstring b, _al_bNgetc getcPtr, void * parm, char terminator); extern int _al_bassigngets (_al_bstring b, _al_bNgetc getcPtr, void * parm, char terminator); extern int _al_breada (_al_bstring b, _al_bNread readPtr, void * parm); /* Stream functions */ extern struct _al_bStream * _al_bsopen (_al_bNread readPtr, void * parm); extern void * _al_bsclose (struct _al_bStream * s); extern int _al_bsbufflength (struct _al_bStream * s, int sz); extern int _al_bsreadln (_al_bstring b, struct _al_bStream * s, char terminator); extern int _al_bsreadlns (_al_bstring r, struct _al_bStream * s, _al_const_bstring term); extern int _al_bsread (_al_bstring b, struct _al_bStream * s, int n); extern int _al_bsreadlna (_al_bstring b, struct _al_bStream * s, char terminator); extern int _al_bsreadlnsa (_al_bstring r, struct _al_bStream * s, _al_const_bstring term); extern int _al_bsreada (_al_bstring b, struct _al_bStream * s, int n); extern int _al_bsunread (struct _al_bStream * s, _al_const_bstring b); extern int _al_bspeek (_al_bstring r, const struct _al_bStream * s); extern int _al_bssplitscb (struct _al_bStream * s, _al_const_bstring splitStr, int (* cb) (void * parm, int ofs, _al_const_bstring entry), void * parm); extern int _al_bssplitstrcb (struct _al_bStream * s, _al_const_bstring splitStr, int (* cb) (void * parm, int ofs, _al_const_bstring entry), void * parm); extern int _al_bseof (const struct _al_bStream * s); #ifndef __al_tagbstring_defined #define __al_tagbstring_defined struct _al_tagbstring { int mlen; int slen; unsigned char * data; }; #endif /* Accessor macros */ #define _al_blengthe(b, e) (((b) == (void *)0 || (b)->slen < 0) ? (int)(e) : ((b)->slen)) #define _al_blength(b) (_al_blengthe ((b), 0)) #define _al_bdataofse(b, o, e) (((b) == (void *)0 || (b)->data == (void*)0) ? (char *)(e) : ((char *)(b)->data) + (o)) #define _al_bdataofs(b, o) (_al_bdataofse ((b), (o), (void *)0)) #define _al_bdatae(b, e) (_al_bdataofse (b, 0, e)) #define _al_bdata(b) (_al_bdataofs (b, 0)) #define _al_bchare(b, p, e) ((((unsigned)(p)) < (unsigned)_al_blength(b)) ? ((b)->data[(p)]) : (e)) #define _al_bchar(b, p) _al_bchare ((b), (p), '\0') /* Static constant string initialization macro */ #define _al_bsStaticMlen(q,m) {(m), (int) sizeof(q)-1, (unsigned char *) ("" q "")} #if defined(_MSC_VER) # define _al_bsStatic(q) _al_bsStaticMlen(q,-32) #endif #ifndef _al_bsStatic # define _al_bsStatic(q) _al_bsStaticMlen(q,-__LINE__) #endif /* Static constant block parameter pair */ #define _al_bsStaticBlkParms(q) ((void *)("" q "")), ((int) sizeof(q)-1) /* Reference building macros */ #define _al_cstr2tbstr _al_btfromcstr #define _al_btfromcstr(t,s) { \ (t).data = (unsigned char *) (s); \ (t).slen = ((t).data) ? ((int) (strlen) ((char *)(t).data)) : 0; \ (t).mlen = -1; \ } #define _al_blk2tbstr(t,s,l) { \ (t).data = (unsigned char *) (s); \ (t).slen = l; \ (t).mlen = -1; \ } #define _al_btfromblk(t,s,l) _al_blk2tbstr(t,s,l) #define _al_bmid2tbstr(t,b,p,l) { \ _al_const_bstring bstrtmp_s = (b); \ if (bstrtmp_s && bstrtmp_s->data && bstrtmp_s->slen >= 0) { \ int bstrtmp_left = (p); \ int bstrtmp_len = (l); \ if (bstrtmp_left < 0) { \ bstrtmp_len += bstrtmp_left; \ bstrtmp_left = 0; \ } \ if (bstrtmp_len > bstrtmp_s->slen - bstrtmp_left) \ bstrtmp_len = bstrtmp_s->slen - bstrtmp_left; \ if (bstrtmp_len <= 0) { \ (t).data = (unsigned char *)""; \ (t).slen = 0; \ } else { \ (t).data = bstrtmp_s->data + bstrtmp_left; \ (t).slen = bstrtmp_len; \ } \ } else { \ (t).data = (unsigned char *)""; \ (t).slen = 0; \ } \ (t).mlen = -__LINE__; \ } #define _al_btfromblkltrimws(t,s,l) { \ int bstrtmp_idx = 0, bstrtmp_len = (l); \ unsigned char * bstrtmp_s = (s); \ if (bstrtmp_s && bstrtmp_len >= 0) { \ for (; bstrtmp_idx < bstrtmp_len; bstrtmp_idx++) { \ if (!isspace (bstrtmp_s[bstrtmp_idx])) break; \ } \ } \ (t).data = bstrtmp_s + bstrtmp_idx; \ (t).slen = bstrtmp_len - bstrtmp_idx; \ (t).mlen = -__LINE__; \ } #define _al_btfromblkrtrimws(t,s,l) { \ int bstrtmp_len = (l) - 1; \ unsigned char * bstrtmp_s = (s); \ if (bstrtmp_s && bstrtmp_len >= 0) { \ for (; bstrtmp_len >= 0; bstrtmp_len--) { \ if (!isspace (bstrtmp_s[bstrtmp_len])) break; \ } \ } \ (t).data = bstrtmp_s; \ (t).slen = bstrtmp_len + 1; \ (t).mlen = -__LINE__; \ } #define _al_btfromblktrimws(t,s,l) { \ int bstrtmp_idx = 0, bstrtmp_len = (l) - 1; \ unsigned char * bstrtmp_s = (s); \ if (bstrtmp_s && bstrtmp_len >= 0) { \ for (; bstrtmp_idx <= bstrtmp_len; bstrtmp_idx++) { \ if (!isspace (bstrtmp_s[bstrtmp_idx])) break; \ } \ for (; bstrtmp_len >= bstrtmp_idx; bstrtmp_len--) { \ if (!isspace (bstrtmp_s[bstrtmp_len])) break; \ } \ } \ (t).data = bstrtmp_s + bstrtmp_idx; \ (t).slen = bstrtmp_len + 1 - bstrtmp_idx; \ (t).mlen = -__LINE__; \ } /* Write protection macros */ #define _al_bwriteprotect(t) { if ((t).mlen >= 0) (t).mlen = -1; } #define _al_bwriteallow(t) { if ((t).mlen == -1) (t).mlen = (t).slen + ((t).slen == 0); } #define _al_biswriteprotected(t) ((t).mlen <= 0) #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/joystick.h000066400000000000000000000055001473414355200206250ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Joystick routines. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_joystick_h #define __al_included_allegro5_joystick_h #include "allegro5/base.h" #include "allegro5/events.h" #ifdef __cplusplus extern "C" { #endif /* internal values */ #define _AL_MAX_JOYSTICK_AXES 3 #define _AL_MAX_JOYSTICK_STICKS 16 #ifdef ALLEGRO_ANDROID #define _AL_MAX_JOYSTICK_BUTTONS 36 #else #define _AL_MAX_JOYSTICK_BUTTONS 32 #endif /* Type: ALLEGRO_JOYSTICK */ typedef struct ALLEGRO_JOYSTICK ALLEGRO_JOYSTICK; /* Type: ALLEGRO_JOYSTICK_STATE */ typedef struct ALLEGRO_JOYSTICK_STATE ALLEGRO_JOYSTICK_STATE; struct ALLEGRO_JOYSTICK_STATE { struct { float axis[_AL_MAX_JOYSTICK_AXES]; /* -1.0 to 1.0 */ } stick[_AL_MAX_JOYSTICK_STICKS]; int button[_AL_MAX_JOYSTICK_BUTTONS]; /* 0 to 32767 */ }; /* Enum: ALLEGRO_JOYFLAGS */ enum ALLEGRO_JOYFLAGS { ALLEGRO_JOYFLAG_DIGITAL = 0x01, ALLEGRO_JOYFLAG_ANALOGUE = 0x02 }; AL_FUNC(bool, al_install_joystick, (void)); AL_FUNC(void, al_uninstall_joystick, (void)); AL_FUNC(bool, al_is_joystick_installed, (void)); AL_FUNC(bool, al_reconfigure_joysticks, (void)); AL_FUNC(int, al_get_num_joysticks, (void)); AL_FUNC(ALLEGRO_JOYSTICK *, al_get_joystick, (int joyn)); AL_FUNC(void, al_release_joystick, (ALLEGRO_JOYSTICK *)); AL_FUNC(bool, al_get_joystick_active, (ALLEGRO_JOYSTICK *)); AL_FUNC(const char*, al_get_joystick_name, (ALLEGRO_JOYSTICK *)); AL_FUNC(int, al_get_joystick_num_sticks, (ALLEGRO_JOYSTICK *)); AL_FUNC(int, al_get_joystick_stick_flags, (ALLEGRO_JOYSTICK *, int stick)); /* junk? */ AL_FUNC(const char*, al_get_joystick_stick_name, (ALLEGRO_JOYSTICK *, int stick)); AL_FUNC(int, al_get_joystick_num_axes, (ALLEGRO_JOYSTICK *, int stick)); AL_FUNC(const char*, al_get_joystick_axis_name, (ALLEGRO_JOYSTICK *, int stick, int axis)); AL_FUNC(int, al_get_joystick_num_buttons, (ALLEGRO_JOYSTICK *)); AL_FUNC(const char*, al_get_joystick_button_name, (ALLEGRO_JOYSTICK *, int buttonn)); AL_FUNC(void, al_get_joystick_state, (ALLEGRO_JOYSTICK *, ALLEGRO_JOYSTICK_STATE *ret_state)); AL_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_joystick_event_source, (void)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/keyboard.h000066400000000000000000000037221473414355200205720ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Keyboard routines. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_keyboard_h #define __al_included_allegro5_keyboard_h #include "allegro5/base.h" #include "allegro5/events.h" #include "allegro5/keycodes.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_KEYBOARD ALLEGRO_KEYBOARD; /* Type: ALLEGRO_KEYBOARD_STATE */ typedef struct ALLEGRO_KEYBOARD_STATE ALLEGRO_KEYBOARD_STATE; struct ALLEGRO_KEYBOARD_STATE { struct ALLEGRO_DISPLAY *display; /* public */ /* internal */ unsigned int __key_down__internal__[(ALLEGRO_KEY_MAX + 31) / 32]; }; AL_FUNC(bool, al_is_keyboard_installed, (void)); AL_FUNC(bool, al_install_keyboard, (void)); AL_FUNC(void, al_uninstall_keyboard, (void)); AL_FUNC(bool, al_can_set_keyboard_leds, (void)); AL_FUNC(bool, al_set_keyboard_leds, (int leds)); AL_FUNC(const char *, al_keycode_to_name, (int keycode)); AL_FUNC(void, al_get_keyboard_state, (ALLEGRO_KEYBOARD_STATE *ret_state)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) AL_FUNC(void, al_clear_keyboard_state, (ALLEGRO_DISPLAY *display)); #endif AL_FUNC(bool, al_key_down, (const ALLEGRO_KEYBOARD_STATE *, int keycode)); AL_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_keyboard_event_source, (void)); #ifdef __cplusplus } #endif #endif /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ allegro5-5.2.10.1/include/allegro5/keycodes.h000066400000000000000000000133241473414355200205770ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Keycode constants. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_keycodes_h #define __al_included_allegro5_keycodes_h /* Note these values are deliberately the same as in Allegro 4.1.x */ enum { ALLEGRO_KEY_A = 1, ALLEGRO_KEY_B = 2, ALLEGRO_KEY_C = 3, ALLEGRO_KEY_D = 4, ALLEGRO_KEY_E = 5, ALLEGRO_KEY_F = 6, ALLEGRO_KEY_G = 7, ALLEGRO_KEY_H = 8, ALLEGRO_KEY_I = 9, ALLEGRO_KEY_J = 10, ALLEGRO_KEY_K = 11, ALLEGRO_KEY_L = 12, ALLEGRO_KEY_M = 13, ALLEGRO_KEY_N = 14, ALLEGRO_KEY_O = 15, ALLEGRO_KEY_P = 16, ALLEGRO_KEY_Q = 17, ALLEGRO_KEY_R = 18, ALLEGRO_KEY_S = 19, ALLEGRO_KEY_T = 20, ALLEGRO_KEY_U = 21, ALLEGRO_KEY_V = 22, ALLEGRO_KEY_W = 23, ALLEGRO_KEY_X = 24, ALLEGRO_KEY_Y = 25, ALLEGRO_KEY_Z = 26, ALLEGRO_KEY_0 = 27, ALLEGRO_KEY_1 = 28, ALLEGRO_KEY_2 = 29, ALLEGRO_KEY_3 = 30, ALLEGRO_KEY_4 = 31, ALLEGRO_KEY_5 = 32, ALLEGRO_KEY_6 = 33, ALLEGRO_KEY_7 = 34, ALLEGRO_KEY_8 = 35, ALLEGRO_KEY_9 = 36, ALLEGRO_KEY_PAD_0 = 37, ALLEGRO_KEY_PAD_1 = 38, ALLEGRO_KEY_PAD_2 = 39, ALLEGRO_KEY_PAD_3 = 40, ALLEGRO_KEY_PAD_4 = 41, ALLEGRO_KEY_PAD_5 = 42, ALLEGRO_KEY_PAD_6 = 43, ALLEGRO_KEY_PAD_7 = 44, ALLEGRO_KEY_PAD_8 = 45, ALLEGRO_KEY_PAD_9 = 46, ALLEGRO_KEY_F1 = 47, ALLEGRO_KEY_F2 = 48, ALLEGRO_KEY_F3 = 49, ALLEGRO_KEY_F4 = 50, ALLEGRO_KEY_F5 = 51, ALLEGRO_KEY_F6 = 52, ALLEGRO_KEY_F7 = 53, ALLEGRO_KEY_F8 = 54, ALLEGRO_KEY_F9 = 55, ALLEGRO_KEY_F10 = 56, ALLEGRO_KEY_F11 = 57, ALLEGRO_KEY_F12 = 58, ALLEGRO_KEY_ESCAPE = 59, ALLEGRO_KEY_TILDE = 60, ALLEGRO_KEY_MINUS = 61, ALLEGRO_KEY_EQUALS = 62, ALLEGRO_KEY_BACKSPACE = 63, ALLEGRO_KEY_TAB = 64, ALLEGRO_KEY_OPENBRACE = 65, ALLEGRO_KEY_CLOSEBRACE = 66, ALLEGRO_KEY_ENTER = 67, ALLEGRO_KEY_SEMICOLON = 68, ALLEGRO_KEY_QUOTE = 69, ALLEGRO_KEY_BACKSLASH = 70, ALLEGRO_KEY_BACKSLASH2 = 71, /* DirectInput calls this DIK_OEM_102: "< > | on UK/Germany keyboards" */ ALLEGRO_KEY_COMMA = 72, ALLEGRO_KEY_FULLSTOP = 73, ALLEGRO_KEY_SLASH = 74, ALLEGRO_KEY_SPACE = 75, ALLEGRO_KEY_INSERT = 76, ALLEGRO_KEY_DELETE = 77, ALLEGRO_KEY_HOME = 78, ALLEGRO_KEY_END = 79, ALLEGRO_KEY_PGUP = 80, ALLEGRO_KEY_PGDN = 81, ALLEGRO_KEY_LEFT = 82, ALLEGRO_KEY_RIGHT = 83, ALLEGRO_KEY_UP = 84, ALLEGRO_KEY_DOWN = 85, ALLEGRO_KEY_PAD_SLASH = 86, ALLEGRO_KEY_PAD_ASTERISK = 87, ALLEGRO_KEY_PAD_MINUS = 88, ALLEGRO_KEY_PAD_PLUS = 89, ALLEGRO_KEY_PAD_DELETE = 90, ALLEGRO_KEY_PAD_ENTER = 91, ALLEGRO_KEY_PRINTSCREEN = 92, ALLEGRO_KEY_PAUSE = 93, ALLEGRO_KEY_ABNT_C1 = 94, ALLEGRO_KEY_YEN = 95, ALLEGRO_KEY_KANA = 96, ALLEGRO_KEY_CONVERT = 97, ALLEGRO_KEY_NOCONVERT = 98, ALLEGRO_KEY_AT = 99, ALLEGRO_KEY_CIRCUMFLEX = 100, ALLEGRO_KEY_COLON2 = 101, ALLEGRO_KEY_KANJI = 102, ALLEGRO_KEY_PAD_EQUALS = 103, /* MacOS X */ ALLEGRO_KEY_BACKQUOTE = 104, /* MacOS X */ ALLEGRO_KEY_SEMICOLON2 = 105, /* MacOS X -- TODO: ask lillo what this should be */ ALLEGRO_KEY_COMMAND = 106, /* MacOS X */ ALLEGRO_KEY_BACK = 107, /* Android back key */ ALLEGRO_KEY_VOLUME_UP = 108, ALLEGRO_KEY_VOLUME_DOWN = 109, /* Android game keys */ ALLEGRO_KEY_SEARCH = 110, ALLEGRO_KEY_DPAD_CENTER = 111, ALLEGRO_KEY_BUTTON_X = 112, ALLEGRO_KEY_BUTTON_Y = 113, ALLEGRO_KEY_DPAD_UP = 114, ALLEGRO_KEY_DPAD_DOWN = 115, ALLEGRO_KEY_DPAD_LEFT = 116, ALLEGRO_KEY_DPAD_RIGHT = 117, ALLEGRO_KEY_SELECT = 118, ALLEGRO_KEY_START = 119, ALLEGRO_KEY_BUTTON_L1 = 120, ALLEGRO_KEY_BUTTON_R1 = 121, ALLEGRO_KEY_BUTTON_L2 = 122, ALLEGRO_KEY_BUTTON_R2 = 123, ALLEGRO_KEY_BUTTON_A = 124, ALLEGRO_KEY_BUTTON_B = 125, ALLEGRO_KEY_THUMBL = 126, ALLEGRO_KEY_THUMBR = 127, ALLEGRO_KEY_UNKNOWN = 128, /* All codes up to before ALLEGRO_KEY_MODIFIERS can be freely * assignedas additional unknown keys, like various multimedia * and application keys keyboards may have. */ ALLEGRO_KEY_MODIFIERS = 215, ALLEGRO_KEY_LSHIFT = 215, ALLEGRO_KEY_RSHIFT = 216, ALLEGRO_KEY_LCTRL = 217, ALLEGRO_KEY_RCTRL = 218, ALLEGRO_KEY_ALT = 219, ALLEGRO_KEY_ALTGR = 220, ALLEGRO_KEY_LWIN = 221, ALLEGRO_KEY_RWIN = 222, ALLEGRO_KEY_MENU = 223, ALLEGRO_KEY_SCROLLLOCK = 224, ALLEGRO_KEY_NUMLOCK = 225, ALLEGRO_KEY_CAPSLOCK = 226, ALLEGRO_KEY_MAX }; enum { ALLEGRO_KEYMOD_SHIFT = 0x00001, ALLEGRO_KEYMOD_CTRL = 0x00002, ALLEGRO_KEYMOD_ALT = 0x00004, ALLEGRO_KEYMOD_LWIN = 0x00008, ALLEGRO_KEYMOD_RWIN = 0x00010, ALLEGRO_KEYMOD_MENU = 0x00020, ALLEGRO_KEYMOD_ALTGR = 0x00040, ALLEGRO_KEYMOD_COMMAND = 0x00080, ALLEGRO_KEYMOD_SCROLLLOCK = 0x00100, ALLEGRO_KEYMOD_NUMLOCK = 0x00200, ALLEGRO_KEYMOD_CAPSLOCK = 0x00400, ALLEGRO_KEYMOD_INALTSEQ = 0x00800, ALLEGRO_KEYMOD_ACCENT1 = 0x01000, ALLEGRO_KEYMOD_ACCENT2 = 0x02000, ALLEGRO_KEYMOD_ACCENT3 = 0x04000, ALLEGRO_KEYMOD_ACCENT4 = 0x08000 }; #endif allegro5-5.2.10.1/include/allegro5/memory.h000066400000000000000000000042731473414355200203040ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Memory management routines. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_memory_h #define __al_included_allegro5_memory_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_MEMORY_INTERFACE */ typedef struct ALLEGRO_MEMORY_INTERFACE ALLEGRO_MEMORY_INTERFACE; struct ALLEGRO_MEMORY_INTERFACE { void *(*mi_malloc)(size_t n, int line, const char *file, const char *func); void (*mi_free)(void *ptr, int line, const char *file, const char *func); void *(*mi_realloc)(void *ptr, size_t n, int line, const char *file, const char *func); void *(*mi_calloc)(size_t count, size_t n, int line, const char *file, const char *func); }; AL_FUNC(void, al_set_memory_interface, (ALLEGRO_MEMORY_INTERFACE *iface)); /* Function: al_malloc */ #define al_malloc(n) \ (al_malloc_with_context((n), __LINE__, __FILE__, __func__)) /* Function: al_free */ #define al_free(p) \ (al_free_with_context((p), __LINE__, __FILE__, __func__)) /* Function: al_realloc */ #define al_realloc(p, n) \ (al_realloc_with_context((p), (n), __LINE__, __FILE__, __func__)) /* Function: al_calloc */ #define al_calloc(c, n) \ (al_calloc_with_context((c), (n), __LINE__, __FILE__, __func__)) AL_FUNC(void *, al_malloc_with_context, (size_t n, int line, const char *file, const char *func)); AL_FUNC(void, al_free_with_context, (void *ptr, int line, const char *file, const char *func)); AL_FUNC(void *, al_realloc_with_context, (void *ptr, size_t n, int line, const char *file, const char *func)); AL_FUNC(void *, al_calloc_with_context, (size_t count, size_t n, int line, const char *file, const char *func)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/monitor.h000066400000000000000000000013651473414355200204620ustar00rootroot00000000000000#ifndef __al_included_allegro5_monitor_h #define __al_included_allegro5_monitor_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_MONITOR_INFO */ typedef struct ALLEGRO_MONITOR_INFO { int x1; int y1; int x2; int y2; } ALLEGRO_MONITOR_INFO; enum { ALLEGRO_DEFAULT_DISPLAY_ADAPTER = -1 }; AL_FUNC(int, al_get_num_video_adapters, (void)); AL_FUNC(bool, al_get_monitor_info, (int adapter, ALLEGRO_MONITOR_INFO *info)); AL_FUNC(int, al_get_monitor_dpi, (int adapter)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) AL_FUNC(int, al_get_monitor_refresh_rate, (int adapter)); #endif #ifdef __cplusplus } #endif #endif /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/mouse.h000066400000000000000000000056251473414355200201260ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Mouse routines. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_mouse_h #define __al_included_allegro5_mouse_h #include "allegro5/base.h" #include "allegro5/events.h" #ifdef __cplusplus extern "C" { #endif /* Allow up to four extra axes for future expansion. */ #define ALLEGRO_MOUSE_MAX_EXTRA_AXES 4 typedef struct ALLEGRO_MOUSE ALLEGRO_MOUSE; /* Type: ALLEGRO_MOUSE_STATE */ typedef struct ALLEGRO_MOUSE_STATE ALLEGRO_MOUSE_STATE; struct ALLEGRO_MOUSE_STATE { /* (x, y) Primary mouse position * (z) Mouse wheel position (1D 'wheel'), or, * (w, z) Mouse wheel position (2D 'ball') * display - the display the mouse is on (coordinates are relative to this) * pressure - the pressure applied to the mouse (for stylus/tablet) */ int x; int y; int z; int w; int more_axes[ALLEGRO_MOUSE_MAX_EXTRA_AXES]; int buttons; float pressure; struct ALLEGRO_DISPLAY *display; }; typedef enum ALLEGRO_MOUSE_BUTTON { ALLEGRO_MOUSE_BUTTON_LEFT = 1, ALLEGRO_MOUSE_BUTTON_RIGHT = 2, ALLEGRO_MOUSE_BUTTON_MIDDLE = 3, } ALLEGRO_MOUSE_BUTTON; AL_FUNC(bool, al_is_mouse_installed, (void)); AL_FUNC(bool, al_install_mouse, (void)); AL_FUNC(void, al_uninstall_mouse, (void)); AL_FUNC(unsigned int, al_get_mouse_num_buttons, (void)); AL_FUNC(unsigned int, al_get_mouse_num_axes, (void)); AL_FUNC(bool, al_set_mouse_xy, (struct ALLEGRO_DISPLAY *display, int x, int y)); AL_FUNC(bool, al_set_mouse_z, (int z)); AL_FUNC(bool, al_set_mouse_w, (int w)); AL_FUNC(bool, al_set_mouse_axis, (int axis, int value)); AL_FUNC(void, al_get_mouse_state, (ALLEGRO_MOUSE_STATE *ret_state)); AL_FUNC(bool, al_mouse_button_down, (const ALLEGRO_MOUSE_STATE *state, int button)); AL_FUNC(int, al_get_mouse_state_axis, (const ALLEGRO_MOUSE_STATE *state, int axis)); AL_FUNC(bool, al_can_get_mouse_cursor_position, (void)); AL_FUNC(bool, al_get_mouse_cursor_position, (int *ret_x, int *ret_y)); AL_FUNC(bool, al_grab_mouse, (struct ALLEGRO_DISPLAY *display)); AL_FUNC(bool, al_ungrab_mouse, (void)); AL_FUNC(void, al_set_mouse_wheel_precision, (int precision)); AL_FUNC(int, al_get_mouse_wheel_precision, (void)); AL_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_mouse_event_source, (void)); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/mouse_cursor.h000066400000000000000000000040211473414355200215100ustar00rootroot00000000000000#ifndef __al_included_allegro5_mouse_cursor_h #define __al_included_allegro5_mouse_cursor_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_MOUSE_CURSOR ALLEGRO_MOUSE_CURSOR; typedef enum ALLEGRO_SYSTEM_MOUSE_CURSOR { ALLEGRO_SYSTEM_MOUSE_CURSOR_NONE = 0, ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT = 1, ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW = 2, ALLEGRO_SYSTEM_MOUSE_CURSOR_BUSY = 3, ALLEGRO_SYSTEM_MOUSE_CURSOR_QUESTION = 4, ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT = 5, ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE = 6, ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N = 7, ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_W = 8, ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_S = 9, ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E = 10, ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW = 11, ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_SW = 12, ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_SE = 13, ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE = 14, ALLEGRO_SYSTEM_MOUSE_CURSOR_PROGRESS = 15, ALLEGRO_SYSTEM_MOUSE_CURSOR_PRECISION = 16, ALLEGRO_SYSTEM_MOUSE_CURSOR_LINK = 17, ALLEGRO_SYSTEM_MOUSE_CURSOR_ALT_SELECT = 18, ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE = 19, ALLEGRO_NUM_SYSTEM_MOUSE_CURSORS } ALLEGRO_SYSTEM_MOUSE_CURSOR; struct ALLEGRO_BITMAP; struct ALLEGRO_DISPLAY; AL_FUNC(ALLEGRO_MOUSE_CURSOR *, al_create_mouse_cursor, ( struct ALLEGRO_BITMAP *sprite, int xfocus, int yfocus)); AL_FUNC(void, al_destroy_mouse_cursor, (ALLEGRO_MOUSE_CURSOR *)); AL_FUNC(bool, al_set_mouse_cursor, (struct ALLEGRO_DISPLAY *display, ALLEGRO_MOUSE_CURSOR *cursor)); AL_FUNC(bool, al_set_system_mouse_cursor, (struct ALLEGRO_DISPLAY *display, ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id)); AL_FUNC(bool, al_show_mouse_cursor, (struct ALLEGRO_DISPLAY *display)); AL_FUNC(bool, al_hide_mouse_cursor, (struct ALLEGRO_DISPLAY *display)); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/opengl/000077500000000000000000000000001473414355200201015ustar00rootroot00000000000000allegro5-5.2.10.1/include/allegro5/opengl/GLext/000077500000000000000000000000001473414355200211245ustar00rootroot00000000000000allegro5-5.2.10.1/include/allegro5/opengl/GLext/gl_ext_api.h000066400000000000000000004454131473414355200234230ustar00rootroot00000000000000/* */ #ifdef _ALLEGRO_GL_VERSION_1_2 AGL_API(void, BlendColor, (GLclampf, GLclampf, GLclampf, GLclampf)) AGL_API(void, BlendEquation, (GLenum)) AGL_API(void, DrawRangeElements, (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *)) AGL_API(void, ColorTable, (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, ColorTableParameterfv, (GLenum, GLenum, const GLfloat *)) AGL_API(void, ColorTableParameteriv, (GLenum, GLenum, const GLint *)) AGL_API(void, CopyColorTable, (GLenum, GLenum, GLint, GLint, GLsizei)) AGL_API(void, GetColorTable, (GLenum, GLenum, GLenum, GLvoid *)) AGL_API(void, GetColorTableParameterfv, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetColorTableParameteriv, (GLenum, GLenum, GLint *)) AGL_API(void, ColorSubTable, (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, CopyColorSubTable, (GLenum, GLsizei, GLint, GLint, GLsizei)) AGL_API(void, TexImage3D, (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *)) AGL_API(void, TexSubImage3D, (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, CopyTexSubImage3D, (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)) #endif #if defined _ALLEGRO_GL_ARB_imaging AGL_API(void, ConvolutionFilter1D, (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, ConvolutionFilter2D, (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, ConvolutionParameterf, (GLenum, GLenum, GLfloat)) AGL_API(void, ConvolutionParameterfv, (GLenum, GLenum, const GLfloat *)) AGL_API(void, ConvolutionParameteri, (GLenum, GLenum, GLint)) AGL_API(void, ConvolutionParameteriv, (GLenum, GLenum, const GLint *)) AGL_API(void, CopyConvolutionFilter1D, (GLenum, GLenum, GLint, GLint, GLsizei)) AGL_API(void, CopyConvolutionFilter2D, (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei)) AGL_API(void, GetConvolutionFilter, (GLenum, GLenum, GLenum, GLvoid *)) AGL_API(void, GetConvolutionParameterfv, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetConvolutionParameteriv, (GLenum, GLenum, GLint *)) AGL_API(void, GetSeparableFilter, (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *)) AGL_API(void, SeparableFilter2D, (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *)) AGL_API(void, GetHistogram, (GLenum, GLboolean, GLenum, GLenum, GLvoid *)) AGL_API(void, GetHistogramParameterfv, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetHistogramParameteriv, (GLenum, GLenum, GLint *)) AGL_API(void, GetMinmax, (GLenum, GLboolean, GLenum, GLenum, GLvoid *)) AGL_API(void, GetMinmaxParameterfv, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetMinmaxParameteriv, (GLenum, GLenum, GLint *)) AGL_API(void, Histogram, (GLenum, GLsizei, GLenum, GLboolean)) AGL_API(void, Minmax, (GLenum, GLenum, GLboolean)) AGL_API(void, ResetHistogram, (GLenum)) AGL_API(void, ResetMinmax, (GLenum)) #endif #if defined _ALLEGRO_GL_VERSION_1_3 AGL_API(void, ActiveTexture, (GLenum)) AGL_API(void, ClientActiveTexture, (GLenum)) AGL_API(void, MultiTexCoord1d, (GLenum, GLdouble)) AGL_API(void, MultiTexCoord1dv, (GLenum, const GLdouble *)) AGL_API(void, MultiTexCoord1f, (GLenum, GLfloat)) AGL_API(void, MultiTexCoord1fv, (GLenum, const GLfloat *)) AGL_API(void, MultiTexCoord1i, (GLenum, GLint)) AGL_API(void, MultiTexCoord1iv, (GLenum, const GLint *)) AGL_API(void, MultiTexCoord1s, (GLenum, GLshort)) AGL_API(void, MultiTexCoord1sv, (GLenum, const GLshort *)) AGL_API(void, MultiTexCoord2d, (GLenum, GLdouble, GLdouble)) AGL_API(void, MultiTexCoord2dv, (GLenum, const GLdouble *)) AGL_API(void, MultiTexCoord2f, (GLenum, GLfloat, GLfloat)) AGL_API(void, MultiTexCoord2fv, (GLenum, const GLfloat *)) AGL_API(void, MultiTexCoord2i, (GLenum, GLint, GLint)) AGL_API(void, MultiTexCoord2iv, (GLenum, const GLint *)) AGL_API(void, MultiTexCoord2s, (GLenum, GLshort, GLshort)) AGL_API(void, MultiTexCoord2sv, (GLenum, const GLshort *)) AGL_API(void, MultiTexCoord3d, (GLenum, GLdouble, GLdouble, GLdouble)) AGL_API(void, MultiTexCoord3dv, (GLenum, const GLdouble *)) AGL_API(void, MultiTexCoord3f, (GLenum, GLfloat, GLfloat, GLfloat)) AGL_API(void, MultiTexCoord3fv, (GLenum, const GLfloat *)) AGL_API(void, MultiTexCoord3i, (GLenum, GLint, GLint, GLint)) AGL_API(void, MultiTexCoord3iv, (GLenum, const GLint *)) AGL_API(void, MultiTexCoord3s, (GLenum, GLshort, GLshort, GLshort)) AGL_API(void, MultiTexCoord3sv, (GLenum, const GLshort *)) AGL_API(void, MultiTexCoord4d, (GLenum, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, MultiTexCoord4dv, (GLenum, const GLdouble *)) AGL_API(void, MultiTexCoord4f, (GLenum, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, MultiTexCoord4fv, (GLenum, const GLfloat *)) AGL_API(void, MultiTexCoord4i, (GLenum, GLint, GLint, GLint, GLint)) AGL_API(void, MultiTexCoord4iv, (GLenum, const GLint *)) AGL_API(void, MultiTexCoord4s, (GLenum, GLshort, GLshort, GLshort, GLshort)) AGL_API(void, MultiTexCoord4sv, (GLenum, const GLshort *)) AGL_API(void, LoadTransposeMatrixf, (const GLfloat *)) AGL_API(void, LoadTransposeMatrixd, (const GLdouble *)) AGL_API(void, MultTransposeMatrixf, (const GLfloat *)) AGL_API(void, MultTransposeMatrixd, (const GLdouble *)) AGL_API(void, SampleCoverage, (GLclampf, GLboolean)) AGL_API(void, CompressedTexImage3D, (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *)) AGL_API(void, CompressedTexImage2D, (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *)) AGL_API(void, CompressedTexImage1D, (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *)) AGL_API(void, CompressedTexSubImage3D, (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *)) AGL_API(void, CompressedTexSubImage2D, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *)) AGL_API(void, CompressedTexSubImage1D, (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *)) AGL_API(void, GetCompressedTexImage, (GLenum, GLint, GLvoid *)) #endif #if defined _ALLEGRO_GL_VERSION_1_4 AGL_API(void, BlendFuncSeparate, (GLenum, GLenum, GLenum, GLenum)) AGL_API(void, FogCoordf, (GLfloat)) AGL_API(void, FogCoordfv, (const GLfloat *)) AGL_API(void, FogCoordd, (GLdouble)) AGL_API(void, FogCoorddv, (const GLdouble *)) AGL_API(void, FogCoordPointer, (GLenum, GLsizei, const GLvoid *)) AGL_API(void, MultiDrawArrays, (GLenum, GLint *, GLsizei *, GLsizei)) AGL_API(void, MultiDrawElements, (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei)) AGL_API(void, PointParameterf, (GLenum, GLfloat)) AGL_API(void, PointParameterfv, (GLenum, const GLfloat *)) AGL_API(void, PointParameteri, (GLenum, GLint)) AGL_API(void, PointParameteriv, (GLenum, const GLint *)) AGL_API(void, SecondaryColor3b, (GLbyte, GLbyte, GLbyte)) AGL_API(void, SecondaryColor3bv, (const GLbyte *)) AGL_API(void, SecondaryColor3d, (GLdouble, GLdouble, GLdouble)) AGL_API(void, SecondaryColor3dv, (const GLdouble *)) AGL_API(void, SecondaryColor3f, (GLfloat, GLfloat, GLfloat)) AGL_API(void, SecondaryColor3fv, (const GLfloat *)) AGL_API(void, SecondaryColor3i, (GLint, GLint, GLint)) AGL_API(void, SecondaryColor3iv, (const GLint *)) AGL_API(void, SecondaryColor3s, (GLshort, GLshort, GLshort)) AGL_API(void, SecondaryColor3sv, (const GLshort *)) AGL_API(void, SecondaryColor3ub, (GLubyte, GLubyte, GLubyte)) AGL_API(void, SecondaryColor3ubv, (const GLubyte *)) AGL_API(void, SecondaryColor3ui, (GLuint, GLuint, GLuint)) AGL_API(void, SecondaryColor3uiv, (const GLuint *)) AGL_API(void, SecondaryColor3us, (GLushort, GLushort, GLushort)) AGL_API(void, SecondaryColor3usv, (const GLushort *)) AGL_API(void, SecondaryColorPointer, (GLint, GLenum, GLsizei, const GLvoid *)) AGL_API(void, WindowPos2d, (GLdouble, GLdouble)) AGL_API(void, WindowPos2dv, (const GLdouble *)) AGL_API(void, WindowPos2f, (GLfloat, GLfloat)) AGL_API(void, WindowPos2fv, (const GLfloat *)) AGL_API(void, WindowPos2i, (GLint, GLint)) AGL_API(void, WindowPos2iv, (const GLint *)) AGL_API(void, WindowPos2s, (GLshort, GLshort)) AGL_API(void, WindowPos2sv, (const GLshort *)) AGL_API(void, WindowPos3d, (GLdouble, GLdouble, GLdouble)) AGL_API(void, WindowPos3dv, (const GLdouble *)) AGL_API(void, WindowPos3f, (GLfloat, GLfloat, GLfloat)) AGL_API(void, WindowPos3fv, (const GLfloat *)) AGL_API(void, WindowPos3i, (GLint, GLint, GLint)) AGL_API(void, WindowPos3iv, (const GLint *)) AGL_API(void, WindowPos3s, (GLshort, GLshort, GLshort)) AGL_API(void, WindowPos3sv, (const GLshort *)) #endif #if defined _ALLEGRO_GL_VERSION_1_5 AGL_API(void, BindBuffer, (GLenum, GLuint)) AGL_API(void, DeleteBuffers, (GLsizei, const GLuint *)) AGL_API(void, GenBuffers, (GLsizei, GLuint *)) AGL_API(GLboolean, IsBuffer, (GLuint)) AGL_API(void, BufferData, (GLenum, GLsizeiptr, const GLvoid *, GLenum)) AGL_API(void, BufferSubData, (GLenum, GLintptr, GLsizeiptr, const GLvoid *)) AGL_API(void, GetBufferSubData, (GLenum, GLintptr, GLsizeiptr, GLvoid *)) AGL_API(GLvoid*, MapBuffer, (GLenum, GLenum)) AGL_API(GLboolean, UnmapBuffer, (GLenum)) AGL_API(void, GetBufferParameteriv, (GLenum, GLenum, GLint *)) AGL_API(void, GetBufferPointerv, (GLenum, GLenum, GLvoid* *)) AGL_API(void, GenQueries, (GLsizei, GLuint *)) AGL_API(void, DeleteQueries, (GLsizei, const GLuint *)) AGL_API(GLboolean, IsQuery, (GLuint)) AGL_API(void, BeginQuery, (GLenum, GLuint)) AGL_API(void, EndQuery, (GLenum)) AGL_API(void, GetQueryiv, (GLenum, GLenum, GLint *)) AGL_API(void, GetQueryObjectiv, (GLuint, GLenum, GLint *)) AGL_API(void, GetQueryObjectuiv, (GLuint, GLenum, GLuint *)) #endif #if defined _ALLEGRO_GL_VERSION_2_0 AGL_API(void, BlendEquationSeparate, (GLenum, GLenum)) AGL_API(GLuint, CreateProgram, (void)) AGL_API(GLuint, CreateShader, (GLenum)) AGL_API(void, DeleteProgram, (GLuint)) AGL_API(void, DeleteShader, (GLuint)) AGL_API(void, AttachShader, (GLuint, GLuint)) AGL_API(void, DetachShader, (GLuint, GLuint)) AGL_API(void, ShaderSource, (GLuint, GLsizei, const GLchar **, const GLint *)) AGL_API(void, CompileShader, (GLuint)) AGL_API(GLboolean, IsProgram, (GLuint)) AGL_API(GLboolean, IsShader, (GLuint)) AGL_API(void, LinkProgram, (GLuint)) AGL_API(void, UseProgram, (GLuint)) AGL_API(void, ValidateProgram, (GLuint)) AGL_API(void, Uniform1f, (GLint, GLfloat)) AGL_API(void, Uniform2f, (GLint, GLfloat, GLfloat)) AGL_API(void, Uniform3f, (GLint, GLfloat, GLfloat, GLfloat)) AGL_API(void, Uniform4f, (GLint, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, Uniform1i, (GLint, GLint)) AGL_API(void, Uniform2i, (GLint, GLint, GLint)) AGL_API(void, Uniform3i, (GLint, GLint, GLint, GLint)) AGL_API(void, Uniform4i, (GLint, GLint, GLint, GLint, GLint)) AGL_API(void, Uniform1fv, (GLint, GLsizei, const GLfloat *)) AGL_API(void, Uniform2fv, (GLint, GLsizei, const GLfloat *)) AGL_API(void, Uniform3fv, (GLint, GLsizei, const GLfloat *)) AGL_API(void, Uniform4fv, (GLint, GLsizei, const GLfloat *)) AGL_API(void, Uniform1iv, (GLint, GLsizei, const GLint *)) AGL_API(void, Uniform2iv, (GLint, GLsizei, const GLint *)) AGL_API(void, Uniform3iv, (GLint, GLsizei, const GLint *)) AGL_API(void, Uniform4iv, (GLint, GLsizei, const GLint *)) AGL_API(void, UniformMatrix2fv, (GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, UniformMatrix3fv, (GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, UniformMatrix4fv, (GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, GetShaderfv, (GLuint, GLenum, GLfloat *)) AGL_API(void, GetShaderiv, (GLuint, GLenum, GLint *)) AGL_API(void, GetProgramfv, (GLuint, GLenum, GLfloat *)) AGL_API(void, GetProgramiv, (GLuint, GLenum, GLint *)) AGL_API(void, GetShaderInfoLog, (GLuint, GLsizei, GLsizei *, GLchar *)) AGL_API(void, GetProgramInfoLog, (GLuint, GLsizei, GLsizei *, GLchar *)) AGL_API(void, GetAttachedShaders, (GLuint, GLsizei, GLsizei *, GLuint *)) AGL_API(GLint, GetUniformLocation, (GLuint, const GLchar *)) AGL_API(void, GetActiveUniform, (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *)) AGL_API(void, GetUniformfv, (GLuint, GLint, GLfloat *)) AGL_API(void, GetUniformiv, (GLuint, GLint, GLint *)) AGL_API(void, GetShaderSource, (GLuint, GLsizei, GLsizei *, GLchar *)) AGL_API(void, VertexAttrib1f, (GLuint, GLfloat)) AGL_API(void, VertexAttrib1s, (GLuint, GLshort)) AGL_API(void, VertexAttrib1d, (GLuint, GLdouble)) AGL_API(void, VertexAttrib2f, (GLuint, GLfloat, GLfloat)) AGL_API(void, VertexAttrib2s, (GLuint, GLshort, GLshort)) AGL_API(void, VertexAttrib2d, (GLuint, GLdouble, GLdouble)) AGL_API(void, VertexAttrib3f, (GLuint, GLfloat, GLfloat, GLfloat)) AGL_API(void, VertexAttrib3s, (GLuint, GLshort, GLshort, GLshort)) AGL_API(void, VertexAttrib3d, (GLuint, GLdouble, GLdouble, GLdouble)) AGL_API(void, VertexAttrib4f, (GLuint, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, VertexAttrib4s, (GLuint, GLshort, GLshort, GLshort, GLshort)) AGL_API(void, VertexAttrib4d, (GLuint, GLdouble,GLdouble,GLdouble,GLdouble)) AGL_API(void, VertexAttrib4Nub, (GLuint, GLubyte, GLubyte, GLubyte, GLubyte)) AGL_API(void, VertexAttrib1fv, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib1sv, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib1dv, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib2fv, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib2sv, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib2dv, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib3fv, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib3sv, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib3dv, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib4fv, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib4sv, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib4dv, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib4iv, (GLuint, const GLint *)) AGL_API(void, VertexAttrib4bv, (GLuint, const GLbyte *)) AGL_API(void, VertexAttrib4ubv, (GLuint, const GLubyte *)) AGL_API(void, VertexAttrib4usv, (GLuint, const GLushort *)) AGL_API(void, VertexAttrib4uiv, (GLuint, const GLuint *)) AGL_API(void, VertexAttrib4Nbv, (GLuint, const GLbyte *)) AGL_API(void, VertexAttrib4Nsv, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib4Niv, (GLuint, const GLint *)) AGL_API(void, VertexAttrib4Nubv, (GLuint, const GLubyte *)) AGL_API(void, VertexAttrib4Nusv, (GLuint, const GLushort *)) AGL_API(void, VertexAttrib4Nuiv, (GLuint, const GLuint *)) AGL_API(void, VertexAttribPointer,(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *)) AGL_API(void, EnableVertexAttribArray, (GLuint)) AGL_API(void, DisableVertexAttribArray, (GLuint)) AGL_API(void, BindAttribLocation, (GLuint, GLuint, const GLchar *)) AGL_API(void, GetActiveAttrib, (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *)) AGL_API(GLint, GetAttribLocation, (GLuint, const GLchar *)) AGL_API(void, GetVertexAttribdv, (GLuint, GLenum, GLdouble *)) AGL_API(void, GetVertexAttribfv, (GLuint, GLenum, GLfloat *)) AGL_API(void, GetVertexAttribiv, (GLuint, GLenum, GLint *)) AGL_API(void, GetVertexAttribPointerv, (GLuint, GLenum, GLvoid **)) AGL_API(void, DrawBuffers, (GLsizei n, const GLenum *)) AGL_API(void, StencilOpSeparate, (GLenum, GLenum, GLenum, GLenum)) AGL_API(void, StencilFuncSeparate, (GLenum, GLenum, GLint, GLuint)) AGL_API(void, StencilMaskSeparate, (GLenum, GLuint)) #endif #if defined _ALLEGRO_GL_VERSION_2_1 AGL_API(void, UniformMatrix2x3fv, (GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, UniformMatrix3x2fv, (GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, UniformMatrix2x4fv, (GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, UniformMatrix4x2fv, (GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, UniformMatrix3x4fv, (GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, UniformMatrix4x3fv, (GLint, GLsizei, GLboolean, const GLfloat *)) #endif #if defined _ALLEGRO_GL_VERSION_3_0 /* OpenGL 3.0 also reuses entry points from these extensions: */ /* ARB_framebuffer_object */ /* ARB_map_buffer_range */ /* ARB_vertex_array_object */ AGL_API(void, ColorMaski, (GLuint, GLboolean, GLboolean, GLboolean, GLboolean)) AGL_API(void, GetBooleani_v, (GLenum, GLuint, GLboolean *)) AGL_API(void, GetIntegeri_v, (GLenum, GLuint, GLint *)) AGL_API(void, Enablei, (GLenum, GLuint)) AGL_API(void, Disablei, (GLenum, GLuint)) AGL_API(GLboolean, IsEnabledi, (GLenum, GLuint)) AGL_API(void, BeginTransformFeedback, (GLenum)) AGL_API(void, EndTransformFeedback, (void)) AGL_API(void, BindBufferRange, (GLenum, GLuint, GLuint, GLintptr, GLsizeiptr)) AGL_API(void, BindBufferBase, (GLenum, GLuint, GLuint)) AGL_API(void, TransformFeedbackVaryings, (GLuint, GLsizei, const GLint *, GLenum)) AGL_API(void, GetTransformFeedbackVarying, (GLuint, GLuint, GLint *)) AGL_API(void, ClampColor, (GLenum, GLenum)) AGL_API(void, BeginConditionalRender, (GLuint, GLenum)) AGL_API(void, EndConditionalRender, (void)) AGL_API(void, VertexAttribI1i, (GLuint, GLint)) AGL_API(void, VertexAttribI2i, (GLuint, GLint, GLint)) AGL_API(void, VertexAttribI3i, (GLuint, GLint, GLint, GLint)) AGL_API(void, VertexAttribI4i, (GLuint, GLint, GLint, GLint, GLint)) AGL_API(void, VertexAttribI1ui, (GLuint, GLuint)) AGL_API(void, VertexAttribI2ui, (GLuint, GLuint, GLuint)) AGL_API(void, VertexAttribI3ui, (GLuint, GLuint, GLuint, GLuint)) AGL_API(void, VertexAttribI4ui, (GLuint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, VertexAttribI1iv, (GLuint, const GLint *)) AGL_API(void, VertexAttribI2iv, (GLuint, const GLint *)) AGL_API(void, VertexAttribI3iv, (GLuint, const GLint *)) AGL_API(void, VertexAttribI4iv, (GLuint, const GLint *)) AGL_API(void, VertexAttribI1uiv, (GLuint, const GLuint *)) AGL_API(void, VertexAttribI2uiv, (GLuint, const GLuint *)) AGL_API(void, VertexAttribI3uiv, (GLuint, const GLuint *)) AGL_API(void, VertexAttribI4uiv, (GLuint, const GLuint *)) AGL_API(void, VertexAttribI4bv, (GLuint, const GLbyte *)) AGL_API(void, VertexAttribI4sv, (GLuint, const GLshort *)) AGL_API(void, VertexAttribI4ubv, (GLuint, const GLubyte *)) AGL_API(void, VertexAttribI4usv, (GLuint, const GLushort *)) AGL_API(void, VertexAttribIPointer, (GLuint, GLint, GLenum, GLsizei, const GLvoid *)) AGL_API(void, GetVertexAttribIiv, (GLuint, GLenum, GLint *)) AGL_API(void, GetVertexAttribIuiv, (GLuint, GLenum, GLuint *)) AGL_API(void, GetUniformuiv, (GLuint, GLint, GLuint *)) AGL_API(void, BindFragDataLocation, (GLuint, GLuint, const GLchar *)) AGL_API(GLint, GetFragDataLocation, (GLuint, const GLchar *)) AGL_API(void, Uniform1ui, (GLint, GLuint)) AGL_API(void, Uniform2ui, (GLint, GLuint, GLuint)) AGL_API(void, Uniform3ui, (GLint, GLuint, GLuint, GLuint)) AGL_API(void, Uniform4ui, (GLint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, Uniform1uiv, (GLint, GLsizei, const GLuint *)) AGL_API(void, Uniform2uiv, (GLint, GLsizei, const GLuint *)) AGL_API(void, Uniform3uiv, (GLint, GLsizei, const GLuint *)) AGL_API(void, Uniform4uiv, (GLint, GLsizei, const GLuint *)) AGL_API(void, TexParameterIiv, (GLenum, GLenum, const GLint *)) AGL_API(void, TexParameterIuiv, (GLenum, GLenum, const GLuint *)) AGL_API(void, GetTexParameterIiv, (GLenum, GLenum, GLint *)) AGL_API(void, GetTexParameterIuiv, (GLenum, GLenum, GLuint *)) AGL_API(void, ClearBufferiv, (GLenum, GLint, const GLint *)) AGL_API(void, ClearBufferuiv, (GLenum, GLint, const GLuint *)) AGL_API(void, ClearBufferfv, (GLenum, GLint, const GLfloat *)) AGL_API(void, ClearBufferfi, (GLenum, GLint, GLfloat, GLint)) AGL_API(const GLubyte *, GetStringi, (GLenum, GLuint)) #endif #if defined _ALLEGRO_GL_VERSION_3_1 /* OpenGL 3.1 also reuses entry points from these extensions: */ /* ARB_copy_buffer */ /* ARB_uniform_buffer_object */ AGL_API(void, DrawArraysInstanced, (GLenum, GLint, GLsizei, GLsizei)) AGL_API(void, DrawElementsInstanced, (GLenum, GLsizei, GLenum, const GLvoid *, GLsizei)) AGL_API(void, TexBuffer, (GLenum, GLenum, GLuint)) AGL_API(void, PrimitiveRestartIndex, (GLuint)) #endif #if defined _ALLEGRO_GL_VERSION_3_2 /* OpenGL 3.2 also reuses entry points from these extensions: */ /* ARB_draw_elements_base_vertex */ /* ARB_provoking_vertex */ /* ARB_sync */ /* ARB_texture_multisample */ AGL_API(void, GetInteger64i_v, (GLenum target, GLuint index, GLint64 *data)) AGL_API(void, GetBufferParameteri64v, (GLenum target, GLenum pname, GLint64 *params)) AGL_API(void, ProgramParameteri, (GLuint program, GLenum pname, GLint value)) AGL_API(void, FramebufferTexture, (GLenum target, GLenum attachment, GLuint texture, GLint level)) #endif #if defined _ALLEGRO_GL_VERSION_3_3 /* OpenGL 3.3 also reuses entry points from these extensions: */ /* ARB_blend_func_extended */ /* ARB_sampler_objects */ /* ARB_explicit_attrib_location, but it has none */ /* ARB_occlusion_query2 (no entry points) */ /* ARB_shader_bit_encoding (no entry points) */ /* ARB_texture_rgb10_a2ui (no entry points) */ /* ARB_texture_swizzle (no entry points) */ /* ARB_timer_query */ /* ARB_vertex_type_2_10_10_10_rev */ #endif #if defined _ALLEGRO_GL_VERSION_4_3 AGL_API(void, ClearBufferData, (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data)) AGL_API(void, ClearBufferSubData, (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data)) AGL_API(void, DispatchCompute, (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z)) AGL_API(void, DispatchComputeIndirect, (GLintptr indirect)) AGL_API(void, CopyImageSubData, (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)) AGL_API(void, FramebufferParameteri, (GLenum target, GLenum pname, GLint param)) AGL_API(void, GetFramebufferParameteriv, (GLenum target, GLenum pname, GLint *params)) AGL_API(void, GetInternalformati64v, (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params)) AGL_API(void, InvalidateTexSubImage, (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)) AGL_API(void, InvalidateTexImage, (GLuint texture, GLint level)) AGL_API(void, InvalidateBufferSubData, (GLuint buffer, GLintptr offset, GLsizeiptr length)) AGL_API(void, InvalidateBufferData, (GLuint buffer)) AGL_API(void, InvalidateFramebuffer, (GLenum target, GLsizei numAttachments, const GLenum *attachments)) AGL_API(void, InvalidateSubFramebuffer, (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)) AGL_API(void, MultiDrawArraysIndirect, (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride)) AGL_API(void, MultiDrawElementsIndirect, (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride)) AGL_API(void, GetProgramInterfaceiv, (GLuint program, GLenum programInterface, GLenum pname, GLint *params)) AGL_API(GLuint, GetProgramResourceIndex, (GLuint program, GLenum programInterface, const GLchar *name)) AGL_API(void, GetProgramResourceName, (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name)) AGL_API(void, GetProgramResourceiv, (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params)) AGL_API(GLint, GetProgramResourceLocation, (GLuint program, GLenum programInterface, const GLchar *name)) AGL_API(GLint, GetProgramResourceLocationIndex, (GLuint program, GLenum programInterface, const GLchar *name)) AGL_API(void, ShaderStorageBlockBinding, (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding)) AGL_API(void, TexBufferRange, (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size)) AGL_API(void, TexStorage2DMultisample, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations)) AGL_API(void, TexStorage3DMultisample, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations)) AGL_API(void, TextureView, (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers)) AGL_API(void, BindVertexBuffer, (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride)) AGL_API(void, VertexAttribFormat, (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset)) AGL_API(void, VertexAttribIFormat, (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset)) AGL_API(void, VertexAttribLFormat, (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset)) AGL_API(void, VertexAttribBinding, (GLuint attribindex, GLuint bindingindex)) AGL_API(void, VertexBindingDivisor, (GLuint bindingindex, GLuint divisor)) AGL_API(void, DebugMessageControl, (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled)) AGL_API(void, DebugMessageInsert, (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf)) AGL_API(void, DebugMessageCallback, (GLDEBUGPROC callback, const void *userParam)) AGL_API(GLuint, GetDebugMessageLog, (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog)) AGL_API(void, PushDebugGroup, (GLenum source, GLuint id, GLsizei length, const GLchar *message)) AGL_API(void, PopDebugGroup, (void)) AGL_API(void, ObjectLabel, (GLenum identifier, GLuint name, GLsizei length, const GLchar *label)) AGL_API(void, GetObjectLabel, (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label)) AGL_API(void, ObjectPtrLabel, (const void *ptr, GLsizei length, const GLchar *label)) AGL_API(void, GetObjectPtrLabel, (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label)) #endif /* GL_VERSION_4_3 */ /* */ /* */ #ifdef _ALLEGRO_GL_ARB_multitexture AGL_API(void, ActiveTextureARB, (GLenum)) AGL_API(void, ClientActiveTextureARB, (GLenum)) AGL_API(void, MultiTexCoord1dARB, (GLenum, GLdouble)) AGL_API(void, MultiTexCoord1dvARB, (GLenum, const GLdouble *)) AGL_API(void, MultiTexCoord1fARB, (GLenum, GLfloat)) AGL_API(void, MultiTexCoord1fvARB, (GLenum, const GLfloat *)) AGL_API(void, MultiTexCoord1iARB, (GLenum, GLint)) AGL_API(void, MultiTexCoord1ivARB, (GLenum, const GLint *)) AGL_API(void, MultiTexCoord1sARB, (GLenum, GLshort)) AGL_API(void, MultiTexCoord1svARB, (GLenum, const GLshort *)) AGL_API(void, MultiTexCoord2dARB, (GLenum, GLdouble, GLdouble)) AGL_API(void, MultiTexCoord2dvARB, (GLenum, const GLdouble *)) AGL_API(void, MultiTexCoord2fARB, (GLenum, GLfloat, GLfloat)) AGL_API(void, MultiTexCoord2fvARB, (GLenum, const GLfloat *)) AGL_API(void, MultiTexCoord2iARB, (GLenum, GLint, GLint)) AGL_API(void, MultiTexCoord2ivARB, (GLenum, const GLint *)) AGL_API(void, MultiTexCoord2sARB, (GLenum, GLshort, GLshort)) AGL_API(void, MultiTexCoord2svARB, (GLenum, const GLshort *)) AGL_API(void, MultiTexCoord3dARB, (GLenum, GLdouble, GLdouble, GLdouble)) AGL_API(void, MultiTexCoord3dvARB, (GLenum, const GLdouble *)) AGL_API(void, MultiTexCoord3fARB, (GLenum, GLfloat, GLfloat, GLfloat)) AGL_API(void, MultiTexCoord3fvARB, (GLenum, const GLfloat *)) AGL_API(void, MultiTexCoord3iARB, (GLenum, GLint, GLint, GLint)) AGL_API(void, MultiTexCoord3ivARB, (GLenum, const GLint *)) AGL_API(void, MultiTexCoord3sARB, (GLenum, GLshort, GLshort, GLshort)) AGL_API(void, MultiTexCoord3svARB, (GLenum, const GLshort *)) AGL_API(void, MultiTexCoord4dARB, (GLenum, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, MultiTexCoord4dvARB, (GLenum, const GLdouble *)) AGL_API(void, MultiTexCoord4fARB, (GLenum, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, MultiTexCoord4fvARB, (GLenum, const GLfloat *)) AGL_API(void, MultiTexCoord4iARB, (GLenum, GLint, GLint, GLint, GLint)) AGL_API(void, MultiTexCoord4ivARB, (GLenum, const GLint *)) AGL_API(void, MultiTexCoord4sARB, (GLenum, GLshort, GLshort, GLshort, GLshort)) AGL_API(void, MultiTexCoord4svARB, (GLenum, const GLshort *)) #endif #if defined _ALLEGRO_GL_ARB_transpose_matrix AGL_API(void, LoadTransposeMatrixfARB, (const GLfloat *)) AGL_API(void, LoadTransposeMatrixdARB, (const GLdouble *)) AGL_API(void, MultTransposeMatrixfARB, (const GLfloat *)) AGL_API(void, MultTransposeMatrixdARB, (const GLdouble *)) #endif #if defined _ALLEGRO_GL_ARB_multisample AGL_API(void, SampleCoverageARB, (GLclampf, GLboolean)) #endif #if defined _ALLEGRO_GL_ARB_texture_compression AGL_API(void, CompressedTexImage3DARB, (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *)) AGL_API(void, CompressedTexImage2DARB, (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *)) AGL_API(void, CompressedTexImage1DARB, (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *)) AGL_API(void, CompressedTexSubImage3DARB, (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *)) AGL_API(void, CompressedTexSubImage2DARB, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *)) AGL_API(void, CompressedTexSubImage1DARB, (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *)) AGL_API(void, GetCompressedTexImageARB, (GLenum, GLint, GLvoid *)) #endif #if defined _ALLEGRO_GL_ARB_point_parameters AGL_API(void, PointParameterfARB, (GLenum, GLfloat)) AGL_API(void, PointParameterfvARB, (GLenum, const GLfloat *)) #endif #if defined _ALLEGRO_GL_ARB_vertex_blend AGL_API(void, WeightbvARB, (GLint, const GLbyte *)) AGL_API(void, WeightsvARB, (GLint, const GLshort *)) AGL_API(void, WeightivARB, (GLint, const GLint *)) AGL_API(void, WeightfvARB, (GLint, const GLfloat *)) AGL_API(void, WeightdvARB, (GLint, const GLdouble *)) AGL_API(void, WeightubvARB, (GLint, const GLubyte *)) AGL_API(void, WeightusvARB, (GLint, const GLushort *)) AGL_API(void, WeightuivARB, (GLint, const GLuint *)) AGL_API(void, WeightPointerARB, (GLint, GLenum, GLsizei, const GLvoid *)) AGL_API(void, VertexBlendARB, (GLint)) #endif #if defined _ALLEGRO_GL_ARB_matrix_palette AGL_API(void, CurrentPaletteMatrixARB, (GLint)) AGL_API(void, MatrixIndexubvARB, (GLint, const GLubyte *)) AGL_API(void, MatrixIndexusvARB, (GLint, const GLushort *)) AGL_API(void, MatrixIndexuivARB, (GLint, const GLuint *)) AGL_API(void, MatrixIndexPointerARB, (GLint, GLenum, GLsizei, const GLvoid *)) #endif #if defined _ALLEGRO_GL_ARB_window_pos AGL_API(void, WindowPos2dARB, (GLdouble, GLdouble)) AGL_API(void, WindowPos2dvARB, (const GLdouble *)) AGL_API(void, WindowPos2fARB, (GLfloat, GLfloat)) AGL_API(void, WindowPos2fvARB, (const GLfloat *)) AGL_API(void, WindowPos2iARB, (GLint, GLint)) AGL_API(void, WindowPos2ivARB, (const GLint *)) AGL_API(void, WindowPos2sARB, (GLshort, GLshort)) AGL_API(void, WindowPos2svARB, (const GLshort *)) AGL_API(void, WindowPos3dARB, (GLdouble, GLdouble, GLdouble)) AGL_API(void, WindowPos3dvARB, (const GLdouble *)) AGL_API(void, WindowPos3fARB, (GLfloat, GLfloat, GLfloat)) AGL_API(void, WindowPos3fvARB, (const GLfloat *)) AGL_API(void, WindowPos3iARB, (GLint, GLint, GLint)) AGL_API(void, WindowPos3ivARB, (const GLint *)) AGL_API(void, WindowPos3sARB, (GLshort, GLshort, GLshort)) AGL_API(void, WindowPos3svARB, (const GLshort *)) #endif #if defined _ALLEGRO_GL_ARB_vertex_program AGL_API(void, VertexAttrib1dARB, (GLuint, GLdouble)) AGL_API(void, VertexAttrib1dvARB, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib1fARB, (GLuint, GLfloat)) AGL_API(void, VertexAttrib1fvARB, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib1sARB, (GLuint, GLshort)) AGL_API(void, VertexAttrib1svARB, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib2dARB, (GLuint, GLdouble, GLdouble)) AGL_API(void, VertexAttrib2dvARB, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib2fARB, (GLuint, GLfloat, GLfloat)) AGL_API(void, VertexAttrib2fvARB, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib2sARB, (GLuint, GLshort, GLshort)) AGL_API(void, VertexAttrib2svARB, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib3dARB, (GLuint, GLdouble, GLdouble, GLdouble)) AGL_API(void, VertexAttrib3dvARB, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib3fARB, (GLuint, GLfloat, GLfloat, GLfloat)) AGL_API(void, VertexAttrib3fvARB, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib3sARB, (GLuint, GLshort, GLshort, GLshort)) AGL_API(void, VertexAttrib3svARB, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib4NbvARB, (GLuint, const GLbyte *)) AGL_API(void, VertexAttrib4NivARB, (GLuint, const GLint *)) AGL_API(void, VertexAttrib4NsvARB, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib4NubARB, (GLuint, GLubyte, GLubyte, GLubyte, GLubyte)) AGL_API(void, VertexAttrib4NubvARB, (GLuint, const GLubyte *)) AGL_API(void, VertexAttrib4NuivARB, (GLuint, const GLuint *)) AGL_API(void, VertexAttrib4NusvARB, (GLuint, const GLushort *)) AGL_API(void, VertexAttrib4bvARB, (GLuint, const GLbyte *)) AGL_API(void, VertexAttrib4dARB, (GLuint, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, VertexAttrib4dvARB, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib4fARB, (GLuint, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, VertexAttrib4fvARB, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib4ivARB, (GLuint, const GLint *)) AGL_API(void, VertexAttrib4sARB, (GLuint, GLshort, GLshort, GLshort, GLshort)) AGL_API(void, VertexAttrib4svARB, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib4ubvARB, (GLuint, const GLubyte *)) AGL_API(void, VertexAttrib4uivARB, (GLuint, const GLuint *)) AGL_API(void, VertexAttrib4usvARB, (GLuint, const GLushort *)) AGL_API(void, VertexAttribPointerARB, (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *)) AGL_API(void, EnableVertexAttribArrayARB, (GLuint)) AGL_API(void, DisableVertexAttribArrayARB, (GLuint)) AGL_API(void, ProgramStringARB, (GLenum, GLenum, GLsizei, const GLvoid *)) AGL_API(void, BindProgramARB, (GLenum, GLuint)) AGL_API(void, DeleteProgramsARB, (GLsizei, const GLuint *)) AGL_API(void, GenProgramsARB, (GLsizei, GLuint *)) AGL_API(void, ProgramEnvParameter4dARB, (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, ProgramEnvParameter4dvARB, (GLenum, GLuint, const GLdouble *)) AGL_API(void, ProgramEnvParameter4fARB, (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, ProgramEnvParameter4fvARB, (GLenum, GLuint, const GLfloat *)) AGL_API(void, ProgramLocalParameter4dARB, (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, ProgramLocalParameter4dvARB, (GLenum, GLuint, const GLdouble *)) AGL_API(void, ProgramLocalParameter4fARB, (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, ProgramLocalParameter4fvARB, (GLenum, GLuint, const GLfloat *)) AGL_API(void, GetProgramEnvParameterdvARB, (GLenum, GLuint, GLdouble *)) AGL_API(void, GetProgramEnvParameterfvARB, (GLenum, GLuint, GLfloat *)) AGL_API(void, GetProgramLocalParameterdvARB, (GLenum, GLuint, GLdouble *)) AGL_API(void, GetProgramLocalParameterfvARB, (GLenum, GLuint, GLfloat *)) AGL_API(void, GetProgramivARB, (GLenum, GLenum, GLint *)) AGL_API(void, GetProgramStringARB, (GLenum, GLenum, GLvoid *)) AGL_API(void, GetVertexAttribdvARB, (GLuint, GLenum, GLdouble *)) AGL_API(void, GetVertexAttribfvARB, (GLuint, GLenum, GLfloat *)) AGL_API(void, GetVertexAttribivARB, (GLuint, GLenum, GLint *)) AGL_API(void, GetVertexAttribPointervARB, (GLuint, GLenum, GLvoid* *)) AGL_API(GLboolean, IsProgramARB, (GLuint)) #endif #if defined _ALLEGRO_GL_ARB_vertex_buffer_object AGL_API(void, BindBufferARB, (GLenum, GLuint)) AGL_API(void, DeleteBuffersARB, (GLsizei, const GLuint *)) AGL_API(void, GenBuffersARB, (GLsizei, GLuint *)) AGL_API(GLboolean, IsBufferARB, (GLuint)) AGL_API(void, BufferDataARB, (GLenum, GLsizeiptrARB, const GLvoid *, GLenum)) AGL_API(void, BufferSubDataARB, (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *)) AGL_API(void, GetBufferSubDataARB, (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *)) AGL_API(GLvoid*, MapBufferARB, (GLenum, GLenum)) AGL_API(GLboolean, UnmapBufferARB, (GLenum)) AGL_API(void, GetBufferParameterivARB, (GLenum, GLenum, GLint *)) AGL_API(void, GetBufferPointervARB, (GLenum, GLenum, GLvoid* *)) #endif #if defined _ALLEGRO_GL_ARB_occlusion_query AGL_API(void, GenQueriesARB, (GLsizei, GLuint *)) AGL_API(void, DeleteQueriesARB, (GLsizei, const GLuint *)) AGL_API(GLboolean, IsQueryARB, (GLuint)) AGL_API(void, BeginQueryARB, (GLenum, GLuint)) AGL_API(void, EndQueryARB, (GLenum)) AGL_API(void, GetQueryivARB, (GLenum, GLenum, GLint *)) AGL_API(void, GetQueryObjectivARB, (GLuint, GLenum, GLint *)) AGL_API(void, GetQueryObjectuivARB, (GLuint, GLenum, GLuint *)) #endif #if defined _ALLEGRO_GL_ARB_shader_objects AGL_API(void, DeleteObjectARB, (GLhandleARB)) AGL_API(GLhandleARB, GetHandleARB, (GLenum)) AGL_API(void, DetachObjectARB, (GLhandleARB, GLhandleARB)) AGL_API(GLhandleARB, CreateShaderObjectARB, (GLenum)) AGL_API(void, ShaderSourceARB, (GLhandleARB, GLsizei, const GLcharARB **, const GLint *)) AGL_API(void, CompileShaderARB, (GLhandleARB)) AGL_API(GLhandleARB, CreateProgramObjectARB, (void)) AGL_API(void, AttachObjectARB, (GLhandleARB, GLhandleARB)) AGL_API(void, LinkProgramARB, (GLhandleARB)) AGL_API(void, UseProgramObjectARB, (GLhandleARB)) AGL_API(void, ValidateProgramARB, (GLhandleARB)) AGL_API(void, Uniform1fARB, (GLint, GLfloat)) AGL_API(void, Uniform2fARB, (GLint, GLfloat, GLfloat)) AGL_API(void, Uniform3fARB, (GLint, GLfloat, GLfloat, GLfloat)) AGL_API(void, Uniform4fARB, (GLint, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, Uniform1iARB, (GLint, GLint)) AGL_API(void, Uniform2iARB, (GLint, GLint, GLint)) AGL_API(void, Uniform3iARB, (GLint, GLint, GLint, GLint)) AGL_API(void, Uniform4iARB, (GLint, GLint, GLint, GLint, GLint)) AGL_API(void, Uniform1fvARB, (GLint, GLsizei, GLfloat *)) AGL_API(void, Uniform2fvARB, (GLint, GLsizei, GLfloat *)) AGL_API(void, Uniform3fvARB, (GLint, GLsizei, GLfloat *)) AGL_API(void, Uniform4fvARB, (GLint, GLsizei, GLfloat *)) AGL_API(void, Uniform1ivARB, (GLint, GLsizei, GLint *)) AGL_API(void, Uniform2ivARB, (GLint, GLsizei, GLint *)) AGL_API(void, Uniform3ivARB, (GLint, GLsizei, GLint *)) AGL_API(void, Uniform4ivARB, (GLint, GLsizei, GLint *)) AGL_API(void, UniformMatrix2fvARB, (GLint, GLsizei, GLboolean, GLfloat *)) AGL_API(void, UniformMatrix3fvARB, (GLint, GLsizei, GLboolean, GLfloat *)) AGL_API(void, UniformMatrix4fvARB, (GLint, GLsizei, GLboolean, GLfloat *)) AGL_API(void, GetObjectParameterfvARB, (GLhandleARB, GLenum, GLfloat *)) AGL_API(void, GetObjectParameterivARB, (GLhandleARB, GLenum, GLint *)) AGL_API(void, GetInfoLogARB, (GLhandleARB, GLsizei, GLsizei *, GLcharARB *)) AGL_API(void, GetAttachedObjectsARB, (GLhandleARB, GLsizei, GLsizei *, GLhandleARB *)) AGL_API(GLint, GetUniformLocationARB, (GLhandleARB, const GLcharARB *)) AGL_API(void, GetActiveUniformARB, (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *)) AGL_API(void, GetUniformfvARB, (GLhandleARB, GLint, GLfloat *)) AGL_API(void, GetUniformivARB, (GLhandleARB, GLint, GLint *)) AGL_API(void, GetShaderSourceARB, (GLhandleARB, GLsizei, GLsizei *, GLcharARB *)) #endif #ifdef _ALLEGRO_GL_ARB_vertex_shader #ifndef GL_ARB_vertex_program AGL_API(void, VertexAttrib1fARB, (GLuint, GLfloat)) AGL_API(void, VertexAttrib1sARB, (GLuint, GLshort)) AGL_API(void, VertexAttrib1dARB, (GLuint, GLdouble)) AGL_API(void, VertexAttrib2fARB, (GLuint, GLfloat, GLfloat)) AGL_API(void, VertexAttrib2sARB, (GLuint, GLshort, GLshort)) AGL_API(void, VertexAttrib2dARB, (GLuint, GLdouble, GLdouble)) AGL_API(void, VertexAttrib3fARB, (GLuint, GLfloat, GLfloat, GLfloat)) AGL_API(void, VertexAttrib3sARB, (GLuint, GLshort, GLshort, GLshort)) AGL_API(void, VertexAttrib3dARB, (GLuint, GLdouble, GLdouble, GLdouble)) AGL_API(void, VertexAttrib4fARB, (GLuint, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, VertexAttrib4sARB, (GLuint, GLshort, GLshort, GLshort, GLshort)) AGL_API(void, VertexAttrib4dARB, (GLuint, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, VertexAttrib4NubARB, (GLuint, GLubyte, GLubyte, GLubyte, GLubyte)) AGL_API(void, VertexAttrib1fvARB, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib1svARB, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib1dvARB, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib2fvARB, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib2svARB, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib2dvARB, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib3fvARB, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib3svARB, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib3dvARB, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib4fvARB, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib4svARB, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib4dvARB, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib4ivARB, (GLuint, const GLint *)) AGL_API(void, VertexAttrib4bvARB, (GLuint, const GLbyte *)) AGL_API(void, VertexAttrib4ubvARB, (GLuint, const GLubyte *)) AGL_API(void, VertexAttrib4usvARB, (GLuint, const GLushort *)) AGL_API(void, VertexAttrib4uivARB, (GLuint, const GLuint *)) AGL_API(void, VertexAttrib4NbvARB, (GLuint, const GLbyte *)) AGL_API(void, VertexAttrib4NsvARB, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib4NivARB, (GLuint, const GLint *)) AGL_API(void, VertexAttrib4NubvARB, (GLuint, const GLubyte *)) AGL_API(void, VertexAttrib4NusvARB, (GLuint, const GLushort *)) AGL_API(void, VertexAttrib4NuivARB, (GLuint, const GLuint *)) AGL_API(void, VertexAttribPointerARB, (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *)) AGL_API(void, EnableVertexAttribArrayARB, (GLuint)) AGL_API(void, DisableVertexAttribArrayARB, (GLuint)) #endif AGL_API(void, BindAttribLocationARB, (GLhandleARB, GLuint, const GLcharARB *)) AGL_API(void, GetActiveAttribARB, (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *)) AGL_API(GLint, GetAttribLocationARB, (GLhandleARB, const GLcharARB *)) #ifndef GL_ARB_vertex_program AGL_API(void, GetVertexAttribdvARB, (GLuint, GLenum, GLdouble *)) AGL_API(void, GetVertexAttribfvARB, (GLuint, GLenum, GLfloat *)) AGL_API(void, GetVertexAttribivARB, (GLuint, GLenum, GLint *)) AGL_API(void, GetVertexAttribPointervARB, (GLuint, GLenum, GLvoid **)) #endif #endif #if defined _ALLEGRO_GL_ARB_draw_buffers AGL_API(void, DrawBuffersARB, (GLsizei n, const GLenum *bufs)) #endif #if defined _ALLEGRO_GL_ARB_color_buffer_float AGL_API(void, ClampColorARB, (GLenum, GLenum clamp)) #endif #if defined _ALLEGRO_GL_ARB_draw_instanced AGL_API(void, DrawArraysInstancedARB, (GLenum, GLint, GLsizei, GLsizei)) AGL_API(void, DrawElementsInstancedARB, (GLenum, GLsizei, GLenum, const GLvoid *, GLsizei)) #endif #if defined _ALLEGRO_GL_ARB_framebuffer_object AGL_API(GLboolean, IsRenderbuffer, (GLuint)) AGL_API(void, BindRenderbuffer, (GLenum, GLuint)) AGL_API(void, DeleteRenderbuffers, (GLsizei, const GLuint *)) AGL_API(void, GenRenderbuffers, (GLsizei, GLuint *)) AGL_API(void, RenderbufferStorage, (GLenum, GLenum, GLsizei, GLsizei)) AGL_API(void, GetRenderbufferParameteriv, (GLenum, GLenum, GLint *)) AGL_API(GLboolean, IsFramebuffer, (GLuint)) AGL_API(void, BindFramebuffer, (GLenum, GLuint)) AGL_API(void, DeleteFramebuffers, (GLsizei, const GLuint *)) AGL_API(void, GenFramebuffers, (GLsizei, GLuint *)) AGL_API(GLenum, CheckFramebufferStatus, (GLenum)) AGL_API(void, FramebufferTexture1D, (GLenum, GLenum, GLenum, GLuint, GLint)) AGL_API(void, FramebufferTexture2D, (GLenum, GLenum, GLenum, GLuint, GLint)) AGL_API(void, FramebufferTexture3D, (GLenum, GLenum, GLenum, GLuint, GLint, GLint)) AGL_API(void, FramebufferRenderbuffer, (GLenum, GLenum, GLenum, GLuint)) AGL_API(void, GetFramebufferAttachmentParameteriv, (GLenum, GLenum, GLenum, GLint *)) AGL_API(void, GenerateMipmap, (GLenum)) AGL_API(void, BlitFramebuffer, (GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum)) AGL_API(void, RenderbufferStorageMultisample, (GLenum, GLsizei, GLenum, GLsizei, GLsizei)) AGL_API(void, FramebufferTextureLayer, (GLenum, GLenum, GLuint, GLint, GLint)) #endif #if defined _ALLEGRO_GL_ARB_geometry_shader4 AGL_API(void, ProgramParameteriARB, (GLuint, GLenum, GLint)) AGL_API(void, FramebufferTextureARB, (GLenum, GLenum, GLuint, GLint)) AGL_API(void, FramebufferTextureLayerARB, (GLenum, GLenum, GLuint, GLint, GLint)) AGL_API(void, FramebufferTextureFaceARB, (GLenum, GLenum, GLuint, GLint, GLenum)) #endif #if defined _ALLEGRO_GL_ARB_instanced_arrays AGL_API(void, VertexAttribDivisor, (GLuint, GLuint)) #endif #if defined _ALLEGRO_GL_ARB_map_buffer_range AGL_API(void, MapBufferRange, (GLenum, GLintptr, GLsizeiptr, GLbitfield)) AGL_API(void, FlushMappedBufferRange, (GLenum, GLintptr, GLsizeiptr)) #endif #if defined _ALLEGRO_GL_ARB_texture_buffer_object AGL_API(void, TexBufferARB, (GLenum, GLenum, GLuint)) #endif #if defined _ALLEGRO_GL_ARB_vertex_array_object AGL_API(void, BindVertexArray, (GLuint)) AGL_API(void, DeleteVertexArrays, (GLsizei, const GLuint *)) AGL_API(void, GenVertexArrays, (GLsizei, GLuint *)) AGL_API(GLboolean, IsVertexArray, (GLuint)) #endif #if defined _ALLEGRO_GL_ARB_uniform_buffer_object AGL_API(void, GetUniformIndices, (GLuint, GLsizei, const GLchar* *, GLuint *)) AGL_API(void, GetActiveUniformsiv, (GLuint, GLsizei, const GLuint *, GLenum, GLint *)) AGL_API(void, GetActiveUniformName, (GLuint, GLuint, GLsizei, GLsizei *, GLchar *)) AGL_API(GLuint, GetUniformBlockIndex, (GLuint, const GLchar *)) AGL_API(void, GetActiveUniformBlockiv, (GLuint, GLuint, GLenum, GLint *)) AGL_API(void, GetActiveUniformBlockName, (GLuint, GLuint, GLsizei, GLsizei *, GLchar *)) AGL_API(void, UniformBlockBinding, (GLuint, GLuint, GLuint)) #endif #if defined _ALLEGRO_GL_ARB_copy_buffer AGL_API(void, CopyBufferSubData, (GLenum, GLenum, GLintptr, GLintptr, GLsizeiptr)) #endif #if defined _ALLEGRO_GL_ARB_draw_elements_base_vertex AGL_API(void, DrawElementsBaseVertex, (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex)) AGL_API(void, DrawRangeElementsBaseVertex, (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex)) AGL_API(void, DrawElementsInstancedBaseVertex, (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex)) AGL_API(void, MultiDrawElementsBaseVertex, (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount, const GLint *basevertex)) #endif #if defined _ALLEGRO_GL_ARB_provoking_vertex AGL_API(void, ProvokingVertex, (GLenum mode)) #endif #if defined _ALLEGRO_GL_ARB_sync AGL_API(GLsync, FenceSync, (GLenum condition, GLbitfield flags)) AGL_API(GLboolean, IsSync, (GLsync sync)) AGL_API(void, DeleteSync, (GLsync sync)) AGL_API(GLenum, ClientWaitSync, (GLsync sync, GLbitfield flags, GLuint64 timeout)) AGL_API(void, WaitSync, (GLsync sync, GLbitfield flags, GLuint64 timeout)) AGL_API(void, GetInteger64v, (GLenum pname, GLint64 *params)) AGL_API(void, GetSynciv, (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)) #endif #if defined _ALLEGRO_GL_ARB_texture_multisample AGL_API(void, TexImage2DMultisample, (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations)) AGL_API(void, TexImage3DMultisample, (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations)) AGL_API(void, GetMultisamplefv, (GLenum pname, GLuint index, GLfloat *val)) AGL_API(void, SampleMaski, (GLuint index, GLbitfield mask)) #endif #if defined _ALLEGRO_GL_ARB_draw_buffers_blend AGL_API(void, BlendEquationi, (GLuint buf, GLenum mode)) AGL_API(void, BlendEquationSeparatei, (GLuint buf, GLenum modeRGB, GLenum modeAlpha)) AGL_API(void, BlendFunci, (GLuint buf, GLenum src, GLenum dst)) AGL_API(void, BlendFuncSeparatei, (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)) #endif #if defined _ALLEGRO_GL_ARB_sample_shading AGL_API(void, MinSampleShading, (GLclampf value)) #endif #if defined _ALLEGRO_GL_ARB_shading_language_include AGL_API(void, NamedStringARB, (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string)) AGL_API(void, DeleteNamedStringARB, (GLint namelen, const GLchar *name)) AGL_API(void, CompileShaderIncludeARB, (GLuint shader, GLsizei count, const GLchar* *path, const GLint *length)) AGL_API(GLboolean, IsNamedStringARB, (GLint namelen, const GLchar *name)) AGL_API(void, GetNamedStringARB, (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string)) AGL_API(void, GetNamedStringivARB, (GLint namelen, const GLchar *name, GLenum pname, GLint *params)) #endif #if defined _ALLEGRO_GL_ARB_blend_func_extended AGL_API(void, BindFragDataLocationIndexed, (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name)) AGL_API(GLint, GetFragDataIndex, (GLuint program, const GLchar *name)) #endif #if defined _ALLEGRO_GL_ARB_sampler_objects AGL_API(void, GenSamplers, (GLsizei count, GLuint *samplers)) AGL_API(void, DeleteSamplers, (GLsizei count, const GLuint *samplers)) AGL_API(GLboolean, IsSampler, (GLuint sampler)) AGL_API(void, BindSampler, (GLenum unit, GLuint sampler)) AGL_API(void, SamplerParameteri, (GLuint sampler, GLenum pname, GLint param)) AGL_API(void, SamplerParameteriv, (GLuint sampler, GLenum pname, const GLint *param)) AGL_API(void, SamplerParameterf, (GLuint sampler, GLenum pname, GLfloat param)) AGL_API(void, SamplerParameterfv, (GLuint sampler, GLenum pname, const GLfloat *param)) AGL_API(void, SamplerParameterIiv, (GLuint sampler, GLenum pname, const GLint *param)) AGL_API(void, SamplerParameterIuiv, (GLuint sampler, GLenum pname, const GLuint *param)) AGL_API(void, GetSamplerParameteriv, (GLuint sampler, GLenum pname, GLint *params)) AGL_API(void, GetSamplerParameterIiv, (GLuint sampler, GLenum pname, GLint *params)) AGL_API(void, GetSamplerParameterfv, (GLuint sampler, GLenum pname, GLfloat *params)) AGL_API(void, GetSamplerParameterIfv, (GLuint sampler, GLenum pname, GLfloat *params)) #endif #if defined _ALLEGRO_GL_ARB_timer_query AGL_API(void, QueryCounter, (GLuint id, GLenum target)) AGL_API(void, GetQueryObjecti64v, (GLuint id, GLenum pname, GLint64 *params)) AGL_API(void, GetQueryObjectui64v, (GLuint id, GLenum pname, GLuint64 *params)) #endif #if defined _ALLEGRO_GL_ARB_vertex_type_2_10_10_10_rev AGL_API(void, VertexP2ui, (GLenum type, GLuint value)) AGL_API(void, VertexP2uiv, (GLenum type, const GLuint *value)) AGL_API(void, VertexP3ui, (GLenum type, GLuint value)) AGL_API(void, VertexP3uiv, (GLenum type, const GLuint *value)) AGL_API(void, VertexP4ui, (GLenum type, GLuint value)) AGL_API(void, VertexP4uiv, (GLenum type, const GLuint *value)) AGL_API(void, TexCoordP1ui, (GLenum type, GLuint coords)) AGL_API(void, TexCoordP1uiv, (GLenum type, const GLuint *coords)) AGL_API(void, TexCoordP2ui, (GLenum type, GLuint coords)) AGL_API(void, TexCoordP2uiv, (GLenum type, const GLuint *coords)) AGL_API(void, TexCoordP3ui, (GLenum type, GLuint coords)) AGL_API(void, TexCoordP3uiv, (GLenum type, const GLuint *coords)) AGL_API(void, TexCoordP4ui, (GLenum type, GLuint coords)) AGL_API(void, TexCoordP4uiv, (GLenum type, const GLuint *coords)) AGL_API(void, MultiTexCoordP1ui, (GLenum texture, GLenum type, GLuint coords)) AGL_API(void, MultiTexCoordP1uiv, (GLenum texture, GLenum type, const GLuint *coords)) AGL_API(void, MultiTexCoordP2ui, (GLenum texture, GLenum type, GLuint coords)) AGL_API(void, MultiTexCoordP2uiv, (GLenum texture, GLenum type, const GLuint *coords)) AGL_API(void, MultiTexCoordP3ui, (GLenum texture, GLenum type, GLuint coords)) AGL_API(void, MultiTexCoordP3uiv, (GLenum texture, GLenum type, const GLuint *coords)) AGL_API(void, MultiTexCoordP4ui, (GLenum texture, GLenum type, GLuint coords)) AGL_API(void, MultiTexCoordP4uiv, (GLenum texture, GLenum type, const GLuint *coords)) AGL_API(void, NormalP3ui, (GLenum type, GLuint coords)) AGL_API(void, NormalP3uiv, (GLenum type, const GLuint *coords)) AGL_API(void, ColorP3ui, (GLenum type, GLuint color)) AGL_API(void, ColorP3uiv, (GLenum type, const GLuint *color)) AGL_API(void, ColorP4ui, (GLenum type, GLuint color)) AGL_API(void, ColorP4uiv, (GLenum type, const GLuint *color)) AGL_API(void, SecondaryColorP3ui, (GLenum type, GLuint color)) AGL_API(void, SecondaryColorP3uiv, (GLenum type, const GLuint *color)) AGL_API(void, VertexAttribP1ui, (GLuint index, GLenum type, GLboolean normalized, GLuint value)) AGL_API(void, VertexAttribP1uiv, (GLuint index, GLenum type, GLboolean normalized, const GLuint *value)) AGL_API(void, VertexAttribP2ui, (GLuint index, GLenum type, GLboolean normalized, GLuint value)) AGL_API(void, VertexAttribP2uiv, (GLuint index, GLenum type, GLboolean normalized, const GLuint *value)) AGL_API(void, VertexAttribP3ui, (GLuint index, GLenum type, GLboolean normalized, GLuint value)) AGL_API(void, VertexAttribP3uiv, (GLuint index, GLenum type, GLboolean normalized, const GLuint *value)) AGL_API(void, VertexAttribP4ui, (GLuint index, GLenum type, GLboolean normalized, GLuint value)) AGL_API(void, VertexAttribP4uiv, (GLuint index, GLenum type, GLboolean normalized, const GLuint *value)) #endif #if defined _ALLEGRO_GL_ARB_draw_indirect AGL_API(void, DrawArraysIndirect, (GLenum mode, const GLvoid *indirect)) AGL_API(void, DrawElementsIndirect, (GLenum mode, GLenum type, const GLvoid *indirect)) #endif #if defined _ALLEGRO_GL_ARB_gpu_shader_fp64 AGL_API(void, Uniform1d, (GLint location, GLdouble x)) AGL_API(void, Uniform2d, (GLint location, GLdouble x, GLdouble y)) AGL_API(void, Uniform3d, (GLint location, GLdouble x, GLdouble y, GLdouble z)) AGL_API(void, Uniform4d, (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w)) AGL_API(void, Uniform1dv, (GLint location, GLsizei count, const GLdouble *value)) AGL_API(void, Uniform2dv, (GLint location, GLsizei count, const GLdouble *value)) AGL_API(void, Uniform3dv, (GLint location, GLsizei count, const GLdouble *value)) AGL_API(void, Uniform4dv, (GLint location, GLsizei count, const GLdouble *value)) AGL_API(void, UniformMatrix2dv, (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, UniformMatrix3dv, (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, UniformMatrix4dv, (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, UniformMatrix2x3dv, (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, UniformMatrix2x4dv, (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, UniformMatrix3x2dv, (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, UniformMatrix3x4dv, (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, UniformMatrix4x2dv, (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, UniformMatrix4x3dv, (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, GetUniformdv, (GLuint program, GLint location, GLdouble *params)) AGL_API(void, ProgramUniform1dEXT, (GLuint program, GLint location, GLdouble x)) AGL_API(void, ProgramUniform2dEXT, (GLuint program, GLint location, GLdouble x, GLdouble y)) AGL_API(void, ProgramUniform3dEXT, (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z)) AGL_API(void, ProgramUniform4dEXT, (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w)) AGL_API(void, ProgramUniform1dvEXT, (GLuint program, GLint location, GLsizei count, const GLdouble *value)) AGL_API(void, ProgramUniform2dvEXT, (GLuint program, GLint location, GLsizei count, const GLdouble *value)) AGL_API(void, ProgramUniform3dvEXT, (GLuint program, GLint location, GLsizei count, const GLdouble *value)) AGL_API(void, ProgramUniform4dvEXT, (GLuint program, GLint location, GLsizei count, const GLdouble *value)) AGL_API(void, ProgramUniformMatrix2dvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, ProgramUniformMatrix3dvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, ProgramUniformMatrix4dvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, ProgramUniformMatrix2x3dvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, ProgramUniformMatrix2x4dvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, ProgramUniformMatrix3x2dvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, ProgramUniformMatrix3x4dvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, ProgramUniformMatrix4x2dvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) AGL_API(void, ProgramUniformMatrix4x3dvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value)) #endif #if defined _ALLEGRO_GL_ARB_shader_subroutine AGL_API(GLint, GetSubroutineUniformLocation, (GLuint program, GLenum shadertype, const GLchar *name)) AGL_API(GLuint, GetSubroutineIndex, (GLuint program, GLenum shadertype, const GLchar *name)) AGL_API(void, GetActiveSubroutineUniformiv, (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values)) AGL_API(void, GetActiveSubroutineUniformName, (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name)) AGL_API(void, GetActiveSubroutineName, (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name)) AGL_API(void, UniformSubroutinesuiv, (GLenum shadertype, GLsizei count, const GLuint *indices)) AGL_API(void, GetUniformSubroutineuiv, (GLenum shadertype, GLint location, GLuint *params)) AGL_API(void, GetProgramStageiv, (GLuint program, GLenum shadertype, GLenum pname, GLint *values)) #endif #if defined _ALLEGRO_GL_ARB_tessellation_shader AGL_API(void, PatchParameteri, (GLenum pname, GLint value)) AGL_API(void, PatchParameterfv, (GLenum pname, const GLfloat *values)) #endif #if defined _ALLEGRO_GL_ARB_transform_feedback2 AGL_API(void, BindTransformFeedback, (GLenum target, GLuint id)) AGL_API(void, DeleteTransformFeedbacks, (GLsizei n, const GLuint *ids)) AGL_API(void, GenTransformFeedbacks, (GLsizei n, GLuint *ids)) AGL_API(GLboolean, IsTransformFeedback, (GLuint id)) AGL_API(void, PauseTransformFeedback, (void)) AGL_API(void, ResumeTransformFeedback, (void)) AGL_API(void, DrawTransformFeedback, (GLenum mode, GLuint id)) #endif #if defined _ALLEGRO_GL_ARB_transform_feedback3 AGL_API(void, DrawTransformFeedbackStream, (GLenum mode, GLuint id, GLuint stream)) AGL_API(void, BeginQueryIndexed, (GLenum target, GLuint index, GLuint id)) AGL_API(void, EndQueryIndexed, (GLenum target, GLuint index)) AGL_API(void, GetQueryIndexediv, (GLenum target, GLuint index, GLenum pname, GLint *params)) #endif /* */ #if defined _ALLEGRO_GL_EXT_blend_color AGL_API(void, BlendColorEXT, (GLclampf, GLclampf, GLclampf, GLclampf)) #endif #if defined _ALLEGRO_GL_EXT_polygon_offset AGL_API(void, PolygonOffsetEXT, (GLfloat, GLfloat)) #endif #if defined _ALLEGRO_GL_EXT_texture3D AGL_API(void, TexImage3DEXT, (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *)) AGL_API(void, TexSubImage3DEXT, (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) #endif #if defined _ALLEGRO_GL_SGIS_texture_filter4 AGL_API(void, GetTexFilterFuncSGIS, (GLenum, GLenum, GLfloat *)) AGL_API(void, TexFilterFuncSGIS, (GLenum, GLenum, GLsizei, const GLfloat *)) #endif #if defined _ALLEGRO_GL_EXT_subtexture AGL_API(void, TexSubImage1DEXT, (GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, TexSubImage2DEXT, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) #endif #if defined _ALLEGRO_GL_EXT_copy_texture AGL_API(void, CopyTexImage1DEXT, (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint)) AGL_API(void, CopyTexImage2DEXT, (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint)) AGL_API(void, CopyTexSubImage1DEXT, (GLenum, GLint, GLint, GLint, GLint, GLsizei)) AGL_API(void, CopyTexSubImage2DEXT, (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)) AGL_API(void, CopyTexSubImage3DEXT, (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)) #endif #if defined _ALLEGRO_GL_EXT_histogram AGL_API(void, GetHistogramEXT, (GLenum, GLboolean, GLenum, GLenum, GLvoid *)) AGL_API(void, GetHistogramParameterfvEXT, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetHistogramParameterivEXT, (GLenum, GLenum, GLint *)) AGL_API(void, GetMinmaxEXT, (GLenum, GLboolean, GLenum, GLenum, GLvoid *)) AGL_API(void, GetMinmaxParameterfvEXT, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetMinmaxParameterivEXT, (GLenum, GLenum, GLint *)) AGL_API(void, HistogramEXT, (GLenum, GLsizei, GLenum, GLboolean)) AGL_API(void, MinmaxEXT, (GLenum, GLenum, GLboolean)) AGL_API(void, ResetHistogramEXT, (GLenum)) AGL_API(void, ResetMinmaxEXT, (GLenum)) #endif #if defined _ALLEGRO_GL_EXT_convolution AGL_API(void, ConvolutionFilter1DEXT, (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, ConvolutionFilter2DEXT, (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, ConvolutionParameterfEXT, (GLenum, GLenum, GLfloat)) AGL_API(void, ConvolutionParameterfvEXT, (GLenum, GLenum, const GLfloat *)) AGL_API(void, ConvolutionParameteriEXT, (GLenum, GLenum, GLint)) AGL_API(void, ConvolutionParameterivEXT, (GLenum, GLenum, const GLint *)) AGL_API(void, CopyConvolutionFilter1DEXT, (GLenum, GLenum, GLint, GLint, GLsizei)) AGL_API(void, CopyConvolutionFilter2DEXT, (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei)) AGL_API(void, GetConvolutionFilterEXT, (GLenum, GLenum, GLenum, GLvoid *)) AGL_API(void, GetConvolutionParameterfvEXT, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetConvolutionParameterivEXT, (GLenum, GLenum, GLint *)) AGL_API(void, GetSeparableFilterEXT, (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *)) AGL_API(void, SeparableFilter2DEXT, (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *)) #endif #if defined _ALLEGRO_GL_SGI_color_table AGL_API(void, ColorTableSGI, (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, ColorTableParameterfvSGI, (GLenum, GLenum, const GLfloat *)) AGL_API(void, ColorTableParameterivSGI, (GLenum, GLenum, const GLint *)) AGL_API(void, CopyColorTableSGI, (GLenum, GLenum, GLint, GLint, GLsizei)) AGL_API(void, GetColorTableSGI, (GLenum, GLenum, GLenum, GLvoid *)) AGL_API(void, GetColorTableParameterfvSGI, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetColorTableParameterivSGI, (GLenum, GLenum, GLint *)) #endif #if defined _ALLEGRO_GL_SGIX_pixel_texture AGL_API(void, PixelTexGenSGIX, (GLenum)) #endif #if defined _ALLEGRO_GL_SGIS_pixel_texture AGL_API(void, PixelTexGenParameteriSGIS, (GLenum, GLint)) AGL_API(void, PixelTexGenParameterivSGIS, (GLenum, const GLint *)) AGL_API(void, PixelTexGenParameterfSGIS, (GLenum, GLfloat)) AGL_API(void, PixelTexGenParameterfvSGIS, (GLenum, const GLfloat *)) AGL_API(void, GetPixelTexGenParameterivSGIS, (GLenum, GLint *)) AGL_API(void, GetPixelTexGenParameterfvSGIS, (GLenum, GLfloat *)) #endif #if defined _ALLEGRO_GL_SGIS_texture4D AGL_API(void, TexImage4DSGIS, (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *)) AGL_API(void, TexSubImage4DSGIS, (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) #endif #if defined _ALLEGRO_GL_EXT_texture_object AGL_API(GLboolean, AreTexturesResidentEXT, (GLsizei, const GLuint *, GLboolean *)) AGL_API(void, BindTextureEXT, (GLenum, GLuint)) AGL_API(void, DeleteTexturesEXT, (GLsizei, const GLuint *)) AGL_API(void, GenTexturesEXT, (GLsizei, GLuint *)) AGL_API(GLboolean, IsTextureEXT, (GLuint)) AGL_API(void, PrioritizeTexturesEXT, (GLsizei, const GLuint *, const GLclampf *)) #endif #if defined _ALLEGRO_GL_SGIS_detail_texture AGL_API(void, DetailTexFuncSGIS, (GLenum, GLsizei, const GLfloat *)) AGL_API(void, GetDetailTexFuncSGIS, (GLenum, GLfloat *)) #endif #if defined _ALLEGRO_GL_SGIS_sharpen_texture AGL_API(void, SharpenTexFuncSGIS, (GLenum, GLsizei, const GLfloat *)) AGL_API(void, GetSharpenTexFuncSGIS, (GLenum, GLfloat *)) #endif #if defined _ALLEGRO_GL_SGIS_multisample AGL_API(void, SampleMaskSGIS, (GLclampf, GLboolean)) AGL_API(void, SamplePatternSGIS, (GLenum)) #endif #if defined _ALLEGRO_GL_EXT_vertex_array AGL_API(void, ArrayElementEXT, (GLint)) AGL_API(void, ColorPointerEXT, (GLint, GLenum, GLsizei, GLsizei, const GLvoid *)) AGL_API(void, DrawArraysEXT, (GLenum, GLint, GLsizei)) AGL_API(void, EdgeFlagPointerEXT, (GLsizei, GLsizei, const GLboolean *)) AGL_API(void, GetPointervEXT, (GLenum, GLvoid* *)) AGL_API(void, IndexPointerEXT, (GLenum, GLsizei, GLsizei, const GLvoid *)) AGL_API(void, NormalPointerEXT, (GLenum, GLsizei, GLsizei, const GLvoid *)) AGL_API(void, TexCoordPointerEXT, (GLint, GLenum, GLsizei, GLsizei, const GLvoid *)) AGL_API(void, VertexPointerEXT, (GLint, GLenum, GLsizei, GLsizei, const GLvoid *)) #endif #if defined _ALLEGRO_GL_EXT_blend_minmax AGL_API(void, BlendEquationEXT, (GLenum)) #endif #if defined _ALLEGRO_GL_SGIX_sprite AGL_API(void, SpriteParameterfSGIX, (GLenum, GLfloat)) AGL_API(void, SpriteParameterfvSGIX, (GLenum, const GLfloat *)) AGL_API(void, SpriteParameteriSGIX, (GLenum, GLint)) AGL_API(void, SpriteParameterivSGIX, (GLenum, const GLint *)) #endif #if defined _ALLEGRO_GL_EXT_point_parameters AGL_API(void, PointParameterfEXT, (GLenum, GLfloat)) AGL_API(void, PointParameterfvEXT, (GLenum, const GLfloat *)) #endif #if defined _ALLEGRO_GL_SGIS_point_parameters AGL_API(void, PointParameterfSGIS, (GLenum, GLfloat)) AGL_API(void, PointParameterfvSGIS, (GLenum, const GLfloat *)) #endif #if defined _ALLEGRO_GL_SGIX_instruments AGL_API(GLint, GetInstrumentsSGIX, (void)) AGL_API(void, InstrumentsBufferSGIX, (GLsizei, GLint *)) AGL_API(GLint, PollInstrumentsSGIX, (GLint *)) AGL_API(void, ReadInstrumentsSGIX, (GLint)) AGL_API(void, StartInstrumentsSGIX, (void)) AGL_API(void, StopInstrumentsSGIX, (GLint)) #endif #if defined _ALLEGRO_GL_SGIX_framezoom AGL_API(void, FrameZoomSGIX, (GLint)) #endif #if defined _ALLEGRO_GL_SGIX_tag_sample_buffer AGL_API(void, TagSampleBufferSGIX, (void)) #endif #if defined _ALLEGRO_GL_SGIX_polynomial_ffd AGL_API(void, DeformationMap3dSGIX, (GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, const GLdouble *)) AGL_API(void, DeformationMap3fSGIX, (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, const GLfloat *)) AGL_API(void, DeformSGIX, (GLbitfield)) AGL_API(void, LoadIdentityDeformationMapSGIX, (GLbitfield)) #endif #if defined _ALLEGRO_GL_SGIX_reference_plane AGL_API(void, ReferencePlaneSGIX, (const GLdouble *)) #endif #if defined _ALLEGRO_GL_SGIX_flush_raster AGL_API(void, FlushRasterSGIX, (void)) #endif #if defined _ALLEGRO_GL_SGIS_fog_function AGL_API(void, FogFuncSGIS, (GLsizei, const GLfloat *)) AGL_API(void, GetFogFuncSGIS, (GLfloat *)) #endif #if defined _ALLEGRO_GL_HP_image_transform AGL_API(void, ImageTransformParameteriHP, (GLenum, GLenum, GLint)) AGL_API(void, ImageTransformParameterfHP, (GLenum, GLenum, GLfloat)) AGL_API(void, ImageTransformParameterivHP, (GLenum, GLenum, const GLint *)) AGL_API(void, ImageTransformParameterfvHP, (GLenum, GLenum, const GLfloat *)) AGL_API(void, GetImageTransformParameterivHP, (GLenum, GLenum, GLint *)) AGL_API(void, GetImageTransformParameterfvHP, (GLenum, GLenum, GLfloat *)) #endif #if defined _ALLEGRO_GL_EXT_color_subtable #ifndef GL_EXT_paletted_texture AGL_API(void, ColorSubTableEXT, (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) #endif AGL_API(void, CopyColorSubTableEXT, (GLenum, GLsizei, GLint, GLint, GLsizei)) #endif #if defined _ALLEGRO_GL_PGI_misc_hints AGL_API(void, HintPGI, (GLenum, GLint)) #endif #if defined _ALLEGRO_GL_EXT_paletted_texture AGL_API(void, ColorTableEXT, (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, GetColorTableEXT, (GLenum, GLenum, GLenum, GLvoid *)) AGL_API(void, GetColorTableParameterivEXT, (GLenum, GLenum, GLint *)) AGL_API(void, GetColorTableParameterfvEXT, (GLenum, GLenum, GLfloat *)) #endif #if defined _ALLEGRO_GL_SGIX_list_priority AGL_API(void, GetListParameterfvSGIX, (GLuint, GLenum, GLfloat *)) AGL_API(void, GetListParameterivSGIX, (GLuint, GLenum, GLint *)) AGL_API(void, ListParameterfSGIX, (GLuint, GLenum, GLfloat)) AGL_API(void, ListParameterfvSGIX, (GLuint, GLenum, const GLfloat *)) AGL_API(void, ListParameteriSGIX, (GLuint, GLenum, GLint)) AGL_API(void, ListParameterivSGIX, (GLuint, GLenum, const GLint *)) #endif #if defined _ALLEGRO_GL_EXT_index_material AGL_API(void, IndexMaterialEXT, (GLenum, GLenum)) #endif #if defined _ALLEGRO_GL_EXT_index_func AGL_API(void, IndexFuncEXT, (GLenum, GLclampf)) #endif #if defined _ALLEGRO_GL_EXT_compiled_vertex_array AGL_API(void, LockArraysEXT, (GLint, GLsizei)) AGL_API(void, UnlockArraysEXT, (void)) #endif #if defined _ALLEGRO_GL_EXT_cull_vertex AGL_API(void, CullParameterdvEXT, (GLenum, GLdouble *)) AGL_API(void, CullParameterfvEXT, (GLenum, GLfloat *)) #endif #if defined _ALLEGRO_GL_SGIX_fragment_lighting AGL_API(void, FragmentColorMaterialSGIX, (GLenum, GLenum)) AGL_API(void, FragmentLightfSGIX, (GLenum, GLenum, GLfloat)) AGL_API(void, FragmentLightfvSGIX, (GLenum, GLenum, const GLfloat *)) AGL_API(void, FragmentLightiSGIX, (GLenum, GLenum, GLint)) AGL_API(void, FragmentLightivSGIX, (GLenum, GLenum, const GLint *)) AGL_API(void, FragmentLightModelfSGIX, (GLenum, GLfloat)) AGL_API(void, FragmentLightModelfvSGIX, (GLenum, const GLfloat *)) AGL_API(void, FragmentLightModeliSGIX, (GLenum, GLint)) AGL_API(void, FragmentLightModelivSGIX, (GLenum, const GLint *)) AGL_API(void, FragmentMaterialfSGIX, (GLenum, GLenum, GLfloat)) AGL_API(void, FragmentMaterialfvSGIX, (GLenum, GLenum, const GLfloat *)) AGL_API(void, FragmentMaterialiSGIX, (GLenum, GLenum, GLint)) AGL_API(void, FragmentMaterialivSGIX, (GLenum, GLenum, const GLint *)) AGL_API(void, GetFragmentLightfvSGIX, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetFragmentLightivSGIX, (GLenum, GLenum, GLint *)) AGL_API(void, GetFragmentMaterialfvSGIX, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetFragmentMaterialivSGIX, (GLenum, GLenum, GLint *)) AGL_API(void, LightEnviSGIX, (GLenum, GLint)) #endif #if defined _ALLEGRO_GL_EXT_draw_range_elements AGL_API(void, DrawRangeElementsEXT, (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *)) #endif #if defined _ALLEGRO_GL_EXT_light_texture AGL_API(void, ApplyTextureEXT, (GLenum)) AGL_API(void, TextureLightEXT, (GLenum)) AGL_API(void, TextureMaterialEXT, (GLenum, GLenum)) #endif #if defined _ALLEGRO_GL_SGIX_async AGL_API(void, AsyncMarkerSGIX, (GLuint)) AGL_API(GLint, FinishAsyncSGIX, (GLuint *)) AGL_API(GLint, PollAsyncSGIX, (GLuint *)) AGL_API(GLuint, GenAsyncMarkersSGIX, (GLsizei)) AGL_API(void, DeleteAsyncMarkersSGIX, (GLuint, GLsizei)) AGL_API(GLboolean, IsAsyncMarkerSGIX, (GLuint)) #endif #if defined _ALLEGRO_GL_INTEL_parallel_arrays AGL_API(void, VertexPointervINTEL, (GLint, GLenum, const GLvoid* *)) AGL_API(void, NormalPointervINTEL, (GLenum, const GLvoid* *)) AGL_API(void, ColorPointervINTEL, (GLint, GLenum, const GLvoid* *)) AGL_API(void, TexCoordPointervINTEL, (GLint, GLenum, const GLvoid* *)) #endif #if defined _ALLEGRO_GL_EXT_pixel_transform AGL_API(void, PixelTransformParameteriEXT, (GLenum, GLenum, GLint)) AGL_API(void, PixelTransformParameterfEXT, (GLenum, GLenum, GLfloat)) AGL_API(void, PixelTransformParameterivEXT, (GLenum, GLenum, const GLint *)) AGL_API(void, PixelTransformParameterfvEXT, (GLenum, GLenum, const GLfloat *)) #endif #if defined _ALLEGRO_GL_EXT_secondary_color AGL_API(void, SecondaryColor3bEXT, (GLbyte, GLbyte, GLbyte)) AGL_API(void, SecondaryColor3bvEXT, (const GLbyte *)) AGL_API(void, SecondaryColor3dEXT, (GLdouble, GLdouble, GLdouble)) AGL_API(void, SecondaryColor3dvEXT, (const GLdouble *)) AGL_API(void, SecondaryColor3fEXT, (GLfloat, GLfloat, GLfloat)) AGL_API(void, SecondaryColor3fvEXT, (const GLfloat *)) AGL_API(void, SecondaryColor3iEXT, (GLint, GLint, GLint)) AGL_API(void, SecondaryColor3ivEXT, (const GLint *)) AGL_API(void, SecondaryColor3sEXT, (GLshort, GLshort, GLshort)) AGL_API(void, SecondaryColor3svEXT, (const GLshort *)) AGL_API(void, SecondaryColor3ubEXT, (GLubyte, GLubyte, GLubyte)) AGL_API(void, SecondaryColor3ubvEXT, (const GLubyte *)) AGL_API(void, SecondaryColor3uiEXT, (GLuint, GLuint, GLuint)) AGL_API(void, SecondaryColor3uivEXT, (const GLuint *)) AGL_API(void, SecondaryColor3usEXT, (GLushort, GLushort, GLushort)) AGL_API(void, SecondaryColor3usvEXT, (const GLushort *)) AGL_API(void, SecondaryColorPointerEXT, (GLint, GLenum, GLsizei, const GLvoid *)) #endif #if defined _ALLEGRO_GL_EXT_texture_perturb_normal AGL_API(void, TextureNormalEXT, (GLenum)) #endif #if defined _ALLEGRO_GL_EXT_multi_draw_arrays AGL_API(void, MultiDrawArraysEXT, (GLenum, GLint *, GLsizei *, GLsizei)) AGL_API(void, MultiDrawElementsEXT, (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei)) #endif #if defined _ALLEGRO_GL_EXT_fog_coord AGL_API(void, FogCoordfEXT, (GLfloat)) AGL_API(void, FogCoordfvEXT, (const GLfloat *)) AGL_API(void, FogCoorddEXT, (GLdouble)) AGL_API(void, FogCoorddvEXT, (const GLdouble *)) AGL_API(void, FogCoordPointerEXT, (GLenum, GLsizei, const GLvoid *)) #endif #if defined _ALLEGRO_GL_EXT_coordinate_frame AGL_API(void, Tangent3bEXT, (GLbyte, GLbyte, GLbyte)) AGL_API(void, Tangent3bvEXT, (const GLbyte *)) AGL_API(void, Tangent3dEXT, (GLdouble, GLdouble, GLdouble)) AGL_API(void, Tangent3dvEXT, (const GLdouble *)) AGL_API(void, Tangent3fEXT, (GLfloat, GLfloat, GLfloat)) AGL_API(void, Tangent3fvEXT, (const GLfloat *)) AGL_API(void, Tangent3iEXT, (GLint, GLint, GLint)) AGL_API(void, Tangent3ivEXT, (const GLint *)) AGL_API(void, Tangent3sEXT, (GLshort, GLshort, GLshort)) AGL_API(void, Tangent3svEXT, (const GLshort *)) AGL_API(void, Binormal3bEXT, (GLbyte, GLbyte, GLbyte)) AGL_API(void, Binormal3bvEXT, (const GLbyte *)) AGL_API(void, Binormal3dEXT, (GLdouble, GLdouble, GLdouble)) AGL_API(void, Binormal3dvEXT, (const GLdouble *)) AGL_API(void, Binormal3fEXT, (GLfloat, GLfloat, GLfloat)) AGL_API(void, Binormal3fvEXT, (const GLfloat *)) AGL_API(void, Binormal3iEXT, (GLint, GLint, GLint)) AGL_API(void, Binormal3ivEXT, (const GLint *)) AGL_API(void, Binormal3sEXT, (GLshort, GLshort, GLshort)) AGL_API(void, Binormal3svEXT, (const GLshort *)) AGL_API(void, TangentPointerEXT, (GLenum, GLsizei, const GLvoid *)) AGL_API(void, BinormalPointerEXT, (GLenum, GLsizei, const GLvoid *)) #endif #if defined _ALLEGRO_GL_SUNX_constant_data AGL_API(void, FinishTextureSUNX, (void)) #endif #if defined _ALLEGRO_GL_SUN_global_alpha AGL_API(void, GlobalAlphaFactorbSUN, (GLbyte)) AGL_API(void, GlobalAlphaFactorsSUN, (GLshort)) AGL_API(void, GlobalAlphaFactoriSUN, (GLint)) AGL_API(void, GlobalAlphaFactorfSUN, (GLfloat)) AGL_API(void, GlobalAlphaFactordSUN, (GLdouble)) AGL_API(void, GlobalAlphaFactorubSUN, (GLubyte)) AGL_API(void, GlobalAlphaFactorusSUN, (GLushort)) AGL_API(void, GlobalAlphaFactoruiSUN, (GLuint)) #endif #if defined _ALLEGRO_GL_SUN_triangle_list AGL_API(void, ReplacementCodeuiSUN, (GLuint)) AGL_API(void, ReplacementCodeusSUN, (GLushort)) AGL_API(void, ReplacementCodeubSUN, (GLubyte)) AGL_API(void, ReplacementCodeuivSUN, (const GLuint *)) AGL_API(void, ReplacementCodeusvSUN, (const GLushort *)) AGL_API(void, ReplacementCodeubvSUN, (const GLubyte *)) AGL_API(void, ReplacementCodePointerSUN, (GLenum, GLsizei, const GLvoid* *)) #endif #if defined _ALLEGRO_GL_SUN_vertex AGL_API(void, Color4ubVertex2fSUN, (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat)) AGL_API(void, Color4ubVertex2fvSUN, (const GLubyte *, const GLfloat *)) AGL_API(void, Color4ubVertex3fSUN, (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat)) AGL_API(void, Color4ubVertex3fvSUN, (const GLubyte *, const GLfloat *)) AGL_API(void, Color3fVertex3fSUN, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, Color3fVertex3fvSUN, (const GLfloat *, const GLfloat *)) AGL_API(void, Normal3fVertex3fSUN, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, Normal3fVertex3fvSUN, (const GLfloat *, const GLfloat *)) AGL_API(void, Color4fNormal3fVertex3fSUN, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, Color4fNormal3fVertex3fvSUN, (const GLfloat *, const GLfloat *, const GLfloat *)) AGL_API(void, TexCoord2fVertex3fSUN, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, TexCoord2fVertex3fvSUN, (const GLfloat *, const GLfloat *)) AGL_API(void, TexCoord4fVertex4fSUN, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, TexCoord4fVertex4fvSUN, (const GLfloat *, const GLfloat *)) AGL_API(void, TexCoord2fColor4ubVertex3fSUN, (GLfloat, GLfloat, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat)) AGL_API(void, TexCoord2fColor4ubVertex3fvSUN, (const GLfloat *, const GLubyte *, const GLfloat *)) AGL_API(void, TexCoord2fColor3fVertex3fSUN, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, TexCoord2fColor3fVertex3fvSUN, (const GLfloat *, const GLfloat *, const GLfloat *)) AGL_API(void, TexCoord2fNormal3fVertex3fSUN, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, TexCoord2fNormal3fVertex3fvSUN, (const GLfloat *, const GLfloat *, const GLfloat *)) AGL_API(void, TexCoord2fColor4fNormal3fVertex3fSUN, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, TexCoord2fColor4fNormal3fVertex3fvSUN, (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *)) AGL_API(void, TexCoord4fColor4fNormal3fVertex4fSUN, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, TexCoord4fColor4fNormal3fVertex4fvSUN, (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *)) AGL_API(void, ReplacementCodeuiVertex3fSUN, (GLuint, GLfloat, GLfloat, GLfloat)) AGL_API(void, ReplacementCodeuiVertex3fvSUN, (const GLuint *, const GLfloat *)) AGL_API(void, ReplacementCodeuiColor4ubVertex3fSUN, (GLuint, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat)) AGL_API(void, ReplacementCodeuiColor4ubVertex3fvSUN, (const GLuint *, const GLubyte *, const GLfloat *)) AGL_API(void, ReplacementCodeuiColor3fVertex3fSUN, (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, ReplacementCodeuiColor3fVertex3fvSUN, (const GLuint *, const GLfloat *, const GLfloat *)) AGL_API(void, ReplacementCodeuiNormal3fVertex3fSUN, (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, ReplacementCodeuiNormal3fVertex3fvSUN, (const GLuint *, const GLfloat *, const GLfloat *)) AGL_API(void, ReplacementCodeuiColor4fNormal3fVertex3fSUN, (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, ReplacementCodeuiColor4fNormal3fVertex3fvSUN, (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *)) AGL_API(void, ReplacementCodeuiTexCoord2fVertex3fSUN, (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, ReplacementCodeuiTexCoord2fVertex3fvSUN, (const GLuint *, const GLfloat *, const GLfloat *)) AGL_API(void, ReplacementCodeuiTexCoord2fNormal3fVertex3fSUN, (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, ReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN, (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *)) AGL_API(void, ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN, (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN, (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *)) #endif #if defined _ALLEGRO_GL_EXT_blend_func_separate AGL_API(void, BlendFuncSeparateEXT, (GLenum, GLenum, GLenum, GLenum)) #endif #if defined _ALLEGRO_GL_INGR_blend_func_separate AGL_API(void, BlendFuncSeparateINGR, (GLenum, GLenum, GLenum, GLenum)) #endif #if defined _ALLEGRO_GL_EXT_vertex_weighting AGL_API(void, VertexWeightfEXT, (GLfloat)) AGL_API(void, VertexWeightfvEXT, (const GLfloat *)) AGL_API(void, VertexWeightPointerEXT, (GLsizei, GLenum, GLsizei, const GLvoid *)) #endif #if defined _ALLEGRO_GL_NV_vertex_array_range AGL_API(void, FlushVertexArrayRangeNV, (void)) AGL_API(void, VertexArrayRangeNV, (GLsizei, const GLvoid *)) #endif #if defined _ALLEGRO_GL_NV_register_combiners AGL_API(void, CombinerParameterfvNV, (GLenum, const GLfloat *)) AGL_API(void, CombinerParameterfNV, (GLenum, GLfloat)) AGL_API(void, CombinerParameterivNV, (GLenum, const GLint *)) AGL_API(void, CombinerParameteriNV, (GLenum, GLint)) AGL_API(void, CombinerInputNV, (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum)) AGL_API(void, CombinerOutputNV, (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLboolean, GLboolean, GLboolean)) AGL_API(void, FinalCombinerInputNV, (GLenum, GLenum, GLenum, GLenum)) AGL_API(void, GetCombinerInputParameterfvNV, (GLenum, GLenum, GLenum, GLenum, GLfloat *)) AGL_API(void, GetCombinerInputParameterivNV, (GLenum, GLenum, GLenum, GLenum, GLint *)) AGL_API(void, GetCombinerOutputParameterfvNV, (GLenum, GLenum, GLenum, GLfloat *)) AGL_API(void, GetCombinerOutputParameterivNV, (GLenum, GLenum, GLenum, GLint *)) AGL_API(void, GetFinalCombinerInputParameterfvNV, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetFinalCombinerInputParameterivNV, (GLenum, GLenum, GLint *)) #endif #if defined _ALLEGRO_GL_MESA_resize_buffers AGL_API(void, ResizeBuffersMESA, (void)) #endif #if defined _ALLEGRO_GL_MESA_window_pos AGL_API(void, WindowPos2dMESA, (GLdouble, GLdouble)) AGL_API(void, WindowPos2dvMESA, (const GLdouble *)) AGL_API(void, WindowPos2fMESA, (GLfloat, GLfloat)) AGL_API(void, WindowPos2fvMESA, (const GLfloat *)) AGL_API(void, WindowPos2iMESA, (GLint, GLint)) AGL_API(void, WindowPos2ivMESA, (const GLint *)) AGL_API(void, WindowPos2sMESA, (GLshort, GLshort)) AGL_API(void, WindowPos2svMESA, (const GLshort *)) AGL_API(void, WindowPos3dMESA, (GLdouble, GLdouble, GLdouble)) AGL_API(void, WindowPos3dvMESA, (const GLdouble *)) AGL_API(void, WindowPos3fMESA, (GLfloat, GLfloat, GLfloat)) AGL_API(void, WindowPos3fvMESA, (const GLfloat *)) AGL_API(void, WindowPos3iMESA, (GLint, GLint, GLint)) AGL_API(void, WindowPos3ivMESA, (const GLint *)) AGL_API(void, WindowPos3sMESA, (GLshort, GLshort, GLshort)) AGL_API(void, WindowPos3svMESA, (const GLshort *)) AGL_API(void, WindowPos4dMESA, (GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, WindowPos4dvMESA, (const GLdouble *)) AGL_API(void, WindowPos4fMESA, (GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, WindowPos4fvMESA, (const GLfloat *)) AGL_API(void, WindowPos4iMESA, (GLint, GLint, GLint, GLint)) AGL_API(void, WindowPos4ivMESA, (const GLint *)) AGL_API(void, WindowPos4sMESA, (GLshort, GLshort, GLshort, GLshort)) AGL_API(void, WindowPos4svMESA, (const GLshort *)) #endif #if defined _ALLEGRO_GL_IBM_multimode_draw_arrays AGL_API(void, MultiModeDrawArraysIBM, (GLenum, const GLint *, const GLsizei *, GLsizei, GLint)) AGL_API(void, MultiModeDrawElementsIBM, (const GLenum *, const GLsizei *, GLenum, const GLvoid* *, GLsizei, GLint)) #endif #ifdef AGK_IBM_vertex_array_lists AGL_API(void, ColorPointerListIBM, (GLint, GLenum, GLint, const GLvoid* *, GLint)) AGL_API(void, SecondaryColorPointerListIBM, (GLint, GLenum, GLint, const GLvoid* *, GLint)) AGL_API(void, EdgeFlagPointerListIBM, (GLint, const GLboolean* *, GLint)) AGL_API(void, FogCoordPointerListIBM, (GLenum, GLint, const GLvoid* *, GLint)) AGL_API(void, IndexPointerListIBM, (GLenum, GLint, const GLvoid* *, GLint)) AGL_API(void, NormalPointerListIBM, (GLenum, GLint, const GLvoid* *, GLint)) AGL_API(void, TexCoordPointerListIBM, (GLint, GLenum, GLint, const GLvoid* *, GLint)) AGL_API(void, VertexPointerListIBM, (GLint, GLenum, GLint, const GLvoid* *, GLint)) #endif #if defined _ALLEGRO_GL_3DFX_tbuffer AGL_API(void, TbufferMask3DFX, (GLuint)) #endif #if defined _ALLEGRO_GL_EXT_multisample AGL_API(void, SampleMaskEXT, (GLclampf, GLboolean)) AGL_API(void, SamplePatternEXT, (GLenum)) #endif #if defined _ALLEGRO_GL_SGIS_texture_color_mask AGL_API(void, TextureColorMaskSGIS, (GLboolean, GLboolean, GLboolean, GLboolean)) #endif #if defined _ALLEGRO_GL_SGIX_igloo_interface AGL_API(void, IglooInterfaceSGIX, (GLenum, const GLvoid *)) #endif #if defined _ALLEGRO_GL_NV_fence AGL_API(void, DeleteFencesNV, (GLsizei, const GLuint *)) AGL_API(void, GenFencesNV, (GLsizei, GLuint *)) AGL_API(GLboolean, IsFenceNV, (GLuint)) AGL_API(GLboolean, TestFenceNV, (GLuint)) AGL_API(void, GetFenceivNV, (GLuint, GLenum, GLint *)) AGL_API(void, FinishFenceNV, (GLuint)) AGL_API(void, SetFenceNV, (GLuint, GLenum)) #endif #if defined _ALLEGRO_GL_NV_evaluators AGL_API(void, MapControlPointsNV, (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLint, GLint, GLboolean, const GLvoid *)) AGL_API(void, MapParameterivNV, (GLenum, GLenum, const GLint *)) AGL_API(void, MapParameterfvNV, (GLenum, GLenum, const GLfloat *)) AGL_API(void, GetMapControlPointsNV, (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLboolean, GLvoid *)) AGL_API(void, GetMapParameterivNV, (GLenum, GLenum, GLint *)) AGL_API(void, GetMapParameterfvNV, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetMapAttribParameterivNV, (GLenum, GLuint, GLenum, GLint *)) AGL_API(void, GetMapAttribParameterfvNV, (GLenum, GLuint, GLenum, GLfloat *)) AGL_API(void, EvalMapsNV, (GLenum, GLenum)) #endif #if defined _ALLEGRO_GL_NV_register_combiners2 AGL_API(void, CombinerStageParameterfvNV, (GLenum, GLenum, const GLfloat *)) AGL_API(void, GetCombinerStageParameterfvNV, (GLenum, GLenum, GLfloat *)) #endif #if defined _ALLEGRO_GL_NV_vertex_program AGL_API(GLboolean, AreProgramsResidentNV, (GLsizei, const GLuint *, GLboolean *)) AGL_API(void, BindProgramNV, (GLenum, GLuint)) AGL_API(void, DeleteProgramsNV, (GLsizei, const GLuint *)) AGL_API(void, ExecuteProgramNV, (GLenum, GLuint, const GLfloat *)) AGL_API(void, GenProgramsNV, (GLsizei, GLuint *)) AGL_API(void, GetProgramParameterdvNV, (GLenum, GLuint, GLenum, GLdouble *)) AGL_API(void, GetProgramParameterfvNV, (GLenum, GLuint, GLenum, GLfloat *)) AGL_API(void, GetProgramivNV, (GLuint, GLenum, GLint *)) AGL_API(void, GetProgramStringNV, (GLuint, GLenum, GLubyte *)) AGL_API(void, GetTrackMatrixivNV, (GLenum, GLuint, GLenum, GLint *)) AGL_API(void, GetVertexAttribdvNV, (GLuint, GLenum, GLdouble *)) AGL_API(void, GetVertexAttribfvNV, (GLuint, GLenum, GLfloat *)) AGL_API(void, GetVertexAttribivNV, (GLuint, GLenum, GLint *)) AGL_API(void, GetVertexAttribPointervNV, (GLuint, GLenum, GLvoid* *)) AGL_API(GLboolean, IsProgramNV, (GLuint)) AGL_API(void, LoadProgramNV, (GLenum, GLuint, GLsizei, const GLubyte *)) AGL_API(void, ProgramParameter4dNV, (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, ProgramParameter4dvNV, (GLenum, GLuint, const GLdouble *)) AGL_API(void, ProgramParameter4fNV, (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, ProgramParameter4fvNV, (GLenum, GLuint, const GLfloat *)) AGL_API(void, ProgramParameters4dvNV, (GLenum, GLuint, GLuint, const GLdouble *)) AGL_API(void, ProgramParameters4fvNV, (GLenum, GLuint, GLuint, const GLfloat *)) AGL_API(void, RequestResidentProgramsNV, (GLsizei, const GLuint *)) AGL_API(void, TrackMatrixNV, (GLenum, GLuint, GLenum, GLenum)) AGL_API(void, VertexAttribPointerNV, (GLuint, GLint, GLenum, GLsizei, const GLvoid *)) AGL_API(void, VertexAttrib1dNV, (GLuint, GLdouble)) AGL_API(void, VertexAttrib1dvNV, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib1fNV, (GLuint, GLfloat)) AGL_API(void, VertexAttrib1fvNV, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib1sNV, (GLuint, GLshort)) AGL_API(void, VertexAttrib1svNV, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib2dNV, (GLuint, GLdouble, GLdouble)) AGL_API(void, VertexAttrib2dvNV, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib2fNV, (GLuint, GLfloat, GLfloat)) AGL_API(void, VertexAttrib2fvNV, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib2sNV, (GLuint, GLshort, GLshort)) AGL_API(void, VertexAttrib2svNV, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib3dNV, (GLuint, GLdouble, GLdouble, GLdouble)) AGL_API(void, VertexAttrib3dvNV, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib3fNV, (GLuint, GLfloat, GLfloat, GLfloat)) AGL_API(void, VertexAttrib3fvNV, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib3sNV, (GLuint, GLshort, GLshort, GLshort)) AGL_API(void, VertexAttrib3svNV, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib4dNV, (GLuint, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, VertexAttrib4dvNV, (GLuint, const GLdouble *)) AGL_API(void, VertexAttrib4fNV, (GLuint, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, VertexAttrib4fvNV, (GLuint, const GLfloat *)) AGL_API(void, VertexAttrib4sNV, (GLuint, GLshort, GLshort, GLshort, GLshort)) AGL_API(void, VertexAttrib4svNV, (GLuint, const GLshort *)) AGL_API(void, VertexAttrib4ubNV, (GLuint, GLubyte, GLubyte, GLubyte, GLubyte)) AGL_API(void, VertexAttrib4ubvNV, (GLuint, const GLubyte *)) AGL_API(void, VertexAttribs1dvNV, (GLuint, GLsizei, const GLdouble *)) AGL_API(void, VertexAttribs1fvNV, (GLuint, GLsizei, const GLfloat *)) AGL_API(void, VertexAttribs1svNV, (GLuint, GLsizei, const GLshort *)) AGL_API(void, VertexAttribs2dvNV, (GLuint, GLsizei, const GLdouble *)) AGL_API(void, VertexAttribs2fvNV, (GLuint, GLsizei, const GLfloat *)) AGL_API(void, VertexAttribs2svNV, (GLuint, GLsizei, const GLshort *)) AGL_API(void, VertexAttribs3dvNV, (GLuint, GLsizei, const GLdouble *)) AGL_API(void, VertexAttribs3fvNV, (GLuint, GLsizei, const GLfloat *)) AGL_API(void, VertexAttribs3svNV, (GLuint, GLsizei, const GLshort *)) AGL_API(void, VertexAttribs4dvNV, (GLuint, GLsizei, const GLdouble *)) AGL_API(void, VertexAttribs4fvNV, (GLuint, GLsizei, const GLfloat *)) AGL_API(void, VertexAttribs4svNV, (GLuint, GLsizei, const GLshort *)) AGL_API(void, VertexAttribs4ubvNV, (GLuint, GLsizei, const GLubyte *)) #endif #if defined _ALLEGRO_GL_ATI_envmap_bumpmap AGL_API(void, TexBumpParameterivATI, (GLenum, const GLint *)) AGL_API(void, TexBumpParameterfvATI, (GLenum, const GLfloat *)) AGL_API(void, GetTexBumpParameterivATI, (GLenum, GLint *)) AGL_API(void, GetTexBumpParameterfvATI, (GLenum, GLfloat *)) #endif #if defined _ALLEGRO_GL_ATI_fragment_shader AGL_API(GLuint, GenFragmentShadersATI, (GLuint)) AGL_API(void, BindFragmentShaderATI, (GLuint)) AGL_API(void, DeleteFragmentShaderATI, (GLuint)) AGL_API(void, BeginFragmentShaderATI, (void)) AGL_API(void, EndFragmentShaderATI, (void)) AGL_API(void, PassTexCoordATI, (GLuint, GLuint, GLenum)) AGL_API(void, SampleMapATI, (GLuint, GLuint, GLenum)) AGL_API(void, ColorFragmentOp1ATI, (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, ColorFragmentOp2ATI, (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, ColorFragmentOp3ATI, (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, AlphaFragmentOp1ATI, (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, AlphaFragmentOp2ATI, (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, AlphaFragmentOp3ATI, (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, SetFragmentShaderConstantATI, (GLuint, const GLfloat *)) #endif #if defined _ALLEGRO_GL_ATI_pn_triangles AGL_API(void, PNTrianglesiATI, (GLenum, GLint)) AGL_API(void, PNTrianglesfATI, (GLenum, GLfloat)) #endif #if defined _ALLEGRO_GL_ATI_vertex_array_object AGL_API(GLuint, NewObjectBufferATI, (GLsizei, const GLvoid *, GLenum)) AGL_API(GLboolean, IsObjectBufferATI, (GLuint)) AGL_API(void, UpdateObjectBufferATI, (GLuint, GLuint, GLsizei, const GLvoid *, GLenum)) AGL_API(void, GetObjectBufferfvATI, (GLuint, GLenum, GLfloat *)) AGL_API(void, GetObjectBufferivATI, (GLuint, GLenum, GLint *)) AGL_API(void, FreeObjectBufferATI, (GLuint)) AGL_API(void, ArrayObjectATI, (GLenum, GLint, GLenum, GLsizei, GLuint, GLuint)) AGL_API(void, GetArrayObjectfvATI, (GLenum, GLenum, GLfloat *)) AGL_API(void, GetArrayObjectivATI, (GLenum, GLenum, GLint *)) AGL_API(void, VariantArrayObjectATI, (GLuint, GLenum, GLsizei, GLuint, GLuint)) AGL_API(void, GetVariantArrayObjectfvATI, (GLuint, GLenum, GLfloat *)) AGL_API(void, GetVariantArrayObjectivATI, (GLuint, GLenum, GLint *)) #endif #if defined _ALLEGRO_GL_EXT_vertex_shader AGL_API(void, BeginVertexShaderEXT, (void)) AGL_API(void, EndVertexShaderEXT, (void)) AGL_API(void, BindVertexShaderEXT, (GLuint)) AGL_API(GLuint, GenVertexShadersEXT, (GLuint)) AGL_API(void, DeleteVertexShaderEXT, (GLuint)) AGL_API(void, ShaderOp1EXT, (GLenum, GLuint, GLuint)) AGL_API(void, ShaderOp2EXT, (GLenum, GLuint, GLuint, GLuint)) AGL_API(void, ShaderOp3EXT, (GLenum, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, SwizzleEXT, (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum)) AGL_API(void, WriteMaskEXT, (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum)) AGL_API(void, InsertComponentEXT, (GLuint, GLuint, GLuint)) AGL_API(void, ExtractComponentEXT, (GLuint, GLuint, GLuint)) AGL_API(GLuint, GenSymbolsEXT, (GLenum, GLenum, GLenum, GLuint)) AGL_API(void, SetInvariantEXT, (GLuint, GLenum, const GLvoid *)) AGL_API(void, SetLocalConstantEXT, (GLuint, GLenum, const GLvoid *)) AGL_API(void, VariantbvEXT, (GLuint, const GLbyte *)) AGL_API(void, VariantsvEXT, (GLuint, const GLshort *)) AGL_API(void, VariantivEXT, (GLuint, const GLint *)) AGL_API(void, VariantfvEXT, (GLuint, const GLfloat *)) AGL_API(void, VariantdvEXT, (GLuint, const GLdouble *)) AGL_API(void, VariantubvEXT, (GLuint, const GLubyte *)) AGL_API(void, VariantusvEXT, (GLuint, const GLushort *)) AGL_API(void, VariantuivEXT, (GLuint, const GLuint *)) AGL_API(void, VariantPointerEXT, (GLuint, GLenum, GLuint, const GLvoid *)) AGL_API(void, EnableVariantClientStateEXT, (GLuint)) AGL_API(void, DisableVariantClientStateEXT, (GLuint)) AGL_API(GLuint, BindLightParameterEXT, (GLenum, GLenum)) AGL_API(GLuint, BindMaterialParameterEXT, (GLenum, GLenum)) AGL_API(GLuint, BindTexGenParameterEXT, (GLenum, GLenum, GLenum)) AGL_API(GLuint, BindTextureUnitParameterEXT, (GLenum, GLenum)) AGL_API(GLuint, BindParameterEXT, (GLenum)) AGL_API(GLboolean, IsVariantEnabledEXT, (GLuint, GLenum)) AGL_API(void, GetVariantBooleanvEXT, (GLuint, GLenum, GLboolean *)) AGL_API(void, GetVariantIntegervEXT, (GLuint, GLenum, GLint *)) AGL_API(void, GetVariantFloatvEXT, (GLuint, GLenum, GLfloat *)) AGL_API(void, GetVariantPointervEXT, (GLuint, GLenum, GLvoid* *)) AGL_API(void, GetInvariantBooleanvEXT, (GLuint, GLenum, GLboolean *)) AGL_API(void, GetInvariantIntegervEXT, (GLuint, GLenum, GLint *)) AGL_API(void, GetInvariantFloatvEXT, (GLuint, GLenum, GLfloat *)) AGL_API(void, GetLocalConstantBooleanvEXT, (GLuint, GLenum, GLboolean *)) AGL_API(void, GetLocalConstantIntegervEXT, (GLuint, GLenum, GLint *)) AGL_API(void, GetLocalConstantFloatvEXT, (GLuint, GLenum, GLfloat *)) #endif #if defined _ALLEGRO_GL_ATI_vertex_streams AGL_API(void, VertexStream1sATI, (GLenum, GLshort)) AGL_API(void, VertexStream1svATI, (GLenum, const GLshort *)) AGL_API(void, VertexStream1iATI, (GLenum, GLint)) AGL_API(void, VertexStream1ivATI, (GLenum, const GLint *)) AGL_API(void, VertexStream1fATI, (GLenum, GLfloat)) AGL_API(void, VertexStream1fvATI, (GLenum, const GLfloat *)) AGL_API(void, VertexStream1dATI, (GLenum, GLdouble)) AGL_API(void, VertexStream1dvATI, (GLenum, const GLdouble *)) AGL_API(void, VertexStream2sATI, (GLenum, GLshort, GLshort)) AGL_API(void, VertexStream2svATI, (GLenum, const GLshort *)) AGL_API(void, VertexStream2iATI, (GLenum, GLint, GLint)) AGL_API(void, VertexStream2ivATI, (GLenum, const GLint *)) AGL_API(void, VertexStream2fATI, (GLenum, GLfloat, GLfloat)) AGL_API(void, VertexStream2fvATI, (GLenum, const GLfloat *)) AGL_API(void, VertexStream2dATI, (GLenum, GLdouble, GLdouble)) AGL_API(void, VertexStream2dvATI, (GLenum, const GLdouble *)) AGL_API(void, VertexStream3sATI, (GLenum, GLshort, GLshort, GLshort)) AGL_API(void, VertexStream3svATI, (GLenum, const GLshort *)) AGL_API(void, VertexStream3iATI, (GLenum, GLint, GLint, GLint)) AGL_API(void, VertexStream3ivATI, (GLenum, const GLint *)) AGL_API(void, VertexStream3fATI, (GLenum, GLfloat, GLfloat, GLfloat)) AGL_API(void, VertexStream3fvATI, (GLenum, const GLfloat *)) AGL_API(void, VertexStream3dATI, (GLenum, GLdouble, GLdouble, GLdouble)) AGL_API(void, VertexStream3dvATI, (GLenum, const GLdouble *)) AGL_API(void, VertexStream4sATI, (GLenum, GLshort, GLshort, GLshort, GLshort)) AGL_API(void, VertexStream4svATI, (GLenum, const GLshort *)) AGL_API(void, VertexStream4iATI, (GLenum, GLint, GLint, GLint, GLint)) AGL_API(void, VertexStream4ivATI, (GLenum, const GLint *)) AGL_API(void, VertexStream4fATI, (GLenum, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, VertexStream4fvATI, (GLenum, const GLfloat *)) AGL_API(void, VertexStream4dATI, (GLenum, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, VertexStream4dvATI, (GLenum, const GLdouble *)) AGL_API(void, NormalStream3bATI, (GLenum, GLbyte, GLbyte, GLbyte)) AGL_API(void, NormalStream3bvATI, (GLenum, const GLbyte *)) AGL_API(void, NormalStream3sATI, (GLenum, GLshort, GLshort, GLshort)) AGL_API(void, NormalStream3svATI, (GLenum, const GLshort *)) AGL_API(void, NormalStream3iATI, (GLenum, GLint, GLint, GLint)) AGL_API(void, NormalStream3ivATI, (GLenum, const GLint *)) AGL_API(void, NormalStream3fATI, (GLenum, GLfloat, GLfloat, GLfloat)) AGL_API(void, NormalStream3fvATI, (GLenum, const GLfloat *)) AGL_API(void, NormalStream3dATI, (GLenum, GLdouble, GLdouble, GLdouble)) AGL_API(void, NormalStream3dvATI, (GLenum, const GLdouble *)) AGL_API(void, ClientActiveVertexStreamATI, (GLenum)) AGL_API(void, VertexBlendEnviATI, (GLenum, GLint)) AGL_API(void, VertexBlendEnvfATI, (GLenum, GLfloat)) #endif #if defined _ALLEGRO_GL_ATI_element_array AGL_API(void, ElementPointerATI, (GLenum, const GLvoid *)) AGL_API(void, DrawElementArrayATI, (GLenum, GLsizei)) AGL_API(void, DrawRangeElementArrayATI, (GLenum, GLuint, GLuint, GLsizei)) #endif #if defined _ALLEGRO_GL_SUN_mesh_array AGL_API(void, DrawMeshArraysSUN, (GLenum, GLint, GLsizei, GLsizei)) #endif #if defined _ALLEGRO_GL_NV_occlusion_query AGL_API(void, GenOcclusionQueriesNV, (GLsizei, GLuint *)) AGL_API(void, DeleteOcclusionQueriesNV, (GLsizei, const GLuint *)) AGL_API(GLboolean, IsOcclusionQueryNV, (GLuint)) AGL_API(void, BeginOcclusionQueryNV, (GLuint)) AGL_API(void, EndOcclusionQueryNV, (void)) AGL_API(void, GetOcclusionQueryivNV, (GLuint, GLenum, GLint *)) AGL_API(void, GetOcclusionQueryuivNV, (GLuint, GLenum, GLuint *)) #endif #if defined _ALLEGRO_GL_NV_point_sprite AGL_API(void, PointParameteriNV, (GLenum, GLint)) AGL_API(void, PointParameterivNV, (GLenum, const GLint *)) #endif #if defined _ALLEGRO_GL_EXT_stencil_two_side AGL_API(void, ActiveStencilFaceEXT, (GLenum)) #endif #if defined _ALLEGRO_GL_APPLE_element_array AGL_API(void, ElementPointerAPPLE, (GLenum, const GLvoid *)) AGL_API(void, DrawElementArrayAPPLE, (GLenum, GLint, GLsizei)) AGL_API(void, DrawRangeElementArrayAPPLE, (GLenum, GLuint, GLuint, GLint, GLsizei)) AGL_API(void, MultiDrawElementArrayAPPLE, (GLenum, const GLint *, const GLsizei *, GLsizei)) AGL_API(void, MultiDrawRangeElementArrayAPPLE, (GLenum, GLuint, GLuint, const GLint *, const GLsizei *, GLsizei)) #endif #if defined _ALLEGRO_GL_APPLE_fence AGL_API(void, GenFencesAPPLE, (GLsizei, GLuint *)) AGL_API(void, DeleteFencesAPPLE, (GLsizei, const GLuint *)) AGL_API(void, SetFenceAPPLE, (GLuint)) AGL_API(GLboolean, IsFenceAPPLE, (GLuint)) AGL_API(GLboolean, TestFenceAPPLE, (GLuint)) AGL_API(void, FinishFenceAPPLE, (GLuint)) AGL_API(GLboolean, TestObjectAPPLE, (GLenum, GLuint)) AGL_API(void, FinishObjectAPPLE, (GLenum, GLint)) #endif #if defined _ALLEGRO_GL_APPLE_vertex_array_object AGL_API(void, BindVertexArrayAPPLE, (GLuint)) AGL_API(void, DeleteVertexArraysAPPLE, (GLsizei, const GLuint *)) AGL_API(void, GenVertexArraysAPPLE, (GLsizei, const GLuint *)) AGL_API(GLboolean, IsVertexArrayAPPLE, (GLuint)) #endif #if defined _ALLEGRO_GL_APPLE_vertex_array_range AGL_API(void, VertexArrayRangeAPPLE, (GLsizei, GLvoid *)) AGL_API(void, FlushVertexArrayRangeAPPLE, (GLsizei, GLvoid *)) AGL_API(void, VertexArrayParameteriAPPLE, (GLenum, GLint)) #endif #if defined _ALLEGRO_GL_ATI_draw_buffers AGL_API(void, DrawBuffersATI, (GLsizei, const GLenum *)) #endif #if defined _ALLEGRO_GL_NV_fragment_program AGL_API(void, ProgramNamedParameter4fNV, (GLuint, GLsizei, const GLubyte *, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, ProgramNamedParameter4dNV, (GLuint, GLsizei, const GLubyte *, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, ProgramNamedParameter4fvNV, (GLuint, GLsizei, const GLubyte *, const GLfloat *)) AGL_API(void, ProgramNamedParameter4dvNV, (GLuint, GLsizei, const GLubyte *, const GLdouble *)) AGL_API(void, GetProgramNamedParameterfvNV, (GLuint, GLsizei, const GLubyte *, GLfloat *)) AGL_API(void, GetProgramNamedParameterdvNV, (GLuint, GLsizei, const GLubyte *, GLdouble *)) #endif #if defined _ALLEGRO_GL_NV_half_float AGL_API(void, Vertex2hNV, (GLhalfNV, GLhalfNV)) AGL_API(void, Vertex2hvNV, (const GLhalfNV *)) AGL_API(void, Vertex3hNV, (GLhalfNV, GLhalfNV, GLhalfNV)) AGL_API(void, Vertex3hvNV, (const GLhalfNV *)) AGL_API(void, Vertex4hNV, (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV)) AGL_API(void, Vertex4hvNV, (const GLhalfNV *)) AGL_API(void, Normal3hNV, (GLhalfNV, GLhalfNV, GLhalfNV)) AGL_API(void, Normal3hvNV, (const GLhalfNV *)) AGL_API(void, Color3hNV, (GLhalfNV, GLhalfNV, GLhalfNV)) AGL_API(void, Color3hvNV, (const GLhalfNV *)) AGL_API(void, Color4hNV, (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV)) AGL_API(void, Color4hvNV, (const GLhalfNV *)) AGL_API(void, TexCoord1hNV, (GLhalfNV)) AGL_API(void, TexCoord1hvNV, (const GLhalfNV *)) AGL_API(void, TexCoord2hNV, (GLhalfNV, GLhalfNV)) AGL_API(void, TexCoord2hvNV, (const GLhalfNV *)) AGL_API(void, TexCoord3hNV, (GLhalfNV, GLhalfNV, GLhalfNV)) AGL_API(void, TexCoord3hvNV, (const GLhalfNV *)) AGL_API(void, TexCoord4hNV, (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV)) AGL_API(void, TexCoord4hvNV, (const GLhalfNV *)) AGL_API(void, MultiTexCoord1hNV, (GLenum, GLhalfNV)) AGL_API(void, MultiTexCoord1hvNV, (GLenum, const GLhalfNV *)) AGL_API(void, MultiTexCoord2hNV, (GLenum, GLhalfNV, GLhalfNV)) AGL_API(void, MultiTexCoord2hvNV, (GLenum, const GLhalfNV *)) AGL_API(void, MultiTexCoord3hNV, (GLenum, GLhalfNV, GLhalfNV, GLhalfNV)) AGL_API(void, MultiTexCoord3hvNV, (GLenum, const GLhalfNV *)) AGL_API(void, MultiTexCoord4hNV, (GLenum, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV)) AGL_API(void, MultiTexCoord4hvNV, (GLenum, const GLhalfNV *)) AGL_API(void, FogCoordhNV, (GLhalfNV)) AGL_API(void, FogCoordhvNV, (const GLhalfNV *)) AGL_API(void, SecondaryColor3hNV, (GLhalfNV, GLhalfNV, GLhalfNV)) AGL_API(void, SecondaryColor3hvNV, (const GLhalfNV *)) AGL_API(void, VertexWeighthNV, (GLhalfNV)) AGL_API(void, VertexWeighthvNV, (const GLhalfNV *)) AGL_API(void, VertexAttrib1hNV, (GLuint, GLhalfNV)) AGL_API(void, VertexAttrib1hvNV, (GLuint, const GLhalfNV *)) AGL_API(void, VertexAttrib2hNV, (GLuint, GLhalfNV, GLhalfNV)) AGL_API(void, VertexAttrib2hvNV, (GLuint, const GLhalfNV *)) AGL_API(void, VertexAttrib3hNV, (GLuint, GLhalfNV, GLhalfNV, GLhalfNV)) AGL_API(void, VertexAttrib3hvNV, (GLuint, const GLhalfNV *)) AGL_API(void, VertexAttrib4hNV, (GLuint, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV)) AGL_API(void, VertexAttrib4hvNV, (GLuint, const GLhalfNV *)) AGL_API(void, VertexAttribs1hvNV, (GLuint, GLsizei, const GLhalfNV *)) AGL_API(void, VertexAttribs2hvNV, (GLuint, GLsizei, const GLhalfNV *)) AGL_API(void, VertexAttribs3hvNV, (GLuint, GLsizei, const GLhalfNV *)) AGL_API(void, VertexAttribs4hvNV, (GLuint, GLsizei, const GLhalfNV *)) #endif #if defined _ALLEGRO_GL_NV_pixel_data_range AGL_API(void, PixelDataRangeNV, (GLenum, GLsizei, GLvoid *)) AGL_API(void, FlushPixelDataRangeNV, (GLenum)) #endif #if defined _ALLEGRO_GL_NV_primitive_restart AGL_API(void, PrimitiveRestartNV, (void)) AGL_API(void, PrimitiveRestartIndexNV, (GLuint)) #endif #if defined _ALLEGRO_GL_ATI_map_object_buffer AGL_API(GLvoid*, MapObjectBufferATI, (GLuint)) AGL_API(void, UnmapObjectBufferATI, (GLuint)) #endif #if defined _ALLEGRO_GL_ATI_separate_stencil AGL_API(void, StencilOpSeparateATI, (GLenum, GLenum, GLenum, GLenum)) AGL_API(void, StencilFuncSeparateATI, (GLenum, GLenum, GLint, GLuint)) #endif #if defined _ALLEGRO_GL_ATI_vertex_attrib_array_object AGL_API(void, VertexAttribArrayObjectATI, (GLuint, GLint, GLenum, GLboolean, GLsizei, GLuint, GLuint)) AGL_API(void, GetVertexAttribArrayObjectfvATI, (GLuint, GLenum, GLfloat *)) AGL_API(void, GetVertexAttribArrayObjectivATI, (GLuint, GLenum, GLint *)) #endif #if defined _ALLEGRO_GL_OES_byte_coordinates AGL_API(void, Vertex2bOES, ( GLbyte, GLbyte )) AGL_API(void, Vertex3bOES, ( GLbyte, GLbyte, GLbyte )) AGL_API(void, Vertex4bOES, ( GLbyte, GLbyte, GLbyte, GLbyte )) AGL_API(void, Vertex2bvOES, ( const GLbyte * )) AGL_API(void, Vertex3bvOES, ( const GLbyte * )) AGL_API(void, Vertex4bvOES, ( const GLbyte * )) AGL_API(void, TexCoord1bOES, ( GLbyte )) AGL_API(void, TexCoord2bOES, ( GLbyte, GLbyte )) AGL_API(void, TexCoord3bOES, ( GLbyte, GLbyte, GLbyte )) AGL_API(void, TexCoord4bOES, ( GLbyte, GLbyte, GLbyte, GLbyte )) AGL_API(void, TexCoord1bvOES, ( const GLbyte * )) AGL_API(void, TexCoord2bvOES, ( const GLbyte * )) AGL_API(void, TexCoord3bvOES, ( const GLbyte * )) AGL_API(void, TexCoord4bvOES, ( const GLbyte * )) AGL_API(void, MultiTexCoord1bOES, ( GLenum, GLbyte )) AGL_API(void, MultiTexCoord2bOES, ( GLenum, GLbyte, GLbyte )) AGL_API(void, MultiTexCoord3bOES, ( GLenum, GLbyte, GLbyte, GLbyte )) AGL_API(void, MultiTexCoord4bOES, ( GLenum, GLbyte, GLbyte, GLbyte, GLbyte )) AGL_API(void, MultiTexCoord1bvOES, ( GLenum texture, const GLbyte * )) AGL_API(void, MultiTexCoord2bvOES, ( GLenum texture, const GLbyte * )) AGL_API(void, MultiTexCoord3bvOES, ( GLenum texture, const GLbyte * )) AGL_API(void, MultiTexCoord4bvOES, ( GLenum texture, const GLbyte * )) #endif #if defined _ALLEGRO_GL_OES_fixed_point AGL_API(void, Vertex2xOES, (GLfixed, GLfixed)) AGL_API(void, Vertex3xOES, (GLfixed, GLfixed, GLfixed)) AGL_API(void, Vertex4xOES, (GLfixed, GLfixed, GLfixed, GLfixed)) AGL_API(void, Vertex2xvOES, (const GLfixed *)) AGL_API(void, Vertex3xvOES, (const GLfixed *)) AGL_API(void, Vertex4xvOES, (const GLfixed *)) AGL_API(void, Normal3xOES, (GLfixed, GLfixed, GLfixed)) AGL_API(void, Normal3xvOES, (const GLfixed *)) AGL_API(void, TexCoord1xOES, (GLfixed)) AGL_API(void, TexCoord2xOES, (GLfixed, GLfixed)) AGL_API(void, TexCoord3xOES, (GLfixed, GLfixed, GLfixed)) AGL_API(void, TexCoord4xOES, (GLfixed, GLfixed, GLfixed, GLfixed)) AGL_API(void, TexCoord1xvOES, (const GLfixed *)) AGL_API(void, TexCoord2xvOES, (const GLfixed *)) AGL_API(void, TexCoord3xvOES, (const GLfixed *)) AGL_API(void, TexCoord4xvOES, (const GLfixed *)) AGL_API(void, MultiTexCoord1xOES, (GLenum, GLfixed)) AGL_API(void, MultiTexCoord2xOES, (GLenum, GLfixed, GLfixed)) AGL_API(void, MultiTexCoord3xOES, (GLenum, GLfixed, GLfixed, GLfixed)) AGL_API(void, MultiTexCoord4xOES, (GLenum, GLfixed, GLfixed, GLfixed, GLfixed)) AGL_API(void, MultiTexCoord1xvOES, (GLenum, const GLfixed *)) AGL_API(void, MultiTexCoord2xvOES, (GLenum, const GLfixed *)) AGL_API(void, MultiTexCoord3xvOES, (GLenum, const GLfixed *)) AGL_API(void, MultiTexCoord4xvOES, (GLenum, const GLfixed *)) AGL_API(void, Color3xOES, (GLfixed, GLfixed, GLfixed)) AGL_API(void, Color4xOES, (GLfixed, GLfixed, GLfixed, GLfixed)) AGL_API(void, Color3xvOES, (const GLfixed *)) AGL_API(void, Color4xvOES, (const GLfixed *)) AGL_API(void, IndexxOES, (GLfixed)) AGL_API(void, IndexxvOES, (const GLfixed *)) AGL_API(void, RectxOES, (GLfixed, GLfixed, GLfixed, GLfixed)) AGL_API(void, RectxvOES, (const GLfixed [2], const GLfixed [2])) AGL_API(void, DepthRangexOES, (GLclampx, GLclampx)) AGL_API(void, LoadMatrixxOES, (const GLfixed [16])) AGL_API(void, MultMatrixxOES, (const GLfixed [16])) AGL_API(void, LoadTransposeMatrixxOES, (const GLfixed [16])) AGL_API(void, MultTransposeMatrixxOES, (const GLfixed [16])) AGL_API(void, RotatexOES, (GLfixed, GLfixed, GLfixed, GLfixed)) AGL_API(void, ScalexOES, (GLfixed, GLfixed, GLfixed)) AGL_API(void, TranslatexOES, (GLfixed, GLfixed, GLfixed)) AGL_API(void, FrustumxOES, (GLfixed, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed)) AGL_API(void, OrthoxOES, (GLfixed, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed)) AGL_API(void, TexGenxOES, (GLenum, GLenum, GLfixed)) AGL_API(void, TexGenxvOES, (GLenum, GLenum, const GLfixed *)) AGL_API(void, GetTexGenxvOES, (GLenum, GLenum, GLfixed *)) AGL_API(void, ClipPlanexOES, (GLenum, const GLfixed *)) AGL_API(void, GetClipPlanexOES, (GLenum, GLfixed *)) AGL_API(void, RasterPos2xOES, (GLfixed, GLfixed)) AGL_API(void, RasterPos3xOES, (GLfixed, GLfixed, GLfixed)) AGL_API(void, RasterPos4xOES, (GLfixed, GLfixed, GLfixed, GLfixed)) AGL_API(void, RasterPos2xvOES, (const GLfixed *)) AGL_API(void, RasterPos3xvOES, (const GLfixed *)) AGL_API(void, RasterPos4xvOES, (const GLfixed *)) AGL_API(void, MaterialxOES, (GLenum, GLenum, GLfixed)) AGL_API(void, MaterialxvOES, (GLenum, GLenum, const GLfixed *)) AGL_API(void, GetMaterialxOES, (GLenum, GLenum, GLfixed *)) AGL_API(void, LightxOES, (GLenum, GLenum, GLfixed)) AGL_API(void, LightxvOES, (GLenum, GLenum, const GLfixed *)) AGL_API(void, GetLightxOES, (GLenum, GLenum, const GLfixed *)) AGL_API(void, LightModelxOES, (GLenum, GLfixed)) AGL_API(void, LightModelxvOES, (GLenum, const GLfixed *)) AGL_API(void, PointSizexOES, (GLfixed size)) AGL_API(void, LineWidthxOES, (GLfixed width)) AGL_API(void, PolygonOffsetxOES, (GLfixed factor, GLfixed units)) AGL_API(void, PixelStorex, (GLenum pname, GLfixed param)) AGL_API(void, PixelTransferxOES, (GLenum pname, GLfixed param)) AGL_API(void, PixelMapx, (GLenum, GLint, const GLfixed *)) AGL_API(void, GetPixelMapxv, (GLenum, GLint, GLfixed *)) AGL_API(void, ConvolutionParameterxOES, (GLenum, GLenum, GLfixed)) AGL_API(void, ConvolutionParameterxvOES, (GLenum, GLenum, const GLfixed *)) AGL_API(void, GetConvolutionParameterxvOES, (GLenum, GLenum, GLfixed *)) AGL_API(void, GetHistogramParameterxvOES, (GLenum, GLenum, GLfixed *)) AGL_API(void, PixelZoomxOES, (GLfixed, GLfixed)) AGL_API(void, BitmapxOES, (GLsizei, GLsizei, GLfixed, GLfixed, GLfixed, GLfixed, const GLubyte *)) AGL_API(void, TexParameterxOES, (GLenum, GLenum, GLfixed)) AGL_API(void, TexParameterxvOES, (GLenum, GLenum, const GLfixed *)) AGL_API(void, GetTexParameterxvOES, (GLenum, GLenum, GLfixed *)) AGL_API(void, GetTexLevelParameterxvOES, (GLenum, GLint, GLenum, GLfixed *)) AGL_API(void, PrioritizeTexturesxOES, (GLsizei, GLuint *, GLclampx *)) AGL_API(void, TexEnvxOES, (GLenum, GLenum, GLfixed)) AGL_API(void, TexEnvxvOES, (GLenum, GLenum, const GLfixed *)) AGL_API(void, GetTexEnvxvOES, (GLenum, GLenum, GLfixed *)) AGL_API(void, FogxOES, (GLenum, GLfixed)) AGL_API(void, FogxvOES, (GLenum, const GLfixed *)) AGL_API(void, SampleCoverageOES, (GLclampx, GLboolean)) AGL_API(void, AlphaFuncxOES, (GLenum, GLclampx)) AGL_API(void, BlendColorxOES, (GLclampx, GLclampx, GLclampx, GLclampx)) AGL_API(void, ClearColorxOES, (GLclampx, GLclampx, GLclampx, GLclampx)) AGL_API(void, ClearDepthxOES, (GLclampx)) AGL_API(void, ClearAccumxOES, (GLclampx, GLclampx, GLclampx, GLclampx)) AGL_API(void, AccumxOES, (GLenum, GLfixed)) AGL_API(void, Map1xOES, (GLenum, GLfixed, GLfixed, GLint, GLint, const GLfixed *)) AGL_API(void, Map2xOES, (GLenum, GLfixed, GLfixed, GLint, GLint, GLfixed, GLfixed, GLint, GLint, const GLfixed *)) AGL_API(void, MapGrid1xOES, (GLint, GLfixed, GLfixed)) AGL_API(void, MapGrid2xOES, (GLint, GLfixed, GLfixed, GLfixed, GLfixed)) AGL_API(void, GetMapxvOES, (GLenum, GLenum, GLfixed *)) AGL_API(void, EvalCoord1xOES, (GLfixed)) AGL_API(void, EvalCoord2xOES, (GLfixed, GLfixed)) AGL_API(void, EvalCoord1xvOES, (const GLfixed *)) AGL_API(void, EvalCoord2xvOES, (const GLfixed *)) AGL_API(void, FeedbackBufferxOES, (GLsizei, GLenum, GLfixed *)) AGL_API(void, PassThroughxOES, (GLfixed)) AGL_API(void, GetFixedvOES, (GLenum, GLfixed *)) #endif #if defined _ALLEGRO_GL_OES_single_precision AGL_API(void, DepthRangefOES, (GLclampf, GLclampf)) AGL_API(void, FrustumfOES, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, OrthofOES, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, ClipPlanefOES, (GLenum, const GLfloat*)) AGL_API(void, GetClipPlanefOES, (GLenum, GLfloat*)) AGL_API(void, ClearDepthfOES, (GLclampd)) #endif #if defined _ALLEGRO_GL_OES_query_matrix AGL_API(GLbitfield, QueryMatrixxOES, (GLfixed [16], GLint [16] )) #endif #if defined _ALLEGRO_GL_EXT_depth_bounds_test AGL_API(void, DepthBoundsEXT, (GLclampd, GLclampd)) #endif #if defined _ALLEGRO_GL_EXT_blend_equation_separate AGL_API(void, BlendEquationSeparateEXT, (GLenum, GLenum)) #endif #if defined _ALLEGRO_GL_EXT_framebuffer_object AGL_API(GLboolean, IsRenderbufferEXT, (GLuint)) AGL_API(void, BindRenderbufferEXT, (GLenum, GLuint)) AGL_API(void, DeleteRenderbuffersEXT, (GLsizei, const GLuint *)) AGL_API(void, GenRenderbuffersEXT, (GLsizei, GLuint *)) AGL_API(void, RenderbufferStorageEXT, (GLenum, GLenum, GLsizei, GLsizei)) AGL_API(void, GetRenderbufferParameterivEXT, (GLenum, GLenum, GLint*)) AGL_API(GLboolean, IsFramebufferEXT, (GLuint)) AGL_API(void, BindFramebufferEXT, (GLenum, GLuint)) AGL_API(void, DeleteFramebuffersEXT, (GLsizei, const GLuint *)) AGL_API(void, GenFramebuffersEXT, (GLsizei, GLuint *)) AGL_API(GLenum, CheckFramebufferStatusEXT, (GLenum)) AGL_API(void, FramebufferTexture1DEXT, (GLenum, GLenum, GLenum, GLuint, GLint)) AGL_API(void, FramebufferTexture2DEXT, (GLenum, GLenum, GLenum, GLuint, GLint)) AGL_API(void, FramebufferTexture3DEXT, (GLenum, GLenum, GLenum, GLuint, GLint, GLint)) AGL_API(void, FramebufferRenderbufferEXT, (GLenum, GLenum, GLenum, GLuint)) AGL_API(void, GetFramebufferAttachmentParameterivEXT, (GLenum, GLenum, GLenum, GLint *)) AGL_API(void, GenerateMipmapEXT, (GLenum)) #endif #if defined _ALLEGRO_GL_GREMEDY_string_marker AGL_API(void, StringMarkerGREMEDY, (GLsizei, const GLvoid *)) #endif #if defined _ALLEGRO_GL_EXT_stencil_clear_tag AGL_API(void, StencilClearTagEXT, (GLsizei, GLuint)) #endif #if defined _ALLEGRO_GL_EXT_framebuffer_blit AGL_API(void, BlitFramebufferEXT, (GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum)) #endif #if defined _ALLEGRO_GL_EXT_framebuffer_multisample AGL_API(void, RenderbufferStorageMultisampleEXT, (GLenum, GLsizei, GLenum, GLsizei, GLsizei)) #endif #if defined _ALLEGRO_GL_EXT_timer_query AGL_API(void, GetQueryObjecti64vEXT, (GLuint, GLenum, GLint64EXT *)) AGL_API(void, GetQueryObjectui64vEXT, (GLuint, GLenum, GLuint64EXT *)) #endif #if defined _ALLEGRO_GL_EXT_gpu_program_parameters AGL_API(void, ProgramEnvParameters4fvEXT, (GLenum, GLuint, GLsizei, const GLfloat *)) AGL_API(void, ProgramLocalParameters4fvEXT, (GLenum, GLuint, GLsizei, const GLfloat *)) #endif #if defined _ALLEGRO_GL_APPLE_flush_buffer_range AGL_API(void, BufferParameteriAPPLE, (GLenum, GLenum, GLint)) AGL_API(void, FlushMappedBufferRangeAPPLE, (GLenum, GLintptr, GLsizeiptr)) #endif #if defined _ALLEGRO_GL_EXT_bindable_uniform AGL_API(void, UniformBufferEXT, (GLuint, GLint, GLuint)) AGL_API(GLint, GetUniformBufferSizeEXT, (GLuint, GLint)) AGL_API(GLintptr, GetUniformOffsetEXT, (GLuint program, GLint)) #endif #if defined _ALLEGRO_GL_EXT_draw_buffers2 AGL_API(void, ColorMaskIndexedEXT, (GLuint, GLboolean, GLboolean, GLboolean, GLboolean)) AGL_API(void, GetBooleanIndexedvEXT, (GLenum, GLuint, GLboolean *)) AGL_API(void, GetIntegerIndexedvEXT, (GLenum, GLuint, GLint *)) AGL_API(void, EnableIndexedEXT, (GLenum, GLuint)) AGL_API(void, DisableIndexedEXT, (GLenum, GLuint)) AGL_API(GLboolean, IsEnabledIndexedEXT, (GLenum, GLuint)) #endif #if defined _ALLEGRO_GL_EXT_draw_instanced AGL_API(void, DrawArraysInstancedEXT, (GLenum, GLint, GLsizei, GLsizei)) AGL_API(void, DrawElementsInstancedEXT, (GLenum, GLsizei, GLenum, const GLvoid *, GLsizei)) #endif #if defined _ALLEGRO_GL_EXT_geometry_shader4 AGL_API(void, ProgramParameteriEXT, (GLuint, GLenum, GLint)) AGL_API(void, FramebufferTextureEXT, (GLenum, GLenum, GLuint, GLint)) #if !defined _ALLEGRO_GL_EXT_texture_array AGL_API(void, FramebufferTextureLayerEXT, (GLenum, GLenum, GLuint, GLint, GLint)) #endif AGL_API(void, FramebufferTextureFaceEXT, (GLenum, GLenum, GLuint, GLint, GLenum)) #endif #if defined _ALLEGRO_GL_EXT_gpu_shader4 AGL_API(void, VertexAttribI1iEXT, (GLuint, GLint)) AGL_API(void, VertexAttribI2iEXT, (GLuint, GLint, GLint)) AGL_API(void, VertexAttribI3iEXT, (GLuint, GLint, GLint, GLint)) AGL_API(void, VertexAttribI4iEXT, (GLuint, GLint, GLint, GLint, GLint)) AGL_API(void, VertexAttribI1uiEXT, (GLuint, GLuint)) AGL_API(void, VertexAttribI2uiEXT, (GLuint, GLuint, GLuint)) AGL_API(void, VertexAttribI3uiEXT, (GLuint, GLuint, GLuint, GLuint)) AGL_API(void, VertexAttribI4uiEXT, (GLuint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, VertexAttribI1ivEXT, (GLuint, const GLint *)) AGL_API(void, VertexAttribI2ivEXT, (GLuint, const GLint *)) AGL_API(void, VertexAttribI3ivEXT, (GLuint, const GLint *)) AGL_API(void, VertexAttribI4ivEXT, (GLuint, const GLint *)) AGL_API(void, VertexAttribI1uivEXT, (GLuint, const GLuint *)) AGL_API(void, VertexAttribI2uivEXT, (GLuint, const GLuint *)) AGL_API(void, VertexAttribI3uivEXT, (GLuint, const GLuint *)) AGL_API(void, VertexAttribI4uivEXT, (GLuint, const GLuint *)) AGL_API(void, VertexAttribI4bvEXT, (GLuint, const GLbyte *)) AGL_API(void, VertexAttribI4svEXT, (GLuint, const GLshort *)) AGL_API(void, VertexAttribI4ubvEXT, (GLuint, const GLubyte *)) AGL_API(void, VertexAttribI4usvEXT, (GLuint, const GLushort *)) AGL_API(void, VertexAttribIPointerEXT, (GLuint, GLint, GLenum, GLsizei, const GLvoid *)) AGL_API(void, GetVertexAttribIivEXT, (GLuint, GLenum, GLint *)) AGL_API(void, GetVertexAttribIuivEXT, (GLuint, GLenum, GLint *)) AGL_API(void, Uniform1uiEXT, (GLint, GLuint)) AGL_API(void, Uniform2uiEXT, (GLint, GLuint, GLuint)) AGL_API(void, Uniform3uiEXT, (GLint, GLuint, GLuint, GLuint)) AGL_API(void, Uniform4uiEXT, (GLint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, Uniform1uivEXT, (GLint, GLsizei, const GLuint *)) AGL_API(void, Uniform2uivEXT, (GLint, GLsizei, const GLuint *)) AGL_API(void, Uniform3uivEXT, (GLint, GLsizei, const GLuint *)) AGL_API(void, Uniform4uivEXT, (GLint, GLsizei, const GLuint *)) AGL_API(void, GetUniformuivEXT, (GLuint, GLint location, GLint *)) AGL_API(void, BindFragDataLocationEXT, (GLuint, GLuint, const GLchar *)) AGL_API(GLint, GetFragDataLocationEXT, (GLuint, const GLchar *)) #endif #if defined _ALLEGRO_GL_EXT_texture_array AGL_API(void, FramebufferTextureLayerEXT, (GLenum, GLenum, GLuint, GLint, GLint)) #endif #if defined _ALLEGRO_GL_EXT_texture_buffer_object AGL_API(void, TexBufferEXT, (GLenum, GLenum, GLuint)) #endif #if defined _ALLEGRO_GL_texture_integer AGL_API(void, ClearColorIiEXT, (GLint, GLint, GLint, GLint)) AGL_API(void, ClearColorIuiEXT, (GLuint, GLuint, GLuint, GLuint)) AGL_API(void, TexParameterIivEXT, (GLenum, GLenum, GLint *)) AGL_API(void, TexParameterIuivEXT, (GLenum, GLenum, GLuint *)) AGL_API(void, GetTexParameterIivEXT, (GLenum, GLenum, GLint *)) AGL_API(void, GetTexParameterIiuvEXT, (GLenum, GLenum, GLuint *)) #endif #if defined _ALLEGRO_GL_NV_depth_buffer_float AGL_API(void, DepthRangedNV, (GLdouble, GLdouble)) AGL_API(void, ClearDepthdNV, (GLdouble)) AGL_API(void, DepthBoundsdNV, (GLdouble, GLdouble)) #endif #if defined _ALLEGRO_GL_NV_framebuffer_multisample_coverage AGL_API(void, RenderbufferStorageMultsampleCoverageNV, (GLenum, GLsizei, GLsizei, GLenum, GLsizei, GLsizei)) #endif #if defined _ALLEGRO_GL_NV_geometry_program4 AGL_API(void, ProgramVertexLimitNV, (GLenum, GLint)) #if !defined _ALLEGRO_GL_EXT_geometry_shader4 AGL_API(void, FramebufferTextureEXT, (GLenum, GLenum, GLuint, GLint)) #if !defined _ALLEGRO_GL_EXT_texture_array AGL_API(void, FramebufferTextureLayerEXT, (GLenum, GLenum, GLuint, GLint, GLint)) #endif #endif #endif #if defined _ALLEGRO_GL_NV_gpu_program4 AGL_API(void, ProgramLocalParameterI4iNV, (GLenum, GLuint, GLint, GLint, GLint, GLint)) AGL_API(void, ProgramLocalParameterI4ivNV, (GLenum, GLuint, const GLint *)) AGL_API(void, ProgramLocalParametersI4ivNV, (GLenum, GLuint, GLsizei, const GLint *)) AGL_API(void, ProgramLocalParameterI4uiNV, (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, ProgramLocalParameterI4uivNV, (GLenum, GLuint, const GLuint *)) AGL_API(void, ProgramLocalParametersI4uivNV, (GLenum, GLuint, GLsizei, const GLuint *)) AGL_API(void, ProgramEnvParameterI4iNV, (GLenum, GLuint, GLint, GLint, GLint, GLint)) AGL_API(void, ProgramEnvParameterI4ivNV, (GLenum, GLuint, const GLint *)) AGL_API(void, ProgramEnvParametersI4ivNV, (GLenum, GLuint, GLsizei, const GLint *)) AGL_API(void, ProgramEnvParameterI4uiNV, (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, ProgramEnvParameterI4uivNV, (GLenum, GLuint, const GLuint *)) AGL_API(void, ProgramEnvParametersI4uivNV, (GLenum, GLuint, GLsizei, const GLuint *)) AGL_API(void, GetProgramLocalParameterIivNV, (GLenum, GLuint, GLint *)) AGL_API(void, GetProgramLocalParameterIuivNV,(GLenum, GLuint, GLuint *)) AGL_API(void, GetProgramEnvParameterIivNV, (GLenum, GLuint, GLint *)) AGL_API(void, GetProgramEnvParameterIuivNV, (GLenum, GLuint, GLuint *)) #endif #if defined _ALLEGRO_GL_NV_parameter_buffer_object #if !defined _ALLEGRO_GL_NV_transform_feedback AGL_API(void, BindBufferRangeNV, (GLenum, GLuint, GLuint, GLintptr, GLsizeiptr)) AGL_API(void, BindBufferOffsetNV,(GLenum, GLuint, GLuint, GLintptr)) AGL_API(void, BindBufferBaseNV, (GLenum, GLuint, GLuint)) #endif AGL_API(void, ProgramBufferParametersfvNV, (GLenum, GLuint, GLuint, GLsizei, const GLfloat *)) AGL_API(void, ProgramBufferParametersIivNV, (GLenum, GLuint, GLuint, GLsizei, const GLint *)) AGL_API(void, ProgramBufferParametersIuivNV,(GLenum, GLuint, GLuint, GLuint, const GLuint *)) #if !defined _ALLEGRO_GL_EXT_draw_buffers2 AGL_API(void, GetIntegerIndexedvEXT, (GLenum, GLuint, GLboolean *)) #endif #endif #if defined _ALLEGRO_GL_NV_transform_feedback AGL_API(void, BindBufferRangeNV, (GLenum, GLuint, GLuint, GLintptr, GLsizeiptr)) AGL_API(void, BindBufferOffsetNV,(GLenum, GLuint, GLuint, GLintptr)) AGL_API(void, BindBufferBaseNV, (GLenum, GLuint, GLuint)) AGL_API(void, TransformFeedbackAttribsNV, (GLsizei, const GLint *, GLenum)) AGL_API(void, TransformFeedbackVaryingsNV,(GLuint, GLsizei, const GLint *, GLenum)) AGL_API(void, BeginTransformFeedbackNV, (GLenum)) AGL_API(void, EndTransformFeedbackNV, (void)) AGL_API(GLint, GetVaryingLocationNV, (GLuint, const GLchar *)) AGL_API(void, GetActiveVaryingNV, (GLuint, GLuint, GLsizei, GLsizei *, GLsizei *, GLenum *, GLchar *)) AGL_API(void, ActiveVaryingNV, (GLuint, const GLchar *)) AGL_API(void, GetTransformFeedbackVaryingNV, (GLuint, GLuint, GLint *)) #if !defined _ALLEGRO_GL_EXT_draw_buffers2 AGL_API(void, GetBooleanIndexedvEXT, (GLenum, GLuint, GLboolean *)) /*AGL_API(void, GetIntegerIndexedvEXT, (GLenum, GLuint, GLint *))*/ #endif #endif #if defined _ALLEGRO_GL_NV_vertex_program4 #ifndef _ALLEGRO_GL_EXT_gpu_shader4 AGL_API(void, VertexAttribI1iEXT, (GLuint, GLint)) AGL_API(void, VertexAttribI2iEXT, (GLuint, GLint, GLint)) AGL_API(void, VertexAttribI3iEXT, (GLuint, GLint, GLint, GLint)) AGL_API(void, VertexAttribI4iEXT, (GLuint, GLint, GLint, GLint, GLint)) AGL_API(void, VertexAttribI1uiEXT, (GLuint, GLuint)) AGL_API(void, VertexAttribI2uiEXT, (GLuint, GLuint, GLuint)) AGL_API(void, VertexAttribI3uiEXT, (GLuint, GLuint, GLuint, GLuint)) AGL_API(void, VertexAttribI4uiEXT, (GLuint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, VertexAttribI1ivEXT, (GLuint, const GLint *)) AGL_API(void, VertexAttribI2ivEXT, (GLuint, const GLint *)) AGL_API(void, VertexAttribI3ivEXT, (GLuint, const GLint *)) AGL_API(void, VertexAttribI4ivEXT, (GLuint, const GLint *)) AGL_API(void, VertexAttribI1uivEXT, (GLuint, const GLuint *)) AGL_API(void, VertexAttribI2uivEXT, (GLuint, const GLuint *)) AGL_API(void, VertexAttribI3uivEXT, (GLuint, const GLuint *)) AGL_API(void, VertexAttribI4uivEXT, (GLuint, const GLuint *)) AGL_API(void, VertexAttribI4bvEXT, (GLuint, const GLbyte *)) AGL_API(void, VertexAttribI4svEXT, (GLuint, const GLshort *)) AGL_API(void, VertexAttribI4ubvEXT, (GLuint, const GLubyte *)) AGL_API(void, VertexAttribI4usvEXT, (GLuint, const GLushort *)) AGL_API(void, VertexAttribIPointerEXT, (GLuint, GLint, GLenum, GLsizei, const GLvoid *)) AGL_API(void, GetVertexAttribIivEXT, (GLuint, GLenum, GLint *)) AGL_API(void, GetVertexAttribIuivEXT, (GLuint, GLenum, GLint *)) #endif #endif #if defined _ALLEGRO_GL_GREMEDY_frame_terminator AGL_API(void, FrameTerminatorGREMEDY, (void)) #endif #if defined _ALLEGRO_GL_NV_conditional_render AGL_API(void, BeginConditionalRenderNV, (GLuint, GLenum)) AGL_API(void, EndConditionalRenderNV, (void)) #endif #if defined _ALLEGRO_GL_EXT_transform_feedback AGL_API(void, BeginTransformFeedbackEXT, (GLenum)) AGL_API(void, EndTransformFeedbackEXT, (void)) AGL_API(void, BindBufferRangeEXT, (GLenum, GLuint, GLuint, GLintptr, GLsizeiptr)) AGL_API(void, BindBufferOffsetEXT, (GLenum, GLuint, GLuint, GLintptr)) AGL_API(void, BindBufferBaseEXT, (GLenum, GLuint, GLuint)) AGL_API(void, TransformFeedbackVaryingsEXT, (GLuint, GLsizei, const GLint *, GLenum)) AGL_API(void, GetTransformFeedbackVaryingEXT, (GLuint, GLuint, GLint *)) #endif #if defined _ALLEGRO_GL_EXT_direct_state_access AGL_API(void, ClientAttribDefaultEXT, (GLbitfield)) AGL_API(void, PushClientAttribDefaultEXT, (GLbitfield)) AGL_API(void, MatrixLoadfEXT, (GLenum, const GLfloat *)) AGL_API(void, MatrixLoaddEXT, (GLenum, const GLdouble *)) AGL_API(void, MatrixMultfEXT, (GLenum, const GLfloat *)) AGL_API(void, MatrixMultdEXT, (GLenum, const GLdouble *)) AGL_API(void, MatrixLoadIdentityEXT, (GLenum)) AGL_API(void, MatrixRotatefEXT, (GLenum, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, MatrixRotatedEXT, (GLenum, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, MatrixScalefEXT, (GLenum, GLfloat, GLfloat, GLfloat)) AGL_API(void, MatrixScaledEXT, (GLenum, GLdouble, GLdouble, GLdouble)) AGL_API(void, MatrixTranslatefEXT, (GLenum, GLfloat, GLfloat, GLfloat)) AGL_API(void, MatrixTranslatedEXT, (GLenum, GLdouble, GLdouble, GLdouble)) AGL_API(void, MatrixFrustumEXT, (GLenum, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, MatrixOrthoEXT, (GLenum, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, MatrixPopEXT, (GLenum)) AGL_API(void, MatrixPushEXT, (GLenum)) AGL_API(void, MatrixLoadTransposefEXT, (GLenum, const GLfloat *)) AGL_API(void, MatrixLoadTransposedEXT, (GLenum, const GLdouble *)) AGL_API(void, MatrixMultTransposefEXT, (GLenum, const GLfloat *)) AGL_API(void, MatrixMultTransposedEXT, (GLenum, const GLdouble *)) AGL_API(void, TextureParameterfEXT, (GLuint, GLenum, GLenum, GLfloat)) AGL_API(void, TextureParameterfvEXT, (GLuint, GLenum, GLenum, const GLfloat *)) AGL_API(void, TextureParameteriEXT, (GLuint, GLenum, GLenum, GLint)) AGL_API(void, TextureParameterivEXT, (GLuint, GLenum, GLenum, const GLint *)) AGL_API(void, TextureImage1DEXT, (GLuint, GLenum, GLint, GLenum, GLsizei, GLint, GLenum, GLenum, const GLvoid *)) AGL_API(void, TextureImage2DEXT, (GLuint, GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *)) AGL_API(void, TextureSubImage1DEXT, (GLuint, GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, TextureSubImage2DEXT, (GLuint, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, CopyTextureImage1DEXT, (GLuint, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint)) AGL_API(void, CopyTextureImage2DEXT, (GLuint, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint)) AGL_API(void, CopyTextureSubImage1DEXT, (GLuint, GLenum, GLint, GLint, GLint, GLint, GLsizei)) AGL_API(void, CopyTextureSubImage2DEXT, (GLuint, GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)) AGL_API(void, GetTextureImageEXT, (GLuint, GLenum, GLint, GLenum, GLenum, GLvoid *)) AGL_API(void, GetTextureParameterfvEXT, (GLuint, GLenum, GLenum, GLfloat *)) AGL_API(void, GetTextureParameterivEXT, (GLuint, GLenum, GLenum, GLint *)) AGL_API(void, GetTextureLevelParameterfvEXT, (GLuint, GLenum, GLint, GLenum, GLfloat *)) AGL_API(void, GetTextureLevelParameterivEXT, (GLuint, GLenum, GLint, GLenum, GLint *)) AGL_API(void, TextureImage3DEXT, (GLuint, GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *)) AGL_API(void, TextureSubImage3DEXT, (GLuint, GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, CopyTextureSubImage3DEXT, (GLuint, GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)) AGL_API(void, MultiTexParameterfEXT, (GLenum, GLenum, GLenum, GLfloat)) AGL_API(void, MultiTexParameterfvEXT, (GLenum, GLenum, GLenum, const GLfloat *)) AGL_API(void, MultiTexParameteriEXT, (GLenum, GLenum, GLenum, GLint)) AGL_API(void, MultiTexParameterivEXT, (GLenum, GLenum, GLenum, const GLint *)) AGL_API(void, MultiTexImage1DEXT, (GLenum, GLenum, GLint, GLenum, GLsizei, GLint, GLenum, GLenum, const GLvoid *)) AGL_API(void, MultiTexImage2DEXT, (GLenum, GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *)) AGL_API(void, MultiTexSubImage1DEXT, (GLenum, GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, MultiTexSubImage2DEXT, (GLenum, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, CopyMultiTexImage1DEXT, (GLenum, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint)) AGL_API(void, CopyMultiTexImage2DEXT, (GLenum, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint)) AGL_API(void, CopyMultiTexSubImage1DEXT, (GLenum, GLenum, GLint, GLint, GLint, GLint, GLsizei)) AGL_API(void, CopyMultiTexSubImage2DEXT, (GLenum, GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)) AGL_API(void, GetMultiTexImageEXT, (GLenum, GLenum, GLint, GLenum, GLenum, GLvoid *)) AGL_API(void, GetMultiTexParameterfvEXT, (GLenum, GLenum, GLenum, GLfloat *)) AGL_API(void, GetMultiTexParameterivEXT, (GLenum, GLenum, GLenum, GLint *)) AGL_API(void, GetMultiTexLevelParameterfvEXT, (GLenum, GLenum, GLint, GLenum, GLfloat *)) AGL_API(void, GetMultiTexLevelParameterivEXT, (GLenum, GLenum, GLint, GLenum, GLint *)) AGL_API(void, MultiTexImage3DEXT, (GLenum, GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *)) AGL_API(void, MultiTexSubImage3DEXT, (GLenum, GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) AGL_API(void, CopyMultiTexSubImage3DEXT, (GLenum, GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)) AGL_API(void, BindMultiTextureEXT, (GLenum, GLenum, GLuint)) AGL_API(void, EnableClientStateIndexedEXT, (GLenum, GLuint)) AGL_API(void, DisableClientStateIndexedEXT, (GLenum, GLuint)) AGL_API(void, MultiTexCoordPointerEXT, (GLenum, GLint, GLenum, GLsizei, const GLvoid *)) AGL_API(void, MultiTexEnvfEXT, (GLenum, GLenum, GLenum, GLfloat)) AGL_API(void, MultiTexEnvfvEXT, (GLenum, GLenum, GLenum, const GLfloat *)) AGL_API(void, MultiTexEnviEXT, (GLenum, GLenum, GLenum, GLint)) AGL_API(void, MultiTexEnvivEXT, (GLenum, GLenum, GLenum, const GLint *)) AGL_API(void, MultiTexGendEXT, (GLenum, GLenum, GLenum, GLdouble)) AGL_API(void, MultiTexGendvEXT, (GLenum, GLenum, GLenum, const GLdouble *)) AGL_API(void, MultiTexGenfEXT, (GLenum, GLenum, GLenum, GLfloat)) AGL_API(void, MultiTexGenfvEXT, (GLenum, GLenum, GLenum, const GLfloat *)) AGL_API(void, MultiTexGeniEXT, (GLenum, GLenum, GLenum, GLint)) AGL_API(void, MultiTexGenivEXT, (GLenum, GLenum, GLenum, const GLint *)) AGL_API(void, GetMultiTexEnvfvEXT, (GLenum, GLenum, GLenum, GLfloat *)) AGL_API(void, GetMultiTexEnvivEXT, (GLenum, GLenum, GLenum, GLint *)) AGL_API(void, GetMultiTexGendvEXT, (GLenum, GLenum, GLenum, GLdouble *)) AGL_API(void, GetMultiTexGenfvEXT, (GLenum, GLenum, GLenum, GLfloat *)) AGL_API(void, GetMultiTexGenivEXT, (GLenum, GLenum, GLenum, GLint *)) AGL_API(void, GetFloatIndexedvEXT, (GLenum, GLuint, GLfloat *)) AGL_API(void, GetDoubleIndexedvEXT, (GLenum, GLuint, GLdouble *)) AGL_API(void, GetPointerIndexedvEXT, (GLenum, GLuint, GLvoid* *)) AGL_API(void, CompressedTextureImage3DEXT, (GLuint, GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *)) AGL_API(void, CompressedTextureImage2DEXT, (GLuint, GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *)) AGL_API(void, CompressedTextureImage1DEXT, (GLuint, GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *)) AGL_API(void, CompressedTextureSubImage3DEXT, (GLuint, GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *)) AGL_API(void, CompressedTextureSubImage2DEXT, (GLuint, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *)) AGL_API(void, CompressedTextureSubImage1DEXT, (GLuint, GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *)) AGL_API(void, GetCompressedTextureImageEXT, (GLuint, GLenum, GLint, GLvoid *)) AGL_API(void, CompressedMultiTexImage3DEXT, (GLenum, GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *)) AGL_API(void, CompressedMultiTexImage2DEXT, (GLenum, GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *)) AGL_API(void, CompressedMultiTexImage1DEXT, (GLenum, GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *)) AGL_API(void, CompressedMultiTexSubImage3DEXT, (GLenum, GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *)) AGL_API(void, CompressedMultiTexSubImage2DEXT, (GLenum, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *)) AGL_API(void, CompressedMultiTexSubImage1DEXT, (GLenum, GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *)) AGL_API(void, GetCompressedMultiTexImageEXT, (GLenum, GLenum, GLint, GLvoid *)) AGL_API(void, NamedProgramStringEXT, (GLuint, GLenum, GLenum, GLsizei, const GLvoid *)) AGL_API(void, NamedProgramLocalParameter4dEXT, (GLuint, GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble)) AGL_API(void, NamedProgramLocalParameter4dvEXT, (GLuint, GLenum, GLuint, const GLdouble *)) AGL_API(void, NamedProgramLocalParameter4fEXT, (GLuint, GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, NamedProgramLocalParameter4fvEXT, (GLuint, GLenum, GLuint, const GLfloat *)) AGL_API(void, GetNamedProgramLocalParameterdvEXT, (GLuint, GLenum, GLuint, GLdouble *)) AGL_API(void, GetNamedProgramLocalParameterfvEXT, (GLuint, GLenum, GLuint, GLfloat *)) AGL_API(void, GetNamedProgramivEXT, (GLuint, GLenum, GLenum, GLint *)) AGL_API(void, GetNamedProgramStringEXT, (GLuint, GLenum, GLenum, GLvoid *)) AGL_API(void, NamedProgramLocalParameters4fvEXT, (GLuint, GLenum, GLuint, GLsizei, const GLfloat *)) AGL_API(void, NamedProgramLocalParameterI4iEXT, (GLuint, GLenum, GLuint, GLint, GLint, GLint, GLint)) AGL_API(void, NamedProgramLocalParameterI4ivEXT, (GLuint, GLenum, GLuint, const GLint *)) AGL_API(void, NamedProgramLocalParametersI4ivEXT, (GLuint, GLenum, GLuint, GLsizei, const GLint *)) AGL_API(void, NamedProgramLocalParameterI4uiEXT, (GLuint, GLenum, GLuint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, NamedProgramLocalParameterI4uivEXT, (GLuint, GLenum, GLuint, const GLuint *)) AGL_API(void, NamedProgramLocalParametersI4uivEXT, (GLuint, GLenum, GLuint, GLsizei, const GLuint *)) AGL_API(void, GetNamedProgramLocalParameterIivEXT, (GLuint, GLenum, GLuint, GLint *)) AGL_API(void, GetNamedProgramLocalParameterIuivEXT, (GLuint, GLenum, GLuint, GLuint *)) AGL_API(void, TextureParameterIivEXT, (GLuint, GLenum, GLenum, const GLint *)) AGL_API(void, TextureParameterIuivEXT, (GLuint, GLenum, GLenum, const GLuint *)) AGL_API(void, GetTextureParameterIivEXT, (GLuint, GLenum, GLenum, GLint *)) AGL_API(void, GetTextureParameterIuivEXT, (GLuint, GLenum, GLenum, GLuint *)) AGL_API(void, MultiTexParameterIivEXT, (GLenum, GLenum, GLenum, const GLint *)) AGL_API(void, MultiTexParameterIuivEXT, (GLenum, GLenum, GLenum, const GLuint *)) AGL_API(void, GetMultiTexParameterIivEXT, (GLenum, GLenum, GLenum, GLint *)) AGL_API(void, GetMultiTexParameterIuivEXT, (GLenum, GLenum, GLenum, GLuint *)) AGL_API(void, ProgramUniform1fEXT, (GLuint, GLint, GLfloat)) AGL_API(void, ProgramUniform2fEXT, (GLuint, GLint, GLfloat, GLfloat)) AGL_API(void, ProgramUniform3fEXT, (GLuint, GLint, GLfloat, GLfloat, GLfloat)) AGL_API(void, ProgramUniform4fEXT, (GLuint, GLint, GLfloat, GLfloat, GLfloat, GLfloat)) AGL_API(void, ProgramUniform1iEXT, (GLuint, GLint, GLint)) AGL_API(void, ProgramUniform2iEXT, (GLuint, GLint, GLint, GLint)) AGL_API(void, ProgramUniform3iEXT, (GLuint, GLint, GLint, GLint, GLint)) AGL_API(void, ProgramUniform4iEXT, (GLuint, GLint, GLint, GLint, GLint, GLint)) AGL_API(void, ProgramUniform1fvEXT, (GLuint, GLint, GLsizei, const GLfloat *)) AGL_API(void, ProgramUniform2fvEXT, (GLuint, GLint, GLsizei, const GLfloat *)) AGL_API(void, ProgramUniform3fvEXT, (GLuint, GLint, GLsizei, const GLfloat *)) AGL_API(void, ProgramUniform4fvEXT, (GLuint, GLint, GLsizei, const GLfloat *)) AGL_API(void, ProgramUniform1ivEXT, (GLuint, GLint, GLsizei, const GLint *)) AGL_API(void, ProgramUniform2ivEXT, (GLuint, GLint, GLsizei, const GLint *)) AGL_API(void, ProgramUniform3ivEXT, (GLuint, GLint, GLsizei, const GLint *)) AGL_API(void, ProgramUniform4ivEXT, (GLuint, GLint, GLsizei, const GLint *)) AGL_API(void, ProgramUniformMatrix2fvEXT, (GLuint, GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, ProgramUniformMatrix3fvEXT, (GLuint, GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, ProgramUniformMatrix4fvEXT, (GLuint, GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, ProgramUniformMatrix2x3fvEXT, (GLuint, GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, ProgramUniformMatrix3x2fvEXT, (GLuint, GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, ProgramUniformMatrix2x4fvEXT, (GLuint, GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, ProgramUniformMatrix4x2fvEXT, (GLuint, GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, ProgramUniformMatrix3x4fvEXT, (GLuint, GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, ProgramUniformMatrix4x3fvEXT, (GLuint, GLint, GLsizei, GLboolean, const GLfloat *)) AGL_API(void, ProgramUniform1uiEXT, (GLuint, GLint, GLuint)) AGL_API(void, ProgramUniform2uiEXT, (GLuint, GLint, GLuint, GLuint)) AGL_API(void, ProgramUniform3uiEXT, (GLuint, GLint, GLuint, GLuint, GLuint)) AGL_API(void, ProgramUniform4uiEXT, (GLuint, GLint, GLuint, GLuint, GLuint, GLuint)) AGL_API(void, ProgramUniform1uivEXT, (GLuint, GLint, GLsizei, const GLuint *)) AGL_API(void, ProgramUniform2uivEXT, (GLuint, GLint, GLsizei, const GLuint *)) AGL_API(void, ProgramUniform3uivEXT, (GLuint, GLint, GLsizei, const GLuint *)) AGL_API(void, ProgramUniform4uivEXT, (GLuint, GLint, GLsizei, const GLuint *)) AGL_API(void, NamedBufferDataEXT, (GLuint, GLsizeiptr, const GLvoid *, GLenum)) AGL_API(void, NamedBufferSubDataEXT, (GLuint, GLintptr, GLsizeiptr, const GLvoid *)) AGL_API(GLvoid*, MapNamedBufferEXT, (GLuint, GLenum)) AGL_API(GLboolean, UnmapNamedBufferEXT, (GLuint)) AGL_API(void, GetNamedBufferParameterivEXT, (GLuint, GLenum, GLint *)) AGL_API(void, GetNamedBufferPointervEXT, (GLuint, GLenum, GLvoid* *)) AGL_API(void, GetNamedBufferSubDataEXT, (GLuint, GLintptr, GLsizeiptr, GLvoid *)) AGL_API(void, TextureBufferEXT, (GLuint, GLenum, GLenum, GLuint)) AGL_API(void, MultiTexBufferEXT, (GLenum, GLenum, GLenum, GLuint)) AGL_API(void, NamedRenderbufferStorageEXT, (GLuint, GLenum, GLsizei, GLsizei)) AGL_API(void, GetNamedRenderbufferParameterivEXT, (GLuint, GLenum, GLint *)) AGL_API(GLenum, CheckNamedFramebufferStatusEXT, (GLuint, GLenum)) AGL_API(void, NamedFramebufferTexture1DEXT, (GLuint, GLenum, GLenum, GLuint, GLint)) AGL_API(void, NamedFramebufferTexture2DEXT, (GLuint, GLenum, GLenum, GLuint, GLint)) AGL_API(void, NamedFramebufferTexture3DEXT, (GLuint, GLenum, GLenum, GLuint, GLint, GLint)) AGL_API(void, NamedFramebufferRenderbufferEXT, (GLuint, GLenum, GLenum, GLuint)) AGL_API(void, GetNamedFramebufferAttachmentParameterivEXT, (GLuint, GLenum, GLenum, GLint *)) AGL_API(void, GenerateTextureMipmapEXT, (GLuint, GLenum)) AGL_API(void, GenerateMultiTexMipmapEXT, (GLenum, GLenum)) AGL_API(void, FramebufferDrawBufferEXT, (GLuint, GLenum)) AGL_API(void, FramebufferDrawBuffersEXT, (GLuint, GLsizei, const GLenum *)) AGL_API(void, FramebufferReadBufferEXT, (GLuint, GLenum)) AGL_API(void, GetFramebufferParameterivEXT, (GLuint, GLenum, GLint *)) AGL_API(void, NamedRenderbufferStorageMultisampleEXT, (GLuint, GLsizei, GLenum, GLsizei, GLsizei)) AGL_API(void, NamedRenderbufferStorageMultisampleCoverageEXT, (GLuint, GLsizei, GLsizei, GLenum, GLsizei, GLsizei)) AGL_API(void, NamedFramebufferTextureEXT, (GLuint, GLenum, GLuint, GLint)) AGL_API(void, NamedFramebufferTextureLayerEXT, (GLuint, GLenum, GLuint, GLint, GLint)) AGL_API(void, NamedFramebufferTextureFaceEXT, (GLuint, GLenum, GLuint, GLint, GLenum)) AGL_API(void, TextureRenderbufferEXT, (GLuint, GLenum, GLuint)) AGL_API(void, MultiTexRenderbufferEXT, (GLenum, GLenum, GLuint)) #endif #if defined _ALLEGRO_GL_NV_explicit_multisample AGL_API(void, GetMultisamplefvNV, (GLenum, GLuint, GLfloat *)) AGL_API(void, SampleMaskIndexedNV, (GLuint, GLbitfield)) AGL_API(void, TexRenderbufferNV, (GLenum, GLuint)) #endif #if defined _ALLEGRO_GL_NV_transform_feedback2 AGL_API(void, BindTransformFeedbackNV, (GLenum, GLuint)) AGL_API(void, DeleteTransformFeedbacksNV, (GLsizei, const GLuint *)) AGL_API(void, GenTransformFeedbacksNV, (GLsizei, GLuint *)) AGL_API(GLboolean, IsTransformFeedbackNV, (GLuint)) AGL_API(void, PauseTransformFeedbackNV, (void)) AGL_API(void, ResumeTransformFeedbackNV, (void)) AGL_API(void, DrawTransformFeedbackNV, (GLenum, GLuint)) #endif #if defined _ALLEGRO_GL_AMD_performance_monitor AGL_API(void, GetPerfMonitorGroupsAMD, (GLint *, GLsizei, GLuint *)) AGL_API(void, GetPerfMonitorCountersAMD, (GLuint, GLint *, GLint *, GLsizei, GLuint *)) AGL_API(void, GetPerfMonitorGroupStringAMD, (GLuint, GLsizei, GLsizei *, GLchar *)) AGL_API(void, GetPerfMonitorCounterStringAMD, (GLuint, GLuint, GLsizei, GLsizei *, GLchar *)) AGL_API(void, GetPerfMonitorCounterInfoAMD, (GLuint, GLuint, GLenum, void *)) AGL_API(void, GenPerfMonitorsAMD, (GLsizei, GLuint *)) AGL_API(void, DeletePerfMonitorsAMD, (GLsizei, GLuint *)) AGL_API(void, SelectPerfMonitorCountersAMD, (GLuint, GLboolean, GLuint, GLint, GLuint *)) AGL_API(void, BeginPerfMonitorAMD, (GLuint)) AGL_API(void, EndPerfMonitorAMD, (GLuint)) AGL_API(void, GetPerfMonitorCounterDataAMD, (GLuint, GLenum, GLsizei, GLuint *, GLint *)) #endif #if defined _ALLEGRO_GL_AMD_vertex_shader_tesselator AGL_API(void, TessellationFactorAMD, (GLfloat)) AGL_API(void, TessellationModeAMD, (GLenum)) #endif #if defined _ALLEGRO_GL_EXT_provoking_vertex AGL_API(void, ProvokingVertexEXT, (GLenum)) #endif #if defined _ALLEGRO_GL_AMD_draw_buffers_blend AGL_API(void, BlendFuncIndexedAMD, (GLuint buf, GLenum src, GLenum dst)) AGL_API(void, BlendFuncSeparateIndexedAMD, (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)) AGL_API(void, BlendEquationIndexedAMD, (GLuint buf, GLenum mode)) AGL_API(void, BlendEquationSeparateIndexedAMD, (GLuint buf, GLenum modeRGB, GLenum modeAlpha)) #endif #if defined _ALLEGRO_GL_APPLE_texture_range AGL_API(void, TextureRangeAPPLE, (GLenum target, GLsizei length, const GLvoid *pointer)) AGL_API(void, GetTexParameterPointervAPPLE, (GLenum target, GLenum pname, GLvoid* *params)) #endif #if defined _ALLEGRO_GL_APPLE_vertex_program_evaluators AGL_API(void, EnableVertexAttribAPPLE, (GLuint index, GLenum pname)) AGL_API(void, DisableVertexAttribAPPLE, (GLuint index, GLenum pname)) AGL_API(GLboolean, IsVertexAttribEnabledAPPLE, (GLuint index, GLenum pname)) AGL_API(void, MapVertexAttrib1dAPPLE, (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points)) AGL_API(void, MapVertexAttrib1fAPPLE, (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points)) AGL_API(void, MapVertexAttrib2dAPPLE, (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points)) AGL_API(void, MapVertexAttrib2fAPPLE, (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points)) #endif #if defined _ALLEGRO_GL_APPLE_object_purgeable AGL_API(GLenum, ObjectPurgeableAPPLE, (GLenum objectType, GLuint name, GLenum option)) AGL_API(GLenum, ObjectUnpurgeableAPPLE, (GLenum objectType, GLuint name, GLenum option)) AGL_API(void, GetObjectParameterivAPPLE, (GLenum objectType, GLuint name, GLenum pname, GLint *params)) #endif #if defined _ALLEGRO_GL_NV_video_capture AGL_API(void, BeginVideoCaptureNV, (GLuint video_capture_slot)) AGL_API(void, BindVideoCaptureStreamBufferNV, (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset)) AGL_API(void, BindVideoCaptureStreamTextureNV, (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture)) AGL_API(void, EndVideoCaptureNV, (GLuint video_capture_slot)) AGL_API(void, GetVideoCaptureivNV, (GLuint video_capture_slot, GLenum pname, GLint *params)) AGL_API(void, GetVideoCaptureStreamivNV, (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params)) AGL_API(void, GetVideoCaptureStreamfvNV, (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params)) AGL_API(void, GetVideoCaptureStreamdvNV, (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params)) AGL_API(GLenum, VideoCaptureNV, (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time)) AGL_API(void, VideoCaptureStreamParameterivNV, (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params)) AGL_API(void, VideoCaptureStreamParameterfvNV, (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params)) AGL_API(void, VideoCaptureStreamParameterdvNV, (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params)) #endif #if defined _ALLEGRO_GL_EXT_separate_shader_objects AGL_API(void, UseShaderProgramEXT, (GLenum type, GLuint program)) AGL_API(void, ActiveProgramEXT, (GLuint program)) AGL_API(GLuint, CreateShaderProgramEXT, (GLenum type, const GLchar *string)) #endif #if defined _ALLEGRO_GL_NV_shader_buffer_load AGL_API(void, MakeBufferResidentNV, (GLenum target, GLenum access)) AGL_API(void, MakeBufferNonResidentNV, (GLenum target)) AGL_API(GLboolean, IsBufferResidentNV, (GLenum target)) AGL_API(void, MakeNamedBufferResidentNV, (GLuint buffer, GLenum access)) AGL_API(void, MakeNamedBufferNonResidentNV, (GLuint buffer)) AGL_API(GLboolean, IsNamedBufferResidentNV, (GLuint buffer)) AGL_API(void, GetBufferParameterui64vNV, (GLenum target, GLenum pname, GLuint64EXT *params)) AGL_API(void, GetNamedBufferParameterui64vNV, (GLuint buffer, GLenum pname, GLuint64EXT *params)) AGL_API(void, GetIntegerui64vNV, (GLenum value, GLuint64EXT *result)) AGL_API(void, Uniformui64NV, (GLint location, GLuint64EXT value)) AGL_API(void, Uniformui64vNV, (GLint location, GLsizei count, const GLuint64EXT *value)) AGL_API(void, GetUniformui64vNV, (GLuint program, GLint location, GLuint64EXT *params)) AGL_API(void, ProgramUniformui64NV, (GLuint program, GLint location, GLuint64EXT value)) AGL_API(void, ProgramUniformui64vNV, (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value)) #endif #if defined _ALLEGRO_GL_NV_vertex_buffer_unified_memory AGL_API(void, BufferAddressRangeNV, (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length)) AGL_API(void, VertexFormatNV, (GLint size, GLenum type, GLsizei stride)) AGL_API(void, NormalFormatNV, (GLenum type, GLsizei stride)) AGL_API(void, ColorFormatNV, (GLint size, GLenum type, GLsizei stride)) AGL_API(void, IndexFormatNV, (GLenum type, GLsizei stride)) AGL_API(void, TexCoordFormatNV, (GLint size, GLenum type, GLsizei stride)) AGL_API(void, EdgeFlagFormatNV, (GLsizei stride)) AGL_API(void, SecondaryColorFormatNV, (GLint size, GLenum type, GLsizei stride)) AGL_API(void, FogCoordFormatNV, (GLenum type, GLsizei stride)) AGL_API(void, VertexAttribFormatNV, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride)) AGL_API(void, VertexAttribIFormatNV, (GLuint index, GLint size, GLenum type, GLsizei stride)) AGL_API(void, GetIntegerui64i_vNV, (GLenum value, GLuint index, GLuint64EXT *result)) #endif #if defined _ALLEGRO_GL_NV_texture_barrier AGL_API(void, TextureBarrierNV, (void)) #endif allegro5-5.2.10.1/include/allegro5/opengl/GLext/gl_ext_defs.h000066400000000000000000006616211473414355200235740ustar00rootroot00000000000000/* */ #if (defined _MSC_VER) && (_MSC_VER < 1400) typedef __int64 GLint64; typedef unsigned __int64 GLuint64; #else typedef int64_t GLint64; typedef uint64_t GLuint64; #endif #ifndef GL_VERSION_1_2 #define GL_VERSION_1_2 1 #define _ALLEGRO_GL_VERSION_1_2 #define GL_UNSIGNED_BYTE_3_3_2 0x8032 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_INT_8_8_8_8 0x8035 #define GL_UNSIGNED_INT_10_10_10_2 0x8036 #define GL_RESCALE_NORMAL 0x803A #define GL_TEXTURE_BINDING_3D 0x806A #define GL_PACK_SKIP_IMAGES 0x806B #define GL_PACK_IMAGE_HEIGHT 0x806C #define GL_UNPACK_SKIP_IMAGES 0x806D #define GL_UNPACK_IMAGE_HEIGHT 0x806E #define GL_TEXTURE_3D 0x806F #define GL_PROXY_TEXTURE_3D 0x8070 #define GL_TEXTURE_DEPTH 0x8071 #define GL_TEXTURE_WRAP_R 0x8072 #define GL_MAX_3D_TEXTURE_SIZE 0x8073 #define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 #define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 #define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_BGR 0x80E0 #define GL_BGRA 0x80E1 #define GL_MAX_ELEMENTS_VERTICES 0x80E8 #define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_CLAMP_TO_EDGE 0x812F #define GL_TEXTURE_MIN_LOD 0x813A #define GL_TEXTURE_MAX_LOD 0x813B #define GL_TEXTURE_BASE_LEVEL 0x813C #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 #define GL_SINGLE_COLOR 0x81F9 #define GL_SEPARATE_SPECULAR_COLOR 0x81FA #define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 #define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 #define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 #define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #endif #ifndef GL_ARB_imaging #define GL_ARB_imaging #define _ALLEGRO_GL_ARB_imaging #define GL_CONSTANT_COLOR 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_CONSTANT_ALPHA 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_BLEND_COLOR 0x8005 #define GL_FUNC_ADD 0x8006 #define GL_MIN 0x8007 #define GL_MAX 0x8008 #define GL_BLEND_EQUATION 0x8009 #define GL_FUNC_SUBTRACT 0x800A #define GL_FUNC_REVERSE_SUBTRACT 0x800B #define GL_CONVOLUTION_1D 0x8010 #define GL_CONVOLUTION_2D 0x8011 #define GL_SEPARABLE_2D 0x8012 #define GL_CONVOLUTION_BORDER_MODE 0x8013 #define GL_CONVOLUTION_FILTER_SCALE 0x8014 #define GL_CONVOLUTION_FILTER_BIAS 0x8015 #define GL_REDUCE 0x8016 #define GL_CONVOLUTION_FORMAT 0x8017 #define GL_CONVOLUTION_WIDTH 0x8018 #define GL_CONVOLUTION_HEIGHT 0x8019 #define GL_MAX_CONVOLUTION_WIDTH 0x801A #define GL_MAX_CONVOLUTION_HEIGHT 0x801B #define GL_POST_CONVOLUTION_RED_SCALE 0x801C #define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D #define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E #define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F #define GL_POST_CONVOLUTION_RED_BIAS 0x8020 #define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 #define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 #define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 #define GL_HISTOGRAM 0x8024 #define GL_PROXY_HISTOGRAM 0x8025 #define GL_HISTOGRAM_WIDTH 0x8026 #define GL_HISTOGRAM_FORMAT 0x8027 #define GL_HISTOGRAM_RED_SIZE 0x8028 #define GL_HISTOGRAM_GREEN_SIZE 0x8029 #define GL_HISTOGRAM_BLUE_SIZE 0x802A #define GL_HISTOGRAM_ALPHA_SIZE 0x802B #define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C #define GL_HISTOGRAM_SINK 0x802D #define GL_MINMAX 0x802E #define GL_MINMAX_FORMAT 0x802F #define GL_MINMAX_SINK 0x8030 #define GL_TABLE_TOO_LARGE 0x8031 #define GL_COLOR_MATRIX 0x80B1 #define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 #define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 #define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 #define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 #define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 #define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 #define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 #define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 #define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA #define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB #define GL_COLOR_TABLE 0x80D0 #define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 #define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 #define GL_PROXY_COLOR_TABLE 0x80D3 #define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 #define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 #define GL_COLOR_TABLE_SCALE 0x80D6 #define GL_COLOR_TABLE_BIAS 0x80D7 #define GL_COLOR_TABLE_FORMAT 0x80D8 #define GL_COLOR_TABLE_WIDTH 0x80D9 #define GL_COLOR_TABLE_RED_SIZE 0x80DA #define GL_COLOR_TABLE_GREEN_SIZE 0x80DB #define GL_COLOR_TABLE_BLUE_SIZE 0x80DC #define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD #define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE #define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF #define GL_CONSTANT_BORDER 0x8151 #define GL_REPLICATE_BORDER 0x8153 #define GL_CONVOLUTION_BORDER_COLOR 0x8154 #endif #ifndef GL_VERSION_1_3 #define GL_VERSION_1_3 1 #define _ALLEGRO_GL_VERSION_1_3 #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 #define GL_MAX_TEXTURE_UNITS 0x84E2 #define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 #define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 #define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 #define GL_MULTISAMPLE 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_ALPHA_TO_ONE 0x809F #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLES 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_COVERAGE_INVERT 0x80AB #define GL_MULTISAMPLE_BIT 0x20000000 #define GL_NORMAL_MAP 0x8511 #define GL_REFLECTION_MAP 0x8512 #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C #define GL_COMPRESSED_ALPHA 0x84E9 #define GL_COMPRESSED_LUMINANCE 0x84EA #define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB #define GL_COMPRESSED_INTENSITY 0x84EC #define GL_COMPRESSED_RGB 0x84ED #define GL_COMPRESSED_RGBA 0x84EE #define GL_TEXTURE_COMPRESSION_HINT 0x84EF #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 #define GL_TEXTURE_COMPRESSED 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_CLAMP_TO_BORDER 0x812D #define GL_CLAMP_TO_BORDER_SGIS 0x812D #define GL_COMBINE 0x8570 #define GL_COMBINE_RGB 0x8571 #define GL_COMBINE_ALPHA 0x8572 #define GL_SOURCE0_RGB 0x8580 #define GL_SOURCE1_RGB 0x8581 #define GL_SOURCE2_RGB 0x8582 #define GL_SOURCE0_ALPHA 0x8588 #define GL_SOURCE1_ALPHA 0x8589 #define GL_SOURCE2_ALPHA 0x858A #define GL_OPERAND0_RGB 0x8590 #define GL_OPERAND1_RGB 0x8591 #define GL_OPERAND2_RGB 0x8592 #define GL_OPERAND0_ALPHA 0x8598 #define GL_OPERAND1_ALPHA 0x8599 #define GL_OPERAND2_ALPHA 0x859A #define GL_RGB_SCALE 0x8573 #define GL_ADD_SIGNED 0x8574 #define GL_INTERPOLATE 0x8575 #define GL_SUBTRACT 0x84E7 #define GL_CONSTANT 0x8576 #define GL_PRIMARY_COLOR 0x8577 #define GL_PREVIOUS 0x8578 #define GL_DOT3_RGB 0x86AE #define GL_DOT3_RGBA 0x86AF #endif #ifndef GL_VERSION_1_4 #define GL_VERSION_1_4 1 #define _ALLEGRO_GL_VERSION_1_4 #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_POINT_SIZE_MIN 0x8126 #define GL_POINT_SIZE_MAX 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 #define GL_POINT_DISTANCE_ATTENUATION 0x8129 #define GL_GENERATE_MIPMAP 0x8191 #define GL_GENERATE_MIPMAP_HINT 0x8192 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_DEPTH_COMPONENT24 0x81A6 #define GL_DEPTH_COMPONENT32 0x81A7 #define GL_MIRRORED_REPEAT 0x8370 #define GL_FOG_COORDINATE_SOURCE 0x8450 #define GL_FOG_COORDINATE 0x8451 #define GL_FRAGMENT_DEPTH 0x8452 #define GL_CURRENT_FOG_COORDINATE 0x8453 #define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 #define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 #define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 #define GL_FOG_COORDINATE_ARRAY 0x8457 #define GL_COLOR_SUM 0x8458 #define GL_CURRENT_SECONDARY_COLOR 0x8459 #define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A #define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B #define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C #define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D #define GL_SECONDARY_COLOR_ARRAY 0x845E #define GL_MAX_TEXTURE_LOD_BIAS 0x84FD #define GL_TEXTURE_FILTER_CONTROL 0x8500 #define GL_TEXTURE_LOD_BIAS 0x8501 #define GL_INCR_WRAP 0x8507 #define GL_DECR_WRAP 0x8508 #define GL_TEXTURE_DEPTH_SIZE 0x884A #define GL_DEPTH_TEXTURE_MODE 0x884B #define GL_TEXTURE_COMPARE_MODE 0x884C #define GL_TEXTURE_COMPARE_FUNC 0x884D #define GL_COMPARE_R_TO_TEXTURE 0x884E #endif #ifndef GL_VERSION_1_5 #define GL_VERSION_1_5 1 #define _ALLEGRO_GL_VERSION_1_5 /* New types */ #include typedef ptrdiff_t GLintptr; typedef ptrdiff_t GLsizeiptr; /* Renamed enumerants */ #define GL_FOG_COORD_SRC GL_FOG_COORDINATE_SOURCE #define GL_FOG_COORD GL_FOG_COORDINATE #define GL_CURRENT_FOG_COORD GL_CURRENT_FOG_COORDINATE #define GL_FOG_COORD_ARRAY_TYPE GL_FOG_COORDINATE_ARRAY_TYPE #define GL_FOG_COORD_ARRAY_STRIDE GL_FOG_COORDINATE_ARRAY_STRIDE #define GL_FOG_COORD_ARRAY_POINTER GL_FOG_COORDINATE_ARRAY_POINTER #define GL_FOG_COORD_ARRAY GL_FOG_COORDINATE_ARRAY #define GL_SRC0_RGB GL_SOURCE0_RGB #define GL_SRC1_RGB GL_SOURCE1_RGB #define GL_SRC2_RGB GL_SOURCE2_RGB #define GL_SRC0_ALPHA GL_SOURCE0_ALPHA #define GL_SRC1_ALPHA GL_SOURCE1_ALPHA #define GL_SRC2_ALPHA GL_SOURCE2_ALPHA /* Promoted exts */ #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 #define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 #define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 #define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D #define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F #define GL_READ_ONLY 0x88B8 #define GL_WRITE_ONLY 0x88B9 #define GL_READ_WRITE 0x88BA #define GL_BUFFER_ACCESS 0x88BB #define GL_BUFFER_MAPPED 0x88BC #define GL_BUFFER_MAP_POINTER 0x88BD #define GL_STREAM_DRAW 0x88E0 #define GL_STREAM_READ 0x88E1 #define GL_STREAM_COPY 0x88E2 #define GL_STATIC_DRAW 0x88E4 #define GL_STATIC_READ 0x88E5 #define GL_STATIC_COPY 0x88E6 #define GL_DYNAMIC_DRAW 0x88E8 #define GL_DYNAMIC_READ 0x88E9 #define GL_DYNAMIC_COPY 0x88EA #define GL_SAMPLES_PASSED 0x8914 #define GL_QUERY_COUNTER_BITS 0x8864 #define GL_CURRENT_QUERY 0x8865 #define GL_QUERY_RESULT 0x8866 #define GL_QUERY_RESULT_AVAILABLE 0x8867 #endif #ifndef GL_VERSION_2_0 #define GL_VERSION_2_0 1 #define _ALLEGRO_GL_VERSION_2_0 /* New types */ typedef char GLchar; #define GL_BLEND_EQUATION_RGB GL_BLEND_EQUATION #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 #define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_MAX_DRAW_BUFFERS 0x8824 #define GL_DRAW_BUFFER0 0x8825 #define GL_DRAW_BUFFER1 0x8826 #define GL_DRAW_BUFFER2 0x8827 #define GL_DRAW_BUFFER3 0x8828 #define GL_DRAW_BUFFER4 0x8829 #define GL_DRAW_BUFFER5 0x882A #define GL_DRAW_BUFFER6 0x882B #define GL_DRAW_BUFFER7 0x882C #define GL_DRAW_BUFFER8 0x882D #define GL_DRAW_BUFFER9 0x882E #define GL_DRAW_BUFFER10 0x882F #define GL_DRAW_BUFFER11 0x8830 #define GL_DRAW_BUFFER12 0x8831 #define GL_DRAW_BUFFER13 0x8832 #define GL_DRAW_BUFFER14 0x8833 #define GL_DRAW_BUFFER15 0x8834 #define GL_BLEND_EQUATION_ALPHA 0x883D #define GL_POINT_SPRITE 0x8861 #define GL_COORD_REPLACE 0x8862 #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_MAX_TEXTURE_COORDS 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A #define GL_MAX_VARYING_FLOATS 0x8B4B #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_SHADER_TYPE 0x8B4F #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT4 0x8B5C #define GL_SAMPLER_1D 0x8B5D #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_3D 0x8B5F #define GL_SAMPLER_CUBE 0x8B60 #define GL_SAMPLER_1D_SHADOW 0x8B61 #define GL_SAMPLER_2D_SHADOW 0x8B62 #define GL_DELETE_STATUS 0x8B80 #define GL_COMPILE_STATUS 0x8B81 #define GL_LINK_STATUS 0x8B82 #define GL_VALIDATE_STATUS 0x8B83 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_CURRENT_PROGRAM 0x8B8D #define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 #define GL_LOWER_LEFT 0x8CA1 #define GL_UPPER_LEFT 0x8CA2 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #endif #ifndef GL_VERSION_2_1 #define GL_VERSION_2_1 1 #define _ALLEGRO_GL_VERSION_2_1 #define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F #define GL_PIXEL_PACK_BUFFER 0x88EB #define GL_PIXEL_UNPACK_BUFFER 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF #define GL_FLOAT_MAT2x3 0x8B65 #define GL_FLOAT_MAT2x4 0x8B66 #define GL_FLOAT_MAT3x2 0x8B67 #define GL_FLOAT_MAT3x4 0x8B68 #define GL_FLOAT_MAT4x2 0x8B69 #define GL_FLOAT_MAT4x3 0x8B6A #define GL_SRGB 0x8C40 #define GL_SRGB8 0x8C41 #define GL_SRGB_ALPHA 0x8C42 #define GL_SRGB8_ALPHA8 0x8C43 #define GL_SLUMINANCE_ALPHA 0x8C44 #define GL_SLUMINANCE8_ALPHA8 0x8C45 #define GL_SLUMINANCE 0x8C46 #define GL_SLUMINANCE8 0x8C47 #define GL_COMPRESSED_SRGB 0x8C48 #define GL_COMPRESSED_SRGB_ALPHA 0x8C49 #define GL_COMPRESSED_SLUMINANCE 0x8C4A #define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B #endif #ifndef GL_VERSION_3_0 #define GL_VERSION_3_0 #define _ALLEGRO_GL_VERSION_3_0 #define GL_COMPARE_REF_TO_TEXTURE GL_COMPARE_R_TO_TEXTURE_ARB #define GL_CLIP_DISTANCE0 GL_CLIP_PLANE0 #define GL_CLIP_DISTANCE1 GL_CLIP_PLANE1 #define GL_CLIP_DISTANCE2 GL_CLIP_PLANE2 #define GL_CLIP_DISTANCE3 GL_CLIP_PLANE3 #define GL_CLIP_DISTANCE4 GL_CLIP_PLANE4 #define GL_CLIP_DISTANCE5 GL_CLIP_PLANE5 #define GL_MAX_CLIP_DISTANCES GL_MAX_CLIP_PLANES #define GL_MAJOR_VERSION 0x821B #define GL_MINOR_VERSION 0x821C #define GL_NUM_EXTENSIONS 0x821D #define GL_CONTEXT_FLAGS 0x821E #define GL_DEPTH_BUFFER 0x8223 #define GL_STENCIL_BUFFER 0x8224 #define GL_COMPRESSED_RED 0x8225 #define GL_COMPRESSED_RG 0x8226 #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001 #define GL_RGBA32F 0x8814 #define GL_RGB32F 0x8815 #define GL_RGBA16F 0x881A #define GL_RGB16F 0x881B #define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF #define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 #define GL_CLAMP_VERTEX_COLOR 0x891A #define GL_CLAMP_FRAGMENT_COLOR 0x891B #define GL_CLAMP_READ_COLOR 0x891C #define GL_FIXED_ONLY 0x891D #define GL_MAX_VARYING_COMPONENTS GL_MAX_VARYING_FLOATS #define GL_TEXTURE_RED_TYPE 0x8C10 #define GL_TEXTURE_GREEN_TYPE 0x8C11 #define GL_TEXTURE_BLUE_TYPE 0x8C12 #define GL_TEXTURE_ALPHA_TYPE 0x8C13 #define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 #define GL_TEXTURE_INTENSITY_TYPE 0x8C15 #define GL_TEXTURE_DEPTH_TYPE 0x8C16 #define GL_UNSIGNED_NORMALIZED 0x8C17 #define GL_TEXTURE_1D_ARRAY 0x8C18 #define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 #define GL_TEXTURE_2D_ARRAY 0x8C1A #define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B #define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C #define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D #define GL_R11F_G11F_B10F 0x8C3A #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B #define GL_RGB9_E5 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E #define GL_TEXTURE_SHARED_SIZE 0x8C3F #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 #define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 #define GL_PRIMITIVES_GENERATED 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 #define GL_RASTERIZER_DISCARD 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B #define GL_INTERLEAVED_ATTRIBS 0x8C8C #define GL_SEPARATE_ATTRIBS 0x8C8D #define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F #define GL_RGBA32UI 0x8D70 #define GL_RGB32UI 0x8D71 #define GL_RGBA16UI 0x8D76 #define GL_RGB16UI 0x8D77 #define GL_RGBA8UI 0x8D7C #define GL_RGB8UI 0x8D7D #define GL_RGBA32I 0x8D82 #define GL_RGB32I 0x8D83 #define GL_RGBA16I 0x8D88 #define GL_RGB16I 0x8D89 #define GL_RGBA8I 0x8D8E #define GL_RGB8I 0x8D8F #define GL_RED_INTEGER 0x8D94 #define GL_GREEN_INTEGER 0x8D95 #define GL_BLUE_INTEGER 0x8D96 #define GL_ALPHA_INTEGER 0x8D97 #define GL_RGB_INTEGER 0x8D98 #define GL_RGBA_INTEGER 0x8D99 #define GL_BGR_INTEGER 0x8D9A #define GL_BGRA_INTEGER 0x8D9B #define GL_SAMPLER_1D_ARRAY 0x8DC0 #define GL_SAMPLER_2D_ARRAY 0x8DC1 #define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 #define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 #define GL_SAMPLER_CUBE_SHADOW 0x8DC5 #define GL_UNSIGNED_INT_VEC2 0x8DC6 #define GL_UNSIGNED_INT_VEC3 0x8DC7 #define GL_UNSIGNED_INT_VEC4 0x8DC8 #define GL_INT_SAMPLER_1D 0x8DC9 #define GL_INT_SAMPLER_2D 0x8DCA #define GL_INT_SAMPLER_3D 0x8DCB #define GL_INT_SAMPLER_CUBE 0x8DCC #define GL_INT_SAMPLER_1D_ARRAY 0x8DCE #define GL_INT_SAMPLER_2D_ARRAY 0x8DCF #define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 #define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 #define GL_QUERY_WAIT 0x8E13 #define GL_QUERY_NO_WAIT 0x8E14 #define GL_QUERY_BY_REGION_WAIT 0x8E15 #define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 #endif #ifndef GL_VERSION_3_0_DEPRECATED #define GL_VERSION_3_0_DEPRECATED #define _ALLEGRO_GL_VERSION_3_0_DEPRECATED #define GL_CLAMP_VERTEX_COLOR 0x891A #define GL_CLAMP_FRAGMENT_COLOR 0x891B #define GL_ALPHA_INTEGER 0x8D97 /* Reuse tokens from ARB_framebuffer_object */ /* reuse GL_TEXTURE_LUMINANCE_TYPE */ /* reuse GL_TEXTURE_INTENSITY_TYPE */ #endif #ifndef GL_VERSION_3_1 #define GL_VERSION_3_1 #define _ALLEGRO_GL_VERSION_3_1 #define GL_SAMPLER_2D_RECT 0x8B63 #define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 #define GL_SAMPLER_BUFFER 0x8DC2 #define GL_INT_SAMPLER_2D_RECT 0x8DCD #define GL_INT_SAMPLER_BUFFER 0x8DD0 #define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 #define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 #define GL_TEXTURE_BUFFER 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B #define GL_TEXTURE_BINDING_BUFFER 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D #define GL_TEXTURE_BUFFER_FORMAT 0x8C2E #define GL_TEXTURE_RECTANGLE 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 #define GL_RED_SNORM 0x8F90 #define GL_RG_SNORM 0x8F91 #define GL_RGB_SNORM 0x8F92 #define GL_RGBA_SNORM 0x8F93 #define GL_R8_SNORM 0x8F94 #define GL_RG8_SNORM 0x8F95 #define GL_RGB8_SNORM 0x8F96 #define GL_RGBA8_SNORM 0x8F97 #define GL_R16_SNORM 0x8F98 #define GL_RG16_SNORM 0x8F99 #define GL_RGB16_SNORM 0x8F9A #define GL_RGBA16_SNORM 0x8F9B #define GL_SIGNED_NORMALIZED 0x8F9C #define GL_PRIMITIVE_RESTART 0x8F9D #define GL_PRIMITIVE_RESTART_INDEX 0x8F9E #endif #ifndef GL_VERSION_3_2 #define GL_VERSION_3_2 #define _ALLEGRO_GL_VERSION_3_2 #define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 #define GL_LINES_ADJACENCY 0x000A #define GL_LINE_STRIP_ADJACENCY 0x000B #define GL_TRIANGLES_ADJACENCY 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY 0x000D #define GL_PROGRAM_POINT_SIZE 0x8642 #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 #define GL_GEOMETRY_SHADER 0x8DD9 #define GL_GEOMETRY_VERTICES_OUT 0x8916 #define GL_GEOMETRY_INPUT_TYPE 0x8917 #define GL_GEOMETRY_OUTPUT_TYPE 0x8918 #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 #define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 #define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 #define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 #define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 #define GL_CONTEXT_PROFILE_MASK 0x9126 #endif #ifndef GL_VERSION_3_3 #define GL_VERSION_3_3 #define _ALLEGRO_GL_VERSION_3_3 #endif #ifndef GL_VERSION_4_3 #define GL_VERSION_4_3 #define _ALLEGRO_GL_VERSION_4_3 typedef void (*GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); #define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 #define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E #define GL_COMPRESSED_RGB8_ETC2 0x9274 #define GL_COMPRESSED_SRGB8_ETC2 0x9275 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 #define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 #define GL_COMPRESSED_R11_EAC 0x9270 #define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 #define GL_COMPRESSED_RG11_EAC 0x9272 #define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 #define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 #define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A #define GL_MAX_ELEMENT_INDEX 0x8D6B #define GL_COMPUTE_SHADER 0x91B9 #define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB #define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC #define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD #define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 #define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 #define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 #define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 #define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 #define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB #define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE #define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF #define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 #define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED #define GL_DISPATCH_INDIRECT_BUFFER 0x90EE #define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF #define GL_COMPUTE_SHADER_BIT 0x00000020 #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 #define GL_DEBUG_CALLBACK_FUNCTION 0x8244 #define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 #define GL_DEBUG_SOURCE_API 0x8246 #define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 #define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 #define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 #define GL_DEBUG_SOURCE_APPLICATION 0x824A #define GL_DEBUG_SOURCE_OTHER 0x824B #define GL_DEBUG_TYPE_ERROR 0x824C #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E #define GL_DEBUG_TYPE_PORTABILITY 0x824F #define GL_DEBUG_TYPE_PERFORMANCE 0x8250 #define GL_DEBUG_TYPE_OTHER 0x8251 #define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 #define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 #define GL_DEBUG_LOGGED_MESSAGES 0x9145 #define GL_DEBUG_SEVERITY_HIGH 0x9146 #define GL_DEBUG_SEVERITY_MEDIUM 0x9147 #define GL_DEBUG_SEVERITY_LOW 0x9148 #define GL_DEBUG_TYPE_MARKER 0x8268 #define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 #define GL_DEBUG_TYPE_POP_GROUP 0x826A #define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B #define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C #define GL_DEBUG_GROUP_STACK_DEPTH 0x826D #define GL_BUFFER 0x82E0 #define GL_SHADER 0x82E1 #define GL_PROGRAM 0x82E2 #define GL_QUERY 0x82E3 #define GL_PROGRAM_PIPELINE 0x82E4 #define GL_SAMPLER 0x82E6 #define GL_MAX_LABEL_LENGTH 0x82E8 #define GL_DEBUG_OUTPUT 0x92E0 #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 #define GL_MAX_UNIFORM_LOCATIONS 0x826E #define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 #define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 #define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 #define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 #define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 #define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 #define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 #define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 #define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 #define GL_INTERNALFORMAT_SUPPORTED 0x826F #define GL_INTERNALFORMAT_PREFERRED 0x8270 #define GL_INTERNALFORMAT_RED_SIZE 0x8271 #define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 #define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 #define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 #define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 #define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 #define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 #define GL_INTERNALFORMAT_RED_TYPE 0x8278 #define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 #define GL_INTERNALFORMAT_BLUE_TYPE 0x827A #define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B #define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C #define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D #define GL_MAX_WIDTH 0x827E #define GL_MAX_HEIGHT 0x827F #define GL_MAX_DEPTH 0x8280 #define GL_MAX_LAYERS 0x8281 #define GL_MAX_COMBINED_DIMENSIONS 0x8282 #define GL_COLOR_COMPONENTS 0x8283 #define GL_DEPTH_COMPONENTS 0x8284 #define GL_STENCIL_COMPONENTS 0x8285 #define GL_COLOR_RENDERABLE 0x8286 #define GL_DEPTH_RENDERABLE 0x8287 #define GL_STENCIL_RENDERABLE 0x8288 #define GL_FRAMEBUFFER_RENDERABLE 0x8289 #define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A #define GL_FRAMEBUFFER_BLEND 0x828B #define GL_READ_PIXELS 0x828C #define GL_READ_PIXELS_FORMAT 0x828D #define GL_READ_PIXELS_TYPE 0x828E #define GL_TEXTURE_IMAGE_FORMAT 0x828F #define GL_TEXTURE_IMAGE_TYPE 0x8290 #define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 #define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 #define GL_MIPMAP 0x8293 #define GL_MANUAL_GENERATE_MIPMAP 0x8294 #define GL_AUTO_GENERATE_MIPMAP 0x8295 #define GL_COLOR_ENCODING 0x8296 #define GL_SRGB_READ 0x8297 #define GL_SRGB_WRITE 0x8298 #define GL_FILTER 0x829A #define GL_VERTEX_TEXTURE 0x829B #define GL_TESS_CONTROL_TEXTURE 0x829C #define GL_TESS_EVALUATION_TEXTURE 0x829D #define GL_GEOMETRY_TEXTURE 0x829E #define GL_FRAGMENT_TEXTURE 0x829F #define GL_COMPUTE_TEXTURE 0x82A0 #define GL_TEXTURE_SHADOW 0x82A1 #define GL_TEXTURE_GATHER 0x82A2 #define GL_TEXTURE_GATHER_SHADOW 0x82A3 #define GL_SHADER_IMAGE_LOAD 0x82A4 #define GL_SHADER_IMAGE_STORE 0x82A5 #define GL_SHADER_IMAGE_ATOMIC 0x82A6 #define GL_IMAGE_TEXEL_SIZE 0x82A7 #define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 #define GL_IMAGE_PIXEL_FORMAT 0x82A9 #define GL_IMAGE_PIXEL_TYPE 0x82AA #define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC #define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD #define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE #define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF #define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 #define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 #define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 #define GL_CLEAR_BUFFER 0x82B4 #define GL_TEXTURE_VIEW 0x82B5 #define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 #define GL_FULL_SUPPORT 0x82B7 #define GL_CAVEAT_SUPPORT 0x82B8 #define GL_IMAGE_CLASS_4_X_32 0x82B9 #define GL_IMAGE_CLASS_2_X_32 0x82BA #define GL_IMAGE_CLASS_1_X_32 0x82BB #define GL_IMAGE_CLASS_4_X_16 0x82BC #define GL_IMAGE_CLASS_2_X_16 0x82BD #define GL_IMAGE_CLASS_1_X_16 0x82BE #define GL_IMAGE_CLASS_4_X_8 0x82BF #define GL_IMAGE_CLASS_2_X_8 0x82C0 #define GL_IMAGE_CLASS_1_X_8 0x82C1 #define GL_IMAGE_CLASS_11_11_10 0x82C2 #define GL_IMAGE_CLASS_10_10_10_2 0x82C3 #define GL_VIEW_CLASS_128_BITS 0x82C4 #define GL_VIEW_CLASS_96_BITS 0x82C5 #define GL_VIEW_CLASS_64_BITS 0x82C6 #define GL_VIEW_CLASS_48_BITS 0x82C7 #define GL_VIEW_CLASS_32_BITS 0x82C8 #define GL_VIEW_CLASS_24_BITS 0x82C9 #define GL_VIEW_CLASS_16_BITS 0x82CA #define GL_VIEW_CLASS_8_BITS 0x82CB #define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC #define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD #define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE #define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF #define GL_VIEW_CLASS_RGTC1_RED 0x82D0 #define GL_VIEW_CLASS_RGTC2_RG 0x82D1 #define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 #define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 #define GL_UNIFORM 0x92E1 #define GL_UNIFORM_BLOCK 0x92E2 #define GL_PROGRAM_INPUT 0x92E3 #define GL_PROGRAM_OUTPUT 0x92E4 #define GL_BUFFER_VARIABLE 0x92E5 #define GL_SHADER_STORAGE_BLOCK 0x92E6 #define GL_VERTEX_SUBROUTINE 0x92E8 #define GL_TESS_CONTROL_SUBROUTINE 0x92E9 #define GL_TESS_EVALUATION_SUBROUTINE 0x92EA #define GL_GEOMETRY_SUBROUTINE 0x92EB #define GL_FRAGMENT_SUBROUTINE 0x92EC #define GL_COMPUTE_SUBROUTINE 0x92ED #define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE #define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF #define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 #define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 #define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 #define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 #define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 #define GL_ACTIVE_RESOURCES 0x92F5 #define GL_MAX_NAME_LENGTH 0x92F6 #define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 #define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 #define GL_NAME_LENGTH 0x92F9 #define GL_TYPE 0x92FA #define GL_ARRAY_SIZE 0x92FB #define GL_OFFSET 0x92FC #define GL_BLOCK_INDEX 0x92FD #define GL_ARRAY_STRIDE 0x92FE #define GL_MATRIX_STRIDE 0x92FF #define GL_IS_ROW_MAJOR 0x9300 #define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 #define GL_BUFFER_BINDING 0x9302 #define GL_BUFFER_DATA_SIZE 0x9303 #define GL_NUM_ACTIVE_VARIABLES 0x9304 #define GL_ACTIVE_VARIABLES 0x9305 #define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 #define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 #define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 #define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 #define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A #define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B #define GL_TOP_LEVEL_ARRAY_SIZE 0x930C #define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D #define GL_LOCATION 0x930E #define GL_LOCATION_INDEX 0x930F #define GL_IS_PER_PATCH 0x92E7 #define GL_SHADER_STORAGE_BUFFER 0x90D2 #define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 #define GL_SHADER_STORAGE_BUFFER_START 0x90D4 #define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 #define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 #define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 #define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 #define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 #define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA #define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB #define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC #define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD #define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE #define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF #define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 #define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 #define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA #define GL_TEXTURE_BUFFER_OFFSET 0x919D #define GL_TEXTURE_BUFFER_SIZE 0x919E #define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F #define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB #define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC #define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD #define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE #define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF #define GL_VERTEX_ATTRIB_BINDING 0x82D4 #define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 #define GL_VERTEX_BINDING_DIVISOR 0x82D6 #define GL_VERTEX_BINDING_OFFSET 0x82D7 #define GL_VERTEX_BINDING_STRIDE 0x82D8 #define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 #define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA #define GL_VERTEX_BINDING_BUFFER 0x8F4F #define GL_DISPLAY_LIST 0x82E7 typedef void (PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); typedef void (PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); typedef void (PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); typedef void (PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); typedef void (PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); typedef void (PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); typedef void (PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); typedef void (PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); typedef void (PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level); typedef void (PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); typedef void (PFNGLINVALIDATEBUFFERDATAPROC) (GLuint buffer); typedef void (PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); typedef void (PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); typedef void (PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); typedef void (PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); typedef GLuint (PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); typedef void (PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); typedef void (PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); typedef GLint (PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); typedef GLint (PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); typedef void (PFNGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); typedef void (PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); typedef void (PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); typedef void (PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); typedef void (PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); typedef void (PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); typedef void (PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); typedef void (PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); typedef void (PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex); typedef void (PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor); typedef void (PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); typedef void (PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); typedef void (PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam); typedef GLuint (PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); typedef void (PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); typedef void (PFNGLPOPDEBUGGROUPPROC) (void); typedef void (PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); typedef void (PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); typedef void (PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label); typedef void (PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); #endif /* */ /* */ #ifndef GL_ARB_multitexture #define GL_ARB_multitexture #define _ALLEGRO_GL_ARB_multitexture #define GL_TEXTURE0_ARB 0x84C0 #define GL_TEXTURE1_ARB 0x84C1 #define GL_TEXTURE2_ARB 0x84C2 #define GL_TEXTURE3_ARB 0x84C3 #define GL_TEXTURE4_ARB 0x84C4 #define GL_TEXTURE5_ARB 0x84C5 #define GL_TEXTURE6_ARB 0x84C6 #define GL_TEXTURE7_ARB 0x84C7 #define GL_TEXTURE8_ARB 0x84C8 #define GL_TEXTURE9_ARB 0x84C9 #define GL_TEXTURE10_ARB 0x84CA #define GL_TEXTURE11_ARB 0x84CB #define GL_TEXTURE12_ARB 0x84CC #define GL_TEXTURE13_ARB 0x84CD #define GL_TEXTURE14_ARB 0x84CE #define GL_TEXTURE15_ARB 0x84CF #define GL_TEXTURE16_ARB 0x84D0 #define GL_TEXTURE17_ARB 0x84D1 #define GL_TEXTURE18_ARB 0x84D2 #define GL_TEXTURE19_ARB 0x84D3 #define GL_TEXTURE20_ARB 0x84D4 #define GL_TEXTURE21_ARB 0x84D5 #define GL_TEXTURE22_ARB 0x84D6 #define GL_TEXTURE23_ARB 0x84D7 #define GL_TEXTURE24_ARB 0x84D8 #define GL_TEXTURE25_ARB 0x84D9 #define GL_TEXTURE26_ARB 0x84DA #define GL_TEXTURE27_ARB 0x84DB #define GL_TEXTURE28_ARB 0x84DC #define GL_TEXTURE29_ARB 0x84DD #define GL_TEXTURE30_ARB 0x84DE #define GL_TEXTURE31_ARB 0x84DF #define GL_ACTIVE_TEXTURE_ARB 0x84E0 #define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 #define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 #endif #ifndef GL_ARB_transpose_matrix #define GL_ARB_transpose_matrix #define _ALLEGRO_GL_ARB_transpose_matrix #define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 #define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 #define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 #endif #ifndef GL_ARB_multisample #define GL_ARB_multisample #define _ALLEGRO_GL_ARB_multisample #define GL_MULTISAMPLE_ARB 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F #define GL_SAMPLE_COVERAGE_ARB 0x80A0 #define GL_SAMPLE_BUFFERS_ARB 0x80A8 #define GL_SAMPLES_ARB 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA #define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB #define GL_MULTISAMPLE_BIT_ARB 0x20000000 #endif #ifndef GL_ARB_texture_cube_map #define GL_ARB_texture_cube_map #define _ALLEGRO_GL_ARB_texture_cube_map #define GL_NORMAL_MAP_ARB 0x8511 #define GL_REFLECTION_MAP_ARB 0x8512 #define GL_TEXTURE_CUBE_MAP_ARB 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C #endif #ifndef GL_ARB_texture_compression #define GL_ARB_texture_compression #define _ALLEGRO_GL_ARB_texture_compression #define GL_COMPRESSED_ALPHA_ARB 0x84E9 #define GL_COMPRESSED_LUMINANCE_ARB 0x84EA #define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB #define GL_COMPRESSED_INTENSITY_ARB 0x84EC #define GL_COMPRESSED_RGB_ARB 0x84ED #define GL_COMPRESSED_RGBA_ARB 0x84EE #define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 #define GL_TEXTURE_COMPRESSED_ARB 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 #endif #ifndef GL_ARB_texture_border_clamp #define GL_ARB_texture_border_clamp #define _ALLEGRO_GL_ARB_texture_border_clamp #define GL_CLAMP_TO_BORDER_ARB 0x812D #endif #ifndef GL_ARB_point_parameters #define GL_ARB_point_parameters #define _ALLEGRO_GL_ARB_point_parameters #define GL_POINT_SIZE_MIN_ARB 0x8126 #define GL_POINT_SIZE_MAX_ARB 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 #define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 #endif #ifndef GL_ARB_vertex_blend #define GL_ARB_vertex_blend #define _ALLEGRO_GL_ARB_vertex_blend #define GL_MAX_VERTEX_UNITS_ARB 0x86A4 #define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 #define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 #define GL_VERTEX_BLEND_ARB 0x86A7 #define GL_CURRENT_WEIGHT_ARB 0x86A8 #define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 #define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA #define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB #define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC #define GL_WEIGHT_ARRAY_ARB 0x86AD #define GL_MODELVIEW0_ARB 0x1700 #define GL_MODELVIEW1_ARB 0x850A #define GL_MODELVIEW2_ARB 0x8722 #define GL_MODELVIEW3_ARB 0x8723 #define GL_MODELVIEW4_ARB 0x8724 #define GL_MODELVIEW5_ARB 0x8725 #define GL_MODELVIEW6_ARB 0x8726 #define GL_MODELVIEW7_ARB 0x8727 #define GL_MODELVIEW8_ARB 0x8728 #define GL_MODELVIEW9_ARB 0x8729 #define GL_MODELVIEW10_ARB 0x872A #define GL_MODELVIEW11_ARB 0x872B #define GL_MODELVIEW12_ARB 0x872C #define GL_MODELVIEW13_ARB 0x872D #define GL_MODELVIEW14_ARB 0x872E #define GL_MODELVIEW15_ARB 0x872F #define GL_MODELVIEW16_ARB 0x8730 #define GL_MODELVIEW17_ARB 0x8731 #define GL_MODELVIEW18_ARB 0x8732 #define GL_MODELVIEW19_ARB 0x8733 #define GL_MODELVIEW20_ARB 0x8734 #define GL_MODELVIEW21_ARB 0x8735 #define GL_MODELVIEW22_ARB 0x8736 #define GL_MODELVIEW23_ARB 0x8737 #define GL_MODELVIEW24_ARB 0x8738 #define GL_MODELVIEW25_ARB 0x8739 #define GL_MODELVIEW26_ARB 0x873A #define GL_MODELVIEW27_ARB 0x873B #define GL_MODELVIEW28_ARB 0x873C #define GL_MODELVIEW29_ARB 0x873D #define GL_MODELVIEW30_ARB 0x873E #define GL_MODELVIEW31_ARB 0x873F #endif #ifndef GL_ARB_matrix_palette #define GL_ARB_matrix_palette #define _ALLEGRO_GL_ARB_matrix_palette #define GL_MATRIX_PALETTE_ARB 0x8840 #define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 #define GL_MAX_PALETTE_MATRICES_ARB 0x8842 #define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 #define GL_MATRIX_INDEX_ARRAY_ARB 0x8844 #define GL_CURRENT_MATRIX_INDEX_ARB 0x8845 #define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 #define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 #define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 #define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 #endif #ifndef GL_ARB_texture_env_combine #define GL_ARB_texture_env_combine #define _ALLEGRO_GL_ARB_texture_env_combine #define GL_COMBINE_ARB 0x8570 #define GL_COMBINE_RGB_ARB 0x8571 #define GL_COMBINE_ALPHA_ARB 0x8572 #define GL_SOURCE0_RGB_ARB 0x8580 #define GL_SOURCE1_RGB_ARB 0x8581 #define GL_SOURCE2_RGB_ARB 0x8582 #define GL_SOURCE0_ALPHA_ARB 0x8588 #define GL_SOURCE1_ALPHA_ARB 0x8589 #define GL_SOURCE2_ALPHA_ARB 0x858A #define GL_OPERAND0_RGB_ARB 0x8590 #define GL_OPERAND1_RGB_ARB 0x8591 #define GL_OPERAND2_RGB_ARB 0x8592 #define GL_OPERAND0_ALPHA_ARB 0x8598 #define GL_OPERAND1_ALPHA_ARB 0x8599 #define GL_OPERAND2_ALPHA_ARB 0x859A #define GL_RGB_SCALE_ARB 0x8573 #define GL_ADD_SIGNED_ARB 0x8574 #define GL_INTERPOLATE_ARB 0x8575 #define GL_SUBTRACT_ARB 0x84E7 #define GL_CONSTANT_ARB 0x8576 #define GL_PRIMARY_COLOR_ARB 0x8577 #define GL_PREVIOUS_ARB 0x8578 #endif #ifndef GL_ARB_texture_env_dot3 #define GL_ARB_texture_env_dot3 #define _ALLEGRO_GL_ARB_texture_env_dot3 #define GL_DOT3_RGB_ARB 0x86AE #define GL_DOT3_RGBA_ARB 0x86AF #endif #ifndef GL_ARB_texture_mirrored_repeat #define GL_ARB_texture_mirrored_repeat #define _ALLEGRO_GL_ARB_texture_mirrored_repeat #define GL_MIRRORED_REPEAT_ARB 0x8370 #endif #ifndef GL_ARB_depth_texture #define GL_ARB_depth_texture #define _ALLEGRO_GL_ARB_depth_texture #define GL_DEPTH_COMPONENT16_ARB 0x81A5 #define GL_DEPTH_COMPONENT24_ARB 0x81A6 #define GL_DEPTH_COMPONENT32_ARB 0x81A7 #define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A #define GL_DEPTH_TEXTURE_MODE_ARB 0x884B #endif #ifndef GL_ARB_window_pos #define GL_ARB_window_pos #define _ALLEGRO_GL_ARB_window_pos #endif #ifndef GL_ARB_shadow #define GL_ARB_shadow #define _ALLEGRO_GL_ARB_shadow #define GL_TEXTURE_COMPARE_MODE_ARB 0x884C #define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D #define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E #endif #ifndef GL_ARB_shadow_ambient #define GL_ARB_shadow_ambient #define _ALLEGRO_GL_ARB_shadow_ambient #define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF #endif #ifndef GL_ARB_vertex_program #define GL_ARB_vertex_program #define _ALLEGRO_GL_ARB_vertex_program #define GL_COLOR_SUM_ARB 0x8458 #define GL_VERTEX_PROGRAM_ARB 0x8620 #define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 #define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 #define GL_PROGRAM_LENGTH_ARB 0x8627 #define GL_PROGRAM_STRING_ARB 0x8628 #define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E #define GL_MAX_PROGRAM_MATRICES_ARB 0x862F #define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 #define GL_CURRENT_MATRIX_ARB 0x8641 #define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 #define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 #define GL_PROGRAM_ERROR_POSITION_ARB 0x864B #define GL_PROGRAM_BINDING_ARB 0x8677 #define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A #define GL_PROGRAM_ERROR_STRING_ARB 0x8874 #define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 #define GL_PROGRAM_FORMAT_ARB 0x8876 #define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 #define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 #define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 #define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 #define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 #define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 #define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 #define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 #define GL_PROGRAM_PARAMETERS_ARB 0x88A8 #define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 #define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA #define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB #define GL_PROGRAM_ATTRIBS_ARB 0x88AC #define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD #define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE #define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF #define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 #define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 #define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 #define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 #define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 #define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 #define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 #define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 #define GL_MATRIX0_ARB 0x88C0 #define GL_MATRIX1_ARB 0x88C1 #define GL_MATRIX2_ARB 0x88C2 #define GL_MATRIX3_ARB 0x88C3 #define GL_MATRIX4_ARB 0x88C4 #define GL_MATRIX5_ARB 0x88C5 #define GL_MATRIX6_ARB 0x88C6 #define GL_MATRIX7_ARB 0x88C7 #define GL_MATRIX8_ARB 0x88C8 #define GL_MATRIX9_ARB 0x88C9 #define GL_MATRIX10_ARB 0x88CA #define GL_MATRIX11_ARB 0x88CB #define GL_MATRIX12_ARB 0x88CC #define GL_MATRIX13_ARB 0x88CD #define GL_MATRIX14_ARB 0x88CE #define GL_MATRIX15_ARB 0x88CF #define GL_MATRIX16_ARB 0x88D0 #define GL_MATRIX17_ARB 0x88D1 #define GL_MATRIX18_ARB 0x88D2 #define GL_MATRIX19_ARB 0x88D3 #define GL_MATRIX20_ARB 0x88D4 #define GL_MATRIX21_ARB 0x88D5 #define GL_MATRIX22_ARB 0x88D6 #define GL_MATRIX23_ARB 0x88D7 #define GL_MATRIX24_ARB 0x88D8 #define GL_MATRIX25_ARB 0x88D9 #define GL_MATRIX26_ARB 0x88DA #define GL_MATRIX27_ARB 0x88DB #define GL_MATRIX28_ARB 0x88DC #define GL_MATRIX29_ARB 0x88DD #define GL_MATRIX30_ARB 0x88DE #define GL_MATRIX31_ARB 0x88DF #endif #ifndef GL_ARB_fragment_program #define GL_ARB_fragment_program #define _ALLEGRO_GL_ARB_fragment_program #define GL_FRAGMENT_PROGRAM_ARB 0x8804 #define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 #define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 #define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 #define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 #define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 #define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A #define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B #define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C #define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D #define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E #define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F #define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 #define GL_MAX_TEXTURE_COORDS_ARB 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 #endif #ifndef GL_ARB_vertex_buffer_object #define GL_ARB_vertex_buffer_object #define _ALLEGRO_GL_ARB_vertex_buffer_object #include typedef ptrdiff_t GLintptrARB; typedef ptrdiff_t GLsizeiptrARB; #define GL_BUFFER_SIZE_ARB 0x8764 #define GL_BUFFER_USAGE_ARB 0x8765 #define GL_ARRAY_BUFFER_ARB 0x8892 #define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 #define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 #define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 #define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 #define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 #define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D #define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F #define GL_READ_ONLY_ARB 0x88B8 #define GL_WRITE_ONLY_ARB 0x88B9 #define GL_READ_WRITE_ARB 0x88BA #define GL_BUFFER_ACCESS_ARB 0x88BB #define GL_BUFFER_MAPPED_ARB 0x88BC #define GL_BUFFER_MAP_POINTER_ARB 0x88BD #define GL_STREAM_DRAW_ARB 0x88E0 #define GL_STREAM_READ_ARB 0x88E1 #define GL_STREAM_COPY_ARB 0x88E2 #define GL_STATIC_DRAW_ARB 0x88E4 #define GL_STATIC_READ_ARB 0x88E5 #define GL_STATIC_COPY_ARB 0x88E6 #define GL_DYNAMIC_DRAW_ARB 0x88E8 #define GL_DYNAMIC_READ_ARB 0x88E9 #define GL_DYNAMIC_COPY_ARB 0x88EA #endif #ifndef GL_ARB_occlusion_query #define GL_ARB_occlusion_query #define _ALLEGRO_GL_ARB_occlusion_query #define GL_SAMPLES_PASSED_ARB 0x8914 #define GL_QUERY_COUNTER_BITS_ARB 0x8864 #define GL_CURRENT_QUERY_ARB 0x8865 #define GL_QUERY_RESULT_ARB 0x8866 #define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 #endif #ifndef GL_ARB_shader_objects #define GL_ARB_shader_objects #define _ALLEGRO_GL_ARB_shader_objects typedef char GLcharARB; typedef unsigned long GLhandleARB; #define GL_PROGRAM_OBJECT_ARB 0x8B40 #define GL_OBJECT_TYPE_ARB 0x8B4E #define GL_OBJECT_SUBTYPE_ARB 0x8B4F #define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 #define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 #define GL_OBJECT_LINK_STATUS_ARB 0x8B82 #define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 #define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 #define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 #define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 #define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 #define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 #define GL_SHADER_OBJECT_ARB 0x8B48 /* GL_FLOAT */ #define GL_FLOAT_VEC2_ARB 0x8B50 #define GL_FLOAT_VEC3_ARB 0x8B51 #define GL_FLOAT_VEC4_ARB 0x8B52 /* GL_INT */ #define GL_INT_VEC2_ARB 0x8B53 #define GL_INT_VEC3_ARB 0x8B54 #define GL_INT_VEC4_ARB 0x8B55 #define GL_BOOL_ARB 0x8B56 #define GL_BOOL_VEC2_ARB 0x8B57 #define GL_BOOL_VEC3_ARB 0x8B58 #define GL_BOOL_VEC4_ARB 0x8B59 #define GL_FLOAT_MAT2_ARB 0x8B5A #define GL_FLOAT_MAT3_ARB 0x8B5B #define GL_FLOAT_MAT4_ARB 0x8B5C #define GL_SAMPLER_1D_ARB 0x8B5D #define GL_SAMPLER_2D_ARB 0x8B5E #define GL_SAMPLER_3D_ARB 0x8B5F #define GL_SAMPLER_CUBE_ARB 0x8B60 #define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 #define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 #define GL_SAMPLER_2D_RECT_ARB 0x8B63 #define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 #endif #ifndef GL_ARB_vertex_shader #define GL_ARB_vertex_shader #define _ALLEGRO_GL_ARB_vertex_shader #define GL_VERTEX_SHADER_ARB 0x8B31 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A #define GL_MAX_VARYING_FLOATS_ARB 0x8B4B #define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 #define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D #define GL_MAX_TEXTURE_COORDS_ARB 0x8871 #define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 #if !defined GL_ARB_shader_objects #define GL_OBJECT_TYPE_ARB 0x8B4E #define GL_OBJECT_SUBTYPE_ARB 0x8B4F #endif #define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 #define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A #if !defined GL_ARB_shader_objects #define GL_SHADER_OBJECT_ARB 0x8B48 #endif #define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A #define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 #define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 #if !defined GL_ARB_shader_objects /* GL_FLOAT */ #define GL_FLOAT_VEC2_ARB 0x8B50 #define GL_FLOAT_VEC3_ARB 0x8B51 #define GL_FLOAT_VEC4_ARB 0x8B52 #define GL_FLOAT_MAT2_ARB 0x8B5A #define GL_FLOAT_MAT3_ARB 0x8B5B #define GL_FLOAT_MAT4_ARB 0x8B5C #endif #endif #ifndef GL_ARB_fragment_shader #define GL_ARB_fragment_shader #define _ALLEGRO_GL_ARB_fragment_shader #define GL_FRAGMENT_SHADER_ARB 0x8B30 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 #define GL_MAX_TEXTURE_COORDS_ARB 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 #if !defined GL_ARB_shader_objects && !defined GL_ARB_vertex_shader #define GL_OBJECT_TYPE_ARB 0x8B4E #define GL_OBJECT_SUBTYPE_ARB 0x8B4F #define GL_SHADER_OBJECT_ARB 0x8B48 #endif #endif #ifndef GL_ARB_shading_language_100 #define GL_ARB_shading_language_100 #define _ALLEGRO_GL_ARB_shading_language_100 #endif #ifndef GL_ARB_texture_non_power_of_two #define GL_ARB_texture_non_power_of_two #define _ALLEGRO_GL_ARB_texture_non_power_of_two #endif #ifndef GL_ARB_point_sprite #define GL_ARB_point_sprite #define _ALLEGRO_GL_ARB_point_sprite #define GL_POINT_SPRITE_ARB 0x8861 #define GL_COORD_REPLACE_ARB 0x8862 /* GL_FALSE */ /* GL_TRUE */ #endif #ifndef GL_ARB_draw_buffers #define GL_ARB_draw_buffers #define _ALLEGRO_GL_ARB_draw_buffers #define GL_MAX_DRAW_BUFFERS_ARB 0x8824 #define GL_DRAW_BUFFER0_ARB 0x8825 #define GL_DRAW_BUFFER1_ARB 0x8826 #define GL_DRAW_BUFFER2_ARB 0x8827 #define GL_DRAW_BUFFER3_ARB 0x8828 #define GL_DRAW_BUFFER4_ARB 0x8829 #define GL_DRAW_BUFFER5_ARB 0x882A #define GL_DRAW_BUFFER6_ARB 0x882B #define GL_DRAW_BUFFER7_ARB 0x882C #define GL_DRAW_BUFFER8_ARB 0x882D #define GL_DRAW_BUFFER9_ARB 0x882E #define GL_DRAW_BUFFER10_ARB 0x882F #define GL_DRAW_BUFFER11_ARB 0x8830 #define GL_DRAW_BUFFER12_ARB 0x8831 #define GL_DRAW_BUFFER13_ARB 0x8832 #define GL_DRAW_BUFFER14_ARB 0x8833 #define GL_DRAW_BUFFER15_ARB 0x8834 #endif #ifndef GL_ARB_texture_rectangle #define GL_ARB_texture_rectangle #define _ALLEGRO_GL_ARB_texture_rectangle #define GL_TEXTURE_RECTANGLE_ARB 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 #endif #ifdef ALLEGRO_MACOSX #ifndef GL_EXT_texture_rectangle #define GL_EXT_texture_rectangle #define _ALLEGRO_GL_EXT_texture_rectangle #define GL_TEXTURE_RECTANGLE_EXT 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE_EXT 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE_EXT 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT 0x84F8 #endif #endif #ifndef GL_ARB_color_buffer_float #define GL_ARB_color_buffer_float #define _ALLEGRO_GL_ARB_color_buffer_float #define GL_RGBA_FLOAT_MODE_ARB 0x8820 #define GL_CLAMP_VERTEX_COLOR_ARB 0x891A #define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B #define GL_CLAMP_READ_COLOR_ARB 0x891C #define GL_FIXED_ONLY_ARB 0x891D #endif #ifndef GL_ARB_half_float_pixel #define GL_ARB_half_float_pixel #define _ALLEGRO_GL_ARB_half_float_pixel #define GL_HALF_FLOAT_ARB 0x140B #endif #ifndef GL_ARB_texture_float #define GL_ARB_texture_float #define _ALLEGRO_GL_ARB_texture_float #define GL_TEXTURE_RED_TYPE_ARB 0x8C10 #define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 #define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 #define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 #define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 #define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 #define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 #define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 #define GL_RGBA32F_ARB 0x8814 #define GL_RGB32F_ARB 0x8815 #define GL_ALPHA32F_ARB 0x8816 #define GL_INTENSITY32F_ARB 0x8817 #define GL_LUMINANCE32F_ARB 0x8818 #define GL_LUMINANCE_ALPHA32F_ARB 0x8819 #define GL_RGBA16F_ARB 0x881A #define GL_RGB16F_ARB 0x881B #define GL_ALPHA16F_ARB 0x881C #define GL_INTENSITY16F_ARB 0x881D #define GL_LUMINANCE16F_ARB 0x881E #define GL_LUMINANCE_ALPHA16F_ARB 0x881F #endif #ifndef GL_ARB_pixel_buffer_object #define GL_ARB_pixel_buffer_object #define _ALLEGRO_GL_ARB_pixel_buffer_object #define GL_PIXEL_PACK_BUFFER_ARB 0x88EB #define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF #endif #ifndef GL_ARB_depth_buffer_float #define GL_ARB_depth_buffer_float #define _ALLEGRO_GL_ARB_depth_buffer_float #define GL_DEPTH_COMPONENT32F 0x8CAC #define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD #endif #ifndef GL_ARB_draw_instanced #define GL_ARB_draw_instanced #define _ALLEGRO_GL_ARB_draw_instanced #endif #ifndef GL_ARB_framebuffer_object #define GL_ARB_framebuffer_object #define _ALLEGRO_GL_ARB_framebuffer_object #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 #define GL_FRAMEBUFFER_DEFAULT 0x8218 #define GL_FRAMEBUFFER_UNDEFINED 0x8219 #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A #define GL_INDEX 0x8222 #define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_DEPTH_STENCIL 0x84F9 #define GL_UNSIGNED_INT_24_8 0x84FA #define GL_DEPTH24_STENCIL8 0x88F0 #define GL_TEXTURE_STENCIL_SIZE 0x88F1 #define GL_FRAMEBUFFER_BINDING 0x8CA6 #define GL_DRAW_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_READ_FRAMEBUFFER 0x8CA8 #define GL_DRAW_FRAMEBUFFER 0x8CA9 #define GL_READ_FRAMEBUFFER_BINDING 0x8CAA #define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_MAX_COLOR_ATTACHMENTS 0x8CDF #define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_COLOR_ATTACHMENT1 0x8CE1 #define GL_COLOR_ATTACHMENT2 0x8CE2 #define GL_COLOR_ATTACHMENT3 0x8CE3 #define GL_COLOR_ATTACHMENT4 0x8CE4 #define GL_COLOR_ATTACHMENT5 0x8CE5 #define GL_COLOR_ATTACHMENT6 0x8CE6 #define GL_COLOR_ATTACHMENT7 0x8CE7 #define GL_COLOR_ATTACHMENT8 0x8CE8 #define GL_COLOR_ATTACHMENT9 0x8CE9 #define GL_COLOR_ATTACHMENT10 0x8CEA #define GL_COLOR_ATTACHMENT11 0x8CEB #define GL_COLOR_ATTACHMENT12 0x8CEC #define GL_COLOR_ATTACHMENT13 0x8CED #define GL_COLOR_ATTACHMENT14 0x8CEE #define GL_COLOR_ATTACHMENT15 0x8CEF #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_FRAMEBUFFER 0x8D40 #define GL_RENDERBUFFER 0x8D41 #define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERBUFFER_HEIGHT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 #define GL_STENCIL_INDEX1 0x8D46 #define GL_STENCIL_INDEX4 0x8D47 #define GL_STENCIL_INDEX8 0x8D48 #define GL_STENCIL_INDEX16 0x8D49 #define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 #define GL_MAX_SAMPLES 0x8D57 #endif #ifndef GL_ARB_framebuffer_sRGB #define GL_ARB_framebuffer_sRGB #define _ALLEGRO_GL_ARB_framebuffer_sRGB #define GL_FRAMEBUFFER_SRGB 0x8DB9 #endif #ifndef GL_ARB_geometry_shader4 #define GL_ARB_geometry_shader4 #define _ALLEGRO_GL_ARB_geometry_shader4 #define GL_LINES_ADJACENCY_ARB 0x000A #define GL_LINE_STRIP_ADJACENCY_ARB 0x000B #define GL_TRIANGLES_ADJACENCY_ARB 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D #define GL_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 #define GL_GEOMETRY_SHADER_ARB 0x8DD9 #define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA #define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB #define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC #define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD #define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 /* reuse GL_MAX_VARYING_COMPONENTS */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ #endif #ifndef GL_ARB_half_float_vertex #define GL_ARB_half_float_vertex #define _ALLEGRO_GL_ARB_half_float_vertex #define GL_HALF_FLOAT 0x140B #endif #ifndef GL_ARB_instanced_arrays #define GL_ARB_instanced_arrays #define _ALLEGRO_GL_ARB_instanced_arrays #endif #ifndef GL_ARB_map_buffer_range #define GL_ARB_map_buffer_range #define _ALLEGRO_GL_ARB_map_buffer_range #define GL_MAP_READ_BIT 0x0001 #define GL_MAP_WRITE_BIT 0x0002 #define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 #define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 #define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 #define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #endif #ifndef GL_ARB_texture_buffer_object #define GL_ARB_texture_buffer_object #define _ALLEGRO_GL_ARB_texture_buffer_object #define GL_TEXTURE_BUFFER_ARB 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B #define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D #define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E #endif #ifndef GL_ARB_texture_compression_rgtc #define GL_ARB_texture_compression_rgtc #define _ALLEGRO_GL_ARB_texture_compression_rgtc #define GL_COMPRESSED_RED_RGTC1 0x8DBB #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC #define GL_COMPRESSED_RG_RGTC2 0x8DBD #define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE #endif #ifndef GL_ARB_texture_rg #define GL_ARB_texture_rg #define _ALLEGRO_GL_ARB_texture_rg #define GL_RG 0x8227 #define GL_RG_INTEGER 0x8228 #define GL_R8 0x8229 #define GL_R16 0x822A #define GL_RG8 0x822B #define GL_RG16 0x822C #define GL_R16F 0x822D #define GL_R32F 0x822E #define GL_RG16F 0x822F #define GL_RG32F 0x8230 #define GL_R8I 0x8231 #define GL_R8UI 0x8232 #define GL_R16I 0x8233 #define GL_R16UI 0x8234 #define GL_R32I 0x8235 #define GL_R32UI 0x8236 #define GL_RG8I 0x8237 #define GL_RG8UI 0x8238 #define GL_RG16I 0x8239 #define GL_RG16UI 0x823A #define GL_RG32I 0x823B #define GL_RG32UI 0x823C #endif #ifndef GL_ARB_vertex_array_object #define GL_ARB_vertex_array_object #define _ALLEGRO_GL_ARB_vertex_array_object #define GL_VERTEX_ARRAY_BINDING 0x85B5 #endif #ifndef GL_ARB_uniform_buffer_object #define GL_ARB_uniform_buffer_object #define _ALLEGRO_GL_ARB_uniform_buffer_object #define GL_UNIFORM_BUFFER 0x8A11 #define GL_UNIFORM_BUFFER_BINDING 0x8A28 #define GL_UNIFORM_BUFFER_START 0x8A29 #define GL_UNIFORM_BUFFER_SIZE 0x8A2A #define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B #define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C #define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D #define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E #define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F #define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 #define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 #define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 #define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 #define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 #define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 #define GL_UNIFORM_TYPE 0x8A37 #define GL_UNIFORM_SIZE 0x8A38 #define GL_UNIFORM_NAME_LENGTH 0x8A39 #define GL_UNIFORM_BLOCK_INDEX 0x8A3A #define GL_UNIFORM_OFFSET 0x8A3B #define GL_UNIFORM_ARRAY_STRIDE 0x8A3C #define GL_UNIFORM_MATRIX_STRIDE 0x8A3D #define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E #define GL_UNIFORM_BLOCK_BINDING 0x8A3F #define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 #define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 #define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 #define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 #define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 #define GL_INVALID_INDEX 0xFFFFFFFFu #endif #ifndef GL_ARB_compatibility #define GL_ARB_compatibility #define _ALLEGRO_GL_ARB_compatibility /* ARB_compatibility just defines tokens from core 3.0 */ #endif #ifndef GL_ARB_copy_buffer #define GL_ARB_copy_buffer #define _ALLEGRO_GL_ARB_copy_buffer #define GL_COPY_READ_BUFFER 0x8F36 #define GL_COPY_WRITE_BUFFER 0x8F37 #endif #ifndef GL_ARB_shader_texture_lod #define GL_ARB_shader_texture_lod #define _ALLEGRO_GL_ARB_shader_texture_lod #endif #ifndef GL_ARB_depth_clamp #define GL_ARB_depth_clamp #define _ALLEGRO_GL_ARB_depth_clamp #define GL_DEPTH_CLAMP 0x864F #endif #ifndef GL_ARB_draw_elements_base_vertex #define GL_ARB_draw_elements_base_vertex #define _ALLEGRO_GL_ARB_draw_elements_base_vertex #endif #ifndef GL_ARB_fragment_coord_conventions #define GL_ARB_fragment_coord_conventions #define _ALLEGRO_GL_ARB_fragment_coord_conventions #endif #ifndef GL_ARB_provoking_vertex #define GL_ARB_provoking_vertex #define _ALLEGRO_GL_ARB_provoking_vertex #define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C #define GL_FIRST_VERTEX_CONVENTION 0x8E4D #define GL_LAST_VERTEX_CONVENTION 0x8E4E #define GL_PROVOKING_VERTEX 0x8E4F #endif #ifndef GL_ARB_seamless_cube_map #define GL_ARB_seamless_cube_map #define _ALLEGRO_GL_ARB_seamless_cube_map #define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F #endif #ifndef GL_ARB_sync #define GL_ARB_sync #define _ALLEGRO_GL_ARB_sync typedef struct __GLsync *GLsync; #define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 #define GL_OBJECT_TYPE 0x9112 #define GL_SYNC_CONDITION 0x9113 #define GL_SYNC_STATUS 0x9114 #define GL_SYNC_FLAGS 0x9115 #define GL_SYNC_FENCE 0x9116 #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 #define GL_UNSIGNALED 0x9118 #define GL_SIGNALED 0x9119 #define GL_ALREADY_SIGNALED 0x911A #define GL_TIMEOUT_EXPIRED 0x911B #define GL_CONDITION_SATISFIED 0x911C #define GL_WAIT_FAILED 0x911D #define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 #define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull #endif #ifndef GL_ARB_texture_multisample #define GL_ARB_texture_multisample #define _ALLEGRO_GL_ARB_texture_multisample #define GL_SAMPLE_POSITION 0x8E50 #define GL_SAMPLE_MASK 0x8E51 #define GL_SAMPLE_MASK_VALUE 0x8E52 #define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 #define GL_TEXTURE_2D_MULTISAMPLE 0x9100 #define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 #define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 #define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 #define GL_TEXTURE_SAMPLES 0x9106 #define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 #define GL_SAMPLER_2D_MULTISAMPLE 0x9108 #define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A #define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B #define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D #define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E #define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F #define GL_MAX_INTEGER_SAMPLES 0x9110 #endif #ifndef GL_ARB_vertex_array_bgra #define GL_ARB_vertex_array_bgra #define _ALLEGRO_GL_ARB_vertex_array_bgra /* reuse GL_BGRA */ #endif #ifndef GL_ARB_draw_buffers_blend #define GL_ARB_draw_buffers_blend #define _ALLEGRO_GL_ARB_draw_buffers_blend #endif #ifndef GL_ARB_sample_shading #define GL_ARB_sample_shading #define _ALLEGRO_GL_ARB_sample_shading #define GL_SAMPLE_SHADING 0x8C36 #define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 #endif #ifndef GL_ARB_texture_cube_map_array #define GL_ARB_texture_cube_map_array #define _ALLEGRO_GL_ARB_texture_cube_map_array #define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 #define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A #define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B #define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D #define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F #endif #ifndef GL_ARB_texture_gather #define GL_ARB_texture_gather #define _ALLEGRO_GL_ARB_texture_gather #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F #endif #ifndef GL_ARB_texture_query_lod #define GL_ARB_texture_query_lod #define _ALLEGRO_GL_ARB_texture_query_lod #endif #ifndef GL_ARB_shading_language_include #define GL_ARB_shading_language_include #define _ALLEGRO_GL_ARB_shading_language_include #define GL_SHADER_INCLUDE_ARB 0x8DAE #define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 #define GL_NAMED_STRING_TYPE_ARB 0x8DEA #endif #ifndef GL_ARB_texture_compression_bptc #define GL_ARB_texture_compression_bptc #define _ALLEGRO_GL_ARB_texture_compression_bptc #define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C #define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F #endif #ifndef GL_ARB_blend_func_extended #define GL_ARB_blend_func_extended #define _ALLEGRO_GL_ARB_blend_func_extended #define GL_SRC1_COLOR 0x88F9 /* reuse GL_SRC1_ALPHA */ #define GL_ONE_MINUS_SRC1_COLOR 0x88FA #define GL_ONE_MINUS_SRC1_ALPHA 0x88FB #define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC #endif #ifndef GL_ARB_explicit_attrib_location #define GL_ARB_explicit_attrib_location #define _ALLEGRO_GL_ARB_explicit_attrib_location #endif #ifndef GL_ARB_occlusion_query2 #define GL_ARB_occlusion_query2 #define _ALLEGRO_GL_ARB_occlusion_query2 #define GL_ANY_SAMPLES_PASSED 0x8C2F #endif #ifndef GL_ARB_sampler_objects #define GL_ARB_sampler_objects #define _ALLEGRO_GL_ARB_sampler_objects #define GL_SAMPLER_BINDING 0x8919 #endif #ifndef GL_ARB_shader_bit_encoding #define GL_ARB_shader_bit_encoding #define _ALLEGRO_GL_ARB_shader_bit_encoding #endif #ifndef GL_ARB_texture_rgb10_a2ui #define GL_ARB_texture_rgb10_a2ui #define _ALLEGRO_GL_ARB_texture_rgb10_a2ui #define GL_RGB10_A2UI 0x906F #endif #ifndef GL_ARB_texture_swizzle #define GL_ARB_texture_swizzle #define _ALLEGRO_GL_ARB_texture_swizzle #define GL_TEXTURE_SWIZZLE_R 0x8E42 #define GL_TEXTURE_SWIZZLE_G 0x8E43 #define GL_TEXTURE_SWIZZLE_B 0x8E44 #define GL_TEXTURE_SWIZZLE_A 0x8E45 #define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 #endif #ifndef GL_ARB_timer_query #define GL_ARB_timer_query #define _ALLEGRO_GL_ARB_timer_query #define GL_TIME_ELAPSED 0x88BF #define GL_TIMESTAMP 0x8E28 #endif #ifndef GL_ARB_vertex_type_2_10_10_10_rev #define GL_ARB_vertex_type_2_10_10_10_rev #define _ALLEGRO_GL_ARB_vertex_type_2_10_10_10_rev /* reuse GL_UNSIGNED_INT_2_10_10_10_REV */ #define GL_INT_2_10_10_10_REV 0x8D9F #endif #ifndef GL_ARB_draw_indirect #define GL_ARB_draw_indirect #define _ALLEGRO_GL_ARB_draw_indirect #define GL_DRAW_INDIRECT_BUFFER 0x8F3F #define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 #endif #ifndef GL_ARB_gpu_shader5 #define GL_ARB_gpu_shader5 #define _ALLEGRO_GL_ARB_gpu_shader5 #define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F #define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A #define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B #define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C #define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D #define GL_MAX_VERTEX_STREAMS 0x8E71 #endif #ifndef GL_ARB_gpu_shader_fp64 #define GL_ARB_gpu_shader_fp64 #define _ALLEGRO_GL_ARB_gpu_shader_fp64 /* reuse GL_DOUBLE */ #define GL_DOUBLE_VEC2 0x8FFC #define GL_DOUBLE_VEC3 0x8FFD #define GL_DOUBLE_VEC4 0x8FFE #define GL_DOUBLE_MAT2 0x8F46 #define GL_DOUBLE_MAT3 0x8F47 #define GL_DOUBLE_MAT4 0x8F48 #define GL_DOUBLE_MAT2x3 0x8F49 #define GL_DOUBLE_MAT2x4 0x8F4A #define GL_DOUBLE_MAT3x2 0x8F4B #define GL_DOUBLE_MAT3x4 0x8F4C #define GL_DOUBLE_MAT4x2 0x8F4D #define GL_DOUBLE_MAT4x3 0x8F4E #endif #ifndef GL_ARB_shader_subroutine #define GL_ARB_shader_subroutine #define _ALLEGRO_GL_ARB_shader_subroutine #define GL_ACTIVE_SUBROUTINES 0x8DE5 #define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 #define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 #define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 #define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 #define GL_MAX_SUBROUTINES 0x8DE7 #define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 #define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A #define GL_COMPATIBLE_SUBROUTINES 0x8E4B /* reuse GL_UNIFORM_SIZE */ /* reuse GL_UNIFORM_NAME_LENGTH */ #endif #ifndef GL_ARB_tessellation_shader #define GL_ARB_tessellation_shader #define _ALLEGRO_GL_ARB_tessellation_shader #define GL_PATCHES 0x000E #define GL_PATCH_VERTICES 0x8E72 #define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 #define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 #define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 #define GL_TESS_GEN_MODE 0x8E76 #define GL_TESS_GEN_SPACING 0x8E77 #define GL_TESS_GEN_VERTEX_ORDER 0x8E78 #define GL_TESS_GEN_POINT_MODE 0x8E79 /* reuse GL_TRIANGLES */ /* reuse GL_QUADS */ #define GL_ISOLINES 0x8E7A /* reuse GL_EQUAL */ #define GL_FRACTIONAL_ODD 0x8E7B #define GL_FRACTIONAL_EVEN 0x8E7C /* reuse GL_CCW */ /* reuse GL_CW */ #define GL_MAX_PATCH_VERTICES 0x8E7D #define GL_MAX_TESS_GEN_LEVEL 0x8E7E #define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F #define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 #define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 #define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 #define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 #define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 #define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 #define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 #define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 #define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A #define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C #define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D #define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E #define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F #define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 #define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 #define GL_TESS_EVALUATION_SHADER 0x8E87 #define GL_TESS_CONTROL_SHADER 0x8E88 #endif #ifndef GL_ARB_texture_buffer_object_rgb32 #define GL_ARB_texture_buffer_object_rgb32 #define _ALLEGRO_GL_ARB_texture_buffer_object_rgb32 /* reuse GL_RGB32F */ /* reuse GL_RGB32UI */ /* reuse GL_RGB32I */ #endif #ifndef GL_ARB_transform_feedback2 #define GL_ARB_transform_feedback2 #define _ALLEGRO_GL_ARB_transform_feedback2 #define GL_TRANSFORM_FEEDBACK 0x8E22 #define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 #define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 #define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 #endif #ifndef GL_ARB_transform_feedback3 #define GL_ARB_transform_feedback3 #define _ALLEGRO_GL_ARB_transform_feedback3 #define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 #endif /* */ #ifndef GL_EXT_abgr #define GL_EXT_abgr #define _ALLEGRO_GL_EXT_abgr #define GL_ABGR_EXT 0x8000 #endif #ifndef GL_EXT_blend_color #define GL_EXT_blend_color #define _ALLEGRO_GL_EXT_blend_color #define GL_CONSTANT_COLOR_EXT 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 #define GL_CONSTANT_ALPHA_EXT 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 #define GL_BLEND_COLOR_EXT 0x8005 #endif #ifndef GL_EXT_polygon_offset #define GL_EXT_polygon_offset #define _ALLEGRO_GL_EXT_polygon_offset #define GL_POLYGON_OFFSET_EXT 0x8037 #define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 #define GL_POLYGON_OFFSET_BIAS_EXT 0x8039 #endif #ifndef GL_EXT_texture #define GL_EXT_texture #define _ALLEGRO_GL_EXT_texture #define GL_ALPHA4_EXT 0x803B #define GL_ALPHA8_EXT 0x803C #define GL_ALPHA12_EXT 0x803D #define GL_ALPHA16_EXT 0x803E #define GL_LUMINANCE4_EXT 0x803F #define GL_LUMINANCE8_EXT 0x8040 #define GL_LUMINANCE12_EXT 0x8041 #define GL_LUMINANCE16_EXT 0x8042 #define GL_LUMINANCE4_ALPHA4_EXT 0x8043 #define GL_LUMINANCE6_ALPHA2_EXT 0x8044 #define GL_LUMINANCE8_ALPHA8_EXT 0x8045 #define GL_LUMINANCE12_ALPHA4_EXT 0x8046 #define GL_LUMINANCE12_ALPHA12_EXT 0x8047 #define GL_LUMINANCE16_ALPHA16_EXT 0x8048 #define GL_INTENSITY_EXT 0x8049 #define GL_INTENSITY4_EXT 0x804A #define GL_INTENSITY8_EXT 0x804B #define GL_INTENSITY12_EXT 0x804C #define GL_INTENSITY16_EXT 0x804D #define GL_RGB2_EXT 0x804E #define GL_RGB4_EXT 0x804F #define GL_RGB5_EXT 0x8050 #define GL_RGB8_EXT 0x8051 #define GL_RGB10_EXT 0x8052 #define GL_RGB12_EXT 0x8053 #define GL_RGB16_EXT 0x8054 #define GL_RGBA2_EXT 0x8055 #define GL_RGBA4_EXT 0x8056 #define GL_RGB5_A1_EXT 0x8057 #define GL_RGBA8_EXT 0x8058 #define GL_RGB10_A2_EXT 0x8059 #define GL_RGBA12_EXT 0x805A #define GL_RGBA16_EXT 0x805B #define GL_TEXTURE_RED_SIZE_EXT 0x805C #define GL_TEXTURE_GREEN_SIZE_EXT 0x805D #define GL_TEXTURE_BLUE_SIZE_EXT 0x805E #define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F #define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 #define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 #define GL_REPLACE_EXT 0x8062 #define GL_PROXY_TEXTURE_1D_EXT 0x8063 #define GL_PROXY_TEXTURE_2D_EXT 0x8064 #define GL_TEXTURE_TOO_LARGE_EXT 0x8065 #endif #ifndef GL_EXT_texture3D #define GL_EXT_texture3D #define _ALLEGRO_GL_EXT_texture3D #define GL_PACK_SKIP_IMAGES_EXT 0x806B #define GL_PACK_IMAGE_HEIGHT_EXT 0x806C #define GL_UNPACK_SKIP_IMAGES_EXT 0x806D #define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E #define GL_TEXTURE_3D_EXT 0x806F #define GL_PROXY_TEXTURE_3D_EXT 0x8070 #define GL_TEXTURE_DEPTH_EXT 0x8071 #define GL_TEXTURE_WRAP_R_EXT 0x8072 #define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 #endif #ifndef GL_SGIS_texture_filter4 #define GL_SGIS_texture_filter4 #define _ALLEGRO_GL_SGIS_texture_filter4 #define GL_FILTER4_SGIS 0x8146 #define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 #endif #ifndef GL_EXT_histogram #define GL_EXT_histogram #define _ALLEGRO_GL_EXT_histogram #define GL_HISTOGRAM_EXT 0x8024 #define GL_PROXY_HISTOGRAM_EXT 0x8025 #define GL_HISTOGRAM_WIDTH_EXT 0x8026 #define GL_HISTOGRAM_FORMAT_EXT 0x8027 #define GL_HISTOGRAM_RED_SIZE_EXT 0x8028 #define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 #define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A #define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B #define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C #define GL_HISTOGRAM_SINK_EXT 0x802D #define GL_MINMAX_EXT 0x802E #define GL_MINMAX_FORMAT_EXT 0x802F #define GL_MINMAX_SINK_EXT 0x8030 #define GL_TABLE_TOO_LARGE_EXT 0x8031 #endif #ifndef GL_EXT_subtexture #define GL_EXT_subtexture #define _ALLEGRO_GL_EXT_subtexture #endif #ifndef GL_EXT_copy_texture #define GL_EXT_copy_texture /* NV's headers don't define EXT_copy_texture yet provide the API */ #ifndef ALLEGRO_GL_HEADER_NV #define _ALLEGRO_GL_EXT_copy_texture #endif #endif #ifndef GL_EXT_histogram #define GL_EXT_histogram #define _ALLEGRO_GL_EXT_histogram #endif #ifndef GL_EXT_convolution #define GL_EXT_convolution #define _ALLEGRO_GL_EXT_convolution #define GL_CONVOLUTION_1D_EXT 0x8010 #define GL_CONVOLUTION_2D_EXT 0x8011 #define GL_SEPARABLE_2D_EXT 0x8012 #define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 #define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 #define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 #define GL_REDUCE_EXT 0x8016 #define GL_CONVOLUTION_FORMAT_EXT 0x8017 #define GL_CONVOLUTION_WIDTH_EXT 0x8018 #define GL_CONVOLUTION_HEIGHT_EXT 0x8019 #define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A #define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B #define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C #define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D #define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E #define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F #define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 #define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 #define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 #define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 #endif #ifndef GL_SGI_color_matrix #define GL_SGI_color_matrix #define _ALLEGRO_GL_SGI_color_matrix #define GL_COLOR_MATRIX_SGI 0x80B1 #define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 #define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 #define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 #define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 #define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 #define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 #define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 #define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 #define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA #define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB #endif #ifndef GL_SGI_color_table #define GL_SGI_color_table #define _ALLEGRO_GL_SGI_color_table #define GL_COLOR_TABLE_SGI 0x80D0 #define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 #define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 #define GL_PROXY_COLOR_TABLE_SGI 0x80D3 #define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 #define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 #define GL_COLOR_TABLE_SCALE_SGI 0x80D6 #define GL_COLOR_TABLE_BIAS_SGI 0x80D7 #define GL_COLOR_TABLE_FORMAT_SGI 0x80D8 #define GL_COLOR_TABLE_WIDTH_SGI 0x80D9 #define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA #define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB #define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC #define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD #define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE #define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF #endif #ifndef GL_SGIS_pixel_texture #define GL_SGIS_pixel_texture #define _ALLEGRO_GL_SGIS_pixel_texture #define GL_PIXEL_TEXTURE_SGIS 0x8353 #define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 #define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 #define GL_PIXEL_GROUP_COLOR_SGIS 0x8356 #endif #ifndef GL_SGIX_pixel_texture #define GL_SGIX_pixel_texture #define _ALLEGRO_GL_SGIX_pixel_texture #define GL_PIXEL_TEX_GEN_SGIX 0x8139 #define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B #endif #ifndef GL_SGIS_texture4D #define GL_SGIS_texture4D #define _ALLEGRO_GL_SGIS_texture4D #define GL_PACK_SKIP_VOLUMES_SGIS 0x8130 #define GL_PACK_IMAGE_DEPTH_SGIS 0x8131 #define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 #define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 #define GL_TEXTURE_4D_SGIS 0x8134 #define GL_PROXY_TEXTURE_4D_SGIS 0x8135 #define GL_TEXTURE_4DSIZE_SGIS 0x8136 #define GL_TEXTURE_WRAP_Q_SGIS 0x8137 #define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 #define GL_TEXTURE_4D_BINDING_SGIS 0x814F #endif #ifndef GL_SGI_texture_color_table #define GL_SGI_texture_color_table #define _ALLEGRO_GL_SGI_texture_color_table #define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC #define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD #endif #ifndef GL_EXT_cmyka #define GL_EXT_cmyka #define _ALLEGRO_GL_EXT_cmyka #define GL_CMYK_EXT 0x800C #define GL_CMYKA_EXT 0x800D #define GL_PACK_CMYK_HINT_EXT 0x800E #define GL_UNPACK_CMYK_HINT_EXT 0x800F #endif #ifndef GL_EXT_texture_object #define GL_EXT_texture_object #define _ALLEGRO_GL_EXT_texture_object #define GL_TEXTURE_PRIORITY_EXT 0x8066 #define GL_TEXTURE_RESIDENT_EXT 0x8067 #define GL_TEXTURE_1D_BINDING_EXT 0x8068 #define GL_TEXTURE_2D_BINDING_EXT 0x8069 #define GL_TEXTURE_3D_BINDING_EXT 0x806A #endif #ifndef GL_SGIS_detail_texture #define GL_SGIS_detail_texture #define _ALLEGRO_GL_SGIS_detail_texture #define GL_DETAIL_TEXTURE_2D_SGIS 0x8095 #define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 #define GL_LINEAR_DETAIL_SGIS 0x8097 #define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 #define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 #define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A #define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B #define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C #endif #ifndef GL_SGIS_sharpen_texture #define GL_SGIS_sharpen_texture #define _ALLEGRO_GL_SGIS_sharpen_texture #define GL_LINEAR_SHARPEN_SGIS 0x80AD #define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE #define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF #define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 #endif #ifndef GL_EXT_packed_pixels #define GL_EXT_packed_pixels #define _ALLEGRO_GL_EXT_packed_pixels #define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 #define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 #define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 #define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 #endif #ifndef GL_SGIS_texture_lod #define GL_SGIS_texture_lod #define _ALLEGRO_GL_SGIS_texture_lod #define GL_TEXTURE_MIN_LOD_SGIS 0x813A #define GL_TEXTURE_MAX_LOD_SGIS 0x813B #define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C #define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D #endif #ifndef GL_SGIS_multisample #define GL_SGIS_multisample #define _ALLEGRO_GL_SGIS_multisample #define GL_MULTISAMPLE_SGIS 0x809D #define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F #define GL_SAMPLE_MASK_SGIS 0x80A0 #define GL_1PASS_SGIS 0x80A1 #define GL_2PASS_0_SGIS 0x80A2 #define GL_2PASS_1_SGIS 0x80A3 #define GL_4PASS_0_SGIS 0x80A4 #define GL_4PASS_1_SGIS 0x80A5 #define GL_4PASS_2_SGIS 0x80A6 #define GL_4PASS_3_SGIS 0x80A7 #define GL_SAMPLE_BUFFERS_SGIS 0x80A8 #define GL_SAMPLES_SGIS 0x80A9 #define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA #define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB #define GL_SAMPLE_PATTERN_SGIS 0x80AC #endif #ifndef GL_EXT_rescale_normal #define GL_EXT_rescale_normal #define _ALLEGRO_GL_EXT_rescale_normal #define GL_RESCALE_NORMAL_EXT 0x803A #endif #ifndef GL_EXT_vertex_array #define GL_EXT_vertex_array #define _ALLEGRO_GL_EXT_vertex_array #define GL_VERTEX_ARRAY_EXT 0x8074 #define GL_NORMAL_ARRAY_EXT 0x8075 #define GL_COLOR_ARRAY_EXT 0x8076 #define GL_INDEX_ARRAY_EXT 0x8077 #define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 #define GL_EDGE_FLAG_ARRAY_EXT 0x8079 #define GL_VERTEX_ARRAY_SIZE_EXT 0x807A #define GL_VERTEX_ARRAY_TYPE_EXT 0x807B #define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C #define GL_VERTEX_ARRAY_COUNT_EXT 0x807D #define GL_NORMAL_ARRAY_TYPE_EXT 0x807E #define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F #define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 #define GL_COLOR_ARRAY_SIZE_EXT 0x8081 #define GL_COLOR_ARRAY_TYPE_EXT 0x8082 #define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 #define GL_COLOR_ARRAY_COUNT_EXT 0x8084 #define GL_INDEX_ARRAY_TYPE_EXT 0x8085 #define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 #define GL_INDEX_ARRAY_COUNT_EXT 0x8087 #define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 #define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 #define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A #define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B #define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C #define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D #define GL_VERTEX_ARRAY_POINTER_EXT 0x808E #define GL_NORMAL_ARRAY_POINTER_EXT 0x808F #define GL_COLOR_ARRAY_POINTER_EXT 0x8090 #define GL_INDEX_ARRAY_POINTER_EXT 0x8091 #define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 #define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 #endif #ifndef GL_SGIS_generate_mipmap #define GL_SGIS_generate_mipmap #define _ALLEGRO_GL_SGIS_generate_mipmap #define GL_GENERATE_MIPMAP_SGIS 0x8191 #define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 #endif #ifndef GL_SGIX_clipmap #define GL_SGIX_clipmap #define _ALLEGRO_GL_SGIX_clipmap #define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 #define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 #define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 #define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 #define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 #define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 #define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 #define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 #define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 #define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D #define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E #define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F #endif #ifndef GL_SGIX_shadow #define GL_SGIX_shadow #define _ALLEGRO_GL_SGIX_shadow #define GL_TEXTURE_COMPARE_SGIX 0x819A #define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B #define GL_TEXTURE_LEQUAL_R_SGIX 0x819C #define GL_TEXTURE_GEQUAL_R_SGIX 0x819D #endif #ifndef GL_SGIS_texture_edge_clamp #define GL_SGIS_texture_edge_clamp #define _ALLEGRO_GL_SGIS_texture_edge_clamp #define GL_CLAMP_TO_EDGE_SGIS 0x812F #endif #ifndef GL_EXT_blend_minmax #define GL_EXT_blend_minmax #define _ALLEGRO_GL_EXT_blend_minmax #define GL_FUNC_ADD_EXT 0x8006 #define GL_MIN_EXT 0x8007 #define GL_MAX_EXT 0x8008 #define GL_BLEND_EQUATION_EXT 0x8009 #endif #ifndef GL_EXT_blend_subtract #define GL_EXT_blend_subtract #define _ALLEGRO_GL_EXT_blend_subtract #define GL_FUNC_SUBTRACT_EXT 0x800A #define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B #endif #ifndef GL_SGIX_interlace #define GL_SGIX_interlace #define _ALLEGRO_GL_SGIX_interlace #define GL_INTERLACE_SGIX 0x8094 #endif #ifndef GL_SGIX_pixel_tiles #define GL_SGIX_pixel_tiles #define _ALLEGRO_GL_SGIX_pixel_tiles #define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E #define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F #define GL_PIXEL_TILE_WIDTH_SGIX 0x8140 #define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 #define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 #define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 #define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 #define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 #endif #ifndef GL_SGIS_texture_select #define GL_SGIS_texture_select #define _ALLEGRO_GL_SGIS_texture_select #define GL_DUAL_ALPHA4_SGIS 0x8110 #define GL_DUAL_ALPHA8_SGIS 0x8111 #define GL_DUAL_ALPHA12_SGIS 0x8112 #define GL_DUAL_ALPHA16_SGIS 0x8113 #define GL_DUAL_LUMINANCE4_SGIS 0x8114 #define GL_DUAL_LUMINANCE8_SGIS 0x8115 #define GL_DUAL_LUMINANCE12_SGIS 0x8116 #define GL_DUAL_LUMINANCE16_SGIS 0x8117 #define GL_DUAL_INTENSITY4_SGIS 0x8118 #define GL_DUAL_INTENSITY8_SGIS 0x8119 #define GL_DUAL_INTENSITY12_SGIS 0x811A #define GL_DUAL_INTENSITY16_SGIS 0x811B #define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C #define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D #define GL_QUAD_ALPHA4_SGIS 0x811E #define GL_QUAD_ALPHA8_SGIS 0x811F #define GL_QUAD_LUMINANCE4_SGIS 0x8120 #define GL_QUAD_LUMINANCE8_SGIS 0x8121 #define GL_QUAD_INTENSITY4_SGIS 0x8122 #define GL_QUAD_INTENSITY8_SGIS 0x8123 #define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 #define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 #endif #ifndef GL_SGIX_sprite #define GL_SGIX_sprite #define _ALLEGRO_GL_SGIX_sprite #define GL_SPRITE_SGIX 0x8148 #define GL_SPRITE_MODE_SGIX 0x8149 #define GL_SPRITE_AXIS_SGIX 0x814A #define GL_SPRITE_TRANSLATION_SGIX 0x814B #define GL_SPRITE_AXIAL_SGIX 0x814C #define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D #define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E #endif #ifndef GL_SGIX_texture_multi_buffer #define GL_SGIX_texture_multi_buffer #define _ALLEGRO_GL_SGIX_texture_multi_buffer #define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E #endif #ifndef GL_EXT_point_parameters #define GL_EXT_point_parameters #define _ALLEGRO_GL_EXT_point_parameters #define GL_POINT_SIZE_MIN_EXT 0x8126 #define GL_POINT_SIZE_MAX_EXT 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 #define GL_DISTANCE_ATTENUATION_EXT 0x8129 #endif #ifndef GL_SGIS_point_parameters #define GL_SGIS_point_parameters #define _ALLEGRO_GL_SGIS_point_parameters #define GL_POINT_SIZE_MIN_SGIS 0x8126 #define GL_POINT_SIZE_MAX_SGIS 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 #define GL_DISTANCE_ATTENUATION_SGIS 0x8129 #endif #ifndef GL_SGIX_instruments #define GL_SGIX_instruments #define _ALLEGRO_GL_SGIX_instruments #define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 #define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 #endif #ifndef GL_SGIX_texture_scale_bias #define GL_SGIX_texture_scale_bias #define _ALLEGRO_GL_SGIX_texture_scale_bias #define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 #define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A #define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B #define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C #endif #ifndef GL_SGIX_framezoom #define GL_SGIX_framezoom #define _ALLEGRO_GL_SGIX_framezoom #define GL_FRAMEZOOM_SGIX 0x818B #define GL_FRAMEZOOM_FACTOR_SGIX 0x818C #define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D #endif #ifndef GL_FfdMaskSGIX #define GL_FfdMaskSGIX #define _ALLEGRO_GL_FfdMaskSGIX #define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 #define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 #endif #ifndef GL_SGIX_tag_sample_buffer #define GL_SGIX_tag_sample_buffer #define _ALLEGRO_GL_SGIX_tag_sample_buffer #endif #ifndef GL_SGIX_polynomial_ffd #define GL_SGIX_polynomial_ffd #define _ALLEGRO_GL_SGIX_polynomial_ffd #define GL_GEOMETRY_DEFORMATION_SGIX 0x8194 #define GL_TEXTURE_DEFORMATION_SGIX 0x8195 #define GL_DEFORMATIONS_MASK_SGIX 0x8196 #define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 #endif #ifndef GL_SGIX_reference_plane #define GL_SGIX_reference_plane #define _ALLEGRO_GL_SGIX_reference_plane #define GL_REFERENCE_PLANE_SGIX 0x817D #define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E #endif #ifndef GL_SGIX_depth_texture #define GL_SGIX_depth_texture #define _ALLEGRO_GL_SGIX_depth_texture #define GL_DEPTH_COMPONENT16_SGIX 0x81A5 #define GL_DEPTH_COMPONENT24_SGIX 0x81A6 #define GL_DEPTH_COMPONENT32_SGIX 0x81A7 #endif #ifndef GL_SGIX_flush_raster #define GL_SGIX_flush_raster #define _ALLEGRO_GL_SGIX_flush_raster #endif #ifndef GL_SGIS_fog_function #define GL_SGIS_fog_function #define _ALLEGRO_GL_SGIS_fog_function #define GL_FOG_FUNC_SGIS 0x812A #define GL_FOG_FUNC_POINTS_SGIS 0x812B #define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C #endif #ifndef GL_SGIX_fog_offset #define GL_SGIX_fog_offset #define _ALLEGRO_GL_SGIX_fog_offset #define GL_FOG_OFFSET_SGIX 0x8198 #define GL_FOG_OFFSET_VALUE_SGIX 0x8199 #endif #ifndef GL_HP_image_transform #define GL_HP_image_transform #define _ALLEGRO_GL_HP_image_transform #define GL_IMAGE_SCALE_X_HP 0x8155 #define GL_IMAGE_SCALE_Y_HP 0x8156 #define GL_IMAGE_TRANSLATE_X_HP 0x8157 #define GL_IMAGE_TRANSLATE_Y_HP 0x8158 #define GL_IMAGE_ROTATE_ANGLE_HP 0x8159 #define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A #define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B #define GL_IMAGE_MAG_FILTER_HP 0x815C #define GL_IMAGE_MIN_FILTER_HP 0x815D #define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E #define GL_CUBIC_HP 0x815F #define GL_AVERAGE_HP 0x8160 #define GL_IMAGE_TRANSFORM_2D_HP 0x8161 #define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 #define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 #endif #ifndef GL_HP_convolution_border_modes #define GL_HP_convolution_border_modes #define _ALLEGRO_GL_HP_convolution_border_modes #define GL_IGNORE_BORDER_HP 0x8150 #define GL_CONSTANT_BORDER_HP 0x8151 #define GL_REPLICATE_BORDER_HP 0x8153 #define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 #endif #ifndef GL_SGIX_texture_add_env #define GL_SGIX_texture_add_env #define _ALLEGRO_GL_SGIX_texture_add_env #define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE #endif #ifndef GL_EXT_color_subtable #define GL_EXT_color_subtable #define _ALLEGRO_GL_EXT_color_subtable #endif #ifndef GL_PGI_vertex_hints #define GL_PGI_vertex_hints #define _ALLEGRO_GL_PGI_vertex_hints #define GL_VERTEX_DATA_HINT_PGI 0x1A22A #define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B #define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C #define GL_MAX_VERTEX_HINT_PGI 0x1A22D #define GL_COLOR3_BIT_PGI 0x00010000 #define GL_COLOR4_BIT_PGI 0x00020000 #define GL_EDGEFLAG_BIT_PGI 0x00040000 #define GL_INDEX_BIT_PGI 0x00080000 #define GL_MAT_AMBIENT_BIT_PGI 0x00100000 #define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 #define GL_MAT_DIFFUSE_BIT_PGI 0x00400000 #define GL_MAT_EMISSION_BIT_PGI 0x00800000 #define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 #define GL_MAT_SHININESS_BIT_PGI 0x02000000 #define GL_MAT_SPECULAR_BIT_PGI 0x04000000 #define GL_NORMAL_BIT_PGI 0x08000000 #define GL_TEXCOORD1_BIT_PGI 0x10000000 #define GL_TEXCOORD2_BIT_PGI 0x20000000 #define GL_TEXCOORD3_BIT_PGI 0x40000000 #define GL_TEXCOORD4_BIT_PGI 0x80000000 #define GL_VERTEX23_BIT_PGI 0x00000004 #define GL_VERTEX4_BIT_PGI 0x00000008 #endif #ifndef GL_PGI_misc_hints #define GL_PGI_misc_hints #define _ALLEGRO_GL_PGI_misc_hints #define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 #define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD #define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE #define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 #define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 #define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 #define GL_ALWAYS_FAST_HINT_PGI 0x1A20C #define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D #define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E #define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F #define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 #define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 #define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 #define GL_STRICT_LIGHTING_HINT_PGI 0x1A217 #define GL_STRICT_SCISSOR_HINT_PGI 0x1A218 #define GL_FULL_STIPPLE_HINT_PGI 0x1A219 #define GL_CLIP_NEAR_HINT_PGI 0x1A220 #define GL_CLIP_FAR_HINT_PGI 0x1A221 #define GL_WIDE_LINE_HINT_PGI 0x1A222 #define GL_BACK_NORMALS_HINT_PGI 0x1A223 #endif #ifndef GL_EXT_paletted_texture #define GL_EXT_paletted_texture #define _ALLEGRO_GL_EXT_paletted_texture #define GL_COLOR_INDEX1_EXT 0x80E2 #define GL_COLOR_INDEX2_EXT 0x80E3 #define GL_COLOR_INDEX4_EXT 0x80E4 #define GL_COLOR_INDEX8_EXT 0x80E5 #define GL_COLOR_INDEX12_EXT 0x80E6 #define GL_COLOR_INDEX16_EXT 0x80E7 #define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED #endif #ifndef GL_EXT_clip_volume_hint #define GL_EXT_clip_volume_hint #define _ALLEGRO_GL_EXT_clip_volume_hint #define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 #endif #ifndef GL_SGIX_list_priority #define GL_SGIX_list_priority #define _ALLEGRO_GL_SGIX_list_priority #define GL_LIST_PRIORITY_SGIX 0x8182 #endif #ifndef GL_SGIX_ir_instrument1 #define GL_SGIX_ir_instrument1 #define _ALLEGRO_GL_SGIX_ir_instrument1 #define GL_IR_INSTRUMENT1_SGIX 0x817F #endif #ifndef GL_SGIX_calligraphic_fragment #define GL_SGIX_calligraphic_fragment #define _ALLEGRO_GL_SGIX_calligraphic_fragment #define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 #endif #ifndef GL_SGIX_texture_lod_bias #define GL_SGIX_texture_lod_bias #define _ALLEGRO_GL_SGIX_texture_lod_bias #define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E #define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F #define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 #endif #ifndef GL_SGIX_shadow_ambient #define GL_SGIX_shadow_ambient #define _ALLEGRO_GL_SGIX_shadow_ambient #define GL_SHADOW_AMBIENT_SGIX 0x80BF #endif #ifndef GL_EXT_index_material #define GL_EXT_index_material #define _ALLEGRO_GL_EXT_index_material #define GL_INDEX_MATERIAL_EXT 0x81B8 #define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 #define GL_INDEX_MATERIAL_FACE_EXT 0x81BA #endif #ifndef GL_EXT_index_func #define GL_EXT_index_func #define _ALLEGRO_GL_EXT_index_func #define GL_INDEX_TEST_EXT 0x81B5 #define GL_INDEX_TEST_FUNC_EXT 0x81B6 #define GL_INDEX_TEST_REF_EXT 0x81B7 #endif #ifndef GL_EXT_index_array_formats #define GL_EXT_index_array_formats #define _ALLEGRO_GL_EXT_index_array_formats #define GL_IUI_V2F_EXT 0x81AD #define GL_IUI_V3F_EXT 0x81AE #define GL_IUI_N3F_V2F_EXT 0x81AF #define GL_IUI_N3F_V3F_EXT 0x81B0 #define GL_T2F_IUI_V2F_EXT 0x81B1 #define GL_T2F_IUI_V3F_EXT 0x81B2 #define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 #define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 #endif #ifndef GL_EXT_compiled_vertex_array #define GL_EXT_compiled_vertex_array #define _ALLEGRO_GL_EXT_compiled_vertex_array #define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 #define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 #endif #ifndef GL_EXT_cull_vertex #define GL_EXT_cull_vertex #define _ALLEGRO_GL_EXT_cull_vertex #define GL_CULL_VERTEX_EXT 0x81AA #define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB #define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC #endif #ifndef GL_SGIX_ycrcb #define GL_SGIX_ycrcb #define _ALLEGRO_GL_SGIX_ycrcb #define GL_YCRCB_422_SGIX 0x81BB #define GL_YCRCB_444_SGIX 0x81BC #endif #ifndef GL_SGIX_fragment_lighting #define GL_SGIX_fragment_lighting #define _ALLEGRO_GL_SGIX_fragment_lighting #define GL_FRAGMENT_LIGHTING_SGIX 0x8400 #define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 #define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 #define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 #define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 #define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 #define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 #define GL_LIGHT_ENV_MODE_SGIX 0x8407 #define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 #define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 #define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A #define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B #define GL_FRAGMENT_LIGHT0_SGIX 0x840C #define GL_FRAGMENT_LIGHT1_SGIX 0x840D #define GL_FRAGMENT_LIGHT2_SGIX 0x840E #define GL_FRAGMENT_LIGHT3_SGIX 0x840F #define GL_FRAGMENT_LIGHT4_SGIX 0x8410 #define GL_FRAGMENT_LIGHT5_SGIX 0x8411 #define GL_FRAGMENT_LIGHT6_SGIX 0x8412 #define GL_FRAGMENT_LIGHT7_SGIX 0x8413 #endif #ifndef GL_IBM_rasterpos_clip #define GL_IBM_rasterpos_clip #define _ALLEGRO_GL_IBM_rasterpos_clip #define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 #endif #ifndef GL_HP_texture_lighting #define GL_HP_texture_lighting #define _ALLEGRO_GL_HP_texture_lighting #define GL_TEXTURE_LIGHTING_MODE_HP 0x8167 #define GL_TEXTURE_POST_SPECULAR_HP 0x8168 #define GL_TEXTURE_PRE_SPECULAR_HP 0x8169 #endif #ifndef GL_EXT_draw_range_elements #define GL_EXT_draw_range_elements #define _ALLEGRO_GL_EXT_draw_range_elements #define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 #define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 #endif #ifndef GL_WIN_phong_shading #define GL_WIN_phong_shading #define _ALLEGRO_GL_WIN_phong_shading #define GL_PHONG_WIN 0x80EA #define GL_PHONG_HINT_WIN 0x80EB #endif #ifndef GL_WIN_specular_fog #define GL_WIN_specular_fog #define _ALLEGRO_GL_WIN_specular_fog #define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC #endif #ifndef GL_EXT_light_texture #define GL_EXT_light_texture #define _ALLEGRO_GL_EXT_light_texture #define GL_FRAGMENT_MATERIAL_EXT 0x8349 #define GL_FRAGMENT_NORMAL_EXT 0x834A #define GL_FRAGMENT_COLOR_EXT 0x834C #define GL_ATTENUATION_EXT 0x834D #define GL_SHADOW_ATTENUATION_EXT 0x834E #define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F #define GL_TEXTURE_LIGHT_EXT 0x8350 #define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 #define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 #ifndef GL_FRAGMENT_DEPTH_EXT #define GL_FRAGMENT_DEPTH_EXT 0x8452 #endif #endif #ifndef GL_SGIX_blend_alpha_minmax #define GL_SGIX_blend_alpha_minmax #define _ALLEGRO_GL_SGIX_blend_alpha_minmax #define GL_ALPHA_MIN_SGIX 0x8320 #define GL_ALPHA_MAX_SGIX 0x8321 #endif #ifndef GL_SGIX_impact_pixel_texture #define GL_SGIX_impact_pixel_texture #define _ALLEGRO_GL_SGIX_impact_pixel_texture #define GL_PIXEL_TEX_GEN_Q_CEILING_SGIX 0x8184 #define GL_PIXEL_TEX_GEN_Q_ROUND_SGIX 0x8185 #define GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX 0x8186 #define GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187 #define GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188 #define GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX 0x8189 #define GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX 0x818A #endif #ifndef GL_EXT_bgra #define GL_EXT_bgra #define _ALLEGRO_GL_EXT_bgra #define GL_BGR_EXT 0x80E0 #define GL_BGRA_EXT 0x80E1 #endif #ifndef GL_SGIX_async #define GL_SGIX_async #define _ALLEGRO_GL_SGIX_async #define GL_ASYNC_MARKER_SGIX 0x8329 #endif #ifndef GL_SGIX_async_pixel #define GL_SGIX_async_pixel #define _ALLEGRO_GL_SGIX_async_pixel #define GL_ASYNC_TEX_IMAGE_SGIX 0x835C #define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D #define GL_ASYNC_READ_PIXELS_SGIX 0x835E #define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F #define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 #define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 #endif #ifndef GL_SGIX_async_histogram #define GL_SGIX_async_histogram #define _ALLEGRO_GL_SGIX_async_histogram #define GL_ASYNC_HISTOGRAM_SGIX 0x832C #define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D #endif #ifndef GL_INTEL_parallel_arrays #define GL_INTEL_parallel_arrays #define _ALLEGRO_GL_INTEL_parallel_arrays #define GL_PARALLEL_ARRAYS_INTEL 0x83F4 #define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 #define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 #define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 #define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 #endif #ifndef GL_HP_occlusion_test #define GL_HP_occlusion_test #define _ALLEGRO_GL_HP_occlusion_test #define GL_OCCLUSION_TEST_HP 0x8165 #define GL_OCCLUSION_TEST_RESULT_HP 0x8166 #endif #ifndef GL_EXT_pixel_transform #define GL_EXT_pixel_transform #define _ALLEGRO_GL_EXT_pixel_transform #define GL_PIXEL_TRANSFORM_2D_EXT 0x8330 #define GL_PIXEL_MAG_FILTER_EXT 0x8331 #define GL_PIXEL_MIN_FILTER_EXT 0x8332 #define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 #define GL_CUBIC_EXT 0x8334 #define GL_AVERAGE_EXT 0x8335 #define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 #define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 #define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 #endif #ifndef GL_EXT_shared_texture_palette #define GL_EXT_shared_texture_palette #define _ALLEGRO_GL_EXT_shared_texture_palette #define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB #endif #ifndef GL_EXT_separate_specular_color #define GL_EXT_separate_specular_color #define _ALLEGRO_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 #ifndef GL_EXT_secondary_color #define GL_EXT_secondary_color #define _ALLEGRO_GL_EXT_secondary_color #define GL_COLOR_SUM_EXT 0x8458 #define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 #define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A #define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B #define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C #define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D #define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E #endif #ifndef GL_EXT_texture_perturb_normal #define GL_EXT_texture_perturb_normal #define _ALLEGRO_GL_EXT_texture_perturb_normal #define GL_PERTURB_EXT 0x85AE #define GL_TEXTURE_NORMAL_EXT 0x85AF #endif #ifndef GL_EXT_multi_draw_arrays #define GL_EXT_multi_draw_arrays #define _ALLEGRO_GL_EXT_multi_draw_arrays #endif #ifndef GL_EXT_fog_coord #define GL_EXT_fog_coord #define _ALLEGRO_GL_EXT_fog_coord #define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 #define GL_FOG_COORDINATE_EXT 0x8451 #define GL_FRAGMENT_DEPTH_EXT 0x8452 #define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 #define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 #define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 #define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 #define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 #endif #ifndef GL_REND_screen_coordinates #define GL_REND_screen_coordinates #define _ALLEGRO_GL_REND_screen_coordinates #define GL_SCREEN_COORDINATES_REND 0x8490 #define GL_INVERTED_SCREEN_W_REND 0x8491 #endif #ifndef GL_EXT_coordinate_frame #define GL_EXT_coordinate_frame #define _ALLEGRO_GL_EXT_coordinate_frame #define GL_TANGENT_ARRAY_EXT 0x8439 #define GL_BINORMAL_ARRAY_EXT 0x843A #define GL_CURRENT_TANGENT_EXT 0x843B #define GL_CURRENT_BINORMAL_EXT 0x843C #define GL_TANGENT_ARRAY_TYPE_EXT 0x843E #define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F #define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 #define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 #define GL_TANGENT_ARRAY_POINTER_EXT 0x8442 #define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 #define GL_MAP1_TANGENT_EXT 0x8444 #define GL_MAP2_TANGENT_EXT 0x8445 #define GL_MAP1_BINORMAL_EXT 0x8446 #define GL_MAP2_BINORMAL_EXT 0x8447 #endif #ifndef GL_EXT_texture_env_combine #define GL_EXT_texture_env_combine #define _ALLEGRO_GL_EXT_texture_env_combine #define GL_COMBINE_EXT 0x8570 #define GL_COMBINE_RGB_EXT 0x8571 #define GL_COMBINE_ALPHA_EXT 0x8572 #define GL_RGB_SCALE_EXT 0x8573 #define GL_ADD_SIGNED_EXT 0x8574 #define GL_INTERPOLATE_EXT 0x8575 #define GL_CONSTANT_EXT 0x8576 #define GL_PRIMARY_COLOR_EXT 0x8577 #define GL_PREVIOUS_EXT 0x8578 #define GL_SOURCE0_RGB_EXT 0x8580 #define GL_SOURCE1_RGB_EXT 0x8581 #define GL_SOURCE2_RGB_EXT 0x8582 #define GL_SOURCE0_ALPHA_EXT 0x8588 #define GL_SOURCE1_ALPHA_EXT 0x8589 #define GL_SOURCE2_ALPHA_EXT 0x858A #define GL_OPERAND0_RGB_EXT 0x8590 #define GL_OPERAND1_RGB_EXT 0x8591 #define GL_OPERAND2_RGB_EXT 0x8592 #define GL_OPERAND0_ALPHA_EXT 0x8598 #define GL_OPERAND1_ALPHA_EXT 0x8599 #define GL_OPERAND2_ALPHA_EXT 0x859A #endif #ifndef GL_APPLE_specular_vector #define GL_APPLE_specular_vector #define _ALLEGRO_GL_APPLE_specular_vector #define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 #endif #ifndef GL_APPLE_transform_hint #define GL_APPLE_transform_hint #define _ALLEGRO_GL_APPLE_transform_hint #define GL_TRANSFORM_HINT_APPLE 0x85B1 #endif #ifndef GL_SGIX_fog_scale #define GL_SGIX_fog_scale #define _ALLEGRO_GL_SGIX_fog_scale #define GL_FOG_SCALE_SGIX 0x81FC #define GL_FOG_SCALE_VALUE_SGIX 0x81FD #endif #ifndef GL_SUNX_constant_data #define GL_SUNX_constant_data #define _ALLEGRO_GL_SUNX_constant_data #define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 #define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 #endif #ifndef GL_SUN_global_alpha #define GL_SUN_global_alpha #define _ALLEGRO_GL_SUN_global_alpha #define GL_GLOBAL_ALPHA_SUN 0x81D9 #define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA #endif #ifndef GL_SUN_triangle_list #define GL_SUN_triangle_list #define _ALLEGRO_GL_SUN_triangle_list #define GL_RESTART_SUN 0x0001 #define GL_REPLACE_MIDDLE_SUN 0x0002 #define GL_REPLACE_OLDEST_SUN 0x0003 #define GL_TRIANGLE_LIST_SUN 0x81D7 #define GL_REPLACEMENT_CODE_SUN 0x81D8 #define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 #define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 #define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 #define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 #define GL_R1UI_V3F_SUN 0x85C4 #define GL_R1UI_C4UB_V3F_SUN 0x85C5 #define GL_R1UI_C3F_V3F_SUN 0x85C6 #define GL_R1UI_N3F_V3F_SUN 0x85C7 #define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 #define GL_R1UI_T2F_V3F_SUN 0x85C9 #define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA #define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB #endif #ifndef GL_SUN_vertex #define GL_SUN_vertex #define _ALLEGRO_GL_SUN_vertex #endif #ifndef GL_EXT_blend_func_separate #define GL_EXT_blend_func_separate #define _ALLEGRO_GL_EXT_blend_func_separate #define GL_BLEND_DST_RGB_EXT 0x80C8 #define GL_BLEND_SRC_RGB_EXT 0x80C9 #define GL_BLEND_DST_ALPHA_EXT 0x80CA #define GL_BLEND_SRC_ALPHA_EXT 0x80CB #endif #ifndef GL_INGR_color_clamp #define GL_INGR_color_clamp #define _ALLEGRO_GL_INGR_color_clamp #define GL_RED_MIN_CLAMP_INGR 0x8560 #define GL_GREEN_MIN_CLAMP_INGR 0x8561 #define GL_BLUE_MIN_CLAMP_INGR 0x8562 #define GL_ALPHA_MIN_CLAMP_INGR 0x8563 #define GL_RED_MAX_CLAMP_INGR 0x8564 #define GL_GREEN_MAX_CLAMP_INGR 0x8565 #define GL_BLUE_MAX_CLAMP_INGR 0x8566 #define GL_ALPHA_MAX_CLAMP_INGR 0x8567 #endif #ifndef GL_INGR_blend_func_separate #define GL_INGR_blend_func_separate #define _ALLEGRO_GL_INGR_blend_func_separate #endif #ifndef GL_INGR_interlace_read #define GL_INGR_interlace_read #define _ALLEGRO_GL_INGR_interlace_read #define GL_INTERLACE_READ_INGR 0x8568 #endif #ifndef GL_EXT_stencil_wrap #define GL_EXT_stencil_wrap #define _ALLEGRO_GL_EXT_stencil_wrap #define GL_INCR_WRAP_EXT 0x8507 #define GL_DECR_WRAP_EXT 0x8508 #endif #ifndef GL_EXT_422_pixels #define GL_EXT_422_pixels #define _ALLEGRO_GL_EXT_422_pixels #define GL_422_EXT 0x80CC #define GL_422_REV_EXT 0x80CD #define GL_422_AVERAGE_EXT 0x80CE #define GL_422_REV_AVERAGE_EXT 0x80CF #endif #ifndef GL_NV_texgen_reflection #define GL_NV_texgen_reflection #define _ALLEGRO_GL_NV_texgen_reflection #define GL_NORMAL_MAP_NV 0x8511 #define GL_REFLECTION_MAP_NV 0x8512 #endif #ifndef GL_EXT_texture_cube_map #define GL_EXT_texture_cube_map #define _ALLEGRO_GL_EXT_texture_cube_map #define GL_NORMAL_MAP_EXT 0x8511 #define GL_REFLECTION_MAP_EXT 0x8512 #define GL_TEXTURE_CUBE_MAP_EXT 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C #endif #ifndef GL_SUN_convolution_border_modes #define GL_SUN_convolution_border_modes #define _ALLEGRO_GL_SUN_convolution_border_modes #define GL_WRAP_BORDER_SUN 0x81D4 #endif #ifndef GL_EXT_texture_lod_bias #define GL_EXT_texture_lod_bias #define _ALLEGRO_GL_EXT_texture_lod_bias #define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD #define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 #define GL_TEXTURE_LOD_BIAS_EXT 0x8501 #endif #ifndef GL_EXT_texture_filter_anisotropic #define GL_EXT_texture_filter_anisotropic #define _ALLEGRO_GL_EXT_texture_filter_anisotropic #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF #endif #ifndef GL_EXT_vertex_weighting #define GL_EXT_vertex_weighting #define _ALLEGRO_GL_EXT_vertex_weighting #define GL_MODELVIEW0_STACK_DEPTH_EXT GL_MODELVIEW_STACK_DEPTH #define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 #define GL_MODELVIEW0_MATRIX_EXT GL_MODELVIEW_MATRIX #define GL_MODELVIEW1_MATRIX_EXT 0x8506 #define GL_VERTEX_WEIGHTING_EXT 0x8509 #define GL_MODELVIEW0_EXT GL_MODELVIEW #define GL_MODELVIEW1_EXT 0x850A #define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B #define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C #define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D #define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E #define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F #define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 #endif #ifndef GL_NV_light_max_exponent #define GL_NV_light_max_exponent #define _ALLEGRO_GL_NV_light_max_exponent #define GL_MAX_SHININESS_NV 0x8504 #define GL_MAX_SPOT_EXPONENT_NV 0x8505 #endif #ifndef GL_NV_vertex_array_range #define GL_NV_vertex_array_range #define _ALLEGRO_GL_NV_vertex_array_range #define GL_VERTEX_ARRAY_RANGE_NV 0x851D #define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E #define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F #define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 #define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 #endif #ifndef GL_NV_register_combiners #define GL_NV_register_combiners #define _ALLEGRO_GL_NV_register_combiners #define GL_REGISTER_COMBINERS_NV 0x8522 #define GL_VARIABLE_A_NV 0x8523 #define GL_VARIABLE_B_NV 0x8524 #define GL_VARIABLE_C_NV 0x8525 #define GL_VARIABLE_D_NV 0x8526 #define GL_VARIABLE_E_NV 0x8527 #define GL_VARIABLE_F_NV 0x8528 #define GL_VARIABLE_G_NV 0x8529 #define GL_CONSTANT_COLOR0_NV 0x852A #define GL_CONSTANT_COLOR1_NV 0x852B #define GL_PRIMARY_COLOR_NV 0x852C #define GL_SECONDARY_COLOR_NV 0x852D #define GL_SPARE0_NV 0x852E #define GL_SPARE1_NV 0x852F #define GL_DISCARD_NV 0x8530 #define GL_E_TIMES_F_NV 0x8531 #define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 #define GL_UNSIGNED_IDENTITY_NV 0x8536 #define GL_UNSIGNED_INVERT_NV 0x8537 #define GL_EXPAND_NORMAL_NV 0x8538 #define GL_EXPAND_NEGATE_NV 0x8539 #define GL_HALF_BIAS_NORMAL_NV 0x853A #define GL_HALF_BIAS_NEGATE_NV 0x853B #define GL_SIGNED_IDENTITY_NV 0x853C #define GL_SIGNED_NEGATE_NV 0x853D #define GL_SCALE_BY_TWO_NV 0x853E #define GL_SCALE_BY_FOUR_NV 0x853F #define GL_SCALE_BY_ONE_HALF_NV 0x8540 #define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 #define GL_COMBINER_INPUT_NV 0x8542 #define GL_COMBINER_MAPPING_NV 0x8543 #define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 #define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 #define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 #define GL_COMBINER_MUX_SUM_NV 0x8547 #define GL_COMBINER_SCALE_NV 0x8548 #define GL_COMBINER_BIAS_NV 0x8549 #define GL_COMBINER_AB_OUTPUT_NV 0x854A #define GL_COMBINER_CD_OUTPUT_NV 0x854B #define GL_COMBINER_SUM_OUTPUT_NV 0x854C #define GL_MAX_GENERAL_COMBINERS_NV 0x854D #define GL_NUM_GENERAL_COMBINERS_NV 0x854E #define GL_COLOR_SUM_CLAMP_NV 0x854F #define GL_COMBINER0_NV 0x8550 #define GL_COMBINER1_NV 0x8551 #define GL_COMBINER2_NV 0x8552 #define GL_COMBINER3_NV 0x8553 #define GL_COMBINER4_NV 0x8554 #define GL_COMBINER5_NV 0x8555 #define GL_COMBINER6_NV 0x8556 #define GL_COMBINER7_NV 0x8557 /* GL_TEXTURE0_ARB */ /* GL_TEXTURE1_ARB */ /* GL_ZERO */ /* GL_NONE */ /* GL_FOG */ #endif #ifndef GL_NV_fog_distance #define GL_NV_fog_distance #define _ALLEGRO_GL_NV_fog_distance #define GL_FOG_DISTANCE_MODE_NV 0x855A #define GL_EYE_RADIAL_NV 0x855B #define GL_EYE_PLANE_ABSOLUTE_NV 0x855C /* GL_EYE_PLANE */ #endif #ifndef GL_NV_texgen_emboss #define GL_NV_texgen_emboss #define _ALLEGRO_GL_NV_texgen_emboss #define GL_EMBOSS_LIGHT_NV 0x855D #define GL_EMBOSS_CONSTANT_NV 0x855E #define GL_EMBOSS_MAP_NV 0x855F #endif #ifndef GL_NV_texture_env_combine4 #define GL_NV_texture_env_combine4 #define _ALLEGRO_GL_NV_texture_env_combine4 #define GL_COMBINE4_NV 0x8503 #define GL_SOURCE3_RGB_NV 0x8583 #define GL_SOURCE3_ALPHA_NV 0x858B #define GL_OPERAND3_RGB_NV 0x8593 #define GL_OPERAND3_ALPHA_NV 0x859B #endif #ifndef GL_EXT_texture_compression_s3tc #define GL_EXT_texture_compression_s3tc #define _ALLEGRO_GL_EXT_texture_compression_s3tc #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 #endif #ifndef GL_MESA_resize_buffers #define GL_MESA_resize_buffers #define _ALLEGRO_GL_MESA_resize_buffers #endif #ifndef GL_MESA_window_pos #define GL_MESA_window_pos #define _ALLEGRO_GL_MESA_window_pos #endif #ifndef GL_IBM_cull_vertex #define GL_IBM_cull_vertex #define _ALLEGRO_GL_IBM_cull_vertex #define GL_CULL_VERTEX_IBM 103050 #endif #ifndef GL_IBM_multimode_draw_arrays #define GL_IBM_multimode_draw_arrays #define _ALLEGRO_GL_IBM_multimode_draw_arrays #endif #ifndef GL_IBM_vertex_array_lists #define GL_IBM_vertex_array_lists #define _ALLEGRO_GL_IBM_vertex_array_lists #define GL_VERTEX_ARRAY_LIST_IBM 103070 #define GL_NORMAL_ARRAY_LIST_IBM 103071 #define GL_COLOR_ARRAY_LIST_IBM 103072 #define GL_INDEX_ARRAY_LIST_IBM 103073 #define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 #define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 #define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 #define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 #define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 #define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 #define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 #define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 #define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 #define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 #define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 #define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 #endif #ifndef GL_SGIX_subsample #define GL_SGIX_subsample #define _ALLEGRO_GL_SGIX_subsample #define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 #define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 #define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 #define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 #define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 #endif #ifndef GL_SGIX_ycrcba #define GL_SGIX_ycrcba #define _ALLEGRO_GL_SGIX_ycrcba #define GL_YCRCB_SGIX 0x8318 #define GL_YCRCBA_SGIX 0x8319 #endif #ifndef GL_SGI_depth_pass_instrument #define GL_SGI_depth_pass_instrument #define _ALLEGRO_GL_SGI_depth_pass_instrument #define GL_DEPTH_PASS_INSTRUMENT_SGIX 0x8310 #define GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311 #define GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312 #endif #ifndef GL_3DFX_texture_compression_FXT1 #define GL_3DFX_texture_compression_FXT1 #define _ALLEGRO_GL_3DFX_texture_compression_FXT1 #define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 #define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 #endif #ifndef GL_3DFX_multisample #define GL_3DFX_multisample #define _ALLEGRO_GL_3DFX_multisample #define GL_MULTISAMPLE_3DFX 0x86B2 #define GL_SAMPLE_BUFFERS_3DFX 0x86B3 #define GL_SAMPLES_3DFX 0x86B4 #define GL_MULTISAMPLE_BIT_3DFX 0x20000000 #endif #ifndef GL_3DFX_tbuffer #define GL_3DFX_tbuffer #ifndef ALLEGRO_GL_HEADER_NV #define _ALLEGRO_GL_3DFX_tbuffer #endif #endif #ifndef GL_EXT_multisample #define GL_EXT_multisample #define _ALLEGRO_GL_EXT_multisample #define GL_MULTISAMPLE_EXT 0x809D #define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F #define GL_SAMPLE_MASK_EXT 0x80A0 #define GL_1PASS_EXT 0x80A1 #define GL_2PASS_0_EXT 0x80A2 #define GL_2PASS_1_EXT 0x80A3 #define GL_4PASS_0_EXT 0x80A4 #define GL_4PASS_1_EXT 0x80A5 #define GL_4PASS_2_EXT 0x80A6 #define GL_4PASS_3_EXT 0x80A7 #define GL_SAMPLE_BUFFERS_EXT 0x80A8 #define GL_SAMPLES_EXT 0x80A9 #define GL_SAMPLE_MASK_VALUE_EXT 0x80AA #define GL_SAMPLE_MASK_INVERT_EXT 0x80AB #define GL_SAMPLE_PATTERN_EXT 0x80AC #define GL_MULTISAMPLE_BIT_EXT 0x20000000 #endif #ifndef GL_SGIX_vertex_preclip #define GL_SGIX_vertex_preclip #define _ALLEGRO_GL_SGIX_vertex_preclip #define GL_VERTEX_PRECLIP_SGIX 0x83EE #define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF #endif #ifndef GL_SGIX_convolution_accuracy #define GL_SGIX_convolution_accuracy #define _ALLEGRO_GL_SGIX_convolution_accuracy #define GL_CONVOLUTION_HINT_SGIX 0x8316 #endif #ifndef GL_SGIX_resample #define GL_SGIX_resample #define _ALLEGRO_GL_SGIX_resample #define GL_PACK_RESAMPLE_SGIX 0x842C #define GL_UNPACK_RESAMPLE_SGIX 0x842D #define GL_RESAMPLE_REPLICATE_SGIX 0x842E #define GL_RESAMPLE_ZERO_FILL_SGIX 0x842F #define GL_RESAMPLE_DECIMATE_SGIX 0x8430 #endif #ifndef GL_SGIS_point_line_texgen #define GL_SGIS_point_line_texgen #define _ALLEGRO_GL_SGIS_point_line_texgen #define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 #define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 #define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 #define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 #define GL_EYE_POINT_SGIS 0x81F4 #define GL_OBJECT_POINT_SGIS 0x81F5 #define GL_EYE_LINE_SGIS 0x81F6 #define GL_OBJECT_LINE_SGIS 0x81F7 #endif #ifndef GL_SGIS_texture_color_mask #define GL_SGIS_texture_color_mask #ifndef ALLEGRO_GL_HEADER_NV #define _ALLEGRO_GL_SGIS_texture_color_mask #define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF #endif #endif #ifndef GL_SGIX_igloo_interface #define GL_SGIX_igloo_interface #define _ALLEGRO_GL_SGIX_igloo_interface #endif #ifndef GL_EXT_texture_env_dot3 #define GL_EXT_texture_env_dot3 #define _ALLEGRO_GL_EXT_texture_env_dot3 /* GL_DOT3_RGB_EXT */ /* GL_DOT3_RGBA_EXT */ #endif #ifndef GL_ATI_texture_mirror_once #define GL_ATI_texture_mirror_once #define _ALLEGRO_GL_ATI_texture_mirror_once #define GL_MIRROR_CLAMP_ATI 0x8742 #define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 #endif #ifndef GL_NV_fence #define GL_NV_fence #define _ALLEGRO_GL_NV_fence #define GL_ALL_COMPLETED_NV 0x84F2 #define GL_FENCE_STATUS_NV 0x84F3 #define GL_FENCE_CONDITION_NV 0x84F4 #endif #ifndef GL_IBM_texture_mirrored_repeat #define GL_IBM_texture_mirrored_repeat #define _ALLEGRO_GL_IBM_texture_mirrored_repeat #define GL_MIRRORED_REPEAT_IBM 0x8370 #endif #ifndef GL_NV_evaluators #define GL_NV_evaluators #define _ALLEGRO_GL_NV_evaluators #define GL_EVAL_2D_NV 0x86C0 #define GL_EVAL_TRIANGULAR_2D_NV 0x86C1 #define GL_MAP_TESSELLATION_NV 0x86C2 #define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 #define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 #define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 #define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 #define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 #define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 #define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 #define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA #define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB #define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC #define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD #define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE #define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF #define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 #define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 #define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 #define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 #define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 #define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 #define GL_MAX_MAP_TESSELLATION_NV 0x86D6 #define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 #endif #ifndef GL_NV_packed_depth_stencil #define GL_NV_packed_depth_stencil #define _ALLEGRO_GL_NV_packed_depth_stencil #define GL_DEPTH_STENCIL_NV 0x84F9 #define GL_UNSIGNED_INT_24_8_NV 0x84FA #endif #ifndef GL_NV_register_combiners2 #define GL_NV_register_combiners2 #define _ALLEGRO_GL_NV_register_combiners2 #define GL_PER_STAGE_CONSTANTS_NV 0x8535 #endif #ifndef GL_NV_texture_rectangle #define GL_NV_texture_rectangle #define _ALLEGRO_GL_NV_texture_rectangle #define GL_TEXTURE_RECTANGLE_NV 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 #endif #ifndef GL_NV_texture_shader #define GL_NV_texture_shader #define _ALLEGRO_GL_NV_texture_shader #define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C #define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D #define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E #define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 #define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA #define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB #define GL_DSDT_MAG_INTENSITY_NV 0x86DC #define GL_SHADER_CONSISTENT_NV 0x86DD #define GL_TEXTURE_SHADER_NV 0x86DE #define GL_SHADER_OPERATION_NV 0x86DF #define GL_CULL_MODES_NV 0x86E0 #define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 #define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 #define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 #define GL_OFFSET_TEXTURE_2D_MATRIX_NV GL_OFFSET_TEXTURE_MATRIX_NV #define GL_OFFSET_TEXTURE_2D_SCALE_NV GL_OFFSET_TEXTURE_SCALE_NV #define GL_OFFSET_TEXTURE_2D_BIAS_NV GL_OFFSET_TEXTURE_BIAS_NV #define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 #define GL_CONST_EYE_NV 0x86E5 #define GL_PASS_THROUGH_NV 0x86E6 #define GL_CULL_FRAGMENT_NV 0x86E7 #define GL_OFFSET_TEXTURE_2D_NV 0x86E8 #define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 #define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA #define GL_DOT_PRODUCT_NV 0x86EC #define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED #define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE #define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 #define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 #define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 #define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 #define GL_HILO_NV 0x86F4 #define GL_DSDT_NV 0x86F5 #define GL_DSDT_MAG_NV 0x86F6 #define GL_DSDT_MAG_VIB_NV 0x86F7 #define GL_HILO16_NV 0x86F8 #define GL_SIGNED_HILO_NV 0x86F9 #define GL_SIGNED_HILO16_NV 0x86FA #define GL_SIGNED_RGBA_NV 0x86FB #define GL_SIGNED_RGBA8_NV 0x86FC #define GL_SIGNED_RGB_NV 0x86FE #define GL_SIGNED_RGB8_NV 0x86FF #define GL_SIGNED_LUMINANCE_NV 0x8701 #define GL_SIGNED_LUMINANCE8_NV 0x8702 #define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 #define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 #define GL_SIGNED_ALPHA_NV 0x8705 #define GL_SIGNED_ALPHA8_NV 0x8706 #define GL_SIGNED_INTENSITY_NV 0x8707 #define GL_SIGNED_INTENSITY8_NV 0x8708 #define GL_DSDT8_NV 0x8709 #define GL_DSDT8_MAG8_NV 0x870A #define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B #define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C #define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D #define GL_HI_SCALE_NV 0x870E #define GL_LO_SCALE_NV 0x870F #define GL_DS_SCALE_NV 0x8710 #define GL_DT_SCALE_NV 0x8711 #define GL_MAGNITUDE_SCALE_NV 0x8712 #define GL_VIBRANCE_SCALE_NV 0x8713 #define GL_HI_BIAS_NV 0x8714 #define GL_LO_BIAS_NV 0x8715 #define GL_DS_BIAS_NV 0x8716 #define GL_DT_BIAS_NV 0x8717 #define GL_MAGNITUDE_BIAS_NV 0x8718 #define GL_VIBRANCE_BIAS_NV 0x8719 #define GL_TEXTURE_BORDER_VALUES_NV 0x871A #define GL_TEXTURE_HI_SIZE_NV 0x871B #define GL_TEXTURE_LO_SIZE_NV 0x871C #define GL_TEXTURE_DS_SIZE_NV 0x871D #define GL_TEXTURE_DT_SIZE_NV 0x871E #define GL_TEXTURE_MAG_SIZE_NV 0x871F #endif #ifndef GL_NV_texture_shader2 #define GL_NV_texture_shader2 #define _ALLEGRO_GL_NV_texture_shader2 #define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF #endif #ifndef GL_NV_vertex_array_range2 #define GL_NV_vertex_array_range2 #define _ALLEGRO_GL_NV_vertex_array_range2 #define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 #endif #ifndef GL_NV_vertex_program #define GL_NV_vertex_program #define _ALLEGRO_GL_NV_vertex_program #define GL_VERTEX_PROGRAM_NV 0x8620 #define GL_VERTEX_STATE_PROGRAM_NV 0x8621 #define GL_ATTRIB_ARRAY_SIZE_NV 0x8623 #define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 #define GL_ATTRIB_ARRAY_TYPE_NV 0x8625 #define GL_CURRENT_ATTRIB_NV 0x8626 #define GL_PROGRAM_LENGTH_NV 0x8627 #define GL_PROGRAM_STRING_NV 0x8628 #define GL_MODELVIEW_PROJECTION_NV 0x8629 #define GL_IDENTITY_NV 0x862A #define GL_INVERSE_NV 0x862B #define GL_TRANSPOSE_NV 0x862C #define GL_INVERSE_TRANSPOSE_NV 0x862D #define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E #define GL_MAX_TRACK_MATRICES_NV 0x862F #define GL_MATRIX0_NV 0x8630 #define GL_MATRIX1_NV 0x8631 #define GL_MATRIX2_NV 0x8632 #define GL_MATRIX3_NV 0x8633 #define GL_MATRIX4_NV 0x8634 #define GL_MATRIX5_NV 0x8635 #define GL_MATRIX6_NV 0x8636 #define GL_MATRIX7_NV 0x8637 #define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 #define GL_CURRENT_MATRIX_NV 0x8641 #define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 #define GL_PROGRAM_PARAMETER_NV 0x8644 #define GL_ATTRIB_ARRAY_POINTER_NV 0x8645 #define GL_PROGRAM_TARGET_NV 0x8646 #define GL_PROGRAM_RESIDENT_NV 0x8647 #define GL_TRACK_MATRIX_NV 0x8648 #define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 #define GL_VERTEX_PROGRAM_BINDING_NV 0x864A #define GL_PROGRAM_ERROR_POSITION_NV 0x864B #define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 #define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 #define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 #define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 #define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 #define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 #define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 #define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 #define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 #define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 #define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A #define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B #define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C #define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D #define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E #define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F #define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 #define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 #define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 #define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 #define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 #define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 #define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 #define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 #define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 #define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 #define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A #define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B #define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C #define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D #define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E #define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F #define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 #define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 #define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 #define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 #define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 #define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 #define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 #define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 #define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 #define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 #define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A #define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B #define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C #define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D #define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E #define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F #endif #ifndef GL_SGIX_texture_coordinate_clamp #define GL_SGIX_texture_coordinate_clamp #define _ALLEGRO_GL_SGIX_texture_coordinate_clamp #define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 #define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A #define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B #endif #ifndef GL_SGIX_scalebias_hint #define GL_SGIX_scalebias_hint #define _ALLEGRO_GL_SGIX_scalebias_hint #define GL_SCALEBIAS_HINT_SGIX 0x8322 #endif #ifndef GL_OML_interlace #define GL_OML_interlace #define _ALLEGRO_GL_OML_interlace #define GL_INTERLACE_OML 0x8980 #define GL_INTERLACE_READ_OML 0x8981 #endif #ifndef GL_OML_subsample #define GL_OML_subsample #define _ALLEGRO_GL_OML_subsample #define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 #define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 #endif #ifndef GL_OML_resample #define GL_OML_resample #define _ALLEGRO_GL_OML_resample #define GL_PACK_RESAMPLE_OML 0x8984 #define GL_UNPACK_RESAMPLE_OML 0x8985 #define GL_RESAMPLE_REPLICATE_OML 0x8986 #define GL_RESAMPLE_ZERO_FILL_OML 0x8987 #define GL_RESAMPLE_AVERAGE_OML 0x8988 #define GL_RESAMPLE_DECIMATE_OML 0x8989 #endif #ifndef GL_NV_copy_depth_to_color #define GL_NV_copy_depth_to_color #define _ALLEGRO_GL_NV_copy_depth_to_color #define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E #define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F #endif #ifndef GL_ATI_envmap_bumpmap #define GL_ATI_envmap_bumpmap #define _ALLEGRO_GL_ATI_envmap_bumpmap #define GL_BUMP_ROT_MATRIX_ATI 0x8775 #define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 #define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 #define GL_BUMP_TEX_UNITS_ATI 0x8778 #define GL_DUDV_ATI 0x8779 #define GL_DU8DV8_ATI 0x877A #define GL_BUMP_ENVMAP_ATI 0x877B #define GL_BUMP_TARGET_ATI 0x877C #endif #ifndef GL_ATI_fragment_shader #define GL_ATI_fragment_shader #define _ALLEGRO_GL_ATI_fragment_shader #define GL_FRAGMENT_SHADER_ATI 0x8920 #define GL_REG_0_ATI 0x8921 #define GL_REG_1_ATI 0x8922 #define GL_REG_2_ATI 0x8923 #define GL_REG_3_ATI 0x8924 #define GL_REG_4_ATI 0x8925 #define GL_REG_5_ATI 0x8926 #define GL_REG_6_ATI 0x8927 #define GL_REG_7_ATI 0x8928 #define GL_REG_8_ATI 0x8929 #define GL_REG_9_ATI 0x892A #define GL_REG_10_ATI 0x892B #define GL_REG_11_ATI 0x892C #define GL_REG_12_ATI 0x892D #define GL_REG_13_ATI 0x892E #define GL_REG_14_ATI 0x892F #define GL_REG_15_ATI 0x8930 #define GL_REG_16_ATI 0x8931 #define GL_REG_17_ATI 0x8932 #define GL_REG_18_ATI 0x8933 #define GL_REG_19_ATI 0x8934 #define GL_REG_20_ATI 0x8935 #define GL_REG_21_ATI 0x8936 #define GL_REG_22_ATI 0x8937 #define GL_REG_23_ATI 0x8938 #define GL_REG_24_ATI 0x8939 #define GL_REG_25_ATI 0x893A #define GL_REG_26_ATI 0x893B #define GL_REG_27_ATI 0x893C #define GL_REG_28_ATI 0x893D #define GL_REG_29_ATI 0x893E #define GL_REG_30_ATI 0x893F #define GL_REG_31_ATI 0x8940 #define GL_CON_0_ATI 0x8941 #define GL_CON_1_ATI 0x8942 #define GL_CON_2_ATI 0x8943 #define GL_CON_3_ATI 0x8944 #define GL_CON_4_ATI 0x8945 #define GL_CON_5_ATI 0x8946 #define GL_CON_6_ATI 0x8947 #define GL_CON_7_ATI 0x8948 #define GL_CON_8_ATI 0x8949 #define GL_CON_9_ATI 0x894A #define GL_CON_10_ATI 0x894B #define GL_CON_11_ATI 0x894C #define GL_CON_12_ATI 0x894D #define GL_CON_13_ATI 0x894E #define GL_CON_14_ATI 0x894F #define GL_CON_15_ATI 0x8950 #define GL_CON_16_ATI 0x8951 #define GL_CON_17_ATI 0x8952 #define GL_CON_18_ATI 0x8953 #define GL_CON_19_ATI 0x8954 #define GL_CON_20_ATI 0x8955 #define GL_CON_21_ATI 0x8956 #define GL_CON_22_ATI 0x8957 #define GL_CON_23_ATI 0x8958 #define GL_CON_24_ATI 0x8959 #define GL_CON_25_ATI 0x895A #define GL_CON_26_ATI 0x895B #define GL_CON_27_ATI 0x895C #define GL_CON_28_ATI 0x895D #define GL_CON_29_ATI 0x895E #define GL_CON_30_ATI 0x895F #define GL_CON_31_ATI 0x8960 #define GL_MOV_ATI 0x8961 #define GL_ADD_ATI 0x8963 #define GL_MUL_ATI 0x8964 #define GL_SUB_ATI 0x8965 #define GL_DOT3_ATI 0x8966 #define GL_DOT4_ATI 0x8967 #define GL_MAD_ATI 0x8968 #define GL_LERP_ATI 0x8969 #define GL_CND_ATI 0x896A #define GL_CND0_ATI 0x896B #define GL_DOT2_ADD_ATI 0x896C #define GL_SECONDARY_INTERPOLATOR_ATI 0x896D #define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E #define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F #define GL_NUM_PASSES_ATI 0x8970 #define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 #define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 #define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 #define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 #define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 #define GL_SWIZZLE_STR_ATI 0x8976 #define GL_SWIZZLE_STQ_ATI 0x8977 #define GL_SWIZZLE_STR_DR_ATI 0x8978 #define GL_SWIZZLE_STQ_DQ_ATI 0x8979 #define GL_SWIZZLE_STRQ_ATI 0x897A #define GL_SWIZZLE_STRQ_DQ_ATI 0x897B #define GL_RED_BIT_ATI 0x00000001 #define GL_GREEN_BIT_ATI 0x00000002 #define GL_BLUE_BIT_ATI 0x00000004 #define GL_2X_BIT_ATI 0x00000001 #define GL_4X_BIT_ATI 0x00000002 #define GL_8X_BIT_ATI 0x00000004 #define GL_HALF_BIT_ATI 0x00000008 #define GL_QUARTER_BIT_ATI 0x00000010 #define GL_EIGHTH_BIT_ATI 0x00000020 #define GL_SATURATE_BIT_ATI 0x00000040 #define GL_COMP_BIT_ATI 0x00000002 #define GL_NEGATE_BIT_ATI 0x00000004 #define GL_BIAS_BIT_ATI 0x00000008 #endif #ifndef GL_ATI_pn_triangles #define GL_ATI_pn_triangles #define _ALLEGRO_GL_ATI_pn_triangles #define GL_PN_TRIANGLES_ATI 0x87F0 #define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 #define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 #define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 #define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 #define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 #define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 #define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 #define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 #endif #ifndef GL_ATI_vertex_array_object #define GL_ATI_vertex_array_object #define _ALLEGRO_GL_ATI_vertex_array_object #define GL_STATIC_ATI 0x8760 #define GL_DYNAMIC_ATI 0x8761 #define GL_PRESERVE_ATI 0x8762 #define GL_DISCARD_ATI 0x8763 #define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 #define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 #define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 #define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 #endif #ifndef GL_EXT_vertex_shader #define GL_EXT_vertex_shader #define _ALLEGRO_GL_EXT_vertex_shader #define GL_VERTEX_SHADER_EXT 0x8780 #define GL_VERTEX_SHADER_BINDING_EXT 0x8781 #define GL_OP_INDEX_EXT 0x8782 #define GL_OP_NEGATE_EXT 0x8783 #define GL_OP_DOT3_EXT 0x8784 #define GL_OP_DOT4_EXT 0x8785 #define GL_OP_MUL_EXT 0x8786 #define GL_OP_ADD_EXT 0x8787 #define GL_OP_MADD_EXT 0x8788 #define GL_OP_FRAC_EXT 0x8789 #define GL_OP_MAX_EXT 0x878A #define GL_OP_MIN_EXT 0x878B #define GL_OP_SET_GE_EXT 0x878C #define GL_OP_SET_LT_EXT 0x878D #define GL_OP_CLAMP_EXT 0x878E #define GL_OP_FLOOR_EXT 0x878F #define GL_OP_ROUND_EXT 0x8790 #define GL_OP_EXP_BASE_2_EXT 0x8791 #define GL_OP_LOG_BASE_2_EXT 0x8792 #define GL_OP_POWER_EXT 0x8793 #define GL_OP_RECIP_EXT 0x8794 #define GL_OP_RECIP_SQRT_EXT 0x8795 #define GL_OP_SUB_EXT 0x8796 #define GL_OP_CROSS_PRODUCT_EXT 0x8797 #define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 #define GL_OP_MOV_EXT 0x8799 #define GL_OUTPUT_VERTEX_EXT 0x879A #define GL_OUTPUT_COLOR0_EXT 0x879B #define GL_OUTPUT_COLOR1_EXT 0x879C #define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D #define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E #define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F #define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 #define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 #define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 #define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 #define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 #define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 #define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 #define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 #define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 #define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 #define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA #define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB #define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC #define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD #define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE #define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF #define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 #define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 #define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 #define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 #define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 #define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 #define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 #define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 #define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 #define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 #define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA #define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB #define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC #define GL_OUTPUT_FOG_EXT 0x87BD #define GL_SCALAR_EXT 0x87BE #define GL_VECTOR_EXT 0x87BF #define GL_MATRIX_EXT 0x87C0 #define GL_VARIANT_EXT 0x87C1 #define GL_INVARIANT_EXT 0x87C2 #define GL_LOCAL_CONSTANT_EXT 0x87C3 #define GL_LOCAL_EXT 0x87C4 #define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 #define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 #define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 #define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 #define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 #define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA #define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB #define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC #define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD #define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE #define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF #define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 #define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 #define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 #define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 #define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 #define GL_X_EXT 0x87D5 #define GL_Y_EXT 0x87D6 #define GL_Z_EXT 0x87D7 #define GL_W_EXT 0x87D8 #define GL_NEGATIVE_X_EXT 0x87D9 #define GL_NEGATIVE_Y_EXT 0x87DA #define GL_NEGATIVE_Z_EXT 0x87DB #define GL_NEGATIVE_W_EXT 0x87DC #define GL_ZERO_EXT 0x87DD #define GL_ONE_EXT 0x87DE #define GL_NEGATIVE_ONE_EXT 0x87DF #define GL_NORMALIZED_RANGE_EXT 0x87E0 #define GL_FULL_RANGE_EXT 0x87E1 #define GL_CURRENT_VERTEX_EXT 0x87E2 #define GL_MVP_MATRIX_EXT 0x87E3 #define GL_VARIANT_VALUE_EXT 0x87E4 #define GL_VARIANT_DATATYPE_EXT 0x87E5 #define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 #define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 #define GL_VARIANT_ARRAY_EXT 0x87E8 #define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 #define GL_INVARIANT_VALUE_EXT 0x87EA #define GL_INVARIANT_DATATYPE_EXT 0x87EB #define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC #define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED #endif #ifndef GL_ATI_vertex_streams #define GL_ATI_vertex_streams #define _ALLEGRO_GL_ATI_vertex_streams #define GL_MAX_VERTEX_STREAMS_ATI 0x876B #define GL_VERTEX_STREAM0_ATI 0x876C #define GL_VERTEX_STREAM1_ATI 0x876D #define GL_VERTEX_STREAM2_ATI 0x876E #define GL_VERTEX_STREAM3_ATI 0x876F #define GL_VERTEX_STREAM4_ATI 0x8770 #define GL_VERTEX_STREAM5_ATI 0x8771 #define GL_VERTEX_STREAM6_ATI 0x8772 #define GL_VERTEX_STREAM7_ATI 0x8773 #define GL_VERTEX_SOURCE_ATI 0x8774 #endif #ifndef GL_ATI_element_array #define GL_ATI_element_array #define _ALLEGRO_GL_ATI_element_array #define GL_ELEMENT_ARRAY_ATI 0x8768 #define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 #define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A #endif #ifndef GL_SUN_mesh_array #define GL_SUN_mesh_array #define _ALLEGRO_GL_SUN_mesh_array #define GL_QUAD_MESH_SUN 0x8614 #define GL_TRIANGLE_MESH_SUN 0x8615 #endif #ifndef GL_SUN_slice_accum #define GL_SUN_slice_accum #define _ALLEGRO_GL_SUN_slice_accum #define GL_SLICE_ACCUM_SUN 0x85CC #endif #ifndef GL_NV_multisample_filter_hint #define GL_NV_multisample_filter_hint #define _ALLEGRO_GL_NV_multisample_filter_hint #define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 #endif #ifndef GL_NV_depth_clamp #define GL_NV_depth_clamp #define _ALLEGRO_GL_NV_depth_clamp #define GL_DEPTH_CLAMP_NV 0x864F #endif #ifndef GL_NV_occlusion_query #define GL_NV_occlusion_query #define _ALLEGRO_GL_NV_occlusion_query #define GL_PIXEL_COUNTER_BITS_NV 0x8864 #define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 #define GL_PIXEL_COUNT_NV 0x8866 #define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 #endif #ifndef GL_NV_point_sprite #define GL_NV_point_sprite #define _ALLEGRO_GL_NV_point_sprite #define GL_POINT_SPRITE_NV 0x8861 #define GL_COORD_REPLACE_NV 0x8862 #define GL_POINT_SPRITE_R_MODE_NV 0x8863 #endif #ifndef GL_NV_texture_shader3 #define GL_NV_texture_shader3 #define _ALLEGRO_GL_NV_texture_shader3 #define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 #define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 #define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 #define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 #define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 #define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 #define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 #define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 #define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 #define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 #define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A #define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B #define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C #define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D #define GL_HILO8_NV 0x885E #define GL_SIGNED_HILO8_NV 0x885F #define GL_FORCE_BLUE_TO_ONE_NV 0x8860 #endif #ifndef GL_EXT_stencil_two_side #define GL_EXT_stencil_two_side #define _ALLEGRO_GL_EXT_stencil_two_side #define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 #define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 #endif #ifndef GL_ATI_text_fragment_shader #define GL_ATI_text_fragment_shader #define _ALLEGRO_GL_ATI_text_fragment_shader #define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 #endif #ifndef GL_APPLE_client_storage #define GL_APPLE_client_storage #define _ALLEGRO_GL_APPLE_client_storage #define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 #endif #ifndef GL_APPLE_element_array #define GL_APPLE_element_array #define _ALLEGRO_GL_APPLE_element_array #define GL_ELEMENT_ARRAY_APPLE 0x8768 #define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8769 #define GL_ELEMENT_ARRAY_POINTER_APPLE 0x876A #endif #ifndef GL_APPLE_fence #define GL_APPLE_fence #define _ALLEGRO_GL_APPLE_fence #define GL_DRAW_PIXELS_APPLE 0x8A0A #define GL_FENCE_APPLE 0x8A0B #endif #ifndef GL_APPLE_vertex_array_object #define GL_APPLE_vertex_array_object #define _ALLEGRO_GL_APPLE_vertex_array_object #define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 #endif #ifndef GL_APPLE_vertex_array_range #define GL_APPLE_vertex_array_range #define _ALLEGRO_GL_APPLE_vertex_array_range #define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D #define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E #define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F #define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 #define GL_STORAGE_CACHED_APPLE 0x85BE #define GL_STORAGE_SHARED_APPLE 0x85BF #endif #ifndef GL_APPLE_ycbcr_422 #define GL_APPLE_ycbcr_422 #define _ALLEGRO_GL_APPLE_ycbcr_422 #define GL_YCBCR_422_APPLE 0x85B9 #define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB #endif #ifndef GL_S3_s3tc #define GL_S3_s3tc #define _ALLEGRO_GL_S3_s3tc #define GL_RGB_S3TC 0x83A0 #define GL_RGB4_S3TC 0x83A1 #define GL_RGBA_S3TC 0x83A2 #define GL_RGBA4_S3TC 0x83A3 #endif #ifndef GL_ATI_draw_buffers #define GL_ATI_draw_buffers #define _ALLEGRO_GL_ATI_draw_buffers #define GL_MAX_DRAW_BUFFERS_ATI 0x8824 #define GL_DRAW_BUFFER0_ATI 0x8825 #define GL_DRAW_BUFFER1_ATI 0x8826 #define GL_DRAW_BUFFER2_ATI 0x8827 #define GL_DRAW_BUFFER3_ATI 0x8828 #define GL_DRAW_BUFFER4_ATI 0x8829 #define GL_DRAW_BUFFER5_ATI 0x882A #define GL_DRAW_BUFFER6_ATI 0x882B #define GL_DRAW_BUFFER7_ATI 0x882C #define GL_DRAW_BUFFER8_ATI 0x882D #define GL_DRAW_BUFFER9_ATI 0x882E #define GL_DRAW_BUFFER10_ATI 0x882F #define GL_DRAW_BUFFER11_ATI 0x8830 #define GL_DRAW_BUFFER12_ATI 0x8831 #define GL_DRAW_BUFFER13_ATI 0x8832 #define GL_DRAW_BUFFER14_ATI 0x8833 #define GL_DRAW_BUFFER15_ATI 0x8834 #endif #ifndef GL_ATI_texture_env_combine3 #define GL_ATI_texture_env_combine3 #define _ALLEGRO_GL_ATI_texture_env_combine3 #define GL_MODULATE_ADD_ATI 0x8744 #define GL_MODULATE_SIGNED_ADD_ATI 0x8745 #define GL_MODULATE_SUBTRACT_ATI 0x8746 #endif #ifndef GL_ATI_texture_float #define GL_ATI_texture_float #define _ALLEGRO_GL_ATI_texture_float #define GL_RGBA_FLOAT32_ATI 0x8814 #define GL_RGB_FLOAT32_ATI 0x8815 #define GL_ALPHA_FLOAT32_ATI 0x8816 #define GL_INTENSITY_FLOAT32_ATI 0x8817 #define GL_LUMINANCE_FLOAT32_ATI 0x8818 #define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 #define GL_RGBA_FLOAT16_ATI 0x881A #define GL_RGB_FLOAT16_ATI 0x881B #define GL_ALPHA_FLOAT16_ATI 0x881C #define GL_INTENSITY_FLOAT16_ATI 0x881D #define GL_LUMINANCE_FLOAT16_ATI 0x881E #define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F #endif #ifndef GL_NV_float_buffer #define GL_NV_float_buffer #define _ALLEGRO_GL_NV_float_buffer #define GL_FLOAT_R_NV 0x8880 #define GL_FLOAT_RG_NV 0x8881 #define GL_FLOAT_RGB_NV 0x8882 #define GL_FLOAT_RGBA_NV 0x8883 #define GL_FLOAT_R16_NV 0x8884 #define GL_FLOAT_R32_NV 0x8885 #define GL_FLOAT_RG16_NV 0x8886 #define GL_FLOAT_RG32_NV 0x8887 #define GL_FLOAT_RGB16_NV 0x8888 #define GL_FLOAT_RGB32_NV 0x8889 #define GL_FLOAT_RGBA16_NV 0x888A #define GL_FLOAT_RGBA32_NV 0x888B #define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C #define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D #define GL_FLOAT_RGBA_MODE_NV 0x888E #endif #ifndef GL_NV_fragment_program #define GL_NV_fragment_program #define _ALLEGRO_GL_NV_fragment_program #define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 #define GL_FRAGMENT_PROGRAM_NV 0x8870 #define GL_MAX_TEXTURE_COORDS_NV 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 #define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 #define GL_PROGRAM_ERROR_STRING_NV 0x8874 #endif #ifndef GL_NV_half_float #define GL_NV_half_float #define _ALLEGRO_GL_NV_half_float typedef short GLhalfNV; #define GL_HALF_FLOAT_NV 0x140B #endif #ifndef GL_NV_pixel_data_range #define GL_NV_pixel_data_range #define _ALLEGRO_GL_NV_pixel_data_range #define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 #define GL_READ_PIXEL_DATA_RANGE_NV 0x8879 #define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A #define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B #define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C #define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D #endif #ifndef GL_NV_primitive_restart #define GL_NV_primitive_restart #define _ALLEGRO_GL_NV_primitive_restart #define GL_PRIMITIVE_RESTART_NV 0x8558 #define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 #endif #ifndef GL_NV_texture_expand_normal #define GL_NV_texture_expand_normal #define _ALLEGRO_GL_NV_texture_expand_normal #define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F #endif #ifndef GL_ATI_map_object_buffer #define GL_ATI_map_object_buffer #define _ALLEGRO_GL_ATI_map_object_buffer #endif #ifndef GL_ATI_separate_stencil #define GL_ATI_separate_stencil #define GL_STENCIL_BACK_FUNC_ATI 0x8800 #define GL_STENCIL_BACK_FAIL_ATI 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 #endif #ifndef GL_ATI_vertex_attrib_array_object #define GL_ATI_vertex_attrib_array_object #define _ALLEGRO_GL_ATI_vertex_attrib_array_object #endif #ifndef GL_OES_byte_coordinates #define GL_OES_byte_coordinates #define _ALLEGRO_GL_OES_byte_coordinates /* GL_BYTE */ #endif #ifndef GL_OES_fixed_point #define GL_OES_fixed_point #define _ALLEGRO_GL_OES_fixed_point typedef int GLfixed; typedef int GLclampx; #define GL_FIXED_OES 0x140C #endif #ifndef GL_OES_single_precision #define GL_OES_single_precision #define _ALLEGRO_GL_OES_single_precision #endif #ifndef GL_OES_compressed_paletted_texture #define GL_OES_compressed_paletted_texture #define _ALLEGRO_GL_OES_compressed_paletted_texture #define GL_PALETTE4_RGB8_OES 0x8B90 #define GL_PALETTE4_RGBA8_OES 0x8B91 #define GL_PALETTE4_R5_G6_B5_OES 0x8B92 #define GL_PALETTE4_RGBA4_OES 0x8B93 #define GL_PALETTE4_RGB5_A1_OES 0x8B94 #define GL_PALETTE8_RGB8_OES 0x8B95 #define GL_PALETTE8_RGBA8_OES 0x8B96 #define GL_PALETTE8_R5_G6_B5_OES 0x8B97 #define GL_PALETTE8_RGBA4_OES 0x8B98 #define GL_PALETTE8_RGB5_A1_OES 0x8B99 #endif #ifndef GL_OES_read_format #define GL_OES_read_format #define _ALLEGRO_GL_OES_read_format #define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B #endif #ifndef GL_OES_query_matrix #define GL_OES_query_matrix #define _ALLEGRO_GL_OES_query_matrix #endif #ifndef GL_OES_framebuffer_object #define GL_OES_framebuffer_object #define GL_FRAMEBUFFER_OES 0x8D40 #define GL_RENDERBUFFER_OES 0x8D41 #define GL_DEPTH_COMPONENT16_OES 0x81A5 #define GL_RGBA4_OES 0x8056 #define GL_RGB5_A1_OES 0x8057 #define GL_RGB565_OES 0x8D62 #define GL_STENCIL_INDEX1_OES 0x8D46 #define GL_STENCIL_INDEX4_OES 0x8D47 #define GL_STENCIL_INDEX8_OES 0x8D48 #define GL_RENDERBUFFER_WIDTH_OES 0x8D42 #define GL_RENDERBUFFER_HEIGHT_OES 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT_OES 0x8D44 #define GL_RENDERBUFFER_RED_SIZE_OES 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE_OES 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE_OES 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE_OES 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE_OES 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE_OES 0x8D55 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4 #define GL_COLOR_ATTACHMENT0_OES 0x8CE0 #define GL_DEPTH_ATTACHMENT_OES 0x8D00 #define GL_STENCIL_ATTACHMENT_OES 0x8D20 #define GL_GL_NONE_OES 0 #define GL_FRAMEBUFFER_COMPLETE_OES 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES 0x8CD9 #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES 0x8CDA #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES 0x8CDC #define GL_FRAMEBUFFER_UNSUPPORTED_OES 0x8CDD #define GL_FRAMEBUFFER_BINDING_OES 0x8CA6 #define GL_RENDERBUFFER_BINDING_OES 0x8CA7 #define GL_MAX_RENDERBUFFER_SIZE_OES 0x84E8 #define GL_INVALID_FRAMEBUFFER_OPERATION_OES 0x0506 #endif #ifndef GL_OES_depth24 #define GL_OES_depth24 #define DEPTH_COMPONENT24_OES 0x81A6 #endif #ifndef GL_EXT_depth_bounds_test #define GL_EXT_depth_bounds_test #define _ALLEGRO_GL_EXT_depth_bounds_test #define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 #define GL_DEPTH_BOUNDS_EXT 0x8891 #endif #ifndef GL_EXT_texture_mirror_clamp #define GL_EXT_texture_mirror_clamp #define _ALLEGRO_GL_EXT_texture_mirror_clamp #define GL_MIRROR_CLAMP_EXT 0x8742 #define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 #define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 #endif #ifndef GL_EXT_blend_equation_separate #define GL_EXT_blend_equation_separate #define _ALLEGRO_GL_EXT_blend_equation_separate #define GL_BLEND_EQUATION_RGB_EXT 0x8009 /* Same as GL_BLEND_EQUATION */ #define GL_BLEND_EQUATION_ALPHA_EXT 0x883D #endif #ifndef GL_MESA_pack_invert #define GL_MESA_pack_invert #define _ALLEGRO_GL_MESA_pack_invert #define GL_PACK_INVERT_MESA 0x8758 #endif #ifndef GL_MESA_ycbcr_texture #define GL_MESA_ycbcr_texture #define _ALLEGRO_GL_MESA_ycbcr_texture #define GL_YCBCR_MESA 0x8757 /* Same as GL_UNSIGNED_SHORT_8_8_APPLE and GL_UNSIGNED_SHORT_8_8_REV_APPLE */ #define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB #endif #ifndef GL_EXT_pixel_buffer_object #define GL_EXT_pixel_buffer_object #define _ALLEGRO_GL_EXT_pixel_buffer_object #define GL_PIXEL_PACK_BUFFER_EXT 0x88EB #define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF #endif #ifndef GL_NV_fragment_program_option #define GL_NV_fragment_program_option #define _ALLEGRO_GL_NV_fragment_program_option #endif #ifndef GL_NV_fragment_program2 #define GL_NV_fragment_program2 #define _ALLEGRO_GL_NV_fragment_program2 #define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 #define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 #define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 #define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 #define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 #endif #ifndef GL_NV_vertex_program2_option #define GL_NV_vertex_program2_option #define _ALLEGRO_GL_NV_vertex_program2_option #define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 #define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 #endif #ifndef GL_NV_vertex_program3 #define GL_NV_vertex_program3 #define _ALLEGRO_GL_NV_vertex_program3 #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C #endif #ifndef GL_EXT_texture_compression_dxt1 #define GL_EXT_texture_compression_dxt1 #define _ALLEGRO_GL_EXT_texture_compression_dxt1 #ifndef ALLEGRO_GL_EXT_texture_compression_s3tc #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 #endif #endif #ifndef GL_EXT_framebuffer_object #define GL_EXT_framebuffer_object #define _ALLEGRO_GL_EXT_framebuffer_object #define GL_FRAMEBUFFER_EXT 0x8D40 #define GL_RENDERBUFFER_EXT 0x8D41 #define GL_STENCIL_INDEX_EXT 0x8D45 #define GL_STENCIL_INDEX1_EXT 0x8D46 #define GL_STENCIL_INDEX4_EXT 0x8D47 #define GL_STENCIL_INDEX8_EXT 0x8D48 #define GL_STENCIL_INDEX16_EXT 0x8D49 #define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 #define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 #define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 #define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 #define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 #define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 #define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 #define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 #define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 #define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 #define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 #define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 #define GL_COLOR_ATTACHMENT10_EXT 0x8CEA #define GL_COLOR_ATTACHMENT11_EXT 0x8CEB #define GL_COLOR_ATTACHMENT12_EXT 0x8CEC #define GL_COLOR_ATTACHMENT13_EXT 0x8CED #define GL_COLOR_ATTACHMENT14_EXT 0x8CEE #define GL_COLOR_ATTACHMENT15_EXT 0x8CEF #define GL_DEPTH_ATTACHMENT_EXT 0x8D00 #define GL_STENCIL_ATTACHMENT_EXT 0x8D20 #define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC #define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD #define GL_FRAMEBUFFER_STATUS_ERROR_EXT 0x8CDE #define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 #define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 #define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF #define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 #define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 #endif #ifndef GL_GREMEDY_string_marker #define GL_GREMEDY_string_marker #define _ALLEGRO_GL_GREMEDY_string_marker #endif #ifndef GL_EXT_packed_depth_stencil #define GL_EXT_packed_depth_stencil #define _ALLEGRO_GL_EXT_packed_depth_stencil #define GL_DEPTH_STENCIL_EXT 0x84F9 #define GL_UNSIGNED_INT_24_8_EXT 0x84FA #define GL_DEPTH24_STENCIL8_EXT 0x88F0 #define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 #endif #ifndef GL_EXT_stencil_clear_tag #define GL_EXT_stencil_clear_tag #define _ALLEGRO_GL_EXT_stencil_clear_tag #define GL_STENCIL_TAG_BITS_EXT 0x88F2 #define GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 #endif #ifndef GL_EXT_texture_sRGB #define GL_EXT_texture_sRGB #define _ALLEGRO_GL_EXT_texture_sRGB #define GL_SRGB_EXT 0x8C40 #define GL_SRGB8_EXT 0x8C41 #define GL_SRGB_ALPHA_EXT 0x8C42 #define GL_SRGB8_ALPHA8_EXT 0x8C43 #define GL_SLUMINANCE_ALPHA_EXT 0x8C44 #define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 #define GL_SLUMINANCE_EXT 0x8C46 #define GL_SLUMINANCE8_EXT 0x8C47 #define GL_COMPRESSED_SRGB_EXT 0x8C48 #define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 #define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A #define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B #define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F #endif #ifndef GL_EXT_framebuffer_blit #define GL_EXT_framebuffer_blit #define _ALLEGRO_GL_EXT_framebuffer_blit #define GL_READ_FRAMEBUFFER_EXT 0x8CA8 #define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 #define GL_READ_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_EXT #define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CAA #endif #ifndef GL_EXT_framebuffer_multisample #define GL_EXT_framebuffer_multisample #define _ALLEGRO_GL_EXT_framebuffer_multisample #define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 #define GL_MAX_SAMPLES_EXT 0x8D57 #endif #ifndef GL_MESAX_texture_stack #define GL_MESAX_texture_stack #define _ALLEGRO_GL_MESAX_texture_stack #define GL_TEXTURE_1D_STACK_MESAX 0x8759 #define GL_TEXTURE_2D_STACK_MESAX 0x875A #define GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B #define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C #define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D #define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E #endif #ifndef GL_EXT_timer_query #define GL_EXT_timer_query #define _ALLEGRO_GL_EXT_timer_query #if (defined _MSC_VER) && (_MSC_VER < 1400) typedef __int64 GLint64EXT; typedef unsigned __int64 GLuint64EXT; #else typedef int64_t GLint64EXT; typedef uint64_t GLuint64EXT; #endif #define GL_TIME_ELAPSED_EXT 0x88BF #endif #ifndef GL_EXT_gpu_program_parameters #define GL_EXT_gpu_program_parameters #define _ALLEGRO_GL_EXT_gpu_program_parameters #endif #ifndef GL_APPLE_flush_buffer_range #define GL_APPLE_flush_buffer_range #define _ALLEGRO_GL_APPLE_flush_buffer_range #define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12 #define GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13 #endif #ifndef GL_EXT_bindable_uniform #define GL_EXT_bindable_uniform #define _ALLEGRO_GL_EXT_bindable_uniform #define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2 #define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3 #define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4 #define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED #define GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF #define GL_UNIFORM_BUFFER_EXT 0x8DEE #endif #ifndef GL_EXT_draw_buffers2 #define GL_EXT_draw_buffers2 #define _ALLEGRO_GL_EXT_draw_buffers2 #endif #ifndef GL_EXT_draw_instanced #define GL_EXT_draw_instanced #define _ALLEGRO_GL_EXT_draw_instanced #endif #ifndef GL_EXT_framebuffer_sRGB #define GL_EXT_framebuffer_sRGB #define _ALLEGRO_GL_EXT_framebuffer_sRGB #define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 #define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA #endif #ifndef GL_EXT_geometry_shader4 #define GL_EXT_geometry_shader4 #define _ALLEGRO_GL_EXT_geometry_shader4 #define GL_GEOMETRY_SHADER_EXT 0x8DD9 #define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA #define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB #define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 #define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD #define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE #define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 #define GL_LINES_ADJACENCY_EXT 0xA #define GL_LINE_STRIP_ADJACENCY_EXT 0xB #define GL_TRIANGLES_ADJACENCY_EXT 0xC #define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0xD #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 #define GL_PROGRAM_POINT_SIZE_EXT 0x8642 #endif #ifndef GL_EXT_gpu_shader4 #define GL_EXT_gpu_shader4 #define _ALLEGRO_GL_EXT_gpu_shader4 #define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD #define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 #define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 #define GL_SAMPLER_BUFFER_EXT 0x8DC2 #define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 #define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 #define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 #define GL_UNSIGNED_INT 0x1405 #define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 #define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 #define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 #define GL_INT_SAMPLER_1D_EXT 0x8DC9 #define GL_INT_SAMPLER_2D_EXT 0x8DCA #define GL_INT_SAMPLER_3D_EXT 0x8DCB #define GL_INT_SAMPLER_CUBE_EXT 0x8DCC #define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD #define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE #define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF #define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 #define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 #define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 #define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 #define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 #define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905 #endif #ifndef GL_EXT_packed_float #define GL_EXT_packed_float #define _ALLEGRO_GL_EXT_packed_float #define GL_R11F_G11F_B10F_EXT 0x8C3A #define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B #define GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C #endif #ifndef GL_EXT_texture_array #define GL_EXT_texture_array #define _ALLEGRO_GL_EXT_texture_array #define GL_TEXTURE_1D_ARRAY_EXT 0x8C18 #define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A #define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B #define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 #define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C #define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D #define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF #define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 #define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 #define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 #define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 #define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 #endif #ifndef GL_EXT_texture_buffer_object #define GL_EXT_texture_buffer_object #define _ALLEGRO_GL_EXT_texture_buffer_object #define GL_TEXTURE_BUFFER_EXT 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B #define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D #define GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E #endif #ifndef GL_EXT_texture_compression_latc #define GL_EXT_texture_compression_latc #define _ALLEGRO_GL_EXT_texture_compression_latc #define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 #define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 #define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 #define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 #endif #ifndef GL_EXT_texture_compression_rgtc #define GL_EXT_texture_compression_rgtc #define _ALLEGRO_GL_EXT_texture_compression_rgtc #define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB #define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC #define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD #define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE #endif #ifndef GL_EXT_texture_integer #define GL_EXT_texture_integer #define _ALLEGRO_GL_EXT_texture_integer #define GL_RGBA_INTEGER_MODE_EXT 0x8D9E #define GL_RGBA32UI_EXT 0x8D70 #define GL_RGB32UI_EXT 0x8D71 #define GL_ALPHA32UI_EXT 0x8D72 #define GL_INTENSITY32UI_EXT 0x8D73 #define GL_LUMINANCE32UI_EXT 0x8D74 #define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 #define GL_RGBA16UI_EXT 0x8D76 #define GL_RGB16UI_EXT 0x8D77 #define GL_ALPHA16UI_EXT 0x8D78 #define GL_INTENSITY16UI_EXT 0x8D79 #define GL_LUMINANCE16UI_EXT 0x8D7A #define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B #define GL_RGBA8UI_EXT 0x8D7C #define GL_RGB8UI_EXT 0x8D7D #define GL_ALPHA8UI_EXT 0x8D7E #define GL_INTENSITY8UI_EXT 0x8D7F #define GL_LUMINANCE8UI_EXT 0x8D80 #define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 #define GL_RGBA32I_EXT 0x8D82 #define GL_RGB32I_EXT 0x8D83 #define GL_ALPHA32I_EXT 0x8D84 #define GL_INTENSITY32I_EXT 0x8D85 #define GL_LUMINANCE32I_EXT 0x8D86 #define GL_LUMINANCE_ALPHA32I_EXT 0x8D87 #define GL_RGBA16I_EXT 0x8D88 #define GL_RGB16I_EXT 0x8D89 #define GL_ALPHA16I_EXT 0x8D8A #define GL_INTENSITY16I_EXT 0x8D8B #define GL_LUMINANCE16I_EXT 0x8D8C #define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D #define GL_RGBA8I_EXT 0x8D8E #define GL_RGB8I_EXT 0x8D8F #define GL_ALPHA8I_EXT 0x8D90 #define GL_INTENSITY8I_EXT 0x8D91 #define GL_LUMINANCE8I_EXT 0x8D92 #define GL_LUMINANCE_ALPHA8I_EXT 0x8D93 #define GL_RED_INTEGER_EXT 0x8D94 #define GL_GREEN_INTEGER_EXT 0x8D95 #define GL_BLUE_INTEGER_EXT 0x8D96 #define GL_ALPHA_INTEGER_EXT 0x8D97 #define GL_RGB_INTEGER_EXT 0x8D98 #define GL_RGBA_INTEGER_EXT 0x8D99 #define GL_BGR_INTEGER_EXT 0x8D9A #define GL_BGRA_INTEGER_EXT 0x8D9B #define GL_LUMINANCE_INTEGER_EXT 0x8D9C #define GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D #endif #ifndef GL_EXT_texture_shared_exponent #define GL_EXT_texture_shared_exponent #define _ALLEGRO_GL_EXT_texture_shared_exponent #define GL_RGB9_E5_EXT 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E #define GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F #endif #ifndef GL_NV_depth_buffer_float #define GL_NV_depth_buffer_float #define _ALLEGRO_GL_NV_depth_buffer_float #define GL_DEPTH_COMPONENT32F_NV 0x8DAB #define GL_DEPTH32F_STENCIL8_NV 0x8DAC #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD #define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF #endif #ifndef GL_NV_fragment_program4 #define GL_NV_fragment_program4 #define _ALLEGRO_GL_NV_fragment_program4 #endif #ifndef GL_NV_framebuffer_multisample_coverage #define GL_NV_framebuffer_multisample_coverage #define _ALLEGRO_GL_NV_framebuffer_multisample_coverage #define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB #define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 #endif #ifndef GL_NV_geometry_program4 #define GL_NV_geometry_program4 #define _ALLEGRO_GL_NV_geometry_program4 #define GL_GEOMETRY_PROGRAM_NV 0x8C26 #define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27 #define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 #if !defined GL_EXT_geometry_shader4 #define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA #define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB #define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 #define GL_LINES_ADJACENCY_EXT 0xA #define GL_LINE_STRIP_ADJACENCY_EXT 0xB #define GL_TRIANGLES_ADJACENCY_EXT 0xC #define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0xD #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 #define GL_PROGRAM_POINT_SIZE_EXT 0x8642 #endif #endif #ifndef GL_NV_gpu_program4 #define GL_NV_gpu_program4 #define _ALLEGRO_GL_NV_gpu_program4 #define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905 #define GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906 #define GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907 #define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908 #define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909 #define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5 #define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6 #endif #ifndef GL_NV_parameter_buffer_object #define GL_NV_parameter_buffer_object #define _ALLEGRO_GL_NV_parameter_buffer_object #define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0 #define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1 #define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2 #define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3 #define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4 #endif #ifndef GL_NV_transform_feedback #define GL_NV_transform_feedback #define _ALLEGRO_GL_NV_transform_feedback #define GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85 #define GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86 #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F #define GL_INTERLEAVED_ATTRIBS_NV 0x8C8C #define GL_SEPARATE_ATTRIBS_NV 0x8C8D #define GL_PRIMITIVES_GENERATED_NV 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88 #define GL_RASTERIZER_DISCARD_NV 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80 #define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E #define GL_ACTIVE_VARYINGS_NV 0x8C81 #define GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82 #define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F #define GL_BACK_PRIMARY_COLOR_NV 0x8C77 #define GL_BACK_SECONDARY_COLOR_NV 0x8C78 #define GL_TEXTURE_COORD_NV 0x8C79 #define GL_CLIP_DISTANCE_NV 0x8C7A #define GL_VERTEX_ID_NV 0x8C7B #define GL_PRIMITIVE_ID_NV 0x8C7C #define GL_GENERIC_ATTRIB_NV 0x8C7D #if !defined GL_NV_register_combiners #define GL_SECONDARY_COLOR_NV 0x852D #endif #if !defined GL_EXT_gpu_shader4 #define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 #define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 #define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 #endif #endif #ifndef GL_NV_vertex_program4 #define GL_NV_vertex_program4 #define _ALLEGRO_GL_NV_vertex_program4 #if !defined GL_EXT_vertex_shader4 #define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD #endif #endif #ifndef GL_GREMEDY_frame_terminator #define GL_GREMEDY_frame_terminator #define _ALLEGRO_GL_GREMEDY_frame_terminator #endif #ifndef GL_NV_conditional_render #define GL_NV_conditional_render #define _ALLEGRO_GL_NV_conditional_render #define GL_QUERY_WAIT_NV 0x8E13 #define GL_QUERY_NO_WAIT_NV 0x8E14 #define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 #define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 #endif #ifndef GL_NV_present_video #define GL_NV_present_video #define _ALLEGRO_GL_NV_present_video #define GL_FRAME_NV 0x8E26 #define GL_FIELDS_NV 0x8E27 #define GL_CURRENT_TIME_NV 0x8E28 #define GL_NUM_FILL_STREAMS_NV 0x8E29 #define GL_PRESENT_TIME_NV 0x8E2A #define GL_PRESENT_DURATION_NV 0x8E2B #endif #ifndef GL_EXT_transform_feedback #define GL_EXT_transform_feedback #define _ALLEGRO_GL_EXT_transform_feedback #define GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85 #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F #define GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C #define GL_SEPARATE_ATTRIBS_EXT 0x8C8D #define GL_PRIMITIVES_GENERATED_EXT 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88 #define GL_RASTERIZER_DISCARD_EXT 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 #define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76 #endif #ifndef GL_EXT_direct_state_access #define GL_EXT_direct_state_access #define _ALLEGRO_GL_EXT_direct_state_access #define GL_PROGRAM_MATRIX_EXT 0x8E2D #define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E #define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F #endif #ifndef GL_EXT_texture_swizzle #define GL_EXT_texture_swizzle #define _ALLEGRO_GL_EXT_texture_swizzle #define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 #define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 #define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 #define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 #define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 #endif #ifndef GL_NV_explicit_multisample #define GL_NV_explicit_multisample #define _ALLEGRO_GL_NV_explicit_multisample #define GL_SAMPLE_POSITION_NV 0x8E50 #define GL_SAMPLE_MASK_NV 0x8E51 #define GL_SAMPLE_MASK_VALUE_NV 0x8E52 #define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53 #define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54 #define GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59 #define GL_TEXTURE_RENDERBUFFER_NV 0x8E55 #define GL_SAMPLER_RENDERBUFFER_NV 0x8E56 #define GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57 #define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58 #endif #ifndef GL_NV_transform_feedback2 #define GL_NV_transform_feedback2 #define _ALLEGRO_GL_NV_transform_feedback2 #define GL_TRANSFORM_FEEDBACK_NV 0x8E22 #define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23 #define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24 #define GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25 #endif #ifndef GL_ATI_meminfo #define GL_ATI_meminfo #define _ALLEGRO_GL_ATI_meminfo #define GL_VBO_FREE_MEMORY_ATI 0x87FB #define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC #define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD #endif #ifndef GL_AMD_performance_monitor #define GL_AMD_performance_monitor #define _ALLEGRO_GL_AMD_performance_monitor #define GL_COUNTER_TYPE_AMD 0x8BC0 #define GL_COUNTER_RANGE_AMD 0x8BC1 #define GL_UNSIGNED_INT64_AMD 0x8BC2 #define GL_PERCENTAGE_AMD 0x8BC3 #define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 #define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 #define GL_PERFMON_RESULT_AMD 0x8BC6 #endif #ifndef GL_AMD_texture_texture4 #define GL_AMD_texture_texture4 #define _ALLEGRO_GL_AMD_texture_texture4 #endif #ifndef GL_AMD_vertex_shader_tesselator #define GL_AMD_vertex_shader_tesselator #define _ALLEGRO_GL_AMD_vertex_shader_tesselator #define GL_SAMPLER_BUFFER_AMD 0x9001 #define GL_INT_SAMPLER_BUFFER_AMD 0x9002 #define GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003 #define GL_TESSELLATION_MODE_AMD 0x9004 #define GL_TESSELLATION_FACTOR_AMD 0x9005 #define GL_DISCRETE_AMD 0x9006 #define GL_CONTINUOUS_AMD 0x9007 #endif #ifndef GL_EXT_provoking_vertex #define GL_EXT_provoking_vertex #define _ALLEGRO_GL_EXT_provoking_vertex #define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C #define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D #define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E #define GL_PROVOKING_VERTEX_EXT 0x8E4F #endif #ifndef GL_EXT_texture_snorm #define GL_EXT_texture_snorm #define _ALLEGRO_GL_EXT_texture_snorm #define GL_ALPHA_SNORM 0x9010 #define GL_LUMINANCE_SNORM 0x9011 #define GL_LUMINANCE_ALPHA_SNORM 0x9012 #define GL_INTENSITY_SNORM 0x9013 #define GL_ALPHA8_SNORM 0x9014 #define GL_LUMINANCE8_SNORM 0x9015 #define GL_LUMINANCE8_ALPHA8_SNORM 0x9016 #define GL_INTENSITY8_SNORM 0x9017 #define GL_ALPHA16_SNORM 0x9018 #define GL_LUMINANCE16_SNORM 0x9019 #define GL_LUMINANCE16_ALPHA16_SNORM 0x901A #define GL_INTENSITY16_SNORM 0x901B /* reuse GL_RED_SNORM */ /* reuse GL_RG_SNORM */ /* reuse GL_RGB_SNORM */ /* reuse GL_RGBA_SNORM */ /* reuse GL_R8_SNORM */ /* reuse GL_RG8_SNORM */ /* reuse GL_RGB8_SNORM */ /* reuse GL_RGBA8_SNORM */ /* reuse GL_R16_SNORM */ /* reuse GL_RG16_SNORM */ /* reuse GL_RGB16_SNORM */ /* reuse GL_RGBA16_SNORM */ /* reuse GL_SIGNED_NORMALIZED */ #endif #ifndef GL_AMD_draw_buffers_blend #define GL_AMD_draw_buffers_blend #define _ALLEGRO_GL_AMD_draw_buffers_blend #endif #ifndef GL_APPLE_texture_range #define GL_APPLE_texture_range #define _ALLEGRO_GL_APPLE_texture_range #define GL_TEXTURE_RANGE_LENGTH_APPLE 0x85B7 #define GL_TEXTURE_RANGE_POINTER_APPLE 0x85B8 #define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC #define GL_STORAGE_PRIVATE_APPLE 0x85BD /* reuse GL_STORAGE_CACHED_APPLE */ /* reuse GL_STORAGE_SHARED_APPLE */ #endif #ifndef GL_APPLE_float_pixels #define GL_APPLE_float_pixels #define _ALLEGRO_GL_APPLE_float_pixels #define GL_HALF_APPLE 0x140B #define GL_RGBA_FLOAT32_APPLE 0x8814 #define GL_RGB_FLOAT32_APPLE 0x8815 #define GL_ALPHA_FLOAT32_APPLE 0x8816 #define GL_INTENSITY_FLOAT32_APPLE 0x8817 #define GL_LUMINANCE_FLOAT32_APPLE 0x8818 #define GL_LUMINANCE_ALPHA_FLOAT32_APPLE 0x8819 #define GL_RGBA_FLOAT16_APPLE 0x881A #define GL_RGB_FLOAT16_APPLE 0x881B #define GL_ALPHA_FLOAT16_APPLE 0x881C #define GL_INTENSITY_FLOAT16_APPLE 0x881D #define GL_LUMINANCE_FLOAT16_APPLE 0x881E #define GL_LUMINANCE_ALPHA_FLOAT16_APPLE 0x881F #define GL_COLOR_FLOAT_APPLE 0x8A0F #endif #ifndef GL_APPLE_vertex_program_evaluators #define GL_APPLE_vertex_program_evaluators #define _ALLEGRO_GL_APPLE_vertex_program_evaluators #define GL_VERTEX_ATTRIB_MAP1_APPLE 0x8A00 #define GL_VERTEX_ATTRIB_MAP2_APPLE 0x8A01 #define GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE 0x8A02 #define GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03 #define GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04 #define GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05 #define GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE 0x8A06 #define GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07 #define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08 #define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09 #endif #ifndef GL_APPLE_aux_depth_stencil #define GL_APPLE_aux_depth_stencil #define _ALLEGRO_GL_APPLE_aux_depth_stencil #define GL_AUX_DEPTH_STENCIL_APPLE 0x8A14 #endif #ifndef GL_APPLE_object_purgeable #define GL_APPLE_object_purgeable #define _ALLEGRO_GL_APPLE_object_purgeable #define GL_BUFFER_OBJECT_APPLE 0x85B3 #define GL_RELEASED_APPLE 0x8A19 #define GL_VOLATILE_APPLE 0x8A1A #define GL_RETAINED_APPLE 0x8A1B #define GL_UNDEFINED_APPLE 0x8A1C #define GL_PURGEABLE_APPLE 0x8A1D #endif #ifndef GL_APPLE_row_bytes #define GL_APPLE_row_bytes #define _ALLEGRO_GL_APPLE_row_bytes #define GL_PACK_ROW_BYTES_APPLE 0x8A15 #define GL_UNPACK_ROW_BYTES_APPLE 0x8A16 #endif #ifndef GL_APPLE_rgb_422 #define GL_APPLE_rgb_422 #define _ALLEGRO_GL_APPLE_rgb_422 #define GL_RGB_422_APPLE 0x8A1F /* reuse GL_UNSIGNED_SHORT_8_8_APPLE */ /* reuse GL_UNSIGNED_SHORT_8_8_REV_APPLE */ #endif #ifndef GL_NV_video_capture #define GL_NV_video_capture #define _ALLEGRO_GL_NV_video_capture #define GL_VIDEO_BUFFER_NV 0x9020 #define GL_VIDEO_BUFFER_BINDING_NV 0x9021 #define GL_FIELD_UPPER_NV 0x9022 #define GL_FIELD_LOWER_NV 0x9023 #define GL_NUM_VIDEO_CAPTURE_STREAMS_NV 0x9024 #define GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025 #define GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026 #define GL_LAST_VIDEO_CAPTURE_STATUS_NV 0x9027 #define GL_VIDEO_BUFFER_PITCH_NV 0x9028 #define GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029 #define GL_VIDEO_COLOR_CONVERSION_MAX_NV 0x902A #define GL_VIDEO_COLOR_CONVERSION_MIN_NV 0x902B #define GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C #define GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D #define GL_PARTIAL_SUCCESS_NV 0x902E #define GL_SUCCESS_NV 0x902F #define GL_FAILURE_NV 0x9030 #define GL_YCBYCR8_422_NV 0x9031 #define GL_YCBAYCR8A_4224_NV 0x9032 #define GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV 0x9033 #define GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034 #define GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV 0x9035 #define GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036 #define GL_Z4Y12Z4CB12Z4CR12_444_NV 0x9037 #define GL_VIDEO_CAPTURE_FRAME_WIDTH_NV 0x9038 #define GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV 0x9039 #define GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A #define GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B #define GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C #endif #ifndef GL_EXT_separate_shader_objects #define GL_EXT_separate_shader_objects #define _ALLEGRO_GL_EXT_separate_shader_objects #define GL_ACTIVE_PROGRAM_EXT 0x8B8D #endif #ifndef GL_NV_parameter_buffer_object2 #define GL_NV_parameter_buffer_object2 #define _ALLEGRO_GL_NV_parameter_buffer_object2 #endif #ifndef GL_NV_shader_buffer_load #define GL_NV_shader_buffer_load #define _ALLEGRO_GL_NV_shader_buffer_load #define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D #define GL_GPU_ADDRESS_NV 0x8F34 #define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 #endif #ifndef GL_NV_vertex_buffer_unified_memory #define GL_NV_vertex_buffer_unified_memory #define _ALLEGRO_GL_NV_vertex_buffer_unified_memory #define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E #define GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F #define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20 #define GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21 #define GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22 #define GL_COLOR_ARRAY_ADDRESS_NV 0x8F23 #define GL_INDEX_ARRAY_ADDRESS_NV 0x8F24 #define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25 #define GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26 #define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27 #define GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28 #define GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29 #define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A #define GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B #define GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C #define GL_COLOR_ARRAY_LENGTH_NV 0x8F2D #define GL_INDEX_ARRAY_LENGTH_NV 0x8F2E #define GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F #define GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30 #define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31 #define GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32 #define GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33 #endif #ifndef GL_NV_texture_barrier #define GL_NV_texture_barrier #define _ALLEGRO_GL_NV_texture_barrier #endif #ifndef GL_AMD_shader_stencil_export #define GL_AMD_shader_stencil_export #define _ALLEGRO_GL_AMD_shader_stencil_export #endif #ifndef GL_AMD_seamless_cubemap_per_texture #define GL_AMD_seamless_cubemap_per_texture #define _ALLEGRO_GL_AMD_seamless_cubemap_per_texture /* reuse GL_TEXTURE_CUBE_MAP_SEAMLESS_ARB */ #endif #ifndef GL_AMD_conservative_depth #define GL_AMD_conservative_depth #define _ALLEGRO_GL_AMD_conservative_depth #endif allegro5-5.2.10.1/include/allegro5/opengl/GLext/gl_ext_list.h000066400000000000000000000355501473414355200236220ustar00rootroot00000000000000AGL_EXT(ARB_imaging, 0) AGL_EXT(ARB_multitexture, 1_2_1) AGL_EXT(ARB_transpose_matrix, 1_3) AGL_EXT(ARB_multisample, 1_3) AGL_EXT(ARB_texture_env_add, 1_3) AGL_EXT(ARB_texture_cube_map, 1_3) AGL_EXT(ARB_texture_compression, 1_3) AGL_EXT(ARB_texture_border_clamp, 1_3) AGL_EXT(ARB_point_parameters, 1_4) AGL_EXT(ARB_vertex_blend, 0) AGL_EXT(ARB_texture_env_combine, 1_3) AGL_EXT(ARB_texture_env_crossbar, 1_4) AGL_EXT(ARB_texture_env_dot3, 1_3) AGL_EXT(ARB_texture_mirrored_repeat, 1_4) AGL_EXT(ARB_depth_texture, 1_4) AGL_EXT(ARB_shadow, 1_4) AGL_EXT(ARB_shadow_ambient, 0) AGL_EXT(ARB_window_pos, 1_4) AGL_EXT(ARB_vertex_program, 0) AGL_EXT(ARB_fragment_program, 0) AGL_EXT(ARB_vertex_buffer_object, 1_5) AGL_EXT(ARB_occlusion_query, 1_5) AGL_EXT(ARB_shader_objects, 0) /* Those were promoted to Core in */ AGL_EXT(ARB_vertex_shader, 0) /* 2.0 with modifications. */ AGL_EXT(ARB_fragment_shader, 0) /* */ AGL_EXT(ARB_shading_language_100, 0) /* */ AGL_EXT(ARB_texture_non_power_of_two,2_0) AGL_EXT(ARB_point_sprite, 2_0) AGL_EXT(ARB_fragment_program_shadow, 0) AGL_EXT(ARB_draw_buffers, 2_0) AGL_EXT(ARB_texture_rectangle, 3_1) AGL_EXT(ARB_color_buffer_float, 3_0) AGL_EXT(ARB_half_float_pixel, 3_0) AGL_EXT(ARB_texture_float, 3_0) AGL_EXT(ARB_pixel_buffer_object, 2_1) AGL_EXT(ARB_instanced_arrays, 0) AGL_EXT(ARB_draw_instanced, 3_1) AGL_EXT(ARB_geometry_shader4, 0) AGL_EXT(ARB_texture_buffer_object, 3_1) AGL_EXT(ARB_depth_buffer_float, 3_0) AGL_EXT(ARB_framebuffer_object, 3_0) AGL_EXT(ARB_framebuffer_sRGB, 3_0) AGL_EXT(ARB_half_float_vertex, 3_0) AGL_EXT(ARB_map_buffer_range, 3_0) AGL_EXT(ARB_texture_compression_rgtc,3_0) AGL_EXT(ARB_texture_rg, 3_0) AGL_EXT(ARB_vertex_array_object, 3_0) AGL_EXT(ARB_copy_buffer, 3_1) AGL_EXT(ARB_compatibility, 0) AGL_EXT(ARB_uniform_buffer_object, 3_1) AGL_EXT(ARB_shader_texture_lod, 0) AGL_EXT(ARB_depth_clamp, 3_2) AGL_EXT(ARB_draw_elements_base_vertex, 3_2) AGL_EXT(ARB_fragment_coord_conventions, 3_2) AGL_EXT(ARB_provoking_vertex, 3_2) AGL_EXT(ARB_seamless_cube_map, 3_2) AGL_EXT(ARB_sync, 3_2) AGL_EXT(ARB_texture_multisample, 3_2) AGL_EXT(ARB_vertex_array_bgra, 0) AGL_EXT(ARB_draw_buffers_blend, 0) AGL_EXT(ARB_sample_shading, 0) AGL_EXT(ARB_texture_cube_map_array, 0) AGL_EXT(ARB_texture_gather, 0) AGL_EXT(ARB_texture_query_lod, 0) AGL_EXT(ARB_shading_language_include, 0) AGL_EXT(ARB_texture_compression_bptc, 0) AGL_EXT(ARB_blend_func_extended, 3_3) AGL_EXT(ARB_explicit_attrib_location, 3_3) AGL_EXT(ARB_occlusion_query2, 3_3) AGL_EXT(ARB_sampler_objects, 3_3) AGL_EXT(ARB_shader_bit_encoding, 3_3) AGL_EXT(ARB_texture_rgb10_a2ui, 3_3) AGL_EXT(ARB_texture_swizzle, 3_3) AGL_EXT(ARB_timer_query, 3_3) AGL_EXT(ARB_vertex_type_2_10_10_10_rev, 3_3) AGL_EXT(ARB_draw_indirect, 4_0) AGL_EXT(ARB_gpu_shader5, 4_0) AGL_EXT(ARB_gpu_shader_fp64, 4_0) AGL_EXT(ARB_shader_subroutine, 4_0) AGL_EXT(ARB_tessellation_shader, 4_0) AGL_EXT(ARB_texture_buffer_object_rgb32, 4_0) AGL_EXT(ARB_transform_feedback2, 4_0) AGL_EXT(ARB_transform_feedback3, 4_0) AGL_EXT(EXT_abgr, 0) AGL_EXT(EXT_blend_color, 1_1) AGL_EXT(EXT_polygon_offset, 1_1) AGL_EXT(EXT_texture, 1_1) AGL_EXT(EXT_texture3D, 1_2) AGL_EXT(SGIS_texture_filter4, 0) AGL_EXT(EXT_subtexture, 1_1) AGL_EXT(EXT_copy_texture, 1_1) AGL_EXT(EXT_histogram, 0) AGL_EXT(EXT_convolution, 0) AGL_EXT(SGI_color_matrix, 0) AGL_EXT(SGI_color_table, 0) AGL_EXT(SGIS_pixel_texture, 0) AGL_EXT(SGIX_pixel_texture, 0) AGL_EXT(SGIS_texture4D, 0) AGL_EXT(SGI_texture_color_table, 0) AGL_EXT(EXT_cmyka, 0) AGL_EXT(EXT_texture_object, 1_1) AGL_EXT(SGIS_detail_texture, 0) AGL_EXT(SGIS_sharpen_texture, 0) AGL_EXT(EXT_packed_pixels, 1_2) AGL_EXT(SGIS_texture_lod, 1_2) AGL_EXT(SGIS_multisample, 1_3) AGL_EXT(EXT_rescale_normal, 1_2) AGL_EXT(EXT_vertex_array, 1_1) AGL_EXT(EXT_misc_attribute, 0) AGL_EXT(SGIS_generate_mipmap, 1_4) AGL_EXT(SGIX_clipmap, 0) AGL_EXT(SGIX_shadow, 0) AGL_EXT(SGIS_texture_edge_clamp, 1_2) AGL_EXT(SGIS_texture_border_clamp, 0) AGL_EXT(EXT_blend_minmax, 0) AGL_EXT(EXT_blend_subtract, 0) AGL_EXT(EXT_blend_logic_op, 1_1) AGL_EXT(SGIX_interlace, 0) AGL_EXT(SGIS_texture_select, 0) AGL_EXT(SGIX_sprite, 0) AGL_EXT(SGIX_texture_multi_buffer, 0) AGL_EXT(EXT_point_parameters, 0) AGL_EXT(SGIX_instruments, 0) AGL_EXT(SGIX_texture_scale_bias, 0) AGL_EXT(SGIX_framezoom, 0) AGL_EXT(SGIX_tag_sample_buffer, 0) AGL_EXT(SGIX_reference_plane, 0) AGL_EXT(SGIX_flush_raster, 0) AGL_EXT(SGIX_depth_texture, 0) AGL_EXT(SGIS_fog_function, 0) AGL_EXT(SGIX_fog_offset, 0) AGL_EXT(HP_image_transform, 0) AGL_EXT(HP_convolution_border_modes, 0) AGL_EXT(SGIX_texture_add_env, 0) AGL_EXT(EXT_color_subtable, 0) AGL_EXT(PGI_vertex_hints, 0) AGL_EXT(PGI_misc_hints, 0) AGL_EXT(EXT_paletted_texture, 0) AGL_EXT(EXT_clip_volume_hint, 0) AGL_EXT(SGIX_list_priority, 0) AGL_EXT(SGIX_ir_instrument1, 0) AGL_EXT(SGIX_texture_lod_bias, 0) AGL_EXT(SGIX_shadow_ambient, 0) AGL_EXT(EXT_index_texture, 0) AGL_EXT(EXT_index_material, 0) AGL_EXT(EXT_index_func, 0) AGL_EXT(EXT_index_array_formats, 0) AGL_EXT(EXT_compiled_vertex_array, 0) AGL_EXT(EXT_cull_vertex, 0) AGL_EXT(SGIX_ycrcb, 0) AGL_EXT(EXT_fragment_lighting, 0) AGL_EXT(IBM_rasterpos_clip, 0) AGL_EXT(HP_texture_lighting, 0) AGL_EXT(EXT_draw_range_elements, 0) AGL_EXT(WIN_phong_shading, 0) AGL_EXT(WIN_specular_fog, 0) AGL_EXT(EXT_light_texture, 0) AGL_EXT(SGIX_blend_alpha_minmax, 0) AGL_EXT(EXT_scene_marker, 0) AGL_EXT(SGIX_pixel_texture_bits, 0) AGL_EXT(EXT_bgra, 1_2) AGL_EXT(SGIX_async, 0) AGL_EXT(SGIX_async_pixel, 0) AGL_EXT(SGIX_async_histogram, 0) AGL_EXT(INTEL_texture_scissor, 0) AGL_EXT(INTEL_parallel_arrays, 0) AGL_EXT(HP_occlusion_test, 0) AGL_EXT(EXT_pixel_transform, 0) AGL_EXT(EXT_pixel_transform_color_table, 0) AGL_EXT(EXT_shared_texture_palette, 0) AGL_EXT(EXT_separate_specular_color, 1_2) AGL_EXT(EXT_secondary_color, 1_4) AGL_EXT(EXT_texture_env, 0) AGL_EXT(EXT_texture_perturb_normal, 0) AGL_EXT(EXT_multi_draw_arrays, 1_4) AGL_EXT(EXT_fog_coord, 1_4) AGL_EXT(REND_screen_coordinates, 0) AGL_EXT(EXT_coordinate_frame, 0) AGL_EXT(EXT_texture_env_combine, 0) AGL_EXT(APPLE_specular_vector, 0) AGL_EXT(APPLE_transform_hint, 0) AGL_EXT(SUNX_constant_data, 0) AGL_EXT(SUN_global_alpha, 0) AGL_EXT(SUN_triangle_list, 0) AGL_EXT(SUN_vertex, 0) AGL_EXT(EXT_blend_func_separate, 1_4) AGL_EXT(INGR_color_clamp, 0) AGL_EXT(INGR_interlace_read, 0) AGL_EXT(EXT_stencil_wrap, 1_4) AGL_EXT(EXT_422_pixels, 0) AGL_EXT(NV_texgen_reflection, 0) AGL_EXT(SGIX_texture_range, 0) AGL_EXT(SUN_convolution_border_modes, 0) AGL_EXT(EXT_texture_env_add, 0) AGL_EXT(EXT_texture_lod_bias, 1_4) AGL_EXT(EXT_texture_filter_anisotropic, 0) AGL_EXT(EXT_vertex_weighting, 0) AGL_EXT(NV_light_max_exponent, 0) AGL_EXT(NV_vertex_array_range, 0) AGL_EXT(NV_register_combiners, 0) AGL_EXT(NV_fog_distance, 0) AGL_EXT(NV_texgen_emboss, 0) AGL_EXT(NV_blend_square, 1_4) AGL_EXT(NV_texture_env_combine4, 0) AGL_EXT(MESA_resize_buffers, 0) AGL_EXT(MESA_window_pos, 0) AGL_EXT(EXT_texture_compression_s3tc, 0) AGL_EXT(IBM_cull_vertex, 0) AGL_EXT(IBM_multimode_draw_arrays, 0) AGL_EXT(IBM_vertex_array_lists, 0) AGL_EXT(3DFX_texture_compression_FXT1, 0) AGL_EXT(3DFX_multisample, 0) AGL_EXT(3DFX_tbuffer, 0) AGL_EXT(SGIX_vertex_preclip, 0) AGL_EXT(SGIX_resample, 0) AGL_EXT(SGIS_texture_color_mask, 0) AGL_EXT(EXT_texture_env_dot3, 0) AGL_EXT(ATI_texture_mirror_once, 0) AGL_EXT(NV_fence, 0) AGL_EXT(IBM_static_data, 0) AGL_EXT(IBM_texture_mirrored_repeat, 0) AGL_EXT(NV_evaluators, 0) AGL_EXT(NV_packed_depth_stencil, 3_0) AGL_EXT(NV_register_combiners2, 0) AGL_EXT(NV_texture_compression_vtc, 0) AGL_EXT(NV_texture_rectangle, 0) AGL_EXT(NV_texture_shader, 0) AGL_EXT(NV_texture_shader2, 0) AGL_EXT(NV_vertex_array_range2, 0) AGL_EXT(NV_vertex_program, 0) AGL_EXT(SGIX_texture_coordinate_clamp, 0) AGL_EXT(OML_interlace, 0) AGL_EXT(OML_subsample, 0) AGL_EXT(OML_resample, 0) AGL_EXT(NV_copy_depth_to_color, 0) AGL_EXT(ATI_envmap_bumpmap, 0) AGL_EXT(ATI_fragment_shader, 0) AGL_EXT(ATI_pn_triangles, 0) AGL_EXT(ATI_vertex_array_object, 0) AGL_EXT(EXT_vertex_shader, 0) AGL_EXT(ATI_vertex_streams, 0) AGL_EXT(ATI_element_array, 0) AGL_EXT(SUN_mesh_array, 0) AGL_EXT(SUN_slice_accum, 0) AGL_EXT(NV_multisample_filter_hint, 0) AGL_EXT(NV_depth_clamp, 0) AGL_EXT(NV_occlusion_query, 0) AGL_EXT(NV_point_sprite, 0) AGL_EXT(NV_texture_shader3, 0) AGL_EXT(NV_vertex_program1_1, 0) AGL_EXT(EXT_shadow_funcs, 1_5) AGL_EXT(EXT_stencil_two_side, 0) AGL_EXT(ATI_text_fragment_shader, 0) AGL_EXT(APPLE_client_storage, 0) AGL_EXT(APPLE_element_array, 0) AGL_EXT(APPLE_fence, 0) AGL_EXT(APPLE_vertex_array_object, 3_0) AGL_EXT(APPLE_vertex_array_range, 0) AGL_EXT(APPLE_ycbcr_422, 0) AGL_EXT(S3_s3tc, 0) AGL_EXT(ATI_draw_buffers, 0) AGL_EXT(ATI_texture_env_combine3, 0) AGL_EXT(ATI_texture_float, 0) AGL_EXT(NV_float_buffer, 0) AGL_EXT(NV_fragment_program, 0) AGL_EXT(NV_half_float, 3_0) AGL_EXT(NV_pixel_data_range, 0) AGL_EXT(NV_primitive_restart, 3_1) AGL_EXT(NV_texture_expand_normal, 0) AGL_EXT(NV_vertex_program2, 0) AGL_EXT(ATI_map_object_buffer, 0) AGL_EXT(ATI_separate_stencil, 2_0) AGL_EXT(ATI_vertex_attrib_array_object, 0) AGL_EXT(OES_byte_coordinates, 0) AGL_EXT(OES_fixed_point, 0) AGL_EXT(OES_single_precision, 0) AGL_EXT(OES_compressed_paletted_texture, 0) AGL_EXT(OES_read_format, 0) AGL_EXT(OES_query_matrix, 0) AGL_EXT(OES_framebuffer_object, 0) AGL_EXT(OES_texture_npot, 0) AGL_EXT(EXT_depth_bounds_test, 0) AGL_EXT(EXT_texture_mirror_clamp, 0) AGL_EXT(EXT_blend_equation_separate, 0) AGL_EXT(MESA_pack_invert, 0) AGL_EXT(MESA_ycbcr_texture, 0) AGL_EXT(EXT_pixel_buffer_object, 0) AGL_EXT(NV_fragment_program_option, 0) AGL_EXT(NV_fragment_program2, 0) AGL_EXT(NV_vertex_program2_option, 0) AGL_EXT(NV_vertex_program3, 0) AGL_EXT(EXT_texture_compression_dxt1, 0) AGL_EXT(EXT_framebuffer_object, 3_0) AGL_EXT(GREMEDY_string_marker, 0) AGL_EXT(EXT_packed_depth_stencil, 0) AGL_EXT(EXT_stencil_clear_tag, 0) AGL_EXT(EXT_texture_sRGB, 2_1) AGL_EXT(EXT_framebuffer_blit, 3_0) AGL_EXT(EXT_framebuffer_multisample, 3_0) AGL_EXT(MESAX_texture_stack, 0) AGL_EXT(EXT_timer_query, 0) AGL_EXT(EXT_gpu_program_parameters, 0) AGL_EXT(APPLE_flush_buffer_range, 0) #ifdef ALLEGRO_MACOSX AGL_EXT(EXT_texture_rectangle, 0) #endif AGL_EXT(EXT_bindable_uniform, 0) AGL_EXT(EXT_draw_buffers2, 3_0) AGL_EXT(EXT_draw_instanced, 0) AGL_EXT(EXT_framebuffer_sRGB, 3_0) AGL_EXT(EXT_geometry_shader4, 0) AGL_EXT(EXT_gpu_shader4, 3_0) AGL_EXT(EXT_packed_float, 3_0) AGL_EXT(EXT_texture_array, 3_0) AGL_EXT(EXT_texture_buffer_object, 0) AGL_EXT(EXT_texture_compression_latc, 0) AGL_EXT(EXT_texture_compression_rgtc,3_0) AGL_EXT(EXT_texture_integer, 3_0) AGL_EXT(EXT_texture_shared_exponent, 3_0) AGL_EXT(NV_depth_buffer_float, 3_0) AGL_EXT(NV_fragment_program4, 0) AGL_EXT(NV_framebuffer_multisample_coverage, 0) AGL_EXT(NV_geometry_program4, 0) AGL_EXT(NV_gpu_program4, 0) AGL_EXT(NV_parameter_buffer_object, 0) AGL_EXT(NV_transform_feedback, 0) AGL_EXT(NV_vertex_program4, 0) AGL_EXT(GREMEDY_frame_terminator, 0) AGL_EXT(NV_conditional_render, 3_0) AGL_EXT(NV_present_video, 0) AGL_EXT(EXT_direct_state_access, 0) AGL_EXT(EXT_transform_feedback, 3_0) AGL_EXT(EXT_texture_swizzle, 0) AGL_EXT(NV_explicit_multisample, 0) AGL_EXT(NV_transform_feedback2, 0) AGL_EXT(ATI_meminfo, 0) AGL_EXT(AMD_performance_monitor, 0) AGL_EXT(AMD_texture_texture4, 0) AGL_EXT(AMD_vertex_shader_tesselator, 0) AGL_EXT(EXT_provoking_vertex, 0) AGL_EXT(EXT_texture_snorm, 0) AGL_EXT(AMD_draw_buffers_blend, 0) AGL_EXT(APPLE_texture_range, 0) AGL_EXT(APPLE_float_pixels, 0) AGL_EXT(APPLE_vertex_program_evaluators, 0) AGL_EXT(APPLE_aux_depth_stencil, 0) AGL_EXT(APPLE_object_purgeable, 0) AGL_EXT(APPLE_row_bytes, 0) AGL_EXT(APPLE_rgb_422, 0) AGL_EXT(NV_video_capture, 0) AGL_EXT(EXT_separate_shader_objects, 0) AGL_EXT(NV_parameter_buffer_object2, 0) AGL_EXT(NV_shader_buffer_load, 0) AGL_EXT(NV_vertex_buffer_unified_memory, 0) AGL_EXT(NV_texture_barrier, 0) AGL_EXT(AMD_shader_stencil_export, 0) AGL_EXT(AMD_seamless_cubemap_per_texture, 0) AGL_EXT(AMD_conservative_depth, 0) allegro5-5.2.10.1/include/allegro5/opengl/GLext/glx_ext_api.h000066400000000000000000000234411473414355200236040ustar00rootroot00000000000000#ifdef _ALLEGRO_GLX_VERSION_1_3 /* GLX 1.3 */ AGL_API(GLXFBConfig *, GetFBConfigs, (Display *, int, int *)) AGL_API(GLXFBConfig *, ChooseFBConfig, (Display *, int, const int *, int *)) AGL_API(int, GetFBConfigAttrib, (Display *, GLXFBConfig, int, int *)) AGL_API(XVisualInfo *, GetVisualFromFBConfig, (Display *, GLXFBConfig)) AGL_API(GLXWindow, CreateWindow, (Display *, GLXFBConfig, Window, const int *)) AGL_API(void, DestroyWindow, (Display *, GLXWindow)) AGL_API(GLXPixmap, CreatePixmap, (Display *, GLXFBConfig, Pixmap, const int *)) AGL_API(void, DestroyPixmap, (Display *, GLXPixmap)) AGL_API(GLXPbuffer, CreatePbuffer, (Display *, GLXFBConfig, const int *)) AGL_API(void, DestroyPbuffer, (Display *, GLXPbuffer)) AGL_API(void, QueryDrawable, (Display *, GLXDrawable, int, unsigned int *)) AGL_API(GLXContext, CreateNewContext, (Display *, GLXFBConfig, int, GLXContext, Bool)) AGL_API(Bool, MakeContextCurrent, (Display *, GLXDrawable, GLXDrawable, GLXContext)) AGL_API(GLXDrawable, GetCurrentReadDrawable, (void)) AGL_API(Display *, GetCurrentDisplay, (void)) AGL_API(int, QueryContext, (Display *, GLXContext, int, int *)) AGL_API(void, SelectEvent, (Display *, GLXDrawable, unsigned long)) AGL_API(void, GetSelectedEvent, (Display *, GLXDrawable, unsigned long *)) #endif #ifdef _ALLEGRO_GLX_VERSION_1_4 /* GLX 1.4 */ AGL_API(__GLXextFuncPtr, GetProcAddress, (const GLubyte *)) #endif #ifdef _ALLEGRO_GLX_ARB_get_proc_address /* GLX_ARB_get_proc_address */ AGL_API(__GLXextFuncPtr, GetProcAddressARB, (const GLubyte *)) #endif #ifdef _ALLEGRO_GLX_ARB_create_context AGL_API(GLXContext, CreateContextAttribsARB, (Display *, GLXFBConfig, GLXContext, Bool, const int *)) #endif #ifdef _ALLEGRO_GLX_SGI_swap_control /* GLX_SGI_swap_control */ AGL_API(int, SwapIntervalSGI, (int)) #endif #ifdef _ALLEGRO_GLX_SGI_video_sync /* GLX_SGI_video_sync */ AGL_API(int, GetVideoSyncSGI, (unsigned int *)) AGL_API(int, WaitVideoSyncSGI, (int, int, unsigned int *)) #endif #ifdef _ALLEGRO_GLX_SGI_make_current_read /* GLX_SGI_make_current_read */ AGL_API(Bool, MakeCurrentReadSGI, (Display *, GLXDrawable, GLXDrawable, GLXContext)) AGL_API(GLXDrawable, GetCurrentReadDrawableSGI, (void)) #endif #ifdef _ALLEGRO_GLX_SGIX_video_source /* GLX_SGIX_video_source */ /* This one needs SGI's header file to be included first */ #ifdef _VL_H_ AGL_API(GLXVideoSourceSGIX, CreateGLXVideoSourceSGIX, (Display *, int, VLServer, VLPath, int, VLNode)) AGL_API(void, DestroyGLXVideoSourceSGIX, (Display *, GLXVideoSourceSGIX)) #endif #endif #ifdef _ALLEGRO_GLX_EXT_import_context /* GLX_EXT_import_context */ AGL_API(Display *, GetCurrentDisplayEXT, (void)) AGL_API(int, QueryContextInfoEXT, (Display *, GLXContext, int, int *)) AGL_API(GLXContextID, GetContextIDEXT, (const GLXContext)) AGL_API(GLXContext, ImportContextEXT, (Display *, GLXContextID)) AGL_API(void, FreeContextEXT, (Display *, GLXContext)) #endif #ifdef _ALLEGRO_GLX_SGIX_fbconfig /* GLX_SGIX_fbconfig */ AGL_API(int, GetFBConfigAttribSGIX, (Display *, GLXFBConfigSGIX, int, int *)) AGL_API(GLXFBConfigSGIX *, ChooseFBConfigSGIX, (Display *, int, int *, int *)) AGL_API(GLXPixmap, CreateGLXPixmapWithConfigSGIX, (Display *, GLXFBConfigSGIX, Pixmap)) AGL_API(GLXContext, CreateContextWithConfigSGIX, (Display *, GLXFBConfigSGIX, int, GLXContext, Bool)) AGL_API(XVisualInfo *, GetVisualFromFBConfigSGIX, (Display *, GLXFBConfigSGIX)) AGL_API(GLXFBConfigSGIX, GetFBConfigFromVisualSGIX, (Display *, XVisualInfo *)) #endif #ifdef _ALLEGRO_GLX_SGIX_pbuffer /* GLX_SGIX_pbuffer */ AGL_API(GLXPbufferSGIX, CreateGLXPbufferSGIX, (Display *, GLXFBConfigSGIX, unsigned int, unsigned int, int *)) AGL_API(void, DestroyGLXPbufferSGIX, (Display *, GLXPbufferSGIX)) AGL_API(int, QueryGLXPbufferSGIX, (Display *, GLXPbufferSGIX, int, unsigned int *)) AGL_API(void, SelectEventSGIX, (Display *, GLXDrawable, unsigned long)) AGL_API(void, GetSelectedEventSGIX, (Display *, GLXDrawable, unsigned long *)) #endif #ifdef _ALLEGRO_GLX_SGI_cushion /* GLX_SGI_cushion */ AGL_API(void, CushionSGI, (Display *, Window, float)) #endif #ifdef _ALLEGRO_GLX_SGIX_video_resize /* GLX_SGIX_video_resize */ AGL_API(int, BindChannelToWindowSGIX, (Display *, int, int, Window)) AGL_API(int, ChannelRectSGIX, (Display *, int, int, int, int, int, int)) AGL_API(int, QueryChannelRectSGIX, (Display *, int, int, int *, int *, int *, int *)) AGL_API(int, QueryChannelDeltasSGIX, (Display *, int, int, int *, int *, int *, int *)) AGL_API(int, ChannelRectSyncSGIX, (Display *, int, int, GLenum)) #endif #ifdef _ALLEGRO_GLX_SGIX_dmbuffer /* GLX_SGIX_dmbuffer */ /* This one needs SGI's header file to be included first */ #ifdef _DM_BUFFER_H_ AGL_API(Bool, AssociateDMPbufferSGIX, (Display *, GLXPbufferSGIX, DMparams *, DMbuffer)) #endif #endif #ifdef _ALLEGRO_GLX_SGIX_swap_group /* GLX_SGIX_swap_group */ AGL_API(void, JoinSwapGroupSGIX, (Display *, GLXDrawable, GLXDrawable)) #endif #ifdef _ALLEGRO_GLX_SGIX_swap_barrier /* GLX_SGIX_swap_barrier */ AGL_API(void, BindSwapBarrierSGIX, (Display *, GLXDrawable, int)) AGL_API(Bool, QueryMaxSwapBarriersSGIX, (Display *, int, int *)) #endif #ifdef _ALLEGRO_GLX_SUN_get_transparent_index /* GLX_SUN_get_transparent_index */ AGL_API(Status, GetTransparentIndexSUN, (Display *, Window, Window, long *)) #endif #ifdef _ALLEGRO_GLX_MESA_copy_sub_buffer /* GLX_MESA_copy_sub_buffer */ AGL_API(void, CopySubBufferMESA, (Display *, GLXDrawable, int, int, int, int)) #endif #ifdef _ALLEGRO_GLX_MESA_pixmap_colormap /* GLX_MESA_pixmap_colormap */ AGL_API(GLXPixmap, CreateGLXPixmapMESA, (Display *, XVisualInfo *, Pixmap, Colormap)) #endif #ifdef _ALLEGRO_GLX_MESA_release_buffers /* GLX_MESA_release_buffers */ AGL_API(Bool, ReleaseBuffersMESA, (Display *, GLXDrawable)) #endif #ifdef _ALLEGRO_GLX_MESA_set_3dfx_mode /* GLX_MESA_set_3dfx_mode */ AGL_API(Bool, Set3DfxModeMESA, (int)) #endif #ifdef _ALLEGRO_GLX_OML_sync_control /* GLX_OML_sync_control */ AGL_API(Bool, GetSyncValuesOML, (Display *, GLXDrawable, int64_t *, int64_t *, int64_t *)) AGL_API(Bool, GetMscRateOML, (Display *, GLXDrawable, int32_t *, int32_t *)) AGL_API(int64_t, SwapBuffersMscOML, (Display *, GLXDrawable, int64_t, int64_t, int64_t)) AGL_API(Bool, WaitForMscOML, (Display *, GLXDrawable, int64_t, int64_t, int64_t, int64_t *, int64_t *, int64_t *)) AGL_API(Bool, WaitForSbcOML, (Display *, GLXDrawable, int64_t, int64_t *, int64_t *, int64_t *)) #endif #ifdef _ALLEGRO_GLX_SGIX_hyperpipe AGL_API(GLXHyperpipeNetworkSGIX *, QueryHyperpipeNetworkSGIX, (Display *dpy, int *npipes)) AGL_API(int, HyperpipeConfigSGIX, (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId)) AGL_API(GLXHyperpipeConfigSGIX *, QueryHyperpipeConfigSGIX, (Display *dpy, int hpId, int *npipes)) AGL_API(int, DestroyHyperpipeConfigSGIX, (Display * dpy, int hpId)) AGL_API(int, BindHyperpipeSGIX, (Display *dpy, int hpId)) AGL_API(int, QueryHyperpipeBestAttribSGIX, (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList)) AGL_API(int, HyperpipeAttribSGIX, (Display *dpy, int timeSlice, int attrib, int size, void *attribList)) AGL_API(int, QueryHyperpipeAttribSGIX, (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList)) #endif #ifdef _ALLEGRO_GLX_MESA_agp_offset AGL_API(unsigned int, GetAGPOffsetMESA, (const void *pointer)) #endif #ifdef _ALLEGRO_GLX_EXT_texture_from_pixmap AGL_API(void, BindTexImageEXT, (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list)) AGL_API(void, ReleaseTextImageEXT, (Display *dpy, GLXDrawable drawable, int buffer)) #endif #ifdef _ALLEGRO_GLX_NV_video_output AGL_API(int, GetVideoDeviceNV, (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice)) AGL_API(int, ReleaseVideoDeviceNV, (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice)) AGL_API(int, BindVideoImageNV, (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer)) AGL_API(int, ReleaseVideoImageNV, (Display *dpy, GLXPbuffer pbuf)) AGL_API(int, SendPbufferToVideoNV, (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock)) AGL_API(int, GetVideoInfoNV, (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputVideo, unsigned long *pulCounterOutputPbuffer)) #endif #ifdef _ALLEGRO_GLX_NV_swap_group AGL_API(Bool, JoinSwapGroupNV, (Display *dpy, GLXDrawable drawable, GLuint group)) AGL_API(Bool, BindSwapBarrierNV, (Display *dpy, GLuint group, GLuint barrier)) AGL_API(Bool, QuerySwapGroupNV, (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier)) AGL_API(Bool, QueryMaxSwapGroupsNV, (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers)) AGL_API(Bool, QueryFrameCountNV, (Display *dpy, int screen, GLuint *count)) AGL_API(Bool, ResetFrameCountNV, (Display *dpy, int screen)) #endif #ifdef _ALLEGRO_GLX_NV_video_capture AGL_API(int, BindVideoCaptureDeviceNV, (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device)) AGL_API(GLXVideoCaptureDeviceNV *, EnumerateVideoCaptureDevicesNV, (Display *dpy, int screen, int *nelements)) AGL_API(void, LockVideoCaptureDeviceNV, (Display *dpy, GLXVideoCaptureDeviceNV device)) AGL_API(int, QueryVideoCaptureDeviceNV, (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value)) AGL_API(void, ReleaseVideoCaptureDeviceNV, (Display *dpy, GLXVideoCaptureDeviceNV device)) #endif #ifdef _ALLEGRO_GLX_EXT_swap_control AGL_API(int, SwapIntervalEXT, (Display *dpy, GLXDrawable drawable, int interval)) #endif #ifdef _ALLEGRO_GLX_NV_copy_image AGL_API(void, CopyImageSubDataNV, (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth)) #endif #ifdef _ALLEGRO_GLX_EXT_create_context_es_profile // no functions #endif allegro5-5.2.10.1/include/allegro5/opengl/GLext/glx_ext_defs.h000066400000000000000000000426171473414355200237620ustar00rootroot00000000000000/* HACK: Prevent both Mesa and SGI's broken headers from screwing us */ #define __glxext_h_ #define __glx_glxext_h_ #include #undef __glxext_h_ #undef __glx_glxext_h_ #ifndef GLX_VERSION_1_3 #define _ALLEGRO_GLX_VERSION_1_3 #define GLX_VERSION_1_3 #define GLX_WINDOW_BIT 0x00000001 #define GLX_PIXMAP_BIT 0x00000002 #define GLX_PBUFFER_BIT 0x00000004 #define GLX_RGBA_BIT 0x00000001 #define GLX_COLOR_INDEX_BIT 0x00000002 #define GLX_PBUFFER_CLOBBER_MASK 0x08000000 #define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001 #define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002 #define GLX_BACK_LEFT_BUFFER_BIT 0x00000004 #define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008 #define GLX_AUX_BUFFERS_BIT 0x00000010 #define GLX_DEPTH_BUFFER_BIT 0x00000020 #define GLX_STENCIL_BUFFER_BIT 0x00000040 #define GLX_ACCUM_BUFFER_BIT 0x00000080 #define GLX_CONFIG_CAVEAT 0x20 #define GLX_X_VISUAL_TYPE 0x22 #define GLX_TRANSPARENT_TYPE 0x23 #define GLX_TRANSPARENT_INDEX_VALUE 0x24 #define GLX_TRANSPARENT_RED_VALUE 0x25 #define GLX_TRANSPARENT_GREEN_VALUE 0x26 #define GLX_TRANSPARENT_BLUE_VALUE 0x27 #define GLX_TRANSPARENT_ALPHA_VALUE 0x28 #define GLX_DONT_CARE 0xFFFFFFFF #define GLX_NONE 0x8000 #define GLX_SLOW_CONFIG 0x8001 #define GLX_TRUE_COLOR 0x8002 #define GLX_DIRECT_COLOR 0x8003 #define GLX_PSEUDO_COLOR 0x8004 #define GLX_STATIC_COLOR 0x8005 #define GLX_GRAY_SCALE 0x8006 #define GLX_STATIC_GRAY 0x8007 #define GLX_TRANSPARENT_RGB 0x8008 #define GLX_TRANSPARENT_INDEX 0x8009 #define GLX_VISUAL_ID 0x800B #define GLX_SCREEN 0x800C #define GLX_NON_CONFORMANT_CONFIG 0x800D #define GLX_DRAWABLE_TYPE 0x8010 #define GLX_RENDER_TYPE 0x8011 #define GLX_X_RENDERABLE 0x8012 #define GLX_FBCONFIG_ID 0x8013 #define GLX_RGBA_TYPE 0x8014 #define GLX_COLOR_INDEX_TYPE 0x8015 #define GLX_MAX_PBUFFER_WIDTH 0x8016 #define GLX_MAX_PBUFFER_HEIGHT 0x8017 #define GLX_MAX_PBUFFER_PIXELS 0x8018 #define GLX_PRESERVED_CONTENTS 0x801B #define GLX_LARGEST_PBUFFER 0x801C #define GLX_WIDTH 0x801D #define GLX_HEIGHT 0x801E #define GLX_EVENT_MASK 0x801F #define GLX_DAMAGED 0x8020 #define GLX_SAVED 0x8021 #define GLX_WINDOW 0x8022 #define GLX_PBUFFER 0x8023 #define GLX_PBUFFER_HEIGHT 0x8040 #define GLX_PBUFFER_WIDTH 0x8041 #endif #ifndef GLX_VERSION_1_4 #define _ALLEGRO_GLX_VERSION_1_4 #define GLX_VERSION_1_4 #define GLX_SAMPLE_BUFFERS 100000 #define GLX_SAMPLES 100001 #endif #ifndef GLX_ARB_get_proc_address #define _ALLEGRO_GLX_ARB_get_proc_address #define GLX_ARB_get_proc_address typedef void (*__GLXextFuncPtr)(void); #endif #ifndef GLX_ARB_multisample #define _ALLEGRO_GLX_ARB_multisample #define GLX_ARB_multisample #define GLX_SAMPLE_BUFFERS_ARB 100000 #define GLX_SAMPLES_ARB 100001 #endif #ifndef GLX_ARB_vertex_buffer_object #define GLX_ARB_vertex_buffer_object #define _ALLEGRO_GLX_ARB_vertex_buffer_object #define GLX_CONTEXT_ALLOW_BUFFER_BYTE_ORDER_MISMATCH_ARB 0x2095 #endif #ifndef GLX_ARB_fbconfig_float #define GLX_ARB_fbconfig_float #define _ALLEGRO_GLX_ARB_fbconfig_float #define GLX_RGBA_FLOAT_TYPE_ARB 0x20B9 #define GLX_RGBA_FLOAT_BIT_ARB 0x00000004 #endif #ifndef GLX_ARB_create_context #define GLX_ARB_create_context #define _ALLEGRO_GLX_ARB_create_context #define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 #define GLX_CONTEXT_FLAGS_ARB 0x2094 #endif #ifndef GLX_ARB_create_context_profile #define GLX_ARB_create_context_profile #define _ALLEGRO_GLX_ARB_create_context_profile #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 #define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 #endif #ifndef GLX_SGIS_multisample #define _ALLEGRO_GLX_SGIS_multisample #define GLX_SGIS_multisample #define GLX_SAMPLE_BUFFERS_SGIS 100000 #define GLX_SAMPLES_SGIS 100001 #endif /* Fix for system headers that define GLX_VERSION_1_4 but do not define * GLX_SAMPLES and GLX_SAMPLE_BUFFERS. */ #ifndef GLX_SAMPLES #define GLX_SAMPLE_BUFFERS 100000 #define GLX_SAMPLES 100001 #endif #ifndef GLX_EXT_visual_info #define _ALLEGRO_GLX_EXT_visual_info #define GLX_EXT_visual_info #define GLX_X_VISUAL_TYPE_EXT 0x22 #define GLX_TRANSPARENT_TYPE_EXT 0x23 #define GLX_TRANSPARENT_INDEX_VALUE_EXT 0x24 #define GLX_TRANSPARENT_RED_VALUE_EXT 0x25 #define GLX_TRANSPARENT_GREEN_VALUE_EXT 0x26 #define GLX_TRANSPARENT_BLUE_VALUE_EXT 0x27 #define GLX_TRANSPARENT_ALPHA_VALUE_EXT 0x28 #define GLX_NONE_EXT 0x8000 #define GLX_TRUE_COLOR_EXT 0x8002 #define GLX_DIRECT_COLOR_EXT 0x8003 #define GLX_PSEUDO_COLOR_EXT 0x8004 #define GLX_STATIC_COLOR_EXT 0x8005 #define GLX_GRAY_SCALE_EXT 0x8006 #define GLX_STATIC_GRAY_EXT 0x8007 #define GLX_TRANSPARENT_RGB_EXT 0x8008 #define GLX_TRANSPARENT_INDEX_EXT 0x8009 #endif #ifndef GLX_EXT_visual_rating #define _ALLEGRO_GLX_EXT_visual_rating #define GLX_EXT_visual_rating #define GLX_VISUAL_CAVEAT_EXT 0x20 #define GLX_SLOW_VISUAL_EXT 0x8001 #define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D /* GLX_NONE_EXT */ #endif #ifndef GLX_EXT_import_context #define _ALLEGRO_GLX_EXT_import_context #define GLX_EXT_import_context #define GLX_SHARE_CONTEXT_EXT 0x800A #define GLX_VISUAL_ID_EXT 0x800B #define GLX_SCREEN_EXT 0x800C #endif #ifndef GLX_SGIX_fbconfig #define _ALLEGRO_GLX_SGIX_fbconfig #define GLX_SGIX_fbconfig typedef XID GLXFBConfigIDSGIX; typedef struct __GLXFBConfigRec *GLXFBConfigSGIX; #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 /* GLX_SCREEN_EXT */ #endif #ifndef GLX_SGIX_pbuffer #define _ALLEGRO_GLX_SGIX_pbuffer #define GLX_SGIX_pbuffer typedef XID GLXPbufferSGIX; typedef struct { int type; unsigned long serial; /* # of last request processed by server */ Bool send_event; /* true if this came for SendEvent request */ Display *display; /* display the event was read from */ GLXDrawable drawable; /* i.d. of Drawable */ int event_type; /* GLX_DAMAGED_SGIX or GLX_SAVED_SGIX */ int draw_type; /* GLX_WINDOW_SGIX or GLX_PBUFFER_SGIX */ unsigned int mask; /* mask indicating which buffers are affected*/ int x, y; int width, height; int count; /* if nonzero, at least this many more */ } GLXBufferClobberEventSGIX; #define GLX_PBUFFER_BIT_SGIX 0x00000004 #define GLX_BUFFER_CLOBBER_MASK_SGIX 0x08000000 #define GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001 #define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002 #define GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004 #define GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008 #define GLX_AUX_BUFFERS_BIT_SGIX 0x00000010 #define GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020 #define GLX_STENCIL_BUFFER_BIT_SGIX 0x00000040 #define GLX_ACCUM_BUFFER_BIT_SGIX 0x00000080 #define GLX_SAMPLE_BUFFERS_BIT_SGIX 0x00000100 #define GLX_MAX_PBUFFER_WIDTH_SGIX 0x8016 #define GLX_MAX_PBUFFER_HEIGHT_SGIX 0x8017 #define GLX_MAX_PBUFFER_PIXELS_SGIX 0x8018 #define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX 0x8019 #define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX 0x801A #define GLX_PRESERVED_CONTENTS_SGIX 0x801B #define GLX_LARGEST_PBUFFER_SGIX 0x801C #define GLX_WIDTH_SGIX 0x801D #define GLX_HEIGHT_SGIX 0x801E #define GLX_EVENT_MASK_SGIX 0x801F #define GLX_DAMAGED_SGIX 0x8020 #define GLX_SAVED_SGIX 0x8021 #define GLX_WINDOW_SGIX 0x8022 #define GLX_PBUFFER_SGIX 0x8023 #endif #ifndef GLX_SGIX_video_resize #define _ALLEGRO_GLX_SGIX_video_resize #define GLX_SGIX_video_resize #define GLX_SYNC_FRAME_SGIX 0x00000000 #define GLX_SYNC_SWAP_SGIX 0x00000001 #endif #ifndef GLX_SGIX_dmbuffer #define _ALLEGRO_GLX_SGIX_dmbuffer #define GLX_SGIX_dmbuffer #define GLX_DIGITAL_MEDIA_PBUFFER_SGIX 0x8024 #endif #ifndef GLX_SGIS_blended_overlay #define _ALLEGRO_GLX_SGIS_blended_overlay #define GLX_SGIS_blended_overlay #define GLX_BLENDED_RGBA_SGIS 0x8025 #endif #ifndef GLX_SGIS_shared_multisample #define _ALLEGRO_GLX_SGIS_shared_multisample #define GLX_SGIS_shared_multisample #define GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026 #define GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027 #endif #ifndef GLX_3DFX_multisample #define _ALLEGRO_GLX_3DFX_multisample #define GLX_3DFX_multisample #define GLX_SAMPLE_BUFFERS_3DFX 0x8050 #define GLX_SAMPLES_3DFX 0x8051 #endif #ifndef GLX_MESA_set_3dfx_mode #define _ALLEGRO_GLX_MESA_set_3dfx_mode #define GLX_MESA_set_3dfx_mode #define GLX_3DFX_WINDOW_MODE_MESA 0x1 #define GLX_3DFX_FULLSCREEN_MODE_MESA 0x2 #endif #ifndef GLX_SGIX_visual_select_group #define _ALLEGRO_GLX_SGIX_visual_select_group #define GLX_SGIX_visual_select_group #define GLX_VISUAL_SELECT_GROUP_SGIX 0x8028 #endif #ifndef GLX_OML_swap_method #define _ALLEGRO_GLX_OML_swap_method #define GLX_OML_swap_method #define GLX_SWAP_METHOD_OML 0x8060 #define GLX_SWAP_EXCHANGE_OML 0x8061 #define GLX_SWAP_COPY_OML 0x8062 #define GLX_SWAP_UNDEFINED_OML 0x8063 #endif #ifndef GLX_SGIX_video_source #define _ALLEGRO_GLX_SGIX_video_source #define GLX_SGIX_video_source typedef XID GLXVideoSourceSGIX; #endif #ifndef GLX_SGI_video_sync #define GLX_SGI_video_sync #define _ALLEGRO_GLX_SGI_video_sync #endif #ifndef GLX_SGI_swap_control #define GLX_SGI_swap_control #define _ALLEGRO_GLX_SGI_swap_control #endif #ifndef GLX_SGI_make_current_read #define GLX_SGI_make_current_read #define _ALLEGRO_GLX_SGI_make_current_read #endif #ifndef GLX_SGI_cushion #define GLX_SGI_cushion #define _ALLEGRO_GLX_SGI_cushion #endif #ifndef GLX_SGIX_swap_group #define GLX_SGIX_swap_group #define _ALLEGRO_GLX_SGIX_swap_group #endif #ifndef GLX_SGIX_swap_barrier #define GLX_SGIX_swap_barrier #define _ALLEGRO_GLX_SGIX_swap_barrier #endif #ifndef GLX_SUN_get_transparent_index #define GLX_SUN_get_transparent_index #define _ALLEGRO_GLX_SUN_get_transparent_index #endif #ifndef GLX_MESA_copy_sub_buffer #define GLX_MESA_copy_sub_buffer #define _ALLEGRO_GLX_MESA_copy_sub_buffer #endif #ifndef GLX_MESA_pixmap_colormap #define GLX_MESA_pixmap_colormap #define _ALLEGRO_GLX_MESA_pixmap_colormap #endif #ifndef GLX_MESA_release_buffers #define GLX_MESA_release_buffers #define _ALLEGRO_GLX_MESA_release_buffers #endif #ifndef GLX_OML_sync_control #define GLX_OML_sync_control #define _ALLEGRO_GLX_OML_sync_control #endif #ifndef GLX_SGIX_hyperpipe #define GLX_SGIX_hyperpipe #define _ALLEGRO_GLX_SGIX_hyperpipe #define GLX_HYPERPIPE_ID_SGIX 0x8030 #define GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80 #define GLX_HYPERPIPE_DISPLAY_PIPE_SGIX 0x00000001 #define GLX_HYPERPIPE_RENDER_PIPE_SGIX 0x00000002 #define GLX_PIPE_RECT_SGIX 0x00000001 #define GLX_PIPE_RECT_LIMITS_SGIX 0x00000002 #define GLX_HYPERPIPE_STEREO_SGIX 0x00000003 #define GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX 0x00000004 #define GLX_BAD_HYPERPIPE_CONFIG_SGIX 91 #define GLX_BAD_HYPERPIPE_SGIX 92 typedef struct { char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; int networkId; } GLXHyperpipeNetworkSGIX; typedef struct { char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; int channel; unsigned int participationType; int timeSlice; } GLXHyperpipeConfigSGIX; typedef struct { char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; int srcXOrigin; int srcYOrigin; int srcWidth; int srcHeight; int destXOrigin; int destYOrigin; int destWidth; int destHeight; } GLXPipeRect; typedef struct { char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; int XOrigin; int YOrigin; int maxHeight; int maxWidth; } GLXPipeRectLimits; #endif #ifndef GLX_MESA_agp_offset #define GLX_MESA_agp_offset #define _ALLEGRO_GLX_MESA_agp_offset #endif #ifndef GLX_EXT_framebuffer_sRGB #define GLX_EXT_framebuffer_sRGB #define _ALLEGRO_GLX_EXT_framebuffer_sRGB #define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2 #endif #ifndef GLX_EXT_fbconfig_packed_float #define GLX_EXT_fbconfig_packed_float #define _ALLEGRO_GLX_EXT_fbconfig_packed_float #define GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT 0x20B1 #define GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT 0x00000008 #endif #ifndef GLX_EXT_texture_from_pixmap #define GLX_EXT_texture_from_pixmap #define _ALLEGRO_GLX_EXT_texture_from_pixmap #define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0 #define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1 #define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2 #define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3 #define GLX_Y_INVERTED_EXT 0x20D4 #define GLX_TEXTURE_FORMAT_EXT 0x20D5 #define GLX_TEXTURE_TARGET_EXT 0x20D6 #define GLX_MIPMAP_TEXTURE_EXT 0x20D7 #define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8 #define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9 #define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA #define GLX_TEXTURE_1D_BIT_EXT 0x00000001 #define GLX_TEXTURE_2D_BIT_EXT 0x00000002 #define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004 #define GLX_TEXTURE_1D_EXT 0x20DB #define GLX_TEXTURE_2D_EXT 0x20DC #define GLX_TEXTURE_RECTANGLE_EXT 0x20DD #define GLX_FRONT_LEFT_EXT 0x20DE #define GLX_FRONT_RIGHT_EXT 0x20DF #define GLX_BACK_LEFT_EXT 0x20E0 #define GLX_BACK_RIGHT_EXT 0x20E1 #define GLX_FRONT_EXT GLX_FRONT_LEFT_EXT #define GLX_BACK_EXT GLX_BACK_LEFT_EXT #define GLX_AUX0_EXT 0x20E2 #define GLX_AUX1_EXT 0x20E3 #define GLX_AUX2_EXT 0x20E4 #define GLX_AUX3_EXT 0x20E5 #define GLX_AUX4_EXT 0x20E6 #define GLX_AUX5_EXT 0x20E7 #define GLX_AUX6_EXT 0x20E8 #define GLX_AUX7_EXT 0x20E9 #define GLX_AUX8_EXT 0x20EA #define GLX_AUX9_EXT 0x20EB #endif #ifndef GLX_NV_present_video #define GLX_NV_present_video #define _ALLEGRO_GLX_NV_present_video #define GLX_GLX_NUM_VIDEO_SLOTS_NV 0x20F0 #endif #ifndef GLX_NV_video_output #define GLX_NV_video_output #define _ALLEGRO_GLX_NV_video_output #define GLX_VIDEO_OUT_COLOR_NV 0x20C3 #define GLX_VIDEO_OUT_ALPHA_NV 0x20C4 #define GLX_VIDEO_OUT_DEPTH_NV 0x20C5 #define GLX_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 #define GLX_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 #define GLX_VIDEO_OUT_FRAME_NV 0x20C8 #define GLX_VIDEO_OUT_FIELD_1_NV 0x20C9 #define GLX_VIDEO_OUT_FIELD_2_NV 0x20CA typedef unsigned int GLXVideoDeviceNV; #endif #ifndef GLX_NV_swap_group #define GLX_NV_swap_group #define _ALLEGRO_GLX_NV_swap_group #endif #ifndef GLX_NV_video_capture #define GLX_NV_video_capture #define _ALLEGRO_GLX_NV_video_capture #define GLX_DEVICE_ID_NV 0x20CD #define GLX_UNIQUE_ID_NV 0x20CE #define GLX_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF typedef XID GLXVideoCaptureDeviceNV; #endif #ifndef GLX_EXT_swap_control #define GLX_EXT_swap_control #define _ALLEGRO_GLX_EXT_swap_control #define GLX_SWAP_INTERVAL_EXT 0x20F1 #define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 #endif #ifndef GLX_NV_copy_image #define GLX_NV_copy_image #define _ALLEGRO_GLX_NV_copy_image #endif #ifndef GLX_INTEL_swap_event #define GLX_INTEL_swap_event #define _ALLEGRO_GLX_INTEL_swap_event #define GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK 0x04000000 #define GLX_EXCHANGE_COMPLETE_INTEL 0x8180 #define GLX_COPY_COMPLETE_INTEL 0x8181 #define GLX_FLIP_COMPLETE_INTEL 0x8182 #endif #ifndef GLX_EXT_create_context_es_profile #define GLX_EXT_create_context_es_profile #define GLX_EXT_create_context_es2_profile #define _ALLEGRO_GLX_EXT_create_context_es_profile #define GLX_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 #define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 #endif allegro5-5.2.10.1/include/allegro5/opengl/GLext/glx_ext_list.h000066400000000000000000000032221473414355200240010ustar00rootroot00000000000000AGL_EXT(ARB_get_proc_address, 0) AGL_EXT(ARB_multisample, 0) AGL_EXT(ARB_fbconfig_float, 0) AGL_EXT(ARB_create_context, 0) AGL_EXT(ARB_vertex_buffer_object, 0) AGL_EXT(EXT_visual_info, 0) AGL_EXT(SGI_swap_control, 0) AGL_EXT(SGI_video_sync, 0) AGL_EXT(SGI_make_current_read, 0) AGL_EXT(SGIX_video_source, 0) AGL_EXT(EXT_visual_rating, 0) AGL_EXT(EXT_import_context, 0) AGL_EXT(SGIX_fbconfig, 0) AGL_EXT(SGIX_pbuffer, 0) AGL_EXT(SGI_cushion, 0) AGL_EXT(SGIX_video_resize, 0) AGL_EXT(SGIX_dm_buffer, 0) AGL_EXT(SGIX_swap_group, 0) AGL_EXT(SGIX_swap_barrier, 0) AGL_EXT(SGIS_color_range, 0) AGL_EXT(SGIS_blended_overlay, 0) AGL_EXT(SUN_get_transparent_index, 0) AGL_EXT(MESA_copy_sub_buffer, 0) AGL_EXT(MESA_pixmap_colormap, 0) AGL_EXT(MESA_release_buffers, 0) AGL_EXT(MESA_set_3dfx_mode, 0) AGL_EXT(SGIX_visual_select_group, 0) AGL_EXT(OML_swap_method, 0) AGL_EXT(OML_sync_control, 0) AGL_EXT(SGIX_hyperpipe, 0) AGL_EXT(MESA_agp_offset, 0) AGL_EXT(EXT_framebuffer_sRGB, 0) AGL_EXT(EXT_packed_float, 0) AGL_EXT(EXT_texture_from_pixmap, 0) AGL_EXT(NV_video_output, 0) AGL_EXT(NV_swap_group, 0) AGL_EXT(NV_video_capture, 0) AGL_EXT(EXT_swap_control, 0) AGL_EXT(NV_copy_image, 0) AGL_EXT(INTEL_swap_event, 0) AGL_EXT(EXT_create_context_es_profile, 0) allegro5-5.2.10.1/include/allegro5/opengl/GLext/wgl_ext_api.h000066400000000000000000000172071473414355200236060ustar00rootroot00000000000000/* WGL_ARB_buffer_region */ AGL_API(HANDLE, CreateBufferRegionARB, (HDC, int, UINT)) AGL_API(VOID, DeleteBufferRegionARB, (HANDLE)) AGL_API(BOOL, SaveBufferRegionARB, (HANDLE, int, int, int, int)) AGL_API(BOOL, RestoreBufferRegionARB, (HANDLE, int, int, int, int, int, int)) /* WGL_ARB_extensions_string */ AGL_API(const char *, GetExtensionsStringARB, (HDC)) /* WGL_ARB_pixel_format */ AGL_API(BOOL, GetPixelFormatAttribivARB, (HDC, int, int, UINT, const int *, int *)) AGL_API(BOOL, GetPixelFormatAttribfvARB, (HDC, int, int, UINT, const int *, FLOAT *)) AGL_API(BOOL, ChoosePixelFormatARB, (HDC, const int *, const FLOAT *, UINT, int *, UINT *)) /* WGL_ARB_make_current_read */ AGL_API(BOOL, MakeContextCurrentARB, (HDC, HDC, HGLRC)) AGL_API(HDC, GetCurrentReadDCARB, (void)) /* WGL_ARB_pbuffer */ AGL_API(HPBUFFERARB, CreatePbufferARB, (HDC, int, int, int, const int *)) AGL_API(HDC, GetPbufferDCARB, (HPBUFFERARB)) AGL_API(int, ReleasePbufferDCARB, (HPBUFFERARB, HDC)) AGL_API(BOOL, DestroyPbufferARB, (HPBUFFERARB)) AGL_API(BOOL, QueryPbufferARB, (HPBUFFERARB, int, int *)) /* WGL_ARB_render_texture */ AGL_API(BOOL, BindTexImageARB, (HPBUFFERARB, int)) AGL_API(BOOL, ReleaseTexImageARB, (HPBUFFERARB, int)) AGL_API(BOOL, SetPbufferAttribARB, (HPBUFFERARB, const int *)) /* WGL_ARB_create_context */ AGL_API(HGLRC, CreateContextAttribsARB, (HDC, HGLRC, const int *)) /* WGL_EXT_display_color_table */ AGL_API(GLboolean, CreateDisplayColorTableEXT, (GLushort)) AGL_API(GLboolean, LoadDisplayColorTableEXT, (const GLushort *, GLuint)) AGL_API(GLboolean, BindDisplayColorTableEXT, (GLushort)) AGL_API(VOID, DestroyDisplayColorTableEXT, (GLushort)) /* WGL_EXT_extensions_string */ AGL_API(const char *, GetExtensionsStringEXT, (void)) /* WGL_EXT_make_current_read */ AGL_API(BOOL, MakeContextCurrentEXT, (HDC, HDC, HGLRC)) AGL_API(HDC, GetCurrentReadDCEXT, (void)) /* WGL_EXT_pbuffer */ AGL_API(HPBUFFEREXT, CreatePbufferEXT, (HDC, int, int, int, const int *)) AGL_API(HDC, GetPbufferDCEXT, (HPBUFFEREXT)) AGL_API(int, ReleasePbufferDCEXT, (HPBUFFEREXT, HDC)) AGL_API(BOOL, DestroyPbufferEXT, (HPBUFFEREXT)) AGL_API(BOOL, QueryPbufferEXT, (HPBUFFEREXT, int, int *)) /* WGL_EXT_pixel_format */ AGL_API(BOOL, GetPixelFormatAttribivEXT, (HDC, int, int, UINT, int *, int *)) AGL_API(BOOL, GetPixelFormatAttribfvEXT, (HDC, int, int, UINT, int *, FLOAT *)) AGL_API(BOOL, ChoosePixelFormatEXT, (HDC, const int *, const FLOAT *, UINT, int *, UINT *)) /* WGL_EXT_swap_control */ AGL_API(BOOL, SwapIntervalEXT, (int)) AGL_API(int, GetSwapIntervalEXT, (void)) /* WGL_NV_vertex_array_range */ AGL_API(void*, AllocateMemoryNV, (GLsizei, GLfloat, GLfloat, GLfloat)) AGL_API(void, FreeMemoryNV, (void *)) /* WGL_OML_sync_control */ AGL_API(BOOL, GetSyncValuesOML, (HDC, INT64 *, INT64 *, INT64 *)) AGL_API(BOOL, GetMscRateOML, (HDC, INT32 *, INT32 *)) AGL_API(INT64, SwapBuffersMscOML, (HDC, INT64, INT64, INT64)) AGL_API(INT64, SwapLayerBuffersMscOML, (HDC, int, INT64, INT64, INT64)) AGL_API(BOOL, WaitForMscOML, (HDC, INT64, INT64, INT64, INT64 *, INT64 *, INT64 *)) AGL_API(BOOL, WaitForSbcOML, (HDC, INT64, INT64 *, INT64 *, INT64 *)) /* WGL_I3D_digital_video_control */ AGL_API(BOOL, GetDigitalVideoParametersI3D, (HDC, int, int *)) AGL_API(BOOL, SetDigitalVideoParametersI3D, (HDC, int, const int *)) /* WGL_I3D_gamma */ AGL_API(BOOL, GetGammaTableParametersI3D, (HDC, int, int *)) AGL_API(BOOL, SetGammaTableParametersI3D, (HDC, int, const int *)) AGL_API(BOOL, GetGammaTableI3D, (HDC, int, USHORT *, USHORT *, USHORT *)) AGL_API(BOOL, SetGammaTableI3D, (HDC, int, const USHORT *, const USHORT *, const USHORT *)) /* WGL_I3D_genlock */ AGL_API(BOOL, EnableGenlockI3D, (HDC)) AGL_API(BOOL, DisableGenlockI3D, (HDC)) AGL_API(BOOL, IsEnabledGenlockI3D, (HDC, BOOL *)) AGL_API(BOOL, GenlockSourceI3D, (HDC, UINT)) AGL_API(BOOL, GetGenlockSourceI3D, (HDC, UINT *)) AGL_API(BOOL, GenlockSourceEdgeI3D, (HDC, UINT)) AGL_API(BOOL, GetGenlockSourceEdgeI3D, (HDC, UINT *)) AGL_API(BOOL, GenlockSampleRateI3D, (HDC, UINT)) AGL_API(BOOL, GetGenlockSampleRateI3D, (HDC, UINT *)) AGL_API(BOOL, GenlockSourceDelayI3D, (HDC, UINT)) AGL_API(BOOL, GetGenlockSourceDelayI3D, (HDC, UINT *)) AGL_API(BOOL, QueryGenlockMaxSourceDelayI3D, (HDC, UINT *, UINT *)) /* WGL_I3D_image_buffer */ AGL_API(LPVOID, CreateImageBufferI3D, (HDC, DWORD, UINT)) AGL_API(BOOL, DestroyImageBufferI3D, (HDC, LPVOID)) AGL_API(BOOL, AssociateImageBufferEventsI3D, (HDC, const HANDLE *, const LPVOID *, const DWORD *, UINT)) AGL_API(BOOL, ReleaseImageBufferEventsI3D, (HDC, const LPVOID *, UINT)) /* WGL_I3D_swap_frame_lock */ AGL_API(BOOL, EnableFrameLockI3D, (void)) AGL_API(BOOL, DisableFrameLockI3D, (void)) AGL_API(BOOL, IsEnabledFrameLockI3D, (BOOL *)) AGL_API(BOOL, QueryFrameLockMasterI3D, (BOOL *)) /* WGL_I3D_swap_frame_usage */ AGL_API(BOOL, GetFrameUsageI3D, (float *)) AGL_API(BOOL, BeginFrameTrackingI3D, (void)) AGL_API(BOOL, EndFrameTrackingI3D, (void)) AGL_API(BOOL, QueryFrameTrackingI3D, (DWORD *, DWORD *, float *)) /* glAddSwapHintRectWIN */ AGL_API(void, AddSwapHintRectWIN, (int, int, int, int)) /* WGL_NV_present_video */ AGL_API(int, EnumerateVideoDevicesNV, (HDC, HVIDEOOUTPUTDEVICENV *)) AGL_API(BOOL, BindVideoDeviceNV, (HDC, unsigned int, HVIDEOOUTPUTDEVICENV, const int *)) AGL_API(BOOL, QueryCurrentContextNV, (int, int *)) /* WGL_NV_video_out */ AGL_API(BOOL, GetVideoDeviceNV, (HDC, int, HPVIDEODEV *)) AGL_API(BOOL, ReleaseVideoDeviceNV, (HPVIDEODEV)) AGL_API(BOOL, BindVideoImageNV, (HPVIDEODEV, HPBUFFERARB, int)) AGL_API(BOOL, ReleaseVideoImageNV, (HPBUFFERARB, int)) AGL_API(BOOL, SendPbufferToVideoNV, (HPBUFFERARB, int, unsigned long *, BOOL)) AGL_API(BOOL, GetVideoInfoNV, (HPVIDEODEV, unsigned long *, unsigned long *)) /* WGL_NV_swap_group */ AGL_API(BOOL, JoinSwapGroupNV, (HDC hDC, GLuint group)) AGL_API(BOOL, BindSwapBarrierNV, (GLuint group, GLuint barrier)) AGL_API(BOOL, QuerySwapGroupNV, (HDC hDC, GLuint *group, GLuint *barrier)) AGL_API(BOOL, QueryMaxSwapGroupsNV, (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers)) AGL_API(BOOL, QueryFrameCountNV, (HDC hDC, GLuint *count)) AGL_API(BOOL, ResetFrameCountNV, (HDC hDC)) /* WGL_NV_gpu_affinity */ AGL_API(BOOL, EnumGpusNV, (UINT, HGPUNV *)) AGL_API(BOOL, EnumGpuDevicesNV, (HGPUNV, UINT, PGPU_DEVICE)) AGL_API(HDC, CreateAffinityDCNV, (const HGPUNV *)) AGL_API(BOOL, EnumGpusFromAffinityDCNV, (HDC, UINT, HGPUNV *)) AGL_API(BOOL, DeleteDCNV, (HDC)) /* WGL_AMD_gpu_association */ AGL_API(UINT, GetGPUIDsAMD, (UINT, UINT *)) AGL_API(INT, GetGPUInfoAMD, (UINT, int, GLenum, UINT, void *)) AGL_API(UINT, GetContextGPUIDAMD, (HGLRC)) AGL_API(HGLRC, CreateAssociatedContextAMD, (UINT)) AGL_API(HGLRC, CreateAssociatedContextAttribsAMD, (UINT, HGLRC, const int *)) AGL_API(BOOL, DeleteAssociatedContextAMD, (HGLRC)) AGL_API(BOOL, MakeAssociatedContextCurrentAMD, (HGLRC)) AGL_API(HGLRC, GetCurrentAssociatedContextAMD, (void)) AGL_API(VOID, BlitContextFramebufferAMD, (HGLRC, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum)) /* WGL_NV_video_capture */ AGL_API(BOOL, BindVideoCaptureDeviceNV, (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice)) AGL_API(UINT, EnumerateVideoCaptureDevicesNV, (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList)) AGL_API(BOOL, LockVideoCaptureDeviceNV, (HDC hDc, HVIDEOINPUTDEVICENV hDevice)) AGL_API(BOOL, QueryVideoCaptureDeviceNV, (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue)) AGL_API(BOOL, ReleaseVideoCaptureDeviceNV, (HDC hDc, HVIDEOINPUTDEVICENV hDevice)) /* WGL_NV_copy_image */ AGL_API(BOOL, CopyImageSubDataNV, (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth)) allegro5-5.2.10.1/include/allegro5/opengl/GLext/wgl_ext_defs.h000066400000000000000000000331171473414355200237540ustar00rootroot00000000000000#ifndef WGL_ARB_buffer_region #define WGL_ARB_buffer_region #define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 #define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 #define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 #define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 #endif #ifndef WGL_ARB_multisample #define WGL_ARB_multisample #define WGL_SAMPLE_BUFFERS_ARB 0x2041 #define WGL_SAMPLES_ARB 0x2042 #endif #ifndef WGL_ARB_pixel_format #define WGL_ARB_pixel_format #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_DRAW_TO_WINDOW_ARB 0x2001 #define WGL_DRAW_TO_BITMAP_ARB 0x2002 #define WGL_ACCELERATION_ARB 0x2003 #define WGL_NEED_PALETTE_ARB 0x2004 #define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 #define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 #define WGL_SWAP_METHOD_ARB 0x2007 #define WGL_NUMBER_OVERLAYS_ARB 0x2008 #define WGL_NUMBER_UNDERLAYS_ARB 0x2009 #define WGL_TRANSPARENT_ARB 0x200A #define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B #define WGL_SHARE_DEPTH_ARB 0x200C #define WGL_SHARE_STENCIL_ARB 0x200D #define WGL_SHARE_ACCUM_ARB 0x200E #define WGL_SUPPORT_GDI_ARB 0x200F #define WGL_SUPPORT_OPENGL_ARB 0x2010 #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_RED_SHIFT_ARB 0x2016 #define WGL_GREEN_BITS_ARB 0x2017 #define WGL_GREEN_SHIFT_ARB 0x2018 #define WGL_BLUE_BITS_ARB 0x2019 #define WGL_BLUE_SHIFT_ARB 0x201A #define WGL_ALPHA_BITS_ARB 0x201B #define WGL_ALPHA_SHIFT_ARB 0x201C #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_NO_ACCELERATION_ARB 0x2025 #define WGL_GENERIC_ACCELERATION_ARB 0x2026 #define WGL_FULL_ACCELERATION_ARB 0x2027 #define WGL_SWAP_EXCHANGE_ARB 0x2028 #define WGL_SWAP_COPY_ARB 0x2029 #define WGL_SWAP_UNDEFINED_ARB 0x202A #define WGL_TYPE_RGBA_ARB 0x202B #define WGL_TYPE_COLORINDEX_ARB 0x202C #endif #ifndef WGL_ARB_make_current_read #define WGL_ARB_make_current_read #define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 #define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 #endif #ifndef WGL_ARB_pbuffer #define WGL_ARB_pbuffer DECLARE_HANDLE(HPBUFFERARB); #define WGL_DRAW_TO_PBUFFER_ARB 0x202D #define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E #define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F #define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 #define WGL_PBUFFER_LARGEST_ARB 0x2033 #define WGL_PBUFFER_WIDTH_ARB 0x2034 #define WGL_PBUFFER_HEIGHT_ARB 0x2035 #define WGL_PBUFFER_LOST_ARB 0x2036 #endif #ifndef WGL_ARB_render_texture #define WGL_ARB_render_texture #define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 #define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 #define WGL_TEXTURE_FORMAT_ARB 0x2072 #define WGL_TEXTURE_TARGET_ARB 0x2073 #define WGL_MIPMAP_TEXTURE_ARB 0x2074 #define WGL_TEXTURE_RGB_ARB 0x2075 #define WGL_TEXTURE_RGBA_ARB 0x2076 #define WGL_NO_TEXTURE_ARB 0x2077 #define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 #define WGL_TEXTURE_1D_ARB 0x2079 #define WGL_TEXTURE_2D_ARB 0x207A #define WGL_MIPMAP_LEVEL_ARB 0x207B #define WGL_CUBE_MAP_FACE_ARB 0x207C #define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E #define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 #define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 #define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 #define WGL_FRONT_LEFT_ARB 0x2083 #define WGL_FRONT_RIGHT_ARB 0x2084 #define WGL_BACK_LEFT_ARB 0x2085 #define WGL_BACK_RIGHT_ARB 0x2086 #define WGL_AUX0_ARB 0x2087 #define WGL_AUX1_ARB 0x2088 #define WGL_AUX2_ARB 0x2089 #define WGL_AUX3_ARB 0x208A #define WGL_AUX4_ARB 0x208B #define WGL_AUX5_ARB 0x208C #define WGL_AUX6_ARB 0x208D #define WGL_AUX7_ARB 0x208E #define WGL_AUX8_ARB 0x208F #define WGL_AUX9_ARB 0x2090 #endif #ifndef WGL_ARB_pixel_format_float #define WGL_ARB_pixel_format_float #define AWGL_ARB_pixel_format_float #define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 #endif #ifndef WGL_ARB_create_context #define WGL_ARB_create_context #define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 #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 ERROR_INVALID_VERSION_ARB 0x2095 #endif #ifndef WGL_ARB_create_context_profile #define WGL_ARB_create_context_profile #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 #define ERROR_INVALID_PROFILE_ARB 0x2096 #endif #ifndef WGL_EXT_make_current_read #define WGL_EXT_make_current_read #define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 #endif #ifndef WGL_EXT_pixel_format #define WGL_EXT_pixel_format #define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 #define WGL_DRAW_TO_WINDOW_EXT 0x2001 #define WGL_DRAW_TO_BITMAP_EXT 0x2002 #define WGL_ACCELERATION_EXT 0x2003 #define WGL_NEED_PALETTE_EXT 0x2004 #define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 #define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 #define WGL_SWAP_METHOD_EXT 0x2007 #define WGL_NUMBER_OVERLAYS_EXT 0x2008 #define WGL_NUMBER_UNDERLAYS_EXT 0x2009 #define WGL_TRANSPARENT_EXT 0x200A #define WGL_TRANSPARENT_VALUE_EXT 0x200B #define WGL_SHARE_DEPTH_EXT 0x200C #define WGL_SHARE_STENCIL_EXT 0x200D #define WGL_SHARE_ACCUM_EXT 0x200E #define WGL_SUPPORT_GDI_EXT 0x200F #define WGL_SUPPORT_OPENGL_EXT 0x2010 #define WGL_DOUBLE_BUFFER_EXT 0x2011 #define WGL_STEREO_EXT 0x2012 #define WGL_PIXEL_TYPE_EXT 0x2013 #define WGL_COLOR_BITS_EXT 0x2014 #define WGL_RED_BITS_EXT 0x2015 #define WGL_RED_SHIFT_EXT 0x2016 #define WGL_GREEN_BITS_EXT 0x2017 #define WGL_GREEN_SHIFT_EXT 0x2018 #define WGL_BLUE_BITS_EXT 0x2019 #define WGL_BLUE_SHIFT_EXT 0x201A #define WGL_ALPHA_BITS_EXT 0x201B #define WGL_ALPHA_SHIFT_EXT 0x201C #define WGL_ACCUM_BITS_EXT 0x201D #define WGL_ACCUM_RED_BITS_EXT 0x201E #define WGL_ACCUM_GREEN_BITS_EXT 0x201F #define WGL_ACCUM_BLUE_BITS_EXT 0x2020 #define WGL_ACCUM_ALPHA_BITS_EXT 0x2021 #define WGL_DEPTH_BITS_EXT 0x2022 #define WGL_STENCIL_BITS_EXT 0x2023 #define WGL_AUX_BUFFERS_EXT 0x2024 #define WGL_NO_ACCELERATION_EXT 0x2025 #define WGL_GENERIC_ACCELERATION_EXT 0x2026 #define WGL_FULL_ACCELERATION_EXT 0x2027 #define WGL_SWAP_EXCHANGE_EXT 0x2028 #define WGL_SWAP_COPY_EXT 0x2029 #define WGL_SWAP_UNDEFINED_EXT 0x202A #define WGL_TYPE_RGBA_EXT 0x202B #define WGL_TYPE_COLORINDEX_EXT 0x202C #endif #ifndef WGL_EXT_pbuffer #define WGL_EXT_pbuffer DECLARE_HANDLE(HPBUFFEREXT); #define WGL_DRAW_TO_PBUFFER_EXT 0x202D #define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E #define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F #define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 #define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 #define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 #define WGL_PBUFFER_LARGEST_EXT 0x2033 #define WGL_PBUFFER_WIDTH_EXT 0x2034 #define WGL_PBUFFER_HEIGHT_EXT 0x2035 #endif #ifndef WGL_EXT_depth_float #define WGL_EXT_depth_float #define WGL_DEPTH_FLOAT_EXT 0x2040 #endif #ifndef WGL_3DFX_multisample #define WGL_3DFX_multisample #define WGL_SAMPLE_BUFFERS_3DFX 0x2060 #define WGL_SAMPLES_3DFX 0x2061 #endif #ifndef WGL_EXT_multisample #define WGL_EXT_multisample #define WGL_SAMPLE_BUFFERS_EXT 0x2041 #define WGL_SAMPLES_EXT 0x2042 #endif #ifndef WGL_I3D_digital_video_control #define WGL_I3D_digital_video_control #define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 #define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 #define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 #define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 #endif #ifndef WGL_I3D_gamma #define WGL_I3D_gamma #define WGL_GAMMA_TABLE_SIZE_I3D 0x204E #define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F #endif #ifndef WGL_I3D_genlock #define WGL_I3D_genlock #define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 #define WGL_GENLOCK_SOURCE_EXTENAL_SYNC_I3D 0x2045 #define WGL_GENLOCK_SOURCE_EXTENAL_FIELD_I3D 0x2046 #define WGL_GENLOCK_SOURCE_EXTENAL_TTL_I3D 0x2047 #define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 #define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 #define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A #define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B #define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C #endif #ifndef WGL_I3D_image_buffer #define WGL_I3D_image_buffer #define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 #define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 #endif #ifndef WGL_NV_render_depth_texture #define WGL_NV_render_depth_texture #define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 #define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 #define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 #define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 #define WGL_DEPTH_COMPONENT_NV 0x20A7 #endif #ifndef WGL_NV_render_texture_rectangle #define WGL_NV_render_texture_rectangle #define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 #define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 #define WGL_TEXTURE_RECTANGLE_NV 0x20A2 #endif #ifndef WGL_NV_float_buffer #define WGL_NV_float_buffer #define WGL_FLOAT_COMPONENTS_NV 0x20B0 #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 #define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 #define WGL_TEXTURE_FLOAT_R_NV 0x20B5 #define WGL_TEXTURE_FLOAT_RG_NV 0x20B6 #define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 #define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 #endif #ifndef WGL_3DL_stereo_control #define WGL_3DL_stereo_control #define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055 #define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056 #define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057 #define WGL_STEREO_POLARITY_INVERT_3DL 0x2058 #endif #ifndef WGL_EXT_framebuffer_sRGB #define WGL_EXT_framebuffer_sRGB #define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 #endif #ifndef WGL_EXT_pixel_format_packed_float #define WGL_EXT_pixel_format_packed_float #define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 #endif #ifndef WGL_WIN_swap_hint #define WGL_WIN_swap_hint #endif #ifndef WGL_NV_present_video #define WGL_NV_present_video DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV); #define WGL_NUM_VIDEO_SLOTS_NV 0x20F0 #endif #ifndef WGL_NV_video_out #define WGL_NV_video_out DECLARE_HANDLE(HPVIDEODEV); #define WGL_BIND_TO_VIDEO_RGB_NV 0x20C0 #define WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1 #define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2 #define WGL_VIDEO_OUT_COLOR_NV 0x20C3 #define WGL_VIDEO_OUT_ALPHA_NV 0x20C4 #define WGL_VIDEO_OUT_DEPTH_NV 0x20C5 #define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 #define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 #define WGL_VIDEO_OUT_FRAME 0x20C8 #define WGL_VIDEO_OUT_FIELD_1 0x20C9 #define WGL_VIDEO_OUT_FIELD_2 0x20CA #define WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB #define WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC #endif #ifndef WGL_NV_swap_group #define WGL_NV_swap_group #endif #ifndef WGL_NV_gpu_affinity #define WGL_NV_gpu_affinity DECLARE_HANDLE(HPGPUNV); DECLARE_HANDLE(HGPUNV); typedef struct _GPU_DEVICE { DWORD cb; CHAR DeviceName[32]; CHAR DeviceString[128]; DWORD Flags; RECT rcVirtualScreen; } GPU_DEVICE, *PGPU_DEVICE; #define WGL_ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0 #define WGL_ERROR_MISSING_AFFINITY_MASK_NV 0x20D1 #endif #ifndef WGL_AMD_gpu_association #define WGL_AMD_gpu_association #define WGL_GPU_VENDOR_AMD 0x1F00 #define WGL_GPU_RENDERER_STRING_AMD 0x1F01 #define WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 #define WGL_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 #define WGL_GPU_RAM_AMD 0x21A3 #define WGL_GPU_CLOCK_AMD 0x21A4 #define WGL_GPU_NUM_PIPES_AMD 0x21A5 #define WGL_GPU_NUM_SIMD_AMD 0x21A6 #define WGL_GPU_NUM_RB_AMD 0x21A7 #define WGL_GPU_NUM_SPI_AMD 0x21A8 #endif #ifndef WGL_NV_video_capture #define WGL_NV_video_capture DECLARE_HANDLE(HVIDEOINPUTDEVICENV); #define WGL_UNIQUE_ID_NV 0x20CE #define WGL_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF #endif #ifndef WGL_NV_copy_image #define WGL_NV_copy_image #endif allegro5-5.2.10.1/include/allegro5/opengl/GLext/wgl_ext_list.h000066400000000000000000000030261473414355200240020ustar00rootroot00000000000000AGL_EXT(ARB_buffer_region, 0) AGL_EXT(ARB_multisample, 0) AGL_EXT(ARB_extensions_string, 0) AGL_EXT(ARB_pixel_format, 0) AGL_EXT(ARB_make_current_read, 0) AGL_EXT(ARB_pbuffer, 0) AGL_EXT(ARB_render_texture, 0) AGL_EXT(ARB_pixel_format_float, 0) AGL_EXT(EXT_display_color_table, 0) AGL_EXT(EXT_extensions_string, 0) AGL_EXT(EXT_make_current_read, 0) AGL_EXT(EXT_pixel_format, 0) AGL_EXT(EXT_pbuffer, 0) AGL_EXT(EXT_swap_control, 0) AGL_EXT(EXT_depth_float, 0) AGL_EXT(EXT_multisample, 0) AGL_EXT(OML_sync_control, 0) AGL_EXT(I3D_digital_video_control, 0) AGL_EXT(I3D_gamma, 0) AGL_EXT(I3D_genlock, 0) AGL_EXT(I3D_image_buffer, 0) AGL_EXT(I3D_swap_frame_lock, 0) AGL_EXT(I3D_swap_frame_usage, 0) AGL_EXT(NV_render_depth_texture, 0) AGL_EXT(NV_render_texture_rectangle, 0) AGL_EXT(ATI_pixel_format_float, 0) AGL_EXT(EXT_framebuffer_sRGB, 0) AGL_EXT(EXT_pixel_format_packed_float,0) AGL_EXT(WIN_swap_hint, 0) AGL_EXT(3DL_stereo_control, 0) AGL_EXT(NV_swap_group, 0) AGL_EXT(NV_gpu_affinity, 0) AGL_EXT(NV_video_out, 0) AGL_EXT(NV_present_video, 0) AGL_EXT(ARB_create_context, 0) AGL_EXT(AMD_gpu_association, 0) AGL_EXT(NV_copy_image, 0) AGL_EXT(NV_video_capture, 0) allegro5-5.2.10.1/include/allegro5/opengl/gl_ext.h000066400000000000000000000073441473414355200215440ustar00rootroot00000000000000 #ifndef __al_included_allegro5_gl_ext_h #define __al_included_allegro5_gl_ext_h #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) /* * MSVC declares the following extensions and MinGW doesn't. In order to * export the same symbols on both platforms we removed the extensions from * MSVC. */ #ifdef ALLEGRO_MSVC #undef GL_EXT_vertex_array #undef GL_EXT_paletted_texture #undef GL_WIN_swap_hint #undef GL_WIN_draw_range_elements #endif /* GL extension definitions. */ /* For example: * * #define GL_BGRA 0x80E1 * */ #if !defined ALLEGRO_CFG_OPENGLES #include "allegro5/opengl/GLext/gl_ext_defs.h" #endif #if defined ALLEGRO_WINDOWS && !defined ALLEGRO_EXCLUDE_WGL #include "allegro5/opengl/GLext/wgl_ext_defs.h" #elif defined ALLEGRO_UNIX && !defined ALLEGRO_EXCLUDE_GLX #include "allegro5/opengl/GLext/glx_ext_defs.h" #endif /* GL extension types */ /* For example: * * typedef void (APIENTRY * _ALLEGRO_glBlendEquation_t (GLenum); * */ #ifndef APIENTRY #define APIENTRY #define APIENTRY_defined #endif #define AGL_API(type, name, args) typedef type (APIENTRY * _ALLEGRO_gl##name##_t) args; # include "allegro5/opengl/GLext/gl_ext_api.h" #undef AGL_API #ifdef ALLEGRO_WINDOWS #define AGL_API(type, name, args) typedef type (APIENTRY * _ALLEGRO_wgl##name##_t) args; # include "allegro5/opengl/GLext/wgl_ext_api.h" #undef AGL_API #elif defined ALLEGRO_UNIX #define AGL_API(type, name, args) typedef type (APIENTRY * _ALLEGRO_glX##name##_t) args; # include "allegro5/opengl/GLext/glx_ext_api.h" #undef AGL_API #endif #ifdef APIENTRY_defined #undef APIENTRY #undef APIENTRY_defined #endif /* GL extension declarations */ /* For example: * * #define glBlendEquation _al_glBlendEquation * extern _ALLEGRO_glBlendEquation_t _al_glBlendEquation; * */ #define AGL_API(type, name, args) AL_VAR(_ALLEGRO_gl##name##_t, _al_gl##name); # include "allegro5/opengl/GLext/gl_ext_alias.h" # include "allegro5/opengl/GLext/gl_ext_api.h" #undef AGL_API #ifdef ALLEGRO_WINDOWS #define AGL_API(type, name, args) AL_VAR(_ALLEGRO_wgl##name##_t, _al_wgl##name); # include "allegro5/opengl/GLext/wgl_ext_alias.h" # include "allegro5/opengl/GLext/wgl_ext_api.h" #undef AGL_API #elif defined ALLEGRO_UNIX #define AGL_API(type, name, args) extern _ALLEGRO_glX##name##_t _al_glX##name; # include "allegro5/opengl/GLext/glx_ext_alias.h" # include "allegro5/opengl/GLext/glx_ext_api.h" #undef AGL_API #endif /* A list of all supported extensions. * * For example: * int ALLEGRO_GL_ARB_imaging; * */ typedef struct ALLEGRO_OGL_EXT_LIST { # define AGL_EXT(name, ver) int ALLEGRO_GL_##name; # include "allegro5/opengl/GLext/gl_ext_list.h" # undef AGL_EXT #ifdef ALLEGRO_UNIX # define AGL_EXT(name, ver) int ALLEGRO_GLX_##name; # include "allegro5/opengl/GLext/glx_ext_list.h" # undef AGL_EXT #elif defined ALLEGRO_WINDOWS # define AGL_EXT(name, ver) int ALLEGRO_WGL_##name; # include "allegro5/opengl/GLext/wgl_ext_list.h" # undef AGL_EXT #endif } ALLEGRO_OGL_EXT_LIST; /* GL extension Structure. Holds the pointers to all the functions * of all extensions, for a single context. * * Example: * ALLEGRO_BlendEquation_t BlendEquation; */ typedef struct ALLEGRO_OGL_EXT_API { #define AGL_API(type, name, args) _ALLEGRO_gl##name##_t name; # include "allegro5/opengl/GLext/gl_ext_api.h" #undef AGL_API #ifdef ALLEGRO_WINDOWS #define AGL_API(type, name, args) _ALLEGRO_wgl##name##_t name; # include "allegro5/opengl/GLext/wgl_ext_api.h" #undef AGL_API #elif defined ALLEGRO_UNIX #define AGL_API(type, name, args) _ALLEGRO_glX##name##_t name; # include "allegro5/opengl/GLext/glx_ext_api.h" #undef AGL_API #endif } ALLEGRO_OGL_EXT_API; #else typedef struct ALLEGRO_OGL_EXT_LIST ALLEGRO_OGL_EXT_LIST; #endif #endif allegro5-5.2.10.1/include/allegro5/path.h000066400000000000000000000042371473414355200177300ustar00rootroot00000000000000#ifndef __al_included_allegro5_path_h #define __al_included_allegro5_path_h #include "allegro5/base.h" #include "allegro5/utf8.h" #ifdef __cplusplus extern "C" { #endif #ifdef ALLEGRO_WINDOWS # define ALLEGRO_NATIVE_PATH_SEP '\\' # define ALLEGRO_NATIVE_DRIVE_SEP ':' #else # define ALLEGRO_NATIVE_PATH_SEP '/' # define ALLEGRO_NATIVE_DRIVE_SEP '\0' #endif typedef struct ALLEGRO_PATH ALLEGRO_PATH; AL_FUNC(ALLEGRO_PATH*, al_create_path, (const char *str)); AL_FUNC(ALLEGRO_PATH*, al_create_path_for_directory, (const char *str)); AL_FUNC(ALLEGRO_PATH*, al_clone_path, (const ALLEGRO_PATH *path)); AL_FUNC(int, al_get_path_num_components, (const ALLEGRO_PATH *path)); AL_FUNC(const char*, al_get_path_component, (const ALLEGRO_PATH *path, int i)); AL_FUNC(void, al_replace_path_component, (ALLEGRO_PATH *path, int i, const char *s)); AL_FUNC(void, al_remove_path_component, (ALLEGRO_PATH *path, int i)); AL_FUNC(void, al_insert_path_component, (ALLEGRO_PATH *path, int i, const char *s)); AL_FUNC(const char*, al_get_path_tail, (const ALLEGRO_PATH *path)); AL_FUNC(void, al_drop_path_tail, (ALLEGRO_PATH *path)); AL_FUNC(void, al_append_path_component, (ALLEGRO_PATH *path, const char *s)); AL_FUNC(bool, al_join_paths, (ALLEGRO_PATH *path, const ALLEGRO_PATH *tail)); AL_FUNC(bool, al_rebase_path, (const ALLEGRO_PATH *head, ALLEGRO_PATH *tail)); AL_FUNC(const char*, al_path_cstr, (const ALLEGRO_PATH *path, char delim)); AL_FUNC(const ALLEGRO_USTR*, al_path_ustr, (const ALLEGRO_PATH *path, char delim)); AL_FUNC(void, al_destroy_path, (ALLEGRO_PATH *path)); AL_FUNC(void, al_set_path_drive, (ALLEGRO_PATH *path, const char *drive)); AL_FUNC(const char*, al_get_path_drive, (const ALLEGRO_PATH *path)); AL_FUNC(void, al_set_path_filename, (ALLEGRO_PATH *path, const char *filename)); AL_FUNC(const char*, al_get_path_filename, (const ALLEGRO_PATH *path)); AL_FUNC(const char*, al_get_path_extension, (const ALLEGRO_PATH *path)); AL_FUNC(bool, al_set_path_extension, (ALLEGRO_PATH *path, char const *extension)); AL_FUNC(const char*, al_get_path_basename, (const ALLEGRO_PATH *path)); AL_FUNC(bool, al_make_path_canonical, (ALLEGRO_PATH *path)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/platform/000077500000000000000000000000001473414355200204415ustar00rootroot00000000000000allegro5-5.2.10.1/include/allegro5/platform/aintandroid.h000066400000000000000000000017241473414355200231120ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Some definitions for internal use by the Android library code. * * By Thomas Fjellstrom. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_aintandroid_h #define __al_included_allegro5_aintandroid_h #include #ifdef __cplusplus extern "C" { #endif #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_display.h" ALLEGRO_PATH *_al_android_get_path(int id); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/platform/aintiphone.h000066400000000000000000000007061473414355200227530ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintiphone_h #define __al_included_allegro5_aintiphone_h #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/system.h" #include "allegro5/platform/aintunix.h" ALLEGRO_DISPLAY_INTERFACE *_al_display_iphone(void); ALLEGRO_SYSTEM_INTERFACE *_al_system_iphone(void); ALLEGRO_PATH *_al_iphone_get_path(int id); #endif allegro5-5.2.10.1/include/allegro5/platform/aintlnx.h000066400000000000000000000056231473414355200222750ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Some definitions for internal use by the Linux console code. * * By George Foot. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_aintlnx_h #define __al_included_allegro5_aintlnx_h #ifdef __cplusplus extern "C" { #endif /**************************************/ /************ Driver lists ************/ /**************************************/ extern _AL_DRIVER_INFO _al_linux_keyboard_driver_list[]; extern _AL_DRIVER_INFO _al_linux_mouse_driver_list[]; #ifdef ALLEGRO_RASPBERRYPI #define AL_MOUSEDRV_LINUX_EVDEV AL_ID('E', 'V', 'D', 'V') #endif /****************************************/ /************ Memory mapping ************/ /* (src/linux/lmemory.c) */ /****************************************/ /* struct MAPPED_MEMORY: Used to describe a block of memory mapped * into our address space (in particular, the video memory). */ struct MAPPED_MEMORY { unsigned int base, size; /* linear address and size of block */ int perms; /* PROT_READ | PROT_WRITE, etc */ void *data; /* pointer to block after mapping */ }; extern int __al_linux_have_ioperms; int __al_linux_init_memory (void); int __al_linux_shutdown_memory (void); int __al_linux_map_memory (struct MAPPED_MEMORY *info); int __al_linux_unmap_memory (struct MAPPED_MEMORY *info); /******************************************/ /************ Console routines ************/ /* (src/linux/lconsole.c) */ /******************************************/ extern int __al_linux_vt; extern int __al_linux_console_fd; extern int __al_linux_prev_vt; extern int __al_linux_got_text_message; extern struct termios __al_linux_startup_termio; extern struct termios __al_linux_work_termio; int __al_linux_use_console (void); int __al_linux_leave_console (void); int __al_linux_console_graphics (void); int __al_linux_console_text (void); int __al_linux_wait_for_display (void); /**************************************/ /************ VT switching ************/ /* (src/linux/vtswitch.c) */ /**************************************/ /* signals for VT switching */ #define SIGRELVT SIGUSR1 #define SIGACQVT SIGUSR2 int __al_linux_init_vtswitch (void); int __al_linux_done_vtswitch (void); int __al_linux_set_display_switch_mode (int mode); void __al_linux_display_switch_lock (int lock, int foreground); extern volatile int __al_linux_switching_blocked; #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/platform/aintosx.h000066400000000000000000000132551473414355200223050ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Internal header file for the MacOS X Allegro library port. * * By Angelo Mottola. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_aintosx_h #define __al_included_allegro5_aintosx_h #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/internal/aintern_mouse.h" #include "allegro5/platform/aintunix.h" #ifdef __OBJC__ #include #include #include #include #include #include #ifndef NSAppKitVersionNumber10_1 #define NSAppKitVersionNumber10_1 620 #endif #ifndef NSAppKitVersionNumber10_2 #define NSAppKitVersionNumber10_2 663 #endif #if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 #error Cannot target OS X versions before 10.4 #endif /* We include code to detect a "dead bootstrap context" and fail * gracefully if that situation is detected, but some of the code uses * deprecated functions and it isn't generally clear what "dead bootstrap * context" means (google's first result points back to Allegro). It is * also not clear if the problem this aims to solve still occurs on recent * versions of OS X. * Define OSX_BOOTSTRAP_DETECTION to compile this check in. It can * be brought back/reactivated when someone finds out how. */ //#define OSX_BOOTSTRAP_DETECTION #define HID_MAX_DEVICES MAX_JOYSTICKS #define HID_MOUSE 0 #define HID_JOYSTICK 1 #define HID_GAMEPAD 2 #define HID_MAX_DEVICE_ELEMENTS ((MAX_JOYSTICK_AXIS * MAX_JOYSTICK_STICKS) + MAX_JOYSTICK_BUTTONS) #define HID_ELEMENT_BUTTON 0 #define HID_ELEMENT_AXIS 1 #define HID_ELEMENT_AXIS_PRIMARY_X 2 #define HID_ELEMENT_AXIS_PRIMARY_Y 3 #define HID_ELEMENT_STANDALONE_AXIS 4 #define HID_ELEMENT_HAT 5 /* If we've included IOKit, generate the full definition * otherwise just a forward definition */ #ifdef _IOKIT_HID_IOHIDLIB_H_ typedef struct HID_ELEMENT { int type; IOHIDElementCookie cookie; int max, min; int app; int col; int index; char *name; } HID_ELEMENT; typedef struct HID_DEVICE { int type; char *manufacturer; char *product; int num_elements; int capacity; HID_ELEMENT *element; IOHIDDeviceInterface **interface; int cur_app; } HID_DEVICE; typedef struct { int count; int capacity; HID_DEVICE* devices; } HID_DEVICE_COLLECTION; #else typedef struct HID_ELEMENT HID_ELEMENT; typedef struct HID_DEVICE HID_DEVICE; typedef struct HID_DEVICE_COLLECTION HID_DEVICE_COLLECTION; #endif int _al_osx_bootstrap_ok(void); void _al_osx_tell_dock(void); void _al_osx_keyboard_handler(int pressed, NSEvent *event, ALLEGRO_DISPLAY*); void _al_osx_keyboard_modifiers(unsigned int new_mods, ALLEGRO_DISPLAY*); void _al_osx_keyboard_focused(int focused, int state); void _al_osx_mouse_generate_event(NSEvent*, ALLEGRO_DISPLAY*); void _al_osx_mouse_handler(NSEvent*); int _al_osx_mouse_set_sprite(ALLEGRO_BITMAP *sprite, int x, int y); int _al_osx_mouse_show(ALLEGRO_BITMAP *bmp, int x, int y); void _al_osx_mouse_hide(void); void _al_osx_mouse_move(int x, int y); HID_DEVICE_COLLECTION *_al_osx_hid_scan(int type, HID_DEVICE_COLLECTION*); void _al_osx_hid_free(HID_DEVICE_COLLECTION *); // Record in the keyboard state that the main window has changed void _al_osx_switch_keyboard_focus(ALLEGRO_DISPLAY *, bool switch_in); // Record in the mouse state that the main window has changed void _al_osx_switch_mouse_focus(ALLEGRO_DISPLAY *, bool switch_in); // Clear the mouse state when a dialog closes in the dialog addon void _al_osx_clear_mouse_state(void); // Notify the display that the mouse driver was installed/uninstalled. void _al_osx_mouse_was_installed(BOOL); // Create and destroy mouse cursors ALLEGRO_MOUSE_CURSOR *_al_osx_create_mouse_cursor(ALLEGRO_BITMAP *bmp, int x_focus, int y_focus); void _al_osx_destroy_mouse_cursor(ALLEGRO_MOUSE_CURSOR *curs); // Notify the display that the keyboard driver was installed/uninstalled. void _al_osx_keyboard_was_installed(BOOL); // Notify that the quit menu was clicked void _al_osx_post_quit(void); // Get the underlying view NSView* _al_osx_view_from_display(ALLEGRO_DISPLAY*); // Create an image from an allegro bitmap NSImage* NSImageFromAllegroBitmap(ALLEGRO_BITMAP* bmp); // Get the y coordinate of the upper-left corner of the primary display. int _al_osx_get_primary_screen_y(void); // Get the global scale factor. float _al_osx_get_global_scale_factor(void); // Drivers AL_FUNC(ALLEGRO_KEYBOARD_DRIVER*, _al_osx_get_keyboard_driver, (void)); AL_FUNC(ALLEGRO_DISPLAY_INTERFACE*, _al_osx_get_display_driver, (void)); AL_FUNC(ALLEGRO_MOUSE_DRIVER*, _al_osx_get_mouse_driver, (void)); AL_FUNC(ALLEGRO_JOYSTICK_DRIVER*, _al_osx_get_joystick_driver, (void)); #endif AL_FUNC(int, _al_osx_run_main, (int argc, char **argv, int (*real_main)(int, char **))); #endif /* Local variables: */ /* mode: objc */ /* c-basic-offset: 3 */ /* indent-tabs-mode: nil */ /* End: */ allegro5-5.2.10.1/include/allegro5/platform/aintraspberrypi.h000066400000000000000000000017211473414355200240310ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Some definitions for internal use by the Raspberry Pi library code. * * By Trent Gamblin. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_aintraspberrypi_h #define __al_included_allegro5_aintraspberrypi_h #ifdef __cplusplus extern "C" { #endif #include "allegro5/platform/aintunix.h" #include "allegro5/internal/aintern_keyboard.h" ALLEGRO_KEYBOARD_DRIVER *_al_xwin_keyboard_driver(void); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/platform/aintunix.h000066400000000000000000000043631473414355200224570ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Some definitions for internal use by the Unix library code. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_aintunix_h #define __al_included_allegro5_aintunix_h #include "allegro5/altime.h" #include "allegro5/path.h" #include "allegro5/internal/aintern_driver.h" /* Need right now for XKeyEvent --pw */ #ifdef ALLEGRO_WITH_XWINDOWS #include #endif #ifdef __cplusplus extern "C" { #endif ALLEGRO_PATH *_al_unix_get_path(int id); double _al_unix_get_time(void); void _al_unix_rest(double seconds); void _al_unix_init_timeout(ALLEGRO_TIMEOUT *timeout, double seconds); #ifdef __cplusplus } #endif #ifdef ALLEGRO_LINUX #include "allegro5/platform/aintlnx.h" #endif /*----------------------------------------------------------------------* * * * New stuff * * * *----------------------------------------------------------------------*/ /* TODO: integrate this above */ #include "allegro5/platform/aintuthr.h" #ifdef __cplusplus extern "C" { #endif /* time */ void _al_unix_init_time(void); /* fdwatch */ void _al_unix_start_watching_fd(int fd, void (*callback)(void *), void *cb_data); void _al_unix_stop_watching_fd(int fd); /* ljoynu.c */ /* This isn't in aintlnx.h because it's needed for the X11 port as well. */ #define _ALLEGRO_JOYDRV_LINUX AL_ID('L','N','X','A') #ifdef ALLEGRO_HAVE_LINUX_INPUT_H AL_VAR(struct ALLEGRO_JOYSTICK_DRIVER, _al_joydrv_linux); #endif /* lhaptic.c */ /* This isn't in aintlnx.h because it's needed for the X11 port as well. */ #define _ALLEGRO_HAPDRV_LINUX AL_ID('L','N','X','H') #ifdef ALLEGRO_HAVE_LINUX_INPUT_H AL_VAR(struct ALLEGRO_HAPTIC_DRIVER, _al_hapdrv_linux); #endif #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/platform/aintuthr.h000066400000000000000000000036671473414355200224640ustar00rootroot00000000000000/* * UNIX threads */ #ifndef __al_included_allegro5_aintuthr_h #define __al_included_allegro5_aintuthr_h #include #include "allegro5/internal/aintern_thread.h" #ifdef __cplusplus extern "C" { #endif /* threads */ struct _AL_THREAD { /* private: */ pthread_t thread; pthread_mutex_t mutex; bool should_stop; void (*proc)(struct _AL_THREAD *self, void *arg); void *arg; }; struct _AL_MUTEX { bool inited; pthread_mutex_t mutex; }; #define _AL_MUTEX_UNINITED { false, PTHREAD_MUTEX_INITIALIZER } /* makes no sense, but shuts gcc up */ #define _AL_MARK_MUTEX_UNINITED(M) do { M.inited = false; } while (0) struct _AL_COND { pthread_cond_t cond; }; typedef struct ALLEGRO_TIMEOUT_UNIX ALLEGRO_TIMEOUT_UNIX; struct ALLEGRO_TIMEOUT_UNIX { struct timespec abstime; }; AL_INLINE(bool, _al_get_thread_should_stop, (struct _AL_THREAD *t), { bool ret; pthread_mutex_lock(&t->mutex); ret = t->should_stop; pthread_mutex_unlock(&t->mutex); return ret; }) AL_FUNC(void, _al_mutex_init, (struct _AL_MUTEX*)); AL_FUNC(void, _al_mutex_destroy, (struct _AL_MUTEX*)); AL_INLINE(void, _al_mutex_lock, (struct _AL_MUTEX *m), { if (m->inited) pthread_mutex_lock(&m->mutex); }) AL_INLINE(void, _al_mutex_unlock, (struct _AL_MUTEX *m), { if (m->inited) pthread_mutex_unlock(&m->mutex); }) AL_INLINE(void, _al_cond_init, (struct _AL_COND *cond), { pthread_cond_init(&cond->cond, NULL); }) AL_INLINE(void, _al_cond_destroy, (struct _AL_COND *cond), { pthread_cond_destroy(&cond->cond); }) AL_INLINE(void, _al_cond_wait, (struct _AL_COND *cond, struct _AL_MUTEX *mutex), { pthread_cond_wait(&cond->cond, &mutex->mutex); }) AL_INLINE(void, _al_cond_broadcast, (struct _AL_COND *cond), { pthread_cond_broadcast(&cond->cond); }) AL_INLINE(void, _al_cond_signal, (struct _AL_COND *cond), { pthread_cond_signal(&cond->cond); }) #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/platform/aintwin.h000066400000000000000000000271741473414355200222760ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Some definitions for internal use by the Windows library code. * * By Stefan Schimanski. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_aintwin_h #define __al_included_allegro5_aintwin_h #ifndef __al_included_allegro5_allegro_h #error must include allegro.h first #endif #ifndef ALLEGRO_WINDOWS #error bad include #endif #include "allegro5/platform/aintwthr.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_vector.h" #include "allegro5/system.h" #define WINDOWS_RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) #ifdef __cplusplus extern "C" { #endif /* user defined hooks into the main win32 event loop */ typedef bool (*ALLEGRO_DISPLAY_WIN_CALLBACK_PROC) (ALLEGRO_DISPLAY *, UINT, WPARAM, LPARAM, LRESULT*, void *); typedef struct ALLEGRO_DISPLAY_WIN_CALLBACK ALLEGRO_DISPLAY_WIN_CALLBACK; struct ALLEGRO_DISPLAY_WIN_CALLBACK { ALLEGRO_DISPLAY_WIN_CALLBACK_PROC proc; void *userdata; }; /* the extended display struct for Windows */ typedef struct ALLEGRO_DISPLAY_WIN ALLEGRO_DISPLAY_WIN; struct ALLEGRO_DISPLAY_WIN { ALLEGRO_DISPLAY display; HWND window; HCURSOR mouse_selected_hcursor; bool mouse_cursor_shown; /* * We want to show the cursor when the user moves the mouse to the * title-bar (to, e.g. close the window). This variable tracks * whether or not we should re-hide the cursor when we enter the * drawable area. * * This is almost always false, unless we actually programmatically * hid the cursor inside wwindow.c. */ bool hide_mouse_on_move; UINT adapter; /* * The display thread must communicate with the main thread * through these variables. */ volatile bool end_thread; /* The display thread should end */ volatile bool thread_ended; /* The display thread has ended */ /* For internal use by the windows driver. When this is set and a Windows * window resize event is received by the window procedure, the event is * ignored and this value is set to false. */ bool ignore_resize; /* DefWindowProc for WM_ENTERSIZEMOVE enters a modal loop, which also * ends up blocking the loop in d3d_display_thread_proc (which is * where we are called from, if using D3D). Rather than batching up * intermediate resize events which the user cannot acknowledge in the * meantime anyway, make it so only a single resize event is generated * at WM_EXITSIZEMOVE. */ bool d3d_ignore_resize; /* Size to reset to when al_set_display_flag(FULLSCREEN_WINDOW, false) * is called. */ int toggle_w; int toggle_h; /* A list of user callbacks associated with the window messages */ _AL_VECTOR msg_callbacks; }; /* standard path */ ALLEGRO_PATH *_al_win_get_path(int id); /* thread routines */ void _al_win_thread_init(void); void _al_win_thread_exit(void); /* input routines */ void _al_win_grab_input(ALLEGRO_DISPLAY_WIN *win_disp); /* keyboard routines */ void _al_win_kbd_handle_key_press(int scode, int vcode, bool extended, bool repeated, ALLEGRO_DISPLAY_WIN *win_disp); void _al_win_kbd_handle_key_release(int scode, int vcode, bool extended, ALLEGRO_DISPLAY_WIN *win_disp); void _al_win_fix_modifiers(void); /* mouse routines */ void _al_win_mouse_handle_move(int x, int y, bool abs, ALLEGRO_DISPLAY_WIN *win_disp); void _al_win_mouse_handle_wheel(int raw_dz, bool abs, ALLEGRO_DISPLAY_WIN *win_disp); void _al_win_mouse_handle_hwheel(int raw_dw, bool abs, ALLEGRO_DISPLAY_WIN *win_disp); void _al_win_mouse_handle_button(int button, bool down, int x, int y, bool abs, ALLEGRO_DISPLAY_WIN *win_disp); void _al_win_mouse_handle_leave(ALLEGRO_DISPLAY_WIN *win_display); void _al_win_mouse_handle_enter(ALLEGRO_DISPLAY_WIN *win_display); /* joystick routines */ void _al_win_joystick_dinput_unacquire(void *unused); void _al_win_joystick_dinput_grab(void *ALLEGRO_DISPLAY_WIN); /* custom Allegro messages */ extern UINT _al_win_msg_call_proc; extern UINT _al_win_msg_suicide; /* main window routines */ AL_FUNC(void, _al_win_wnd_schedule_proc, (HWND wnd, void (*proc)(void*), void *param)); AL_FUNC(void, _al_win_wnd_call_proc, (HWND wnd, void (*proc)(void*), void *param)); int _al_win_determine_adapter(void); extern bool _al_win_disable_screensaver; /* dynamic library loading */ HMODULE _al_win_safe_load_library(const char *filename); /* time */ void _al_win_init_time(void); void _al_win_shutdown_time(void); /* This is used to stop MinGW from complaining about type-punning */ #define MAKE_UNION(ptr, t) \ union { \ LPVOID *v; \ t p; \ } u; \ u.p = (ptr); typedef struct ALLEGRO_SYSTEM_WIN ALLEGRO_SYSTEM_WIN; /* This is our version of ALLEGRO_SYSTEM with driver specific extra data. */ struct ALLEGRO_SYSTEM_WIN { ALLEGRO_SYSTEM system; /* This must be the first member, we "derive" from it. */ ALLEGRO_DISPLAY *mouse_grab_display; /* May be inaccurate. */ int toggle_mouse_grab_keycode; /* Disabled if zero. */ unsigned int toggle_mouse_grab_modifiers; }; /* helpers to create windows */ HWND _al_win_create_window(ALLEGRO_DISPLAY *display, int width, int height, int flags); HWND _al_win_create_faux_fullscreen_window(LPCTSTR devname, ALLEGRO_DISPLAY *display, int x1, int y1, int width, int height, int refresh_rate, int flags); int _al_win_init_window(void); void _al_win_shutdown_window(void); HWND _al_win_create_hidden_window(void); void _al_win_post_create_window(ALLEGRO_DISPLAY *display); /* icon helpers */ void _al_win_set_display_icons(ALLEGRO_DISPLAY *display, int num_icons, ALLEGRO_BITMAP *bitmap[]); HICON _al_win_create_icon(HWND wnd, ALLEGRO_BITMAP *sprite, int xfocus, int yfocus, bool is_cursor, bool resize); void _al_win_destroy_display_icons(ALLEGRO_DISPLAY *display); /* window decorations */ void _al_win_set_window_position(HWND window, int x, int y); void _al_win_get_window_position(HWND window, int *x, int *y); bool _al_win_get_window_borders(ALLEGRO_DISPLAY *display, int *left, int *top, int *right, int *bottom); bool _al_win_set_window_constraints(ALLEGRO_DISPLAY *display, int min_w, int min_h, int max_w, int max_h); bool _al_win_get_window_constraints(ALLEGRO_DISPLAY *display, int *min_w, int *min_h, int *max_w, int *max_h); void _al_win_apply_window_constraints(ALLEGRO_DISPLAY *display, bool onoff); void _al_win_set_window_frameless(ALLEGRO_DISPLAY *display, HWND window, bool frameless); bool _al_win_set_display_flag(ALLEGRO_DISPLAY *display, int flag, bool onoff); void _al_win_set_window_title(ALLEGRO_DISPLAY *display, const char *title); /* cursor routines */ typedef struct ALLEGRO_MOUSE_CURSOR_WIN ALLEGRO_MOUSE_CURSOR_WIN; struct ALLEGRO_MOUSE_CURSOR_WIN { HCURSOR hcursor; }; ALLEGRO_MOUSE_CURSOR* _al_win_create_mouse_cursor(ALLEGRO_BITMAP *sprite, int xfocus, int yfocus); void _al_win_destroy_mouse_cursor(ALLEGRO_MOUSE_CURSOR *cursor); bool _al_win_set_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_MOUSE_CURSOR *cursor); bool _al_win_set_system_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id); bool _al_win_show_mouse_cursor(ALLEGRO_DISPLAY *display); bool _al_win_hide_mouse_cursor(ALLEGRO_DISPLAY *display); /* driver specific functions */ #if defined ALLEGRO_CFG_D3D ALLEGRO_DISPLAY_INTERFACE* _al_display_d3d_driver(void); int _al_d3d_get_num_display_modes(int format, int refresh_rate, int flags); ALLEGRO_DISPLAY_MODE* _al_d3d_get_display_mode(int index, int format, int refresh_rate, int flags, ALLEGRO_DISPLAY_MODE *mode); void _al_d3d_shutdown_display(void); #endif /* defined ALLEGRO_CFG_D3D */ #if defined ALLEGRO_CFG_OPENGL ALLEGRO_DISPLAY_INTERFACE *_al_display_wgl_driver(void); int _al_wgl_get_num_display_modes(int format, int refresh_rate, int flags); ALLEGRO_DISPLAY_MODE* _al_wgl_get_display_mode(int index, int format, int refresh_rate, int flags, ALLEGRO_DISPLAY_MODE *mode); #endif /* defined ALLEGRO_CFG_OPENGL */ /* touch input specific API */ #if (_WIN32_WINNT < 0x0601) typedef struct tagTOUCHINPUT { LONG x; LONG y; HANDLE hSource; DWORD dwID; DWORD dwFlags; DWORD dwMask; DWORD dwTime; ULONG_PTR dwExtraInfo; DWORD cxContact; DWORD cyContact; } TOUCHINPUT, *PTOUCHINPUT; #endif /* Define those fellows. They are available on Windows SDK 7.0, * which is shipped with Visual Studio 2010. So it is not likely they * will be defined in . Also do not trust MinGW WinAPI * headers as they are outdated. Version 3.15, which is newest at the * time of writting this, still have invalid defines related to * multi-touch support. */ #define _AL_WM_TOUCH 0x0240 #define _AL_MOUSEEVENTF_FROMTOUCH 0xFF515700 #define _AL_TOUCHEVENTF_MOVE 0x0001 #define _AL_TOUCHEVENTF_DOWN 0x0002 #define _AL_TOUCHEVENTF_UP 0x0004 #define _AL_TOUCHEVENTF_PRIMARY 0x0010 #define _AL_SM_DIGITIZER 94 #define _AL_NID_READY 0x80 /* set of function required to handle touch input on Windows */ typedef BOOL (WINAPI *CLOSETOUCHINPUTHANDLEPROC)(HANDLE hTouchInput); typedef BOOL (WINAPI *GETTOUCHINPUTINFOPROC)(HANDLE hTouchInput, UINT cInputs, PTOUCHINPUT pInputs, int cbSize); typedef BOOL (WINAPI *ISTOUCHWINDOWPROC)(HWND hWnd, PULONG pulFlags); typedef BOOL (WINAPI *REGISTERTOUCHWINDOWPROC)(HWND hWnd, ULONG ulFlags); typedef BOOL (WINAPI *UNREGISTERTOUCHWINDOWPROC)(HWND hWnd); bool _al_win_init_touch_input_api(void); void _al_win_exit_touch_input_api(void); extern CLOSETOUCHINPUTHANDLEPROC _al_win_close_touch_input_handle; extern GETTOUCHINPUTINFOPROC _al_win_get_touch_input_info; extern ISTOUCHWINDOWPROC _al_win_is_touch_window; extern REGISTERTOUCHWINDOWPROC _al_win_register_touch_window; extern UNREGISTERTOUCHWINDOWPROC _al_win_unregister_touch_window; /* touch input routines */ void _al_win_touch_input_set_time_stamp(size_t timestamp); void _al_win_touch_input_handle_begin(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY_WIN *win_disp); void _al_win_touch_input_handle_end(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY_WIN *win_disp); void _al_win_touch_input_handle_move(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY_WIN *win_disp); void _al_win_touch_input_handle_cancel(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY_WIN *win_disp); /* Helpers for getting Windows system errors * May be called from addons */ AL_FUNC(const char*, _al_win_error, (DWORD)); AL_FUNC(const char*, _al_win_last_error, (void)); /* Time handling */ double _al_win_get_time(void); void _al_win_rest(double seconds); void _al_win_init_timeout(ALLEGRO_TIMEOUT *timeout, double seconds); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/platform/aintwiz.h000066400000000000000000000010601473414355200222740ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintwiz_h #define __al_included_allegro5_aintwiz_h #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/system.h" #include "allegro5/platform/aintunix.h" ALLEGRO_DISPLAY_INTERFACE *_al_display_gp2xwiz_opengl_driver(void); ALLEGRO_DISPLAY_INTERFACE *_al_display_gp2xwiz_framebuffer_driver(void); ALLEGRO_SYSTEM_INTERFACE *_al_system_gp2xwiz_driver(void); ALLEGRO_BITMAP_INTERFACE *_al_bitmap_gp2xwiz_driver(void); #endif allegro5-5.2.10.1/include/allegro5/platform/aintwthr.h000066400000000000000000000024601473414355200224540ustar00rootroot00000000000000/* * Windows threads */ #ifndef __al_included_allegro5_aintwthr_h #define __al_included_allegro5_aintwthr_h #include #ifdef __cplusplus extern "C" { #endif /* threads */ struct _AL_THREAD { /* private: */ HANDLE thread; CRITICAL_SECTION cs; bool should_stop; /* XXX: use a dedicated terminate Event object? */ void (*proc)(struct _AL_THREAD *self, void *arg); void *arg; }; struct _AL_MUTEX { PCRITICAL_SECTION cs; }; #define _AL_MUTEX_UNINITED { NULL } #define _AL_MARK_MUTEX_UNINITED(M) do { M.cs = NULL; } while (0) struct _AL_COND { long nWaitersBlocked; long nWaitersGone; long nWaitersToUnblock; HANDLE semBlockQueue; CRITICAL_SECTION semBlockLock; CRITICAL_SECTION mtxUnblockLock; }; typedef struct ALLEGRO_TIMEOUT_WIN ALLEGRO_TIMEOUT_WIN; struct ALLEGRO_TIMEOUT_WIN { DWORD abstime; }; AL_INLINE(bool, _al_get_thread_should_stop, (struct _AL_THREAD *t), { bool ret; EnterCriticalSection(&t->cs); ret = t->should_stop; LeaveCriticalSection(&t->cs); return ret; }) AL_INLINE(void, _al_mutex_lock, (struct _AL_MUTEX *m), { if (m->cs) EnterCriticalSection(m->cs); }) AL_INLINE(void, _al_mutex_unlock, (struct _AL_MUTEX *m), { if (m->cs) LeaveCriticalSection(m->cs); }) #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/platform/aintxglx.h000066400000000000000000000003171473414355200224510ustar00rootroot00000000000000#ifndef __al_included_allegro5_aintxglx_h #define __al_included_allegro5_aintxglx_h ALLEGRO_DISPLAY_INTERFACE *_al_display_xglx_driver(void); ALLEGRO_SYSTEM_INTERFACE *_al_system_xglx_driver(void); #endif allegro5-5.2.10.1/include/allegro5/platform/alandroid.h000066400000000000000000000014411473414355200225470ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Android-specific header defines. * * See readme.txt for copyright information. */ #ifndef ALLEGRO_ANDROID #error bad include #endif #include #ifdef __cplusplus extern "C" int main(int argc, char ** argv); #else extern int main(int argc, char ** argv); #endif /* Nothing left */ allegro5-5.2.10.1/include/allegro5/platform/alandroidcfg.h000066400000000000000000000016521473414355200232330ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration defines for use on Android platforms. * * By Thomas Fjellstrom. * * See readme.txt for copyright information. */ /* Describe this platform. */ #define ALLEGRO_PLATFORM_STR "Android" #define ALLEGRO_EXTRA_HEADER "allegro5/platform/alandroid.h" #define ALLEGRO_INTERNAL_HEADER "allegro5/platform/aintandroid.h" #define ALLEGRO_INTERNAL_THREAD_HEADER "allegro5/platform/aintuthr.h" #define ALLEGRO_EXCLUDE_GLX allegro5-5.2.10.1/include/allegro5/platform/albcc32.h000066400000000000000000000055501473414355200220300ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration defines for use with Borland C++Builder. * * By Greg Hackmann. * * See readme.txt for copyright information. */ /* #ifdef ALLEGRO_SRC #error Currently BCC32 cannot build the library #endif */ #include #include #include #include #pragma warn -8004 /* unused assigned value */ #pragma warn -8008 /* condition always met */ #pragma warn -8057 /* unused parameter */ #pragma warn -8066 /* unreachable code */ /* describe this platform */ #define ALLEGRO_PLATFORM_STR "BCC32" #define ALLEGRO_WINDOWS #define ALLEGRO_I386 #define ALLEGRO_LITTLE_ENDIAN #define ALLEGRO_GUESS_INTTYPES_OK /* TODO: check if BCC has inttypes.h and/or stdint.h */ #ifdef ALLEGRO_USE_CONSOLE #define ALLEGRO_NO_MAGIC_MAIN #endif /* describe how function prototypes look to BCC32 */ #if (defined ALLEGRO_STATICLINK) #define _AL_DLL #elif (defined ALLEGRO_SRC) #define _AL_DLL __declspec(dllexport) #else #define _AL_DLL __declspec(dllimport) #endif #define AL_VAR(type, name) extern _AL_DLL type name #define AL_ARRAY(type, name) extern _AL_DLL type name[] #define AL_FUNC(type, name, args) extern _AL_DLL type name args #define AL_METHOD(type, name, args) type (*name) args #define AL_FUNCPTR(type, name, args) extern _AL_DLL type (*name) args #define END_OF_INLINE(name) //#define AL_INLINE(type, name, args, code) extern __inline type name args code END_OF_INLINE(name) #define INLINE __inline #undef AL_INLINE #undef AL_INLINE_STATIC #define AL_INLINE(type, name, args, code) extern __inline type __cdecl name args code END_OF_INLINE(name) #define AL_INLINE_STATIC(type, name, args, code) static __inline type name args code END_OF_INLINE(name) #define int64_t signed __int64 #define uint64_t unsigned __int64 #define __func__ "FIXME" #define _wfindfirst __wfindfirst #define _wfindnext __wfindnext #define WinMain _main /* windows specific defines */ #ifdef NONAMELESSUNION #undef NONAMELESSUNION #endif /* This fixes 99.999999% of Borland C++Builder's problems with structs. */ /* arrange for other headers to be included later on */ #define ALLEGRO_EXTRA_HEADER "allegro5/platform/alwin.h" #define ALLEGRO_INTERNAL_HEADER "allegro5/platform/aintwin.h" #define ALLEGRO_INTERNAL_THREAD_HEADER "allegro5/platform/aintwthr.h" allegro5-5.2.10.1/include/allegro5/platform/aldmc.h000066400000000000000000000044171473414355200217000ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration defines for use with Digital Mars C compiler. * * By Matthew Leverton. * * See readme.txt for copyright information. */ #include #include #include /* a static auto config */ #define ALLEGRO_HAVE_INTTYPES_H #define ALLEGRO_HAVE_STDINT_H #define LONG_LONG long long /* describe this platform */ #ifdef ALLEGRO_STATICLINK #define ALLEGRO_PLATFORM_STR "DMC.s" #else #define ALLEGRO_PLATFORM_STR "DMC" #endif #define ALLEGRO_WINDOWS #define ALLEGRO_I386 #define ALLEGRO_LITTLE_ENDIAN #ifdef ALLEGRO_USE_CONSOLE #define ALLEGRO_NO_MAGIC_MAIN #endif /* describe how function prototypes look to DMC */ #if (defined ALLEGRO_STATICLINK) || (defined ALLEGRO_SRC) #define _AL_DLL #else #define _AL_DLL __declspec(dllimport) #endif #define AL_VAR(type, name) extern _AL_DLL type name #define AL_ARRAY(type, name) extern _AL_DLL type name[] #define AL_FUNC(type, name, args) extern type name args #define AL_METHOD(type, name, args) type (*name) args #define AL_FUNCPTR(type, name, args) extern _AL_DLL type (*name) args /* Windows specific defines */ #if (defined ALLEGRO_SRC) #if (!defined S_IRUSR) #define S_IRUSR S_IREAD #define S_IWUSR S_IWRITE #endif typedef unsigned long _fsize_t; struct _wfinddata_t { unsigned attrib; time_t time_create; /* -1 for FAT file systems */ time_t time_access; /* -1 for FAT file systems */ time_t time_write; _fsize_t size; wchar_t name[260]; /* may include spaces. */ }; #endif /* ALLEGRO_SRC */ /* arrange for other headers to be included later on */ #define ALLEGRO_EXTRA_HEADER "allegro5/platform/alwin.h" #define ALLEGRO_INTERNAL_HEADER "allegro5/platform/aintwin.h" allegro5-5.2.10.1/include/allegro5/platform/aliphone.h000066400000000000000000000003331473414355200224100ustar00rootroot00000000000000#ifndef ALLEGRO_IPHONE #error bad include #endif #ifndef ALLEGRO_LIB_BUILD #define ALLEGRO_MAGIC_MAIN #define main _al_mangled_main #ifdef __cplusplus extern "C" int _al_mangled_main(int, char **); #endif #endif allegro5-5.2.10.1/include/allegro5/platform/aliphonecfg.h000066400000000000000000000020741473414355200230740ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration defines for use on iOS. * * See readme.txt for copyright information. */ #include #include /* Describe this platform. */ #define ALLEGRO_PLATFORM_STR "IPHONE" #define ALLEGRO_EXTRA_HEADER "allegro5/platform/aliphone.h" #define ALLEGRO_INTERNAL_HEADER "allegro5/platform/aintiphone.h" #define ALLEGRO_INTERNAL_THREAD_HEADER "allegro5/platform/aintuthr.h" #define ALLEGRO_EXCLUDE_GLX #ifndef AL_INLINE #define AL_INLINE(type, name, args, code) \ static __inline__ type name args; \ static __inline__ type name args code #endif allegro5-5.2.10.1/include/allegro5/platform/allegro_internal_sdl.h000066400000000000000000000033331473414355200247770ustar00rootroot00000000000000#include "SDL.h" #include "allegro5/altime.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/internal/aintern_mouse.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_system.h" typedef struct { ALLEGRO_SYSTEM system; ALLEGRO_MUTEX *mutex; #ifdef __EMSCRIPTEN__ double timer_time; #endif } ALLEGRO_SYSTEM_SDL; typedef struct ALLEGRO_DISPLAY_SDL { ALLEGRO_DISPLAY display; /* This must be the first member. */ int x, y; SDL_Window *window; SDL_GLContext context; } ALLEGRO_DISPLAY_SDL; ALLEGRO_SYSTEM_INTERFACE *_al_sdl_system_driver(void); ALLEGRO_DISPLAY_INTERFACE *_al_sdl_display_driver(void); ALLEGRO_KEYBOARD_DRIVER *_al_sdl_keyboard_driver(void); ALLEGRO_MOUSE_DRIVER *_al_sdl_mouse_driver(void); ALLEGRO_TOUCH_INPUT_DRIVER *_al_sdl_touch_input_driver(void); ALLEGRO_JOYSTICK_DRIVER *_al_sdl_joystick_driver(void); ALLEGRO_BITMAP_INTERFACE *_al_sdl_bitmap_driver(void); void _al_sdl_keyboard_event(SDL_Event *e); void _al_sdl_mouse_event(SDL_Event *e); void _al_sdl_touch_input_event(SDL_Event *e); void _al_sdl_display_event(SDL_Event *e); void _al_sdl_joystick_event(SDL_Event *e); int _al_sdl_get_allegro_pixel_format(int sdl_format); int _al_sdl_get_sdl_pixel_format(int allegro_format); ALLEGRO_DISPLAY *_al_sdl_find_display(uint32_t window_id); float _al_sdl_get_display_pixel_ratio(ALLEGRO_DISPLAY *display); void _al_sdl_event_hack(void); double _al_sdl_get_time(void); void _al_sdl_rest(double seconds); void _al_sdl_init_timeout(ALLEGRO_TIMEOUT *timeout, double seconds); typedef struct ALLEGRO_MOUSE_CURSOR_SDL ALLEGRO_MOUSE_CURSOR_SDL; struct ALLEGRO_MOUSE_CURSOR_SDL { SDL_Cursor *cursor; }; allegro5-5.2.10.1/include/allegro5/platform/allegro_sdl_config.h000066400000000000000000000004411473414355200244250ustar00rootroot00000000000000#define ALLEGRO_PLATFORM_STR "SDL" #define ALLEGRO_INTERNAL_HEADER "allegro5/platform/allegro_internal_sdl.h" #define ALLEGRO_INTERNAL_THREAD_HEADER "allegro5/platform/allegro_sdl_thread.h" // FIXME: remove once we don't use Unix specifics anymore #include #include allegro5-5.2.10.1/include/allegro5/platform/allegro_sdl_thread.h000066400000000000000000000031121473414355200244250ustar00rootroot00000000000000#ifndef __al_included_allegro5_allegro_sdl_thread_h #define __al_included_allegro5_allegro_sdl_thread_h #include "SDL.h" #ifdef __cplusplus extern "C" { #endif struct _AL_MUTEX { SDL_mutex *mutex; }; struct _AL_THREAD { /* private: */ SDL_Thread *thread; bool should_stop; void (*proc)(struct _AL_THREAD *self, void *arg); void *arg; }; #define _AL_MUTEX_UNINITED { NULL } #define _AL_MARK_MUTEX_UNINITED(M) do { M.mutex = NULL; } while (0) struct _AL_COND { SDL_cond *cond; }; typedef struct ALLEGRO_TIMEOUT_SDL ALLEGRO_TIMEOUT_SDL; struct ALLEGRO_TIMEOUT_SDL { int ms; }; AL_INLINE(bool, _al_get_thread_should_stop, (struct _AL_THREAD *t), { return t->should_stop; }) AL_FUNC(void, _al_mutex_init, (struct _AL_MUTEX*)); AL_FUNC(void, _al_mutex_destroy, (struct _AL_MUTEX*)); AL_INLINE(void, _al_mutex_lock, (struct _AL_MUTEX *m), { if (m->mutex) SDL_LockMutex(m->mutex); }) AL_INLINE(void, _al_mutex_unlock, (struct _AL_MUTEX *m), { if (m->mutex) SDL_UnlockMutex(m->mutex); }) AL_INLINE(void, _al_cond_init, (struct _AL_COND *cond), { cond->cond = SDL_CreateCond(); }) AL_INLINE(void, _al_cond_destroy, (struct _AL_COND *cond), { SDL_DestroyCond(cond->cond); }) AL_INLINE(void, _al_cond_wait, (struct _AL_COND *cond, struct _AL_MUTEX *mutex), { SDL_CondWait(cond->cond, mutex->mutex); }) AL_INLINE(void, _al_cond_broadcast, (struct _AL_COND *cond), { SDL_CondBroadcast(cond->cond); }) AL_INLINE(void, _al_cond_signal, (struct _AL_COND *cond), { SDL_CondSignal(cond->cond); }) #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/platform/almngw32.h000066400000000000000000000044761473414355200222570ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration defines for use with Mingw32. * * By Michael Rickmann. * * Native build version by Henrik Stokseth. * * See readme.txt for copyright information. */ #include #include #include #include #include "allegro5/platform/alplatf.h" /* describe this platform */ #ifdef ALLEGRO_STATICLINK #define ALLEGRO_PLATFORM_STR "MinGW32.s" #else #define ALLEGRO_PLATFORM_STR "MinGW32" #endif #define ALLEGRO_WINDOWS #define ALLEGRO_I386 #define ALLEGRO_LITTLE_ENDIAN #ifdef ALLEGRO_USE_CONSOLE #define ALLEGRO_NO_MAGIC_MAIN #endif /* describe how function prototypes look to MINGW32 */ #if (defined ALLEGRO_STATICLINK) || (defined ALLEGRO_SRC) #define _AL_DLL #else #define _AL_DLL __declspec(dllimport) #endif #define AL_VAR(type, name) extern _AL_DLL type name #define AL_ARRAY(type, name) extern _AL_DLL type name[] #define AL_FUNC(type, name, args) extern type name args #define AL_METHOD(type, name, args) type (*name) args #define AL_FUNCPTR(type, name, args) extern _AL_DLL type (*name) args /* windows specific defines */ #if (defined ALLEGRO_SRC) /* pathches to handle DX7 headers on a win9x system */ /* should WINNT be defined on win9x systems? */ #ifdef WINNT #undef WINNT #endif /* defined in windef.h */ #ifndef HMONITOR_DECLARED #define HMONITOR_DECLARED 1 #endif #endif /* ALLEGRO_SRC */ /* another instance of missing constants in the mingw32 headers */ #ifndef ENUM_CURRENT_SETTINGS #define ENUM_CURRENT_SETTINGS ((DWORD)-1) #endif /* arrange for other headers to be included later on */ #define ALLEGRO_EXTRA_HEADER "allegro5/platform/alwin.h" #define ALLEGRO_INTERNAL_HEADER "allegro5/platform/aintwin.h" #define ALLEGRO_INTERNAL_THREAD_HEADER "allegro5/platform/aintwthr.h" allegro5-5.2.10.1/include/allegro5/platform/almsvc.h000066400000000000000000000056331473414355200221060ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration defines for use with MSVC. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #include #include #include #include #include "allegro5/platform/alplatf.h" #pragma warning (disable: 4200 4244 4305 4800) /* describe this platform */ #ifdef ALLEGRO_STATICLINK #define ALLEGRO_PLATFORM_STR "MSVC.s" #else #define ALLEGRO_PLATFORM_STR "MSVC" #endif #define ALLEGRO_WINDOWS #define ALLEGRO_I386 #define ALLEGRO_LITTLE_ENDIAN #define ALLEGRO_GUESS_INTTYPES_OK #ifdef ALLEGRO_USE_CONSOLE #define ALLEGRO_NO_MAGIC_MAIN #endif /* describe how function prototypes look to MSVC */ #ifndef ALLEGRO_STATICLINK #ifdef ALLEGRO_SRC #define _AL_DLL __declspec(dllexport) #else #define _AL_DLL __declspec(dllimport) #endif #else #define _AL_DLL #endif #define AL_VAR(type, name) extern _AL_DLL type name #define AL_ARRAY(type, name) extern _AL_DLL type name[] #define AL_FUNC(type, name, args) _AL_DLL type __cdecl name args #define AL_METHOD(type, name, args) type (__cdecl *name) args #define AL_FUNCPTR(type, name, args) extern _AL_DLL type (__cdecl *name) args #ifdef AL_INLINE #define END_OF_INLINE(name) void *_force_instantiate_##name = name; #else #define END_OF_INLINE(name) #endif #undef AL_INLINE #undef AL_INLINE_STATIC #define AL_INLINE(type, name, args, code) __inline _AL_DLL type __cdecl name args code END_OF_INLINE(name) #define AL_INLINE_STATIC(type, name, args, code) __inline type __cdecl name args code END_OF_INLINE(name) #define INLINE __inline /* VC10 is the first version to define int64_t and uint64_t */ #if _MSC_VER < 1600 #define int64_t signed __int64 #define uint64_t unsigned __int64 #endif /* __func__ is C99 */ #ifndef __func__ /* MSVC versions before VC7 don't have __FUNCTION__ */ #if _MSC_VER < 1300 #define __func__ "???" #else #define __func__ __FUNCTION__ #endif #endif /* life would be so easy if compilers would all use the same names! */ #if (!defined S_IRUSR) #define S_IRUSR S_IREAD #define S_IWUSR S_IWRITE #define S_IXUSR S_IEXEC #endif /* arrange for other headers to be included later on */ #define ALLEGRO_EXTRA_HEADER "allegro5/platform/alwin.h" #define ALLEGRO_INTERNAL_HEADER "allegro5/platform/aintwin.h" #define ALLEGRO_INTERNAL_THREAD_HEADER "allegro5/platform/aintwthr.h" allegro5-5.2.10.1/include/allegro5/platform/alosx.h000066400000000000000000000042411473414355200217410ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * MacOS X specific header defines. * * By Angelo Mottola. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_alosx_h #define __al_included_allegro5_alosx_h #ifndef ALLEGRO_MACOSX #error bad include #endif #include #include #include #include #include #include #if defined __OBJC__ && defined ALLEGRO_SRC #import #import #import #import #import #import #import #import #import #import #import #import #import #endif ALLEGRO_PATH *_al_osx_get_path(int id); #ifndef ALLEGRO_LIB_BUILD #ifndef ALLEGRO_NO_MAGIC_MAIN #define ALLEGRO_MAGIC_MAIN #if __GNUC__ >= 4 #define main __attribute__ ((visibility("default"),used)) _al_mangled_main #else #define main _al_mangled_main #endif #ifdef __cplusplus extern "C" int _al_mangled_main(int, char **); /* We can't provide a prototype for C without restricting * users into a single function signature for main(). */ #endif #endif #endif /* Keyboard driver */ #define KEYBOARD_MACOSX AL_ID('O','S','X','K') #endif /* Local variables: */ /* mode: objc */ /* c-basic-offset: 3 */ /* indent-tabs-mode: nil */ /* End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/platform/alosxcfg.h000066400000000000000000000021501473414355200224160ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration defines for use with MacOS X. * * By Angelo Mottola. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_alosxcfg_h #define __al_included_allegro5_alosxcfg_h /* Include configuration information. */ #include "allegro5/platform/alplatf.h" #define ALLEGRO_INTERNAL_THREAD_HEADER "allegro5/platform/aintuthr.h" /* Describe this platform */ #define ALLEGRO_PLATFORM_STR "MacOS X" /* Arrange for other headers to be included later on */ #define ALLEGRO_EXTRA_HEADER "allegro5/platform/alosx.h" #define ALLEGRO_INTERNAL_HEADER "allegro5/platform/aintosx.h" #endif allegro5-5.2.10.1/include/allegro5/platform/alplatf.h.cmake000066400000000000000000000101201473414355200233060ustar00rootroot00000000000000/* alplatf.h is generated from alplatf.h.cmake */ #cmakedefine ALLEGRO_MINGW32 #cmakedefine ALLEGRO_UNIX #cmakedefine ALLEGRO_MSVC #cmakedefine ALLEGRO_MACOSX #cmakedefine ALLEGRO_BCC32 #cmakedefine ALLEGRO_IPHONE #cmakedefine ALLEGRO_ANDROID #cmakedefine ALLEGRO_RASPBERRYPI #cmakedefine ALLEGRO_CFG_NO_FPU #cmakedefine ALLEGRO_CFG_DLL_TLS #cmakedefine ALLEGRO_CFG_PTHREADS_TLS #cmakedefine ALLEGRO_CFG_RELEASE_LOGGING #cmakedefine ALLEGRO_CFG_D3D #cmakedefine ALLEGRO_CFG_D3D9EX #cmakedefine ALLEGRO_CFG_D3DX9 #cmakedefine ALLEGRO_CFG_XINPUT #cmakedefine ALLEGRO_CFG_OPENGL #cmakedefine ALLEGRO_CFG_OPENGLES #cmakedefine ALLEGRO_CFG_OPENGLES1 #cmakedefine ALLEGRO_CFG_OPENGLES2 #cmakedefine ALLEGRO_CFG_OPENGLES3 #cmakedefine ALLEGRO_CFG_OPENGL_FIXED_FUNCTION #cmakedefine ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE #cmakedefine ALLEGRO_CFG_SHADER_GLSL #cmakedefine ALLEGRO_CFG_SHADER_HLSL #cmakedefine ALLEGRO_CFG_ANDROID_LEGACY #cmakedefine ALLEGRO_CFG_HAVE_XINPUT_CAPABILITIES_EX /*---------------------------------------------------------------------------*/ /* Define to 1 if you have the corresponding header file. */ #cmakedefine ALLEGRO_HAVE_DIRENT_H #cmakedefine ALLEGRO_HAVE_INTTYPES_H #cmakedefine ALLEGRO_HAVE_LINUX_AWE_VOICE_H #cmakedefine ALLEGRO_HAVE_LINUX_INPUT_H #cmakedefine ALLEGRO_HAVE_LINUX_SOUNDCARD_H #cmakedefine ALLEGRO_HAVE_MACHINE_SOUNDCARD_H #cmakedefine ALLEGRO_HAVE_SOUNDCARD_H #cmakedefine ALLEGRO_HAVE_STDBOOL_H #cmakedefine ALLEGRO_HAVE_STDINT_H #cmakedefine ALLEGRO_HAVE_SV_PROCFS_H #cmakedefine ALLEGRO_HAVE_SYS_IO_H #cmakedefine ALLEGRO_HAVE_SYS_SOUNDCARD_H #cmakedefine ALLEGRO_HAVE_SYS_STAT_H #cmakedefine ALLEGRO_HAVE_SYS_TIME_H #cmakedefine ALLEGRO_HAVE_TIME_H #cmakedefine ALLEGRO_HAVE_SYS_UTSNAME_H #cmakedefine ALLEGRO_HAVE_SYS_TYPES_H #cmakedefine ALLEGRO_HAVE_OSATOMIC_H #cmakedefine ALLEGRO_HAVE_SYS_INOTIFY_H #cmakedefine ALLEGRO_HAVE_SAL_H /* Define to 1 if the corresponding functions are available. */ #cmakedefine ALLEGRO_HAVE_GETEXECNAME #cmakedefine ALLEGRO_HAVE_MKSTEMP #cmakedefine ALLEGRO_HAVE_MMAP #cmakedefine ALLEGRO_HAVE_MPROTECT #cmakedefine ALLEGRO_HAVE_SCHED_YIELD #cmakedefine ALLEGRO_HAVE_SYSCONF #cmakedefine ALLEGRO_HAVE_SYSCTL #cmakedefine ALLEGRO_HAVE_FSEEKO #cmakedefine ALLEGRO_HAVE_FTELLO #cmakedefine ALLEGRO_HAVE_STRERROR_R #cmakedefine ALLEGRO_HAVE_STRERROR_S #cmakedefine ALLEGRO_HAVE_VA_COPY #cmakedefine ALLEGRO_HAVE_FTELLI64 #cmakedefine ALLEGRO_HAVE_FSEEKI64 /* Define to 1 if procfs reveals argc and argv */ #cmakedefine ALLEGRO_HAVE_PROCFS_ARGCV /*---------------------------------------------------------------------------*/ /* Define if target machine is little endian. */ #cmakedefine ALLEGRO_LITTLE_ENDIAN /* Define if target machine is big endian. */ #cmakedefine ALLEGRO_BIG_ENDIAN /* Define if target platform is Darwin. */ #cmakedefine ALLEGRO_DARWIN /*---------------------------------------------------------------------------*/ /* Define if you need support for X-Windows. */ #cmakedefine ALLEGRO_WITH_XWINDOWS /* Define if XCursor ARGB extension is available. */ #cmakedefine ALLEGRO_XWINDOWS_WITH_XCURSOR /* Define if XF86VidMode extension is supported. */ #cmakedefine ALLEGRO_XWINDOWS_WITH_XF86VIDMODE /* Define if Xinerama extension is supported. */ #cmakedefine ALLEGRO_XWINDOWS_WITH_XINERAMA /* Define if XRandR extension is supported. */ #cmakedefine ALLEGRO_XWINDOWS_WITH_XRANDR /* Define if XScreenSaver extension is supported. */ #cmakedefine ALLEGRO_XWINDOWS_WITH_XSCREENSAVER /* Define if XIM extension is supported. */ #cmakedefine ALLEGRO_XWINDOWS_WITH_XIM /* Define if XInput 2.2 X11 extension is supported. */ #cmakedefine ALLEGRO_XWINDOWS_WITH_XINPUT2 /*---------------------------------------------------------------------------*/ /* Define if target platform is linux. */ #cmakedefine ALLEGRO_LINUX /* Define if we are building with SDL backend. */ #cmakedefine ALLEGRO_SDL /* Define if sleep should be used instead of threads (only useful for emscripten without web workers) */ #cmakedefine ALLEGRO_WAIT_EVENT_SLEEP /*---------------------------------------------------------------------------*/ /* vi: set ft=c ts=3 sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/platform/alraspberrypi.h000066400000000000000000000013501473414355200234700ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Raspberry Pi-specific header defines. * * See readme.txt for copyright information. */ #ifndef ALLEGRO_RASPBERRYPI #error bad include #endif #ifdef ALLEGRO_LIB_BUILD #include "allegro5/platform/aintuthr.h" #endif /* Nothing left */ allegro5-5.2.10.1/include/allegro5/platform/alraspberrypicfg.h000066400000000000000000000017661473414355200241630ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration defines for use on Raspberry Pi platforms. * * By Trent Gamblin. * * See readme.txt for copyright information. */ #include #include #include /* Describe this platform. */ #define ALLEGRO_PLATFORM_STR "RaspberryPi" #define ALLEGRO_EXTRA_HEADER "allegro5/platform/alraspberrypi.h" #define ALLEGRO_INTERNAL_HEADER "allegro5/platform/aintraspberrypi.h" #define ALLEGRO_INTERNAL_THREAD_HEADER "allegro5/platform/aintuthr.h" #define ALLEGRO_EXCLUDE_GLX allegro5-5.2.10.1/include/allegro5/platform/alucfg.h000066400000000000000000000022311473414355200220510ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration defines for use on Unix platforms. * * By Michael Bukin. * * See readme.txt for copyright information. */ #include #include /* Describe this platform. */ #define ALLEGRO_PLATFORM_STR "Unix" #define ALLEGRO_EXTRA_HEADER "allegro5/platform/alunix.h" #ifdef _this_is_a_hack_to_fool_scons #include "alunix.h" #endif #define ALLEGRO_INTERNAL_HEADER "allegro5/platform/aintunix.h" #define ALLEGRO_INTERNAL_THREAD_HEADER "allegro5/platform/aintuthr.h" /* Include configuration information. */ #include "allegro5/platform/alplatf.h" /* Enable OpenGL if GLX is available. */ #ifdef ALLEGRO_GLX #define ALLEGRO_CFG_OPENGL #endif allegro5-5.2.10.1/include/allegro5/platform/alunix.h000066400000000000000000000012221473414355200221070ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Unix-specific header defines. * * See readme.txt for copyright information. */ #ifndef ALLEGRO_UNIX #error bad include #endif /* Nothing left */ allegro5-5.2.10.1/include/allegro5/platform/alwatcom.h000066400000000000000000000127611473414355200224300ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration defines for use with Watcom. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #ifndef __SW_3S #error Allegro only supports stack based calling convention #endif #ifndef __SW_S #error Stack overflow checking must be disabled #endif #include #include #include #include #include #include #pragma disable_message (120 201 202) /* these are available in OpenWatcom 1.3 (12.3) */ #if __WATCOMC__ >= 1230 #define ALLEGRO_HAVE_INTTYPES_H 1 #define ALLEGRO_HAVE_STDINT_H 1 #else #define ALLEGRO_GUESS_INTTYPES_OK #endif /* describe this platform */ #define ALLEGRO_PLATFORM_STR "Watcom" #define ALLEGRO_DOS #define ALLEGRO_I386 #define ALLEGRO_LITTLE_ENDIAN #ifdef ALLEGRO_GUESS_INTTYPES_OK #define int64_t signed long long #define uint64_t unsigned long long #endif /* emulate some important djgpp routines */ #define inportb(port) inp(port) #define inportw(port) inpw(port) #define outportb(port, val) outp(port, val) #define outportw(port, val) outpw(port, val) #define ffblk find_t #define ff_name name #define ff_attrib attrib #define ff_fsize size #define ff_ftime wr_time #define ff_fdate wr_date #define findfirst(name, dta, attrib) _dos_findfirst(name, attrib, dta) #define findnext(dta) _dos_findnext(dta) #define random() rand() #define srandom(n) srand(n) #define _dos_ds _default_ds() #define dosmemget(offset, length, buffer) memcpy(buffer, (void *)(offset), length) #define dosmemput(buffer, length, offset) memcpy((void *)(offset), buffer, length) #define __djgpp_nearptr_enable() 1 #define __djgpp_nearptr_disable() #define __djgpp_base_address 0 #define __djgpp_conventional_base 0 #define _crt0_startup_flags 1 #define _CRT0_FLAG_NEARPTR 1 #ifdef __cplusplus extern "C" { #endif typedef union __dpmi_regs { struct { unsigned long edi, esi, ebp, res, ebx, edx, ecx, eax; } d; struct { unsigned short di, di_hi, si, si_hi, bp, bp_hi, res, res_hi; unsigned short bx, bx_hi, dx, dx_hi, cx, cx_hi, ax, ax_hi; unsigned short flags, es, ds, fs, gs, ip, cs, sp, ss; } x; struct { unsigned char edi[4], esi[4], ebp[4], res[4]; unsigned char bl, bh, ebx_b2, ebx_b3, dl, dh, edx_b2, edx_b3; unsigned char cl, ch, ecx_b2, ecx_b3, al, ah, eax_b2, eax_b3; } h; } __dpmi_regs; typedef struct __dpmi_meminfo { unsigned long handle; unsigned long size; unsigned long address; } __dpmi_meminfo; typedef struct __dpmi_free_mem_info { unsigned long largest_available_free_block_in_bytes; unsigned long maximum_unlocked_page_allocation_in_pages; unsigned long maximum_locked_page_allocation_in_pages; unsigned long linear_address_space_size_in_pages; unsigned long total_number_of_unlocked_pages; unsigned long total_number_of_free_pages; unsigned long total_number_of_physical_pages; unsigned long free_linear_address_space_in_pages; unsigned long size_of_paging_file_partition_in_pages; unsigned long reserved[3]; } __dpmi_free_mem_info; extern unsigned long __tb; int __dpmi_int(int vector, __dpmi_regs *regs); int __dpmi_allocate_dos_memory(int paragraphs, int *ret); int __dpmi_free_dos_memory(int selector); int __dpmi_physical_address_mapping(__dpmi_meminfo *info); int __dpmi_free_physical_address_mapping(__dpmi_meminfo *info); int __dpmi_lock_linear_region(__dpmi_meminfo *info); int __dpmi_unlock_linear_region(__dpmi_meminfo *info); int __dpmi_allocate_ldt_descriptors(int count); int __dpmi_free_ldt_descriptor(int descriptor); int __dpmi_get_segment_base_address(int selector, unsigned long *addr); int __dpmi_set_segment_base_address(int selector, unsigned long address); int __dpmi_set_segment_limit(int selector, unsigned long limit); int __dpmi_get_free_memory_information(__dpmi_free_mem_info *info); int __dpmi_simulate_real_mode_interrupt(int vector, __dpmi_regs *regs); int __dpmi_simulate_real_mode_procedure_retf(__dpmi_regs *regs); int _go32_dpmi_lock_data(void *lockaddr, unsigned long locksize); int _go32_dpmi_lock_code(void *lockaddr, unsigned long locksize); long _allocate_real_mode_callback(void (*handler)(__dpmi_regs *r), __dpmi_regs *regs); /* memory locking macros */ void _unlock_dpmi_data(void *addr, int size); #ifdef __cplusplus } #endif #define END_OF_FUNCTION(x) void x##_end(void) { } #define END_OF_STATIC_FUNCTION(x) static void x##_end(void) { } #define LOCK_DATA(d, s) _go32_dpmi_lock_data(d, s) #define LOCK_CODE(c, s) _go32_dpmi_lock_code(c, s) #define UNLOCK_DATA(d,s) _unlock_dpmi_data(d, s) #define LOCK_VARIABLE(x) LOCK_DATA((void *)&x, sizeof(x)) #define LOCK_FUNCTION(x) LOCK_CODE((void *)FP_OFF(x), (long)FP_OFF(x##_end) - (long)FP_OFF(x)) /* arrange for other headers to be included later on */ #define ALLEGRO_EXTRA_HEADER "allegro5/platform/aldos.h" #define ALLEGRO_INTERNAL_HEADER "allegro5/platform/aintdos.h" allegro5-5.2.10.1/include/allegro5/platform/alwin.h000066400000000000000000000067071473414355200217360ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows-specific header defines. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #ifndef ALLEGRO_WINDOWS #error bad include #endif /*******************************************/ /********** magic main emulation ***********/ /*******************************************/ #ifdef __cplusplus extern "C" { #endif AL_FUNC(int, _WinMain, (void *_main, void *hInst, void *hPrev, char *Cmd, int nShow)); #ifdef __cplusplus } #endif /* The following is due to torhu from A.cc (see * http://www.allegro.cc/forums/thread/596872/756993#target) */ #ifndef ALLEGRO_NO_MAGIC_MAIN #if defined _MSC_VER && !defined ALLEGRO_LIB_BUILD #pragma comment(linker,"/ENTRY:mainCRTStartup") #endif #endif /*******************************************/ /************ joystick drivers *************/ /*******************************************/ #define AL_JOY_TYPE_DIRECTX AL_ID('D','X',' ',' ') #ifdef __cplusplus extern "C" { #endif AL_VAR(struct ALLEGRO_JOYSTICK_DRIVER, _al_joydrv_directx); #ifdef __cplusplus } #endif #define _AL_JOYSTICK_DRIVER_DIRECTX \ { AL_JOY_TYPE_DIRECTX, &_al_joydrv_directx, true }, #define AL_JOY_TYPE_XINPUT AL_ID('X','I',' ',' ') #ifdef __cplusplus extern "C" { #endif AL_VAR(struct ALLEGRO_JOYSTICK_DRIVER, _al_joydrv_xinput); #ifdef __cplusplus } #endif #define _AL_JOYSTICK_DRIVER_XINPUT \ { AL_JOY_TYPE_XINPUT, &_al_joydrv_xinput, true }, #define AL_JOY_TYPE_WINDOWS_ALL AL_ID('X','D',' ',' ') #ifdef __cplusplus extern "C" { #endif AL_VAR(struct ALLEGRO_JOYSTICK_DRIVER, _al_joydrv_windows_all); #ifdef __cplusplus } #endif #define _AL_JOYSTICK_DRIVER_WINDOWS_ALL \ { AL_JOY_TYPE_WINDOWS_ALL, &_al_joydrv_windows_all, true }, /*******************************************/ /************ haptic drivers *************/ /*******************************************/ #define AL_HAPTIC_TYPE_DIRECTX AL_ID('D','X','F','F') #ifdef __cplusplus extern "C" { #endif AL_VAR(struct ALLEGRO_HAPTIC_DRIVER, _al_hapdrv_directx); #ifdef __cplusplus } #endif #define _AL_HAPTIC_DRIVER_DIRECTX \ { AL_HAPTIC_TYPE_DIRECTX, &_al_hapdrv_directx, true }, #define AL_HAPTIC_TYPE_XINPUT AL_ID('X','I','F','F') #ifdef __cplusplus extern "C" { #endif AL_VAR(struct ALLEGRO_HAPTIC_DRIVER, _al_hapdrv_xinput); #ifdef __cplusplus } #endif #define _AL_HAPTIC_DRIVER_XINPUT \ { AL_HAPTIC_TYPE_XINPUT, &_al_hapdrv_xinput, true }, #define AL_HAPTIC_TYPE_WINDOWS_ALL AL_ID('X','D','F','F') #ifdef __cplusplus extern "C" { #endif AL_VAR(struct ALLEGRO_HAPTIC_DRIVER, _al_hapdrv_windows_all); #ifdef __cplusplus } #endif #define _AL_HAPTIC_DRIVER_WINDOWS_ALL \ { AL_HAPTIC_TYPE_WINDOWS_ALL, &_al_hapdrv_windows_all, true }, allegro5-5.2.10.1/include/allegro5/platform/alwiz.h000066400000000000000000000017001473414355200217360ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Wiz-specific header defines. * * By Trent Gamblin * * See readme.txt for copyright information. */ #ifndef ALLEGRO_GP2XWIZ #error bad include #endif #define AL_JOY_TYPE_GP2XWIZ AL_ID('W','I','Z',' ') AL_VAR(struct ALLEGRO_JOYSTICK_DRIVER, _al_joydrv_gp2xwiz); #define _AL_JOYSTICK_DRIVER_GP2XWIZ \ { AL_JOY_TYPE_GP2XWIZ, &_al_joydrv_gp2xwiz, true }, #include "allegro5/platform/alunix.h" allegro5-5.2.10.1/include/allegro5/platform/alwizcfg.h000066400000000000000000000020461473414355200224220ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration defines for use on GP2X Wiz * * By Trent Gamblin * * See readme.txt for copyright information. */ #include #include /* Describe this platform. */ #define ALLEGRO_PLATFORM_STR "GP2XWIZ" #define ALLEGRO_EXTRA_HEADER "allegro5/platform/alwiz.h" #define ALLEGRO_INTERNAL_HEADER "allegro5/platform/aintwiz.h" #define ALLEGRO_INTERNAL_THREAD_HEADER "allegro5/platform/aintuthr.h" /* Include configuration information. */ #include "allegro5/platform/alplatf.h" /* No GLX on the Wiz */ #define ALLEGRO_EXCLUDE_GLX allegro5-5.2.10.1/include/allegro5/platform/astdbool.h000066400000000000000000000017571473414355200224330ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * A header file to get C99's stdbool.h. * * By Peter Wang. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_astdbool_h #define __al_included_allegro5_astdbool_h #ifndef __cplusplus # ifdef ALLEGRO_HAVE_STDBOOL_H # include # else # ifndef ALLEGRO_HAVE__BOOL typedef unsigned char _Bool; # endif # define bool _Bool # define false 0 # define true 1 # define __bool_true_false_are_defined 1 # endif #endif #endif allegro5-5.2.10.1/include/allegro5/platform/astdint.h000066400000000000000000000045701473414355200222660ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * A header file to get definitions of uint*_t and int*_t. * * By Peter Wang. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_astdint_h #define __al_included_allegro5_astdint_h /* Please only include this file from include/allegro5/internal/alconfig.h * and don't add more than inttypes.h/stdint.h emulation here. Thanks. */ #if defined ALLEGRO_HAVE_INTTYPES_H #include #elif defined ALLEGRO_HAVE_STDINT_H #include #elif defined ALLEGRO_I386 && defined ALLEGRO_LITTLE_ENDIAN #ifndef ALLEGRO_GUESS_INTTYPES_OK #warning Guessing the definitions of fixed-width integer types. #endif #include #define int8_t signed char #define uint8_t unsigned char #define int16_t signed short #define uint16_t unsigned short #define int32_t signed int #define uint32_t unsigned int #define INT8_MIN CHAR_MIN #define INT8_MAX CHAR_MAX #define UINT8_MAX UCHAR_MAX #define INT16_MIN SHRT_MIN #define INT16_MAX SHRT_MAX #define UINT16_MAX USHRT_MAX #define INT32_MIN INT_MIN #define INT32_MAX INT_MAX #define UINT32_MAX UINT_MAX #ifdef ALLEGRO_WINDOWS #ifndef _INTPTR_T_DEFINED #ifdef _WIN64 #define intptr_t __int64 #else #define intptr_t int #endif #define _INTPTR_T_DEFINED #endif #ifndef _UINTPTR_T_DEFINED #ifdef _WIN64 #define uintptr_t unsigned __int64 #else #define uintptr_t unsigned int #endif #define _UINTPTR_T_DEFINED #endif #else #define intptr_t int32_t #define uintptr_t uint32_t #endif #else #error I dunno how to get the definitions of fixed-width integer types on your platform. Please report this to your friendly Allegro developer. #endif #endif allegro5-5.2.10.1/include/allegro5/render_state.h000066400000000000000000000027321473414355200214510ustar00rootroot00000000000000#ifndef __al_included_allegro5_render_state_h #define __al_included_allegro5_render_state_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif /* Enum: ALLEGRO_RENDER_STATE */ typedef enum ALLEGRO_RENDER_STATE { /* ALLEGRO_ALPHA_TEST was the name of a rare bitmap flag only used on the * Wiz port. Reuse the name but retain the same value. */ ALLEGRO_ALPHA_TEST = 0x0010, ALLEGRO_WRITE_MASK, ALLEGRO_DEPTH_TEST, ALLEGRO_DEPTH_FUNCTION, ALLEGRO_ALPHA_FUNCTION, ALLEGRO_ALPHA_TEST_VALUE } ALLEGRO_RENDER_STATE; /* Enum: ALLEGRO_RENDER_FUNCTION */ typedef enum ALLEGRO_RENDER_FUNCTION { ALLEGRO_RENDER_NEVER, ALLEGRO_RENDER_ALWAYS, ALLEGRO_RENDER_LESS, ALLEGRO_RENDER_EQUAL, ALLEGRO_RENDER_LESS_EQUAL, ALLEGRO_RENDER_GREATER, ALLEGRO_RENDER_NOT_EQUAL, ALLEGRO_RENDER_GREATER_EQUAL } ALLEGRO_RENDER_FUNCTION; /* Enum: ALLEGRO_WRITE_MASK_FLAGS */ typedef enum ALLEGRO_WRITE_MASK_FLAGS { ALLEGRO_MASK_RED = 1 << 0, ALLEGRO_MASK_GREEN = 1 << 1, ALLEGRO_MASK_BLUE = 1 << 2, ALLEGRO_MASK_ALPHA = 1 << 3, ALLEGRO_MASK_DEPTH = 1 << 4, ALLEGRO_MASK_RGB = (ALLEGRO_MASK_RED | ALLEGRO_MASK_GREEN | ALLEGRO_MASK_BLUE), ALLEGRO_MASK_RGBA = (ALLEGRO_MASK_RGB | ALLEGRO_MASK_ALPHA) } ALLEGRO_WRITE_MASK_FLAGS; AL_FUNC(int, al_get_render_state, (ALLEGRO_RENDER_STATE state)); AL_FUNC(void, al_set_render_state, (ALLEGRO_RENDER_STATE state, int value)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/shader.h000066400000000000000000000057571473414355200202520ustar00rootroot00000000000000#ifndef __al_included_allegro5_shader_h #define __al_included_allegro5_shader_h #include "allegro5/base.h" #include "allegro5/transformations.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_SHADER */ typedef struct ALLEGRO_SHADER ALLEGRO_SHADER; enum ALLEGRO_SHADER_TYPE { ALLEGRO_VERTEX_SHADER = 1, ALLEGRO_PIXEL_SHADER = 2 }; /* Enum: ALLEGRO_SHADER_TYPE */ typedef enum ALLEGRO_SHADER_TYPE ALLEGRO_SHADER_TYPE; enum ALLEGRO_SHADER_PLATFORM { ALLEGRO_SHADER_AUTO = 0, ALLEGRO_SHADER_GLSL = 1, ALLEGRO_SHADER_HLSL = 2, ALLEGRO_SHADER_AUTO_MINIMAL = 3, ALLEGRO_SHADER_GLSL_MINIMAL = 4, ALLEGRO_SHADER_HLSL_MINIMAL = 5, ALLEGRO_SHADER_HLSL_SM_3_0 = 6, }; /* Enum: ALLEGRO_SHADER_PLATFORM */ typedef enum ALLEGRO_SHADER_PLATFORM ALLEGRO_SHADER_PLATFORM; /* Shader variable names */ #define ALLEGRO_SHADER_VAR_COLOR "al_color" #define ALLEGRO_SHADER_VAR_POS "al_pos" #define ALLEGRO_SHADER_VAR_PROJVIEW_MATRIX "al_projview_matrix" #define ALLEGRO_SHADER_VAR_TEX "al_tex" #define ALLEGRO_SHADER_VAR_TEXCOORD "al_texcoord" #define ALLEGRO_SHADER_VAR_TEX_MATRIX "al_tex_matrix" #define ALLEGRO_SHADER_VAR_USER_ATTR "al_user_attr_" #define ALLEGRO_SHADER_VAR_USE_TEX "al_use_tex" #define ALLEGRO_SHADER_VAR_USE_TEX_MATRIX "al_use_tex_matrix" #define ALLEGRO_SHADER_VAR_ALPHA_TEST "al_alpha_test" #define ALLEGRO_SHADER_VAR_ALPHA_FUNCTION "al_alpha_func" #define ALLEGRO_SHADER_VAR_ALPHA_TEST_VALUE "al_alpha_test_val" AL_FUNC(ALLEGRO_SHADER *, al_create_shader, (ALLEGRO_SHADER_PLATFORM platform)); AL_FUNC(bool, al_attach_shader_source, (ALLEGRO_SHADER *shader, ALLEGRO_SHADER_TYPE type, const char *source)); AL_FUNC(bool, al_attach_shader_source_file, (ALLEGRO_SHADER *shader, ALLEGRO_SHADER_TYPE type, const char *filename)); AL_FUNC(bool, al_build_shader, (ALLEGRO_SHADER *shader)); AL_FUNC(const char *, al_get_shader_log, (ALLEGRO_SHADER *shader)); AL_FUNC(ALLEGRO_SHADER_PLATFORM, al_get_shader_platform, (ALLEGRO_SHADER *shader)); AL_FUNC(bool, al_use_shader, (ALLEGRO_SHADER *shader)); AL_FUNC(ALLEGRO_SHADER *, al_get_current_shader, (void)); AL_FUNC(void, al_destroy_shader, (ALLEGRO_SHADER *shader)); AL_FUNC(bool, al_set_shader_sampler, (const char *name, ALLEGRO_BITMAP *bitmap, int unit)); AL_FUNC(bool, al_set_shader_matrix, (const char *name, const ALLEGRO_TRANSFORM *matrix)); AL_FUNC(bool, al_set_shader_int, (const char *name, int i)); AL_FUNC(bool, al_set_shader_float, (const char *name, float f)); AL_FUNC(bool, al_set_shader_int_vector, (const char *name, int num_components, const int *i, int num_elems)); AL_FUNC(bool, al_set_shader_float_vector, (const char *name, int num_components, const float *f, int num_elems)); AL_FUNC(bool, al_set_shader_bool, (const char *name, bool b)); AL_FUNC(char const *, al_get_default_shader_source, (ALLEGRO_SHADER_PLATFORM platform, ALLEGRO_SHADER_TYPE type)); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/system.h000066400000000000000000000036401473414355200203150ustar00rootroot00000000000000#ifndef __al_included_allegro5_system_h #define __al_included_allegro5_system_h #include "allegro5/config.h" #include "allegro5/path.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALLEGRO_SYSTEM ALLEGRO_SYSTEM; /* Enum: ALLEGRO_SYSTEM_ID */ enum ALLEGRO_SYSTEM_ID { ALLEGRO_SYSTEM_ID_UNKNOWN = 0, ALLEGRO_SYSTEM_ID_XGLX = AL_ID('X', 'G', 'L', 'X'), ALLEGRO_SYSTEM_ID_WINDOWS = AL_ID('W', 'I', 'N', 'D'), ALLEGRO_SYSTEM_ID_MACOSX = AL_ID('O', 'S', 'X', ' '), ALLEGRO_SYSTEM_ID_ANDROID = AL_ID('A', 'N', 'D', 'R'), ALLEGRO_SYSTEM_ID_IPHONE = AL_ID('I', 'P', 'H', 'O'), ALLEGRO_SYSTEM_ID_GP2XWIZ = AL_ID('W', 'I', 'Z', ' '), ALLEGRO_SYSTEM_ID_RASPBERRYPI = AL_ID('R', 'A', 'S', 'P'), ALLEGRO_SYSTEM_ID_SDL = AL_ID('S', 'D', 'L', '2') }; typedef enum ALLEGRO_SYSTEM_ID ALLEGRO_SYSTEM_ID; /* Function: al_init */ #define al_init() (al_install_system(ALLEGRO_VERSION_INT, atexit)) AL_FUNC(bool, al_install_system, (int version, int (*atexit_ptr)(void (*)(void)))); AL_FUNC(void, al_uninstall_system, (void)); AL_FUNC(bool, al_is_system_installed, (void)); AL_FUNC(ALLEGRO_SYSTEM *, al_get_system_driver, (void)); AL_FUNC(ALLEGRO_CONFIG *, al_get_system_config, (void)); AL_FUNC(ALLEGRO_SYSTEM_ID, al_get_system_id, (void)); enum { ALLEGRO_RESOURCES_PATH = 0, ALLEGRO_TEMP_PATH, ALLEGRO_USER_DATA_PATH, ALLEGRO_USER_HOME_PATH, ALLEGRO_USER_SETTINGS_PATH, ALLEGRO_USER_DOCUMENTS_PATH, ALLEGRO_EXENAME_PATH, ALLEGRO_LAST_PATH /* must be last */ }; AL_FUNC(ALLEGRO_PATH *, al_get_standard_path, (int id)); AL_FUNC(void, al_set_exe_name, (char const *path)); AL_FUNC(void, al_set_org_name, (const char *org_name)); AL_FUNC(void, al_set_app_name, (const char *app_name)); AL_FUNC(const char *, al_get_org_name, (void)); AL_FUNC(const char *, al_get_app_name, (void)); AL_FUNC(bool, al_inhibit_screensaver, (bool inhibit)); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/threads.h000066400000000000000000000046421473414355200204260ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Thread routines. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_threads_h #define __al_included_allegro5_threads_h #include "allegro5/altime.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_THREAD */ typedef struct ALLEGRO_THREAD ALLEGRO_THREAD; /* Type: ALLEGRO_MUTEX */ typedef struct ALLEGRO_MUTEX ALLEGRO_MUTEX; /* Type: ALLEGRO_COND */ typedef struct ALLEGRO_COND ALLEGRO_COND; AL_FUNC(ALLEGRO_THREAD *, al_create_thread, (void *(*proc)(ALLEGRO_THREAD *thread, void *arg), void *arg)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) AL_FUNC(ALLEGRO_THREAD *, al_create_thread_with_stacksize, (void *(*proc)(ALLEGRO_THREAD *thread, void *arg), void *arg, size_t stacksize)); #endif AL_FUNC(void, al_start_thread, (ALLEGRO_THREAD *outer)); AL_FUNC(void, al_join_thread, (ALLEGRO_THREAD *outer, void **ret_value)); AL_FUNC(void, al_set_thread_should_stop, (ALLEGRO_THREAD *outer)); AL_FUNC(bool, al_get_thread_should_stop, (ALLEGRO_THREAD *outer)); AL_FUNC(void, al_destroy_thread, (ALLEGRO_THREAD *thread)); AL_FUNC(void, al_run_detached_thread, (void *(*proc)(void *arg), void *arg)); AL_FUNC(ALLEGRO_MUTEX *, al_create_mutex, (void)); AL_FUNC(ALLEGRO_MUTEX *, al_create_mutex_recursive, (void)); AL_FUNC(void, al_lock_mutex, (ALLEGRO_MUTEX *mutex)); AL_FUNC(void, al_unlock_mutex, (ALLEGRO_MUTEX *mutex)); AL_FUNC(void, al_destroy_mutex, (ALLEGRO_MUTEX *mutex)); AL_FUNC(ALLEGRO_COND *, al_create_cond, (void)); AL_FUNC(void, al_destroy_cond, (ALLEGRO_COND *cond)); AL_FUNC(void, al_wait_cond, (ALLEGRO_COND *cond, ALLEGRO_MUTEX *mutex)); AL_FUNC(int, al_wait_cond_until, (ALLEGRO_COND *cond, ALLEGRO_MUTEX *mutex, const ALLEGRO_TIMEOUT *timeout)); AL_FUNC(void, al_broadcast_cond, (ALLEGRO_COND *cond)); AL_FUNC(void, al_signal_cond, (ALLEGRO_COND *cond)); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/include/allegro5/timer.h000066400000000000000000000037511473414355200201140ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Timer routines. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_timer_h #define __al_included_allegro5_timer_h #include "allegro5/base.h" #include "allegro5/events.h" #ifdef __cplusplus extern "C" { #endif /* Function: ALLEGRO_USECS_TO_SECS */ #define ALLEGRO_USECS_TO_SECS(x) ((x) / 1000000.0) /* Function: ALLEGRO_MSECS_TO_SECS */ #define ALLEGRO_MSECS_TO_SECS(x) ((x) / 1000.0) /* Function: ALLEGRO_BPS_TO_SECS */ #define ALLEGRO_BPS_TO_SECS(x) (1.0 / (x)) /* Function: ALLEGRO_BPM_TO_SECS */ #define ALLEGRO_BPM_TO_SECS(x) (60.0 / (x)) /* Type: ALLEGRO_TIMER */ typedef struct ALLEGRO_TIMER ALLEGRO_TIMER; AL_FUNC(ALLEGRO_TIMER*, al_create_timer, (double speed_secs)); AL_FUNC(void, al_destroy_timer, (ALLEGRO_TIMER *timer)); AL_FUNC(void, al_start_timer, (ALLEGRO_TIMER *timer)); AL_FUNC(void, al_stop_timer, (ALLEGRO_TIMER *timer)); AL_FUNC(void, al_resume_timer, (ALLEGRO_TIMER *timer)); AL_FUNC(bool, al_get_timer_started, (const ALLEGRO_TIMER *timer)); AL_FUNC(double, al_get_timer_speed, (const ALLEGRO_TIMER *timer)); AL_FUNC(void, al_set_timer_speed, (ALLEGRO_TIMER *timer, double speed_secs)); AL_FUNC(int64_t, al_get_timer_count, (const ALLEGRO_TIMER *timer)); AL_FUNC(void, al_set_timer_count, (ALLEGRO_TIMER *timer, int64_t count)); AL_FUNC(void, al_add_timer_count, (ALLEGRO_TIMER *timer, int64_t diff)); AL_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_timer_event_source, (ALLEGRO_TIMER *timer)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/tls.h000066400000000000000000000034041473414355200175710ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Thread local storage routines. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_tls_h #define __al_included_allegro5_tls_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif /* Enum: ALLEGRO_STATE_FLAGS */ typedef enum ALLEGRO_STATE_FLAGS { ALLEGRO_STATE_NEW_DISPLAY_PARAMETERS = 0x0001, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS = 0x0002, ALLEGRO_STATE_DISPLAY = 0x0004, ALLEGRO_STATE_TARGET_BITMAP = 0x0008, ALLEGRO_STATE_BLENDER = 0x0010, ALLEGRO_STATE_NEW_FILE_INTERFACE = 0x0020, ALLEGRO_STATE_TRANSFORM = 0x0040, ALLEGRO_STATE_PROJECTION_TRANSFORM = 0x0100, ALLEGRO_STATE_BITMAP = ALLEGRO_STATE_TARGET_BITMAP +\ ALLEGRO_STATE_NEW_BITMAP_PARAMETERS, ALLEGRO_STATE_ALL = 0xffff } ALLEGRO_STATE_FLAGS; /* Type: ALLEGRO_STATE */ typedef struct ALLEGRO_STATE ALLEGRO_STATE; struct ALLEGRO_STATE { /* Internally, a thread_local_state structure is placed here. */ char _tls[1024]; }; AL_FUNC(void, al_store_state, (ALLEGRO_STATE *state, int flags)); AL_FUNC(void, al_restore_state, (ALLEGRO_STATE const *state)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/touch_input.h000066400000000000000000000054331473414355200213340ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Touch input routines. * * See readme.txt for copyright information. */ #ifndef __al_included_allegro5_touch_input_h #define __al_included_allegro5_touch_input_h #include "allegro5/base.h" #include "allegro5/events.h" #ifdef __cplusplus extern "C" { #endif /* Enum: ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT */ #define ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT 16 /* Type: ALLEGRO_TOUCH_INPUT */ typedef struct ALLEGRO_TOUCH_INPUT ALLEGRO_TOUCH_INPUT; /* Type: ALLEGRO_TOUCH_INPUT_STATE */ typedef struct ALLEGRO_TOUCH_INPUT_STATE ALLEGRO_TOUCH_INPUT_STATE; /* Type: ALLEGRO_TOUCH_STATE */ typedef struct ALLEGRO_TOUCH_STATE ALLEGRO_TOUCH_STATE; struct ALLEGRO_TOUCH_STATE { /* (id) An identifier of touch. If touch is valid this number is positive. * (x, y) Touch position on the screen in 1:1 resolution. * (dx, dy) Relative touch position. * (primary) True, if touch is a primary one (usually first one). * (display) Display at which the touch belong. */ int id; float x, y; float dx, dy; bool primary; struct ALLEGRO_DISPLAY *display; }; struct ALLEGRO_TOUCH_INPUT_STATE { ALLEGRO_TOUCH_STATE touches[ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT]; }; #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) /* Enum: ALLEGRO_MOUSE_EMULATION_MODE */ typedef enum ALLEGRO_MOUSE_EMULATION_MODE { ALLEGRO_MOUSE_EMULATION_NONE, ALLEGRO_MOUSE_EMULATION_TRANSPARENT, ALLEGRO_MOUSE_EMULATION_INCLUSIVE, ALLEGRO_MOUSE_EMULATION_EXCLUSIVE, ALLEGRO_MOUSE_EMULATION_5_0_x } ALLEGRO_MOUSE_EMULATION_MODE; #endif AL_FUNC(bool, al_is_touch_input_installed, (void)); AL_FUNC(bool, al_install_touch_input, (void)); AL_FUNC(void, al_uninstall_touch_input, (void)); AL_FUNC(void, al_get_touch_input_state, (ALLEGRO_TOUCH_INPUT_STATE *ret_state)); AL_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_touch_input_event_source, (void)); #if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC) AL_FUNC(void, al_set_mouse_emulation_mode, (int mode)); AL_FUNC(int, al_get_mouse_emulation_mode, (void)); AL_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_touch_input_mouse_emulation_event_source, (void)); #endif #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/transformations.h000066400000000000000000000056271473414355200222310ustar00rootroot00000000000000#ifndef __al_included_allegro5_transformations_h #define __al_included_allegro5_transformations_h #include "allegro5/display.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_TRANSFORM */ typedef struct ALLEGRO_TRANSFORM ALLEGRO_TRANSFORM; struct ALLEGRO_TRANSFORM { float m[4][4]; }; /* Transformations*/ AL_FUNC(void, al_use_transform, (const ALLEGRO_TRANSFORM* trans)); AL_FUNC(void, al_use_projection_transform, (const ALLEGRO_TRANSFORM* trans)); AL_FUNC(void, al_copy_transform, (ALLEGRO_TRANSFORM* dest, const ALLEGRO_TRANSFORM* src)); AL_FUNC(void, al_identity_transform, (ALLEGRO_TRANSFORM* trans)); AL_FUNC(void, al_build_transform, (ALLEGRO_TRANSFORM* trans, float x, float y, float sx, float sy, float theta)); AL_FUNC(void, al_build_camera_transform, (ALLEGRO_TRANSFORM *trans, float position_x, float position_y, float position_z, float look_x, float look_y, float look_z, float up_x, float up_y, float up_z)); AL_FUNC(void, al_translate_transform, (ALLEGRO_TRANSFORM* trans, float x, float y)); AL_FUNC(void, al_translate_transform_3d, (ALLEGRO_TRANSFORM *trans, float x, float y, float z)); AL_FUNC(void, al_rotate_transform, (ALLEGRO_TRANSFORM* trans, float theta)); AL_FUNC(void, al_rotate_transform_3d, (ALLEGRO_TRANSFORM *trans, float x, float y, float z, float angle)); AL_FUNC(void, al_scale_transform, (ALLEGRO_TRANSFORM* trans, float sx, float sy)); AL_FUNC(void, al_scale_transform_3d, (ALLEGRO_TRANSFORM *trans, float sx, float sy, float sz)); AL_FUNC(void, al_transform_coordinates, (const ALLEGRO_TRANSFORM* trans, float* x, float* y)); AL_FUNC(void, al_transform_coordinates_3d, (const ALLEGRO_TRANSFORM *trans, float *x, float *y, float *z)); AL_FUNC(void, al_transform_coordinates_4d, (const ALLEGRO_TRANSFORM *trans, float *x, float *y, float *z, float *w)); AL_FUNC(void, al_transform_coordinates_3d_projective, (const ALLEGRO_TRANSFORM *trans, float *x, float *y, float *z)); AL_FUNC(void, al_compose_transform, (ALLEGRO_TRANSFORM* trans, const ALLEGRO_TRANSFORM* other)); AL_FUNC(const ALLEGRO_TRANSFORM*, al_get_current_transform, (void)); AL_FUNC(const ALLEGRO_TRANSFORM*, al_get_current_inverse_transform, (void)); AL_FUNC(const ALLEGRO_TRANSFORM *, al_get_current_projection_transform, (void)); AL_FUNC(void, al_invert_transform, (ALLEGRO_TRANSFORM *trans)); AL_FUNC(void, al_transpose_transform, (ALLEGRO_TRANSFORM *trans)); AL_FUNC(int, al_check_inverse, (const ALLEGRO_TRANSFORM *trans, float tol)); AL_FUNC(void, al_orthographic_transform, (ALLEGRO_TRANSFORM *trans, float left, float top, float n, float right, float bottom, float f)); AL_FUNC(void, al_perspective_transform, (ALLEGRO_TRANSFORM *trans, float left, float top, float n, float right, float bottom, float f)); AL_FUNC(void, al_horizontal_shear_transform, (ALLEGRO_TRANSFORM *trans, float theta)); AL_FUNC(void, al_vertical_shear_transform, (ALLEGRO_TRANSFORM *trans, float theta)); #ifdef __cplusplus } #endif #endif allegro5-5.2.10.1/include/allegro5/utf8.h000066400000000000000000000140631473414355200176600ustar00rootroot00000000000000#ifndef __al_included_allegro5_utf8_h #define __al_included_allegro5_utf8_h #include "allegro5/base.h" #ifdef __cplusplus extern "C" { #endif /* Type: ALLEGRO_USTR */ typedef struct _al_tagbstring ALLEGRO_USTR; /* Type: ALLEGRO_USTR_INFO */ typedef struct _al_tagbstring ALLEGRO_USTR_INFO; #ifndef __al_tagbstring_defined #define __al_tagbstring_defined struct _al_tagbstring { int mlen; int slen; unsigned char * data; }; #endif /* Creating strings */ AL_FUNC(ALLEGRO_USTR *, al_ustr_new, (const char *s)); AL_FUNC(ALLEGRO_USTR *, al_ustr_new_from_buffer, (const char *s, size_t size)); AL_PRINTFUNC(ALLEGRO_USTR *, al_ustr_newf, (const char *fmt, ...), 1, 2); AL_FUNC(void, al_ustr_free, (ALLEGRO_USTR *us)); AL_FUNC(const char *, al_cstr, (const ALLEGRO_USTR *us)); AL_FUNC(void, al_ustr_to_buffer, (const ALLEGRO_USTR *us, char *buffer, int size)); AL_FUNC(char *, al_cstr_dup, (const ALLEGRO_USTR *us)); AL_FUNC(ALLEGRO_USTR *, al_ustr_dup, (const ALLEGRO_USTR *us)); AL_FUNC(ALLEGRO_USTR *, al_ustr_dup_substr, (const ALLEGRO_USTR *us, int start_pos, int end_pos)); /* Predefined string */ AL_FUNC(const ALLEGRO_USTR *, al_ustr_empty_string, (void)); /* Reference strings */ AL_FUNC(const ALLEGRO_USTR *, al_ref_cstr, (ALLEGRO_USTR_INFO *info, const char *s)); AL_FUNC(const ALLEGRO_USTR *, al_ref_buffer, (ALLEGRO_USTR_INFO *info, const char *s, size_t size)); AL_FUNC(const ALLEGRO_USTR *, al_ref_ustr, (ALLEGRO_USTR_INFO *info, const ALLEGRO_USTR *us, int start_pos, int end_pos)); AL_FUNC(const ALLEGRO_USTR *, al_ref_info, (const ALLEGRO_USTR_INFO *info)); /* Sizes and offsets */ AL_FUNC(size_t, al_ustr_size, (const ALLEGRO_USTR *us)); AL_FUNC(size_t, al_ustr_length, (const ALLEGRO_USTR *us)); AL_FUNC(int, al_ustr_offset, (const ALLEGRO_USTR *us, int index)); AL_FUNC(bool, al_ustr_next, (const ALLEGRO_USTR *us, int *pos)); AL_FUNC(bool, al_ustr_prev, (const ALLEGRO_USTR *us, int *pos)); /* Get codepoints */ AL_FUNC(int32_t, al_ustr_get, (const ALLEGRO_USTR *us, int pos)); AL_FUNC(int32_t, al_ustr_get_next, (const ALLEGRO_USTR *us, int *pos)); AL_FUNC(int32_t, al_ustr_prev_get, (const ALLEGRO_USTR *us, int *pos)); /* Insert */ AL_FUNC(bool, al_ustr_insert, (ALLEGRO_USTR *us1, int pos, const ALLEGRO_USTR *us2)); AL_FUNC(bool, al_ustr_insert_cstr, (ALLEGRO_USTR *us, int pos, const char *us2)); AL_FUNC(size_t, al_ustr_insert_chr, (ALLEGRO_USTR *us, int pos, int32_t c)); /* Append */ AL_FUNC(bool, al_ustr_append, (ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2)); AL_FUNC(bool, al_ustr_append_cstr, (ALLEGRO_USTR *us, const char *s)); AL_FUNC(size_t, al_ustr_append_chr, (ALLEGRO_USTR *us, int32_t c)); AL_PRINTFUNC(bool, al_ustr_appendf, (ALLEGRO_USTR *us, const char *fmt, ...), 2, 3); AL_FUNC(bool, al_ustr_vappendf, (ALLEGRO_USTR *us, const char *fmt, va_list ap)); /* Remove */ AL_FUNC(bool, al_ustr_remove_chr, (ALLEGRO_USTR *us, int pos)); AL_FUNC(bool, al_ustr_remove_range, (ALLEGRO_USTR *us, int start_pos, int end_pos)); AL_FUNC(bool, al_ustr_truncate, (ALLEGRO_USTR *us, int start_pos)); AL_FUNC(bool, al_ustr_ltrim_ws, (ALLEGRO_USTR *us)); AL_FUNC(bool, al_ustr_rtrim_ws, (ALLEGRO_USTR *us)); AL_FUNC(bool, al_ustr_trim_ws, (ALLEGRO_USTR *us)); /* Assign */ AL_FUNC(bool, al_ustr_assign, (ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2)); AL_FUNC(bool, al_ustr_assign_substr, (ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2, int start_pos, int end_pos)); AL_FUNC(bool, al_ustr_assign_cstr, (ALLEGRO_USTR *us1, const char *s)); /* Replace */ AL_FUNC(size_t, al_ustr_set_chr, (ALLEGRO_USTR *us, int pos, int32_t c)); AL_FUNC(bool, al_ustr_replace_range, (ALLEGRO_USTR *us1, int start_pos1, int end_pos1, const ALLEGRO_USTR *us2)); /* Searching */ AL_FUNC(int, al_ustr_find_chr, (const ALLEGRO_USTR *us, int start_pos, int32_t c)); AL_FUNC(int, al_ustr_rfind_chr, (const ALLEGRO_USTR *us, int start_pos, int32_t c)); AL_FUNC(int, al_ustr_find_set, (const ALLEGRO_USTR *us, int start_pos, const ALLEGRO_USTR *accept)); AL_FUNC(int, al_ustr_find_set_cstr, (const ALLEGRO_USTR *us, int start_pos, const char *accept)); AL_FUNC(int, al_ustr_find_cset, (const ALLEGRO_USTR *us, int start_pos, const ALLEGRO_USTR *reject)); AL_FUNC(int, al_ustr_find_cset_cstr, (const ALLEGRO_USTR *us, int start_pos, const char *reject)); AL_FUNC(int, al_ustr_find_str, (const ALLEGRO_USTR *haystack, int start_pos, const ALLEGRO_USTR *needle)); AL_FUNC(int, al_ustr_find_cstr, (const ALLEGRO_USTR *haystack, int start_pos, const char *needle)); AL_FUNC(int, al_ustr_rfind_str, (const ALLEGRO_USTR *haystack, int start_pos, const ALLEGRO_USTR *needle)); AL_FUNC(int, al_ustr_rfind_cstr, (const ALLEGRO_USTR *haystack, int start_pos, const char *needle)); AL_FUNC(bool, al_ustr_find_replace, (ALLEGRO_USTR *us, int start_pos, const ALLEGRO_USTR *find, const ALLEGRO_USTR *replace)); AL_FUNC(bool, al_ustr_find_replace_cstr, (ALLEGRO_USTR *us, int start_pos, const char *find, const char *replace)); /* Compare */ AL_FUNC(bool, al_ustr_equal, (const ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2)); AL_FUNC(int, al_ustr_compare, (const ALLEGRO_USTR *u, const ALLEGRO_USTR *v)); AL_FUNC(int, al_ustr_ncompare, (const ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2, int n)); AL_FUNC(bool, al_ustr_has_prefix,(const ALLEGRO_USTR *u, const ALLEGRO_USTR *v)); AL_FUNC(bool, al_ustr_has_prefix_cstr, (const ALLEGRO_USTR *u, const char *s)); AL_FUNC(bool, al_ustr_has_suffix,(const ALLEGRO_USTR *u, const ALLEGRO_USTR *v)); AL_FUNC(bool, al_ustr_has_suffix_cstr,(const ALLEGRO_USTR *us1, const char *s)); /* Low level UTF-8 functions */ AL_FUNC(size_t, al_utf8_width, (int32_t c)); AL_FUNC(size_t, al_utf8_encode, (char s[], int32_t c)); /* UTF-16 */ AL_FUNC(ALLEGRO_USTR *, al_ustr_new_from_utf16, (uint16_t const *s)); AL_FUNC(size_t, al_ustr_size_utf16, (const ALLEGRO_USTR *us)); AL_FUNC(size_t, al_ustr_encode_utf16, (const ALLEGRO_USTR *us, uint16_t *s, size_t n)); AL_FUNC(size_t, al_utf16_width, (int c)); AL_FUNC(size_t, al_utf16_encode, (uint16_t s[], int32_t c)); #ifdef __cplusplus } #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/indent.pro000066400000000000000000000001461473414355200154640ustar00rootroot00000000000000-kr -nce -ss -ncs -i3 -cli3 -nut -bls -l80 -T ALLEGRO_BITMAP -T PACKFILE -T BMPINFOHEADER -T PalEntry allegro5-5.2.10.1/misc/000077500000000000000000000000001473414355200144135ustar00rootroot00000000000000allegro5-5.2.10.1/misc/Allegro5_iOS/000077500000000000000000000000001473414355200166375ustar00rootroot00000000000000allegro5-5.2.10.1/misc/Allegro5_iOS/Allegro5_iOS.xcodeproj/000077500000000000000000000000001473414355200230575ustar00rootroot00000000000000allegro5-5.2.10.1/misc/Allegro5_iOS/Allegro5_iOS.xcodeproj/project.pbxproj000066400000000000000000001554621473414355200261500ustar00rootroot00000000000000// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 968608761B6B12960008BD29 /* dds.c in Sources */ = {isa = PBXBuildFile; fileRef = 968608751B6B12960008BD29 /* dds.c */; }; 96A12D031D2F3C3E00F245D9 /* png.c in Sources */ = {isa = PBXBuildFile; fileRef = 96A12D021D2F3C3E00F245D9 /* png.c */; }; 96A12D051D2F3F9300F245D9 /* identify.c in Sources */ = {isa = PBXBuildFile; fileRef = 96A12D041D2F3F9300F245D9 /* identify.c */; }; 96A3016E1B9A874F002E2D1C /* clipboard.c in Sources */ = {isa = PBXBuildFile; fileRef = 96A3016D1B9A874F002E2D1C /* clipboard.c */; }; 96A301701B9A8778002E2D1C /* iphone_clipboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A3016F1B9A8778002E2D1C /* iphone_clipboard.m */; }; 96CE34EB1B6B059C00705360 /* allegro.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34BB1B6B059C00705360 /* allegro.c */; }; 96CE34EC1B6B059C00705360 /* bitmap_draw.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34BC1B6B059C00705360 /* bitmap_draw.c */; }; 96CE34ED1B6B059C00705360 /* bitmap_io.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34BD1B6B059C00705360 /* bitmap_io.c */; }; 96CE34EE1B6B059C00705360 /* bitmap_lock.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34BE1B6B059C00705360 /* bitmap_lock.c */; }; 96CE34EF1B6B059C00705360 /* bitmap_pixel.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34BF1B6B059C00705360 /* bitmap_pixel.c */; }; 96CE34F01B6B059C00705360 /* bitmap_type.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34C01B6B059C00705360 /* bitmap_type.c */; }; 96CE34F11B6B059C00705360 /* bitmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34C11B6B059C00705360 /* bitmap.c */; }; 96CE34F21B6B059C00705360 /* blenders.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34C21B6B059C00705360 /* blenders.c */; }; 96CE34F31B6B059C00705360 /* config.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34C31B6B059C00705360 /* config.c */; }; 96CE34F41B6B059C00705360 /* convert.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34C41B6B059C00705360 /* convert.c */; }; 96CE34F51B6B059C00705360 /* debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34C51B6B059C00705360 /* debug.c */; }; 96CE34F61B6B059C00705360 /* display_settings.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34C61B6B059C00705360 /* display_settings.c */; }; 96CE34F71B6B059C00705360 /* display.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34C71B6B059C00705360 /* display.c */; }; 96CE34F81B6B059C00705360 /* drawing.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34C81B6B059C00705360 /* drawing.c */; }; 96CE34F91B6B059C00705360 /* dtor.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34C91B6B059C00705360 /* dtor.c */; }; 96CE34FA1B6B059C00705360 /* events.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34CA1B6B059C00705360 /* events.c */; }; 96CE34FB1B6B059C00705360 /* evtsrc.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34CB1B6B059C00705360 /* evtsrc.c */; }; 96CE34FC1B6B059C00705360 /* exitfunc.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34CC1B6B059C00705360 /* exitfunc.c */; }; 96CE34FD1B6B059C00705360 /* file_slice.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34CD1B6B059C00705360 /* file_slice.c */; }; 96CE34FE1B6B059C00705360 /* file_stdio.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34CE1B6B059C00705360 /* file_stdio.c */; }; 96CE34FF1B6B059C00705360 /* file.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34CF1B6B059C00705360 /* file.c */; }; 96CE35001B6B059C00705360 /* fshook_stdio.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34D01B6B059C00705360 /* fshook_stdio.c */; }; 96CE35011B6B059C00705360 /* fshook.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34D11B6B059C00705360 /* fshook.c */; }; 96CE35021B6B059C00705360 /* fullscreen_mode.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34D21B6B059C00705360 /* fullscreen_mode.c */; }; 96CE35031B6B059C00705360 /* haptic.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34D31B6B059C00705360 /* haptic.c */; }; 96CE35041B6B059C00705360 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34D41B6B059C00705360 /* inline.c */; }; 96CE35051B6B059C00705360 /* joynu.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34D51B6B059C00705360 /* joynu.c */; }; 96CE35061B6B059C00705360 /* keybdnu.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34D61B6B059C00705360 /* keybdnu.c */; }; 96CE35071B6B059C00705360 /* libc.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34D71B6B059C00705360 /* libc.c */; }; 96CE35081B6B059C00705360 /* math.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34D81B6B059C00705360 /* math.c */; }; 96CE35091B6B059C00705360 /* memblit.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34D91B6B059C00705360 /* memblit.c */; }; 96CE350A1B6B059C00705360 /* memdraw.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34DA1B6B059C00705360 /* memdraw.c */; }; 96CE350B1B6B059C00705360 /* memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34DB1B6B059C00705360 /* memory.c */; }; 96CE350C1B6B059C00705360 /* monitor.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34DC1B6B059C00705360 /* monitor.c */; }; 96CE350D1B6B059C00705360 /* mouse_cursor.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34DD1B6B059C00705360 /* mouse_cursor.c */; }; 96CE350E1B6B059C00705360 /* mousenu.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34DE1B6B059C00705360 /* mousenu.c */; }; 96CE350F1B6B059C00705360 /* path.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34DF1B6B059C00705360 /* path.c */; }; 96CE35101B6B059C00705360 /* pixels.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34E01B6B059C00705360 /* pixels.c */; }; 96CE35111B6B059C00705360 /* shader.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34E11B6B059C00705360 /* shader.c */; }; 96CE35121B6B059C00705360 /* system.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34E21B6B059C00705360 /* system.c */; }; 96CE35131B6B059C00705360 /* threads.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34E31B6B059C00705360 /* threads.c */; }; 96CE35141B6B059C00705360 /* timernu.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34E41B6B059C00705360 /* timernu.c */; }; 96CE35151B6B059C00705360 /* tls_dll.inc in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34E51B6B059C00705360 /* tls_dll.inc */; }; 96CE35161B6B059C00705360 /* tls.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34E61B6B059C00705360 /* tls.c */; }; 96CE35171B6B059C00705360 /* touch_input.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34E71B6B059C00705360 /* touch_input.c */; }; 96CE35181B6B059C00705360 /* transformations.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34E81B6B059C00705360 /* transformations.c */; }; 96CE35191B6B059C00705360 /* tri_soft.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34E91B6B059C00705360 /* tri_soft.c */; }; 96CE351A1B6B059C00705360 /* utf8.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE34EA1B6B059C00705360 /* utf8.c */; }; 96CE351D1B6B05D100705360 /* utime.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE351B1B6B05D100705360 /* utime.c */; }; 96CE351E1B6B05D100705360 /* uxthread.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE351C1B6B05D100705360 /* uxthread.c */; }; 96CE35281B6B05F900705360 /* extensions.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE351F1B6B05F900705360 /* extensions.c */; }; 96CE35291B6B05F900705360 /* ogl_bitmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35201B6B05F900705360 /* ogl_bitmap.c */; }; 96CE352A1B6B05F900705360 /* ogl_display.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35211B6B05F900705360 /* ogl_display.c */; }; 96CE352B1B6B05F900705360 /* ogl_draw.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35221B6B05F900705360 /* ogl_draw.c */; }; 96CE352C1B6B05F900705360 /* ogl_fbo.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35231B6B05F900705360 /* ogl_fbo.c */; }; 96CE352D1B6B05F900705360 /* ogl_lock_es.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35241B6B05F900705360 /* ogl_lock_es.c */; }; 96CE352E1B6B05F900705360 /* ogl_lock.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35251B6B05F900705360 /* ogl_lock.c */; }; 96CE352F1B6B05F900705360 /* ogl_render_state.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35261B6B05F900705360 /* ogl_render_state.c */; }; 96CE35301B6B05F900705360 /* ogl_shader.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35271B6B05F900705360 /* ogl_shader.c */; }; 96CE35361B6B061200705360 /* aatree.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35311B6B061200705360 /* aatree.c */; }; 96CE35371B6B061200705360 /* bstrlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35321B6B061200705360 /* bstrlib.c */; }; 96CE35381B6B061200705360 /* list.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35341B6B061200705360 /* list.c */; }; 96CE35391B6B061200705360 /* vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35351B6B061200705360 /* vector.c */; }; 96CE35451B6B063800705360 /* allegroAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CE353A1B6B063800705360 /* allegroAppDelegate.m */; }; 96CE35461B6B063800705360 /* EAGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CE353B1B6B063800705360 /* EAGLView.m */; }; 96CE35471B6B063800705360 /* iphone_display.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CE353C1B6B063800705360 /* iphone_display.m */; }; 96CE35481B6B063800705360 /* iphone_joystick.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CE353D1B6B063800705360 /* iphone_joystick.m */; }; 96CE35491B6B063800705360 /* iphone_keyboard.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE353E1B6B063800705360 /* iphone_keyboard.c */; }; 96CE354A1B6B063800705360 /* iphone_main.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CE353F1B6B063800705360 /* iphone_main.m */; }; 96CE354B1B6B063800705360 /* iphone_mouse.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35401B6B063800705360 /* iphone_mouse.m */; }; 96CE354C1B6B063800705360 /* iphone_path.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35411B6B063800705360 /* iphone_path.m */; }; 96CE354D1B6B063800705360 /* iphone_system.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35421B6B063800705360 /* iphone_system.c */; }; 96CE354E1B6B063800705360 /* iphone_touch_input.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35431B6B063800705360 /* iphone_touch_input.m */; }; 96CE354F1B6B063800705360 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35441B6B063800705360 /* ViewController.m */; }; 96CE35511B6B064F00705360 /* color.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35501B6B064F00705360 /* color.c */; }; 96CE35561B6B066100705360 /* font.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35521B6B066100705360 /* font.c */; }; 96CE35571B6B066100705360 /* fontbmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35531B6B066100705360 /* fontbmp.c */; }; 96CE35581B6B066100705360 /* stdfont.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35541B6B066100705360 /* stdfont.c */; }; 96CE35591B6B066100705360 /* text.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35551B6B066100705360 /* text.c */; }; 96CE355F1B6B068800705360 /* bmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE355A1B6B068800705360 /* bmp.c */; }; 96CE35601B6B068800705360 /* iio.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE355B1B6B068800705360 /* iio.c */; }; 96CE35621B6B068800705360 /* pcx.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE355D1B6B068800705360 /* pcx.c */; }; 96CE35631B6B068800705360 /* tga.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE355E1B6B068800705360 /* tga.c */; }; 96CE35651B6B069700705360 /* generic_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35641B6B069700705360 /* generic_main.c */; }; 96CE35671B6B06A400705360 /* memfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35661B6B06A400705360 /* memfile.c */; }; 96CE356A1B6B06C400705360 /* a5_physfs_dir.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35681B6B06C400705360 /* a5_physfs_dir.c */; }; 96CE356B1B6B06C400705360 /* a5_physfs.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35691B6B06C400705360 /* a5_physfs.c */; }; 96CE35791B6B06EF00705360 /* directx_shaders.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96CE356C1B6B06EF00705360 /* directx_shaders.cpp */; }; 96CE357A1B6B06EF00705360 /* high_primitives.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE356D1B6B06EF00705360 /* high_primitives.c */; }; 96CE357B1B6B06EF00705360 /* line_soft.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE356E1B6B06EF00705360 /* line_soft.c */; }; 96CE357D1B6B06EF00705360 /* point_soft.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35701B6B06EF00705360 /* point_soft.c */; }; 96CE357E1B6B06EF00705360 /* polygon.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35711B6B06EF00705360 /* polygon.c */; }; 96CE357F1B6B06EF00705360 /* polyline.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35721B6B06EF00705360 /* polyline.c */; }; 96CE35801B6B06EF00705360 /* prim_directx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35731B6B06EF00705360 /* prim_directx.cpp */; }; 96CE35811B6B06EF00705360 /* prim_opengl.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35741B6B06EF00705360 /* prim_opengl.c */; }; 96CE35821B6B06EF00705360 /* prim_soft.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35751B6B06EF00705360 /* prim_soft.c */; }; 96CE35831B6B06EF00705360 /* prim_util.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35761B6B06EF00705360 /* prim_util.c */; }; 96CE35841B6B06EF00705360 /* primitives.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35771B6B06EF00705360 /* primitives.c */; }; 96CE35851B6B06EF00705360 /* triangulator.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35781B6B06EF00705360 /* triangulator.c */; }; 96CE35871B6B070300705360 /* ttf.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CE35861B6B070300705360 /* ttf.c */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ 964130ED1A6353E700184496 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = "include/$(PRODUCT_NAME)"; dstSubfolderSpec = 16; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 964130EF1A6353E700184496 /* libAllegro5_iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAllegro5_iOS.a; sourceTree = BUILT_PRODUCTS_DIR; }; 968608751B6B12960008BD29 /* dds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dds.c; path = ../../addons/image/dds.c; sourceTree = ""; }; 96A12D021D2F3C3E00F245D9 /* png.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = png.c; path = ../../addons/image/png.c; sourceTree = ""; }; 96A12D041D2F3F9300F245D9 /* identify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = identify.c; path = ../../addons/image/identify.c; sourceTree = ""; }; 96A3016D1B9A874F002E2D1C /* clipboard.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = clipboard.c; path = ../../src/clipboard.c; sourceTree = ""; }; 96A3016F1B9A8778002E2D1C /* iphone_clipboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = iphone_clipboard.m; path = ../../src/iphone/iphone_clipboard.m; sourceTree = ""; }; 96CE34BB1B6B059C00705360 /* allegro.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = allegro.c; path = ../../src/allegro.c; sourceTree = ""; }; 96CE34BC1B6B059C00705360 /* bitmap_draw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bitmap_draw.c; path = ../../src/bitmap_draw.c; sourceTree = ""; }; 96CE34BD1B6B059C00705360 /* bitmap_io.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bitmap_io.c; path = ../../src/bitmap_io.c; sourceTree = ""; }; 96CE34BE1B6B059C00705360 /* bitmap_lock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bitmap_lock.c; path = ../../src/bitmap_lock.c; sourceTree = ""; }; 96CE34BF1B6B059C00705360 /* bitmap_pixel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bitmap_pixel.c; path = ../../src/bitmap_pixel.c; sourceTree = ""; }; 96CE34C01B6B059C00705360 /* bitmap_type.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bitmap_type.c; path = ../../src/bitmap_type.c; sourceTree = ""; }; 96CE34C11B6B059C00705360 /* bitmap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bitmap.c; path = ../../src/bitmap.c; sourceTree = ""; }; 96CE34C21B6B059C00705360 /* blenders.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = blenders.c; path = ../../src/blenders.c; sourceTree = ""; }; 96CE34C31B6B059C00705360 /* config.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = config.c; path = ../../src/config.c; sourceTree = ""; }; 96CE34C41B6B059C00705360 /* convert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = convert.c; path = ../../src/convert.c; sourceTree = ""; }; 96CE34C51B6B059C00705360 /* debug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = debug.c; path = ../../src/debug.c; sourceTree = ""; }; 96CE34C61B6B059C00705360 /* display_settings.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = display_settings.c; path = ../../src/display_settings.c; sourceTree = ""; }; 96CE34C71B6B059C00705360 /* display.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = display.c; path = ../../src/display.c; sourceTree = ""; }; 96CE34C81B6B059C00705360 /* drawing.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = drawing.c; path = ../../src/drawing.c; sourceTree = ""; }; 96CE34C91B6B059C00705360 /* dtor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dtor.c; path = ../../src/dtor.c; sourceTree = ""; }; 96CE34CA1B6B059C00705360 /* events.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = events.c; path = ../../src/events.c; sourceTree = ""; }; 96CE34CB1B6B059C00705360 /* evtsrc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = evtsrc.c; path = ../../src/evtsrc.c; sourceTree = ""; }; 96CE34CC1B6B059C00705360 /* exitfunc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = exitfunc.c; path = ../../src/exitfunc.c; sourceTree = ""; }; 96CE34CD1B6B059C00705360 /* file_slice.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = file_slice.c; path = ../../src/file_slice.c; sourceTree = ""; }; 96CE34CE1B6B059C00705360 /* file_stdio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = file_stdio.c; path = ../../src/file_stdio.c; sourceTree = ""; }; 96CE34CF1B6B059C00705360 /* file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = file.c; path = ../../src/file.c; sourceTree = ""; }; 96CE34D01B6B059C00705360 /* fshook_stdio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fshook_stdio.c; path = ../../src/fshook_stdio.c; sourceTree = ""; }; 96CE34D11B6B059C00705360 /* fshook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fshook.c; path = ../../src/fshook.c; sourceTree = ""; }; 96CE34D21B6B059C00705360 /* fullscreen_mode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fullscreen_mode.c; path = ../../src/fullscreen_mode.c; sourceTree = ""; }; 96CE34D31B6B059C00705360 /* haptic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = haptic.c; path = ../../src/haptic.c; sourceTree = ""; }; 96CE34D41B6B059C00705360 /* inline.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = inline.c; path = ../../src/inline.c; sourceTree = ""; }; 96CE34D51B6B059C00705360 /* joynu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = joynu.c; path = ../../src/joynu.c; sourceTree = ""; }; 96CE34D61B6B059C00705360 /* keybdnu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = keybdnu.c; path = ../../src/keybdnu.c; sourceTree = ""; }; 96CE34D71B6B059C00705360 /* libc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = libc.c; path = ../../src/libc.c; sourceTree = ""; }; 96CE34D81B6B059C00705360 /* math.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = math.c; path = ../../src/math.c; sourceTree = ""; }; 96CE34D91B6B059C00705360 /* memblit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memblit.c; path = ../../src/memblit.c; sourceTree = ""; }; 96CE34DA1B6B059C00705360 /* memdraw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memdraw.c; path = ../../src/memdraw.c; sourceTree = ""; }; 96CE34DB1B6B059C00705360 /* memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memory.c; path = ../../src/memory.c; sourceTree = ""; }; 96CE34DC1B6B059C00705360 /* monitor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = monitor.c; path = ../../src/monitor.c; sourceTree = ""; }; 96CE34DD1B6B059C00705360 /* mouse_cursor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mouse_cursor.c; path = ../../src/mouse_cursor.c; sourceTree = ""; }; 96CE34DE1B6B059C00705360 /* mousenu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mousenu.c; path = ../../src/mousenu.c; sourceTree = ""; }; 96CE34DF1B6B059C00705360 /* path.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = path.c; path = ../../src/path.c; sourceTree = ""; }; 96CE34E01B6B059C00705360 /* pixels.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pixels.c; path = ../../src/pixels.c; sourceTree = ""; }; 96CE34E11B6B059C00705360 /* shader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = shader.c; path = ../../src/shader.c; sourceTree = ""; }; 96CE34E21B6B059C00705360 /* system.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = system.c; path = ../../src/system.c; sourceTree = ""; }; 96CE34E31B6B059C00705360 /* threads.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = threads.c; path = ../../src/threads.c; sourceTree = ""; }; 96CE34E41B6B059C00705360 /* timernu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = timernu.c; path = ../../src/timernu.c; sourceTree = ""; }; 96CE34E51B6B059C00705360 /* tls_dll.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = tls_dll.inc; path = ../../src/tls_dll.inc; sourceTree = ""; }; 96CE34E61B6B059C00705360 /* tls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tls.c; path = ../../src/tls.c; sourceTree = ""; }; 96CE34E71B6B059C00705360 /* touch_input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = touch_input.c; path = ../../src/touch_input.c; sourceTree = ""; }; 96CE34E81B6B059C00705360 /* transformations.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = transformations.c; path = ../../src/transformations.c; sourceTree = ""; }; 96CE34E91B6B059C00705360 /* tri_soft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tri_soft.c; path = ../../src/tri_soft.c; sourceTree = ""; }; 96CE34EA1B6B059C00705360 /* utf8.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utf8.c; path = ../../src/utf8.c; sourceTree = ""; }; 96CE351B1B6B05D100705360 /* utime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utime.c; path = ../../src/unix/utime.c; sourceTree = ""; }; 96CE351C1B6B05D100705360 /* uxthread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uxthread.c; path = ../../src/unix/uxthread.c; sourceTree = ""; }; 96CE351F1B6B05F900705360 /* extensions.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = extensions.c; path = ../../src/opengl/extensions.c; sourceTree = ""; }; 96CE35201B6B05F900705360 /* ogl_bitmap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ogl_bitmap.c; path = ../../src/opengl/ogl_bitmap.c; sourceTree = ""; }; 96CE35211B6B05F900705360 /* ogl_display.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ogl_display.c; path = ../../src/opengl/ogl_display.c; sourceTree = ""; }; 96CE35221B6B05F900705360 /* ogl_draw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ogl_draw.c; path = ../../src/opengl/ogl_draw.c; sourceTree = ""; }; 96CE35231B6B05F900705360 /* ogl_fbo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ogl_fbo.c; path = ../../src/opengl/ogl_fbo.c; sourceTree = ""; }; 96CE35241B6B05F900705360 /* ogl_lock_es.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ogl_lock_es.c; path = ../../src/opengl/ogl_lock_es.c; sourceTree = ""; }; 96CE35251B6B05F900705360 /* ogl_lock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ogl_lock.c; path = ../../src/opengl/ogl_lock.c; sourceTree = ""; }; 96CE35261B6B05F900705360 /* ogl_render_state.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ogl_render_state.c; path = ../../src/opengl/ogl_render_state.c; sourceTree = ""; }; 96CE35271B6B05F900705360 /* ogl_shader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ogl_shader.c; path = ../../src/opengl/ogl_shader.c; sourceTree = ""; }; 96CE35311B6B061200705360 /* aatree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = aatree.c; path = ../../src/misc/aatree.c; sourceTree = ""; }; 96CE35321B6B061200705360 /* bstrlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bstrlib.c; path = ../../src/misc/bstrlib.c; sourceTree = ""; }; 96CE35331B6B061200705360 /* bstrlib.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = bstrlib.txt; path = ../../src/misc/bstrlib.txt; sourceTree = ""; }; 96CE35341B6B061200705360 /* list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = list.c; path = ../../src/misc/list.c; sourceTree = ""; }; 96CE35351B6B061200705360 /* vector.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vector.c; path = ../../src/misc/vector.c; sourceTree = ""; }; 96CE353A1B6B063800705360 /* allegroAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = allegroAppDelegate.m; path = ../../src/iphone/allegroAppDelegate.m; sourceTree = ""; }; 96CE353B1B6B063800705360 /* EAGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EAGLView.m; path = ../../src/iphone/EAGLView.m; sourceTree = ""; }; 96CE353C1B6B063800705360 /* iphone_display.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = iphone_display.m; path = ../../src/iphone/iphone_display.m; sourceTree = ""; }; 96CE353D1B6B063800705360 /* iphone_joystick.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = iphone_joystick.m; path = ../../src/iphone/iphone_joystick.m; sourceTree = ""; }; 96CE353E1B6B063800705360 /* iphone_keyboard.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iphone_keyboard.c; path = ../../src/iphone/iphone_keyboard.c; sourceTree = ""; }; 96CE353F1B6B063800705360 /* iphone_main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = iphone_main.m; path = ../../src/iphone/iphone_main.m; sourceTree = ""; }; 96CE35401B6B063800705360 /* iphone_mouse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = iphone_mouse.m; path = ../../src/iphone/iphone_mouse.m; sourceTree = ""; }; 96CE35411B6B063800705360 /* iphone_path.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = iphone_path.m; path = ../../src/iphone/iphone_path.m; sourceTree = ""; }; 96CE35421B6B063800705360 /* iphone_system.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iphone_system.c; path = ../../src/iphone/iphone_system.c; sourceTree = ""; }; 96CE35431B6B063800705360 /* iphone_touch_input.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = iphone_touch_input.m; path = ../../src/iphone/iphone_touch_input.m; sourceTree = ""; }; 96CE35441B6B063800705360 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ViewController.m; path = ../../src/iphone/ViewController.m; sourceTree = ""; }; 96CE35501B6B064F00705360 /* color.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = color.c; path = ../../addons/color/color.c; sourceTree = ""; }; 96CE35521B6B066100705360 /* font.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = font.c; path = ../../addons/font/font.c; sourceTree = ""; }; 96CE35531B6B066100705360 /* fontbmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fontbmp.c; path = ../../addons/font/fontbmp.c; sourceTree = ""; }; 96CE35541B6B066100705360 /* stdfont.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stdfont.c; path = ../../addons/font/stdfont.c; sourceTree = ""; }; 96CE35551B6B066100705360 /* text.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = text.c; path = ../../addons/font/text.c; sourceTree = ""; }; 96CE355A1B6B068800705360 /* bmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bmp.c; path = ../../addons/image/bmp.c; sourceTree = ""; }; 96CE355B1B6B068800705360 /* iio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iio.c; path = ../../addons/image/iio.c; sourceTree = ""; }; 96CE355D1B6B068800705360 /* pcx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pcx.c; path = ../../addons/image/pcx.c; sourceTree = ""; }; 96CE355E1B6B068800705360 /* tga.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tga.c; path = ../../addons/image/tga.c; sourceTree = ""; }; 96CE35641B6B069700705360 /* generic_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = generic_main.c; path = ../../addons/main/generic_main.c; sourceTree = ""; }; 96CE35661B6B06A400705360 /* memfile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memfile.c; path = ../../addons/memfile/memfile.c; sourceTree = ""; }; 96CE35681B6B06C400705360 /* a5_physfs_dir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = a5_physfs_dir.c; path = ../../addons/physfs/a5_physfs_dir.c; sourceTree = ""; }; 96CE35691B6B06C400705360 /* a5_physfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = a5_physfs.c; path = ../../addons/physfs/a5_physfs.c; sourceTree = ""; }; 96CE356C1B6B06EF00705360 /* directx_shaders.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = directx_shaders.cpp; path = ../../addons/primitives/directx_shaders.cpp; sourceTree = ""; }; 96CE356D1B6B06EF00705360 /* high_primitives.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = high_primitives.c; path = ../../addons/primitives/high_primitives.c; sourceTree = ""; }; 96CE356E1B6B06EF00705360 /* line_soft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = line_soft.c; path = ../../addons/primitives/line_soft.c; sourceTree = ""; }; 96CE35701B6B06EF00705360 /* point_soft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = point_soft.c; path = ../../addons/primitives/point_soft.c; sourceTree = ""; }; 96CE35711B6B06EF00705360 /* polygon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = polygon.c; path = ../../addons/primitives/polygon.c; sourceTree = ""; }; 96CE35721B6B06EF00705360 /* polyline.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = polyline.c; path = ../../addons/primitives/polyline.c; sourceTree = ""; }; 96CE35731B6B06EF00705360 /* prim_directx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = prim_directx.cpp; path = ../../addons/primitives/prim_directx.cpp; sourceTree = ""; }; 96CE35741B6B06EF00705360 /* prim_opengl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = prim_opengl.c; path = ../../addons/primitives/prim_opengl.c; sourceTree = ""; }; 96CE35751B6B06EF00705360 /* prim_soft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = prim_soft.c; path = ../../addons/primitives/prim_soft.c; sourceTree = ""; }; 96CE35761B6B06EF00705360 /* prim_util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = prim_util.c; path = ../../addons/primitives/prim_util.c; sourceTree = ""; }; 96CE35771B6B06EF00705360 /* primitives.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = primitives.c; path = ../../addons/primitives/primitives.c; sourceTree = ""; }; 96CE35781B6B06EF00705360 /* triangulator.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = triangulator.c; path = ../../addons/primitives/triangulator.c; sourceTree = ""; }; 96CE35861B6B070300705360 /* ttf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ttf.c; path = ../../addons/ttf/ttf.c; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 964130EC1A6353E700184496 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 964130E61A6353E700184496 = { isa = PBXGroup; children = ( 96CE35861B6B070300705360 /* ttf.c */, 96CE34BA1B6B055300705360 /* src */, 964130F01A6353E700184496 /* Products */, ); sourceTree = ""; }; 964130F01A6353E700184496 /* Products */ = { isa = PBXGroup; children = ( 964130EF1A6353E700184496 /* libAllegro5_iOS.a */, ); name = Products; sourceTree = ""; }; 96CE34BA1B6B055300705360 /* src */ = { isa = PBXGroup; children = ( 96A12D041D2F3F9300F245D9 /* identify.c */, 96A12D021D2F3C3E00F245D9 /* png.c */, 96A3016F1B9A8778002E2D1C /* iphone_clipboard.m */, 96A3016D1B9A874F002E2D1C /* clipboard.c */, 96CE356C1B6B06EF00705360 /* directx_shaders.cpp */, 96CE356D1B6B06EF00705360 /* high_primitives.c */, 96CE356E1B6B06EF00705360 /* line_soft.c */, 96CE35701B6B06EF00705360 /* point_soft.c */, 96CE35711B6B06EF00705360 /* polygon.c */, 96CE35721B6B06EF00705360 /* polyline.c */, 96CE35731B6B06EF00705360 /* prim_directx.cpp */, 96CE35741B6B06EF00705360 /* prim_opengl.c */, 96CE35751B6B06EF00705360 /* prim_soft.c */, 96CE35761B6B06EF00705360 /* prim_util.c */, 96CE35771B6B06EF00705360 /* primitives.c */, 96CE35781B6B06EF00705360 /* triangulator.c */, 96CE35681B6B06C400705360 /* a5_physfs_dir.c */, 96CE35691B6B06C400705360 /* a5_physfs.c */, 96CE35661B6B06A400705360 /* memfile.c */, 96CE35641B6B069700705360 /* generic_main.c */, 96CE355A1B6B068800705360 /* bmp.c */, 96CE355B1B6B068800705360 /* iio.c */, 96CE355D1B6B068800705360 /* pcx.c */, 96CE355E1B6B068800705360 /* tga.c */, 968608751B6B12960008BD29 /* dds.c */, 96CE35521B6B066100705360 /* font.c */, 96CE35531B6B066100705360 /* fontbmp.c */, 96CE35541B6B066100705360 /* stdfont.c */, 96CE35551B6B066100705360 /* text.c */, 96CE35501B6B064F00705360 /* color.c */, 96CE353A1B6B063800705360 /* allegroAppDelegate.m */, 96CE353B1B6B063800705360 /* EAGLView.m */, 96CE353C1B6B063800705360 /* iphone_display.m */, 96CE353D1B6B063800705360 /* iphone_joystick.m */, 96CE353E1B6B063800705360 /* iphone_keyboard.c */, 96CE353F1B6B063800705360 /* iphone_main.m */, 96CE35401B6B063800705360 /* iphone_mouse.m */, 96CE35411B6B063800705360 /* iphone_path.m */, 96CE35421B6B063800705360 /* iphone_system.c */, 96CE35431B6B063800705360 /* iphone_touch_input.m */, 96CE35441B6B063800705360 /* ViewController.m */, 96CE35311B6B061200705360 /* aatree.c */, 96CE35321B6B061200705360 /* bstrlib.c */, 96CE35331B6B061200705360 /* bstrlib.txt */, 96CE35341B6B061200705360 /* list.c */, 96CE35351B6B061200705360 /* vector.c */, 96CE351F1B6B05F900705360 /* extensions.c */, 96CE35201B6B05F900705360 /* ogl_bitmap.c */, 96CE35211B6B05F900705360 /* ogl_display.c */, 96CE35221B6B05F900705360 /* ogl_draw.c */, 96CE35231B6B05F900705360 /* ogl_fbo.c */, 96CE35241B6B05F900705360 /* ogl_lock_es.c */, 96CE35251B6B05F900705360 /* ogl_lock.c */, 96CE35261B6B05F900705360 /* ogl_render_state.c */, 96CE35271B6B05F900705360 /* ogl_shader.c */, 96CE351B1B6B05D100705360 /* utime.c */, 96CE351C1B6B05D100705360 /* uxthread.c */, 96CE34BB1B6B059C00705360 /* allegro.c */, 96CE34BC1B6B059C00705360 /* bitmap_draw.c */, 96CE34BD1B6B059C00705360 /* bitmap_io.c */, 96CE34BE1B6B059C00705360 /* bitmap_lock.c */, 96CE34BF1B6B059C00705360 /* bitmap_pixel.c */, 96CE34C01B6B059C00705360 /* bitmap_type.c */, 96CE34C11B6B059C00705360 /* bitmap.c */, 96CE34C21B6B059C00705360 /* blenders.c */, 96CE34C31B6B059C00705360 /* config.c */, 96CE34C41B6B059C00705360 /* convert.c */, 96CE34C51B6B059C00705360 /* debug.c */, 96CE34C61B6B059C00705360 /* display_settings.c */, 96CE34C71B6B059C00705360 /* display.c */, 96CE34C81B6B059C00705360 /* drawing.c */, 96CE34C91B6B059C00705360 /* dtor.c */, 96CE34CA1B6B059C00705360 /* events.c */, 96CE34CB1B6B059C00705360 /* evtsrc.c */, 96CE34CC1B6B059C00705360 /* exitfunc.c */, 96CE34CD1B6B059C00705360 /* file_slice.c */, 96CE34CE1B6B059C00705360 /* file_stdio.c */, 96CE34CF1B6B059C00705360 /* file.c */, 96CE34D01B6B059C00705360 /* fshook_stdio.c */, 96CE34D11B6B059C00705360 /* fshook.c */, 96CE34D21B6B059C00705360 /* fullscreen_mode.c */, 96CE34D31B6B059C00705360 /* haptic.c */, 96CE34D41B6B059C00705360 /* inline.c */, 96CE34D51B6B059C00705360 /* joynu.c */, 96CE34D61B6B059C00705360 /* keybdnu.c */, 96CE34D71B6B059C00705360 /* libc.c */, 96CE34D81B6B059C00705360 /* math.c */, 96CE34D91B6B059C00705360 /* memblit.c */, 96CE34DA1B6B059C00705360 /* memdraw.c */, 96CE34DB1B6B059C00705360 /* memory.c */, 96CE34DC1B6B059C00705360 /* monitor.c */, 96CE34DD1B6B059C00705360 /* mouse_cursor.c */, 96CE34DE1B6B059C00705360 /* mousenu.c */, 96CE34DF1B6B059C00705360 /* path.c */, 96CE34E01B6B059C00705360 /* pixels.c */, 96CE34E11B6B059C00705360 /* shader.c */, 96CE34E21B6B059C00705360 /* system.c */, 96CE34E31B6B059C00705360 /* threads.c */, 96CE34E41B6B059C00705360 /* timernu.c */, 96CE34E51B6B059C00705360 /* tls_dll.inc */, 96CE34E61B6B059C00705360 /* tls.c */, 96CE34E71B6B059C00705360 /* touch_input.c */, 96CE34E81B6B059C00705360 /* transformations.c */, 96CE34E91B6B059C00705360 /* tri_soft.c */, 96CE34EA1B6B059C00705360 /* utf8.c */, ); name = "src "; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 964130EE1A6353E700184496 /* Allegro5_iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 964131031A6353E800184496 /* Build configuration list for PBXNativeTarget "Allegro5_iOS" */; buildPhases = ( 964130EB1A6353E700184496 /* Sources */, 964130EC1A6353E700184496 /* Frameworks */, 964130ED1A6353E700184496 /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = Allegro5_iOS; productName = "Allegro 5 iOS"; productReference = 964130EF1A6353E700184496 /* libAllegro5_iOS.a */; productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 964130E71A6353E700184496 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0610; ORGANIZATIONNAME = Allegro; TargetAttributes = { 964130EE1A6353E700184496 = { CreatedOnToolsVersion = 6.1.1; }; }; }; buildConfigurationList = 964130EA1A6353E700184496 /* Build configuration list for PBXProject "Allegro5_iOS" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 964130E61A6353E700184496; productRefGroup = 964130F01A6353E700184496 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 964130EE1A6353E700184496 /* Allegro5_iOS */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ 964130EB1A6353E700184496 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 96CE35091B6B059C00705360 /* memblit.c in Sources */, 96CE35591B6B066100705360 /* text.c in Sources */, 96CE35381B6B061200705360 /* list.c in Sources */, 96CE35011B6B059C00705360 /* fshook.c in Sources */, 96CE35181B6B059C00705360 /* transformations.c in Sources */, 96CE357A1B6B06EF00705360 /* high_primitives.c in Sources */, 96CE350E1B6B059C00705360 /* mousenu.c in Sources */, 96CE356B1B6B06C400705360 /* a5_physfs.c in Sources */, 96CE34F91B6B059C00705360 /* dtor.c in Sources */, 96CE35851B6B06EF00705360 /* triangulator.c in Sources */, 96CE35031B6B059C00705360 /* haptic.c in Sources */, 96CE357E1B6B06EF00705360 /* polygon.c in Sources */, 96CE34FC1B6B059C00705360 /* exitfunc.c in Sources */, 96CE354A1B6B063800705360 /* iphone_main.m in Sources */, 96CE35511B6B064F00705360 /* color.c in Sources */, 96CE352D1B6B05F900705360 /* ogl_lock_es.c in Sources */, 96CE35821B6B06EF00705360 /* prim_soft.c in Sources */, 96A3016E1B9A874F002E2D1C /* clipboard.c in Sources */, 96CE35651B6B069700705360 /* generic_main.c in Sources */, 96CE352A1B6B05F900705360 /* ogl_display.c in Sources */, 96CE357D1B6B06EF00705360 /* point_soft.c in Sources */, 96CE34FF1B6B059C00705360 /* file.c in Sources */, 96CE35831B6B06EF00705360 /* prim_util.c in Sources */, 96CE35841B6B06EF00705360 /* primitives.c in Sources */, 96CE34F01B6B059C00705360 /* bitmap_type.c in Sources */, 96CE35131B6B059C00705360 /* threads.c in Sources */, 96CE35491B6B063800705360 /* iphone_keyboard.c in Sources */, 96CE350A1B6B059C00705360 /* memdraw.c in Sources */, 96CE35631B6B068800705360 /* tga.c in Sources */, 96CE35291B6B05F900705360 /* ogl_bitmap.c in Sources */, 96CE35621B6B068800705360 /* pcx.c in Sources */, 96CE357F1B6B06EF00705360 /* polyline.c in Sources */, 96CE352C1B6B05F900705360 /* ogl_fbo.c in Sources */, 96A12D051D2F3F9300F245D9 /* identify.c in Sources */, 96CE354F1B6B063800705360 /* ViewController.m in Sources */, 96CE34FD1B6B059C00705360 /* file_slice.c in Sources */, 96CE35481B6B063800705360 /* iphone_joystick.m in Sources */, 96CE35451B6B063800705360 /* allegroAppDelegate.m in Sources */, 96CE351E1B6B05D100705360 /* uxthread.c in Sources */, 96CE35471B6B063800705360 /* iphone_display.m in Sources */, 96CE34EC1B6B059C00705360 /* bitmap_draw.c in Sources */, 96CE34FB1B6B059C00705360 /* evtsrc.c in Sources */, 96CE35001B6B059C00705360 /* fshook_stdio.c in Sources */, 96CE35021B6B059C00705360 /* fullscreen_mode.c in Sources */, 96A12D031D2F3C3E00F245D9 /* png.c in Sources */, 96CE34F81B6B059C00705360 /* drawing.c in Sources */, 96CE350D1B6B059C00705360 /* mouse_cursor.c in Sources */, 96CE350C1B6B059C00705360 /* monitor.c in Sources */, 96CE34F21B6B059C00705360 /* blenders.c in Sources */, 96CE354D1B6B063800705360 /* iphone_system.c in Sources */, 96CE35811B6B06EF00705360 /* prim_opengl.c in Sources */, 96CE35801B6B06EF00705360 /* prim_directx.cpp in Sources */, 96CE34EB1B6B059C00705360 /* allegro.c in Sources */, 96CE34F31B6B059C00705360 /* config.c in Sources */, 96CE355F1B6B068800705360 /* bmp.c in Sources */, 96CE35371B6B061200705360 /* bstrlib.c in Sources */, 96CE35871B6B070300705360 /* ttf.c in Sources */, 96CE352E1B6B05F900705360 /* ogl_lock.c in Sources */, 96CE34ED1B6B059C00705360 /* bitmap_io.c in Sources */, 96CE350F1B6B059C00705360 /* path.c in Sources */, 96CE35171B6B059C00705360 /* touch_input.c in Sources */, 96CE35101B6B059C00705360 /* pixels.c in Sources */, 96CE34F51B6B059C00705360 /* debug.c in Sources */, 96CE35571B6B066100705360 /* fontbmp.c in Sources */, 96CE350B1B6B059C00705360 /* memory.c in Sources */, 96CE35111B6B059C00705360 /* shader.c in Sources */, 968608761B6B12960008BD29 /* dds.c in Sources */, 96CE35601B6B068800705360 /* iio.c in Sources */, 96CE35301B6B05F900705360 /* ogl_shader.c in Sources */, 96CE34EF1B6B059C00705360 /* bitmap_pixel.c in Sources */, 96CE35281B6B05F900705360 /* extensions.c in Sources */, 96CE351A1B6B059C00705360 /* utf8.c in Sources */, 96CE354B1B6B063800705360 /* iphone_mouse.m in Sources */, 96A301701B9A8778002E2D1C /* iphone_clipboard.m in Sources */, 96CE35561B6B066100705360 /* font.c in Sources */, 96CE354C1B6B063800705360 /* iphone_path.m in Sources */, 96CE34F41B6B059C00705360 /* convert.c in Sources */, 96CE34F61B6B059C00705360 /* display_settings.c in Sources */, 96CE351D1B6B05D100705360 /* utime.c in Sources */, 96CE35791B6B06EF00705360 /* directx_shaders.cpp in Sources */, 96CE357B1B6B06EF00705360 /* line_soft.c in Sources */, 96CE35391B6B061200705360 /* vector.c in Sources */, 96CE352B1B6B05F900705360 /* ogl_draw.c in Sources */, 96CE35061B6B059C00705360 /* keybdnu.c in Sources */, 96CE34FE1B6B059C00705360 /* file_stdio.c in Sources */, 96CE35141B6B059C00705360 /* timernu.c in Sources */, 96CE35161B6B059C00705360 /* tls.c in Sources */, 96CE35191B6B059C00705360 /* tri_soft.c in Sources */, 96CE34F71B6B059C00705360 /* display.c in Sources */, 96CE354E1B6B063800705360 /* iphone_touch_input.m in Sources */, 96CE35461B6B063800705360 /* EAGLView.m in Sources */, 96CE34F11B6B059C00705360 /* bitmap.c in Sources */, 96CE356A1B6B06C400705360 /* a5_physfs_dir.c in Sources */, 96CE35671B6B06A400705360 /* memfile.c in Sources */, 96CE35151B6B059C00705360 /* tls_dll.inc in Sources */, 96CE352F1B6B05F900705360 /* ogl_render_state.c in Sources */, 96CE34FA1B6B059C00705360 /* events.c in Sources */, 96CE35581B6B066100705360 /* stdfont.c in Sources */, 96CE35081B6B059C00705360 /* math.c in Sources */, 96CE35051B6B059C00705360 /* joynu.c in Sources */, 96CE35041B6B059C00705360 /* inline.c in Sources */, 96CE35071B6B059C00705360 /* libc.c in Sources */, 96CE35121B6B059C00705360 /* system.c in Sources */, 96CE34EE1B6B059C00705360 /* bitmap_lock.c in Sources */, 96CE35361B6B061200705360 /* aatree.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 964131011A6353E800184496 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.1; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; }; 964131021A6353E800184496 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.1; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; 964131041A6353E800184496 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++98"; CLANG_CXX_LIBRARY = "libstdc++"; CLANG_ENABLE_OBJC_ARC = NO; GCC_PREPROCESSOR_DEFINITIONS = ( ALLEGRO_LIB_BUILD, ALLEGRO_UNSTABLE, ALLEGRO_INTERNAL_UNSTABLE, ); HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, ../../include, ../../deps/include, ../../addons/color, ../../addons/font, ../../addons/image, ../../addons/main, ../../addons/memfile, ../../addons/physfs, ../../addons/primitives, ../../addons/ttf, ../../misc/Allegro5_iOS, ); IPHONEOS_DEPLOYMENT_TARGET = 6.1; LIBRARY_SEARCH_PATHS = ""; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = Allegro5_iOS; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VALID_ARCHS = "arm64 armv7"; }; name = Debug; }; 964131051A6353E800184496 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++98"; CLANG_CXX_LIBRARY = "libstdc++"; CLANG_ENABLE_OBJC_ARC = NO; GCC_OPTIMIZATION_LEVEL = s; GCC_PREPROCESSOR_DEFINITIONS = ( ALLEGRO_LIB_BUILD, ALLEGRO_UNSTABLE, ALLEGRO_INTERNAL_UNSTABLE, ); HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, ../../include, ../../deps/include, ../../addons/color, ../../addons/font, ../../addons/image, ../../addons/main, ../../addons/memfile, ../../addons/physfs, ../../addons/primitives, ../../addons/ttf, ../../misc/Allegro5_iOS, ); IPHONEOS_DEPLOYMENT_TARGET = 6.1; LIBRARY_SEARCH_PATHS = ""; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = Allegro5_iOS; SKIP_INSTALL = NO; TARGETED_DEVICE_FAMILY = "1,2"; VALID_ARCHS = "arm64 armv7"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 964130EA1A6353E700184496 /* Build configuration list for PBXProject "Allegro5_iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 964131011A6353E800184496 /* Debug */, 964131021A6353E800184496 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 964131031A6353E800184496 /* Build configuration list for PBXNativeTarget "Allegro5_iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 964131041A6353E800184496 /* Debug */, 964131051A6353E800184496 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 964130E71A6353E700184496 /* Project object */; } allegro5-5.2.10.1/misc/Allegro5_iOS/allegro5/000077500000000000000000000000001473414355200203515ustar00rootroot00000000000000allegro5-5.2.10.1/misc/Allegro5_iOS/allegro5/internal/000077500000000000000000000000001473414355200221655ustar00rootroot00000000000000allegro5-5.2.10.1/misc/Allegro5_iOS/allegro5/internal/aintern_image_cfg.h000066400000000000000000000007231473414355200257610ustar00rootroot00000000000000/* #define ALLEGRO_CFG_WANT_NATIVE_IMAGE_LOADER */ /* which libraries are present and needed? */ /* #undef ALLEGRO_CFG_IIO_HAVE_GDIPLUS */ /* #undef ALLEGRO_CFG_IIO_HAVE_GDIPLUS_LOWERCASE_H */ /* #undef ALLEGRO_CFG_IIO_HAVE_ANDROID */ /* #undef ALLEGRO_CFG_IIO_HAVE_PNG */ /* #undef ALLEGRO_CFG_IIO_HAVE_JPG */ #define ALLEGRO_CFG_IIO_HAVE_PNG /* which formats are supported and wanted? */ #define ALLEGRO_CFG_IIO_SUPPORT_PNG //#define ALLEGRO_CFG_IIO_SUPPORT_JPG allegro5-5.2.10.1/misc/Allegro5_iOS/allegro5/internal/aintern_ttf_cfg.h000066400000000000000000000000461473414355200254720ustar00rootroot00000000000000/* #undef ALLEGRO_CFG_TTF_FREETYPE */ allegro5-5.2.10.1/misc/Allegro5_iOS/allegro5/platform/000077500000000000000000000000001473414355200221755ustar00rootroot00000000000000allegro5-5.2.10.1/misc/Allegro5_iOS/allegro5/platform/alplatf.h000066400000000000000000000066111473414355200237750ustar00rootroot00000000000000/* alplatf.h is generated from alplatf.h.cmake */ /* #undef ALLEGRO_MINGW32 */ /* #undef ALLEGRO_UNIX */ /* #undef ALLEGRO_MSVC */ /* #undef ALLEGRO_MACOSX */ /* #undef ALLEGRO_BCC32 */ #define ALLEGRO_IPHONE /* #undef ALLEGRO_ANDROID */ /* #undef ALLEGRO_RASPBERRYPI */ /* #undef ALLEGRO_CFG_NO_FPU */ /* #undef ALLEGRO_CFG_DLL_TLS */ #define ALLEGRO_CFG_PTHREADS_TLS /* #undef ALLEGRO_CFG_RELEASE_LOGGING */ /* #undef ALLEGRO_CFG_D3D */ /* #undef ALLEGRO_CFG_D3D9EX */ /* #undef ALLEGRO_CFG_D3DX9 */ /* #undef ALLEGRO_CFG_XINPUT */ #define ALLEGRO_CFG_OPENGL #define ALLEGRO_CFG_OPENGLES #define ALLEGRO_CFG_OPENGLES2 #define ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE #define ALLEGRO_CFG_SHADER_GLSL /* #undef ALLEGRO_CFG_SHADER_HLSL */ /* #undef ALLEGRO_CFG_OPENGL_S3TC_LOCKING */ /* #undef ALLEGRO_CFG_ANDROID_LEGACY */ /*---------------------------------------------------------------------------*/ /* Define to 1 if you have the corresponding header file. */ #define ALLEGRO_HAVE_DIRENT_H #define ALLEGRO_HAVE_INTTYPES_H /* #undef ALLEGRO_HAVE_LINUX_AWE_VOICE_H */ /* #undef ALLEGRO_HAVE_LINUX_INPUT_H */ /* #undef ALLEGRO_HAVE_LINUX_SOUNDCARD_H */ /* #undef ALLEGRO_HAVE_MACHINE_SOUNDCARD_H */ /* #undef ALLEGRO_HAVE_SOUNDCARD_H */ #define ALLEGRO_HAVE_STDBOOL_H #define ALLEGRO_HAVE_STDINT_H /* #undef ALLEGRO_HAVE_SV_PROCFS_H */ /* #undef ALLEGRO_HAVE_SYS_IO_H */ /* #undef ALLEGRO_HAVE_SYS_SOUNDCARD_H */ #define ALLEGRO_HAVE_SYS_STAT_H #define ALLEGRO_HAVE_SYS_TIME_H #define ALLEGRO_HAVE_TIME_H #define ALLEGRO_HAVE_SYS_UTSNAME_H #define ALLEGRO_HAVE_SYS_TYPES_H #define ALLEGRO_HAVE_OSATOMIC_H /* #undef ALLEGRO_HAVE_SYS_INOTIFY_H */ /* #undef ALLEGRO_HAVE_SAL_H */ /* Define to 1 if the corresponding functions are available. */ /* #undef ALLEGRO_HAVE_GETEXECNAME */ #define ALLEGRO_HAVE_MKSTEMP #define ALLEGRO_HAVE_MMAP #define ALLEGRO_HAVE_MPROTECT #define ALLEGRO_HAVE_SCHED_YIELD #define ALLEGRO_HAVE_SYSCONF #define ALLEGRO_HAVE_FSEEKO #define ALLEGRO_HAVE_FTELLO #define ALLEGRO_HAVE_STRERROR_R /* #undef ALLEGRO_HAVE_STRERROR_S */ #define ALLEGRO_HAVE_VA_COPY /* Define to 1 if procfs reveals argc and argv */ /* #undef ALLEGRO_HAVE_PROCFS_ARGCV */ /*---------------------------------------------------------------------------*/ /* Define if target machine is little endian. */ #define ALLEGRO_LITTLE_ENDIAN /* Define if target machine is big endian. */ /* #undef ALLEGRO_BIG_ENDIAN */ /* Define if target platform is Darwin. */ /* #undef ALLEGRO_DARWIN */ /*---------------------------------------------------------------------------*/ /* Define if you need support for X-Windows. */ /* #undef ALLEGRO_WITH_XWINDOWS */ /* Define if XCursor ARGB extension is available. */ /* #undef ALLEGRO_XWINDOWS_WITH_XCURSOR */ /* Define if XF86VidMode extension is supported. */ /* #undef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE */ /* Define if Xinerama extension is supported. */ /* #undef ALLEGRO_XWINDOWS_WITH_XINERAMA */ /* Define if XRandR extension is supported. */ /* #undef ALLEGRO_XWINDOWS_WITH_XRANDR */ /* Define if XIM extension is supported. */ /* #undef ALLEGRO_XWINDOWS_WITH_XIM */ /*---------------------------------------------------------------------------*/ /* Define if target platform is linux. */ /* #undef ALLEGRO_LINUX */ /* Define if we are building with SDL backend. */ /* #undef ALLEGRO_SDL */ /*---------------------------------------------------------------------------*/ /* vi: set ft=c ts=3 sts=3 sw=3 et: */ allegro5-5.2.10.1/misc/allegro.pc.in000066400000000000000000000005051473414355200167710ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro Description: Allegro game programming library Version: ${version} Libs: -L${libdir} -lallegro${suffix} Libs.private: @link_with@ Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_acodec.pc.in000066400000000000000000000006421473414355200202710ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_acodec Description: Allegro game programming library, audio codec addon Version: ${version} Libs: -L${libdir} -lallegro_acodec${suffix} Libs.private: @link_with@ Requires: allegro_audio${suffix}-${versuffix} >= ${version} Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_audio.pc.in000066400000000000000000000006241473414355200201540ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_audio Description: Allegro game programming library, audio addon Version: ${version} Libs: -L${libdir} -lallegro_audio${suffix} Libs.private: @link_with@ Requires: allegro${suffix}-${versuffix} >= ${version} Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_color.pc.in000066400000000000000000000006251473414355200201720ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_color Description: Allegro game programming library, colors addon Version: ${version} Libs: -L${libdir} -lallegro_color${suffix} Libs.private: @link_with@ Requires: allegro${suffix}-${versuffix} >= ${version} Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_dialog.pc.in000066400000000000000000000006361473414355200203150ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_dialog Description: Allegro game programming library, native dialog addon Version: ${version} Libs: -L${libdir} -lallegro_dialog${suffix} Libs.private: @link_with@ Requires: allegro${suffix}-${versuffix} >= ${version} Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_font.pc.in000066400000000000000000000006211473414355200200160ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_font Description: Allegro game programming library, font addon Version: ${version} Libs: -L${libdir} -lallegro_font${suffix} Libs.private: @link_with@ Requires: allegro${suffix}-${versuffix} >= ${version} Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_image.pc.in000066400000000000000000000006301473414355200201320ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_image Description: Allegro game programming library, image I/O addon Version: ${version} Libs: -L${libdir} -lallegro_image${suffix} Libs.private: @link_with@ Requires: allegro${suffix}-${versuffix} >= ${version} Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_main.pc.in000066400000000000000000000006271473414355200200020ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_main Description: Allegro game programming library, magic main addon Version: ${version} Libs: -L${libdir} -lallegro_main${suffix} Libs.private: @link_with@ Requires: allegro${suffix}-${versuffix} >= ${version} Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_memfile.pc.in000066400000000000000000000006371473414355200204750ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_memfile Description: Allegro game programming library, memory files addon Version: ${version} Libs: -L${libdir} -lallegro_memfile${suffix} Libs.private: @link_with@ Requires: allegro${suffix}-${versuffix} >= ${version} Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_monolith.pc.in000066400000000000000000000005551473414355200207070ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_monolith Description: Allegro game programming library (all addons included) Version: ${version} Libs: -L${libdir} -lallegro_monolith${suffix} Libs.private: @link_with@ Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_physfs.pc.in000066400000000000000000000006321473414355200203660ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_physfs Description: Allegro game programming library, PhysicsFS addon Version: ${version} Libs: -L${libdir} -lallegro_physfs${suffix} Libs.private: @link_with@ Requires: allegro${suffix}-${versuffix} >= ${version} Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_primitives.pc.in000066400000000000000000000006431473414355200212470ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_primitives Description: Allegro game programming library, primitives addon Version: ${version} Libs: -L${libdir} -lallegro_primitives${suffix} Libs.private: @link_with@ Requires: allegro${suffix}-${versuffix} >= ${version} Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_ttf.pc.in000066400000000000000000000006361473414355200176530ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_ttf Description: Allegro game programming library, TrueType fonts addon Version: ${version} Libs: -L${libdir} -lallegro_ttf${suffix} Libs.private: @link_with@ Requires: allegro_font${suffix}-${versuffix} >= ${version} Cflags: -I${includedir} allegro5-5.2.10.1/misc/allegro_video.pc.in000066400000000000000000000006411473414355200201600ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ version=@ALLEGRO_VERSION@ suffix=@lib_type@@lib_linkage@ versuffix=@versuffix@ Name: allegro_video Description: Allegro game programming library, video player addon Version: ${version} Libs: -L${libdir} -lallegro_video${suffix} Libs.private: @link_with@ Requires: allegro_audio${suffix}-${versuffix} >= ${version} Cflags: -I${includedir} allegro5-5.2.10.1/misc/askq.c000066400000000000000000000010751473414355200155210ustar00rootroot00000000000000/* * ASKQ - asks a yes/no question, returning an exit status to the caller. * This is used by the msvcmake installation batch file. */ #include #include int main(int argc, char *argv[]) { int i; puts("\n"); for (i=1; i 1) putc(' ', stdout); puts(argv[i]); } puts("? [y/n] "); for (;;) { i = getc(stdin); if ((tolower(i) == 'y') || (tolower(i) == 'n')) { putc(i, stdout); puts("\n\n"); return (tolower(i) == 'y') ? 0 : 1; } else putc(7, stdout); } } allegro5-5.2.10.1/misc/convert_line_endings.sh000077500000000000000000000032141473414355200211500ustar00rootroot00000000000000#!/bin/sh # # This file is only used now to convert file line endings by misc/zipup.sh. # We used to do this in fix.sh/fix.bat but those files have been removed # in the 4.9.x series as running them could confuse the CMake and Scons builds, # plus the old build system is not being maintained. # proc_filelist() { # common files. This must not include any shell scripts or batch files. AL_FILELIST=`find . -type f "(" ! -path "*/.*" ")" -a "(" \ -name "*.c" -o -name "*.cfg" -o -name "*.cpp" -o -name "*.def" -o \ -name "*.h" -o -name "*.hin" -o -name "*.in" -o -name "*.inc" -o \ -name "*.m" -o -name "*.m4" -o -name "*.mft" -o -name "*.s" -o \ -name "*.rc" -o -name "*.rh" -o -name "*.spec" -o -name "*.pl" -o \ -name "*.txt" -o -name "*._tx" -o -name "makefile*" -o \ -name "*.inl" -o -name "CHANGES" -o \ -name "AUTHORS" -o -name "THANKS" ")" \ -a ! -path "*.dist*" \ ` # touch unix shell scripts? if [ "$1" != "omit_sh" ]; then AL_FILELIST="$AL_FILELIST `find . -type f -name '*.sh' -o \ -name 'configure' -a ! -path "*addons*"`" fi # touch DOS batch files? if [ "$1" != "omit_bat" ]; then AL_FILELIST="$AL_FILELIST `find . -type f -name '*.bat' -a \ ! -path "*addons*"`" fi } proc_utod() { echo "Converting files from Unix to DOS/Win32 ..." proc_filelist "omit_sh" /bin/sh misc/utod.sh $AL_FILELIST } proc_dtou() { echo "Converting files from DOS/Win32 to Unix ..." proc_filelist "omit_bat" /bin/sh misc/dtou.sh $AL_FILELIST } trap 'exit $?' 1 2 3 13 15 case "$1" in "--utod" ) proc_utod ;; "--dtou" ) proc_dtou ;; esac echo "Done!" allegro5-5.2.10.1/misc/coverage.sh000077500000000000000000000022451473414355200165500ustar00rootroot00000000000000#!/bin/sh -e # Produce test coverage results using lcov. # Run this from a dedicated build directory unless you don't mind your build # flags being changed. BUILDDIR=$(dirname $PWD) JOBS=${JOBS:-4} if ! test ../LICENSE.txt then echo "Run this in a build subdirectory." 1>&2 exit 1 fi if ! which lcov 2>&1 >/dev/null then echo "lcov is required." 1>&2 exit 1 fi # ccache can interfere with gcov by causing profiling data to end up in the # ~/.ccache directory. export CCACHE_DISABLE=1 cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_C_FLAGS=--coverage \ -DCMAKE_CXX_FLAGS=--coverage \ -DCMAKE_EXE_LINKER_FLAGS=--coverage \ -DWANT_POPUP_EXAMPLES=no \ .. lcov -d $BUILDDIR --zerocounters make -j${JOBS} ex_blend_test make -j${JOBS} ex_config make -j${JOBS} ex_dir make -j${JOBS} ex_path_test make -j${JOBS} ex_utf8 make -j${JOBS} copy_example_data copy_demo_data ( cd examples ./ex_blend_test ./ex_config ./ex_dir ./ex_path_test ./ex_utf8 ) || true ( cd tests make -j${JOBS} run_tests ) || true lcov -d $BUILDDIR --capture --output allegro_auto.info genhtml --legend allegro_auto.info --output-directory coverage allegro5-5.2.10.1/misc/create_release_archives.sh000077500000000000000000000015731473414355200216070ustar00rootroot00000000000000#!/bin/sh set -e ver=$1 if [ -z "$ver" ] then echo "Please pass a version." exit 1 fi if git show $ver -- 2>&1 | grep -q 'fatal' then echo "$ver is not a valid revision." exit 1 fi export LC_ALL=en_US repo=$PWD tmpdir=$( mktemp -d ) git archive --format=tar --prefix=allegro/ ${ver} | ( cd $tmpdir && tar xf - ) ( cd "$tmpdir/allegro" for file in $( find -type f -printf '%P\n' ) do echo $file commit=$( cd $repo && git rev-list ${ver} "$file" | head -n 1 ) mtime=$( cd $repo && git show --pretty=format:%ai $commit | head -n 1) touch -d "$mtime" "$file" done ) ( cd "$tmpdir/allegro" ./misc/zipup.sh allegro-$ver.zip mv .dist/*.* .. ) (cd "$tmpdir" rm -rf allegro unzip allegro-$ver.zip ./allegro/misc/mkunixdists.sh allegro-$ver.zip ) mv "$tmpdir"/*.* ./ rm -rf -- "$tmpdir" echo "Done and done!" allegro5-5.2.10.1/misc/dtou.sh000077500000000000000000000016161473414355200157310ustar00rootroot00000000000000#!/bin/sh # # Convert CR/LF line endings to LF line endings, preserving timestamps and # permissions on the file. # with_unix_tools() { for file in "$@" do echo "$file" tmpfile=`dirname "$file"`/__dtou_tmp.$RANDOM || exit 1 trap 'rm -f "$tmpfile"' 1 2 3 13 15 # We go through a slightly convoluted sequence of commands in order to # preserve both the timestamp and permissions on the file. { tr -d '\015' < "$file" > "$tmpfile" && touch -r "$file" "$tmpfile" && cat "$tmpfile" > "$file" && touch -r "$tmpfile" "$file" && rm -f "$tmpfile" } || exit 1 done } with_cygwin() { for file in "$@" do dos2unix $file || exit 1 done } if test -z "$1" then echo "$0 filename" exit fi if test "$ALLEGRO_USE_CYGWIN" = "1" then with_cygwin "$@" else with_unix_tools "$@" fi # vi: sts=3 sw=3 et allegro5-5.2.10.1/misc/embedman.bat000077500000000000000000000031301473414355200166530ustar00rootroot00000000000000@ECHO OFF REM *** embedman.bat is a helper tool for MSVC8. REM It embeds all XML manifest files into its corresponding executable. REM ======== DISPATCHING ======== IF "%1" == "" GOTO usage IF "%1" == "all" IF "%2" == "" GOTO search IF "%2" == "" GOTO bad_usage IF NOT EXIST "%1" GOTO file_not_found IF NOT EXIST "%1.manifest" GOTO no_manifest REM ======== EMBED MANIFEST ======== mt -nologo -manifest %1.manifest -outputresource:%1;%2 IF NOT "%ERRORLEVEL%" == "0" GOTO mt_fail del %1.manifest GOTO end REM ======== SEARCH AND EMBED ======== :search FOR /R %%v IN (*.exe) DO CALL %0 %%v 1 -silent FOR /R %%v IN (*.scr) DO CALL %0 %%v 1 -silent FOR /R %%v IN (*.dll) DO CALL %0 %%v 2 -silent GOTO end REM ======== ERRORS ======== :usage ECHO. ECHO Running embedman.bat with "all" as the first and only parameter causes it to ECHO search for all executables and DLLs with manifest files, and embed them. ECHO. ECHO %0 all ECHO. ECHO Alternatively, you can specify an exact file: ECHO. ECHO %0 file.exe 1 ECHO %0 file.dll 2 ECHO. ECHO In every case, the manifest file must exist in the same folder with the same ECHO name as the executable for it to work. The manifest file is then deleted. GOTO end :bad_usage ECHO. ECHO You must specify whether the file is an executable or DLL via the second ECHO parameter. ECHO. ECHO 1 = Executable ECHO 2 = DLL GOTO end :file_not_found ECHO. ECHO The file "%1" was not found. GOTO end :mt_fail ECHO Unable to embed %1.manifest! Make sure mt.exe is in the path. GOTO end :no_manifest IF NOT "%3" == "-silent" ECHO No manifest found for %1 REM ======== THE END ======== :endallegro5-5.2.10.1/misc/fixver.sh000077500000000000000000000053151473414355200162610ustar00rootroot00000000000000#! /bin/sh -e # # Shell script to adjust the version numbers and dates in files. # # Note: if you pass "datestamp" as the only argument, then the version # digits will remain unchanged and the comment will be set to the date. # This is in particular useful for making SVN snapshots. BASE_H_FILE="include/allegro5/base.h" if [ $# -eq 1 ] && [ "$1" = "datestamp" ]; then major_num=$( awk '/^#define\s+ALLEGRO_VERSION\s+[0-9]+$/ { print $NF }' $BASE_H_FILE ) sub_num=$( awk '/^#define\s+ALLEGRO_SUB_VERSION\s+[0-9]+$/ { print $NF }' $BASE_H_FILE ) wip_num=$( awk '/^#define\s+ALLEGRO_WIP_VERSION\s+[0-9]+$/ { print $NF }' $BASE_H_FILE ) datestamp=`date '+%Y%m%d'` echo "Re-invoking script with args: [$major_num $sub_num $wip_num $datestamp]" $0 $major_num $sub_num $wip_num $datestamp exit $? fi case $# in 3|4|5) ;; *) echo "Usage: fixver major_num sub_num wip_num [n] [comment]" 1>&2 echo " or: fixver datestamp" 1>&2 echo "Example: fixver 4 9 14 SVN" 1>&2 echo " fixver 4 9 14 WIP" 1>&2 echo " fixver 4 9 14 1 WIP" 1>&2 echo " fixver 5 0 0" 1>&2 exit 1 ;; esac # get the version and date strings in a nice format case $# in 3) # Proper release. fourth=1 comment= ;; 4) case $4 in WIP) # Proper release fourth=1 comment=WIP ;; [0-9]) # Proper release fourth=$(( $4 + 1 )) comment= ;; *) fourth=0 comment=$4 ;; esac ;; 5) fourth=$(( $4 + 1 )) comment=$5 ;; esac if [ -z "$comment" ]; then verstr="$1.$2.$3" else verstr="$1.$2.$3 ($comment)" fi year=$(date +%Y) month=$(date +%m) day=$(date +%d) datestr="$(date +%b) $day, $year" # patch allegro/base.h echo "s/\#define ALLEGRO_VERSION .*/\#define ALLEGRO_VERSION $1/" > fixver.sed echo "s/\#define ALLEGRO_SUB_VERSION .*/\#define ALLEGRO_SUB_VERSION $2/" >> fixver.sed echo "s/\#define ALLEGRO_WIP_VERSION .*/\#define ALLEGRO_WIP_VERSION $3/" >> fixver.sed echo "s/\#define ALLEGRO_RELEASE_NUMBER .*/\#define ALLEGRO_RELEASE_NUMBER $fourth/" >> fixver.sed echo "s/\#define ALLEGRO_VERSION_STR .*/\#define ALLEGRO_VERSION_STR \"$verstr\"/" >> fixver.sed echo "s/\#define ALLEGRO_DATE_STR .*/\#define ALLEGRO_DATE_STR \"$year\"/" >> fixver.sed echo "s/\#define ALLEGRO_DATE .*/\#define ALLEGRO_DATE $year$month$day \/\* yyyymmdd \*\//" >> fixver.sed echo "Patching ${BASE_H_FILE}..." cp $BASE_H_FILE fixver.tmp sed -f fixver.sed fixver.tmp > $BASE_H_FILE # clean up after ourselves rm fixver.sed fixver.tmp echo "Done!" allegro5-5.2.10.1/misc/gcc-uni.sh000077500000000000000000000050671473414355200163070ustar00rootroot00000000000000#!/bin/sh # gcc-uni.sh # ---------- # By Matthew Leverton # # Builds a universal binary by a multi-step process to allow for individual # options for both architectures. Its primary use is to be used as a wrapper # for makefile based projects. # # Although untested, it should be able to build OS X 10.2 compatible builds. # Note that you may need to install the various OS SDKs before this will # work. gcc-3.3 is used for the PPC build. The active version of gcc is used # for the Intel build. (Note that it must be at least version 4.) # # If the makefile has a CC variable, this is all that should be necessary: # # CC=/usr/bin/gcc-uni.sh # # set up defaults mode=link output= cmd= # check whether to use gcc or g++ # (using a symlink with g++ in name is recommended) case "$0" in *g++*) gcc=g++ ;; *) gcc=gcc ;; esac # which OSX to target (used for PPC) OSX_TARGET=10.2 # which SDK to use (unused with PPC because gcc-3.3 doesn't know about it)) SDK_i386=/Developer/SDKs/MacOSX10.4u.sdk SDK_PPC= # i386 flags CFLAGS_i386=" -isysroot $SDK_i386" LDFLAGS_i386=" -isysroot $SDK_i386 -Wl,-syslibroot,$SDK_i386" # ppc flags CFLAGS_PPC= LDFLAGS_PPC= # Parse options: # -arch switches are ignored # looks for -c to enable the CFLAGS # looks for -o to determine the name of the output if [ $# -eq 0 ]; then echo "This is a wrapper around gcc that builds universal binaries." echo "It can only be used to compile or link." exit 1 fi # remember the arguments in case there's no output files args=$* while [ -n "$1" ]; do case "$1" in -arch) shift ;; -c) mode=compile cmd="$cmd -c" ;; -o) shift output="$1" ;; *) cmd="$cmd $1" ;; esac shift done # if no output file, just pass the original command as-is and hope for the best if [ -z "$output" ]; then exec $gcc $args fi # figure out if we are compiling or linking case "$mode" in link) FLAGS_i386="$LDFLAGS_i386" FLAGS_PPC="$LDFLAGS_PPC" ;; compile) FLAGS_i386="$CFLAGS_i386" FLAGS_PPC="$CFLAGS_PPC" ;; *) echo "internal error in gcc-uni.sh script" exit 1 ;; esac # TODO: use trap to cleanup # build the i386 version $gcc $cmd $FLAGS_i386 -arch i386 -o $output.i386 if [ $? -ne 0 ]; then exit 1 fi # build the PPC version MACOSX_DEPLOYMENT_TARGET=$OSX_TARGET /usr/bin/$gcc-3.3 $cmd $FLAGS_PPC -arch ppc -o $output.ppc if [ $? -ne 0 ]; then rm -f $output.i386 exit 1 fi # create the universal version lipo -create $output.i386 $output.ppc -output $output if [ $? -ne 0 ]; then rm -f $output.i386 $output.ppc exit 1 fi # cleanup rm -f $output.i386 $output.ppc allegro5-5.2.10.1/misc/gl_mkalias.sh000077500000000000000000000010271473414355200170550ustar00rootroot00000000000000#!/bin/sh # This script creates '*_ext_alias.h' from '*_ext_api.h' in # include/allegro5/opengl/GLext/ dir prefix="glx wgl gl" for name in $prefix; do src="include/allegro5/opengl/GLext/"$name"_ext_api.h" out="include/allegro5/opengl/GLext/"$name"_ext_alias.h" prfx=`echo $name | sed 's/glx/glX/'` cat $src | sed -e '/^[ ]*#/!s/[ ]//g' | awk -F"," "BEGIN{print\"/*Automatically generated by gl_mkalias.sh DO NOT EDIT!*/\"} {if (\$0 ~ /^AGL_API/) printf \"#define $prfx%s _al_$prfx%s\n\",\$2,\$2; else print \$0}" > $out done allegro5-5.2.10.1/misc/icon.png000066400000000000000000000010061473414355200160460ustar00rootroot00000000000000PNG  IHDR00WIDAThY+r0]u { (((r 4((!|14Y}lcIMFA$-}mQ!kB~4,&) թK ȮiM /]Pڇݭzit8G)1)lwk^EQ`JHj*S`.+,s.e"}{1%e< g`0_\iS-$ֺٝ/hj)mus^b~aׅB x^4E(,[!)JL5 E:SϰNsA)zc9e"M Q)xAg I,ӛ3K1`/. 1*}|6lJDtN% 6DeN%.lI[1_lpIENDB`allegro5-5.2.10.1/misc/icon.xpm000066400000000000000000000051141473414355200160720ustar00rootroot00000000000000/* XPM */ static char * alex_xpm[] = { "48 48 6 1", " c None", ". c #080808", "+ c #FCFCFC", "@ c #486028", "# c #587834", "$ c #A4C47C", " .... .... ", " .... .... ", " .++++.. .++++.. ", " .++++.. .++++.. ", " ...... ...++.......++... ", " ...... ...++.......++... ", "..@@####............@@###....##@.. ", "..@@####............@@###....##@.. ", "..###########################..#@@.. ", "..###########################..#@@.. ", ".............................#####.. ", ".............................#####.. ", " ...#########@@.. ", " ......#####..#######.. ", " ......#####..#######.. ", " .....######.....$$#######.. ", " .....######.....$$#######.. ", " .....#####...... ..$$#######.. ", " .....#####...... ..$$#######.. ", " ..#####..... .$$##..###@@.. ", " ..#####..... .$$##..###@@.. ", " ..... .......###@@.. ", " ..... .......###@@.. ", " ..#########.@@.. ", " ..##.......@##.. ", " ..##.......@##.. ", " ...$$$$#####.. ", " ...$$$$#####.. ", " .$$$$#####.. .. ", " .$$$$#####.. .. ", " .$$$$#####.. ..@@.", " .$$$$#####.. ..@@.", " .$$..#####@@.. ..@@.", " .$$..#####@@.. ..@@.", " ..####@..##.. ..##@@.", " ..####@..##.. ..##@@.", " ..####@..####...##@@$$.", " .####@@.$$#######@@$$.. ", " .####@@.$$#######@@$$.. ", " .##@@.....$$$$$$$$$.. ", " .##@@.....$$$$$$$$$.. ", " ..##@@............ ", " ..##@@............ ", " ...######.@@.. ", " ...######.@@.. ", " ..#####@@###..@@.. ", " ..#####@@###..@@.. ", " .................. "}; allegro5-5.2.10.1/misc/install_test.c000066400000000000000000000035261473414355200172720ustar00rootroot00000000000000/* * A small test program that you can compile and run to verify that Allegro was * installed correctly. It assumes you installed all the addons. */ #include #include #include #include #include #include #include #include #include #include #include #include #include int main() { uint32_t version = al_get_allegro_version(); int major = version >> 24; int minor = (version >> 16) & 255; int revision = (version >> 8) & 255; int release = version & 255; fprintf(stderr, "Library version: %d.%d.%d.%d\n", major, minor, revision, release); fprintf(stderr, "Header version: %d.%d.%d.%d\n", ALLEGRO_VERSION, ALLEGRO_SUB_VERSION, ALLEGRO_WIP_VERSION, ALLEGRO_RELEASE_NUMBER); fprintf(stderr, "Header version string: %s\n", ALLEGRO_VERSION_STR); if (!al_init()) { fprintf(stderr, "Failed to initialize Allegro, probably a header/shared library version mismatch.\n"); return -1; } #define INIT_CHECK(init_function, addon_name) do { if (!init_function()) { fprintf(stderr, "Failed to initialize the " addon_name " addon.\n"); return -1; } } while (0) INIT_CHECK(al_init_font_addon, "font"); INIT_CHECK(al_init_ttf_addon, "TTF"); INIT_CHECK(al_init_image_addon, "image"); INIT_CHECK(al_install_audio, "audio"); INIT_CHECK(al_init_acodec_addon, "acodec"); INIT_CHECK(al_init_native_dialog_addon, "native dialog"); INIT_CHECK(al_init_primitives_addon, "primitives"); INIT_CHECK(al_init_video_addon, "video"); fprintf(stderr, "Everything looks good!\n"); return 0; } allegro5-5.2.10.1/misc/make_converters.py000077500000000000000000000346301473414355200201650ustar00rootroot00000000000000#!/usr/bin/env python3 import collections, optparse, re, sys formats_by_name = {} formats_list = [] def read_color_h(filename): """ Read in the list of formats. """ formats = [] inside_enum = False for line in open(filename): line = line.strip() if line == "{": continue if line == "typedef enum ALLEGRO_PIXEL_FORMAT": inside_enum = True elif inside_enum: match = re.match(r"\s*ALLEGRO_PIXEL_FORMAT_(\w+)", line) if match: formats.append(match.group(1)) else: break return formats def parse_format(format): """ Parse the format name into an info structure. """ if format.startswith("ANY"): return None if "DXT" in format: return None separator = format.find("_") class Info: pass class Component: pass Info = collections.namedtuple("Info", "components, name, little_endian," "float, single_channel, size") Component = collections.namedtuple("Component", "color, size," "position_from_left, position") pos = 0 info = Info( components={}, name=format, little_endian="_LE" in format, float=False, single_channel=False, size=None, ) if "F32" in format: return info._replace( float=True, size=128, ) if "SINGLE_CHANNEL" in format: return info._replace( single_channel=True, size=8, ) for i in range(separator): c = Component( color=format[i], size=int(format[separator + 1 + i]), position_from_left=pos, position=None, ) info.components[c.color] = c pos += c.size size = pos return info._replace( components={k: c._replace(position=size - c.position_from_left - c.size) for k, c in info.components.items()}, size=size, float=False, ) def macro_lines(info_a, info_b): """ Write out the lines of a conversion macro. """ r = "" names = list(info_b.components.keys()) names.sort() if info_a.float: if info_b.single_channel: return " (uint32_t)((x).r * 255)\n" lines = [] for name in names: if name == "X": continue c = info_b.components[name] mask = (1 << c.size) - 1 lines.append( "((uint32_t)((x)." + name.lower() + " * " + str(mask) + ") << " + str(c.position) + ")") r += " (" r += " | \\\n ".join(lines) r += ")\n" return r if info_b.float: if info_a.single_channel: return " al_map_rgb(x, 0, 0)\n" lines = [] for name in "RGBA": if name not in info_a.components: break c = info_a.components[name] mask = (1 << c.size) - 1 line = "((x) >> " + str(c.position) + ") & " + str(mask) if c.size < 8: line = "_al_rgb_scale_" + str(c.size) + "[" + line + "]" lines.append(line) r += " al_map_rgba(" if len(lines) == 4 else " al_map_rgb(" r += ",\\\n ".join(lines) r += ")\n" return r if info_a.single_channel: lines = [] for name in names: # Only map to R, and let A=1 if name in ["X", "G", "B"]: continue c = info_b.components[name] shift = 8 - c.size - c.position m = hex(((1 << c.size) - 1) << c.position) if name == "A": lines.append(m) continue if shift > 0: lines.append("(((x) >> " + str(shift) + ") & " + m + ")") elif shift < 0: lines.append("(((x) << " + str(-shift) + ") & " + m + ")") else: lines.append("((x) & " + m + ")") r += " (" r += " | \\\n ".join(lines) r += ")\n" return r if info_b.single_channel: c = info_a.components["R"] m = (1 << c.size) - 1 extract = "(((x) >> " + str(c.position) + ") & " + hex(m) + ")" if (c.size != 8): scale = "(_al_rgb_scale_" + str(c.size) + "[" + extract + "])" else: scale = extract r += " " + scale + "\n" return r # Generate a list of (mask, shift, add) tuples for all components. ops = {} for name in names: if name == "X": continue # We simply ignore X components. c_b = info_b.components[name] if name not in info_a.components: # Set A component to all 1 bits if the source doesn't have it. if name == "A": add = (1 << c_b.size) - 1 add <<= c_b.position ops[name] = (0, 0, add, 0, 0, 0) continue c_a = info_a.components[name] mask = (1 << c_b.size) - 1 shift_right = c_a.position mask_pos = c_a.position shift_left = c_b.position bitdiff = c_a.size - c_b.size if bitdiff > 0: shift_right += bitdiff mask_pos += bitdiff else: shift_left -= bitdiff mask = (1 << c_a.size) - 1 mask <<= mask_pos shift = shift_left - shift_right ops[name] = (mask, shift, 0, c_a.size, c_b.size, mask_pos) # Collapse multiple components if possible. common_shifts = {} for name, (mask, shift, add, size_a, size_b, mask_pos) in ops.items(): if not add and not (size_a != 8 and size_b == 8): if shift in common_shifts: common_shifts[shift].append(name) else: common_shifts[shift] = [name] for newshift, colors in common_shifts.items(): if len(colors) == 1: continue newname = "" newmask = 0 colors.sort() masks_pos = [] for name in colors: mask, shift, add, size_a, size_b, mask_pos = ops[name] names.remove(name) newname += name newmask |= mask masks_pos.append(mask_pos) names.append(newname) ops[newname] = (newmask, newshift, 0, size_a, size_b, min(masks_pos)) # Write out a line for each remaining operation. lines = [] add_format = "0x%0" + str(info_b.size >> 2) + "x" mask_format = "0x%0" + str(info_a.size >> 2) + "x" for name in names: if not name in ops: continue mask, shift, add, size_a, size_b, mask_pos = ops[name] if add: line = "(" + (add_format % add) + ")" lines.append((line, name, 0, size_a, size_b, mask_pos)) continue mask_string = "((x) & " + (mask_format % mask) + ")" if (size_a != 8 and size_b == 8): line = "(_al_rgb_scale_" + str(size_a) + "[" + mask_string + " >> %2d" % mask_pos + "]" else: if (shift > 0): line = "(" + mask_string + " << %2d" % shift + ")" elif (shift < 0): line = "(" + mask_string + " >> %2d" % -shift + ")" else: line = mask_string + " " lines.append((line, name, shift, size_a, size_b, mask_pos)) # Concoct the macro. for i in range(len(lines)): line, name, shift, size_a, size_b, mask_pos = lines[i] if i == 0: start = " (" else: start = " " if i == len(lines) - 1: cont = ") " else: cont = " | \\" if size_a != 8 and size_b == 8: shift = shift+(mask_pos-(8-size_a)) if shift > 0: backshift = " << %2d)" % shift elif shift < 0: backshift = " >> %2d)" % -shift else: backshift = " )" else: backshift = " " r += start + line + backshift + " /* " + name + " */" + cont + "\n" return r def converter_macro(info_a, info_b): """ Create a conversion macro. """ if not info_a or not info_b: return None name = "ALLEGRO_CONVERT_" + info_a.name + "_TO_" + info_b.name r = "" if info_a.little_endian or info_b.little_endian: r += "#ifdef ALLEGRO_BIG_ENDIAN\n" r += "#define " + name + "(x) \\\n" if info_a.name == "ABGR_8888_LE": r += macro_lines(formats_by_name["RGBA_8888"], info_b) elif info_b.name == "ABGR_8888_LE": r += macro_lines(info_a, formats_by_name["RGBA_8888"]) else: r += "#error Conversion %s -> %s not understood by make_converters.py\n" % ( info_a.name, info_b.name) r += "#else\n" r += "#define " + name + "(x) \\\n" r += macro_lines(info_a, info_b) r += "#endif\n" else: r += "#define " + name + "(x) \\\n" r += macro_lines(info_a, info_b) return r def write_convert_h(filename): """ Create the file with all the conversion macros. """ f = open(filename, "w") f.write("""\ // Warning: This file was created by make_converters.py - do not edit. #ifndef __al_included_allegro5_aintern_convert_h #define __al_included_allegro5_aintern_convert_h #include "allegro5/allegro.h" #include "allegro5/internal/aintern_pixels.h" """) for a in formats_list: for b in formats_list: if b == a: continue macro = converter_macro(a, b) if macro: f.write(macro) f.write("""\ #endif // Warning: This file was created by make_converters.py - do not edit. """) def converter_function(info_a, info_b): """ Create a string with one conversion function. """ name = info_a.name.lower() + "_to_" + info_b.name.lower() params = "const void *src, int src_pitch,\n" params += " void *dst, int dst_pitch,\n" params += " int sx, int sy, int dx, int dy, int width, int height" declaration = "static void " + name + "(" + params + ")" macro_name = "ALLEGRO_CONVERT_" + info_a.name + "_TO_" + info_b.name types_and_sizes = { 8 : ("uint8_t", "", 1), 15 : ("uint16_t", "", 2), 16 : ("uint16_t", "", 2), 24: ("uint8_t", " * 3", 1), 32 : ("uint32_t", "", 4), 128 : ("ALLEGRO_COLOR", "", 16)} a_type, a_count, a_size = types_and_sizes[info_a.size] b_type, b_count, b_size = types_and_sizes[info_b.size] if a_count == "" and b_count == "": conversion = """\ *dst_ptr = %(macro_name)s(*src_ptr); dst_ptr++; src_ptr++;""" % locals() else: if a_count != "": s_conversion = """\ #ifdef ALLEGRO_BIG_ENDIAN int src_pixel = src_ptr[2] | (src_ptr[1] << 8) | (src_ptr[0] << 16); #else int src_pixel = src_ptr[0] | (src_ptr[1] << 8) | (src_ptr[2] << 16); #endif """ % locals() if b_count != "": d_conversion = """\ #ifdef ALLEGRO_BIG_ENDIAN dst_ptr[0] = dst_pixel >> 16; dst_ptr[1] = dst_pixel >> 8; dst_ptr[2] = dst_pixel; #else dst_ptr[0] = dst_pixel; dst_ptr[1] = dst_pixel >> 8; dst_ptr[2] = dst_pixel >> 16; #endif """ % locals() if a_count != "" and b_count != "": conversion = s_conversion + ("""\ int dst_pixel = %(macro_name)s(src_pixel); """ % locals()) + d_conversion elif a_count != "": conversion = s_conversion + ("""\ *dst_ptr = %(macro_name)s(src_pixel); """ % locals()) else: conversion = ("""\ int dst_pixel = %(macro_name)s(*src_ptr); """ % locals()) + d_conversion conversion += """\ src_ptr += 1%(a_count)s; dst_ptr += 1%(b_count)s;""" % locals() r = declaration + "\n" r += "{\n" r += """\ int y; const %(a_type)s *src_ptr = (const %(a_type)s *)((const char *)src + sy * src_pitch); %(b_type)s *dst_ptr = (void *)((char *)dst + dy * dst_pitch); int src_gap = src_pitch / %(a_size)d - width%(a_count)s; int dst_gap = dst_pitch / %(b_size)d - width%(b_count)s; src_ptr += sx%(a_count)s; dst_ptr += dx%(b_count)s; for (y = 0; y < height; y++) { %(b_type)s *dst_end = dst_ptr + width%(b_count)s; while (dst_ptr < dst_end) { %(conversion)s } src_ptr += src_gap; dst_ptr += dst_gap; } """ % locals() r += "}\n" return r def write_convert_c(filename): """ Write out the file with the conversion functions. """ f = open(filename, "w") f.write("""\ // Warning: This file was created by make_converters.py - do not edit. #include "allegro5/allegro.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_convert.h" """) for a in formats_list: for b in formats_list: if b == a: continue if not a or not b: continue function = converter_function(a, b) f.write(function) f.write("""\ void (*_al_convert_funcs[ALLEGRO_NUM_PIXEL_FORMATS] [ALLEGRO_NUM_PIXEL_FORMATS])(const void *, int, void *, int, int, int, int, int, int, int) = { """) for a in formats_list: if not a: f.write(" {NULL},\n") else: f.write(" {") was_null = False for b in formats_list: if b and a != b: name = a.name.lower() + "_to_" + b.name.lower() f.write("\n " + name + ",") was_null = False else: if not was_null: f.write("\n ") f.write(" NULL,") was_null = True f.write("\n },\n") f.write("""\ }; // Warning: This file was created by make_converters.py - do not edit. """) def main(argv): global options p = optparse.OptionParser() p.description = """\ When run from the toplevel A5 folder, this will re-create the convert.h and convert.c files containing all the low-level color conversion macros and functions.""" options, args = p.parse_args() # Read in color.h to get the available formats. formats = read_color_h("include/allegro5/color.h") print(formats) # Parse the component info for each format. for f in formats: info = parse_format(f) formats_by_name[f] = info formats_list.append(info) # Output a macro for each possible conversion. write_convert_h("include/allegro5/internal/aintern_convert.h") # Output a function for each possible conversion. write_convert_c("src/convert.c") if __name__ == "__main__": main(sys.argv) # vim: set sts=4 sw=4 et: allegro5-5.2.10.1/misc/make_icon.py000077500000000000000000000016661473414355200167260ustar00rootroot00000000000000#!/usr/bin/env python3 """Generate the icon.c file used for the default icon. Usage: make_icon.py in_file.png out_file.inc """ import numpy as np import PIL.Image import sys image = np.array(PIL.Image.open(sys.argv[1]).convert("RGBA")) with open(sys.argv[2], "w") as f: f.write("/* Generated using make_icon.py */\n") f.write(f"#define ICON_WIDTH {image.shape[1]}\n") f.write(f"#define ICON_HEIGHT {image.shape[0]}\n") f.write("static uint32_t icon_data[] = {\n") for i, row in enumerate(image): for j, col in enumerate(row): # Premultiply alpha. col = col.astype(np.float32) / 255. col = (col * col[-1] * 255.).astype(np.uint32) col = (col[0] << 24) + (col[1] << 16) + (col[2] << 8) + col[3] f.write(f"{col:#010x}") if i + 1 < image.shape[0] or j + 1 < image.shape[1]: f.write(",") f.write("\n") f.write("};\n") allegro5-5.2.10.1/misc/make_mixer_helpers.py000077500000000000000000000225741473414355200206450ustar00rootroot00000000000000#!/usr/bin/env python3 # # Run: # misc/make_mixer_helpers.py | indent -kr -i3 -l0 import sys, re # http://code.activestate.com/recipes/502257/ def interp(string): locals = sys._getframe(1).f_locals globals = sys._getframe(1).f_globals for item in re.findall(r'#\{([^}]*)\}', string): string = string.replace('#{%s}' % item, str(eval(item, globals, locals))) return string class Depth: def index(self, fmt): if fmt == "f32": return self.index_f32 if fmt == "s16": return self.index_s16 class Depth_f32(Depth): def constant(self): return "ALLEGRO_AUDIO_DEPTH_FLOAT32" def index_f32(self, buf, index): return interp("#{buf}.f32[ #{index} ]") def index_s16(self, buf, index): return interp("(int16_t) (#{buf}.f32[ #{index} ] * 0x7FFF)") class Depth_int24(Depth): def constant(self): return "ALLEGRO_AUDIO_DEPTH_INT24" def index_f32(self, buf, index): return interp("(float) #{buf}.s24[ #{index} ] / ((float)0x7FFFFF + 0.5f)") def index_s16(self, buf, index): return interp("(int16_t) (#{buf}.s24[ #{index} ] >> 9)") class Depth_uint24(Depth): def constant(self): return "ALLEGRO_AUDIO_DEPTH_UINT24" def index_f32(self, buf, index): return interp("(float) #{buf}.u24[ #{index} ] / ((float)0x7FFFFF + 0.5f) - 1.0f") def index_s16(self, buf, index): return interp("(int16_t) ((#{buf}.u24[ #{index} ] - 0x800000) >> 9)") class Depth_int16(Depth): def constant(self): return "ALLEGRO_AUDIO_DEPTH_INT16" def index_f32(self, buf, index): return interp("(float) #{buf}.s16[ #{index} ] / ((float)0x7FFF + 0.5f)") def index_s16(self, buf, index): return interp("#{buf}.s16[ #{index} ]") class Depth_uint16(Depth): def constant(self): return "ALLEGRO_AUDIO_DEPTH_UINT16" def index_f32(self, buf, index): return interp("(float) #{buf}.u16[ #{index} ] / ((float)0x7FFF + 0.5f) - 1.0f") def index_s16(self, buf, index): return interp("(int16_t) (#{buf}.u16[ #{index} ] - 0x8000)") class Depth_int8(Depth): def constant(self): return "ALLEGRO_AUDIO_DEPTH_INT8" def index_f32(self, buf, index): return interp("(float) #{buf}.s8[ #{index} ] / ((float)0x7F + 0.5f)") def index_s16(self, buf, index): return interp("(int16_t) #{buf}.s8[ #{index} ] << 7") class Depth_uint8(Depth): def constant(self): return "ALLEGRO_AUDIO_DEPTH_UINT8" def index_f32(self, buf, index): return interp("(float) #{buf}.u8[ #{index} ] / ((float)0x7F + 0.5f) - 1.0f") def index_s16(self, buf, index): return interp("(int16_t) (#{buf}.u8[ #{index} ] - 0x80) << 7") depths = [ Depth_f32(), Depth_int24(), Depth_uint24(), Depth_int16(), Depth_uint16(), Depth_int8(), Depth_uint8() ] def make_point_interpolator(name, fmt): print(interp("""\ static INLINE const void * #{name} (SAMP_BUF *samp_buf, const ALLEGRO_SAMPLE_INSTANCE *spl, unsigned int maxc) { unsigned int i0 = spl->pos*maxc; unsigned int i; switch (spl->spl_data.depth) { """)) for depth in depths: buf_index = depth.index(fmt)("spl->spl_data.buffer", "i0 + i") print(interp("""\ case #{depth.constant()}: for (i = 0; i < maxc; i++) { samp_buf-> #{fmt} [i] = #{buf_index}; } break; """)) print(interp("""\ } return samp_buf-> #{fmt} ; }""")) def make_linear_interpolator(name, fmt): assert fmt == "f32" or fmt == "s16" print(interp("""\ static INLINE const void * #{name} (SAMP_BUF *samp_buf, const ALLEGRO_SAMPLE_INSTANCE *spl, unsigned int maxc) { int p0 = spl->pos; int p1 = spl->pos+1; switch (spl->loop) { case ALLEGRO_PLAYMODE_ONCE: if (p1 >= spl->spl_data.len) p1 = p0; break; case ALLEGRO_PLAYMODE_LOOP_ONCE: case ALLEGRO_PLAYMODE_LOOP: if (p1 >= spl->loop_end) p1 = spl->loop_start; break; case ALLEGRO_PLAYMODE_BIDIR: if (p1 >= spl->loop_end) { p1 = spl->loop_end - 1; if (p1 < spl->loop_start) p1 = spl->loop_start; } break; case _ALLEGRO_PLAYMODE_STREAM_ONCE: case _ALLEGRO_PLAYMODE_STREAM_LOOP_ONCE: case _ALLEGRO_PLAYMODE_STREAM_ONEDIR:""" + # For audio streams, sample i+1 may be in the next buffer fragment, # which may not even be generated yet. So we lag by one sample and # interpolate between sample i-1 and sample i. # # We arrange the buffers in memory such that indexing i-1 is always # valid, even after wrapping around from the last buffer fragment to # the first buffer fragment. See _al_kcm_refill_stream. """ p0--; p1--; break; } p0 *= maxc; p1 *= maxc; switch (spl->spl_data.depth) { """)) for depth in depths: x0 = depth.index(fmt)("spl->spl_data.buffer", "p0 + i") x1 = depth.index(fmt)("spl->spl_data.buffer", "p1 + i") print(interp("""\ case #{depth.constant()}: {""")) if fmt == "f32": print(interp("""\ const float t = (float)spl->pos_bresenham_error / spl->step_denom; int i; for (i = 0; i < (int)maxc; i++) { const float x0 = #{x0}; const float x1 = #{x1}; const float s = (x0 * (1.0f - t)) + (x1 * t); samp_buf->f32[i] = s; }""")) elif fmt == "s16": print(interp("""\ const int32_t t = 256 * spl->pos_bresenham_error / spl->step_denom; int i; for (i = 0; i < (int)maxc; i++) { const int32_t x0 = #{x0}; const int32_t x1 = #{x1}; const int32_t s = ((x0 * (256 - t))>>8) + ((x1 * t)>>8); samp_buf->s16[i] = (int16_t)s; }""")) print(interp("""\ } break; """)) print(interp("""\ } return samp_buf-> #{fmt}; }""")) def make_cubic_interpolator(name, fmt): assert fmt == "f32" print(interp("""\ static INLINE const void * #{name} (SAMP_BUF *samp_buf, const ALLEGRO_SAMPLE_INSTANCE *spl, unsigned int maxc) { int p0 = spl->pos-1; int p1 = spl->pos; int p2 = spl->pos+1; int p3 = spl->pos+2; switch (spl->loop) { case ALLEGRO_PLAYMODE_ONCE: if (p0 < 0) p0 = 0; if (p2 >= spl->spl_data.len) p2 = spl->spl_data.len - 1; if (p3 >= spl->spl_data.len) p3 = spl->spl_data.len - 1; break; case ALLEGRO_PLAYMODE_LOOP_ONCE: case ALLEGRO_PLAYMODE_LOOP: case ALLEGRO_PLAYMODE_BIDIR: /* These positions should really wrap/bounce instead of clamping * but it's probably unnoticeable. */ if (p0 < spl->loop_start) p0 = spl->loop_end - 1; if (p2 >= spl->loop_end) p2 = spl->loop_start; if (p3 >= spl->loop_end) p3 = spl->loop_start; break; case _ALLEGRO_PLAYMODE_STREAM_ONCE: case _ALLEGRO_PLAYMODE_STREAM_LOOP_ONCE: case _ALLEGRO_PLAYMODE_STREAM_ONEDIR: /* Lag by three samples in total. */ p0 -= 2; p1 -= 2; p2 -= 2; p3 -= 2; break; } p0 *= maxc; p1 *= maxc; p2 *= maxc; p3 *= maxc; switch (spl->spl_data.depth) { """)) for depth in depths: value0 = depth.index(fmt)("spl->spl_data.buffer", "p0 + i") value1 = depth.index(fmt)("spl->spl_data.buffer", "p1 + i") value2 = depth.index(fmt)("spl->spl_data.buffer", "p2 + i") value3 = depth.index(fmt)("spl->spl_data.buffer", "p3 + i") # 4-point, cubic Hermite interpolation # Code transcribed from "Polynomial Interpolators for High-Quality # Resampling of Oversampled Audio" by Olli Niemitalo # http://yehar.com/blog/?p=197 print(interp("""\ case #{depth.constant()}: { const float t = (float)spl->pos_bresenham_error / spl->step_denom; signed int i; for (i = 0; i < (signed int)maxc; i++) { float x0 = #{value0}; float x1 = #{value1}; float x2 = #{value2}; float x3 = #{value3}; float c0 = x1; float c1 = 0.5f * (x2 - x0); float c2 = x0 - (2.5f * x1) + (2.0f * x2) - (0.5f * x3); float c3 = (0.5f * (x3 - x0)) + (1.5f * (x1 - x2)); float s = (((((c3 * t) + c2) * t) + c1) * t) + c0; samp_buf->f32[i] = s; } } break; """)) print(interp("""\ } return samp_buf-> #{fmt} ; }""")) if __name__ == "__main__": print("// Warning: This file was created by make_resamplers.py - do not edit.") print("// vim: set ft=c:") make_point_interpolator("point_spl32", "f32") make_point_interpolator("point_spl16", "s16") make_linear_interpolator("linear_spl32", "f32") make_linear_interpolator("linear_spl16", "s16") make_cubic_interpolator("cubic_spl32", "f32") # vim: set sts=3 sw=3 et: allegro5-5.2.10.1/misc/make_pixel_tables.py000077500000000000000000000024351473414355200204440ustar00rootroot00000000000000#!/usr/bin/env python3 import optparse, sys def main(argv): p = optparse.OptionParser() p.description = ("When run from the toplevel A5 folder, this will " "re-create the src/pixel_tables.inc.""") p.parse_args() with open("src/pixel_tables.inc", "w") as f: f.write("""// Warning: This file was created by make_pixel_tables.py - do not edit. """); f.write("float _al_u8_to_float[] = {\n") for i in range(256): f.write(f" {i / 255.0},\n") f.write("};\n\n") f.write("int _al_rgb_scale_1[] = {\n") for i in range(2): f.write(f" {i * 255 // 1},\n") f.write("};\n\n") f.write("int _al_rgb_scale_4[] = {\n") for i in range(16): f.write(f" {i * 255 // 15},\n") f.write("};\n\n") f.write("int _al_rgb_scale_5[] = {\n") for i in range(32): f.write(f" {i * 255 // 31},\n") f.write("};\n\n") f.write("int _al_rgb_scale_6[] = {\n") for i in range(64): f.write(f" {i * 255 // 63},\n") f.write("};\n\n") f.write("""// Warning: This file was created by make_pixel_tables.py - do not edit. """); if __name__ == "__main__": main(sys.argv) allegro5-5.2.10.1/misc/make_scanline_drawers.py000077500000000000000000000360771473414355200213250ustar00rootroot00000000000000#!/usr/bin/env python3 # # Generate the routines to draw each scanline of a primitive. # Run: # misc/make_scanline_drawers.py | indent -kr -i3 -l0 > src/scanline_drawers.inc import sys, re # http://code.activestate.com/recipes/502257/ def interp(string): locals = sys._getframe(1).f_locals globals = sys._getframe(1).f_globals for item in re.findall(r'#\{([^}]*)\}', string): string = string.replace('#{%s}' % item, str(eval(item, globals, locals))) return string def make_drawer(name): global texture, grad, solid, shade, opaque, white texture = "_texture_" in name grad = "_grad_" in name solid = "_solid_" in name shade = "_shade" in name opaque = "_opaque" in name white = "_white" in name repeat = "_repeat" in name if grad and solid: raise Exception("grad and solid") if grad and white: raise Exception("grad and white") if shade and opaque: raise Exception("shade and opaque") print(interp("static void #{name} (uintptr_t state, int x1, int y, int x2) {")) if not texture: if grad: print("""\ state_grad_any_2d *gs = (state_grad_any_2d *)state; state_solid_any_2d *s = &gs->solid; ALLEGRO_COLOR cur_color = s->cur_color; """) else: print("""\ state_solid_any_2d *s = (state_solid_any_2d *)state; ALLEGRO_COLOR cur_color = s->cur_color; """) else: if grad: print("""\ state_texture_grad_any_2d *gs = (state_texture_grad_any_2d *)state; state_texture_solid_any_2d *s = &gs->solid; ALLEGRO_COLOR cur_color = s->cur_color; """) else: print("""\ state_texture_solid_any_2d *s = (state_texture_solid_any_2d *)state; """) print("""\ float u = s->u; float v = s->v; """) # XXX still don't understand why y-1 is required print("""\ ALLEGRO_BITMAP *target = s->target; if (target->parent) { x1 += target->xofs; x2 += target->xofs; y += target->yofs; target = target->parent; } x1 -= target->lock_x; x2 -= target->lock_x; y -= target->lock_y; y--; if (y < 0 || y >= target->lock_h) { return; } if (x1 < 0) { """) if texture: print("""\ u += s->du_dx * -x1; v += s->dv_dx * -x1; """) if grad: print("""\ cur_color.r += gs->color_dx.r * -x1; cur_color.g += gs->color_dx.g * -x1; cur_color.b += gs->color_dx.b * -x1; cur_color.a += gs->color_dx.a * -x1; """) print("""\ x1 = 0; } if (x2 > target->lock_w - 1) { x2 = target->lock_w - 1; } """) print("{") if shade: print("""\ int op, src_mode, dst_mode; int op_alpha, src_alpha, dst_alpha; ALLEGRO_COLOR const_color; al_get_separate_bitmap_blender(&op, &src_mode, &dst_mode, &op_alpha, &src_alpha, &dst_alpha); const_color = al_get_blend_color(); """) print("{") if texture: print("""\ const int offset_x = s->texture->parent ? s->texture->xofs : 0; const int offset_y = s->texture->parent ? s->texture->yofs : 0; ALLEGRO_BITMAP* texture = s->texture->parent ? s->texture->parent : s->texture; const int src_format = texture->locked_region.format; const int src_size = texture->locked_region.pixel_size; ALLEGRO_BITMAP_WRAP wrap_u, wrap_v; _al_get_bitmap_wrap(texture, &wrap_u, &wrap_v); int tile_u = (int)(floorf(u / s->w)); int tile_v = (int)(floorf(v / s->h)); /* Ensure u in [0, s->w) and v in [0, s->h). */ while (u < 0) u += s->w; while (v < 0) v += s->h; u = fmodf(u, s->w); v = fmodf(v, s->h); ASSERT(0 <= u); ASSERT(u < s->w); ASSERT(0 <= v); ASSERT(v < s->h); """) print("{") print("""\ const int dst_format = target->locked_region.format; uint8_t *dst_data = (uint8_t *)target->lock_data + y * target->locked_region.pitch + x1 * target->locked_region.pixel_size; """) if shade: make_if_blender_loop( op='ALLEGRO_ADD', src_mode='ALLEGRO_ONE', src_alpha='ALLEGRO_ONE', op_alpha='ALLEGRO_ADD', dst_mode='ALLEGRO_INVERSE_ALPHA', dst_alpha='ALLEGRO_INVERSE_ALPHA', const_color='NULL', if_format='ALLEGRO_PIXEL_FORMAT_ARGB_8888', alpha_only=True, repeat=repeat, ) print("else") make_if_blender_loop( op='ALLEGRO_ADD', src_mode='ALLEGRO_ALPHA', src_alpha='ALLEGRO_ALPHA', op_alpha='ALLEGRO_ADD', dst_mode='ALLEGRO_INVERSE_ALPHA', dst_alpha='ALLEGRO_INVERSE_ALPHA', const_color='NULL', if_format='ALLEGRO_PIXEL_FORMAT_ARGB_8888', alpha_only=True, repeat=repeat, ) print("else") make_if_blender_loop( op='ALLEGRO_ADD', src_mode='ALLEGRO_ONE', src_alpha='ALLEGRO_ONE', op_alpha='ALLEGRO_ADD', dst_mode='ALLEGRO_ONE', dst_alpha='ALLEGRO_ONE', const_color='NULL', if_format='ALLEGRO_PIXEL_FORMAT_ARGB_8888', alpha_only=True, repeat=repeat, ) print("else") if opaque and white: make_loop(copy_format=True, src_size='4') print("else") make_loop(copy_format=True, src_size='3') print("else") make_loop(copy_format=True, src_size='2') print("else") else: make_loop( if_format='ALLEGRO_PIXEL_FORMAT_ARGB_8888' ) print("else") make_loop() print("""\ } } } } """) def make_if_blender_loop( op='op', src_mode='src_mode', dst_mode='dst_mode', op_alpha='op_alpha', src_alpha='src_alpha', dst_alpha='dst_alpha', src_format='src_format', dst_format='dst_format', const_color='NULL', if_format=None, alpha_only=False, repeat=False, ): print(interp("""\ if (op == #{op} && src_mode == #{src_mode} && src_alpha == #{src_alpha} && op_alpha == #{op_alpha} && dst_mode == #{dst_mode} && dst_alpha == #{dst_alpha}) { """)) if texture and if_format: make_loop( op=op, src_mode=src_mode, src_alpha=src_alpha, op_alpha=op_alpha, dst_mode=dst_mode, dst_alpha=dst_alpha, const_color=const_color, if_format=if_format, alpha_only=alpha_only, repeat=repeat, ) print("else") make_loop( op=op, src_mode=src_mode, src_alpha=src_alpha, op_alpha=op_alpha, dst_mode=dst_mode, dst_alpha=dst_alpha, const_color=const_color, alpha_only=alpha_only, repeat=repeat, ) print("}") def make_loop( op='op', src_mode='src_mode', dst_mode='dst_mode', op_alpha='op_alpha', src_alpha='src_alpha', dst_alpha='dst_alpha', src_format='src_format', dst_format='dst_format', src_size='src_size', const_color='&const_color', if_format=None, copy_format=False, alpha_only=False, repeat=False, ): if if_format: src_format = if_format dst_format = if_format print(interp("if (dst_format == #{dst_format}")) if texture: print(interp("&& src_format == #{src_format}")) print(")") elif copy_format: assert opaque and white print(interp("if (dst_format == src_format && src_size == #{src_size})")) print("{") if texture: print("""\ uint8_t *lock_data = texture->locked_region.data; const int src_pitch = texture->locked_region.pitch; const al_fixed du_dx = al_ftofix(s->du_dx); const al_fixed dv_dx = al_ftofix(s->dv_dx); """) if opaque: # If texture coordinates never wrap around then we can simplify the # innermost loop. It doesn't seem to have so great an impact when the # loop is complicated by blending. print("""\ const float steps = x2 - x1 + 1; const float end_u = u + steps * s->du_dx; const float end_v = v + steps * s->dv_dx; if (end_u >= 0 && end_u < s->w && end_v >= 0 && end_v < s->h) { """) make_innermost_loop( op=op, src_mode=src_mode, dst_mode=dst_mode, op_alpha=op_alpha, src_alpha=src_alpha, dst_alpha=dst_alpha, src_format=src_format, dst_format=dst_format, const_color=const_color, src_size=src_size, copy_format=copy_format, tiling=False, alpha_only=alpha_only, repeat=repeat, ) print("} else") make_innermost_loop( op=op, src_mode=src_mode, dst_mode=dst_mode, op_alpha=op_alpha, src_alpha=src_alpha, dst_alpha=dst_alpha, src_format=src_format, dst_format=dst_format, const_color=const_color, src_size=src_size, copy_format=copy_format, alpha_only=alpha_only, repeat=repeat, ) print("}") def make_innermost_loop( op='op', src_mode='src_mode', dst_mode='dst_mode', op_alpha='op_alpha', src_alpha='src_alpha', dst_alpha='dst_alpha', src_format='src_format', dst_format='dst_format', const_color='&const_color', src_size='src_size', copy_format=False, tiling=True, alpha_only=True, repeat=False, ): print("{") if texture: # In non-tiling mode we can hoist offsets out of the loop. if tiling: print("""\ al_fixed uu = al_ftofix(u); al_fixed vv = al_ftofix(v); const int uu_ofs = offset_x - texture->lock_x; const int vv_ofs = offset_y - texture->lock_y; const al_fixed w = al_ftofix(s->w); const al_fixed h = al_ftofix(s->h); """) uu_ofs = "uu_ofs" vv_ofs = "vv_ofs" else: print("""\ al_fixed uu = al_ftofix(u) + ((offset_x - texture->lock_x) << 16); al_fixed vv = al_ftofix(v) + ((offset_y - texture->lock_y) << 16); """) uu_ofs = vv_ofs = "0" print("for (; x1 <= x2; x1++) {") if not texture: print("""\ ALLEGRO_COLOR src_color = cur_color; """) else: print(interp("""\ int src_x = (uu >> 16) + #{uu_ofs}; int src_y = (vv >> 16) + #{vv_ofs}; """)); if not repeat: print("""\ switch (wrap_u) { case ALLEGRO_BITMAP_WRAP_CLAMP: if (tile_u < 0) src_x = 0; if (tile_u > 0) src_x = s->w - 1; break; case ALLEGRO_BITMAP_WRAP_MIRROR: if (tile_u % 2) src_x = s->w - 1 - src_x; // REPEAT and DEFAULT. default: break; } switch (wrap_v) { case ALLEGRO_BITMAP_WRAP_CLAMP: if (tile_v < 0) src_y = 0; if (tile_v > 0) src_y = s->h - 1; break; case ALLEGRO_BITMAP_WRAP_MIRROR: if (tile_v % 2) src_y = s->h - 1 - src_y; // REPEAT and DEFAULT. default: break; } """) print(interp("""\ uint8_t *src_data = lock_data + src_y * src_pitch + src_x * #{src_size}; """)) if copy_format: pass else: print(interp("""\ ALLEGRO_COLOR src_color; _AL_INLINE_GET_PIXEL(#{src_format}, src_data, src_color, false); """)) if grad: print("""\ SHADE_COLORS(src_color, cur_color); """) elif not white: print("""\ SHADE_COLORS(src_color, s->cur_color); """) if copy_format: print(interp("""\ switch (#{src_size}) { case 4: memcpy(dst_data, src_data, 4); dst_data += 4; break; case 3: memcpy(dst_data, src_data, 3); dst_data += 3; break; case 2: *dst_data++ = *src_data++; *dst_data++ = *src_data; break; case 1: *dst_data++ = *src_data; break; } """)) elif shade: blend = "_al_blend_inline" if alpha_only: blend = "_al_blend_alpha_inline" print(interp("""\ { ALLEGRO_COLOR dst_color; ALLEGRO_COLOR result; _AL_INLINE_GET_PIXEL(#{dst_format}, dst_data, dst_color, false); #{blend}(&src_color, &dst_color, #{op}, #{src_mode}, #{dst_mode}, #{op_alpha}, #{src_alpha}, #{dst_alpha}, #{const_color}, &result); _AL_INLINE_PUT_PIXEL(#{dst_format}, dst_data, result, true); } """)) else: print(interp("""\ _AL_INLINE_PUT_PIXEL(#{dst_format}, dst_data, src_color, true); """)) if texture: print("""\ uu += du_dx; vv += dv_dx; """) if tiling: print("""\ if (_AL_EXPECT_FAIL(uu < 0)) { uu += w; tile_u--; } else if (_AL_EXPECT_FAIL(uu >= w)) { uu -= w; tile_u++; } if (_AL_EXPECT_FAIL(vv < 0)) { vv += h; tile_v--; } else if (_AL_EXPECT_FAIL(vv >= h)) { vv -= h; tile_v++; } """) if grad: print("""\ cur_color.r += gs->color_dx.r; cur_color.g += gs->color_dx.g; cur_color.b += gs->color_dx.b; cur_color.a += gs->color_dx.a; """) print("""\ } }""") if __name__ == "__main__": print("""\ // Warning: This file was created by make_scanline_drawers.py - do not edit. #if __GNUC__ #define _AL_EXPECT_FAIL(expr) __builtin_expect((expr), 0) #else #define _AL_EXPECT_FAIL(expr) (expr) #endif """) make_drawer("shader_solid_any_draw_shade") make_drawer("shader_solid_any_draw_opaque") make_drawer("shader_grad_any_draw_shade") make_drawer("shader_grad_any_draw_opaque") make_drawer("shader_texture_solid_any_draw_shade") make_drawer("shader_texture_solid_any_draw_shade_repeat") make_drawer("shader_texture_solid_any_draw_shade_white") make_drawer("shader_texture_solid_any_draw_shade_white_repeat") make_drawer("shader_texture_solid_any_draw_opaque") make_drawer("shader_texture_solid_any_draw_opaque_white") make_drawer("shader_texture_grad_any_draw_shade") make_drawer("shader_texture_grad_any_draw_opaque") # vim: set sts=3 sw=3 et: allegro5-5.2.10.1/misc/mkunixdists.sh000077500000000000000000000113231473414355200173340ustar00rootroot00000000000000#!/bin/sh ################################################################ # mkunixdists.sh -- shell script to generate Unix distributions # # Usage: mkunixdists.sh [.zip] [tmpdir] # # This generates all the Unix-specific distributions. The # existing ZIP format is fine on Unix too, but we'll generate # here a .tar.gz in Unix format (no `fix.sh unix' necessary) and # also an end-user distribution which just creates and installs # the library, without examples, documentation, etc. I suppose # there's a danger that people will download this as a cut-down # development version, but if we shoot those people then this # problem will be solved. This script might need a lot of disk # space, but no more than the existing zipup.sh needs. :) ################################################################ # First process the arguments if [ $# -lt 1 -o $# -gt 2 ]; then echo "Usage: mkunixdists.sh [.zip] [tmpdir]" exit 1 fi # Sort out `dir', adding a trailing `/' if necessary if [ $# -gt 1 ]; then dir=$(echo "$2" | sed -e 's/\([^/]\)$/\0\//').tmp else dir=.tmp fi ################################################################ # Error reporter error() { echo "Error occured, aborting" ; rm -rf $dir ; exit 1 } ################################################################ # Unzip the archive and convert line endings mkdir $dir || error echo "Unzipping $1 to $dir" unzip -qq $1 -d $dir || error echo "Running 'convert_line_endings.sh --dtou'" (cd $dir/allegro && rm -f makefile && sh misc/convert_line_endings.sh --dtou >/dev/null ) || error echo "Checking version number" # Derive version number from the archive name, as the number in # CMakeLists.txt won't reflect the fourth version digit. version=$( echo $1 | sed -e 's/^allegro-// ; s/\.zip$//' ) test -n "$version" || error basename="allegro-$version" basename2="allegro-enduser-$version" echo "Renaming 'allegro' to '$basename'" mv $dir/allegro $dir/$basename || error ################################################################ # Make .tar.gz distributions mktargz() { echo "Creating $1.tar" (cd $dir && tar -cf - $basename) > $1.tar || error echo "gzipping to $1.tar.gz" gzip $1.tar || error } # Create the developers' archive mktargz $basename # Hack'n'slash # XXX end-user distribution is useless while we are in WIP mode # This code is outdated anyway. if false then echo "Stripping to form end-user distribution" (cd $dir/$basename && { (cd src && rm -rf beos qnx dos mac ppc win) (cd obj && rm -rf bcc32 beos qnx djgpp mingw32 msvc watcom) (cd lib && rm -rf bcc32 beos qnx djgpp mingw32 msvc watcom) (cd include && rm -f bealleg.h qnxalleg.h winalleg.h) (cd misc && rm -f cmplog.pl dllsyms.lst findtext.sh fixpatch.sh fixver.sh) (cd misc && rm -f allegro-config-qnx.sh zipup.sh zipwin.sh *.bat *.c) mkdir .saveme cp readme.txt docs/build/unix.txt docs/build/linux.txt .saveme rm -rf demo docs examples resource setup tests tools rm -f AUTHORS CHANGES THANKS *.txt fix* indent* readme.* allegro.mft rm -f makefile.all makefile.be makefile.qnx makefile.bcc makefile.dj rm -f makefile.mgw makefile.mpw makefile.vc makefile.wat makefile.tst rm -f xmake.sh rm -f keyboard.dat language.dat mv .saveme/* . rmdir .saveme { # Tweak makefile.in cp makefile.in makefile.old && cat makefile.old | sed -e "s/INSTALL_TARGETS = .*/INSTALL_TARGETS = mini-install/" | sed -e "s/DEFAULT_TARGETS = .*/DEFAULT_TARGETS = lib modules/" | cat > makefile.in && rm -f makefile.old } }) # Create the end users' archive mktargz $basename2 fi # false ################################################################ # Create SRPM distribution # # We don't actually create the binary RPMs here, since that # will really need to be done on many different machines. # Instead we'll build the source RPM. # # This requires you to have Red Hat's default RPM build system # properly set up, so we'll skip it if that's not the case. # XXX SRPMs disabled because they must be broken by now # Also, they are useless. if false then rpmdir= [ -d /usr/src/redhat ] && rpmdir=/usr/src/redhat [ -d /usr/src/packages ] && rpmdir=/usr/src/packages [ -d /usr/src/RPM ] && rpmdir=/usr/src/RPM [ -d /usr/src/rpm ] && rpmdir=/usr/src/rpm if [ -n "$rpmdir" ]; then echo "Creating SRPM" echo "Enter your root password if prompted" su -c "(\ cp -f $basename.tar.gz $rpmdir/SOURCES ;\ cp -f $dir/$basename/misc/icon.xpm $rpmdir/SOURCES ;\ rpm -bs $dir/$basename/misc/allegro.spec ;\ mv -f $rpmdir/SRPMS/allegro-*.rpm . ;\ rm -f $rpmdir/SOURCES/icon.xpm ;\ rm -f $rpmdir/SOURCES/$basename.tar.gz ;\ )" fi fi # false ################################################################ # All done! rm -rf $dir echo "All done!" allegro5-5.2.10.1/misc/msvchelp.c000066400000000000000000000025741473414355200164100ustar00rootroot00000000000000#define WIN32_LEAN_AND_MEAN #include #include #include #define MAKEFILE_HELPER_FILENAME "makefile.helper" int main(int argc, char *argv[]) { char shortfilename[MAX_PATH]; char *longfilename; int ret; FILE *fout; if (argc != 2) { fprintf(stderr, "msvchelp: No argument given!\n"); return 1; } longfilename = getenv(argv[1]); if (longfilename == NULL) { fprintf(stderr, "msvchelp: Given argument does not correspond to any enviroment variable name!\n"); return 2; } ret = GetShortPathName(longfilename, shortfilename, MAX_PATH); if (ret == 0 || ret > MAX_PATH) { fprintf(stderr, "msvchelp: Cannot convert to short name!\n"); return 3; } fout = fopen(MAKEFILE_HELPER_FILENAME, "wt"); if (fout == NULL) { fprintf(stderr, "msvchelp: Cannot create output file '%s'!\n", MAKEFILE_HELPER_FILENAME); return 4; } ret = fprintf(fout, "%s = %s\n", argv[1], shortfilename); if (ret < 0) { fprintf(stderr, "msvchelp: Cannot write to the output file '%s'!\n", MAKEFILE_HELPER_FILENAME); return 5; } ret = fclose(fout); if (ret != 0) { fprintf(stderr, "msvchelp: Cannot close the output file '%s'!\n", MAKEFILE_HELPER_FILENAME); return 6; } return EXIT_SUCCESS; } allegro5-5.2.10.1/misc/regenerate.sh000077500000000000000000000005231473414355200170730ustar00rootroot00000000000000#!/bin/bash # Recreate the automatically generated source files in the tree. set -e set -x misc/make_scanline_drawers.py | \ indent -kr -i3 -l0 > src/scanline_drawers.inc misc/make_converters.py misc/gl_mkalias.sh misc/make_mixer_helpers.py | \ indent -kr -i3 -l0 > addons/audio/kcm_mixer_helpers.inc # vim: set sts=3 sw=3 et: allegro5-5.2.10.1/misc/utod.sh000077500000000000000000000016421473414355200157300ustar00rootroot00000000000000#!/bin/sh # # Convert LF line endings to CR/LF line endings, preserving timestamps and # permissions on the file. # with_unix_tools() { for file in "$@" do echo "$file" tmpfile=`dirname "$file"`/__dtou_tmp.$RANDOM || exit 1 trap 'rm -f "$tmpfile"' 1 2 3 13 15 # We go through a slightly convoluted sequence of commands in order to # preserve both the timestamp and permissions on the file. { perl -p -e "s/([^\r]|^)\n/\1\r\n/" "$file" > "$tmpfile" && touch -r "$file" "$tmpfile" && cat "$tmpfile" > "$file" && touch -r "$tmpfile" "$file" && rm -f "$tmpfile" } || exit 1 done } with_cygwin() { for file in "$@" do unix2dos $file || exit 1 done } if test -z "$1" then echo "$0 filename" exit fi if test "$ALLEGRO_USE_CYGWIN" = "1" then with_cygwin "$@" else with_unix_tools "$@" fi # vi: sts=3 sw=3 et allegro5-5.2.10.1/misc/vcvars.c000066400000000000000000000070241473414355200160660ustar00rootroot00000000000000/* * VCVARS - sets up a command prompt with suitable options for using MSVC. * * This program tries to locate the vcvars32.bat file, first by looking in * the registry, and then if that fails, by asking the user. It then sets * the environment variable VCVARS to the full path of this file. * * If it was given a commandline argument, it then runs that program, * or otherwise it opens up a new command prompt. In either case it will * adjust the environment size to make sure there is enough space for * setting the compiler variables. */ #define WIN32_LEAN_AND_MEAN #include #include #include #include /* try to read a value from the registry */ int read_registry(char *path, char *var, char *val, int size) { HKEY key; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &key) != ERROR_SUCCESS) return 0; if (RegQueryValueEx(key, var, NULL, NULL, val, &size) != ERROR_SUCCESS) { RegCloseKey(key); return 0; } RegCloseKey(key); return 1; } /* locate vcvars32.bat */ void find_vcvars() { char data[256], name[256]; int i; /* look in the registry (try VC versions 4 through 9, just in case :-) */ for (i=9; i>=4; i--) { sprintf(name, "Software\\Microsoft\\DevStudio\\%d.0\\Products\\Microsoft Visual C++", i); if (read_registry(name, "ProductDir", data, sizeof(data))) { strcat(data, "\\bin\\vcvars32.bat"); if (access(data, 4) == 0) { printf("Found %s\n", data); break; } } data[0] = 0; } /* oh dear, have to ask the user where they put it */ if (!data[0]) { printf("\n Unable to find MSVC ProductDir information in your registry!\n\n"); printf(" To install Allegro, I need to know the path where your compiler is\n"); printf(" installed. Somewhere in your MSVC installation directory there will\n"); printf(" be a file called vcvars32.bat, which contains this information.\n"); printf(" Please enter the full path to where I can find that file, for example\n"); printf(" c:\\Program Files\\Microsoft Visual Studio\\VC98\\bin\\vcvars32.bat\n"); for (;;) { printf("\n> "); fflush(stdout); if (gets(data)) { i = strlen(data) - 12; if (i < 0) i = 0; if (stricmp(data+i, "vcvars32.bat") != 0) printf("\nError: that path doesn't end in vcvars32.bat!\n"); else if (access(data, 4) != 0) printf("\nError: can't find a vcvars32.bat file there!\n"); else { printf("\nUsing %s\n", data); break; } } data[0] = 0; } } /* put it in the environment */ strcpy(name, "VCVARS="); strcat(name, data); putenv(name); } /* the main program */ int main(int argc, char *argv[]) { char cmd[256]; int i; find_vcvars(); if ((getenv("OS")) && (stricmp(getenv("OS"), "Windows_NT") == 0)) { if (argc > 1) { /* run program using cmd.exe */ strcpy(cmd, "cmd.exe /e:8192 /c"); } else { /* TSR using cmd.exe */ sprintf(cmd, "cmd.exe /e:8192 /k \"%s\"", getenv("VCVARS")); } } else { if (argc > 1) { /* run program using command.com */ strcpy(cmd, "command.com /e:8192 /c"); } else { /* TSR using command.com */ sprintf(cmd, "command.com /e:8192 /k \"%s\"", getenv("VCVARS")); } } /* what program do we want to invoke? */ for (i=1; i&2 exit 1 fi if [ -n "$2" ] && [ ! -r ../"$2" ]; then echo "Previous archive $2 not in parent directory, aborting" exit 1 fi # strip off the path and extension from our arguments name=$(echo "$1" | sed -e 's/.*[\\\/]//; s/\.zip//') prev=$(echo "$2" | sed -e 's/.*[\\\/]//; s/\.zip//') # make a datestamped archive if specified if test $name = datestamp; then date=`date '+%Y%m%d'` name=allegro_$date fi # make sure all the makefiles are in Unix text format # for file in makefile.*; do # mv $file _tmpfile # tr -d \\\r < _tmpfile > $file # touch -r _tmpfile $file # rm _tmpfile # done # delete all generated files # echo "Cleaning the Allegro tree..." # # sed -n -e "/CLEAN_FILES/,/^$/p; /^ALLEGRO_.*_EXES/,/^$/p" makefile.lst | \ # sed -e "/CLEAN_FILES/d; /ALLEGRO_.*_EXES/d; s/\\\\//g" | \ # xargs -n 1 echo | \ # sed -e "s/\(.*\)/-c \"rm -f \1\"/" | \ # xargs -l sh # # find . -name '*~' -exec rm -f {} \; # emulation of the djgpp utod utility program (Unix to DOS text format) utod() { for file in $*; do if echo $file | grep "^\.\.\./" >/dev/null; then # files like .../*.c recurse into directories (emulating djgpp libc) spec=$(echo $file | sed -e "s/^\.\.\.\///") find . -type f -name "$spec" -exec perl -p -i -e 's/([^\r]|^)\n/\1\r\n/' {} \; else perl -p -e "s/([^\r]|^)\n/\1\r\n/" $file > _tmpfile touch -r $file _tmpfile mv _tmpfile $file fi done } # generate dependencies for DJGPP # echo "Generating DJGPP dependencies..." # # ./fix.sh djgpp --quick # # make depend UNIX_TOOLS=1 CC=gcc # generate dependencies for Watcom # echo "Generating Watcom dependencies..." # # ./fix.sh watcom --quick # # make depend UNIX_TOOLS=1 CC=gcc # generate dependencies for MSVC # echo "Generating MSVC dependencies..." # # ./fix.sh msvc --quick # # make depend UNIX_TOOLS=1 CC=gcc # generate dependencies for MinGW # echo "Generating MinGW dependencies..." # # ./fix.sh mingw --quick # # make depend UNIX_TOOLS=1 CC=gcc # generate dependencies for Borland C++ # echo "Generating BCC32 dependencies..." # # ./fix.sh bcc32 --quick # # make depend UNIX_TOOLS=1 CC=gcc # generate dependencies for BeOS # echo "Generating BeOS dependencies..." # # ./fix.sh beos --quick # # make depend UNIX_TOOLS=1 CC=gcc # generate dependencies for QNX # echo "Generating QNX dependencies..." # # ./fix.sh qnx --quick # # make depend UNIX_TOOLS=1 CC=gcc # generate dependencies for MacOS X # echo "Generating MacOS X dependencies..." # # ./fix.sh macosx --quick # # make depend UNIX_TOOLS=1 CC=gcc # generate the DLL export definition files for Windows compilers # misc/fixdll.sh # running autoconf # echo "Running autoconf to generate configure script..." # autoconf || exit 1 # touch stamp-h.in so the user doesn't need autoheader to compile # touch stamp-h.in # convert documentation from the ._tx source files # echo "Converting documentation..." # # gcc -o _makedoc.exe docs/src/makedoc/*.c # # ./_makedoc.exe -ascii readme.txt docs/src/readme._tx # ./_makedoc.exe -ascii CHANGES docs/src/changes._tx # ./_makedoc.exe -part -ascii AUTHORS docs/src/thanks._tx # ./_makedoc.exe -part -ascii THANKS docs/src/thanks._tx # for base in abi ahack allegro const faq help mistakes; do # ./_makedoc.exe -ascii docs/txt/$base.txt docs/src/$base._tx # done # for base in bcc32 beos darwin djgpp linux macosx mingw32 msvc qnx unix watcom; do # ./_makedoc.exe -ascii docs/build/$base.txt docs/src/build/$base._tx # done # # # rm _makedoc.exe # convert documentation from pandoc-format source files if which cmake >/dev/null && which pandoc >/dev/null && which makeinfo >/dev/null then echo "Generating documentation from Pandoc source files..." builddir=,,zipup_builddir.$$ trap 'rm -rf $builddir' 0 1 2 3 13 15 mkdir $builddir ( cd $builddir cmake .. make -j4 docs html man mv docs/txt/changes-5.0.txt ../CHANGES-5.0.txt mv docs/txt/changes-5.1.txt ../CHANGES-5.1.txt mv docs/txt/changes-5.2.txt ../CHANGES-5.2.txt test -d ../docs/html || mkdir -p ../docs/html rm -rf ../docs/html/refman mv docs/html/refman ../docs/html/refman rm -rf ../docs/man mv docs/man ../docs/man ) || exit 1 rm -rf $builddir else echo "ERROR: CMake/Pandoc/makeinfo not found" 1>&2 exit 1 fi # generate NaturalDocs documentation # if which NaturalDocs >/dev/null # then # echo "Generating NaturalDocs..." # ( cd docs/naturaldocs # make clean # make public # ) || exit 1 # else # echo "WARNING: NaturalDocs not found, skipping step" 1>&2 # fi # create language.dat and keyboard.dat files # misc/mkdata.sh || exit 1 # convert files to djgpp format for distribution # ./fix.sh djgpp --utod # convert line endings to CR/LF ./misc/convert_line_endings.sh --utod || exit 1 # recursive helper to fill any empty directories with a tmpfile.txt scan_for_empties() { if [ -f $1/tmpfile.txt ]; then rm $1/tmpfile.txt; fi files=`echo $1/*` if [ "$files" = "$1/CVS" -o "$files" = "$1/cvs" -o "$files" = "$1/*" ]; then echo "This file is needed because some unzip programs skip empty directories." > $1/tmpfile.txt else for file in $files; do if [ -d $file ]; then scan_for_empties $file fi done fi } #echo "Filling empty directories with tmpfile.txt..." scan_for_empties "." # build the main zip archive echo "Creating $name.zip..." if [ -f .dist/$name.zip ]; then rm .dist/$name.zip; fi rm -rf ./autom4te* mkdir -p .dist/allegro # Note: we use -print0 and xargs -0 to handle file names with spaces. find . -type f "(" -path "*/.*" -prune -o -iname "*.rej" \ -prune -o -iname "*.orig" -prune -o -print0 ")" | \ xargs -0 cp -a --parents -t .dist/allegro # from now on, the scripts runs inside .dist cd .dist # If 7za is available, use that to produce .7z files. # I used to produce .zip files with it as well but I noticed upon extraction # files with timestamps 10 hours into the future (I'm at UTC+10). .7z files # seem to be unaffected. This was with p7zip 4.65. if 7za > /dev/null ; then rm -f $name.7z if [ -n "$FAST_ZIPUP" ]; then 7za a -mx0 $name.7z allegro else 7za a -mx9 -ms=on $name.7z allegro fi fi rm -f $name.zip if [ -n "$FAST_ZIPUP" ]; then zip -0 -r $name.zip allegro else zip -9 -r $name.zip allegro fi # generate the manifest file echo "Generating allegro.mft..." unzip -Z1 $name.zip | sort > allegro/allegro.mft echo "allegro/allegro.mft" >> allegro/allegro.mft utod allegro/allegro.mft zip -9 $name.zip allegro/allegro.mft if [ -r $name.7z ]; then 7za a $name.7z allegro/allegro.mft fi # if we are building diffs as well, do those if [ $# -eq 2 ]; then echo "Inflating current version ($name.zip)..." mkdir current unzip -q $name.zip -d current echo "Inflating previous version ($2)..." mkdir previous unzip -q ../../"$2" -d previous || exit 1 echo "Generating diffs..." diff -U 3 -N --recursive previous/ current/ > $name.diff echo "Deleting temp files..." rm -r previous rm -r current # generate the .txt file for the diff archive echo "This is a set of diffs to upgrade from $prev to $name." > $name.txt echo >> $name.txt echo "Date: $(date '+%A %B %d, %Y, %H:%M')" >> $name.txt echo >> $name.txt echo "To apply this patch, copy $name.diff into the same directory where you" >> $name.txt echo "installed Allegro (this should be one level up from the allegro/ dir, eg." >> $name.txt echo "if your Allegro installation lives in c:/djgpp/allegro/, you should be in" >> $name.txt echo "c:/djgpp/). Then type the command:" >> $name.txt echo >> $name.txt echo " patch -p1 < $name.diff" >> $name.txt echo >> $name.txt echo "Change into the allegro directory, run make, and enjoy!" >> $name.txt utod $name.txt # zip up the diff archive echo "Creating ${name}_diff.zip..." if [ -f ${name}_diff.zip ]; then rm ${name}_diff.zip; fi zip -9 ${name}_diff.zip $name.diff $name.txt # find if we need to add any binary files as well bin=$(sed -n -e "s/Binary files previous\/\(.*\) and current.* differ/\1/p" $name.diff) if [ "$bin" != "" ]; then echo "Adding binary diffs..." zip -9 ${name}_diff.zip $bin fi rm $name.diff $name.txt fi # convert line endings to back to LF cd .. ./misc/convert_line_endings.sh --dtou || exit 1 allegro5-5.2.10.1/misc/zipwin.sh000077500000000000000000000234641473414355200163030ustar00rootroot00000000000000#! /bin/sh # # Shell script to create a Windows binary distribution. This will # compile the DLL files using MSVC or Cygwin, generate the batch file and # associated helpers needed for end users to build the example programs, # and finally zip up the results. # # Note! If you use Cygwin to generate the DLLs make sure you have set up # your MINGDIR and ALLEGRO_USE_CYGWIN environment variables correctly. # # It should be run from the root of the Allegro directory, eg. # bash misc/zipwin.sh, so that it can find misc/vcvars.c and misc/askq.c. # check we have a filename, and strip off the path and extension from it if [ $# -ne 1 ]; then echo "Usage: zipwin " 1>&2 exit 1 fi name=$(echo "$1" | sed -e 's/.*[\\\/]//; s/\.zip//') # check that MSVC or Cygwin is available if [ "$ALLEGRO_USE_CYGWIN" = "1" ]; then if [ "$MINGDIR" = "" ]; then echo "You need to set up Cygwin before running this script" 1>&2 exit 1 fi else if [ "$MSVCDIR" = "" ]; then echo "You need to set up MSVC (run vcvars32.bat) before running this script" 1>&2 exit 1 fi fi # check that we are in the Allegro dir if [ ! -f include/allegro5/allegro.h ]; then echo "Oops, you don't appear to be in the root of the Allegro directory" 1>&2 exit 1 fi # convert Allegro to MSVC or Cygwin format if [ "$ALLEGRO_USE_CYGWIN" = "1" ]; then ./fix.sh mingw --dtou else ./fix.sh msvc --utod fi # delete all generated files echo "Cleaning the Allegro tree..." make.exe -s veryclean # generate DLL export definition files misc/fixdll.sh # generate dependencies echo "Generating dependencies..." make.exe depend # build all three libs make.exe lib make.exe lib DEBUGMODE=1 make.exe lib PROFILEMODE=1 # find what library version (DLL filename) the batch file should build ver=`sed -n -e "s/LIBRARY_VERSION = \(.*\)/\1/p" makefile.ver` # compile vcvars echo "Compiling vcvars.exe..." if [ "$ALLEGRO_USE_CYGWIN" = "1" ]; then gcc -Wl,--subsystem,console -o vcvars.exe misc/vcvars.c -ladvapi32 else cl -nologo misc/vcvars.c advapi32.lib rm vcvars.obj fi # compile askq echo "Compiling askq.exe..." if [ "$ALLEGRO_USE_CYGWIN" = "1" ]; then gcc -Wl,--subsystem,console -o askq.exe misc/askq.c else cl -nologo misc/askq.c rm askq.obj fi # generate the setup code for msvcmake.bat (this bit checks for vcvars32, # and builds the import libs) echo "Generating msvcmake.bat..." cat > msvcmake.bat << END_OF_BATCH @echo off rem Batch file for installing the precompiled Allegro DLL files, rem and building the MSVC example and test programs. rem Generated by misc/zipwin.sh if not exist include\\allegro.h goto no_allegro if not "%MSVCDIR%" == "" goto got_msvc if "%VCVARS%" == "" goto no_vcvars call "%VCVARS%" goto got_msvc :no_vcvars echo MSVC environment variables not found: running vcvars.exe to look for them vcvars.exe msvcmake.bat goto the_end :got_msvc call fix.bat msvc --quick echo Generating release mode import library copy lib\\msvc\\allegro.def lib\\msvc\\alleg$ver.def > nul lib /nologo /machine:ix86 /def:lib\\msvc\\alleg$ver.def /out:lib\\msvc\\alleg.lib echo Generating debug mode import library copy lib\\msvc\\allegro.def lib\\msvc\\alld$ver.def > nul lib /nologo /machine:ix86 /def:lib\\msvc\\alld$ver.def /out:lib\\msvc\\alld.lib /debugtype:cv echo Generating profile mode import library copy lib\\msvc\\allegro.def lib\\msvc\\allp$ver.def > nul lib /nologo /machine:ix86 /def:lib\\msvc\\allp$ver.def /out:lib\\msvc\\allp.lib echo Compiling test and example programs END_OF_BATCH # If running Cygwin, we need to do some trickery if [ "$ALLEGRO_USE_CYGWIN" = "1" ]; then ./fix.sh msvc --utod export MSVCDIR="MSVCDIR" make.exe depend UNIX_TOOLS=1 echo "Fooling the MSVC makefile ..." cp lib/mingw32/*.dll lib/msvc/ make.exe -t lib fi # SED script for converting make -n output into a funky batch file cat > _fix1.sed << END_OF_SED # remove any echo messages from the make output /^echo/d # strip out references to runner.exe s/obj\/msvc\/runner.exe // # turn program name slashes into DOS format s/\\//\\\\/g # make sure were are using command.com copy, rather than cp s/^.*cat tools.*msvc.plugins.h/copy \/B tools\\\\plugins\\\\*.inc tools\\\\plugins\\\\plugins.h/ # add blank lines, to make the batch output more readable s/^\([^@]*\)$/\\ \1/ # turn any @ argfile references into an echo+tmpfile sequence s/\(.*\) @ \(.*\)/\\ echo \2 > _tmp.arg\\ \1 @_tmp.arg\\ del _tmp.arg/ END_OF_SED # second SED script, for splitting long echos into multiple segments cat > _fix2.sed << END_OF_SED s/echo \(................................................[^ ]*\) \(........*\) \(>>*\) _tmp\.arg/echo \1 \3 _tmp.arg\\ echo \2 >> _tmp.arg/ END_OF_SED # run make -n, to see what commands are needed for building this thing echo "Running make -n, to generate the command list..." make.exe -n | \ sed -f _fix1.sed | \ sed -f _fix2.sed | \ sed -f _fix2.sed | \ sed -f _fix2.sed | \ sed -f _fix2.sed | \ sed -f _fix2.sed | \ sed -f _fix2.sed | \ sed -f _fix2.sed | \ sed -f _fix2.sed \ >> msvcmake.bat rm _fix1.sed _fix2.sed if [ "$ALLEGRO_USE_CYGWIN" = "1" ]; then unset MSVCDIR fi # finish writing msvcmake.bat (this bit asks whether to install the headers, # libs, and DLL files) cat >> msvcmake.bat << END_OF_BATCH askq.exe Would you like to copy the headers and libs to your MSVC directories if errorlevel 1 goto no_lib_copy if not "%MSVCDIR%" == "" set _VC_DIR_=%MSVCDIR% echo Copying libraries copy lib\\msvc\\*.lib "%_VC_DIR_%\\lib" echo Copying allegro.h copy include\\allegro.h "%_VC_DIR_%\\include" echo Copying winalleg.h copy include\\winalleg.h "%_VC_DIR_%\\include" echo Copying module headers md "%_VC_DIR_%\\include\\allegro" copy include\\allegro\\*.h "%_VC_DIR_%\\include\\allegro" echo Copying inline headers md "%_VC_DIR_%\\include\\allegro\\inline" copy include\\allegro\\inline\\*.inl "%_VC_DIR_%\\include\\allegro\\inline" echo Copying internal headers md "%_VC_DIR_%\\include\\allegro\\internal" copy include\\allegro\\internal\\*.h "%_VC_DIR_%\\include\\allegro\\internal" echo Copying platform headers md "%_VC_DIR_%\\include\\allegro\\platform" copy include\\allegro\\platform\\aintwin.h "%_VC_DIR_%\\include\\allegro\\platform" copy include\\allegro\\platform\\almsvc.h "%_VC_DIR_%\\include\\allegro\\platform" copy include\\allegro\\platform\\alplatf.h "%_VC_DIR_%\\include\\allegro\\platform" copy include\\allegro\\platform\\alwin.h "%_VC_DIR_%\\include\\allegro\\platform" set _VC_DIR_= goto lib_copy_done :no_lib_copy echo Library and header files were not installed. echo You can find the headers in the allegro\\include directory, echo and the libs in allegro\\lib\\msvc\\ :lib_copy_done askq.exe Would you like to copy the DLL files to your Windows system directory if errorlevel 1 goto no_dll_copy if "%OS%" == "Windows_NT" set _WIN_DIR_=%SYSTEMROOT%\\system32 if "%OS%" == "" set _WIN_DIR_=%windir%\\system echo Copying DLL files to %_WIN_DIR_% copy lib\\msvc\\*.dll %_WIN_DIR_% set _WIN_DIR_= goto dll_copy_done :no_dll_copy echo DLL files were not installed. echo You can find them in allegro\\lib\\msvc\\ :dll_copy_done echo. echo All done: Allegro is now installed on your system! goto the_end :no_allegro echo Can't find the Allegro library source files! To install this binary echo distribution, you must also have a copy of the library sources, so echo that I can compile the support programs and convert the documentation. :the_end END_OF_BATCH # generate the readme cat > $name.txt << END_OF_README ______ ___ ___ /\\ _ \\ /\\_ \\ /\\_ \\ \\ \\ \\L\\ \\\\//\\ \\ \\//\\ \\ __ __ _ __ ___ \\ \\ __ \\ \\ \\ \\ \\ \\ \\ /'__\`\\ /'_ \`\\/\\\`'__\\/ __\`\\ \\ \\ \\/\\ \\ \\_\\ \\_ \\_\\ \\_/\\ __//\\ \\L\\ \\ \\ \\//\\ \\L\\ \\ \\ \\_\\ \\_\\/\\____\\/\\____\\ \\____\\ \\____ \\ \\_\\\\ \\____/ \\/_/\\/_/\\/____/\\/____/\\/____/\\/___L\\ \\/_/ \\/___/ /\\____/ \\_/__/ Windows binary distribution. This package contains precompiled copies of the Windows DLL files for the Allegro library, to save you having to compile it yourself. This is not a complete distribution of Allegro, as it does not contain any of the documentation, example programs, headers, etc. You need to download the full source version, and then just unzip this package over the top of it. To install, run the batch file msvcmake.bat, either from a command prompt or by double-clicking on it from the Windows explorer. This will hopefully be able to autodetect all the details of where to find your compiler, and will automatically compile the various support programs that come with Allegro. At the end of the install process you will be asked whether to copy libs and headers into your compiler directories, and whether to install the DLL files into the Windows system directory. You should normally say yes here, but if you prefer, you can leave these files in the Allegro directory, and then specify the paths to them later on, when you come to compile your own programs using Allegro. There are three versions of the DLL included in this zip: alleg$ver.dll is the normal optimised version alld$ver.dll is the debugging build, and should be used during development allp$ver.dll is a profiling build, for collecting performance info For more general information about using Allegro, see the readme.txt and docs/build/msvc.txt files from the source distribution. END_OF_README # build the main zip archive echo "Creating $name.zip..." cd .. if [ -f $name.zip ]; then rm $name.zip; fi if [ "$ALLEGRO_USE_CYGWIN" = "1" ]; then unix2dos allegro/$name.txt unix2dos allegro/msvcmake.bat fi zip -9 $name.zip allegro/$name.txt allegro/msvcmake.bat allegro/vcvars.exe allegro/askq.exe allegro/lib/msvc/*.dll # clean up after ourselves cd allegro rm $name.txt msvcmake.bat vcvars.exe askq.exe echo "Done!" allegro5-5.2.10.1/python/000077500000000000000000000000001473414355200150015ustar00rootroot00000000000000allegro5-5.2.10.1/python/CMakeLists.txt000066400000000000000000000026541473414355200175500ustar00rootroot00000000000000include(FindPythonInterp) # Construct list of files whose modification should trigger a rebuild of # the Python API. foreach(x ${MONOLITH_SOURCES} ${MONOLITH_HEADERS} ${ALLEGRO_PUBLIC_HEADERS}) if(NOT ${x} MATCHES "^/.*") file(RELATIVE_PATH xrel ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/${x}) list(APPEND SOURCES ${xrel}) endif() endforeach() if(WIN32) add_custom_command( OUTPUT python_protos DEPENDS ${SOURCES} COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/python/checkdocs.py -c ${CMAKE_C_COMPILER} -p python_protos -b ${PROJECT_BINARY_DIR} -s ${PROJECT_SOURCE_DIR} -w ) else(WIN32) add_custom_command( OUTPUT python_protos DEPENDS ${SOURCES} COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/python/checkdocs.py -p python_protos -b ${PROJECT_BINARY_DIR} -s ${PROJECT_SOURCE_DIR} ) endif(WIN32) SET(release "") append_lib_type_suffix(release) append_lib_linkage_suffix(release) SET(version "${ALLEGRO_SOVERSION}") add_custom_command( OUTPUT allegro.py DEPENDS python_protos COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/python/generate_python_ctypes.py -p python_protos -o allegro.py -t \"${release}\" -v \"${version}\" ) add_custom_target(python ALL DEPENDS allegro.py ) allegro5-5.2.10.1/python/checkdocs.py000077500000000000000000000236621473414355200173150ustar00rootroot00000000000000#!/usr/bin/env python3 import optparse import subprocess import sys import os import re import glob links = {} symbols = {} structs = {} types = {} anonymous_enums = {} functions = {} constants = {} sections = {} def check_references(): """ Check if each [link] in the reference manual actually exists. Also fills in global variable "links". """ print("Checking References...") html_refs = os.path.join(options.build, "docs", "html_refs") for line in open(html_refs): mob = re.match(r"\[(.*?)\]", line) if mob: links[mob.group(1)] = True docs = glob.glob("docs/src/refman/*.txt") for doc in docs: text = file(doc).read() text = re.compile(".*?", re.S).sub("", text) # in case of [A][B], we will not see A but we do see B. for link in re.findall(r" \[([^[]*?)\][^([]", text): if not link in links: print("Missing: %s: %s" % (doc, link)) for section in re.findall(r"^#+ (.*)", text, re.MULTILINE): if not section.startswith("API:"): sections[section] = 1 for link in sections.keys(): del links[link] def add_struct(line): if options.protos: kind = re.match("\s*(\w+)", line).group(1) if kind in ["typedef", "struct", "enum", "union"]: mob = None if kind != "typedef": mob = re.match(kind + "\s+(\w+)", line) if not mob: mob = re.match(".*?(\w+);$", line) if not mob and kind == "typedef": mob = re.match("typedef.*?\(\s*\*\s*(\w+)\)", line) if not mob: anonymous_enums[line] = 1 else: sname = mob.group(1) if sname.startswith("_ALLEGRO_gl"): return if kind == "typedef": types[sname] = line else: structs[sname] = line def parse_header(lines, filename): """ Minimal C parser which extracts most symbols from a header. Fills them into the global variable "symbols". """ n = 0 ok = False brace = 0 lines2 = [] cline = "" for line in lines: line = line.strip() if not line: continue if line.startswith("#"): if line.startswith("#define"): if ok: name = line[8:] match = re.match("#define ([a-zA-Z_]+)", line) name = match.group(1) symbols[name] = "macro" simple_constant = line.split() if len(simple_constant) == 3 and\ not "(" in simple_constant[1] and\ simple_constant[2][0].isdigit(): constants[name] = simple_constant[2] n += 1 elif line.startswith("#undef"): pass else: ok = False match = re.match(r'# \d+ "(.*?)"', line) if match: name = match.group(1) if name == "" or name.startswith(options.build) or \ name.startswith("include") or \ name.startswith("addons") or\ name.startswith(options.source): ok = True continue if not ok: continue sublines = line.split(";") for i, subline in enumerate(sublines): if i < len(sublines) - 1: subline += ";" brace -= subline.count("}") brace -= subline.count(")") brace += subline.count("{") brace += subline.count("(") if cline: if cline[-1].isalnum(): cline += " " cline += subline if brace == 0 and subline.endswith(";") or subline.endswith("}"): lines2.append(cline.strip()) cline = "" for line in lines2: line = line.replace("__attribute__((__stdcall__))", "") if line.startswith("enum"): add_struct(line) elif line.startswith("typedef"): match = None if not match: match = re.match(r".*?(\w+);$", line) if not match: match = re.match(r".*?(\w*)\[", line) if not match: match = re.match(r".*?\(\s*\*\s*(\w+)\s*\).*?", line) if match: name = match.group(1) symbols[name] = "typedef" n += 1 else: print("? " + line) add_struct(line) elif line.startswith("struct"): add_struct(line) elif line.startswith("union"): add_struct(line) else: try: parenthesis = line.find("(") if parenthesis < 0: match = re.match(r".*?(\w+)\s*=", line) if not match: match = re.match(r".*?(\w+)\s*;$", line) if not match: match = re.match(r".*?(\w+)", line) symbols[match.group(1)] = "variable" n += 1 else: match = re.match(r".*?(\w+)\s*\(", line) fname = match.group(1) symbols[fname] = "function" if not fname in functions: functions[fname] = line n += 1 except AttributeError as e: print("Cannot parse in " + filename) print("Line is: " + line) print(e) return n def parse_all_headers(): """ Call parse_header() on all of Allegro's public include files. """ p = options.source includes = " -I " + p + "/include -I " + os.path.join(options.build, "include") includes += " -I " + p + "/addons/acodec" headers = [p + "/include/allegro5/allegro.h", p + "/addons/acodec/allegro5/allegro_acodec.h", p + "/include/allegro5/allegro_opengl.h"] if options.windows: headers += [p + "/include/allegro5/allegro_windows.h"] for addon in glob.glob(p + "/addons/*"): name = addon[len(p + "/addons/"):] header = os.path.join(p, "addons", name, "allegro5", "allegro_" + name + ".h") if os.path.exists(header): headers.append(header) includes += " -I " + os.path.join(p, "addons", name) for header in headers: p = subprocess.Popen(options.compiler + " -E -dD - " + includes, stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=True) filename = "#include \n" + open(header).read() p.stdin.write(filename.encode('utf-8')) p.stdin.close() text = p.stdout.read().decode("utf-8") parse_header(text.splitlines(), header) #print("%d definitions in %s" % (n, header)) def check_undocumented_functions(): """ Cross-compare the documentation links with public symbols found in headers. """ print("Checking if each documented function exists...") parse_all_headers() for link in links: if not link in symbols: print("Missing: " + link) print("") print("Checking if each function is documented...") others = [] for link in symbols: if not link in links: if symbols[link] == "function": print("Missing: " + link) else: if link and not link.startswith("GL") and \ not link.startswith("gl") and \ not link.startswith("_al_gl") and \ not link.startswith("_ALLEGRO_gl") and \ not link.startswith("_ALLEGRO_GL") and \ not link.startswith("ALLEGRO_"): others.append(link) print("Also leaking:") others.sort() print(", ".join(others)) def list_all_symbols(): parse_all_headers() for name in sorted(symbols.keys()): print(name) def main(argv): global options p = optparse.OptionParser() p.description = """\ When run from the toplevel A5 directory, this script will parse the include, addons and cmake build directory for global definitions and check against all references in the documentation - then report symbols which are not documented. """ p.add_option("-b", "--build", help="Path to the build directory.") p.add_option("-c", "--compiler", help="Path to gcc.") p.add_option("-s", "--source", help="Path to the source directory.") p.add_option("-l", "--list", action="store_true", help="List all symbols.") p.add_option("-p", "--protos", help="Write all public " + "prototypes to the given file.") p.add_option("-w", "--windows", action="store_true", help="Include windows specific symbols.") options, args = p.parse_args() if not options.source: options.source = "." if not options.compiler: options.compiler = "gcc" if not options.build: sys.stderr.write("Build path required (-p).\n") p.print_help() sys.exit(-1) if options.protos: parse_all_headers() f = open(options.protos, "w") for name, s in structs.items(): f.write(name + ": " + s + "\n") for name, s in types.items(): f.write(name + ": " + s + "\n") for e in anonymous_enums.keys(): f.write(": " + e + "\n") for fname, proto in functions.items(): f.write(fname + "(): " + proto + "\n") for name, value in constants.items(): f.write(name + ": #define " + name + " " + value + "\n") elif options.list: list_all_symbols() else: check_references() print("") check_undocumented_functions() if __name__ == "__main__": main(sys.argv) allegro5-5.2.10.1/python/ex_draw_bitmap.py000077500000000000000000000246021473414355200203470ustar00rootroot00000000000000#!/usr/bin/env python3 import sys, os from random import * from math import * from ctypes import * # Get path to examples data. p = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "examples")) from allegro import * def abort_example(text): sys.stderr.write(text) sys.exit(1) FPS = 60 MAX_SPRITES = 1024 class Sprite: def __init__(self): self.x, self.y, self.dx, self.dy = 0, 0, 0, 0 text = [ "Space - toggle use of textures", "B - toggle alpha blending", "Left/Right - change bitmap size", "Up/Down - change bitmap count", "F1 - toggle help text" ] class Example: sprites = [Sprite() for i in range(MAX_SPRITES)] use_memory_bitmaps = False blending = False display = None mysha = None bitmap = None bitmap_size = 0 sprite_count = 0 show_help = True font = None mouse_down = False last_x, last_y = 0, 0 white = None half_white = None dark = None red = None direct_speed_measure = 1.0 ftpos = 0 frame_times = [0.0] * FPS example = Example() def add_time(): example.frame_times[example.ftpos] = al_get_time() example.ftpos += 1 if example.ftpos >= FPS: example.ftpos = 0 def get_fps(): prev = FPS - 1 min_dt = 1 max_dt = 1 / 1000000 av = 0 for i in range(FPS): if i != example.ftpos: dt = example.frame_times[i] - example.frame_times[prev] if dt < min_dt and dt > 0: min_dt = dt if dt > max_dt: max_dt = dt av += dt prev = i av /= FPS - 1 average = ceil(1 / av) d = 1 / min_dt - 1 / max_dt minmax = floor(d / 2) return average, minmax def add_sprite(): if example.sprite_count < MAX_SPRITES: w = al_get_display_width(example.display) h = al_get_display_height(example.display) i = example.sprite_count example.sprite_count += 1 s = example.sprites[i] a = randint(0, 359) s.x = randint(0, w - example.bitmap_size - 1) s.y = randint(0, h - example.bitmap_size - 1) s.dx = cos(a) * FPS * 2 s.dy = sin(a) * FPS * 2 def add_sprites(n): for i in range(n): add_sprite() def remove_sprites(n): example.sprite_count -= n if example.sprite_count < 0: example.sprite_count = 0 def change_size(size): if size < 1: size = 1 if size > 1024: size = 1024 if example.bitmap: al_destroy_bitmap(example.bitmap) al_set_new_bitmap_flags( ALLEGRO_MEMORY_BITMAP if example.use_memory_bitmaps else 0) example.bitmap = al_create_bitmap(size, size) example.bitmap_size = size al_set_target_bitmap(example.bitmap) al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO, example.white) al_clear_to_color(al_map_rgba_f(0, 0, 0, 0)) bw = al_get_bitmap_width(example.mysha) bh = al_get_bitmap_height(example.mysha) al_draw_scaled_bitmap(example.mysha, 0, 0, bw, bh, 0, 0, size, size, 0) al_set_target_backbuffer(example.display) def sprite_update(s): w = al_get_display_width(example.display) h = al_get_display_height(example.display) s.x += s.dx / FPS s.y += s.dy / FPS if s.x < 0: s.x = -s.x s.dx = -s.dx if s.x + example.bitmap_size > w: s.x = -s.x + 2 * (w - example.bitmap_size) s.dx = -s.dx if s.y < 0: s.y = -s.y s.dy = -s.dy if s.y + example.bitmap_size > h: s.y = -s.y + 2 * (h - example.bitmap_size) s.dy = -s.dy if example.bitmap_size > w: s.x = w / 2 - example.bitmap_size / 2 if example.bitmap_size > h: s.y = h / 2 - example.bitmap_size / 2 def update(): for i in range(example.sprite_count): sprite_update(example.sprites[i]) def redraw(): w = al_get_display_width(example.display) h = al_get_display_height(example.display) fh = al_get_font_line_height(example.font) info = ["textures", "memory buffers"] binfo = ["alpha", "additive", "tinted", "solid"] tint = example.white if example.blending == 0: al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) tint = example.half_white elif example.blending == 1: al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE) tint = example.dark elif example.blending == 2: al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO) tint = example.red elif example.blending == 3: al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO, example.white) for i in range(example.sprite_count): s = example.sprites[i] al_draw_tinted_bitmap(example.bitmap, tint, s.x, s.y, 0) al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) if example.show_help: for i in range(5): al_draw_text(example.font, example.white, 0, h - 5 * fh + i * fh, 0, text[i]) al_draw_textf(example.font, example.white, 0, 0, 0, "count: %d", example.sprite_count) al_draw_textf(example.font, example.white, 0, fh, 0, "size: %d", example.bitmap_size) al_draw_textf(example.font, example.white, 0, fh * 2, 0, "%s", info[example.use_memory_bitmaps].encode("utf8")) al_draw_textf(example.font, example.white, 0, fh * 3, 0, "%s", binfo[example.blending].encode("utf8")) f1, f2 = get_fps() al_draw_textf(example.font, example.white, w, 0, ALLEGRO_ALIGN_RIGHT, "%s", ("FPS: %4d +- %-4d" % (f1, f2)).encode("utf8")) al_draw_textf(example.font, example.white, w, fh, ALLEGRO_ALIGN_RIGHT, "%s", ("%4d / sec" % int(1.0 / example.direct_speed_measure)).encode("utf8")) def main(): w, h = 640, 480 done = False need_redraw = True example.show_help = True if not al_install_system(ALLEGRO_VERSION_INT, None): abort_example("Failed to init Allegro.\n") sys.exit(1) if not al_init_image_addon(): abort_example("Failed to init IIO addon.\n") sys.exit(1) al_init_font_addon() al_get_num_video_adapters() info = ALLEGRO_MONITOR_INFO() al_get_monitor_info(0, byref(info)) if info.x2 - info.x1 < w: w = info.x2 - info.x1 if info.y2 - info.y1 < h: h = info.y2 - info.y1 example.display = al_create_display(w, h) if not example.display: abort_example("Error creating display.\n") if not al_install_keyboard(): abort_example("Error installing keyboard.\n") if not al_install_mouse(): abort_example("Error installing mouse.\n") example.font = al_load_font(p + "/data/fixed_font.tga", 0, 0) if not example.font: abort_example("Error loading data/fixed_font.tga\n") example.mysha = al_load_bitmap(p + "/data/mysha256x256.png") if not example.mysha: abort_example("Error loading data/mysha256x256.png\n") example.white = al_map_rgb_f(1, 1, 1) example.half_white = al_map_rgba_f(1, 1, 1, 0.5) example.dark = al_map_rgb(15, 15, 15) example.red = al_map_rgb_f(1, 0.2, 0.1) change_size(256) add_sprite() add_sprite() timer = al_create_timer(1.0 / FPS) queue = al_create_event_queue() al_register_event_source(queue, al_get_keyboard_event_source()) al_register_event_source(queue, al_get_mouse_event_source()) al_register_event_source(queue, al_get_timer_event_source(timer)) al_register_event_source(queue, al_get_display_event_source(example.display)) al_start_timer(timer) while not done: event = ALLEGRO_EVENT() if need_redraw and al_is_event_queue_empty(queue): t = -al_get_time() add_time() al_clear_to_color(al_map_rgb_f(0, 0, 0)) redraw() t += al_get_time() example.direct_speed_measure = t al_flip_display() need_redraw = False al_wait_for_event(queue, byref(event)) if event.type == ALLEGRO_EVENT_KEY_CHAR: if event.keyboard.keycode == ALLEGRO_KEY_ESCAPE: done = True elif event.keyboard.keycode == ALLEGRO_KEY_UP: add_sprites(1) elif event.keyboard.keycode == ALLEGRO_KEY_DOWN: remove_sprites(1) elif event.keyboard.keycode == ALLEGRO_KEY_LEFT: change_size(example.bitmap_size - 1) elif event.keyboard.keycode == ALLEGRO_KEY_RIGHT: change_size(example.bitmap_size + 1) elif event.keyboard.keycode == ALLEGRO_KEY_F1: example.show_help ^= 1 elif event.keyboard.keycode == ALLEGRO_KEY_SPACE: example.use_memory_bitmaps ^= 1 change_size(example.bitmap_size) elif event.keyboard.keycode == ALLEGRO_KEY_B: example.blending += 1 if example.blending == 4: example.blending = 0 elif event.type == ALLEGRO_EVENT_DISPLAY_CLOSE: done = True elif event.type == ALLEGRO_EVENT_TIMER: update() need_redraw = True elif event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: example.mouse_down = True example.last_x = event.mouse.x example.last_y = event.mouse.y elif event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP: fh = al_get_font_line_height(example.font) example.mouse_down = False if event.mouse.x < 40 and event.mouse.y >= h - fh * 5: button = (event.mouse.y - (h - fh * 5)) // fh if button == 0: example.use_memory_bitmaps ^= 1 change_size(example.bitmap_size) if button == 1: example.blending += 1 if example.blending == 4: example.blending = 0 if button == 4: example.show_help ^= 1 elif event.type == ALLEGRO_EVENT_MOUSE_AXES: if example.mouse_down: dx = event.mouse.x - example.last_x dy = event.mouse.y - example.last_y if dy > 4: add_sprites(int(dy / 4)) if dy < -4: remove_sprites(-int(dy / 4)) if dx > 4: change_size(example.bitmap_size + dx - 4) if dx < -4: change_size(example.bitmap_size + dx + 4) example.last_x = event.mouse.x example.last_y = event.mouse.y al_destroy_bitmap(example.bitmap) al_uninstall_system() al_main(main) allegro5-5.2.10.1/python/generate_python_ctypes.py000077500000000000000000000430561473414355200221500ustar00rootroot00000000000000#!/usr/bin/env python3 import sys import re import optparse from ctypes import * """ This script will use the prototypes from "checkdocs.py -s" to concoct a 1:1 Python wrapper for Allegro. """ class _AL_UTF8String: pass class Allegro: def __init__(self): self.types = {} self.functions = {} self.constants = {} def add_struct(self, name): x = type(name, (Structure, ), {}) self.types[name] = x def add_union(self, name): x = type(name, (Union, ), {}) self.types[name] = x def get_type(self, ptype): conversion = { "bool": c_bool, "_Bool": c_bool, "char": c_byte, "unsignedchar": c_ubyte, "int": c_int, "unsigned": c_uint, "unsignedint": c_uint, "int16_t": c_int16, "uint16_t": c_uint16, "int32_t": c_int32, "uint32_t": c_uint32, "int64_t": c_int64, "uint64_t": c_uint64, "uintptr_t": c_void_p, "intptr_t": c_void_p, "GLuint": c_uint, "unsignedlong": c_ulong, "long": c_long, "size_t": c_size_t, "off_t": c_int64, "time_t": c_int64, "va_list": c_void_p, "float": c_float, "double": c_double, "al_fixed": c_int, "HWND": c_void_p, "char*": _AL_UTF8String, # hack: this probably shouldn't be in the public docs "postprocess_callback_t": c_void_p, } ptype = re.sub(r"\b(struct|union)\b", "", ptype) ptype = re.sub(r"\bconst\b", "", ptype) ptype = re.sub(r"\bextern\b", "", ptype) ptype = re.sub(r"\b__inline__\b", "", ptype) ptype = re.sub(r"\s+", "", ptype) if ptype.endswith("*"): if ptype in conversion: return conversion[ptype] t = ptype[:-1] if t in self.types: return POINTER(self.types[t]) return c_void_p elif ptype in self.types: return self.types[ptype] else: try: return conversion[ptype] except KeyError: print("Type Error:" + str(ptype)) return None def parse_funcs(self, funcs): """ Go through all documented functions and add their prototypes as Python functions. The file should have been generated by Allegro's documentation generation scripts. """ for func in funcs: name, proto = func.split(":", 1) if not name.startswith("al_"): continue proto = proto.strip() name = name[:-2] if proto.startswith("enum"): continue if proto.startswith("typedef"): continue if "=" in proto: continue if proto.startswith("#"): continue funcstart = proto.find(name) funcend = funcstart + len(name) ret = proto[:funcstart].rstrip() params = proto[funcend:].strip(" ;") if params[0] != "(" or params[-1] != ")": print("Error:") print(params) continue params2 = params[1:-1] # remove callback argument lists balance = 0 params = "" for c in params2: if c == ")": balance -= 1 if balance == 0: params += c if c == "(": balance += 1 params = params.split(",") plist = [] for param in params: param = re.sub(r"\bconst\b", "", param) param = param.strip() if param == "void": continue if param == "": continue if param == "...": continue # treat arrays as a void pointer, for now if param.endswith("]") or param.endswith("*"): plist.append(c_void_p) continue # treat callbacks as a void pointer, for now if param.endswith(")"): plist.append(c_void_p) continue mob = re.match("^.*?(\w+)$", param) if mob: pnamepos = mob.start(1) if pnamepos == 0: # Seems the parameter is not named pnamepos = len(param) else: print(params) print(proto) print("") continue ptype = param[:pnamepos] ptype = self.get_type(ptype) plist.append(ptype) f = type("", (object, ), {"restype": c_int}) if not ret.endswith("void"): f.restype = self.get_type(ret) try: f.argtypes = plist except TypeError as e: print(e) print(name) print(plist) self.functions[name] = f def parse_protos(self, filename): protos = [] unions = [] funcs = [] # first pass: create all structs, but without fields for line in open(filename): name, proto = line.split(":", 1) proto = proto.lstrip() if name.endswith("()"): funcs.append(line) continue # anonymous structs have no name at all if name and not name.startswith("ALLEGRO_"): continue if name == "ALLEGRO_OGL_EXT_API": continue if proto.startswith("union") or\ proto.startswith("typedef union"): self.add_union(name) unions.append((name, proto)) elif proto.startswith("struct") or\ proto.startswith("typedef struct"): self.add_struct(name) protos.append((name, proto)) elif proto.startswith("enum") or\ proto.startswith("typedef enum"): if name: self.types[name] = c_int protos.append(("", proto)) elif proto.startswith("#define"): if not name.startswith("_") and not name.startswith("GL_"): i = eval(proto.split(None, 2)[2]) self.constants[name] = i else: # actual typedef mob = re.match("typedef (.*) " + name, proto) if mob: t = mob.group(1) self.types[name] = self.get_type(t.strip()) else: # Probably a function pointer self.types[name] = c_void_p protos += unions # second pass: fill in fields for name, proto in protos: bo = proto.find("{") if bo == -1: continue bc = proto.rfind("}") braces = proto[bo + 1:bc] if proto.startswith("enum") or \ proto.startswith("typedef enum"): fields = braces.split(",") i = 0 for field in fields: if "=" in field: fname, val = field.split("=", 1) fname = fname.strip() # replace any 'X' (an integer value in C) with # ord('X') to match up in Python val = re.sub("('.')", "ord(\\1)", val) try: i = int(eval(val, globals(), self.constants)) except NameError: i = val except Exception: raise ValueError( "Exception while parsing '{}'".format( val)) else: fname = field.strip() if not fname: continue self.constants[fname] = i try: i += 1 except TypeError: pass continue balance = 0 fields = [""] for c in braces: if c == "{": balance += 1 if c == "}": balance -= 1 if c == ";" and balance == 0: fields.append("") else: fields[-1] += c flist = [] for field in fields: if not field: continue # add function pointer as void pointer mob = re.match(".*?\(\*(\w+)\)", field) if mob: flist.append((mob.group(1), "c_void_p")) continue # add any pointer as void pointer mob = re.match(".*?\*(\w+)$", field) if mob: flist.append((mob.group(1), "c_void_p")) continue # add an array mob = re.match("(.*)\s+(\w+)\[(.*?)\]$", field) if mob: # this is all a hack n = 0 ftype = mob.group(1) if ftype.startswith("struct"): if ftype == "struct {float axis[3];}": t = "c_float * 3" else: print("Error: Can't parse " + ftype + " yet.") t = None else: n = mob.group(3) # something in A5 uses a 2d array if "][" in n: n = n.replace("][", " * ") # something uses a division expression if "/" in n: n = "(" + n.replace("/", "//") + ")" t = self.get_type(ftype).__name__ + " * " + n fname = mob.group(2) flist.append((fname, t)) continue vars = field.split(",") mob = re.match("\s*(.*?)\s+(\w+)\s*$", vars[0]) t = self.get_type(mob.group(1)) vname = mob.group(2) if t is not None and vname is not None: flist.append((vname, t.__name__)) for v in vars[1:]: flist.append((v.strip(), t.__name__)) else: print("Error: " + str(vars)) try: self.types[name].my_fields = flist except AttributeError: print(name, flist) self.parse_funcs(funcs) def main(): p = optparse.OptionParser() p.add_option("-o", "--output", help="location of generated file") p.add_option("-p", "--protos", help="A file with all " + "prototypes to generate Python wrappers for, one per line. " "Generate it with docs/scripts/checkdocs.py -p") p.add_option("-t", "--type", help="the library type to " + "use, e.g. debug") p.add_option("-v", "--version", help="the library version to " + "use, e.g. 5.1") options, args = p.parse_args() if not options.protos: p.print_help() return al = Allegro() al.parse_protos(options.protos) f = open(options.output, "w") if options.output else sys.stdout release = options.type version = options.version f.write(r"""# Generated by generate_python_ctypes.py. import os, platform, sys from ctypes import * from ctypes.util import * # You must adjust this function to point ctypes to the A5 DLLs you are # distributing. _dlls = [] def _add_dll(name): release = "%(release)s" if os.name == "nt": release = "%(release)s-%(version)s" # Under Windows, DLLs are found in the current directory, so this # would be an easy way to keep all your DLLs in a sub-folder. # os.chdir("dlls") path = find_library(name + release) if not path: if os.name == "mac": path = name + release + ".dylib" elif os.name == "nt": path = name + release + ".dll" elif os.name == "posix": if platform.mac_ver()[0]: path = name + release + ".dylib" else: path = "lib" + name + release + ".so" else: sys.stderr.write("Cannot find library " + name + "\n") # In most cases, you actually don't want the above and instead # use the exact filename within your game distribution, possibly # even within a .zip file. # if not os.path.exists(path): # path = "dlls/" + path try: # RTLD_GLOBAL is required under OSX for some reason (?) _dlls.append(CDLL(path, RTLD_GLOBAL)) except OSError: # No need to fail here, might just be one of the addons. pass # os.chdir("..") _add_dll("allegro") _add_dll("allegro_acodec") _add_dll("allegro_audio") _add_dll("allegro_primitives") _add_dll("allegro_color") _add_dll("allegro_font") _add_dll("allegro_ttf") _add_dll("allegro_image") _add_dll("allegro_dialog") _add_dll("allegro_memfile") _add_dll("allegro_physfs") _add_dll("allegro_shader") _add_dll("allegro_main") _add_dll("allegro_video") _add_dll("allegro_monolith") # We don't have information ready which A5 function is in which DLL, # so we just try them all. def _dll(func, ret, params): for dll in _dlls: try: f = dll[func] f.restype = ret f.argtypes = params if ret is _AL_UTF8String: # ctypes cannot do parameter conversion of the return type for us f.restype = c_char_p if sys.version_info[0] > 2: return lambda *x: f(*x).decode("utf8") return f except AttributeError: pass sys.stderr.write("Cannot find function " + func + "\n") return lambda *args: None # In Python3, all Python strings are unicode so we have to convert to # UTF8 byte strings before passing to Allegro. if sys.version_info[0] > 2: class _AL_UTF8String: def from_param(x): return x.encode("utf8") else: _AL_UTF8String = c_char_p """ % locals()) postpone = [] for name, val in sorted(al.constants.items()): try: if isinstance(val, str): val = int(eval(val, globals(), al.constants)) f.write(name + " = " + str(val) + "\n") except: postpone.append((name, val)) for name, val in postpone: f.write(name + " = " + val + "\n") structs = set() # output everything except structs and unions for name, x in sorted(al.types.items()): if not name: continue base = x.__bases__[0] if base != Structure and base != Union: f.write(name + " = " + x.__name__ + "\n") else: structs.add(name) # order structs and unions by their dependencies structs_list = [] remaining = set(structs) while remaining: for name in sorted(remaining): ok = True x = al.types[name] if hasattr(x, "my_fields"): for fname, ftype in x.my_fields: if " " in ftype: ftype = ftype.split()[0] if ftype in structs and ftype in remaining: ok = False break if ok: structs_list.append(name) remaining.remove(name) for name in structs_list: x = al.types[name] base = x.__bases__[0] f.write("class " + name + "(" + base.__name__ + "):\n") if hasattr(x, "my_fields"): f.write(" _fields_ = [\n") for fname, ftype in x.my_fields: f.write(" (\"" + fname + "\", " + ftype + "),\n") f.write(" ]\n") else: f.write(" pass\n") pt = POINTER(x) f.write("%s = POINTER(%s)\n" % (pt.__name__, name)) for name, x in sorted(al.functions.items()): try: line = name + " = _dll(\"" + name + "\", " line += x.restype.__name__ + ", " line += "[" + (", ".join([a.__name__ for a in x.argtypes])) +\ "])\n" f.write(line) except AttributeError as e: print("Ignoring " + name + " because of errors (" + str(e) + ").") # some stuff the automated parser doesn't pick up f.write(r""" ALLEGRO_VERSION_INT = \ ((ALLEGRO_VERSION << 24) | (ALLEGRO_SUB_VERSION << 16) | \ (ALLEGRO_WIP_VERSION << 8) | ALLEGRO_RELEASE_NUMBER) """) f.write(r""" # work around bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36834 if os.name == "nt": def al_map_rgba_f(r, g, b, a): return ALLEGRO_COLOR(r, g, b, a) def al_map_rgb_f(r, g, b): return ALLEGRO_COLOR(r, g, b, 1) def al_map_rgba(r, g, b, a): return ALLEGRO_COLOR(r / 255.0, g / 255.0, b / 255.0, a / 255.0) def al_map_rgb(r, g, b): return ALLEGRO_COLOR(r / 255.0, g / 255.0, b / 255.0, 1) """) f.write(""" def al_main(real_main, *args): def python_callback(argc, argv): real_main(*args) return 0 cb = CFUNCTYPE(c_int, c_int, c_void_p)(python_callback) al_run_main(0, 0, cb); """) f.close() main() allegro5-5.2.10.1/python/pong.py000077500000000000000000000251541473414355200163300ustar00rootroot00000000000000#!/usr/bin/env python3 """ Allegro Python port game example Original Author: Jeroen De Busser """ from allegro import * from random import randint, random import os examples_data = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "examples/data")) class Pallet: def __init__(self, x, y, w, h, speed, color): self.__initials = (x, y, w, h, speed, color, 0) self.reset() def reset(self): '''Resets this pallet to its starting values ''' self.x, self.y, self.w, self.h, self.speed, self.color, self.moving =\ self.__initials def update(self): self.y += self.moving * self.speed if self.y < 0: self.y = 0 elif self.y > al_get_display_height(al_get_current_display()) - self.h: self.y = al_get_display_height(al_get_current_display()) - self.h def draw(self): # Fill al_draw_filled_rounded_rectangle(self.x, self.y, self.x + self.w, self.y + self.h, 6, 6, self.color) # Highlight al_draw_filled_rounded_rectangle(self.x + 2, self.y + 2, self.x + self.w / 2, self.y + self.h - 5, 4, 4, al_map_rgba_f(0.2, 0.2, 0.2, 0.2)) class Player(Pallet): def __init__(self, x, y, h, w, speed, keyup, keydown, color): self.__initials = (x, y, h, w, speed, keyup, keydown, color) Pallet.__init__(self, x, y, h, w, speed, color) self.keyup, self.keydown = keyup, keydown def handle_event(self, ev): if ev.type == ALLEGRO_EVENT_KEY_DOWN: if ev.keyboard.keycode == self.keyup: self.moving = -1 elif ev.keyboard.keycode == self.keydown: self.moving = 1 elif ev.type == ALLEGRO_EVENT_KEY_UP: if (ev.keyboard.keycode == self.keyup and self.moving == -1) or\ (ev.keyboard.keycode == self.keydown and self.moving == 1): self.moving = 0 class AI(Pallet): def __init__(self, x, y, w, h, speed, color, difficulty, ball): Pallet.__init__(self, x, y, w, h, speed, color) self.difficulty = difficulty self.ball = ball def handle_event(self, ev): #Only fire on a timer event if ev.type == ALLEGRO_EVENT_TIMER: #Calculate the target y location according to the difficulty level if self.difficulty == 1: target_y = self.ball.y + self.ball.size / 2 else: # Higher difficulty, so we need to precalculate the position of # the ball if it is closer than a certain treshold dh = al_get_display_height(al_get_current_display()) if self.ball.xdir == -1 or abs(self.x - self.ball.x) >\ al_get_display_width(al_get_current_display()) * ( self.difficulty - 1) / self.difficulty: # If the ball is moving away, return to the center of the # screen target_y = dh / 2 else: # The ball is moving towards this pallet within its FOV. # Calculate what the y location of the ball will be when it # lands at this pallets x location target_y = self.ball.y + (self.x - self.ball.x) *\ self.ball.ydir if target_y < 0: target_y = abs(target_y) elif target_y > dh: target_y = dh - target_y % dh #Set the movement if target_y > self.y + self.h * 3 / 4: self.moving = 1 elif target_y < self.y + self.h * 1 / 4: self.moving = -1 else: self.moving = 0 class Ball: def __init__(self, x, y, speed, size, pallets, color): self.x, self.y, self.speed, self.size, self.pallets, self.color =\ x, y, speed, size, pallets, color self.xdir = randint(0, 1) self.xdir = self.xdir - (self.xdir == 0) self.ydir = randint(0, 1) self.ydir = self.ydir - (self.ydir == 0) def update(self): new_x = self.x + self.xdir * self.speed new_y = self.y + self.ydir * self.speed p = self.pallets[(self.xdir == 1)] # The pallet this ball is flying to if ((new_x <= p.x + p.w and self.xdir == -1) or (new_x + self.size >= p.x and self.xdir == 1)) and new_y + self.size >= p.y and\ new_y <= p.y + p.h: # We hit the pallet self.xdir = -self.xdir self.speed += 0.1 self.on_pallet_touch(p) self.new_x = self.x dw = al_get_display_width(al_get_current_display()) dh = al_get_display_height(al_get_current_display()) if self.x < 0 or self.x > dw: self.on_screen_exit() if new_y < 0 or new_y + self.size > dh: # We hit a wall self.ydir = -self.ydir new_y = self.y # Reset the y value self.x = new_x self.y = new_y def on_pallet_touch(self, pallet): """This function should be called on hitting a pallet""" pass def on_screen_exit(self): '''This function is called when this ball exits the screen''' pass def draw(self): # Fill al_draw_filled_circle(self.x + self.size / 2, self.y + self.size / 2, self.size / 2, self.color) # Highlight al_draw_filled_circle(self.x + self.size / 4, self.y + self.size / 4, self.size / 6, al_map_rgb_f(0.8, 0.9, 0.8)) class Upgrade(Ball): def __init__(self, x, y, speed, pallets, color, effect_function): Ball.__init__(self, x, y, speed, 10, pallets, color) self.function = effect_function self.touched = False def on_pallet_touch(self, pallet): self.touched = True self.function(pallet) def on_screen_exit(self): self.touched = True def main(): #Initialisation difficulty = int(input("What difficulty do you want to play on? " + "Input: 0 for two-player mode, 1-4 for AI difficulty setting.\n")) al_install_system(ALLEGRO_VERSION_INT, None) w, h = 800, 600 #Make lines draw smoother al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST) al_set_new_display_option(ALLEGRO_SAMPLES, 4, ALLEGRO_SUGGEST) display = al_create_display(w, h) al_init_primitives_addon() al_install_keyboard() al_init_image_addon() al_init_font_addon() font = al_load_font(os.path.join(examples_data, "fixed_font.tga"), 0, 0) finished = False need_redraw = True FPS = 60 pallet_w, pallet_h, pallet_speed = 20, 80, 5 ball_size, ball_speed = 30, 4.6 players = [] players.append(Player(0, h / 2 - pallet_h / 2, pallet_w, pallet_h, pallet_speed, ALLEGRO_KEY_W, ALLEGRO_KEY_S, al_map_rgb_f(1.0, 0.0, 0.0))) ball = Ball(w / 2, h / 2, ball_speed, ball_size, players, al_map_rgb_f(0, 1.0, 0)) if not difficulty: players.append(Player(w - pallet_w, h / 2 - pallet_h / 2, pallet_w, pallet_h, pallet_speed, ALLEGRO_KEY_UP, ALLEGRO_KEY_DOWN, al_map_rgb_f(0.0, 0.0, 1.0))) else: players.append(AI(w - pallet_w, h / 2 - pallet_h / 2, pallet_w, pallet_h, pallet_speed, al_map_rgb_f(0.0, 0.0, 1.0), difficulty, ball)) def upgrade_grow_height(pallet): pallet.h *= 1.25 def upgrade_shrink_height(pallet): pallet.h *= 0.8 def upgrade_increase_speed(pallet): pallet.speed *= 1.5 def upgrade_decrease_speed(pallet): pallet.speed /= 1.5 upgrade_types = [ (al_map_rgb_f(0.0, 1.0, 0.0), upgrade_grow_height), (al_map_rgb_f(1.0, 0.0, 0.0), upgrade_shrink_height), (al_map_rgb_f(1.0, 1.0, 1.0), upgrade_increase_speed), (al_map_rgb_f(0.3, 0.3, 0.3), upgrade_decrease_speed)] upgrade_probability = 0.005 timer = al_create_timer(1.0 / FPS) queue = al_create_event_queue() al_register_event_source(queue, al_get_timer_event_source(timer)) al_register_event_source(queue, al_get_keyboard_event_source()) al_register_event_source(queue, al_get_display_event_source(display)) al_start_timer(timer) upgrades = [] score = [0, 0] while True: if need_redraw and al_is_event_queue_empty(queue): al_clear_to_color(al_map_rgb_f(0, 0, 0)) for player in players: player.draw() ball.draw() for upgrade in upgrades: upgrade.draw() if not finished: al_draw_text(font, al_map_rgb_f(1, 1, 1), w / 2, 10, ALLEGRO_ALIGN_CENTRE, "Player 1: use W and S to move, " + "Player 2: use the up and down arrow keys.") else: al_draw_text(font, al_map_rgb_f(1, 1, 1), w / 2, 10, ALLEGRO_ALIGN_CENTRE, "Press R to reset, ESC to exit.") al_draw_text(font, al_map_rgb_f(1, 1, 1), w / 2, h - 20, ALLEGRO_ALIGN_CENTRE, "{0} - {1}".format(*score)) al_flip_display() need_redraw = False ev = ALLEGRO_EVENT() al_wait_for_event(queue, byref(ev)) if ev.type == ALLEGRO_EVENT_TIMER: for player in players: player.update() ball.update() if ball.x + ball.size < 0 or ball.x > w: finished = True score[ball.x < 0] += 1 al_stop_timer(timer) for upgrade in upgrades: upgrade.update() if upgrade.touched: upgrades.remove(upgrade) if random() < upgrade_probability: i = randint(0, len(upgrade_types) - 1) upgrades.append(Upgrade(w / 2, h / 2, ball_speed, players, upgrade_types[i][0], upgrade_types[i][1])) need_redraw = True elif (ev.type == ALLEGRO_EVENT_KEY_DOWN and ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) or\ ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE: break elif ev.type == ALLEGRO_EVENT_KEY_DOWN and\ ev.keyboard.keycode == ALLEGRO_KEY_R: ball.x = w / 2 ball.y = h / 2 ball.speed = ball_speed upgrades = [] for player in players: player.reset() al_start_timer(timer) finished = False for player in players: player.handle_event(ev) al_uninstall_system() if __name__ == '__main__': #Only start the game when this file is executed directly. al_main(main) allegro5-5.2.10.1/python/readme.txt000066400000000000000000000064771473414355200170150ustar00rootroot00000000000000# Python wrapper This wrapper is not a proper Python-Allegro, but a simple 1:1 export of all Allegro functions and constants using ctypes. ## Building Enable WANT_PYTHON_WRAPPER in cmake and you should end up with a single file called allegro.py in the python folder of your build directory. You also need to build the shared version so you end up with either: Windows: liballegro*.dll OSX: liballegro*.dylib Unix: liballegro*.so For simplicity we will simply call those files "DLL files". ## Using it Distribute the allegro.py as well as the required DLL files along with your project. If you want you can modify it to directly point to the DLL files so you can be sure they are found. By default, it will try several system specific locations. E.g. in linux it will find .so files as long as they are in LD_LIBRARY_PATH or in ldconfig paths. For distribution build of your game, this usually means that the .so files are found within your distributions /usr/lib directory. For a standalone distribution, you may provide a shell script which modifies LD_LIBRARY_PATH to point to your game's library folder then runs the python executable. To run the included Python example something like this will work under Linux, starting within the Allegro source distribution folder: mkdir build cd build cmake -D WANT_PYTHON_WRAPPER=1 .. make export PYTHONPATH=python/ export LD_LIBRARY_PATH=lib/ python ../python/ex_draw_bitmap.py We use PYTHONPATH to specify the location of the allegro.py module and LD_LIBRARY_PATH to specify the location of the .so files. For OSX, this should work: mkdir build cd build cmake -D WANT_PYTHON_WRAPPER=1 .. make export PYTHONPATH=python/ export DYLD_LIBRARY_PATH=lib/ python ../python/ex_draw_bitmap.py For Windows: Make sure to have WANT_PYTHON_WRAPPER enabled when building. It doesn't matter whether you use mingw or MSVC, but Python must be installed on your system. Then run ex_draw_bitmap.py. The DLLs as well as allegro.py must be found, easiest is to just have them all in the same directory. Or you can also edit allegro.py and specify a directory from which to load the DLLs - see the comments in there. ## Limitations Right now this is only a proof-of concept implementation, some important things still have to be fixed: ### Variable arguments not parsed properly yet For example, if C code has: al_draw_textf(font, x, y, flags, "%d, %d", x, y); You have to do it like this in Python right now: al_draw_textf(font, x, y, flags, "%s", "%d, %d" % (x, y)) ### No reference counting or garbage collection For example, if you call al_load_bitmap, a C pointer is returned. If it goes out of scope you end up with a memory leak - very unpythonic. Therefore you should do something like this: class Bitmap: def __init__(self, filename): self.c_pointer = al_load_bitmap(filename) def __del__(self): al_destroy_bitmap(self.c_pointer) def draw(self, x, y, flags): al_draw_bitmap(self.c_pointer, x, y, flags); In other words, make a proper Python wrapper. ### No docstrings Even though the documentation system provides the description of each functions it's not copied into allegro.py right now. You will need to use the C documentation until this is fixed. ### Need more examples Or a demo game. It should test that at least each addon can be used. allegro5-5.2.10.1/src/000077500000000000000000000000001473414355200142475ustar00rootroot00000000000000allegro5-5.2.10.1/src/allegro.c000066400000000000000000000024121473414355200160370ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Assorted routines. * * By Shawn Hargreaves and Allegro developers. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/platform/alplatf.h" #include "allegro5/internal/aintern.h" #include ALLEGRO_INTERNAL_HEADER /* Function: al_get_allegro_version */ uint32_t al_get_allegro_version(void) { return ALLEGRO_VERSION_INT; } /* Function: al_run_main */ int al_run_main(int argc, char **argv, int (*user_main)(int, char **)) { #ifdef ALLEGRO_MACOSX return _al_osx_run_main(argc, argv, user_main); #else return user_main(argc, argv); #endif } int _al_get_least_multiple(int val, int mul) { int rem = val % mul; if (rem == 0) return val; else return val + mul - rem; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/android/000077500000000000000000000000001473414355200156675ustar00rootroot00000000000000allegro5-5.2.10.1/src/android/android_apk_file.c000066400000000000000000000134231473414355200213100ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_android.h" #include "allegro5/internal/aintern_android.h" #define streq(a, b) (0 == strcmp(a, b)) ALLEGRO_DEBUG_CHANNEL("android") typedef struct ALLEGRO_FILE_APK ALLEGRO_FILE_APK; struct ALLEGRO_FILE_APK { jobject apk; bool error_indicator; }; static ALLEGRO_FILE_APK *cast_stream(ALLEGRO_FILE *f) { return (ALLEGRO_FILE_APK *)al_get_file_userdata(f); } static void apk_set_errno(ALLEGRO_FILE_APK *fp) { al_set_errno(-1); if (fp) { fp->error_indicator = true; } } static jobject APK_openRead(const char *filename) { JNIEnv *jnienv; jmethodID ctor; jstring str; jobject is, ref; jboolean res; jnienv = _al_android_get_jnienv(); ctor = _jni_call(jnienv, jclass, GetMethodID, _al_android_apk_stream_class(), "", "(L" ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/AllegroActivity;Ljava/lang/String;)V"); str = (*jnienv)->NewStringUTF(jnienv, filename); ref = _jni_call(jnienv, jobject, NewObject, _al_android_apk_stream_class(), ctor, _al_android_activity_object(), str); is = _jni_call(jnienv, jobject, NewGlobalRef, ref); _jni_callv(jnienv, DeleteLocalRef, ref); _jni_callv(jnienv, DeleteLocalRef, str); res = _jni_callBooleanMethodV(_al_android_get_jnienv(), is, "open", "()Z"); return (res) ? is : NULL; } static bool APK_close(jobject apk_stream) { jboolean ret = _jni_callBooleanMethodV(_al_android_get_jnienv(), apk_stream, "close", "()Z"); _jni_callv(_al_android_get_jnienv(), DeleteGlobalRef, apk_stream); if (ret) { apk_set_errno(NULL); } return ret; } static bool APK_seek(jobject apk_stream, long bytes) { jboolean res = _jni_callBooleanMethodV(_al_android_get_jnienv(), apk_stream, "seek", "(J)Z", (jlong)bytes); return res; } static long APK_tell(jobject apk_stream) { long res = _jni_callLongMethodV(_al_android_get_jnienv(), apk_stream, "tell", "()J"); return res; } static int APK_read(jobject apk_stream, char *buf, int len) { JNIEnv *jnienv = _al_android_get_jnienv(); jbyteArray b = (*jnienv)->NewByteArray(jnienv, len); jint res = _jni_callIntMethodV(jnienv, apk_stream, "read", "([B)I", b); if (res > 0) { (*jnienv)->GetByteArrayRegion(jnienv, b, 0, res, (jbyte *)buf); } _jni_callv(jnienv, DeleteLocalRef, b); return res; } static long APK_size(jobject apk_stream) { long res = _jni_callLongMethod(_al_android_get_jnienv(), apk_stream, "size"); return res; } static void *file_apk_fopen(const char *filename, const char *mode) { ALLEGRO_FILE_APK *fp; jobject apk; if (streq(mode, "r") || streq(mode, "rb")) apk = APK_openRead(filename); else return NULL; if (!apk) { apk_set_errno(NULL); return NULL; } fp = al_malloc(sizeof(*fp)); if (!fp) { al_set_errno(ENOMEM); APK_close(apk); return NULL; } fp->apk = apk; fp->error_indicator = false; return fp; } static bool file_apk_fclose(ALLEGRO_FILE *f) { ALLEGRO_FILE_APK *fp = cast_stream(f); bool ret; ret = APK_close(fp->apk); al_free(fp); return ret; } static size_t file_apk_fread(ALLEGRO_FILE *f, void *buf, size_t buf_size) { ALLEGRO_FILE_APK *fp = cast_stream(f); int n; if (buf_size == 0) return 0; n = APK_read(fp->apk, buf, buf_size); if (n < 0) { apk_set_errno(fp); return 0; } return n; } static size_t file_apk_fwrite(ALLEGRO_FILE *f, const void *buf, size_t buf_size) { // Not supported (void)f; (void)buf; (void)buf_size; return 0; } static bool file_apk_fflush(ALLEGRO_FILE *f) { // Not supported (void)f; return true; } static int64_t file_apk_ftell(ALLEGRO_FILE *f) { ALLEGRO_FILE_APK *fp = cast_stream(f); return APK_tell(fp->apk); } static bool file_apk_seek(ALLEGRO_FILE *f, int64_t offset, int whence) { ALLEGRO_FILE_APK *fp = cast_stream(f); long base; switch (whence) { case ALLEGRO_SEEK_SET: base = 0; break; case ALLEGRO_SEEK_CUR: base = APK_tell(fp->apk); if (base < 0) { apk_set_errno(fp); return false; } break; case ALLEGRO_SEEK_END: base = APK_size(fp->apk); if (base < 0) { apk_set_errno(fp); return false; } break; default: al_set_errno(EINVAL); return false; } if (!APK_seek(fp->apk, base + offset)) { apk_set_errno(fp); return false; } return true; } static bool file_apk_feof(ALLEGRO_FILE *f) { ALLEGRO_FILE_APK *fp = cast_stream(f); jboolean res = _jni_callBooleanMethodV(_al_android_get_jnienv(), fp->apk, "eof", "()Z"); return res; } static int file_apk_ferror(ALLEGRO_FILE *f) { ALLEGRO_FILE_APK *fp = cast_stream(f); return (fp->error_indicator) ? 1 : 0; } static const char *file_apk_ferrmsg(ALLEGRO_FILE *f) { (void)f; return ""; } static void file_apk_fclearerr(ALLEGRO_FILE *f) { ALLEGRO_FILE_APK *fp = cast_stream(f); fp->error_indicator = false; } static off_t file_apk_fsize(ALLEGRO_FILE *f) { ALLEGRO_FILE_APK *fp = cast_stream(f); return APK_size(fp->apk); } static const ALLEGRO_FILE_INTERFACE file_apk_vtable = { file_apk_fopen, file_apk_fclose, file_apk_fread, file_apk_fwrite, file_apk_fflush, file_apk_ftell, file_apk_seek, file_apk_feof, file_apk_ferror, file_apk_ferrmsg, file_apk_fclearerr, NULL, /* default ungetc implementation */ file_apk_fsize }; const ALLEGRO_FILE_INTERFACE *_al_get_apk_file_vtable(void) { return &file_apk_vtable; } /* Function: al_android_set_apk_file_interface */ void al_android_set_apk_file_interface(void) { al_set_new_file_interface(&file_apk_vtable); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/android/android_apk_fs.c000066400000000000000000000151401473414355200207770ustar00rootroot00000000000000/* * Filesystem driver for APK contents. * * By Elias Pschernig. */ #include "allegro5/allegro.h" #include "allegro5/allegro_android.h" #include "allegro5/internal/aintern_android.h" #include ALLEGRO_DEBUG_CHANNEL("android") typedef struct ALLEGRO_FS_ENTRY_APK ALLEGRO_FS_ENTRY_APK; struct ALLEGRO_FS_ENTRY_APK { ALLEGRO_FS_ENTRY fs_entry; /* must be first */ ALLEGRO_PATH *path; const char *path_cstr; /* For directory listing. */ char *file_list; char *file_list_pos; bool is_dir_open; }; /* forward declaration */ static const ALLEGRO_FS_INTERFACE fs_apk_vtable; /* current working directory */ /* TODO: free this somewhere */ static ALLEGRO_USTR *fs_apk_cwd_ustr; static ALLEGRO_FILE *fs_apk_open_file(ALLEGRO_FS_ENTRY *fse, const char *mode); static ALLEGRO_USTR *get_fake_cwd(void) { if (!fs_apk_cwd_ustr) { fs_apk_cwd_ustr = al_ustr_new("/"); } return fs_apk_cwd_ustr; } static bool path_is_absolute(const char *path) { return (path && path[0] == '/'); } static void ensure_trailing_slash(ALLEGRO_USTR *us) { int pos = al_ustr_size(us); if (al_ustr_prev_get(us, &pos) != '/') { al_ustr_append_chr(us, '/'); } } static ALLEGRO_USTR *apply_cwd(const char *path) { ALLEGRO_USTR *us; if (path_is_absolute(path)) { return al_ustr_new(path); } us = al_ustr_dup(get_fake_cwd()); al_ustr_append_cstr(us, path); return us; } static ALLEGRO_FS_ENTRY *fs_apk_create_entry(const char *path) { ALLEGRO_FS_ENTRY_APK *e; ALLEGRO_USTR *us; e = al_calloc(1, sizeof *e); if (!e) return NULL; e->fs_entry.vtable = &fs_apk_vtable; us = apply_cwd(path); e->path = al_create_path(al_cstr(us)); al_ustr_free(us); if (!e->path) { al_free(e); return NULL; } e->path_cstr = al_path_cstr(e->path, '/'); return &e->fs_entry; } static char *fs_apk_get_current_directory(void) { return al_cstr_dup(get_fake_cwd()); } static bool fs_apk_change_directory(const char *path) { ALLEGRO_USTR *us; ALLEGRO_USTR *cwd = get_fake_cwd(); /* Figure out which directory we are trying to change to. */ if (path_is_absolute(path)) us = al_ustr_new(path); else us = apply_cwd(path); ensure_trailing_slash(us); al_ustr_assign(cwd, us); al_ustr_free(us); return true; } static bool fs_apk_remove_filename(const char *path) { (void)path; return false; } static bool fs_apk_make_directory(const char *path) { (void)path; return false; } static const char *fs_apk_entry_name(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_APK *e = (ALLEGRO_FS_ENTRY_APK *)fse; return al_path_cstr(e->path, '/'); } static bool fs_apk_update_entry(ALLEGRO_FS_ENTRY *fse) { (void)fse; return true; } static off_t fs_apk_entry_size(ALLEGRO_FS_ENTRY *fse) { // Only way to determine the size would be to read the file... // we won't do that. (void)fse; return 0; } static uint32_t fs_apk_entry_mode(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_APK *e = (ALLEGRO_FS_ENTRY_APK *)fse; uint32_t mode = ALLEGRO_FILEMODE_READ; int n = strlen(e->path_cstr); if (e->path_cstr[n - 1] == '/') mode |= ALLEGRO_FILEMODE_ISDIR | ALLEGRO_FILEMODE_EXECUTE; else mode |= ALLEGRO_FILEMODE_ISFILE; return mode; } static time_t fs_apk_entry_mtime(ALLEGRO_FS_ENTRY *fse) { (void)fse; return 0; } static bool fs_apk_entry_exists(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FILE *f = fs_apk_open_file(fse, "r"); if (f) { al_fclose(f); return true; } return false; } static bool fs_apk_remove_entry(ALLEGRO_FS_ENTRY *fse) { (void)fse; return false; } static bool fs_apk_open_directory(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_APK *e = (ALLEGRO_FS_ENTRY_APK *)fse; JNIEnv *jnienv; jnienv = _al_android_get_jnienv(); jstring jpath = (*jnienv)->NewStringUTF(jnienv, e->path_cstr); jstring js = _jni_callStaticObjectMethodV(jnienv, _al_android_apk_fs_class(), "list", "(L" ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/AllegroActivity;Ljava/lang/String;)Ljava/lang/String;", _al_android_activity_object(), jpath); const char *cs = _jni_call(jnienv, const char *, GetStringUTFChars, js, NULL); e->file_list = al_malloc(strlen(cs) + 1); strcpy(e->file_list, cs); e->file_list_pos = e->file_list; _jni_callv(jnienv, ReleaseStringUTFChars, js, cs); _jni_callv(jnienv, DeleteLocalRef, js); _jni_callv(jnienv, DeleteLocalRef, jpath); e->is_dir_open = true; return true; } static ALLEGRO_FS_ENTRY *fs_apk_read_directory(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_APK *e = (ALLEGRO_FS_ENTRY_APK *)fse; ALLEGRO_FS_ENTRY *next; ALLEGRO_USTR *tmp; if (!e->file_list_pos) return NULL; if (!*e->file_list_pos) return NULL; tmp = al_ustr_new(e->path_cstr); ensure_trailing_slash(tmp); char *name = e->file_list_pos; char *semi = strchr(name, ';'); if (semi) { *semi = 0; e->file_list_pos = semi + 1; } else { e->file_list_pos = name + strlen(name); } al_ustr_append_cstr(tmp, name); next = fs_apk_create_entry(al_cstr(tmp)); al_ustr_free(tmp); return next; } static bool fs_apk_close_directory(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_APK *e = (ALLEGRO_FS_ENTRY_APK *)fse; al_free(e->file_list); e->file_list = NULL; e->is_dir_open = false; return true; } static void fs_apk_destroy_entry(ALLEGRO_FS_ENTRY *fse) { ALLEGRO_FS_ENTRY_APK *e = (ALLEGRO_FS_ENTRY_APK *)fse; if (e->is_dir_open) fs_apk_close_directory(fse); al_destroy_path(e->path); al_free(e); } static ALLEGRO_FILE *fs_apk_open_file(ALLEGRO_FS_ENTRY *fse, const char *mode) { return al_fopen_interface(_al_get_apk_file_vtable(), fs_apk_entry_name(fse), mode); } static bool fs_apk_filename_exists(const char *path) { bool ret; ALLEGRO_FS_ENTRY *e = fs_apk_create_entry(path); ret = fs_apk_entry_exists(e); fs_apk_destroy_entry(e); return ret; } static const ALLEGRO_FS_INTERFACE fs_apk_vtable = { fs_apk_create_entry, fs_apk_destroy_entry, fs_apk_entry_name, fs_apk_update_entry, fs_apk_entry_mode, fs_apk_entry_mtime, fs_apk_entry_mtime, fs_apk_entry_mtime, fs_apk_entry_size, fs_apk_entry_exists, fs_apk_remove_entry, fs_apk_open_directory, fs_apk_read_directory, fs_apk_close_directory, fs_apk_filename_exists, fs_apk_remove_filename, fs_apk_get_current_directory, fs_apk_change_directory, fs_apk_make_directory, fs_apk_open_file }; /* Function: al_android_set_apk_fs_interface */ void al_android_set_apk_fs_interface(void) { al_set_fs_interface(&fs_apk_vtable); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/android/android_clipboard.c000066400000000000000000000045421473414355200214770ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_//_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Android clipboard handling. * * By Beoran. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_android.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_android.h" #include "allegro5/internal/aintern_bitmap.h" #include ALLEGRO_DEBUG_CHANNEL("clipboard") static bool android_set_clipboard_text(ALLEGRO_DISPLAY *display, const char *text) { JNIEnv * env = (JNIEnv *)_al_android_get_jnienv(); jstring jtext= _jni_call(env, jstring, NewStringUTF, text); (void) display; return _jni_callBooleanMethodV(env, _al_android_activity_object(), "setClipboardText", "(Ljava/lang/String;)Z", jtext); } static char *android_get_clipboard_text(ALLEGRO_DISPLAY *display) { JNIEnv * env = (JNIEnv *)_al_android_get_jnienv(); jobject jtext = _jni_callObjectMethod(env, _al_android_activity_object(), "getClipboardText", "()Ljava/lang/String;"); jsize len = _jni_call(env, jsize, GetStringUTFLength, jtext); const char *str = _jni_call(env, const char *, GetStringUTFChars, jtext, NULL); char * text = al_malloc(len+1); (void) display; text = _al_sane_strncpy(text, str, len); _jni_callv(env, ReleaseStringUTFChars, jtext, str); _jni_callv(env, DeleteLocalRef, jtext); return text; } static bool android_has_clipboard_text(ALLEGRO_DISPLAY *display) { JNIEnv * env = (JNIEnv *)_al_android_get_jnienv(); (void) display; return _jni_callBooleanMethodV(env, _al_android_activity_object(), "hasClipboardText", "()Z"); } void _al_android_add_clipboard_functions(ALLEGRO_DISPLAY_INTERFACE *vt) { vt->set_clipboard_text = android_set_clipboard_text; vt->get_clipboard_text = android_get_clipboard_text; vt->has_clipboard_text = android_has_clipboard_text; } /* vi: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/src/android/android_display.c000066400000000000000000000701231473414355200212030ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Android Java/JNI display driver * * By Thomas Fjellstrom. * */ #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern_android.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_shader.h" #include "allegro5/internal/aintern_pixels.h" #include "EGL/egl.h" ALLEGRO_DEBUG_CHANNEL("display") static ALLEGRO_DISPLAY_INTERFACE *vt; static ALLEGRO_EXTRA_DISPLAY_SETTINGS main_thread_display_settings; static int select_best_visual_and_update(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d); static void android_set_display_option(ALLEGRO_DISPLAY *d, int o, int v); static void _al_android_resize_display(ALLEGRO_DISPLAY_ANDROID *d, int width, int height); static bool _al_android_init_display(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *display); void _al_android_clear_current(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d); void _al_android_make_current(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d); JNI_FUNC(void, AllegroSurface, nativeOnCreate, (JNIEnv *env, jobject obj)) { ALLEGRO_DEBUG("nativeOnCreate"); (void)env; (void)obj; ALLEGRO_SYSTEM *system = (void *)al_get_system_driver(); ASSERT(system != NULL); ALLEGRO_DEBUG("AllegroSurface_nativeOnCreate"); ALLEGRO_DISPLAY_ANDROID **dptr = _al_vector_ref(&system->displays, 0); ALLEGRO_DISPLAY_ANDROID *d = *dptr; ASSERT(d != NULL); d->recreate = true; } JNI_FUNC(bool, AllegroSurface, nativeOnDestroy, (JNIEnv *env, jobject obj)) { ALLEGRO_SYSTEM *sys = (void *)al_get_system_driver(); ASSERT(sys != NULL); ALLEGRO_DISPLAY_ANDROID **dptr = _al_vector_ref(&sys->displays, 0); ALLEGRO_DISPLAY_ANDROID *display = *dptr; ASSERT(display != NULL); ALLEGRO_DISPLAY *d = (ALLEGRO_DISPLAY *)display; ALLEGRO_DEBUG("AllegroSurface_nativeOnDestroy"); (void)obj; (void)env; if (!display->created) { ALLEGRO_DEBUG("Display creation failed, not sending HALT"); return false; } display->created = false; if (display->is_destroy_display) { return true; } // we'll wait for acknowledge_drawing_halt display->halt_acknowledge = false; // emit ALLEGRO_EVENT_DISPLAY_HALT_DRAWING ALLEGRO_DEBUG("locking display event source: %p %p", d, &d->es); _al_event_source_lock(&d->es); if (_al_event_source_needs_to_generate_event(&d->es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_HALT_DRAWING; event.display.timestamp = al_current_time(); _al_event_source_emit_event(&d->es, &event); } ALLEGRO_DEBUG("unlocking display event source"); _al_event_source_unlock(&d->es); // wait for acknowledge_drawing_halt ALLEGRO_DEBUG("waiting for acknowledge_drawing_halt"); al_lock_mutex(display->mutex); while (!display->halt_acknowledge) al_wait_cond(display->cond, display->mutex); al_unlock_mutex(display->mutex); ALLEGRO_DEBUG("done waiting for acknowledge_drawing_halt"); ALLEGRO_DEBUG("AllegroSurface_nativeOnDestroy end"); return true; } // FIXME: need to loop over the display list looking for the right surface // object in the following jni callbacks JNI_FUNC(void, AllegroSurface, nativeOnChange, (JNIEnv *env, jobject obj, jint format, jint width, jint height)) { ALLEGRO_SYSTEM *system = (void *)al_get_system_driver(); ASSERT(system != NULL); ALLEGRO_DISPLAY_ANDROID **dptr = _al_vector_ref(&system->displays, 0); ALLEGRO_DISPLAY_ANDROID *d = *dptr; ALLEGRO_DISPLAY *display = (ALLEGRO_DISPLAY*)d; ASSERT(display != NULL); ALLEGRO_DEBUG("on change %dx%d!", width, height); (void)format; if (!d->first_run && !d->recreate) { _al_android_resize_display(d, width, height); return; } al_lock_mutex(d->mutex); if (d->first_run || d->recreate) { d->surface_object = (*env)->NewGlobalRef(env, obj); if (display->flags & ALLEGRO_FULLSCREEN_WINDOW) { display->w = width; display->h = height; } } bool ret = _al_android_init_display(env, d); if (!ret && d->first_run) { al_broadcast_cond(d->cond); al_unlock_mutex(d->mutex); return; } _al_android_clear_current(env, d); d->created = true; d->recreate = false; d->resumed = false; if (!d->first_run) { ALLEGRO_DEBUG("locking display event source: %p", d); _al_event_source_lock(&display->es); ALLEGRO_DEBUG("check generate event"); if (_al_event_source_needs_to_generate_event(&display->es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING; event.display.timestamp = al_current_time(); _al_event_source_emit_event(&display->es, &event); } ALLEGRO_DEBUG("unlocking display event source"); _al_event_source_unlock(&display->es); } if (d->first_run) { al_broadcast_cond(d->cond); d->first_run = false; } else { ALLEGRO_DEBUG("Waiting for al_acknowledge_drawing_resume"); while (!d->resumed) { al_wait_cond(d->cond, d->mutex); } ALLEGRO_DEBUG("Got al_acknowledge_drawing_resume"); } al_unlock_mutex(d->mutex); /* Send a resize event to signify that the display may have changed sizes. */ if (!d->first_run) { _al_android_resize_display(d, width, height); } } JNI_FUNC(void, AllegroSurface, nativeOnJoystickAxis, (JNIEnv *env, jobject obj, jint index, jint stick, jint axis, jfloat value)) { (void)env; (void)obj; _al_android_generate_joystick_axis_event(index+1, stick, axis, value); } JNI_FUNC(void, AllegroSurface, nativeOnJoystickButton, (JNIEnv *env, jobject obj, jint index, jint button, jboolean down)) { (void)env; (void)obj; _al_android_generate_joystick_button_event(index+1, button, down); } void _al_android_create_surface(JNIEnv *env, bool post) { if (post) { _jni_callVoidMethod(env, _al_android_activity_object(), "postCreateSurface"); } else { _jni_callVoidMethod(env, _al_android_activity_object(), "createSurface"); } } void _al_android_destroy_surface(JNIEnv *env, jobject surface, bool post) { (void)surface; if (post) { _jni_callVoidMethodV(env, _al_android_activity_object(), "postDestroySurface", "()V"); } else { _jni_callVoidMethodV(env, _al_android_activity_object(), "destroySurface", "()V"); } } void _al_android_make_current(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d) { _jni_callVoidMethodV(env, d->surface_object, "egl_makeCurrent", "()V"); } void _al_android_clear_current(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d) { _jni_callVoidMethodV(env, d->surface_object, "egl_clearCurrent", "()V"); } static bool _al_android_init_display(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *display) { ALLEGRO_SYSTEM_ANDROID *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY *d = (ALLEGRO_DISPLAY *)display; const ALLEGRO_EXTRA_DISPLAY_SETTINGS *extras = &main_thread_display_settings; int config_index; bool programmable_pipeline; int major_version, minor_version; bool is_required_major, is_required_minor; bool is_suggested_major, is_suggested_minor; int ret; ASSERT(system != NULL); ASSERT(display != NULL); ALLEGRO_DEBUG("calling egl_Init"); if (!_jni_callBooleanMethodV(env, display->surface_object, "egl_Init", "()Z")) { // XXX should probably destroy the AllegroSurface here ALLEGRO_ERROR("failed to initialize EGL"); display->failed = true; return false; } config_index = select_best_visual_and_update(env, display); if (config_index < 0) { // XXX should probably destroy the AllegroSurface here ALLEGRO_ERROR("Failed to choose config.\n"); display->failed = true; return false; } programmable_pipeline = (d->flags & ALLEGRO_PROGRAMMABLE_PIPELINE); major_version = extras->settings[ALLEGRO_OPENGL_MAJOR_VERSION]; minor_version = extras->settings[ALLEGRO_OPENGL_MINOR_VERSION]; is_required_major = (extras->required & ((int64_t)1 << ALLEGRO_OPENGL_MAJOR_VERSION)); is_required_minor = (extras->required & ((int64_t)1 << ALLEGRO_OPENGL_MINOR_VERSION)); is_suggested_major = (extras->suggested & ((int64_t)1 << ALLEGRO_OPENGL_MAJOR_VERSION)); is_suggested_minor = (extras->suggested & ((int64_t)1 << ALLEGRO_OPENGL_MINOR_VERSION)); if (!is_required_major && !is_suggested_major) // "don't care" major_version = 0; if (!is_required_minor && !is_suggested_minor) minor_version = 0; ALLEGRO_DEBUG("calling egl_createContext"); ret = _jni_callIntMethodV(env, display->surface_object, "egl_createContext", "(IZIIZZ)I", config_index, programmable_pipeline, major_version, minor_version, is_required_major, is_required_minor); if (!ret) { // XXX should probably destroy the AllegroSurface here ALLEGRO_ERROR("failed to create egl context!"); display->failed = true; return false; } ALLEGRO_DEBUG("calling egl_createSurface"); if (!_jni_callBooleanMethodV(env, display->surface_object, "egl_createSurface", "()Z")) { // XXX should probably destroy the AllegroSurface here ALLEGRO_ERROR("failed to create egl surface!"); display->failed = true; return false; } ALLEGRO_DEBUG("initialize ogl extensions"); _al_ogl_manage_extensions(d); _al_ogl_set_extensions(d->ogl_extras->extension_api); _al_ogl_setup_gl(d); return true; } /* implementation helpers */ static void _al_android_resize_display(ALLEGRO_DISPLAY_ANDROID *d, int width, int height) { ALLEGRO_DISPLAY *display = (ALLEGRO_DISPLAY *)d; bool emitted_event = true; ALLEGRO_DEBUG("display resize"); d->resize_acknowledge = false; d->resize_acknowledge2 = false; ALLEGRO_DEBUG("locking mutex"); al_lock_mutex(d->mutex); ALLEGRO_DEBUG("done locking mutex"); ALLEGRO_DEBUG("locking display event source: %p", d); _al_event_source_lock(&display->es); ALLEGRO_DEBUG("check generate event"); if(_al_event_source_needs_to_generate_event(&display->es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_RESIZE; event.display.timestamp = al_current_time(); event.display.x = 0; // FIXME: probably not correct event.display.y = 0; event.display.width = width; event.display.height = height; event.display.orientation = _al_android_get_display_orientation(); _al_event_source_emit_event(&display->es, &event); } else { emitted_event = false; } ALLEGRO_DEBUG("unlocking display event source"); _al_event_source_unlock(&display->es); if (emitted_event) { ALLEGRO_DEBUG("waiting for display resize acknowledge"); while (!d->resize_acknowledge) { ALLEGRO_DEBUG("calling al_wait_cond"); al_wait_cond(d->cond, d->mutex); } al_unlock_mutex(d->mutex); ALLEGRO_DEBUG("done waiting for display resize acknowledge"); } display->w = width; display->h = height; ALLEGRO_DEBUG("resize backbuffer"); _al_ogl_setup_gl(display); if (emitted_event) { d->resize_acknowledge2 = true; al_broadcast_cond(d->cond); } al_unlock_mutex(d->mutex); ALLEGRO_DEBUG("done"); } static void call_initRequiredAttribs(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d) { _jni_callVoidMethodV(env, d->surface_object, "egl_initRequiredAttribs", "()V"); } static void call_setRequiredAttrib(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d, int attr, int value) { _jni_callVoidMethodV(env, d->surface_object, "egl_setRequiredAttrib", "(II)V", attr, value); } static int call_chooseConfig(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d) { bool pp = (d->display.flags & ALLEGRO_PROGRAMMABLE_PIPELINE); return _jni_callIntMethodV(env, d->surface_object, "egl_chooseConfig", "(Z)I", pp); } static void call_getConfigAttribs(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d, int configIndex, ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds) { jintArray jArray; jint *ptr; int i; jArray = (*env)->NewIntArray(env, ALLEGRO_DISPLAY_OPTIONS_COUNT); if (jArray == NULL) { ALLEGRO_ERROR("NewIntArray failed\n"); return; } _jni_callVoidMethodV(env, d->surface_object, "egl_getConfigAttribs", "(I[I)V", configIndex, jArray); ptr = (*env)->GetIntArrayElements(env, jArray, 0); for (i = 0; i < ALLEGRO_DISPLAY_OPTIONS_COUNT; i++) { eds->settings[i] = ptr[i]; } (*env)->ReleaseIntArrayElements(env, jArray, ptr, 0); } static void set_required_attribs(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d, ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref) { #define MAYBE_SET(v) \ do { \ bool required = (ref->required & ((int64_t)1 << (v))); \ if (required) { \ call_setRequiredAttrib(env, d, (v), ref->settings[(v)]); \ } \ } while (0) MAYBE_SET(ALLEGRO_RED_SIZE); MAYBE_SET(ALLEGRO_GREEN_SIZE); MAYBE_SET(ALLEGRO_BLUE_SIZE); MAYBE_SET(ALLEGRO_ALPHA_SIZE); MAYBE_SET(ALLEGRO_COLOR_SIZE); MAYBE_SET(ALLEGRO_DEPTH_SIZE); MAYBE_SET(ALLEGRO_STENCIL_SIZE); MAYBE_SET(ALLEGRO_SAMPLE_BUFFERS); MAYBE_SET(ALLEGRO_SAMPLES); #undef MAYBE_SET } static int select_best_visual_and_update(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref = &main_thread_display_settings; ALLEGRO_EXTRA_DISPLAY_SETTINGS **eds = NULL; int num_configs; int chosen_index; int i; ALLEGRO_DEBUG("Setting required display settings.\n"); call_initRequiredAttribs(env, d); set_required_attribs(env, d, ref); ALLEGRO_DEBUG("Calling eglChooseConfig.\n"); num_configs = call_chooseConfig(env, d); if (num_configs < 1) { return -1; } eds = al_calloc(num_configs, sizeof(*eds)); for (i = 0; i < num_configs; i++) { eds[i] = al_calloc(1, sizeof(*eds[i])); call_getConfigAttribs(env, d, i, eds[i]); eds[i]->settings[ALLEGRO_RENDER_METHOD] = 1; eds[i]->settings[ALLEGRO_COMPATIBLE_DISPLAY] = 1; eds[i]->settings[ALLEGRO_SWAP_METHOD] = 2; eds[i]->settings[ALLEGRO_VSYNC] = 1; eds[i]->index = i; eds[i]->score = _al_score_display_settings(eds[i], ref); } ALLEGRO_DEBUG("Sorting configs.\n"); qsort(eds, num_configs, sizeof(*eds), _al_display_settings_sorter); chosen_index = eds[0]->index; ALLEGRO_INFO("Chose config %i\n", chosen_index); d->display.extra_settings = *eds[0]; /* Don't need this any more. */ for (i = 0; i < num_configs; i++) { al_free(eds[i]); } al_free(eds); return chosen_index; } /* driver implementation hooks */ static bool android_set_display_flag(ALLEGRO_DISPLAY *dpy, int flag, bool onoff) { (void)dpy; (void)flag; (void)onoff; if (flag == ALLEGRO_FRAMELESS) { _jni_callVoidMethodV(_al_android_get_jnienv(), _al_android_activity_object(), "setAllegroFrameless", "(Z)V", onoff); } return false; } static ALLEGRO_DISPLAY *android_create_display(int w, int h) { ALLEGRO_DEBUG("begin"); int flags = al_get_new_display_flags(); #ifndef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { ALLEGRO_WARN("Programmable pipeline support not built.\n"); return NULL; } #endif ALLEGRO_DISPLAY_ANDROID *d = al_malloc(sizeof *d); ALLEGRO_DISPLAY *display = (void *)d; ALLEGRO_OGL_EXTRAS *ogl = al_malloc(sizeof *ogl); memset(d, 0, sizeof *d); memset(ogl, 0, sizeof *ogl); display->ogl_extras = ogl; display->vt = _al_get_android_display_driver(); display->w = w; display->h = h; display->flags = flags; display->flags |= ALLEGRO_OPENGL; #ifdef ALLEGRO_CFG_OPENGLES2 display->flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; #endif #ifdef ALLEGRO_CFG_OPENGLES display->flags |= ALLEGRO_OPENGL_ES_PROFILE; #endif _al_event_source_init(&display->es); /* Java thread needs this but it's thread local. * For now we assume display is created and set up in main thread. */ main_thread_display_settings = *_al_get_new_display_settings(); d->mutex = al_create_mutex(); d->cond = al_create_cond(); d->recreate = true; d->first_run = true; d->failed = false; ALLEGRO_SYSTEM *system = (void *)al_get_system_driver(); ASSERT(system != NULL); ALLEGRO_DISPLAY_ANDROID **add; add = _al_vector_alloc_back(&system->displays); *add = d; al_lock_mutex(d->mutex); // post create surface request and wait _al_android_create_surface(_al_android_get_jnienv(), true); // wait for sizing to happen ALLEGRO_DEBUG("waiting for surface onChange"); while (!d->created && !d->failed) { al_wait_cond(d->cond, d->mutex); } al_unlock_mutex(d->mutex); ALLEGRO_DEBUG("done waiting for surface onChange"); if (d->failed) { ALLEGRO_DEBUG("Display creation failed"); _al_vector_find_and_delete(&system->displays, &d); al_free(ogl); al_free(d); return NULL; } ALLEGRO_DEBUG("display: %p %ix%i", display, display->w, display->h); _al_android_clear_current(_al_android_get_jnienv(), d); _al_android_make_current(_al_android_get_jnienv(), d); /* Don't need to repeat what this does */ android_set_display_option(display, ALLEGRO_SUPPORTED_ORIENTATIONS, al_get_new_display_option(ALLEGRO_SUPPORTED_ORIENTATIONS, NULL)); /* Fill in opengl version */ const int v = d->display.ogl_extras->ogl_info.version; d->display.extra_settings.settings[ALLEGRO_OPENGL_MAJOR_VERSION] = (v >> 24) & 0xFF; d->display.extra_settings.settings[ALLEGRO_OPENGL_MINOR_VERSION] = (v >> 16) & 0xFF; if (flags & ALLEGRO_FRAMELESS) { android_set_display_flag(display, ALLEGRO_FRAMELESS, true); } ALLEGRO_DEBUG("end"); return display; } static void android_destroy_display(ALLEGRO_DISPLAY *dpy) { ALLEGRO_DISPLAY_ANDROID *d = (ALLEGRO_DISPLAY_ANDROID*)dpy; ALLEGRO_DEBUG("clear current"); if (!d->created) { // if nativeOnDestroy was called (the app switched out) and // then the display is destroyed before the app switches back // in, there is no EGL context to destroy. goto already_deleted; } _al_android_clear_current(_al_android_get_jnienv(), d); al_lock_mutex(d->mutex); d->is_destroy_display = true; _al_android_destroy_surface(_al_android_get_jnienv(), d, true); /* I don't think we can use a condition for this, because there are two * possibilities of how a nativeOnDestroy/surfaceDestroyed callback can be * called. One is from here, manually, and one happens automatically and is * out of our hands. */ while (d->created) { al_rest(0.001); } _al_event_source_free(&dpy->es); already_deleted: // XXX: this causes a crash, no idea why as of yet //ALLEGRO_DEBUG("destroy backbuffer"); //_al_ogl_destroy_backbuffer(al_get_backbuffer(dpy)); ALLEGRO_DEBUG("destroy mutex"); al_destroy_mutex(d->mutex); ALLEGRO_DEBUG("destroy cond"); al_destroy_cond(d->cond); ALLEGRO_DEBUG("free ogl_extras"); al_free(dpy->ogl_extras); ALLEGRO_DEBUG("remove display from system list"); ALLEGRO_SYSTEM *s = al_get_system_driver(); _al_vector_find_and_delete(&s->displays, &d); _al_vector_free(&dpy->bitmaps); al_free(dpy->vertex_cache); ALLEGRO_DEBUG("free display"); al_free(d); ALLEGRO_DEBUG("done"); } static bool android_set_current_display(ALLEGRO_DISPLAY *dpy) { ALLEGRO_DEBUG("make current %p", dpy); if (al_get_current_display() != NULL){ _al_android_clear_current(_al_android_get_jnienv(), (ALLEGRO_DISPLAY_ANDROID *)al_get_current_display()); } if (dpy) { _al_android_make_current(_al_android_get_jnienv(), (ALLEGRO_DISPLAY_ANDROID *)dpy); } _al_ogl_update_render_state(dpy); return true; } static void android_unset_current_display(ALLEGRO_DISPLAY *dpy) { ALLEGRO_DEBUG("unset current %p", dpy); _al_android_clear_current(_al_android_get_jnienv(), (ALLEGRO_DISPLAY_ANDROID *)dpy); } static void android_flip_display(ALLEGRO_DISPLAY *dpy) { // Some Androids crash if you swap buffers with an fbo bound // so temporarily change target to the backbuffer. ALLEGRO_BITMAP *old_target = al_get_target_bitmap(); al_set_target_backbuffer(dpy); _jni_callVoidMethod(_al_android_get_jnienv(), ((ALLEGRO_DISPLAY_ANDROID *)dpy)->surface_object, "egl_SwapBuffers"); al_set_target_bitmap(old_target); /* Backup bitmaps created without ALLEGRO_NO_PRESERVE_TEXTURE that are * dirty, to system memory. */ al_backup_dirty_bitmaps(dpy); } static void android_update_display_region(ALLEGRO_DISPLAY *dpy, int x, int y, int width, int height) { (void)x; (void)y; (void)width; (void)height; android_flip_display(dpy); } static bool android_acknowledge_resize(ALLEGRO_DISPLAY *dpy) { ALLEGRO_DISPLAY_ANDROID *d = (ALLEGRO_DISPLAY_ANDROID *)dpy; ALLEGRO_DEBUG("clear current context"); _al_android_clear_current(_al_android_get_jnienv(), d); ALLEGRO_DEBUG("locking mutex"); al_lock_mutex(d->mutex); d->resize_acknowledge = true; al_broadcast_cond(d->cond); ALLEGRO_DEBUG("broadcasted condvar"); ALLEGRO_DEBUG("waiting for display resize acknowledge 2"); while (!d->resize_acknowledge2) { ALLEGRO_DEBUG("calling al_wait_cond"); al_wait_cond(d->cond, d->mutex); } al_unlock_mutex(d->mutex); ALLEGRO_DEBUG("done waiting for display resize acknowledge 2"); ALLEGRO_DEBUG("acquire context"); _al_android_make_current(_al_android_get_jnienv(), d); ALLEGRO_DEBUG("done"); return true; } static int android_get_orientation(ALLEGRO_DISPLAY *dpy) { (void)dpy; return _al_android_get_display_orientation(); } static bool android_is_compatible_bitmap(ALLEGRO_DISPLAY *dpy, ALLEGRO_BITMAP *bmp) { (void)dpy; (void)bmp; return true; } static bool android_resize_display(ALLEGRO_DISPLAY *dpy, int w, int h) { (void)dpy; (void)w; (void)h; return false; } static void android_set_icons(ALLEGRO_DISPLAY *dpy, int num_icons, ALLEGRO_BITMAP *bmps[]) { (void)dpy; (void)num_icons; (void)bmps; } static void android_set_window_title(ALLEGRO_DISPLAY *dpy, const char *title) { (void)dpy; (void)title; } static void android_set_window_position(ALLEGRO_DISPLAY *dpy, int x, int y) { (void)dpy; (void)x; (void)y; } static void android_get_window_position(ALLEGRO_DISPLAY *dpy, int *x, int *y) { (void)dpy; *x = *y = 0; } static bool android_wait_for_vsync(ALLEGRO_DISPLAY *dpy) { (void)dpy; return false; } static bool android_set_mouse_cursor(ALLEGRO_DISPLAY *dpy, ALLEGRO_MOUSE_CURSOR *cursor) { (void)dpy; (void)cursor; return false; } static bool android_set_system_mouse_cursor(ALLEGRO_DISPLAY *dpy, ALLEGRO_SYSTEM_MOUSE_CURSOR id) { (void)dpy; (void)id; return false; } static bool android_show_mouse_cursor(ALLEGRO_DISPLAY *dpy) { (void)dpy; return false; } static bool android_hide_mouse_cursor(ALLEGRO_DISPLAY *dpy) { (void)dpy; return false; } static void android_acknowledge_drawing_halt(ALLEGRO_DISPLAY *dpy) { int i; ALLEGRO_DEBUG("android_acknowledge_drawing_halt"); for (i = 0; i < (int)dpy->bitmaps._size; i++) { ALLEGRO_BITMAP **bptr = _al_vector_ref(&dpy->bitmaps, i); ALLEGRO_BITMAP *bmp = *bptr; int bitmap_flags = al_get_bitmap_flags(bmp); if (!bmp->parent && !(bitmap_flags & ALLEGRO_MEMORY_BITMAP)) { ALLEGRO_BITMAP_EXTRA_OPENGL *extra = bmp->extra; al_remove_opengl_fbo(bmp); glDeleteTextures(1, &extra->texture); extra->texture = 0; } } ALLEGRO_DISPLAY_ANDROID *d = (ALLEGRO_DISPLAY_ANDROID *)dpy; _al_android_clear_current(_al_android_get_jnienv(), d); /* signal the condition variable */ al_lock_mutex(d->mutex); d->halt_acknowledge = true; al_broadcast_cond(d->cond); al_unlock_mutex(d->mutex); ALLEGRO_DEBUG("acknowledged drawing halt"); } static void android_broadcast_resume(ALLEGRO_DISPLAY_ANDROID *d) { ALLEGRO_DEBUG("Broadcasting resume"); d->resumed = true; al_broadcast_cond(d->cond); ALLEGRO_DEBUG("done broadcasting resume"); } static void android_acknowledge_drawing_resume(ALLEGRO_DISPLAY *dpy) { unsigned i; ALLEGRO_DEBUG("begin"); ALLEGRO_DISPLAY_ANDROID *d = (ALLEGRO_DISPLAY_ANDROID *)dpy; _al_android_clear_current(_al_android_get_jnienv(), d); _al_android_make_current(_al_android_get_jnienv(), d); ALLEGRO_DEBUG("made current"); if (dpy->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { dpy->default_shader = _al_create_default_shader(dpy); } // Bitmaps can still have stale shaders attached. _al_glsl_unuse_shaders(); // Restore the transformations. dpy->vt->update_transformation(dpy, al_get_target_bitmap()); // Restore bitmaps // have to get this because new bitmaps could be created below for (i = 0; i < _al_vector_size(&dpy->bitmaps); i++) { ALLEGRO_BITMAP **bptr = _al_vector_ref(&dpy->bitmaps, i); ALLEGRO_BITMAP *bmp = *bptr; int bitmap_flags = al_get_bitmap_flags(bmp); if (!bmp->parent && !(bitmap_flags & ALLEGRO_MEMORY_BITMAP)) { int format = al_get_bitmap_format(bmp); format = _al_pixel_format_is_compressed(format) ? ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE : format; if (!(bitmap_flags & ALLEGRO_NO_PRESERVE_TEXTURE)) _al_ogl_upload_bitmap_memory(bmp, format, bmp->memory); else _al_ogl_upload_bitmap_memory(bmp, format, NULL); bmp->dirty = false; } } android_broadcast_resume(d); ALLEGRO_DEBUG("acknowledge_drawing_resume end"); } static void android_set_display_option(ALLEGRO_DISPLAY *d, int o, int v) { (void)d; if (o == ALLEGRO_SUPPORTED_ORIENTATIONS) { _jni_callVoidMethodV(_al_android_get_jnienv(), _al_android_activity_object(), "setAllegroOrientation", "(I)V", v); } } /* obtain a reference to the android driver */ ALLEGRO_DISPLAY_INTERFACE *_al_get_android_display_driver(void) { if (vt) return vt; vt = al_malloc(sizeof *vt); memset(vt, 0, sizeof *vt); vt->create_display = android_create_display; vt->destroy_display = android_destroy_display; vt->set_current_display = android_set_current_display; vt->unset_current_display = android_unset_current_display; vt->flip_display = android_flip_display; vt->update_display_region = android_update_display_region; vt->acknowledge_resize = android_acknowledge_resize; vt->create_bitmap = _al_ogl_create_bitmap; vt->get_backbuffer = _al_ogl_get_backbuffer; vt->set_target_bitmap = _al_ogl_set_target_bitmap; vt->get_orientation = android_get_orientation; vt->is_compatible_bitmap = android_is_compatible_bitmap; vt->resize_display = android_resize_display; vt->set_icons = android_set_icons; vt->set_window_title = android_set_window_title; vt->set_window_position = android_set_window_position; vt->get_window_position = android_get_window_position; vt->set_display_flag = android_set_display_flag; vt->wait_for_vsync = android_wait_for_vsync; vt->set_mouse_cursor = android_set_mouse_cursor; vt->set_system_mouse_cursor = android_set_system_mouse_cursor; vt->show_mouse_cursor = android_show_mouse_cursor; vt->hide_mouse_cursor = android_hide_mouse_cursor; vt->acknowledge_drawing_halt = android_acknowledge_drawing_halt; vt->acknowledge_drawing_resume = android_acknowledge_drawing_resume; vt->set_display_option = android_set_display_option; vt->update_render_state = _al_ogl_update_render_state; _al_ogl_add_drawing_functions(vt); _al_android_add_clipboard_functions(vt); return vt; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/android/android_image.c000066400000000000000000000225241473414355200206220ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Android image loading. * * By Thomas Fjellstrom. */ #include "allegro5/allegro.h" #include "allegro5/allegro_android.h" #include "allegro5/internal/aintern_android.h" #include "allegro5/internal/aintern_bitmap.h" #include ALLEGRO_DEBUG_CHANNEL("android") static void copy_bitmap_data(ALLEGRO_BITMAP *bitmap, const uint32_t *src, ALLEGRO_PIXEL_FORMAT src_format, int src_pitch, int bitmap_w, int bitmap_h) { ALLEGRO_LOCKED_REGION *lr; lr = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); ASSERT(lr); if (!lr) return; _al_convert_bitmap_data(src, src_format, src_pitch, lr->data, lr->format, lr->pitch, 0, 0, 0, 0, bitmap_w, bitmap_h); al_unlock_bitmap(bitmap); } static void copy_bitmap_data_multiply_alpha(ALLEGRO_BITMAP *bitmap, const uint32_t *src, int bitmap_w, int bitmap_h) { ALLEGRO_LOCKED_REGION *lr; int x, y; lr = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ABGR_8888, ALLEGRO_LOCK_WRITEONLY); ASSERT(lr); if (!lr) return; for (y = 0; y < bitmap_h; y++) { uint32_t *dst = (uint32_t *)(((uint8_t *)lr->data) + y * lr->pitch); for (x = 0; x < bitmap_w; x++) { uint32_t c = *src++; uint32_t a = (c >> 24) & 0xff; c = (a << 24) | (((c >> 16) & 0xff) * a / 255) | ((((c >> 8) & 0xff) * a / 255) << 8) | (((c & 0xff) * a / 255) << 16); *dst++ = c; } } al_unlock_bitmap(bitmap); } static void copy_bitmap_data_demultiply_alpha(ALLEGRO_BITMAP *bitmap, const uint32_t *src, int src_format, int src_pitch, int bitmap_w, int bitmap_h) { ALLEGRO_LOCKED_REGION *lr; int x, y; lr = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ABGR_8888, ALLEGRO_LOCK_WRITEONLY); ASSERT(lr); if (!lr) return; _al_convert_bitmap_data(src, src_format, src_pitch, lr->data, lr->format, lr->pitch, 0, 0, 0, 0, bitmap_w, bitmap_h); for (y = 0; y < bitmap_h; y++) { uint32_t *dst = (uint32_t *)(((uint8_t *)lr->data) + y * lr->pitch); for (x = 0; x < bitmap_w; x++) { uint32_t c = *dst; uint8_t a = (c >> 24); uint8_t b = (c >> 16); uint8_t g = (c >> 8); uint8_t r = (c >> 0); // NOTE: avoid divide by zero by adding a fraction. float alpha_mul = 255.0f / (a+0.001f); r *= alpha_mul; g *= alpha_mul; b *= alpha_mul; *dst = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)g << 8) | ((uint32_t)r); dst++; } } al_unlock_bitmap(bitmap); } /* Note: This is not used when loading an image from the .apk. * * The ImageLoader class uses Java to load a bitmap. To support * Allegro's filesystem functions, the bitmap is read from an * AllegroInputStream which in turn calls back into C to use Allegro's * file functions. */ ALLEGRO_BITMAP *_al_android_load_image_f(ALLEGRO_FILE *fh, int flags) { JNIEnv *jnienv; jclass image_loader_class; jobject input_stream_class; jmethodID input_stream_ctor; jobject input_stream; int buffer_len; uint8_t *buffer; jobject byte_buffer; jobject jbitmap; ALLEGRO_BITMAP *bitmap; int bitmap_w; int bitmap_h; int pitch; if (flags & ALLEGRO_KEEP_INDEX) { ALLEGRO_ERROR("ALLEGRO_KEEP_INDEX not yet supported\n"); return NULL; } jnienv = (JNIEnv *)_al_android_get_jnienv(); // Note: This is always ImageLoader image_loader_class = _al_android_image_loader_class(); // Note: This is always AllegroInputStream input_stream_class = _al_android_input_stream_class(); input_stream_ctor = _jni_call(jnienv, jclass, GetMethodID, input_stream_class, "", "(J)V"); input_stream = _jni_call(jnienv, jobject, NewObject, input_stream_class, input_stream_ctor, (jlong)(intptr_t)fh); if (!input_stream) { ALLEGRO_ERROR("failed to create new AllegroInputStream object"); return NULL; } jbitmap = _jni_callStaticObjectMethodV(jnienv, image_loader_class, "decodeBitmapStream", "(Ljava/io/InputStream;)Landroid/graphics/Bitmap;", input_stream); _jni_callv(jnienv, DeleteLocalRef, input_stream); if (!jbitmap) return NULL; bitmap_w = _jni_callIntMethod(jnienv, jbitmap, "getWidth"); bitmap_h = _jni_callIntMethod(jnienv, jbitmap, "getHeight"); pitch = _jni_callIntMethod(jnienv, jbitmap, "getRowBytes"); buffer_len = pitch * bitmap_h; buffer = al_malloc(buffer_len); if (!buffer) { _jni_callv(jnienv, DeleteLocalRef, jbitmap); return NULL; } int src_format = _jni_callStaticIntMethodV(jnienv, image_loader_class, "getBitmapFormat", "(Landroid/graphics/Bitmap;)I", jbitmap); // FIXME: at some point add support for the ndk AndroidBitmap api need to // check for header at build time, and android version at runtime if thats // even possible, might need to try and dynamically load the lib? I dunno. // That would get rid of this buffer allocation and copy. byte_buffer = _jni_call(jnienv, jobject, NewDirectByteBuffer, buffer, buffer_len); _jni_callVoidMethodV(jnienv, jbitmap, "copyPixelsToBuffer", "(Ljava/nio/Buffer;)V", byte_buffer); // Tell java we don't need the byte_buffer object. _jni_callv(jnienv, DeleteLocalRef, byte_buffer); // Tell java we're done with the bitmap as well. _jni_callv(jnienv, DeleteLocalRef, jbitmap); bitmap = al_create_bitmap(bitmap_w, bitmap_h); if (!bitmap) { al_free(buffer); return NULL; } /* buffer already has alpha multiplied in. */ if (flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA) { copy_bitmap_data_demultiply_alpha(bitmap, (const uint32_t *)buffer, src_format, pitch, bitmap_w, bitmap_h); } else { copy_bitmap_data(bitmap, (const uint32_t *)buffer, src_format, pitch, bitmap_w, bitmap_h); } al_free(buffer); return bitmap; } static ALLEGRO_BITMAP *android_load_image_asset(const char *filename, int flags) { JNIEnv *jnienv; jclass image_loader_class; jobject activity; jobject str; jobject jbitmap; int bitmap_w; int bitmap_h; ALLEGRO_BITMAP *bitmap; jintArray ia; jint *arr; if (flags & ALLEGRO_KEEP_INDEX) { ALLEGRO_ERROR("ALLEGRO_KEEP_INDEX not yet supported\n"); return NULL; } jnienv = _al_android_get_jnienv(); image_loader_class = _al_android_image_loader_class(); activity = _al_android_activity_object(); str = (*jnienv)->NewStringUTF(jnienv, filename); jbitmap = _jni_callStaticObjectMethodV(jnienv, image_loader_class, "decodeBitmapAsset", "(Landroid/app/Activity;Ljava/lang/String;)Landroid/graphics/Bitmap;", activity, str); /* For future Java noobs like me: If the calling thread is a Java * thread, it will clean up these references when the native method * returns. But here that's not the case (though technically we were * spawned ultimately by a Java thread, we never return.) In any case, * it never does any harm to release the reference anyway. */ (*jnienv)->DeleteLocalRef(jnienv, str); if (!jbitmap) return NULL; bitmap_w = _jni_callIntMethod(jnienv, jbitmap, "getWidth"); bitmap_h = _jni_callIntMethod(jnienv, jbitmap, "getHeight"); ALLEGRO_DEBUG("bitmap dimensions: %d, %d", bitmap_w, bitmap_h); bitmap = al_create_bitmap(bitmap_w, bitmap_h); if (!bitmap) { _jni_callv(jnienv, DeleteLocalRef, jbitmap); return NULL; } ia = _jni_callStaticObjectMethodV(jnienv, image_loader_class, "getPixels", "(Landroid/graphics/Bitmap;)[I", jbitmap); arr = (*jnienv)->GetIntArrayElements(jnienv, ia, 0); /* arr is an array of packed colours, NON-premultiplied alpha. */ if (flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA) { int src_format = ALLEGRO_PIXEL_FORMAT_ARGB_8888; int src_pitch = bitmap_w * sizeof(uint32_t); copy_bitmap_data(bitmap, (const uint32_t *)arr, src_format, src_pitch, bitmap_w, bitmap_h); } else { copy_bitmap_data_multiply_alpha(bitmap, (const uint32_t *)arr, bitmap_w, bitmap_h); } (*jnienv)->ReleaseIntArrayElements(jnienv, ia, arr, JNI_ABORT); _jni_callv(jnienv, DeleteLocalRef, ia); _jni_callv(jnienv, DeleteLocalRef, jbitmap); return bitmap; } ALLEGRO_BITMAP *_al_android_load_image(const char *filename, int flags) { ALLEGRO_FILE *fp; ALLEGRO_BITMAP *bmp; /* Bypass the ALLEGRO_FILE interface when we know the underlying stream * implementation, to avoid a lot of shunting between C and Java. * We could probably do this for normal filesystem as well. */ if (al_get_new_file_interface() == _al_get_apk_file_vtable()) { return android_load_image_asset(filename, flags); } fp = al_fopen(filename, "rb"); if (fp) { bmp = _al_android_load_image_f(fp, flags); al_fclose(fp); return bmp; } return NULL; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/android/android_input_stream.c000066400000000000000000000037151473414355200222530ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Android input stream. * * By Thomas Fjellstrom. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_android.h" #include ALLEGRO_DEBUG_CHANNEL("android") /* XXX ALLEGRO_FILE pointers currently passed as ints */ ALLEGRO_STATIC_ASSERT(android, sizeof(jlong) >= sizeof(ALLEGRO_FILE *)); JNI_FUNC(int, AllegroInputStream, nativeRead, (JNIEnv *env, jobject obj, jlong handle, jbyteArray array, int offset, int length)) { ALLEGRO_FILE *fp = (ALLEGRO_FILE *)(intptr_t)handle; int ret = -1; jbyte *array_ptr = NULL; ASSERT(fp != NULL); (void)obj; ALLEGRO_DEBUG("nativeRead begin: handle:%lli fp:%p offset:%i length:%i", handle, fp, offset, length); int array_len = _jni_call(env, int, GetArrayLength, array); ALLEGRO_DEBUG("array length: %i", array_len); array_ptr = _jni_call(env, jbyte *, GetByteArrayElements, array, NULL); ASSERT(array_ptr != NULL); ALLEGRO_DEBUG("al_fread: p:%p, o:%i, l:%i", array_ptr, offset, length); ret = al_fread(fp, array_ptr + offset, length); if (ret == 0 && al_feof(fp)) { /* InputStream.read() semantics. */ ret = -1; } _jni_callv(env, ReleaseByteArrayElements, array, array_ptr, 0); ALLEGRO_DEBUG("nativeRead end"); return ret; } JNI_FUNC(void, AllegroInputStream, nativeClose, (JNIEnv *env, jobject obj, jlong handle)) { ALLEGRO_FILE *fp = (ALLEGRO_FILE *)(intptr_t)handle; (void)env; (void)obj; al_fclose(fp); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/android/android_joystick.c000066400000000000000000000260001473414355200213700ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_android.h" ALLEGRO_DEBUG_CHANNEL("android") /* the number of gamepad & dpad buttons defined in the Android documentation https://developer.android.com/reference/android/view/KeyEvent */ #define MAX_BUTTONS 36 ALLEGRO_STATIC_ASSERT(android_joystick, _AL_MAX_JOYSTICK_BUTTONS >= MAX_BUTTONS); /* sticks: left & right thumbsticks; left & right triggers */ #define MAX_STICKS 4 ALLEGRO_STATIC_ASSERT(android_joystick, _AL_MAX_JOYSTICK_STICKS >= MAX_STICKS); typedef struct ALLEGRO_JOYSTICK_ANDROID { ALLEGRO_JOYSTICK parent; ALLEGRO_JOYSTICK_STATE joystate; char name[64]; } ALLEGRO_JOYSTICK_ANDROID; static const char *button_name[MAX_BUTTONS] = { /* buttons are named according to the Android documentation https://developer.android.com/reference/android/view/KeyEvent */ /* standard gamepad & d-pad buttons */ "A", "B", "X", "Y", "L1", "R1", "DPAD LEFT", "DPAD RIGHT", "DPAD UP", "DPAD DOWN", "START", /* start / menu */ "SELECT", /* select / back */ "MODE", /* mode / guide */ "THUMBL", "THUMBR", "L2", "R2", "C", "Z", "DPAD CENTER", /* generic gamepad buttons */ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16" }; static _AL_VECTOR joysticks = _AL_VECTOR_INITIALIZER(ALLEGRO_JOYSTICK_ANDROID *); static bool initialized; static char *android_get_joystick_name(JNIEnv *env, jobject activity, int index, char *buffer, size_t buffer_size) { jstring str_obj = (jstring)_jni_callObjectMethodV(env, activity, "getJoystickName", "(I)Ljava/lang/String;", (jint)index); ALLEGRO_USTR *s = _jni_getString(env, str_obj); _al_sane_strncpy(buffer, al_cstr(s), buffer_size); al_ustr_free(s); _jni_callv(env, DeleteLocalRef, str_obj); return buffer; } static void android_init_joysticks(int num) { int i, j; JNIEnv *env = _al_android_get_jnienv(); jobject activity = _al_android_activity_object(); for (i = 0; i < num; i++) { ALLEGRO_JOYSTICK_ANDROID *stick = al_calloc(1, sizeof(ALLEGRO_JOYSTICK_ANDROID)); ALLEGRO_JOYSTICK_ANDROID **ptr; ALLEGRO_JOYSTICK *joy; joy = (void *)stick; /* Fill in the joystick information fields. */ android_get_joystick_name(env, activity, i, stick->name, sizeof(stick->name)); joy->info.num_sticks = MAX_STICKS; joy->info.num_buttons = MAX_BUTTONS; joy->info.stick[0].name = "Left Thumbstick"; joy->info.stick[0].num_axes = 2; joy->info.stick[0].axis[0].name = "X"; joy->info.stick[0].axis[1].name = "Y"; joy->info.stick[0].flags = ALLEGRO_JOYFLAG_ANALOGUE; joy->info.stick[1].name = "Right Thumbstick"; joy->info.stick[1].num_axes = 2; joy->info.stick[1].axis[0].name = "X"; joy->info.stick[1].axis[1].name = "Y"; joy->info.stick[1].flags = ALLEGRO_JOYFLAG_ANALOGUE; joy->info.stick[2].name = "Left Trigger"; joy->info.stick[2].num_axes = 1; joy->info.stick[2].axis[0].name = "Ramp"; joy->info.stick[2].flags = ALLEGRO_JOYFLAG_ANALOGUE; joy->info.stick[3].name = "Right Trigger"; joy->info.stick[3].num_axes = 1; joy->info.stick[3].axis[0].name = "Ramp"; joy->info.stick[3].flags = ALLEGRO_JOYFLAG_ANALOGUE; for (j = 0; j < joy->info.num_buttons; j++) { joy->info.button[j].name = button_name[j]; } ptr = _al_vector_alloc_back(&joysticks); *ptr = stick; } } static bool andjoy_init_joystick(void) { ALLEGRO_JOYSTICK_ANDROID *accel = al_calloc(1, sizeof(ALLEGRO_JOYSTICK_ANDROID)); ALLEGRO_JOYSTICK_ANDROID **ptr; ALLEGRO_JOYSTICK *joy; int num; joy = (void *)accel; /* Fill in the joystick information fields. */ _al_sane_strncpy(accel->name, "Accelerometer", sizeof(accel->name)); joy->info.num_sticks = 1; joy->info.num_buttons = 0; joy->info.stick[0].name = "Accelerometer"; joy->info.stick[0].num_axes = 3; joy->info.stick[0].axis[0].name = "X"; joy->info.stick[0].axis[1].name = "Y"; joy->info.stick[0].axis[2].name = "Z"; joy->info.stick[0].flags = ALLEGRO_JOYFLAG_ANALOGUE; ptr = _al_vector_alloc_back(&joysticks); *ptr = accel; num = _jni_callIntMethodV(_al_android_get_jnienv(), _al_android_activity_object(), "getNumJoysticks", "()I"); android_init_joysticks(num); initialized = true; _jni_callVoidMethod(_al_android_get_jnienv(), _al_android_activity_object(), "setJoystickActive"); return true; } static void andjoy_exit_joystick(void) { initialized = false; } static bool andjoy_reconfigure_joysticks(void) { int i; int sz; int num; sz = _al_vector_size(&joysticks); for (i = 1; i < sz; i++) { al_free(*((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, 1))); _al_vector_delete_at(&joysticks, 1); } _jni_callVoidMethod(_al_android_get_jnienv(), _al_android_activity_object(), "reconfigureJoysticks"); num = _jni_callIntMethodV(_al_android_get_jnienv(), _al_android_activity_object(), "getNumJoysticks", "()I"); android_init_joysticks(num); return true; } static int andjoy_num_joysticks(void) { return _al_vector_size(&joysticks); } static ALLEGRO_JOYSTICK *andjoy_get_joystick(int num) { ALLEGRO_JOYSTICK_ANDROID *andjoy; ALLEGRO_JOYSTICK *joy; if (num >= andjoy_num_joysticks()) return NULL; andjoy = *((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, num)); joy = &andjoy->parent; return joy; } static void andjoy_release_joystick(ALLEGRO_JOYSTICK *joy) { int i; int sz; (void)joy; sz = _al_vector_size(&joysticks); for (i = 0; i < sz; i++) { al_free(*((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, 0))); _al_vector_delete_at(&joysticks, 0); } _jni_callVoidMethod(_al_android_get_jnienv(), _al_android_activity_object(), "setJoystickInactive"); ALLEGRO_DEBUG("Joystick released.\n"); initialized = false; } static void andjoy_get_joystick_state(ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state) { ALLEGRO_JOYSTICK_ANDROID *andjoy = (void *)joy; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); int i; bool found = false; for (i = 0; i < (int)_al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_ANDROID **ptr = _al_vector_ref(&joysticks, i); ALLEGRO_JOYSTICK_ANDROID *thisjoy = *ptr; if (andjoy == thisjoy) { found = true; break; } } if (!found) { memset(ret_state, 0, sizeof(*ret_state)); return; } _al_event_source_lock(es); *ret_state = andjoy->joystate; _al_event_source_unlock(es); } void _al_android_generate_accelerometer_event(float x, float y, float z) { if (!initialized) return; /* Android reports accelerometer data in the approximate range * -9.81 -> 9.81, but can be higher or lower. Allegro joysticks * use -1 -> 1. Also, the axis' are all reversed on Android, * hence the negative division. */ x /= -9.81f; if (x < -1) x = -1; if (x > 1) x = 1; y /= -9.81f; if (y < -1) y = -1; if (y > 1) y = 1; z /= -9.81f; if (z < -1) z = -1; if (z > 1) z = 1; ALLEGRO_JOYSTICK_ANDROID *accel = *((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, 0)); ALLEGRO_JOYSTICK *joy = &accel->parent; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); ALLEGRO_EVENT event; _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { float pos[] = {x, y, z}; int i; for (i = 0; i < 3; i++) { event.joystick.id = joy; event.joystick.type = ALLEGRO_EVENT_JOYSTICK_AXIS; event.joystick.timestamp = al_get_time(); event.joystick.stick = 0; event.joystick.axis = i; event.joystick.pos = pos[i]; event.joystick.button = 0; accel->joystate.stick[0].axis[i] = pos[i]; _al_event_source_emit_event(es, &event); } } _al_event_source_unlock(es); } void _al_android_generate_joystick_axis_event(int index, int stick, int axis, float value) { if (!initialized || index >= andjoy_num_joysticks()) return; ALLEGRO_JOYSTICK_ANDROID *joystick = *((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, index)); ALLEGRO_JOYSTICK *joy = &joystick->parent; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); ALLEGRO_EVENT event; _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { event.joystick.id = joy; event.joystick.type = ALLEGRO_EVENT_JOYSTICK_AXIS; event.joystick.timestamp = al_get_time(); event.joystick.stick = stick; event.joystick.axis = axis; event.joystick.pos = value; event.joystick.button = 0; joystick->joystate.stick[stick].axis[axis] = value; _al_event_source_emit_event(es, &event); } _al_event_source_unlock(es); } void _al_android_generate_joystick_button_event(int index, int button, bool down) { int type; if (!initialized || index >= andjoy_num_joysticks()) return; ALLEGRO_JOYSTICK_ANDROID *joystick = *((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, index)); ALLEGRO_JOYSTICK *joy = &joystick->parent; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); ALLEGRO_EVENT event; _al_event_source_lock(es); if (down) type = ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN; else type = ALLEGRO_EVENT_JOYSTICK_BUTTON_UP; if (_al_event_source_needs_to_generate_event(es)) { event.joystick.id = joy; event.joystick.type = type; event.joystick.timestamp = al_get_time(); event.joystick.stick = 0; event.joystick.axis = 0; event.joystick.pos = 0; event.joystick.button = button; joystick->joystate.button[button] = type == ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN ? 1 : 0; _al_event_source_emit_event(es, &event); } _al_event_source_unlock(es); } static char const *andjoy_get_name(ALLEGRO_JOYSTICK *joy) { int i; (void)joy; for (i = 0; i < (int)_al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_ANDROID *andjoy = *((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, i)); if ((ALLEGRO_JOYSTICK *)andjoy == joy) return andjoy->name; } return ""; } static bool andjoy_get_active(ALLEGRO_JOYSTICK *joy) { (void)joy; return true; } ALLEGRO_JOYSTICK_DRIVER _al_android_joystick_driver = { AL_ID('A', 'N', 'D', 'R'), "", "", "android joystick", andjoy_init_joystick, andjoy_exit_joystick, andjoy_reconfigure_joysticks, andjoy_num_joysticks, andjoy_get_joystick, andjoy_release_joystick, andjoy_get_joystick_state, andjoy_get_name, andjoy_get_active }; allegro5-5.2.10.1/src/android/android_keyboard.c000066400000000000000000000105361473414355200213400ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/internal/aintern_android.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_keyboard.h" #include ALLEGRO_DEBUG_CHANNEL("keyboard") static ALLEGRO_KEYBOARD the_keyboard; static ALLEGRO_KEYBOARD_STATE the_state; static bool android_init_keyboard(void) { memset(&the_keyboard, 0, sizeof the_keyboard); _al_event_source_init(&the_keyboard.es); return true; } static void android_exit_keyboard(void) { _al_event_source_free(&the_keyboard.es); } static ALLEGRO_KEYBOARD *android_get_keyboard(void) { return &the_keyboard; } static bool android_set_keyboard_leds(int leds) { (void)leds; return false; } static char const *android_keycode_to_name(int keycode) { static bool created = false; static char names[ALLEGRO_KEY_MAX][5]; ASSERT(keycode >= 0 && keycode < ALLEGRO_KEY_MAX); if (!created) { int i; created = true; for (i = 0; i < ALLEGRO_KEY_MAX; i++) { snprintf(names[i], 5, "%d", i); } } return names[keycode]; } static void android_get_keyboard_state(ALLEGRO_KEYBOARD_STATE *ret_state) { _al_event_source_lock(&the_keyboard.es); { *ret_state = the_state; } _al_event_source_unlock(&the_keyboard.es); } static void android_clear_keyboard_state(void) { _al_event_source_lock(&the_keyboard.es); { memset(&the_state, 0, sizeof(the_state)); } _al_event_source_unlock(&the_keyboard.es); } static ALLEGRO_KEYBOARD_DRIVER android_keyboard_driver = { AL_ID('A','N','D','R'), "", "", "android keyboard", android_init_keyboard, android_exit_keyboard, android_get_keyboard, android_set_keyboard_leds, android_keycode_to_name, android_get_keyboard_state, android_clear_keyboard_state }; ALLEGRO_KEYBOARD_DRIVER *_al_get_android_keyboard_driver(void) { return &android_keyboard_driver; } static void android_keyboard_handle_event(ALLEGRO_DISPLAY *display, int scancode, int unichar, ALLEGRO_EVENT_TYPE event_type) { ALLEGRO_EVENT event; ASSERT(display != NULL); ASSERT(scancode > 0); if (event_type == ALLEGRO_EVENT_KEY_UP) { _AL_KEYBOARD_STATE_CLEAR_KEY_DOWN(the_state, scancode); } else { _AL_KEYBOARD_STATE_SET_KEY_DOWN(the_state, scancode); } _al_event_source_lock(&the_keyboard.es); if (_al_event_source_needs_to_generate_event(&the_keyboard.es)) { event.keyboard.type = event_type; event.keyboard.timestamp = al_get_time(); event.keyboard.display = display; event.keyboard.keycode = scancode; event.keyboard.unichar = unichar; event.keyboard.modifiers = 0; event.keyboard.repeat = event_type == ALLEGRO_EVENT_KEY_CHAR; _al_event_source_emit_event(&the_keyboard.es, &event); } _al_event_source_unlock(&the_keyboard.es); } JNI_FUNC(void, KeyListener, nativeOnKeyDown, (JNIEnv *env, jobject obj, jint scancode, jint unichar)) { (void)env; (void)obj; ALLEGRO_SYSTEM *system = al_get_system_driver(); ASSERT(system != NULL); ALLEGRO_DISPLAY **dptr = _al_vector_ref(&system->displays, 0); ALLEGRO_DISPLAY *display = *dptr; ASSERT(display != NULL); android_keyboard_handle_event(display, scancode, unichar, ALLEGRO_EVENT_KEY_DOWN); } JNI_FUNC(void, KeyListener, nativeOnKeyUp, (JNIEnv *env, jobject obj, jint scancode)) { (void)env; (void)obj; ALLEGRO_SYSTEM *system = al_get_system_driver(); ASSERT(system != NULL); ALLEGRO_DISPLAY **dptr = _al_vector_ref(&system->displays, 0); ALLEGRO_DISPLAY *display = *dptr; ASSERT(display != NULL); android_keyboard_handle_event(display, scancode, 0, ALLEGRO_EVENT_KEY_UP); } JNI_FUNC(void, KeyListener, nativeOnKeyChar, (JNIEnv *env, jobject obj, jint scancode, jint unichar)) { (void)env; (void)obj; ALLEGRO_SYSTEM *system = al_get_system_driver(); ASSERT(system != NULL); ALLEGRO_DISPLAY **dptr = _al_vector_ref(&system->displays, 0); ALLEGRO_DISPLAY *display = *dptr; ASSERT(display != NULL); android_keyboard_handle_event(display, scancode, unichar, ALLEGRO_EVENT_KEY_CHAR); } JNI_FUNC(void, KeyListener, nativeOnJoystickButton, (JNIEnv *env, jobject obj, jint index, jint button, jboolean down)) { (void)env; (void)obj; _al_android_generate_joystick_button_event(index+1, button, down); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/android/android_mouse.c000066400000000000000000000057721473414355200206760ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/internal/aintern_mouse.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_android.h" typedef struct ALLEGRO_MOUSE_ANDROID { ALLEGRO_MOUSE parent; ALLEGRO_MOUSE_STATE state; } ALLEGRO_MOUSE_ANDROID; static ALLEGRO_MOUSE_ANDROID the_mouse; static bool amouse_installed; /* * Helper to generate a mouse event. */ void _al_android_generate_mouse_event(unsigned int type, int x, int y, unsigned int button, ALLEGRO_DISPLAY *d) { ALLEGRO_EVENT event; _al_event_source_lock(&the_mouse.parent.es); //_al_android_translate_from_screen(d, &x, &y); the_mouse.state.x = x; the_mouse.state.y = y; if (type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { the_mouse.state.buttons |= (1 << button); } else if (type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { the_mouse.state.buttons &= ~(1 << button); } the_mouse.state.pressure = the_mouse.state.buttons ? 1.0 : 0.0; // TODO if (_al_event_source_needs_to_generate_event(&the_mouse.parent.es)) { event.mouse.type = type; event.mouse.timestamp = al_get_time(); event.mouse.display = d; event.mouse.x = x; event.mouse.y = y; event.mouse.z = 0; event.mouse.w = 0; event.mouse.dx = 0; // TODO event.mouse.dy = 0; // TODO event.mouse.dz = 0; // TODO event.mouse.dw = 0; // TODO event.mouse.button = button; event.mouse.pressure = the_mouse.state.pressure; _al_event_source_emit_event(&the_mouse.parent.es, &event); } _al_event_source_unlock(&the_mouse.parent.es); } static void amouse_exit(void); static bool amouse_init(void) { if (amouse_installed) amouse_exit(); memset(&the_mouse, 0, sizeof the_mouse); _al_event_source_init(&the_mouse.parent.es); amouse_installed = true; return true; } static void amouse_exit(void) { if (!amouse_installed) return; amouse_installed = false; _al_event_source_free(&the_mouse.parent.es); } static ALLEGRO_MOUSE *amouse_get_mouse(void) { ASSERT(amouse_installed); return (ALLEGRO_MOUSE *)&the_mouse; } /* We report multi-touch as different buttons. */ static unsigned int amouse_get_mouse_num_buttons(void) { return 5; } static unsigned int amouse_get_mouse_num_axes(void) { return 2; } /* Hard to accomplish on a touch screen. */ static bool amouse_set_mouse_xy(ALLEGRO_DISPLAY *display, int x, int y) { (void)display; (void)x; (void)y; return false; } static bool amouse_set_mouse_axis(int which, int z) { (void)which; (void)z; return false; } static ALLEGRO_MOUSE_DRIVER android_mouse_driver = { AL_ID('A', 'N', 'D', 'R'), "", "", "android mouse", amouse_init, amouse_exit, amouse_get_mouse, amouse_get_mouse_num_buttons, amouse_get_mouse_num_axes, amouse_set_mouse_xy, amouse_set_mouse_axis, _al_android_mouse_get_state }; ALLEGRO_MOUSE_DRIVER *_al_get_android_mouse_driver(void) { return &android_mouse_driver; } allegro5-5.2.10.1/src/android/android_sensors.c000066400000000000000000000016501473414355200212310ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Android Java/JNI system driver * * By Thomas Fjellstrom. */ #include "allegro5/allegro.h" #include "allegro5/allegro_android.h" #include "allegro5/internal/aintern_android.h" #include JNI_FUNC(void, Sensors, nativeOnAccel, (JNIEnv *env, jobject obj, jint id, jfloat x, jfloat y, jfloat z)) { (void)env; (void)obj; (void)id; _al_android_generate_accelerometer_event(x, y, z); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/android/android_system.c000066400000000000000000000477171473414355200210770ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Android Java/JNI system driver * * By Thomas Fjellstrom. * */ #include "allegro5/allegro.h" #include "allegro5/allegro_android.h" #include "allegro5/platform/aintunix.h" #include "allegro5/internal/aintern_android.h" #include "allegro5/internal/aintern_tls.h" #include "allegro5/platform/aintandroid.h" #include "allegro5/platform/alandroid.h" #include "allegro5/threads.h" #include #include #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern_opengl.h" ALLEGRO_DEBUG_CHANNEL("android") struct system_data_t { JNIEnv *env; jobject activity_object; jclass input_stream_class; jclass illegal_argument_exception_class; jclass apk_stream_class; jclass image_loader_class; jclass clipboard_class; jclass apk_fs_class; ALLEGRO_SYSTEM_ANDROID *system; ALLEGRO_MUTEX *mutex; ALLEGRO_COND *cond; ALLEGRO_THREAD *trampoline; bool trampoline_running; ALLEGRO_USTR *user_lib_name; ALLEGRO_USTR *resources_dir; ALLEGRO_USTR *data_dir; ALLEGRO_USTR *temp_dir; ALLEGRO_USTR *apk_path; ALLEGRO_USTR *model; ALLEGRO_USTR *manufacturer; void *user_lib; int (*user_main)(int argc, char **argv); int orientation; bool paused; }; static struct system_data_t system_data; static JavaVM* javavm; static JNIEnv *main_env; static const char *_real_al_android_get_os_version(JNIEnv *env); bool _al_android_is_paused(void) { return system_data.paused; } int _al_android_get_display_orientation(void) { return system_data.orientation; } jclass _al_android_input_stream_class(void) { return system_data.input_stream_class; } jclass _al_android_apk_stream_class(void) { return system_data.apk_stream_class; } jclass _al_android_image_loader_class(void) { return system_data.image_loader_class; } jclass _al_android_clipboard_class(void) { return system_data.clipboard_class; } jobject _al_android_activity_object() { return system_data.activity_object; } jclass _al_android_apk_fs_class(void) { return system_data.apk_fs_class; } static void finish_activity(JNIEnv *env); static bool already_cleaned_up = false; /* NOTE: don't put any ALLEGRO_DEBUG in here! */ static void android_cleanup(bool uninstall_system) { if (already_cleaned_up) { return; } already_cleaned_up = true; if (uninstall_system) { /* I don't think android calls our atexit() stuff since we're in a shared lib so make sure al_uninstall_system is called */ al_uninstall_system(); } finish_activity(_al_android_get_jnienv()); (*javavm)->DetachCurrentThread(javavm); } static void *android_app_trampoline(ALLEGRO_THREAD *thr, void *arg) { const int argc = 1; const char *argv[2] = {system_data.user_lib, NULL}; int ret; (void)thr; (void)arg; ALLEGRO_DEBUG("signaling running"); al_lock_mutex(system_data.mutex); system_data.trampoline_running = true; al_broadcast_cond(system_data.cond); al_unlock_mutex(system_data.mutex); ALLEGRO_DEBUG("entering main function %p", system_data.user_main); ret = (system_data.user_main)(argc, (char **)argv); /* Can we do anything with this exit code? */ ALLEGRO_DEBUG("returned from main function, exit code = %d", ret); /* NOTE: don't put any ALLEGRO_DEBUG in here after running main! */ android_cleanup(true); return NULL; } /* called by JNI/Java */ jint JNI_OnLoad(JavaVM* vm, void* reserved) { (void)reserved; javavm = vm; return JNI_VERSION_1_4; } JNI_FUNC(bool, AllegroActivity, nativeOnCreate, (JNIEnv *env, jobject obj)) { ALLEGRO_SYSTEM_ANDROID *na_sys = NULL; jclass iae; jclass aisc; jclass asc; ALLEGRO_DEBUG("entered nativeOnCreate"); // we're already initialized, we REALLY don't want to run all the stuff below again. if(system_data.system) { return true; } pthread_t self = pthread_self(); ALLEGRO_DEBUG("pthread_self:%p", (void*)self); ALLEGRO_DEBUG("nativeOnCreate begin"); memset(&system_data, 0, sizeof(system_data)); ALLEGRO_DEBUG("grab activity global refs"); system_data.env = env; system_data.activity_object = (*env)->NewGlobalRef(env, obj); iae = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); system_data.illegal_argument_exception_class = (*env)->NewGlobalRef(env, iae); aisc = (*env)->FindClass(env, ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/AllegroInputStream"); system_data.input_stream_class = (*env)->NewGlobalRef(env, aisc); asc = (*env)->FindClass(env, ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/AllegroAPKStream"); system_data.apk_stream_class = (*env)->NewGlobalRef(env, asc); asc = (*env)->FindClass(env, ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/ImageLoader"); system_data.image_loader_class = (*env)->NewGlobalRef(env, asc); asc = (*env)->FindClass(env, ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/Clipboard"); system_data.clipboard_class = (*env)->NewGlobalRef(env, asc); asc = (*env)->FindClass(env, ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/AllegroAPKList"); system_data.apk_fs_class = (*env)->NewGlobalRef(env, asc); ALLEGRO_DEBUG("create mutex and cond objects"); system_data.mutex = al_create_mutex(); system_data.cond = al_create_cond(); ALLEGRO_DEBUG("get directories"); system_data.user_lib_name = _jni_callStringMethod(env, system_data.activity_object, "getUserLibName", "()Ljava/lang/String;"); system_data.resources_dir = _jni_callStringMethod(env, system_data.activity_object, "getResourcesDir", "()Ljava/lang/String;"); system_data.data_dir = _jni_callStringMethod(env, system_data.activity_object, "getPubDataDir", "()Ljava/lang/String;"); system_data.temp_dir = _jni_callStringMethod(env, system_data.activity_object, "getTempDir", "()Ljava/lang/String;"); system_data.apk_path = _jni_callStringMethod(env, system_data.activity_object, "getApkPath", "()Ljava/lang/String;"); system_data.model = _jni_callStringMethod(env, system_data.activity_object, "getModel", "()Ljava/lang/String;"); system_data.manufacturer = _jni_callStringMethod(env, system_data.activity_object, "getManufacturer", "()Ljava/lang/String;"); ALLEGRO_DEBUG("resources_dir: %s", al_cstr(system_data.resources_dir)); ALLEGRO_DEBUG("data_dir: %s", al_cstr(system_data.data_dir)); ALLEGRO_DEBUG("temp_dir: %s", al_cstr(system_data.temp_dir)); ALLEGRO_DEBUG("apk_path: %s", al_cstr(system_data.apk_path)); ALLEGRO_DEBUG("model: %s", al_cstr(system_data.model)); ALLEGRO_DEBUG("manufacturer: %s", al_cstr(system_data.manufacturer)); ALLEGRO_DEBUG("creating ALLEGRO_SYSTEM_ANDROID struct"); na_sys = system_data.system = (ALLEGRO_SYSTEM_ANDROID*)al_malloc(sizeof *na_sys); memset(na_sys, 0, sizeof *na_sys); ALLEGRO_DEBUG("get system pointer"); ALLEGRO_SYSTEM *sys = &na_sys->system; ALLEGRO_DEBUG("get system interface"); sys->vt = _al_system_android_interface(); ALLEGRO_DEBUG("init display vector"); _al_vector_init(&sys->displays, sizeof(ALLEGRO_DISPLAY_ANDROID *)); ALLEGRO_DEBUG("init time"); _al_unix_init_time(); const char *user_lib_name = al_cstr(system_data.user_lib_name); ALLEGRO_DEBUG("load user lib: %s", user_lib_name); system_data.user_lib = dlopen(user_lib_name, RTLD_LAZY|RTLD_GLOBAL); if (!system_data.user_lib) { ALLEGRO_ERROR("failed to load user lib: %s", user_lib_name); ALLEGRO_ERROR("%s", dlerror()); return false; } system_data.user_main = dlsym(system_data.user_lib, "main"); if (!system_data.user_main) { ALLEGRO_ERROR("failed to locate symbol main: %s", dlerror()); dlclose(system_data.user_lib); return false; } ALLEGRO_DEBUG("main function address: %p\n", system_data.user_main); ALLEGRO_DEBUG("creating trampoline for app thread"); system_data.trampoline = al_create_thread(android_app_trampoline, NULL); al_start_thread(system_data.trampoline); ALLEGRO_DEBUG("waiting for app trampoline to signal running"); al_lock_mutex(system_data.mutex); while(!system_data.trampoline_running) { al_wait_cond(system_data.cond, system_data.mutex); } al_unlock_mutex(system_data.mutex); ALLEGRO_DEBUG("setup done. returning to dalvik."); return true; } JNI_FUNC(void, AllegroActivity, nativeOnPause, (JNIEnv *env, jobject obj)) { (void)env; (void)obj; ALLEGRO_DEBUG("pause activity\n"); system_data.paused = true; ALLEGRO_SYSTEM *sys = (void *)al_get_system_driver(); if (!system_data.system || !sys) { ALLEGRO_DEBUG("no system driver"); return; } if (!_al_vector_size(&sys->displays)) { ALLEGRO_DEBUG("no display, not sending SWITCH_OUT event"); return; } ALLEGRO_DISPLAY *display = *(ALLEGRO_DISPLAY**)_al_vector_ref(&sys->displays, 0); if (display) { ALLEGRO_EVENT event; _al_event_source_lock(&display->es); if(_al_event_source_needs_to_generate_event(&display->es)) { event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_OUT; event.display.timestamp = al_current_time(); _al_event_source_emit_event(&display->es, &event); } _al_event_source_unlock(&display->es); } } JNI_FUNC(void, AllegroActivity, nativeOnResume, (JNIEnv *env, jobject obj)) { ALLEGRO_SYSTEM *sys = &system_data.system->system; ALLEGRO_DISPLAY *d = NULL; (void)obj; system_data.paused = false; ALLEGRO_DEBUG("resume activity"); if(!system_data.system || !sys) { ALLEGRO_DEBUG("no system driver"); return; } if(!_al_vector_size(&sys->displays)) { ALLEGRO_DEBUG("no display, not sending SWITCH_IN event"); return; } d = *(ALLEGRO_DISPLAY**)_al_vector_ref(&sys->displays, 0); ALLEGRO_DEBUG("got display: %p", d); if(!((ALLEGRO_DISPLAY_ANDROID*)d)->created) { _al_android_create_surface(env, true); // request android create our surface } ALLEGRO_DISPLAY *display = *(ALLEGRO_DISPLAY**)_al_vector_ref(&sys->displays, 0); if (display) { ALLEGRO_EVENT event; _al_event_source_lock(&display->es); if(_al_event_source_needs_to_generate_event(&display->es)) { event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_IN; event.display.timestamp = al_current_time(); _al_event_source_emit_event(&display->es, &event); } _al_event_source_unlock(&display->es); } } /* NOTE: don't put any ALLEGRO_DEBUG in here! */ JNI_FUNC(void, AllegroActivity, nativeOnDestroy, (JNIEnv *env, jobject obj)) { (void)obj; /* onDestroy can be called before main returns, for example if you start * a new activity, your Allegro game will get onDestroy when it returns. * At that point there's nothing you can do and any code you execute will * crash, so this attempts to handle that more gracefully. Calling * android_cleanup() eventually leads back here anyway. We ask android_cleanup * not to call al_uninstall_system because GPU access causes a crash at * this point (cleaning up bitmaps/displays etc.) The trampoline will exit * eventually too so we guard against android_cleanup() being called twice. */ bool main_returned = _jni_callBooleanMethodV( env, system_data.activity_object, "getMainReturned", "()Z" ); if (!main_returned) { exit(0); } if(!system_data.user_lib) { return; } system_data.user_main = NULL; if(dlclose(system_data.user_lib) != 0) { return; } (*env)->DeleteGlobalRef(env, system_data.activity_object); (*env)->DeleteGlobalRef(env, system_data.illegal_argument_exception_class); (*env)->DeleteGlobalRef(env, system_data.input_stream_class); free(system_data.system); memset(&system_data, 0, sizeof(system_data)); } JNI_FUNC(void, AllegroActivity, nativeOnOrientationChange, (JNIEnv *env, jobject obj, int orientation, bool init)) { ALLEGRO_SYSTEM *sys = &system_data.system->system; ALLEGRO_DISPLAY *d = NULL; ALLEGRO_EVENT event; (void)env; (void)obj; ALLEGRO_DEBUG("got orientation change!"); system_data.orientation = orientation; if (!init) { /* no display, just skip */ if (!_al_vector_size(&sys->displays)) { ALLEGRO_DEBUG("no display, not sending orientation change event"); return; } d = *(ALLEGRO_DISPLAY**)_al_vector_ref(&sys->displays, 0); ASSERT(d != NULL); ALLEGRO_DEBUG("locking display event source: %p %p", d, &d->es); _al_event_source_lock(&d->es); if(_al_event_source_needs_to_generate_event(&d->es)) { ALLEGRO_DEBUG("emit event"); event.display.type = ALLEGRO_EVENT_DISPLAY_ORIENTATION; event.display.timestamp = al_current_time(); event.display.orientation = orientation; _al_event_source_emit_event(&d->es, &event); } ALLEGRO_DEBUG("unlocking display event source"); _al_event_source_unlock(&d->es); } } JNI_FUNC(void, AllegroActivity, nativeSendJoystickConfigurationEvent, (JNIEnv *env, jobject obj)) { (void)env; (void)obj; if (!al_is_joystick_installed()) { return; } ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); _al_event_source_lock(es); ALLEGRO_EVENT event; event.type = ALLEGRO_EVENT_JOYSTICK_CONFIGURATION; _al_event_source_emit_event(es, &event); _al_event_source_unlock(es); } /* NOTE: don't put any ALLEGRO_DEBUG in here! */ static void finish_activity(JNIEnv *env) { _jni_callVoidMethod(env, system_data.activity_object, "postFinish"); } static ALLEGRO_SYSTEM *android_initialize(int flags) { (void)flags; ALLEGRO_DEBUG("android_initialize"); /* This was stored before user main ran, to make it easy and accessible * the same way for all threads, we set it in tls */ _al_android_set_jnienv(main_env); return &system_data.system->system; } static ALLEGRO_JOYSTICK_DRIVER *android_get_joystick_driver(void) { return &_al_android_joystick_driver; } static int android_get_num_video_adapters(void) { return 1; } static bool android_get_monitor_info(int adapter, ALLEGRO_MONITOR_INFO *info) { if (adapter >= android_get_num_video_adapters()) return false; JNIEnv * env = (JNIEnv *)_al_android_get_jnienv(); jobject rect = _jni_callObjectMethod(env, _al_android_activity_object(), "getDisplaySize", "()Landroid/graphics/Rect;"); info->x1 = 0; info->y1 = 0; info->x2 = _jni_callIntMethod(env, rect, "width"); info->y2 = _jni_callIntMethod(env, rect, "height"); ALLEGRO_DEBUG("Monitor Info: %d:%d", info->x2, info->y2); _jni_callv(env, DeleteLocalRef, rect); return true; } static void android_shutdown_system(void) { ALLEGRO_SYSTEM *s = al_get_system_driver(); /* Close all open displays. */ while (_al_vector_size(&s->displays) > 0) { ALLEGRO_DISPLAY **dptr = _al_vector_ref(&s->displays, 0); ALLEGRO_DISPLAY *d = *dptr; al_destroy_display(d); } _al_vector_free(&s->displays); } static bool android_inhibit_screensaver(bool inhibit) { return _jni_callBooleanMethodV(_al_android_get_jnienv(), system_data.activity_object, "inhibitScreenLock", "(Z)Z", inhibit); } static ALLEGRO_SYSTEM_INTERFACE *android_vt; ALLEGRO_SYSTEM_INTERFACE *_al_system_android_interface() { if(android_vt) return android_vt; android_vt = al_malloc(sizeof *android_vt); memset(android_vt, 0, sizeof *android_vt); android_vt->id = ALLEGRO_SYSTEM_ID_ANDROID; android_vt->initialize = android_initialize; android_vt->get_display_driver = _al_get_android_display_driver; android_vt->get_keyboard_driver = _al_get_android_keyboard_driver; android_vt->get_mouse_driver = _al_get_android_mouse_driver; android_vt->get_touch_input_driver = _al_get_android_touch_input_driver; android_vt->get_joystick_driver = android_get_joystick_driver; android_vt->get_num_video_adapters = android_get_num_video_adapters; android_vt->get_monitor_info = android_get_monitor_info; android_vt->get_path = _al_android_get_path; android_vt->shutdown_system = android_shutdown_system; android_vt->inhibit_screensaver = android_inhibit_screensaver; android_vt->get_time = _al_unix_get_time; android_vt->rest = _al_unix_rest; android_vt->init_timeout = _al_unix_init_timeout; return android_vt; } ALLEGRO_PATH *_al_android_get_path(int id) { ALLEGRO_PATH *path = NULL; switch(id) { case ALLEGRO_RESOURCES_PATH: /* path to bundle's files */ path = al_create_path_for_directory(al_cstr(system_data.resources_dir)); break; case ALLEGRO_TEMP_PATH: /* path to the application cache */ path = al_create_path_for_directory(al_cstr(system_data.temp_dir)); break; case ALLEGRO_USER_DATA_PATH: case ALLEGRO_USER_HOME_PATH: case ALLEGRO_USER_SETTINGS_PATH: case ALLEGRO_USER_DOCUMENTS_PATH: /* path to sdcard */ path = al_create_path_for_directory(al_cstr(system_data.data_dir)); break; case ALLEGRO_EXENAME_PATH: /* bundle path + bundle name */ // FIXME! path = al_create_path(al_cstr(system_data.apk_path)); break; default: path = al_create_path_for_directory("/DANGER/WILL/ROBINSON"); break; } return path; } static const char *_real_al_android_get_os_version(JNIEnv *env) { static char buffer[25]; ALLEGRO_USTR *s = _jni_callStringMethod(env, system_data.activity_object, "getOsVersion", "()Ljava/lang/String;"); strncpy(buffer, al_cstr(s), 25); al_ustr_free(s); return buffer; } /* Function: al_android_get_os_version */ const char *al_android_get_os_version(void) { return _real_al_android_get_os_version(_al_android_get_jnienv()); } void _al_android_thread_created(void) { JNIEnv *env; JavaVMAttachArgs attach_args = { JNI_VERSION_1_4, "trampoline", NULL }; (*javavm)->AttachCurrentThread(javavm, &env, &attach_args); /* This function runs once before al_init, so before TLS is initialized * so we save the environment and set it later in that case. */ ALLEGRO_SYSTEM *s = al_get_system_driver(); if (s && s->installed) { _al_android_set_jnienv(env); } else { main_env = env; } } void _al_android_thread_ended(void) { (*javavm)->DetachCurrentThread(javavm); } void _al_android_set_capture_volume_keys(ALLEGRO_DISPLAY *display, bool onoff) { ALLEGRO_DISPLAY_ANDROID *d = (ALLEGRO_DISPLAY_ANDROID *)display; _jni_callVoidMethodV(_al_android_get_jnienv(), d->surface_object, "setCaptureVolumeKeys", "(Z)V", onoff); } /* register system interfaces */ void _al_register_system_interfaces(void) { ALLEGRO_SYSTEM_INTERFACE **add; /* add the native activity driver */ add = _al_vector_alloc_back(&_al_system_interfaces); *add = _al_system_android_interface(); /* TODO: add the non native activity driver */ } /* Function: al_android_get_jni_env */ JNIEnv *al_android_get_jni_env(void) { return _al_android_get_jnienv(); } /* Function: al_android_get_activity */ jobject al_android_get_activity(void) { return _al_android_activity_object(); } /* Function: al_android_open_fd */ int al_android_open_fd(const char *uri, const char *mode) { JNIEnv *env = _al_android_get_jnienv(); jobject activity = _al_android_activity_object(); jstring juri = _jni_call(env, jstring, NewStringUTF, uri != NULL ? uri : ""); /* content:// or file:// */ jstring jmode = _jni_call(env, jstring, NewStringUTF, mode != NULL ? mode : ""); /* "r", "w", "rw", "wa", "wt", "rwt" */ int fd = _jni_callIntMethodV(env, activity, "openFileDescriptor", "(Ljava/lang/String;Ljava/lang/String;)I", juri, jmode); _jni_callv(env, DeleteLocalRef, jmode); _jni_callv(env, DeleteLocalRef, juri); if (fd == -1) al_set_errno(ENOENT); else if (fd < 0) al_set_errno(ENOTSUP); return fd; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/android/android_touch.c000066400000000000000000000261511473414355200206620ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Android family device touch input driver. * * By Thomas Fjellstrom. * * Based on the iOS touch input driver by Michał Cichoń. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_android.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_touch_input.h" ALLEGRO_DEBUG_CHANNEL("android") /* forward declaration */ static void android_touch_input_handle_cancel(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp); static ALLEGRO_TOUCH_INPUT_STATE touch_input_state; static ALLEGRO_MOUSE_STATE mouse_state; static ALLEGRO_TOUCH_INPUT touch_input; static bool installed = false; static void reset_touch_input_state(void) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; i++) { touch_input_state.touches[i].id = -1; } } static void generate_touch_input_event(unsigned int type, double timestamp, int id, float x, float y, float dx, float dy, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_EVENT event; bool want_touch_event = _al_event_source_needs_to_generate_event(&touch_input.es); bool want_mouse_emulation_event; if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_5_0_x) { want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && al_is_mouse_installed(); } else { want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && primary && al_is_mouse_installed(); } if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_NONE) want_mouse_emulation_event = false; else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_INCLUSIVE) want_touch_event = al_is_mouse_installed() ? (want_touch_event && !primary) : want_touch_event; else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_EXCLUSIVE) want_touch_event = al_is_mouse_installed() ? false : want_touch_event; if (!want_touch_event && !want_mouse_emulation_event) return; if (want_touch_event) { event.touch.type = type; event.touch.display = (ALLEGRO_DISPLAY*)disp; event.touch.timestamp = timestamp; event.touch.id = id; event.touch.x = x; event.touch.y = y; event.touch.dx = dx; event.touch.dy = dy; event.touch.primary = primary; _al_event_source_lock(&touch_input.es); _al_event_source_emit_event(&touch_input.es, &event); _al_event_source_unlock(&touch_input.es); } if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_NONE) { mouse_state.x = (int)x; mouse_state.y = (int)y; if (type == ALLEGRO_EVENT_TOUCH_BEGIN) mouse_state.buttons++; else if (type == ALLEGRO_EVENT_TOUCH_END) mouse_state.buttons--; mouse_state.pressure = mouse_state.buttons ? 1.0 : 0.0; /* TODO */ _al_event_source_lock(&touch_input.mouse_emulation_es); if (want_mouse_emulation_event) { switch (type) { case ALLEGRO_EVENT_TOUCH_BEGIN: type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN; break; case ALLEGRO_EVENT_TOUCH_CANCEL: case ALLEGRO_EVENT_TOUCH_END: type = ALLEGRO_EVENT_MOUSE_BUTTON_UP; break; case ALLEGRO_EVENT_TOUCH_MOVE: type = ALLEGRO_EVENT_MOUSE_AXES; break; } event.mouse.type = type; event.mouse.timestamp = timestamp; event.mouse.display = (ALLEGRO_DISPLAY*)disp; event.mouse.x = (int)x; event.mouse.y = (int)y; event.mouse.dx = (int)dx; event.mouse.dy = (int)dy; event.mouse.dz = 0; event.mouse.dw = 0; if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) { event.mouse.button = 1; } else { event.mouse.button = id; } event.mouse.pressure = mouse_state.pressure; if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) { al_set_mouse_xy(event.mouse.display, event.mouse.x, event.mouse.y); } _al_event_source_emit_event(&touch_input.mouse_emulation_es, &event); } _al_event_source_unlock(&touch_input.mouse_emulation_es); } } static bool init_touch_input(void) { if (installed) return false; reset_touch_input_state(); memset(&mouse_state, 0, sizeof(mouse_state)); _al_event_source_init(&touch_input.es); _al_event_source_init(&touch_input.mouse_emulation_es); touch_input.mouse_emulation_mode = ALLEGRO_MOUSE_EMULATION_TRANSPARENT; installed = true; return true; } static void exit_touch_input(void) { if (!installed) return; reset_touch_input_state(); memset(&mouse_state, 0, sizeof(mouse_state)); _al_event_source_free(&touch_input.es); _al_event_source_free(&touch_input.mouse_emulation_es); installed = false; } static ALLEGRO_TOUCH_INPUT* get_touch_input(void) { return &touch_input; } static void get_touch_input_state(ALLEGRO_TOUCH_INPUT_STATE *ret_state) { _al_event_source_lock(&touch_input.es); *ret_state = touch_input_state; _al_event_source_unlock(&touch_input.es); } static void set_mouse_emulation_mode(int mode) { if (touch_input.mouse_emulation_mode != mode) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) { ALLEGRO_TOUCH_STATE* touch = touch_input_state.touches + i; if (touch->id > 0) { android_touch_input_handle_cancel(touch->id, al_get_time(), touch->x, touch->y, touch->primary, touch->display); } } touch_input.mouse_emulation_mode = mode; } } static ALLEGRO_TOUCH_STATE* find_free_touch_state(void) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) if (touch_input_state.touches[i].id < 0) return touch_input_state.touches + i; return NULL; } static ALLEGRO_TOUCH_STATE* find_touch_state_with_id(int id) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) if (touch_input_state.touches[i].id == id) return touch_input_state.touches + i; return NULL; } static void android_touch_input_handle_begin(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_TOUCH_STATE* state = find_free_touch_state(); (void)primary; if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->id = id; state->x = x; state->y = y; state->dx = 0.0f; state->dy = 0.0f; state->primary = primary; state->display = disp; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_BEGIN, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); } static void android_touch_input_handle_end(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_TOUCH_STATE* state = find_touch_state_with_id(id); (void)primary; if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_END, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); _al_event_source_lock(&touch_input.es); state->id = -1; _al_event_source_unlock(&touch_input.es); } static void android_touch_input_handle_move(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_TOUCH_STATE* state = find_touch_state_with_id(id); (void)primary; if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_MOVE, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); } static void android_touch_input_handle_cancel(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_TOUCH_STATE* state = find_touch_state_with_id(id); (void)primary; if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_CANCEL, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); _al_event_source_lock(&touch_input.es); state->id = -1; _al_event_source_unlock(&touch_input.es); } JNI_FUNC(void, TouchListener, nativeOnTouch, (JNIEnv *env, jobject obj, jint id, jint action, jfloat x, jfloat y, jboolean primary)) { (void)env; (void)obj; ALLEGRO_SYSTEM *system = al_get_system_driver(); ASSERT(system != NULL); ALLEGRO_DISPLAY **dptr = _al_vector_ref(&system->displays, 0); ALLEGRO_DISPLAY *display = *dptr; ASSERT(display != NULL); switch (action) { case ALLEGRO_EVENT_TOUCH_BEGIN: android_touch_input_handle_begin(id, al_get_time(), x, y, primary, display); break; case ALLEGRO_EVENT_TOUCH_END: android_touch_input_handle_end(id, al_get_time(), x, y, primary, display); break; case ALLEGRO_EVENT_TOUCH_MOVE: android_touch_input_handle_move(id, al_get_time(), x, y, primary, display); break; case ALLEGRO_EVENT_TOUCH_CANCEL: android_touch_input_handle_cancel(id, al_get_time(), x, y, primary, display); break; default: ALLEGRO_ERROR("unknown touch action: %i", action); break; } } /* the driver vtable */ #define TOUCH_INPUT_ANDROID AL_ID('A','T','I','D') static ALLEGRO_TOUCH_INPUT_DRIVER touch_input_driver = { TOUCH_INPUT_ANDROID, init_touch_input, exit_touch_input, get_touch_input, get_touch_input_state, set_mouse_emulation_mode, NULL }; ALLEGRO_TOUCH_INPUT_DRIVER *_al_get_android_touch_input_driver(void) { return &touch_input_driver; } void _al_android_mouse_get_state(ALLEGRO_MOUSE_STATE *ret_state) { _al_event_source_lock(&touch_input.es); *ret_state = mouse_state; _al_event_source_unlock(&touch_input.es); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/android/jni_helpers.c000066400000000000000000000073471473414355200203500ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Android jni helpers * * By Thomas Fjellstrom. * */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_android.h" #include #include ALLEGRO_DEBUG_CHANNEL("jni") #define VERBOSE_DEBUG(a, ...) (void)0 /* jni helpers */ void __jni_checkException(JNIEnv *env, const char *file, const char *func, int line) { jthrowable exc; exc = (*env)->ExceptionOccurred(env); if (exc) { ALLEGRO_DEBUG("GOT AN EXCEPTION @ %s:%i %s", file, line, func); /* We don't do much with the exception, except that we print a debug message for it, clear it, and throw a new exception. */ (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); (*env)->FatalError(env, "EXCEPTION"); //(*env)->ThrowNew(env, system_data.illegal_argument_exception_class, "thrown from C code"); } } jobject _jni_callObjectMethod(JNIEnv *env, jobject object, const char *name, const char *sig) { VERBOSE_DEBUG("%s (%s)", name, sig); jclass class_id = _jni_call(env, jclass, GetObjectClass, object); jmethodID method_id = _jni_call(env, jmethodID, GetMethodID, class_id, name, sig); jobject ret = _jni_call(env, jobject, CallObjectMethod, object, method_id); _jni_callv(env, DeleteLocalRef, class_id); return ret; } jobject _jni_callObjectMethodV(JNIEnv *env, jobject object, const char *name, const char *sig, ...) { va_list ap; VERBOSE_DEBUG("%s (%s)", name, sig); jclass class_id = _jni_call(env, jclass, GetObjectClass, object); jmethodID method_id = _jni_call(env, jmethodID, GetMethodID, class_id, name, sig); va_start(ap, sig); jobject ret = _jni_call(env, jobject, CallObjectMethodV, object, method_id, ap); va_end(ap); _jni_callv(env, DeleteLocalRef, class_id); VERBOSE_DEBUG("callObjectMethodV end"); return ret; } ALLEGRO_USTR *_jni_getString(JNIEnv *env, jstring str_obj) { VERBOSE_DEBUG("GetStringUTFLength"); jsize len = _jni_call(env, jsize, GetStringUTFLength, str_obj); const char *str = _jni_call(env, const char *, GetStringUTFChars, str_obj, NULL); VERBOSE_DEBUG("al_ustr_new_from_buffer"); ALLEGRO_USTR *ustr = al_ustr_new_from_buffer(str, len); _jni_callv(env, ReleaseStringUTFChars, str_obj, str); return ustr; } ALLEGRO_USTR *_jni_callStringMethod(JNIEnv *env, jobject obj, const char *name, const char *sig) { jstring str_obj = (jstring)_jni_callObjectMethod(env, obj, name, sig); ALLEGRO_USTR *ustr = _jni_getString(env, str_obj); _jni_callv(env, DeleteLocalRef, str_obj); return ustr; } jobject _jni_callStaticObjectMethodV(JNIEnv *env, jclass cls, const char *name, const char *sig, ...) { jmethodID mid; jobject ret; va_list ap; mid = _jni_call(env, jmethodID, GetStaticMethodID, cls, name, sig); va_start(ap, sig); ret = _jni_call(env, jobject, CallStaticObjectMethodV, cls, mid, ap); va_end(ap); return ret; } jint _jni_callStaticIntMethodV(JNIEnv *env, jclass cls, const char *name, const char *sig, ...) { jmethodID mid; jint ret; va_list ap; mid = _jni_call(env, jmethodID, GetStaticMethodID, cls, name, sig); va_start(ap, sig); ret = _jni_call(env, jint, CallStaticIntMethodV, cls, mid, ap); va_end(ap); return ret; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/bitmap.c000066400000000000000000000500171473414355200156720ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * New bitmap routines. * * By Elias Pschernig and Trent Gamblin. * * See readme.txt for copyright information. */ /* Title: Bitmap routines */ #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_pixels.h" #include "allegro5/internal/aintern_shader.h" #include "allegro5/internal/aintern_system.h" ALLEGRO_DEBUG_CHANNEL("bitmap") /* Creates a memory bitmap. */ static ALLEGRO_BITMAP *create_memory_bitmap(ALLEGRO_DISPLAY *current_display, int w, int h, int format, int flags) { ALLEGRO_BITMAP *bitmap; int pitch; if (_al_pixel_format_is_video_only(format)) { /* Can't have a video-only memory bitmap... */ return NULL; } format = _al_get_real_pixel_format(current_display, format); bitmap = al_calloc(1, sizeof *bitmap); pitch = w * al_get_pixel_size(format); bitmap->vt = NULL; bitmap->_format = format; /* If this is really a video bitmap, we add it to the list of to * be converted bitmaps. */ bitmap->_flags = flags | ALLEGRO_MEMORY_BITMAP; bitmap->_flags &= ~ALLEGRO_VIDEO_BITMAP; bitmap->w = w; bitmap->h = h; bitmap->pitch = pitch; bitmap->_display = NULL; bitmap->locked = false; bitmap->cl = bitmap->ct = 0; bitmap->cr_excl = w; bitmap->cb_excl = h; al_identity_transform(&bitmap->transform); al_identity_transform(&bitmap->inverse_transform); bitmap->inverse_transform_dirty = false; al_identity_transform(&bitmap->proj_transform); al_orthographic_transform(&bitmap->proj_transform, 0, 0, -1.0, w, h, 1.0); bitmap->parent = NULL; bitmap->xofs = bitmap->yofs = 0; bitmap->memory = al_malloc(pitch * h); bitmap->use_bitmap_blender = false; bitmap->blender.blend_color = al_map_rgba(0, 0, 0, 0); al_get_new_bitmap_wrap(&bitmap->_wrap_u, &bitmap->_wrap_v); _al_register_convert_bitmap(bitmap); return bitmap; } static void destroy_memory_bitmap(ALLEGRO_BITMAP *bmp) { _al_unregister_convert_bitmap(bmp); if (bmp->memory) al_free(bmp->memory); al_free(bmp); } ALLEGRO_BITMAP *_al_create_bitmap_params(ALLEGRO_DISPLAY *current_display, int w, int h, int format, int flags, int depth, int samples) { ALLEGRO_SYSTEM *system = al_get_system_driver(); ALLEGRO_BITMAP *bitmap; ALLEGRO_BITMAP **back; bool result; /* Reject bitmaps with negative dimensions. * Also reject bitmaps where a calculation pixel_size*w*h would overflow * int. Supporting such bitmaps would require a lot more work. * Overflow calc based on https://stackoverflow.com/a/1514309/231929 */ if (w < 0 || h < 0 || (h > 0 && (int64_t) w > (INT_MAX/4) / (int64_t) h)) { ALLEGRO_WARN("Rejecting %dx%d bitmap\n", w, h); return NULL; } if ((flags & ALLEGRO_MEMORY_BITMAP) || !current_display || !current_display->vt || current_display->vt->create_bitmap == NULL || _al_vector_size(&system->displays) < 1) { if (flags & ALLEGRO_VIDEO_BITMAP) return NULL; return create_memory_bitmap(current_display, w, h, format, flags); } /* Else it's a display bitmap */ bitmap = current_display->vt->create_bitmap(current_display, w, h, format, flags); if (!bitmap) { ALLEGRO_ERROR("failed to create display bitmap\n"); return NULL; } bitmap->_display = current_display; bitmap->w = w; bitmap->h = h; bitmap->locked = false; bitmap->cl = 0; bitmap->ct = 0; bitmap->cr_excl = w; bitmap->cb_excl = h; al_identity_transform(&bitmap->transform); al_identity_transform(&bitmap->inverse_transform); bitmap->inverse_transform_dirty = false; al_identity_transform(&bitmap->proj_transform); al_orthographic_transform(&bitmap->proj_transform, 0, 0, -1.0, w, h, 1.0); bitmap->parent = NULL; bitmap->xofs = 0; bitmap->yofs = 0; bitmap->_flags |= ALLEGRO_VIDEO_BITMAP; bitmap->dirty = !(bitmap->_flags & ALLEGRO_NO_PRESERVE_TEXTURE); bitmap->_depth = depth; bitmap->_samples = samples; bitmap->use_bitmap_blender = false; bitmap->blender.blend_color = al_map_rgba(0, 0, 0, 0); al_get_new_bitmap_wrap(&bitmap->_wrap_u, &bitmap->_wrap_v); /* The display driver should have set the bitmap->memory field if * appropriate; video bitmaps may leave it NULL. */ ASSERT(bitmap->pitch >= w * al_get_pixel_size(bitmap->_format)); result = bitmap->vt->upload_bitmap(bitmap); if (!result) { al_destroy_bitmap(bitmap); if (flags & ALLEGRO_VIDEO_BITMAP) return NULL; /* With ALLEGRO_CONVERT_BITMAP, just use a memory bitmap instead if * video failed. */ return create_memory_bitmap(current_display, w, h, format, flags); } /* We keep a list of bitmaps depending on the current display so that we can * convert them to memory bimaps when the display is destroyed. */ back = _al_vector_alloc_back(¤t_display->bitmaps); *back = bitmap; return bitmap; } /* Function: al_create_bitmap */ ALLEGRO_BITMAP *al_create_bitmap(int w, int h) { ALLEGRO_BITMAP *bitmap; bitmap = _al_create_bitmap_params(al_get_current_display(), w, h, al_get_new_bitmap_format(), al_get_new_bitmap_flags(), al_get_new_bitmap_depth(), al_get_new_bitmap_samples()); if (bitmap) { bitmap->dtor_item = _al_register_destructor(_al_dtor_list, "bitmap", bitmap, (void (*)(void *))al_destroy_bitmap); } return bitmap; } /* Function: al_destroy_bitmap */ void al_destroy_bitmap(ALLEGRO_BITMAP *bitmap) { if (!bitmap) { return; } /* As a convenience, implicitly untarget the bitmap on the calling thread * before it is destroyed, but maintain the current display. */ if (bitmap == al_get_target_bitmap()) { ALLEGRO_DISPLAY *display = al_get_current_display(); if (display) al_set_target_bitmap(al_get_backbuffer(display)); else al_set_target_bitmap(NULL); } _al_set_bitmap_shader_field(bitmap, NULL); _al_unregister_destructor(_al_dtor_list, bitmap->dtor_item); if (!al_is_sub_bitmap(bitmap)) { ALLEGRO_DISPLAY* disp = _al_get_bitmap_display(bitmap); if (al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP) { destroy_memory_bitmap(bitmap); return; } /* Else it's a display bitmap */ if (bitmap->locked) al_unlock_bitmap(bitmap); if (bitmap->vt) bitmap->vt->destroy_bitmap(bitmap); if (disp) _al_vector_find_and_delete(&disp->bitmaps, &bitmap); if (bitmap->memory) al_free(bitmap->memory); } al_free(bitmap); } /* Function: al_convert_mask_to_alpha */ void al_convert_mask_to_alpha(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR mask_color) { ALLEGRO_LOCKED_REGION *lr; int x, y; ALLEGRO_COLOR pixel; ALLEGRO_COLOR alpha_pixel; ALLEGRO_STATE state; if (!(lr = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ANY, 0))) { ALLEGRO_ERROR("Couldn't lock bitmap."); return; } al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP); al_set_target_bitmap(bitmap); alpha_pixel = al_map_rgba(0, 0, 0, 0); for (y = 0; y < bitmap->h; y++) { for (x = 0; x < bitmap->w; x++) { pixel = al_get_pixel(bitmap, x, y); if (memcmp(&pixel, &mask_color, sizeof(ALLEGRO_COLOR)) == 0) { al_put_pixel(x, y, alpha_pixel); } } } al_unlock_bitmap(bitmap); al_restore_state(&state); } /* Function: al_get_bitmap_width */ int al_get_bitmap_width(ALLEGRO_BITMAP *bitmap) { return bitmap->w; } /* Function: al_get_bitmap_height */ int al_get_bitmap_height(ALLEGRO_BITMAP *bitmap) { return bitmap->h; } /* Function: al_get_bitmap_format */ int al_get_bitmap_format(ALLEGRO_BITMAP *bitmap) { if (bitmap->parent) return bitmap->parent->_format; else return bitmap->_format; } int _al_get_bitmap_memory_format(ALLEGRO_BITMAP *bitmap) { if (bitmap->parent) return bitmap->parent->_memory_format; else return bitmap->_memory_format; } /* Function: al_get_bitmap_flags */ int al_get_bitmap_flags(ALLEGRO_BITMAP *bitmap) { if (bitmap->parent) return bitmap->parent->_flags; else return bitmap->_flags; } ALLEGRO_DISPLAY *_al_get_bitmap_display(ALLEGRO_BITMAP *bitmap) { if (bitmap->parent) return bitmap->parent->_display; else return bitmap->_display; } /* Function: al_get_bitmap_depth */ int al_get_bitmap_depth(ALLEGRO_BITMAP *bitmap) { if (bitmap->parent) return bitmap->parent->_depth; else return bitmap->_depth; } /* Function: al_get_bitmap_samples */ int al_get_bitmap_samples(ALLEGRO_BITMAP *bitmap) { if (bitmap->parent) return bitmap->parent->_samples; else return bitmap->_samples; } /* Function: al_get_bitmap_blend_color */ ALLEGRO_COLOR al_get_bitmap_blend_color(void) { ALLEGRO_BITMAP *bitmap = al_get_target_bitmap(); ALLEGRO_BLENDER *b; ASSERT(bitmap); if (!bitmap->use_bitmap_blender) { /* If no bitmap blender set, use TLS */ return al_get_blend_color(); } b = &bitmap->blender; return b->blend_color; } /* Function: al_get_bitmap_blender */ void al_get_bitmap_blender(int *op, int *src, int *dst) { al_get_separate_bitmap_blender(op, src, dst, NULL, NULL, NULL); } /* Function: al_get_separate_bitmap_blender */ void al_get_separate_bitmap_blender(int *op, int *src, int *dst, int *alpha_op, int *alpha_src, int *alpha_dst) { ALLEGRO_BITMAP *bitmap = al_get_target_bitmap(); ALLEGRO_BLENDER *b; ASSERT(bitmap); if (!bitmap->use_bitmap_blender) { /* If no bitmap blender set, use TLS */ al_get_separate_blender(op, src, dst, alpha_op, alpha_src, alpha_dst); return; } b = &bitmap->blender; if (op) *op = b->blend_op; if (src) *src = b->blend_source; if (dst) *dst = b->blend_dest; if (alpha_op) *alpha_op = b->blend_alpha_op; if (alpha_src) *alpha_src = b->blend_alpha_source; if (alpha_dst) *alpha_dst = b->blend_alpha_dest; } /* Function: al_set_bitmap_blend_color */ void al_set_bitmap_blend_color(ALLEGRO_COLOR col) { ALLEGRO_BITMAP *bitmap = al_get_target_bitmap(); ALLEGRO_BLENDER *b; ASSERT(bitmap); b = &bitmap->blender; b->blend_color = col; } /* Function: al_set_bitmap_blender */ void al_set_bitmap_blender(int op, int src, int dest) { ALLEGRO_BITMAP *bitmap = al_get_target_bitmap(); ASSERT(bitmap); al_set_separate_bitmap_blender(op, src, dest, op, src, dest); } /* Function: al_set_separate_bitmap_blender */ void al_set_separate_bitmap_blender(int op, int src, int dst, int alpha_op, int alpha_src, int alpha_dst) { ALLEGRO_BITMAP *bitmap = al_get_target_bitmap(); ALLEGRO_BLENDER *b; ASSERT(bitmap); bitmap->use_bitmap_blender = true; b = &bitmap->blender; b->blend_op = op; b->blend_source = src; b->blend_dest = dst; b->blend_alpha_op = alpha_op; b->blend_alpha_source = alpha_src; b->blend_alpha_dest = alpha_dst; } /* Function: al_reset_bitmap_blender */ void al_reset_bitmap_blender(void) { ALLEGRO_BITMAP *bitmap = al_get_target_bitmap(); ASSERT(bitmap); bitmap->use_bitmap_blender = false; bitmap->blender.blend_color = al_map_rgba(0, 0, 0, 0); } /* Function: al_set_clipping_rectangle */ void al_set_clipping_rectangle(int x, int y, int width, int height) { ALLEGRO_BITMAP *bitmap = al_get_target_bitmap(); ASSERT(bitmap); if (x < 0) { width += x; x = 0; } if (y < 0) { height += y; y = 0; } if (x + width > bitmap->w) { width = bitmap->w - x; } if (y + height > bitmap->h) { height = bitmap->h - y; } if (width < 0) { width = 0; } if (height < 0) { height = 0; } bitmap->cl = x; bitmap->ct = y; bitmap->cr_excl = x + width; bitmap->cb_excl = y + height; if (bitmap->vt && bitmap->vt->update_clipping_rectangle) { bitmap->vt->update_clipping_rectangle(bitmap); } } /* Function: al_reset_clipping_rectangle */ void al_reset_clipping_rectangle(void) { ALLEGRO_BITMAP *bitmap = al_get_target_bitmap(); if (bitmap) { int w = al_get_bitmap_width(bitmap); int h = al_get_bitmap_height(bitmap); al_set_clipping_rectangle(0, 0, w, h); } } /* Function: al_get_clipping_rectangle */ void al_get_clipping_rectangle(int *x, int *y, int *w, int *h) { ALLEGRO_BITMAP *bitmap = al_get_target_bitmap(); ASSERT(bitmap); if (x) *x = bitmap->cl; if (y) *y = bitmap->ct; if (w) *w = bitmap->cr_excl - bitmap->cl; if (h) *h = bitmap->cb_excl - bitmap->ct; } /* Function: al_create_sub_bitmap */ ALLEGRO_BITMAP *al_create_sub_bitmap(ALLEGRO_BITMAP *parent, int x, int y, int w, int h) { ALLEGRO_BITMAP *bitmap; if (parent->parent) { x += parent->xofs; y += parent->yofs; parent = parent->parent; } bitmap = al_calloc(1, sizeof *bitmap); bitmap->vt = parent->vt; /* Sub-bitmap inherits these from the parent. * Leave these unchanged so they can be detected if improperly accessed * directly. */ bitmap->_format = 0; bitmap->_flags = 0; bitmap->_display = (ALLEGRO_DISPLAY*)0x1; bitmap->_wrap_u = 0; bitmap->_wrap_v = 0; bitmap->w = w; bitmap->h = h; bitmap->locked = false; bitmap->cl = bitmap->ct = 0; bitmap->cr_excl = w; bitmap->cb_excl = h; al_identity_transform(&bitmap->transform); al_identity_transform(&bitmap->inverse_transform); bitmap->inverse_transform_dirty = false; al_identity_transform(&bitmap->proj_transform); al_orthographic_transform(&bitmap->proj_transform, 0, 0, -1.0, w, h, 1.0); bitmap->shader = NULL; bitmap->parent = parent; bitmap->xofs = x; bitmap->yofs = y; bitmap->memory = NULL; bitmap->dtor_item = _al_register_destructor(_al_dtor_list, "sub_bitmap", bitmap, (void (*)(void *))al_destroy_bitmap); return bitmap; } /* Function: al_reparent_bitmap */ void al_reparent_bitmap(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP *parent, int x, int y, int w, int h) { ASSERT(bitmap->parent); /* Re-parenting a non-sub-bitmap makes no sense, so in release mode * just ignore it. */ if (!bitmap->parent) return; if (parent->parent) { x += parent->xofs; y += parent->yofs; parent = parent->parent; } bitmap->parent = parent; bitmap->xofs = x; bitmap->yofs = y; bitmap->w = w; bitmap->h = h; } /* Function: al_is_sub_bitmap */ bool al_is_sub_bitmap(ALLEGRO_BITMAP *bitmap) { return (bitmap->parent != NULL); } /* Function: al_get_parent_bitmap */ ALLEGRO_BITMAP *al_get_parent_bitmap(ALLEGRO_BITMAP *bitmap) { ASSERT(bitmap); return bitmap->parent; } /* Function: al_get_bitmap_x */ int al_get_bitmap_x(ALLEGRO_BITMAP *bitmap) { ASSERT(bitmap); return bitmap->xofs; } /* Function: al_get_bitmap_y */ int al_get_bitmap_y(ALLEGRO_BITMAP *bitmap) { ASSERT(bitmap); return bitmap->yofs; } static bool transfer_bitmap_data(ALLEGRO_BITMAP *src, ALLEGRO_BITMAP *dst) { ALLEGRO_LOCKED_REGION *dst_region; ALLEGRO_LOCKED_REGION *src_region; int src_format = al_get_bitmap_format(src); int dst_format = al_get_bitmap_format(dst); bool src_compressed = _al_pixel_format_is_compressed(src_format); bool dst_compressed = _al_pixel_format_is_compressed(dst_format); int copy_w = src->w; int copy_h = src->h; if (src_compressed && dst_compressed && src_format == dst_format) { int block_width = al_get_pixel_block_width(src_format); int block_height = al_get_pixel_block_height(src_format); if (!(src_region = al_lock_bitmap_blocked(src, ALLEGRO_LOCK_READONLY))) return false; if (!(dst_region = al_lock_bitmap_blocked(dst, ALLEGRO_LOCK_WRITEONLY))) { al_unlock_bitmap(src); return false; } copy_w = _al_get_least_multiple(copy_w, block_width); copy_h = _al_get_least_multiple(copy_h, block_height); ALLEGRO_DEBUG("Taking fast clone path.\n"); } else { int lock_format = ALLEGRO_PIXEL_FORMAT_ANY; /* Go through a non-compressed intermediate */ if (src_compressed && !dst_compressed) { lock_format = dst_format; } else if (!src_compressed && dst_compressed) { lock_format = src_format; } if (!(src_region = al_lock_bitmap(src, lock_format, ALLEGRO_LOCK_READONLY))) return false; if (!(dst_region = al_lock_bitmap(dst, lock_format, ALLEGRO_LOCK_WRITEONLY))) { al_unlock_bitmap(src); return false; } } _al_convert_bitmap_data( src_region->data, src_region->format, src_region->pitch, dst_region->data, dst_region->format, dst_region->pitch, 0, 0, 0, 0, copy_w, copy_h); al_unlock_bitmap(src); al_unlock_bitmap(dst); return true; } void _al_copy_bitmap_data( const void *src, int src_pitch, void *dst, int dst_pitch, int sx, int sy, int dx, int dy, int width, int height, int format) { int block_width = al_get_pixel_block_width(format); int block_height = al_get_pixel_block_height(format); int block_size = al_get_pixel_block_size(format); const char *src_ptr = src; char *dst_ptr = dst; int y; ASSERT(src); ASSERT(dst); ASSERT(_al_pixel_format_is_real(format)); ASSERT(width % block_width == 0); ASSERT(height % block_height == 0); ASSERT(sx % block_width == 0); ASSERT(sy % block_height == 0); ASSERT(dx % block_width == 0); ASSERT(dy % block_height == 0); sx /= block_width; sy /= block_height; dx /= block_width; dy /= block_height; width /= block_width; height /= block_height; if ((src_ptr == dst_ptr) && (src_pitch == dst_pitch)) { return; } src_ptr += sy * src_pitch + sx * block_size; dst_ptr += dy * dst_pitch + dx * block_size; for (y = 0; y < height; y++) { memcpy(dst_ptr, src_ptr, width * block_size); src_ptr += src_pitch; dst_ptr += dst_pitch; } } void _al_convert_bitmap_data( const void *src, int src_format, int src_pitch, void *dst, int dst_format, int dst_pitch, int sx, int sy, int dx, int dy, int width, int height) { ASSERT(src); ASSERT(dst); ASSERT(_al_pixel_format_is_real(dst_format)); /* Use memcpy if no conversion is needed. */ if (src_format == dst_format) { _al_copy_bitmap_data(src, src_pitch, dst, dst_pitch, sx, sy, dx, dy, width, height, src_format); return; } /* Video-only formats don't have conversion functions, so they should have * been taken care of before reaching this location. */ ASSERT(!_al_pixel_format_is_video_only(src_format)); ASSERT(!_al_pixel_format_is_video_only(dst_format)); (_al_convert_funcs[src_format][dst_format])(src, src_pitch, dst, dst_pitch, sx, sy, dx, dy, width, height); } /* Function: al_clone_bitmap */ ALLEGRO_BITMAP *al_clone_bitmap(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP *clone; ASSERT(bitmap); clone = al_create_bitmap(bitmap->w, bitmap->h); if (!clone) return NULL; if (!transfer_bitmap_data(bitmap, clone)) { al_destroy_bitmap(clone); return NULL; } return clone; } /* Function: al_backup_dirty_bitmap */ void al_backup_dirty_bitmap(ALLEGRO_BITMAP *bitmap) { if (bitmap->vt && bitmap->vt->backup_dirty_bitmap) bitmap->vt->backup_dirty_bitmap(bitmap); } void _al_get_bitmap_wrap(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_WRAP *wrap_u, ALLEGRO_BITMAP_WRAP *wrap_v) { ASSERT(bitmap); ASSERT(wrap_u); ASSERT(wrap_v); if (bitmap->parent) { bitmap = bitmap->parent; } *wrap_u = bitmap->_wrap_u; *wrap_v = bitmap->_wrap_v; } /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/src/bitmap_draw.c000066400000000000000000000161251473414355200167110ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Bitmap drawing routines. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_memblit.h" #include "allegro5/internal/aintern_pixels.h" static ALLEGRO_COLOR solid_white = {1, 1, 1, 1}; static void _bitmap_drawer(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, int flags) { ALLEGRO_BITMAP *dest = al_get_target_bitmap(); ALLEGRO_DISPLAY *display = _al_get_bitmap_display(dest); ASSERT(bitmap->parent == NULL); ASSERT(!(flags & (ALLEGRO_FLIP_HORIZONTAL | ALLEGRO_FLIP_VERTICAL))); ASSERT(bitmap != dest && bitmap != dest->parent); /* If destination is memory, do a memory blit */ if (al_get_bitmap_flags(dest) & ALLEGRO_MEMORY_BITMAP || _al_pixel_format_is_compressed(al_get_bitmap_format(dest))) { _al_draw_bitmap_region_memory(bitmap, tint, sx, sy, sw, sh, 0, 0, flags); } else { /* if source is memory or incompatible */ if ((al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP) || (!al_is_compatible_bitmap(bitmap))) { if (display && display->vt->draw_memory_bitmap_region) { display->vt->draw_memory_bitmap_region(display, bitmap, sx, sy, sw, sh, flags); } else { _al_draw_bitmap_region_memory(bitmap, tint, sx, sy, sw, sh, 0, 0, flags); } } else { /* Compatible display bitmap, use full acceleration */ bitmap->vt->draw_bitmap_region(bitmap, tint, sx, sy, sw, sh, flags); } } } static void _draw_tinted_rotated_scaled_bitmap_region(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float cx, float cy, float angle, float xscale, float yscale, float sx, float sy, float sw, float sh, float dx, float dy, int flags) { ALLEGRO_TRANSFORM backup; ALLEGRO_TRANSFORM t; ALLEGRO_BITMAP *parent = bitmap; float const orig_sw = sw; float const orig_sh = sh; ASSERT(bitmap); al_copy_transform(&backup, al_get_current_transform()); al_identity_transform(&t); if (bitmap->parent) { parent = bitmap->parent; sx += bitmap->xofs; sy += bitmap->yofs; } if (sx < 0) { sw += sx; al_translate_transform(&t, -sx, 0); sx = 0; } if (sy < 0) { sh += sy; al_translate_transform(&t, 0, -sy); sy = 0; } if (sx + sw > parent->w) sw = parent->w - sx; if (sy + sh > parent->h) sh = parent->h - sy; if (flags & ALLEGRO_FLIP_HORIZONTAL) { al_scale_transform(&t, -1, 1); al_translate_transform(&t, orig_sw, 0); flags &= ~ALLEGRO_FLIP_HORIZONTAL; } if (flags & ALLEGRO_FLIP_VERTICAL) { al_scale_transform(&t, 1, -1); al_translate_transform(&t, 0, orig_sh); flags &= ~ALLEGRO_FLIP_VERTICAL; } al_translate_transform(&t, -cx, -cy); al_scale_transform(&t, xscale, yscale); al_rotate_transform(&t, angle); al_translate_transform(&t, dx, dy); al_compose_transform(&t, &backup); al_use_transform(&t); _bitmap_drawer(parent, tint, sx, sy, sw, sh, flags); al_use_transform(&backup); } /* Function: al_draw_tinted_bitmap_region */ void al_draw_tinted_bitmap_region(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, float dx, float dy, int flags) { _draw_tinted_rotated_scaled_bitmap_region(bitmap, tint, 0, 0, 0, 1, 1, sx, sy, sw, sh, dx, dy, flags); } /* Function: al_draw_tinted_bitmap */ void al_draw_tinted_bitmap(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float dx, float dy, int flags) { ASSERT(bitmap); al_draw_tinted_bitmap_region(bitmap, tint, 0, 0, bitmap->w, bitmap->h, dx, dy, flags); } /* Function: al_draw_bitmap */ void al_draw_bitmap(ALLEGRO_BITMAP *bitmap, float dx, float dy, int flags) { al_draw_tinted_bitmap(bitmap, solid_white, dx, dy, flags); } /* Function: al_draw_bitmap_region */ void al_draw_bitmap_region(ALLEGRO_BITMAP *bitmap, float sx, float sy, float sw, float sh, float dx, float dy, int flags) { al_draw_tinted_bitmap_region(bitmap, solid_white, sx, sy, sw, sh, dx, dy, flags); } /* Function: al_draw_tinted_scaled_bitmap */ void al_draw_tinted_scaled_bitmap(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, int flags) { _draw_tinted_rotated_scaled_bitmap_region(bitmap, tint, 0, 0, 0, dw / sw, dh / sh, sx, sy, sw, sh, dx, dy, flags); } /* Function: al_draw_scaled_bitmap */ void al_draw_scaled_bitmap(ALLEGRO_BITMAP *bitmap, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, int flags) { al_draw_tinted_scaled_bitmap(bitmap, solid_white, sx, sy, sw, sh, dx, dy, dw, dh, flags); } /* Function: al_draw_tinted_rotated_bitmap * * angle is specified in radians and moves clockwise * on the screen. */ void al_draw_tinted_rotated_bitmap(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float cx, float cy, float dx, float dy, float angle, int flags) { al_draw_tinted_scaled_rotated_bitmap(bitmap, tint, cx, cy, dx, dy, 1, 1, angle, flags); } /* Function: al_draw_rotated_bitmap */ void al_draw_rotated_bitmap(ALLEGRO_BITMAP *bitmap, float cx, float cy, float dx, float dy, float angle, int flags) { al_draw_tinted_rotated_bitmap(bitmap, solid_white, cx, cy, dx, dy, angle, flags); } /* Function: al_draw_tinted_scaled_rotated_bitmap */ void al_draw_tinted_scaled_rotated_bitmap(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float cx, float cy, float dx, float dy, float xscale, float yscale, float angle, int flags) { _draw_tinted_rotated_scaled_bitmap_region(bitmap, tint, cx, cy, angle, xscale, yscale, 0, 0, bitmap->w, bitmap->h, dx, dy, flags); } /* Function: al_draw_tinted_scaled_rotated_bitmap_region */ void al_draw_tinted_scaled_rotated_bitmap_region(ALLEGRO_BITMAP *bitmap, float sx, float sy, float sw, float sh, ALLEGRO_COLOR tint, float cx, float cy, float dx, float dy, float xscale, float yscale, float angle, int flags) { _draw_tinted_rotated_scaled_bitmap_region(bitmap, tint, cx, cy, angle, xscale, yscale, sx, sy, sw, sh, dx, dy, flags); } /* Function: al_draw_scaled_rotated_bitmap */ void al_draw_scaled_rotated_bitmap(ALLEGRO_BITMAP *bitmap, float cx, float cy, float dx, float dy, float xscale, float yscale, float angle, int flags) { al_draw_tinted_scaled_rotated_bitmap(bitmap, solid_white, cx, cy, dx, dy, xscale, yscale, angle, flags); } /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/src/bitmap_io.c000066400000000000000000000155551473414355200163710ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Bitmap I/O framework. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_vector.h" #include ALLEGRO_DEBUG_CHANNEL("bitmap") #define MAX_EXTENSION (32) typedef struct Handler { char extension[MAX_EXTENSION]; ALLEGRO_IIO_LOADER_FUNCTION loader; ALLEGRO_IIO_SAVER_FUNCTION saver; ALLEGRO_IIO_FS_LOADER_FUNCTION fs_loader; ALLEGRO_IIO_FS_SAVER_FUNCTION fs_saver; ALLEGRO_IIO_IDENTIFIER_FUNCTION identifier; } Handler; /* globals */ static _AL_VECTOR iio_table = _AL_VECTOR_INITIALIZER(Handler); static Handler *add_iio_table_f(const char *ext) { Handler *ent; ent = _al_vector_alloc_back(&iio_table); strcpy(ent->extension, ext); ent->loader = NULL; ent->saver = NULL; ent->fs_loader = NULL; ent->fs_saver = NULL; ent->identifier = NULL; return ent; } static Handler *find_handler(const char *extension, bool create_if_not) { unsigned i; ASSERT(extension); if (strlen(extension) + 1 >= MAX_EXTENSION) { return NULL; } for (i = 0; i < _al_vector_size(&iio_table); i++) { Handler *l = _al_vector_ref(&iio_table, i); if (0 == _al_stricmp(extension, l->extension)) { return l; } } if (create_if_not) return add_iio_table_f(extension); return NULL; } static Handler *find_handler_for_file(ALLEGRO_FILE *f) { unsigned i; ASSERT(f); for (i = 0; i < _al_vector_size(&iio_table); i++) { Handler *l = _al_vector_ref(&iio_table, i); if (l->identifier) { int64_t pos = al_ftell(f); bool identified = l->identifier(f); al_fseek(f, pos, ALLEGRO_SEEK_SET); if (identified) return l; } } return NULL; } static void free_iio_table(void) { _al_vector_free(&iio_table); } void _al_init_iio_table(void) { _al_add_exit_func(free_iio_table, "free_iio_table"); } #define REGISTER(function) \ Handler *ent = find_handler(extension, function != NULL); \ if (!function) { \ if (!ent || !ent->function) { \ return false; /* Nothing to remove. */ \ } \ } \ ent->function = function; \ return true; /* Function: al_register_bitmap_loader */ bool al_register_bitmap_loader(const char *extension, ALLEGRO_BITMAP *(*loader)(const char *filename, int flags)) { REGISTER(loader) } /* Function: al_register_bitmap_saver */ bool al_register_bitmap_saver(const char *extension, bool (*saver)(const char *filename, ALLEGRO_BITMAP *bmp)) { REGISTER(saver) } /* Function: al_register_bitmap_loader_f */ bool al_register_bitmap_loader_f(const char *extension, ALLEGRO_BITMAP *(*fs_loader)(ALLEGRO_FILE *fp, int flags)) { REGISTER(fs_loader) } /* Function: al_register_bitmap_saver_f */ bool al_register_bitmap_saver_f(const char *extension, bool (*fs_saver)(ALLEGRO_FILE *fp, ALLEGRO_BITMAP *bmp)) { REGISTER(fs_saver) } /* Function: al_register_bitmap_identifier */ bool al_register_bitmap_identifier(const char *extension, bool (*identifier)(ALLEGRO_FILE *f)) { REGISTER(identifier) } /* Function: al_load_bitmap */ ALLEGRO_BITMAP *al_load_bitmap(const char *filename) { int flags = 0; /* For backwards compatibility with the 5.0 branch. */ if (al_get_new_bitmap_flags() & ALLEGRO_NO_PREMULTIPLIED_ALPHA) { flags |= ALLEGRO_NO_PREMULTIPLIED_ALPHA; ALLEGRO_WARN("ALLEGRO_NO_PREMULTIPLIED_ALPHA in new_bitmap_flags " "is deprecated\n"); } return al_load_bitmap_flags(filename, flags); } /* Function: al_load_bitmap_flags */ ALLEGRO_BITMAP *al_load_bitmap_flags(const char *filename, int flags) { const char *ext; Handler *h; ALLEGRO_BITMAP *ret; ext = al_identify_bitmap(filename); if (!ext) { ext = strrchr(filename, '.'); if (!ext) { ALLEGRO_ERROR("Could not identify bitmap %s!\n", filename); return NULL; } } h = find_handler(ext, false); if (h && h->loader) { ret = h->loader(filename, flags); if (!ret) ALLEGRO_ERROR("Failed loading bitmap %s with %s handler.\n", filename, ext); } else { ALLEGRO_ERROR("No handler for bitmap %s!\n", filename); ret = NULL; } return ret; } /* Function: al_save_bitmap */ bool al_save_bitmap(const char *filename, ALLEGRO_BITMAP *bitmap) { const char *ext; Handler *h; ext = strrchr(filename, '.'); if (!ext) { ALLEGRO_ERROR("Unable to determine file format from %s\n", filename); return false; } h = find_handler(ext, false); if (h && h->saver) return h->saver(filename, bitmap); else { ALLEGRO_ERROR("No handler for image %s found\n", filename); return false; } } /* Function: al_load_bitmap_f */ ALLEGRO_BITMAP *al_load_bitmap_f(ALLEGRO_FILE *fp, const char *ident) { int flags = 0; /* For backwards compatibility with the 5.0 branch. */ if (al_get_new_bitmap_flags() & ALLEGRO_NO_PREMULTIPLIED_ALPHA) { flags |= ALLEGRO_NO_PREMULTIPLIED_ALPHA; ALLEGRO_WARN("ALLEGRO_NO_PREMULTIPLIED_ALPHA in new_bitmap_flags " "is deprecated\n"); } return al_load_bitmap_flags_f(fp, ident, flags); } /* Function: al_load_bitmap_flags_f */ ALLEGRO_BITMAP *al_load_bitmap_flags_f(ALLEGRO_FILE *fp, const char *ident, int flags) { Handler *h; if (ident) h = find_handler(ident, false); else h = find_handler_for_file(fp); if (h && h->fs_loader) return h->fs_loader(fp, flags); else return NULL; } /* Function: al_save_bitmap_f */ bool al_save_bitmap_f(ALLEGRO_FILE *fp, const char *ident, ALLEGRO_BITMAP *bitmap) { Handler *h = find_handler(ident, false); if (h && h->fs_saver) return h->fs_saver(fp, bitmap); else { ALLEGRO_ERROR("No handler for image %s found\n", ident); return false; } } /* Function: al_identify_bitmap_f */ char const *al_identify_bitmap_f(ALLEGRO_FILE *fp) { Handler *h = find_handler_for_file(fp); if (!h) return NULL; return h->extension; } /* Function: al_identify_bitmap */ char const *al_identify_bitmap(char const *filename) { char const *ext; ALLEGRO_FILE *fp = al_fopen(filename, "rb"); if (!fp) return NULL; ext = al_identify_bitmap_f(fp); al_fclose(fp); return ext; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/bitmap_lock.c000066400000000000000000000175251473414355200167110ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Bitmap locking routines. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_pixels.h" /* Function: al_lock_bitmap_region */ ALLEGRO_LOCKED_REGION *al_lock_bitmap_region(ALLEGRO_BITMAP *bitmap, int x, int y, int width, int height, int format, int flags) { ALLEGRO_LOCKED_REGION *lr; int bitmap_format = al_get_bitmap_format(bitmap); int bitmap_flags = al_get_bitmap_flags(bitmap); int block_width = al_get_pixel_block_width(bitmap_format); int block_height = al_get_pixel_block_height(bitmap_format); int xc, yc, wc, hc; ASSERT(x >= 0); ASSERT(y >= 0); ASSERT(width >= 0); ASSERT(height >= 0); ASSERT(!_al_pixel_format_is_video_only(format)); if (_al_pixel_format_is_real(format)) { ASSERT(al_get_pixel_block_width(format) == 1); ASSERT(al_get_pixel_block_height(format) == 1); } /* For sub-bitmaps */ if (bitmap->parent) { x += bitmap->xofs; y += bitmap->yofs; bitmap = bitmap->parent; } if (bitmap->locked) return NULL; if (!(bitmap_flags & ALLEGRO_MEMORY_BITMAP) && !(flags & ALLEGRO_LOCK_READONLY)) bitmap->dirty = true; ASSERT(x+width <= bitmap->w); ASSERT(y+height <= bitmap->h); xc = (x / block_width) * block_width; yc = (y / block_height) * block_height; wc = _al_get_least_multiple(x + width, block_width) - xc; hc = _al_get_least_multiple(y + height, block_height) - yc; bitmap->lock_x = xc; bitmap->lock_y = yc; bitmap->lock_w = wc; bitmap->lock_h = hc; bitmap->lock_flags = flags; if (flags == ALLEGRO_LOCK_WRITEONLY && (xc != x || yc != y || wc != width || hc != height)) { /* Unaligned write-only access requires that we fill in the padding * from the texture. * XXX: In principle, this could be done more efficiently. */ flags = ALLEGRO_LOCK_READWRITE; } if (bitmap_flags & ALLEGRO_MEMORY_BITMAP) { int f = _al_get_real_pixel_format(al_get_current_display(), format); if (f < 0) { return NULL; } ASSERT(bitmap->memory); if (format == ALLEGRO_PIXEL_FORMAT_ANY || bitmap_format == format || bitmap_format == f) { bitmap->locked_region.data = bitmap->memory + bitmap->pitch * yc + xc * al_get_pixel_size(bitmap_format); bitmap->locked_region.format = bitmap_format; bitmap->locked_region.pitch = bitmap->pitch; bitmap->locked_region.pixel_size = al_get_pixel_size(bitmap_format); } else { bitmap->locked_region.pitch = al_get_pixel_size(f) * wc; bitmap->locked_region.data = al_malloc(bitmap->locked_region.pitch*hc); bitmap->locked_region.format = f; bitmap->locked_region.pixel_size = al_get_pixel_size(f); if (!(bitmap->lock_flags & ALLEGRO_LOCK_WRITEONLY)) { _al_convert_bitmap_data( bitmap->memory, bitmap_format, bitmap->pitch, bitmap->locked_region.data, f, bitmap->locked_region.pitch, xc, yc, 0, 0, wc, hc); } } lr = &bitmap->locked_region; } else { lr = bitmap->vt->lock_region(bitmap, xc, yc, wc, hc, format, flags); if (!lr) { return NULL; } } bitmap->lock_data = lr->data; /* Fixup the data pointer for unaligned access */ lr->data = (char*)lr->data + (x - xc) * lr->pixel_size + (y - yc) * lr->pitch; bitmap->locked = true; return lr; } /* Function: al_lock_bitmap */ ALLEGRO_LOCKED_REGION *al_lock_bitmap(ALLEGRO_BITMAP *bitmap, int format, int flags) { return al_lock_bitmap_region(bitmap, 0, 0, bitmap->w, bitmap->h, format, flags); } /* Function: al_unlock_bitmap */ void al_unlock_bitmap(ALLEGRO_BITMAP *bitmap) { int bitmap_format = al_get_bitmap_format(bitmap); /* For sub-bitmaps */ if (bitmap->parent) { bitmap = bitmap->parent; } if (!(al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP)) { if (_al_pixel_format_is_compressed(bitmap->locked_region.format)) bitmap->vt->unlock_compressed_region(bitmap); else bitmap->vt->unlock_region(bitmap); } else { if (bitmap->locked_region.format != 0 && bitmap->locked_region.format != bitmap_format) { if (!(bitmap->lock_flags & ALLEGRO_LOCK_READONLY)) { _al_convert_bitmap_data( bitmap->locked_region.data, bitmap->locked_region.format, bitmap->locked_region.pitch, bitmap->memory, bitmap_format, bitmap->pitch, 0, 0, bitmap->lock_x, bitmap->lock_y, bitmap->lock_w, bitmap->lock_h); } al_free(bitmap->locked_region.data); } } bitmap->locked = false; } /* Function: al_is_bitmap_locked */ bool al_is_bitmap_locked(ALLEGRO_BITMAP *bitmap) { return bitmap->locked; } /* Function: al_lock_bitmap_blocked */ ALLEGRO_LOCKED_REGION *al_lock_bitmap_blocked(ALLEGRO_BITMAP *bitmap, int flags) { int bitmap_format = al_get_bitmap_format(bitmap); int block_width = al_get_pixel_block_width(bitmap_format); int block_height = al_get_pixel_block_height(bitmap_format); return al_lock_bitmap_region_blocked(bitmap, 0, 0, _al_get_least_multiple(bitmap->w, block_width) / block_width, _al_get_least_multiple(bitmap->h, block_height) / block_height, flags); } /* Function: al_lock_bitmap_region_blocked */ ALLEGRO_LOCKED_REGION *al_lock_bitmap_region_blocked(ALLEGRO_BITMAP *bitmap, int x_block, int y_block, int width_block, int height_block, int flags) { ALLEGRO_LOCKED_REGION *lr; int bitmap_format = al_get_bitmap_format(bitmap); int bitmap_flags = al_get_bitmap_flags(bitmap); int block_width = al_get_pixel_block_width(bitmap_format); int block_height = al_get_pixel_block_height(bitmap_format); ASSERT(x_block >= 0); ASSERT(y_block >= 0); ASSERT(width_block >= 0); ASSERT(height_block >= 0); if (block_width == 1 && block_height == 1 && !_al_pixel_format_is_video_only(bitmap_format)) { return al_lock_bitmap_region(bitmap, x_block, y_block, width_block, height_block, bitmap_format, flags); } /* Currently, this is the only format that gets to this point */ ASSERT(_al_pixel_format_is_compressed(bitmap_format)); ASSERT(!(bitmap_flags & ALLEGRO_MEMORY_BITMAP)); /* For sub-bitmaps */ if (bitmap->parent) { if (bitmap->xofs % block_width != 0 || bitmap->yofs % block_height != 0) { return NULL; } x_block += bitmap->xofs / block_width; y_block += bitmap->yofs / block_height; bitmap = bitmap->parent; } if (bitmap->locked) return NULL; if (!(flags & ALLEGRO_LOCK_READONLY)) bitmap->dirty = true; ASSERT(x_block + width_block <= _al_get_least_multiple(bitmap->w, block_width) / block_width); ASSERT(y_block + height_block <= _al_get_least_multiple(bitmap->h, block_height) / block_height); bitmap->lock_x = x_block * block_width; bitmap->lock_y = y_block * block_height; bitmap->lock_w = width_block * block_width; bitmap->lock_h = height_block * block_height; bitmap->lock_flags = flags; lr = bitmap->vt->lock_compressed_region(bitmap, bitmap->lock_x, bitmap->lock_y, bitmap->lock_w, bitmap->lock_h, flags); if (!lr) { return NULL; } bitmap->locked = true; return lr; } /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/src/bitmap_pixel.c000066400000000000000000000076001473414355200170730ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Bitmap pixel manipulation. * * See LICENSE.txt for copyright information. */ #include /* for memset */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_blend.h" #include "allegro5/internal/aintern_pixels.h" ALLEGRO_DEBUG_CHANNEL("bitmap") /* Function: al_get_pixel */ ALLEGRO_COLOR al_get_pixel(ALLEGRO_BITMAP *bitmap, int x, int y) { ALLEGRO_LOCKED_REGION *lr; char *data; ALLEGRO_COLOR color = al_map_rgba_f(0, 0, 0, 0); if (bitmap->parent) { x += bitmap->xofs; y += bitmap->yofs; bitmap = bitmap->parent; } if (bitmap->locked) { if (_al_pixel_format_is_video_only(bitmap->locked_region.format)) { ALLEGRO_ERROR("Invalid lock format."); return color; } x -= bitmap->lock_x; y -= bitmap->lock_y; if (x < 0 || y < 0 || x >= bitmap->lock_w || y >= bitmap->lock_h) { ALLEGRO_ERROR("Out of bounds."); return color; } data = bitmap->locked_region.data; data += y * bitmap->locked_region.pitch; data += x * al_get_pixel_size(bitmap->locked_region.format); _AL_INLINE_GET_PIXEL(bitmap->locked_region.format, data, color, false); } else { /* FIXME: must use clip not full bitmap */ if (x < 0 || y < 0 || x >= bitmap->w || y >= bitmap->h) { return color; } if (!(lr = al_lock_bitmap_region(bitmap, x, y, 1, 1, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY))) { return color; } /* FIXME: check for valid pixel format */ data = bitmap->lock_data; _AL_INLINE_GET_PIXEL(lr->format, data, color, false); al_unlock_bitmap(bitmap); } return color; } void _al_put_pixel(ALLEGRO_BITMAP *bitmap, int x, int y, ALLEGRO_COLOR color) { ALLEGRO_LOCKED_REGION *lr; char *data; if (bitmap->parent) { x += bitmap->xofs; y += bitmap->yofs; bitmap = bitmap->parent; } if (x < bitmap->cl || y < bitmap->ct || x >= bitmap->cr_excl || y >= bitmap->cb_excl) { return; } if (bitmap->locked) { if (_al_pixel_format_is_video_only(bitmap->locked_region.format)) { ALLEGRO_ERROR("Invalid lock format."); return; } x -= bitmap->lock_x; y -= bitmap->lock_y; if (x < 0 || y < 0 || x >= bitmap->lock_w || y >= bitmap->lock_h) { return; } data = bitmap->locked_region.data; data += y * bitmap->locked_region.pitch; data += x * al_get_pixel_size(bitmap->locked_region.format); _AL_INLINE_PUT_PIXEL(bitmap->locked_region.format, data, color, false); } else { lr = al_lock_bitmap_region(bitmap, x, y, 1, 1, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); if (!lr) return; /* FIXME: check for valid pixel format */ data = bitmap->lock_data; _AL_INLINE_PUT_PIXEL(lr->format, data, color, false); al_unlock_bitmap(bitmap); } } /* Function: al_put_pixel */ void al_put_pixel(int x, int y, ALLEGRO_COLOR color) { _al_put_pixel(al_get_target_bitmap(), x, y, color); } /* Function: al_put_blended_pixel */ void al_put_blended_pixel(int x, int y, ALLEGRO_COLOR color) { ALLEGRO_COLOR result; ALLEGRO_BITMAP* bitmap = al_get_target_bitmap(); _al_blend_memory(&color, bitmap, x, y, &result); _al_put_pixel(bitmap, x, y, result); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/bitmap_type.c000066400000000000000000000232701473414355200167340ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Convert between memory and video bitmap types. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_shader.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_vector.h" ALLEGRO_DEBUG_CHANNEL("bitmap") /* Global list of MEMORY bitmaps with ALLEGRO_CONVERT_BITMAP flag. */ struct BITMAP_CONVERSION_LIST { ALLEGRO_MUTEX *mutex; _AL_VECTOR bitmaps; }; static struct BITMAP_CONVERSION_LIST convert_bitmap_list; static void cleanup_convert_bitmap_list(void) { _al_vector_free(&convert_bitmap_list.bitmaps); al_destroy_mutex(convert_bitmap_list.mutex); } /* This is called in al_install_system. Exit functions are called in * al_uninstall_system. */ void _al_init_convert_bitmap_list(void) { convert_bitmap_list.mutex = al_create_mutex_recursive(); _al_vector_init(&convert_bitmap_list.bitmaps, sizeof(ALLEGRO_BITMAP *)); _al_add_exit_func(cleanup_convert_bitmap_list, "cleanup_convert_bitmap_list"); } void _al_register_convert_bitmap(ALLEGRO_BITMAP *bitmap) { int bitmap_flags = al_get_bitmap_flags(bitmap); if (!(bitmap_flags & ALLEGRO_MEMORY_BITMAP)) return; if (bitmap_flags & ALLEGRO_CONVERT_BITMAP) { ALLEGRO_BITMAP **back; al_lock_mutex(convert_bitmap_list.mutex); back = _al_vector_alloc_back(&convert_bitmap_list.bitmaps); *back = bitmap; al_unlock_mutex(convert_bitmap_list.mutex); } } void _al_unregister_convert_bitmap(ALLEGRO_BITMAP *bitmap) { int bitmap_flags = al_get_bitmap_flags(bitmap); if (!(bitmap_flags & ALLEGRO_MEMORY_BITMAP)) return; if (bitmap_flags & ALLEGRO_CONVERT_BITMAP) { al_lock_mutex(convert_bitmap_list.mutex); _al_vector_find_and_delete(&convert_bitmap_list.bitmaps, &bitmap); al_unlock_mutex(convert_bitmap_list.mutex); } } static void swap_bitmaps(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP *other) { ALLEGRO_BITMAP temp; _AL_LIST_ITEM *bitmap_dtor_item = bitmap->dtor_item; _AL_LIST_ITEM *other_dtor_item = other->dtor_item; ALLEGRO_DISPLAY *bitmap_display, *other_display; _al_unregister_convert_bitmap(bitmap); _al_unregister_convert_bitmap(other); if (other->shader) _al_unregister_shader_bitmap(other->shader, other); if (bitmap->shader) _al_unregister_shader_bitmap(bitmap->shader, bitmap); temp = *bitmap; *bitmap = *other; *other = temp; /* Re-associate the destructors back, as they are tied to the object * pointers. */ bitmap->dtor_item = bitmap_dtor_item; other->dtor_item = other_dtor_item; bitmap_display = _al_get_bitmap_display(bitmap); other_display = _al_get_bitmap_display(other); /* We are basically done already. Except we now have to update everything * possibly referencing any of the two bitmaps. */ if (bitmap_display && !other_display) { /* This means before the swap, other was the display bitmap, and we * now should replace it with the swapped pointer. */ ALLEGRO_BITMAP **back; int pos = _al_vector_find(&bitmap_display->bitmaps, &other); ASSERT(pos >= 0); back = _al_vector_ref(&bitmap_display->bitmaps, pos); *back = bitmap; } if (other_display && !bitmap_display) { ALLEGRO_BITMAP **back; int pos = _al_vector_find(&other_display->bitmaps, &bitmap); ASSERT(pos >= 0); back = _al_vector_ref(&other_display->bitmaps, pos); *back = other; } if (other->shader) _al_register_shader_bitmap(other->shader, other); if (bitmap->shader) _al_register_shader_bitmap(bitmap->shader, bitmap); _al_register_convert_bitmap(bitmap); _al_register_convert_bitmap(other); if (bitmap->vt && bitmap->vt->bitmap_pointer_changed) bitmap->vt->bitmap_pointer_changed(bitmap, other); if (other->vt && other->vt->bitmap_pointer_changed) other->vt->bitmap_pointer_changed(other, bitmap); } /* Function: al_convert_bitmap */ void al_convert_bitmap(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP *clone; int bitmap_flags = al_get_bitmap_flags(bitmap); int new_bitmap_flags = al_get_new_bitmap_flags(); bool want_memory = (new_bitmap_flags & ALLEGRO_MEMORY_BITMAP) != 0; bool clone_memory; ALLEGRO_BITMAP *target_bitmap; bitmap_flags &= ~_ALLEGRO_INTERNAL_OPENGL; /* If a cloned bitmap would be identical, we can just do nothing. */ if (al_get_bitmap_format(bitmap) == al_get_new_bitmap_format() && bitmap_flags == new_bitmap_flags && _al_get_bitmap_display(bitmap) == al_get_current_display()) { return; } if (bitmap->parent) { al_convert_bitmap(bitmap->parent); return; } else { clone = al_clone_bitmap(bitmap); } if (!clone) { return; } clone_memory = (al_get_bitmap_flags(clone) & ALLEGRO_MEMORY_BITMAP) != 0; if (clone_memory != want_memory) { /* We couldn't convert. */ al_destroy_bitmap(clone); return; } swap_bitmaps(bitmap, clone); /* Preserve bitmap state. */ bitmap->cl = clone->cl; bitmap->ct = clone->ct; bitmap->cr_excl = clone->cr_excl; bitmap->cb_excl = clone->cb_excl; bitmap->transform = clone->transform; bitmap->inverse_transform = clone->inverse_transform; bitmap->inverse_transform_dirty = clone->inverse_transform_dirty; /* Memory bitmaps do not support custom projection transforms, * so reset it to the orthographic transform. */ if (new_bitmap_flags & ALLEGRO_MEMORY_BITMAP) { al_identity_transform(&bitmap->proj_transform); al_orthographic_transform(&bitmap->proj_transform, 0, 0, -1.0, bitmap->w, bitmap->h, 1.0); } else { bitmap->proj_transform = clone->proj_transform; } /* If we just converted this bitmap, and the backing bitmap is the same * as the target's backing bitmap, then the viewports and transformations * will be messed up. Detect this, and just re-call al_set_target_bitmap * on the current target. */ target_bitmap = al_get_target_bitmap(); if (target_bitmap) { ALLEGRO_BITMAP *target_parent = target_bitmap->parent ? target_bitmap->parent : target_bitmap; if (bitmap == target_parent || bitmap->parent == target_parent) { al_set_target_bitmap(target_bitmap); } } al_destroy_bitmap(clone); } /* Function: al_convert_memory_bitmaps */ void al_convert_memory_bitmaps(void) { ALLEGRO_STATE backup; ALLEGRO_DISPLAY *display = al_get_current_display(); _AL_VECTOR copy; size_t i; if (!display) return; al_store_state(&backup, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS); al_lock_mutex(convert_bitmap_list.mutex); _al_vector_init(©, sizeof(ALLEGRO_BITMAP *)); for (i = 0; i < _al_vector_size(&convert_bitmap_list.bitmaps); i++) { ALLEGRO_BITMAP **bptr, **bptr2; bptr = _al_vector_ref(&convert_bitmap_list.bitmaps, i); bptr2 = _al_vector_alloc_back(©); *bptr2 = *bptr; } _al_vector_free(&convert_bitmap_list.bitmaps); _al_vector_init(&convert_bitmap_list.bitmaps, sizeof(ALLEGRO_BITMAP *)); for (i = 0; i < _al_vector_size(©); i++) { ALLEGRO_BITMAP **bptr; int flags; bptr = _al_vector_ref(©, i); flags = al_get_bitmap_flags(*bptr); flags &= ~ALLEGRO_MEMORY_BITMAP; al_set_new_bitmap_flags(flags); al_set_new_bitmap_format(al_get_bitmap_format(*bptr)); ALLEGRO_DEBUG("converting memory bitmap %p to display bitmap\n", *bptr); al_convert_bitmap(*bptr); } _al_vector_free(©); al_unlock_mutex(convert_bitmap_list.mutex); al_restore_state(&backup); } /* Converts a memory bitmap to a display bitmap preserving its contents. * The created bitmap belongs to the current display. * * If this is called for a sub-bitmap, the parent also is converted. */ void _al_convert_to_display_bitmap(ALLEGRO_BITMAP *bitmap) { ALLEGRO_STATE backup; int bitmap_flags = al_get_bitmap_flags(bitmap); /* Do nothing if it is a display bitmap already. */ if (!(bitmap_flags & ALLEGRO_MEMORY_BITMAP)) return; ALLEGRO_DEBUG("converting memory bitmap %p to display bitmap\n", bitmap); al_store_state(&backup, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS); al_set_new_bitmap_flags(bitmap_flags & ~ALLEGRO_MEMORY_BITMAP); al_set_new_bitmap_format(al_get_bitmap_format(bitmap)); al_convert_bitmap(bitmap); al_restore_state(&backup); } /* Converts a display bitmap to a memory bitmap preserving its contents. * If this is called for a sub-bitmap, the parent also is converted. */ void _al_convert_to_memory_bitmap(ALLEGRO_BITMAP *bitmap) { ALLEGRO_STATE backup; int bitmap_flags = al_get_bitmap_flags(bitmap); /* Do nothing if it is a memory bitmap already. */ if (bitmap_flags & ALLEGRO_MEMORY_BITMAP) return; ALLEGRO_DEBUG("converting display bitmap %p to memory bitmap\n", bitmap); al_store_state(&backup, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS); al_set_new_bitmap_flags((bitmap_flags & ~ALLEGRO_VIDEO_BITMAP) | ALLEGRO_MEMORY_BITMAP); al_set_new_bitmap_format(al_get_bitmap_format(bitmap)); al_convert_bitmap(bitmap); al_restore_state(&backup); } /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/src/blenders.c000066400000000000000000000027741473414355200162230ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Memory bitmap blending routines * * by Trent Gamblin. * */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_blend.h" #include "allegro5/internal/aintern_display.h" #include void _al_blend_memory(ALLEGRO_COLOR *scol, ALLEGRO_BITMAP *dest, int dx, int dy, ALLEGRO_COLOR *result) { ALLEGRO_COLOR dcol; ALLEGRO_COLOR constcol; int op, src_blend, dest_blend, alpha_op, alpha_src_blend, alpha_dest_blend; dcol = al_get_pixel(dest, dx, dy); al_get_separate_bitmap_blender(&op, &src_blend, &dest_blend, &alpha_op, &alpha_src_blend, &alpha_dest_blend); constcol = al_get_blend_color(); _al_blend_inline(scol, &dcol, op, src_blend, dest_blend, alpha_op, alpha_src_blend, alpha_dest_blend, &constcol, result); (void) _al_blend_alpha_inline; // silence compiler } allegro5-5.2.10.1/src/clipboard.c000066400000000000000000000032751473414355200163610ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Clipboard handling. * * By Beoran. * * See readme.txt for copyright information. */ /* Title: Event sources */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_display.h" /* Function: al_get_clipboard_text */ char *al_get_clipboard_text(ALLEGRO_DISPLAY *display) { if (!display) display = al_get_current_display(); if (!display) return NULL; if (!display->vt->get_clipboard_text) return NULL; return display->vt->get_clipboard_text(display); } /* Function: al_set_clipboard_text */ bool al_set_clipboard_text(ALLEGRO_DISPLAY *display, const char *text) { if (!display) display = al_get_current_display(); if (!display) return false; if (!display->vt->set_clipboard_text) return false; return display->vt->set_clipboard_text(display, text); } /* Function: al_clipboard_has_text */ bool al_clipboard_has_text(ALLEGRO_DISPLAY *display) { if (!display) display = al_get_current_display(); if (!display) return false; if (!display->vt->has_clipboard_text) return false; return display->vt->has_clipboard_text(display); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/config.c000066400000000000000000000373041473414355200156670ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Configuration routines. * * By Trent Gamblin. */ /* Title: Configuration routines */ #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_aatree.h" #include "allegro5/internal/aintern_config.h" static int cmp_ustr(void const *a, void const *b) { return al_ustr_compare(a, b); } /* Function: al_create_config */ ALLEGRO_CONFIG *al_create_config(void) { ALLEGRO_CONFIG *config = al_calloc(1, sizeof(ALLEGRO_CONFIG)); ASSERT(config); return config; } static ALLEGRO_CONFIG_SECTION *find_section(const ALLEGRO_CONFIG *config, const ALLEGRO_USTR *section) { return _al_aa_search(config->tree, section, cmp_ustr); } static ALLEGRO_CONFIG_ENTRY *find_entry(const ALLEGRO_CONFIG_SECTION *section, const ALLEGRO_USTR *key) { return _al_aa_search(section->tree, key, cmp_ustr); } static void get_key_and_value(const ALLEGRO_USTR *buf, ALLEGRO_USTR *key, ALLEGRO_USTR *value) { int eq = al_ustr_find_chr(buf, 0, '='); if (eq == -1) { al_ustr_assign(key, buf); al_ustr_assign_cstr(value, ""); } else { al_ustr_assign_substr(key, buf, 0, eq); al_ustr_assign_substr(value, buf, eq + 1, al_ustr_size(buf)); } al_ustr_trim_ws(key); al_ustr_trim_ws(value); } static ALLEGRO_CONFIG_SECTION *config_add_section(ALLEGRO_CONFIG *config, const ALLEGRO_USTR *name) { ALLEGRO_CONFIG_SECTION *sec = config->head; ALLEGRO_CONFIG_SECTION *section; if ((section = find_section(config, name))) return section; section = al_calloc(1, sizeof(ALLEGRO_CONFIG_SECTION)); section->name = al_ustr_dup(name); if (sec == NULL) { config->head = section; config->last = section; } else { ASSERT(config->last->next == NULL); config->last->next = section; section->prev = config->last; config->last = section; } config->tree = _al_aa_insert(config->tree, section->name, section, cmp_ustr); return section; } /* Function: al_add_config_section */ void al_add_config_section(ALLEGRO_CONFIG *config, const char *name) { ALLEGRO_USTR_INFO name_info; const ALLEGRO_USTR *uname; uname = al_ref_cstr(&name_info, name); config_add_section(config, uname); } static void config_set_value(ALLEGRO_CONFIG *config, const ALLEGRO_USTR *section, const ALLEGRO_USTR *key, const ALLEGRO_USTR *value) { ALLEGRO_CONFIG_SECTION *s; ALLEGRO_CONFIG_ENTRY *entry; s = find_section(config, section); if (s) { entry = find_entry(s, key); if (entry) { al_ustr_assign(entry->value, value); al_ustr_trim_ws(entry->value); return; } } entry = al_calloc(1, sizeof(ALLEGRO_CONFIG_ENTRY)); entry->is_comment = false; entry->key = al_ustr_dup(key); entry->value = al_ustr_dup(value); al_ustr_trim_ws(entry->value); if (!s) { s = config_add_section(config, section); } if (s->head == NULL) { s->head = entry; s->last = entry; } else { ASSERT(s->last->next == NULL); s->last->next = entry; entry->prev = s->last; s->last = entry; } s->tree = _al_aa_insert(s->tree, entry->key, entry, cmp_ustr); } /* Function: al_set_config_value */ void al_set_config_value(ALLEGRO_CONFIG *config, const char *section, const char *key, const char *value) { ALLEGRO_USTR_INFO section_info; ALLEGRO_USTR_INFO key_info; ALLEGRO_USTR_INFO value_info; const ALLEGRO_USTR *usection; const ALLEGRO_USTR *ukey; const ALLEGRO_USTR *uvalue; if (section == NULL) { section = ""; } ASSERT(key); ASSERT(value); usection = al_ref_cstr(§ion_info, section); ukey = al_ref_cstr(&key_info, key); uvalue = al_ref_cstr(&value_info, value); config_set_value(config, usection, ukey, uvalue); } static void config_add_comment(ALLEGRO_CONFIG *config, const ALLEGRO_USTR *section, const ALLEGRO_USTR *comment) { ALLEGRO_CONFIG_SECTION *s; ALLEGRO_CONFIG_ENTRY *entry; s = find_section(config, section); entry = al_calloc(1, sizeof(ALLEGRO_CONFIG_ENTRY)); entry->is_comment = true; entry->key = al_ustr_dup(comment); /* Replace all newline characters by spaces, otherwise the written comment * file will be corrupted. */ al_ustr_find_replace_cstr(entry->key, 0, "\n", " "); if (!s) { s = config_add_section(config, section); } if (s->head == NULL) { s->head = entry; s->last = entry; } else { ASSERT(s->last->next == NULL); s->last->next = entry; entry->prev = s->last; s->last = entry; } } /* Function: al_add_config_comment */ void al_add_config_comment(ALLEGRO_CONFIG *config, const char *section, const char *comment) { ALLEGRO_USTR_INFO section_info; ALLEGRO_USTR_INFO comment_info; const ALLEGRO_USTR *usection; const ALLEGRO_USTR *ucomment; if (section == NULL) { section = ""; } ASSERT(comment); usection = al_ref_cstr(§ion_info, section); ucomment = al_ref_cstr(&comment_info, comment); config_add_comment(config, usection, ucomment); } static bool config_get_value(const ALLEGRO_CONFIG *config, const ALLEGRO_USTR *section, const ALLEGRO_USTR *key, const ALLEGRO_USTR **ret_value) { ALLEGRO_CONFIG_SECTION *s; ALLEGRO_CONFIG_ENTRY *e; s = find_section(config, section); if (!s) return false; e = find_entry(s, key); if (!e) return false; *ret_value = e->value; return true; } /* Function: al_get_config_value */ const char *al_get_config_value(const ALLEGRO_CONFIG *config, const char *section, const char *key) { ALLEGRO_USTR_INFO section_info; ALLEGRO_USTR_INFO key_info; const ALLEGRO_USTR *usection; const ALLEGRO_USTR *ukey; const ALLEGRO_USTR *value; if (section == NULL) { section = ""; } usection = al_ref_cstr(§ion_info, section); ukey = al_ref_cstr(&key_info, key); if (config_get_value(config, usection, ukey, &value)) return al_cstr(value); else return NULL; } static bool readline(ALLEGRO_FILE *file, ALLEGRO_USTR *line) { char buf[128]; if (!al_fgets(file, buf, sizeof(buf))) { return false; } do { al_ustr_append_cstr(line, buf); if (al_ustr_has_suffix_cstr(line, "\n")) break; } while (al_fgets(file, buf, sizeof(buf))); return true; } /* Function: al_load_config_file */ ALLEGRO_CONFIG *al_load_config_file(const char *filename) { ALLEGRO_FILE *file; ALLEGRO_CONFIG *cfg = NULL; file = al_fopen(filename, "r"); if (file) { cfg = al_load_config_file_f(file); al_fclose(file); } return cfg; } /* Function: al_load_config_file_f */ ALLEGRO_CONFIG *al_load_config_file_f(ALLEGRO_FILE *file) { ALLEGRO_CONFIG *config; ALLEGRO_CONFIG_SECTION *current_section = NULL; ALLEGRO_USTR *line; ALLEGRO_USTR *section; ALLEGRO_USTR *key; ALLEGRO_USTR *value; ASSERT(file); config = al_create_config(); if (!config) { return NULL; } line = al_ustr_new(""); section = al_ustr_new(""); key = al_ustr_new(""); value = al_ustr_new(""); while (1) { al_ustr_assign_cstr(line, ""); if (!readline(file, line)) break; al_ustr_trim_ws(line); if (al_ustr_has_prefix_cstr(line, "#") || al_ustr_size(line) == 0) { /* Preserve comments and blank lines */ const ALLEGRO_USTR *name; if (current_section) name = current_section->name; else name = al_ustr_empty_string(); config_add_comment(config, name, line); } else if (al_ustr_has_prefix_cstr(line, "[")) { int rbracket = al_ustr_rfind_chr(line, al_ustr_size(line), ']'); if (rbracket == -1) rbracket = al_ustr_size(line); al_ustr_assign_substr(section, line, 1, rbracket); current_section = config_add_section(config, section); } else { get_key_and_value(line, key, value); if (current_section == NULL) config_set_value(config, al_ustr_empty_string(), key, value); else config_set_value(config, current_section->name, key, value); } } al_ustr_free(line); al_ustr_free(section); al_ustr_free(key); al_ustr_free(value); return config; } static bool config_write_section(ALLEGRO_FILE *file, const ALLEGRO_CONFIG_SECTION *s) { ALLEGRO_CONFIG_ENTRY *e; if (al_ustr_size(s->name) > 0) { al_fputc(file, '['); al_fputs(file, al_cstr(s->name)); al_fputs(file, "]\n"); if (al_ferror(file)) { return false; } } e = s->head; while (e != NULL) { if (e->is_comment) { if (al_ustr_size(e->key) > 0) { if (!al_ustr_has_prefix_cstr(e->key, "#")) { al_fputs(file, "# "); } al_fputs(file, al_cstr(e->key)); } al_fputc(file, '\n'); } else { al_fputs(file, al_cstr(e->key)); al_fputc(file, '='); al_fputs(file, al_cstr(e->value)); al_fputc(file, '\n'); } if (al_ferror(file)) { return false; } e = e->next; } return !al_feof(file); } /* Function: al_save_config_file */ bool al_save_config_file(const char *filename, const ALLEGRO_CONFIG *config) { ALLEGRO_FILE *file; file = al_fopen(filename, "w"); if (file) { bool retsave = al_save_config_file_f(file, config); bool retclose = al_fclose(file); return retsave && retclose; } return false; } /* Function: al_save_config_file_f */ bool al_save_config_file_f(ALLEGRO_FILE *file, const ALLEGRO_CONFIG *config) { ALLEGRO_CONFIG_SECTION *s; /* Save global section */ s = config->head; while (s != NULL) { if (al_ustr_size(s->name) == 0) { if (!config_write_section(file, s)) { return false; } break; } s = s->next; } /* Save other sections */ s = config->head; while (s != NULL) { if (al_ustr_size(s->name) > 0) { if (!config_write_section(file, s)) { return false; } } s = s->next; } return !al_feof(file); } /* do_config_merge_into: * Helper function for merging. */ static void do_config_merge_into(ALLEGRO_CONFIG *master, const ALLEGRO_CONFIG *add, bool merge_comments) { ALLEGRO_CONFIG_SECTION *s; ALLEGRO_CONFIG_ENTRY *e; ASSERT(master); if (!add) { return; } /* Save each section */ s = add->head; while (s != NULL) { config_add_section(master, s->name); e = s->head; while (e != NULL) { if (!e->is_comment) { config_set_value(master, s->name, e->key, e->value); } else if (merge_comments) { config_add_comment(master, s->name, e->key); } e = e->next; } s = s->next; } } /* Function: al_merge_config_into */ void al_merge_config_into(ALLEGRO_CONFIG *master, const ALLEGRO_CONFIG *add) { do_config_merge_into(master, add, false); } /* Function: al_merge_config */ ALLEGRO_CONFIG *al_merge_config(const ALLEGRO_CONFIG *cfg1, const ALLEGRO_CONFIG *cfg2) { ALLEGRO_CONFIG *config = al_create_config(); do_config_merge_into(config, cfg1, true); do_config_merge_into(config, cfg2, false); return config; } static void destroy_entry(ALLEGRO_CONFIG_ENTRY *e) { al_ustr_free(e->key); al_ustr_free(e->value); al_free(e); } static void destroy_section(ALLEGRO_CONFIG_SECTION *s) { ALLEGRO_CONFIG_ENTRY *e = s->head; while (e) { ALLEGRO_CONFIG_ENTRY *tmp = e->next; destroy_entry(e); e = tmp; } al_ustr_free(s->name); _al_aa_free(s->tree); al_free(s); } /* Function: al_destroy_config */ void al_destroy_config(ALLEGRO_CONFIG *config) { ALLEGRO_CONFIG_SECTION *s; if (!config) { return; } s = config->head; while (s) { ALLEGRO_CONFIG_SECTION *tmp = s->next; destroy_section(s); s = tmp; } _al_aa_free(config->tree); al_free(config); } /* Function: al_get_first_config_section */ char const *al_get_first_config_section(ALLEGRO_CONFIG const *config, ALLEGRO_CONFIG_SECTION **iterator) { ALLEGRO_CONFIG_SECTION *s; if (!config) return NULL; s = config->head; if (iterator) *iterator = s; return s ? al_cstr(s->name) : NULL; } /* Function: al_get_next_config_section */ char const *al_get_next_config_section(ALLEGRO_CONFIG_SECTION **iterator) { ALLEGRO_CONFIG_SECTION *s; if (!iterator) return NULL; s = *iterator; if (s) s = s->next; *iterator = s; return s ? al_cstr(s->name) : NULL; } /* Function: al_get_first_config_entry */ char const *al_get_first_config_entry(ALLEGRO_CONFIG const *config, char const *section, ALLEGRO_CONFIG_ENTRY **iterator) { ALLEGRO_USTR_INFO section_info; const ALLEGRO_USTR *usection; ALLEGRO_CONFIG_SECTION *s; ALLEGRO_CONFIG_ENTRY *e; if (!config) return NULL; if (section == NULL) section = ""; usection = al_ref_cstr(§ion_info, section); s = find_section(config, usection); if (!s) return NULL; e = s->head; while (e && e->is_comment) e = e->next; if (iterator) *iterator = e; return e ? al_cstr(e->key) : NULL; } /* Function: al_get_next_config_entry */ char const *al_get_next_config_entry(ALLEGRO_CONFIG_ENTRY **iterator) { ALLEGRO_CONFIG_ENTRY *e; if (!iterator) return NULL; e = *iterator; if (e) e = e->next; while (e && e->is_comment) e = e->next; *iterator = e; return e ? al_cstr(e->key) : NULL; } /* Function: al_remove_config_section */ bool al_remove_config_section(ALLEGRO_CONFIG *config, char const *section) { ALLEGRO_USTR_INFO section_info; ALLEGRO_USTR const *usection; void *value; ALLEGRO_CONFIG_SECTION *s; if (section == NULL) section = ""; usection = al_ref_cstr(§ion_info, section); value = NULL; config->tree = _al_aa_delete(config->tree, usection, cmp_ustr, &value); if (!value) return false; s = value; if (s->prev) { s->prev->next = s->next; } else { ASSERT(config->head == s); config->head = s->next; } if (s->next) { s->next->prev = s->prev; } else { ASSERT(config->last == s); config->last = s->prev; } destroy_section(s); return true; } /* Function: al_remove_config_key */ bool al_remove_config_key(ALLEGRO_CONFIG *config, char const *section, char const *key) { ALLEGRO_USTR_INFO section_info; ALLEGRO_USTR_INFO key_info; ALLEGRO_USTR const *usection; ALLEGRO_USTR const *ukey = al_ref_cstr(&key_info, key); void *value; ALLEGRO_CONFIG_ENTRY * e; if (section == NULL) section = ""; usection = al_ref_cstr(§ion_info, section); ALLEGRO_CONFIG_SECTION *s = find_section(config, usection); if (!s) return false; value = NULL; s->tree = _al_aa_delete(s->tree, ukey, cmp_ustr, &value); if (!value) return false; e = value; if (e->prev) { e->prev->next = e->next; } else { ASSERT(s->head == e); s->head = e->next; } if (e->next) { e->next->prev = e->prev; } else { ASSERT(s->last == e); s->last = e->prev; } destroy_entry(e); return true; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/cpu.c000066400000000000000000000056051473414355200152100ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * CPU and hardware information. * * By Beoran. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/cpu.h" #include "allegro5/internal/aintern.h" /* * The CPU and pysical memory detection functions below use * sysconf() if the right define is available as a parameter, * otherwise they use sysctl(), again if the right define is available. * This was chosen so because sysconf is POSIX and (in theory) * more portable than sysctl(). * On Windows, of course, the Windows API is always used. */ #ifdef ALLEGRO_HAVE_SYSCONF #include #endif #ifdef ALLEGRO_HAVE_SYSCTL #include #include #endif #ifdef ALLEGRO_WINDOWS #ifndef WINVER #define WINVER 0x0500 #endif #include #endif /* Function: al_get_cpu_count */ int al_get_cpu_count(void) { #if defined(ALLEGRO_HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) return (int)sysconf(_SC_NPROCESSORS_ONLN); #elif defined(ALLEGRO_HAVE_SYSCTL) #if defined(HW_AVAILCPU) int mib[2] = {CTL_HW, HW_AVAILCPU}; #elif defined(HW_NCPU) int mib[2] = {CTL_HW, HW_NCPU}; #else return -1; #endif int ncpu = 1; size_t len = sizeof(ncpu); if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == 0) { return ncpu; } #elif defined(ALLEGRO_WINDOWS) SYSTEM_INFO info; GetSystemInfo(&info); return info.dwNumberOfProcessors; #endif return -1; } /* Function: al_get_ram_size */ int al_get_ram_size(void) { #if defined(ALLEGRO_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) uint64_t aid = (uint64_t) sysconf(_SC_PHYS_PAGES); aid *= (uint64_t) sysconf(_SC_PAGESIZE); aid /= (uint64_t) (1024 * 1024); return (int)(aid); #elif defined(ALLEGRO_HAVE_SYSCTL) #ifdef HW_REALMEM int mib[2] = {CTL_HW, HW_REALMEM}; #elif defined(HW_PHYSMEM) int mib[2] = {CTL_HW, HW_PHYSMEM}; #elif defined(HW_MEMSIZE) int mib[2] = {CTL_HW, HW_MEMSIZE}; #else return -1; #endif uint64_t memsize = 0; size_t len = sizeof(memsize); if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) { return (int)(memsize / (1024*1024)); } #elif defined(ALLEGRO_WINDOWS) MEMORYSTATUSEX status; status.dwLength = sizeof(status); if (GlobalMemoryStatusEx(&status)) { return (int)(status.ullTotalPhys / (1024 * 1024)); } #endif return -1; } /* vi: set ts=4 sw=4 expandtab: */ allegro5-5.2.10.1/src/debug.c000066400000000000000000000223701473414355200155050ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Logging and assertion handlers. * * See LICENSE.txt for copyright information. */ #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern_debug.h" #include "allegro5/internal/aintern_thread.h" #include "allegro5/internal/aintern_vector.h" #ifdef ALLEGRO_WINDOWS #include "allegro5/internal/aintern_wunicode.h" #endif #ifdef ALLEGRO_ANDROID #include #include #endif /* tracing */ typedef struct TRACE_INFO { bool trace_virgin; FILE *trace_file; bool need_close; _AL_MUTEX trace_mutex; /* 0: debug, 1: info, 2: warn, 3: error */ int level; /* 1: line number, 2: function name, 4: timestamp */ int flags; /* List of channels to log. NULL to log all channels. */ _AL_VECTOR channels; _AL_VECTOR excluded; /* Whether settings have been read from allegro5.cfg or not. */ bool configured; } TRACE_INFO; static TRACE_INFO trace_info = { true, NULL, true, _AL_MUTEX_UNINITED, 0, 7, _AL_VECTOR_INITIALIZER(ALLEGRO_USTR *), _AL_VECTOR_INITIALIZER(ALLEGRO_USTR *), false }; static char static_trace_buffer[2048]; /* run-time assertions */ void (*_al_user_assert_handler)(char const *expr, char const *file, int line, char const *func); void (*_al_user_trace_handler)(char const *message); static void delete_string_list(_AL_VECTOR *v) { while (_al_vector_is_nonempty(v)) { int i = _al_vector_size(v) - 1; ALLEGRO_USTR **iter = _al_vector_ref(v, i); al_ustr_free(*iter); _al_vector_delete_at(v, i); } _al_vector_free(v); } void _al_configure_logging(void) { ALLEGRO_CONFIG *config; char const *v; bool got_all = false; config = al_get_system_config(); v = al_get_config_value(config, "trace", "channels"); if (v) { ALLEGRO_USTR_INFO uinfo; const ALLEGRO_USTR *u = al_ref_cstr(&uinfo, v); int pos = 0; while (pos >= 0) { int comma = al_ustr_find_chr(u, pos, ','); int first; ALLEGRO_USTR *u2, **iter; if (comma == -1) u2 = al_ustr_dup_substr(u, pos, al_ustr_length(u)); else u2 = al_ustr_dup_substr(u, pos, comma); al_ustr_trim_ws(u2); first = al_ustr_get(u2, 0); if (first == '-') { al_ustr_remove_chr(u2, 0); iter = _al_vector_alloc_back(&trace_info.excluded); *iter = u2; } else { if (first == '+') al_ustr_remove_chr(u2, 0); iter = _al_vector_alloc_back(&trace_info.channels); *iter = u2; if (!strcmp(al_cstr(u2), "all")) got_all = true; } pos = comma; al_ustr_get_next(u, &pos); } if (got_all) delete_string_list(&trace_info.channels); } #ifdef DEBUGMODE trace_info.level = 0; #else trace_info.level = 9999; #endif v = getenv("ALLEGRO_TRACE_LEVEL"); if (!v) v = al_get_config_value(config, "trace", "level"); if (v) { if (!strcmp(v, "error")) trace_info.level = 3; else if (!strcmp(v, "warn")) trace_info.level = 2; else if (!strcmp(v, "info")) trace_info.level = 1; else if (!strcmp(v, "debug")) trace_info.level = 0; else if (!strcmp(v, "none")) trace_info.level = 9999; } v = al_get_config_value(config, "trace", "timestamps"); if (!v || strcmp(v, "0")) trace_info.flags |= 4; else trace_info.flags &= ~4; v = al_get_config_value(config, "trace", "functions"); if (!v || strcmp(v, "0")) trace_info.flags |= 2; else trace_info.flags &= ~2; v = al_get_config_value(config, "trace", "lines"); if (!v || strcmp(v, "0")) trace_info.flags |= 1; else trace_info.flags &= ~1; if (!trace_info.configured) _al_mutex_init(&trace_info.trace_mutex); trace_info.configured = true; } static void open_trace_file(void) { if (trace_info.trace_virgin) { const char *s = getenv("ALLEGRO_TRACE"); if (s) { if (!strcmp(s, "-")) { trace_info.trace_file = stdout; trace_info.need_close = false; } else { trace_info.trace_file = fopen(s, "w"); } } else #if defined(ALLEGRO_IPHONE) || defined(ALLEGRO_ANDROID) || defined(__EMSCRIPTEN__) /* iPhone and Android don't like us writing files, so we'll be doing * something else there by default. */ trace_info.trace_file = NULL; #else trace_info.trace_file = fopen("allegro.log", "w"); #endif trace_info.trace_virgin = false; } } static void do_trace(const char *msg, ...) { va_list ap; int s = strlen(static_trace_buffer); va_start(ap, msg); vsnprintf(static_trace_buffer + s, sizeof(static_trace_buffer) - s, msg, ap); va_end(ap); } /* _al_trace_prefix: * Conditionally write the initial part of a trace message. If we do, return true * and continue to hold the trace_mutex lock. */ bool _al_trace_prefix(char const *channel, int level, char const *file, int line, char const *function) { size_t i; char *name; _AL_VECTOR const *v; if (!trace_info.configured) { _al_configure_logging(); } if (level < trace_info.level) return false; v = &trace_info.channels; if (_al_vector_is_empty(v)) goto channel_included; for (i = 0; i < _al_vector_size(v); i++) { ALLEGRO_USTR **iter = _al_vector_ref(v, i); if (!strcmp(al_cstr(*iter), channel)) goto channel_included; } return false; channel_included: v = &trace_info.excluded; if (_al_vector_is_nonempty(v)) { for (i = 0; i < _al_vector_size(v); i++) { ALLEGRO_USTR **iter = _al_vector_ref(v, i); if (!strcmp(al_cstr(*iter), channel)) return false; } } /* Avoid interleaved output from different threads. */ _al_mutex_lock(&trace_info.trace_mutex); if (!_al_user_trace_handler) open_trace_file(); do_trace("%-8s ", channel); if (level == 0) do_trace("D "); if (level == 1) do_trace("I "); if (level == 2) do_trace("W "); if (level == 3) do_trace("E "); #ifdef ALLEGRO_ANDROID { char pid_buf[16]; snprintf(pid_buf, sizeof(pid_buf), "%i: ", gettid()); do_trace(pid_buf); } #endif #ifdef ALLEGRO_MSVC name = strrchr(file, '\\'); #else name = strrchr(file, '/'); #endif if (trace_info.flags & 1) { do_trace("%20s:%-4d ", name ? name + 1 : file, line); } if (trace_info.flags & 2) { do_trace("%-32s ", function); } if (trace_info.flags & 4) { double t = 0; if (al_is_system_installed()) t = al_get_time(); do_trace("[%10.5f] ", t); } /* Do not unlock trace_mutex here; that is done by _al_trace_suffix. */ return true; } /* _al_trace_suffix: * Output the final part of a trace message, and release the trace_mutex lock. */ void _al_trace_suffix(const char *msg, ...) { int olderr = errno; va_list ap; int s = strlen(static_trace_buffer); va_start(ap, msg); vsnprintf(static_trace_buffer + s, sizeof(static_trace_buffer) - s, msg, ap); va_end(ap); if (_al_user_trace_handler) { _al_user_trace_handler(static_trace_buffer); } else { #ifdef ALLEGRO_ANDROID (void)__android_log_print(ANDROID_LOG_INFO, "allegro", "%s", static_trace_buffer); #endif #if defined(ALLEGRO_IPHONE) || defined(__EMSCRIPTEN__) fprintf(stderr, "%s", static_trace_buffer); fflush(stderr); #endif #ifdef ALLEGRO_WINDOWS { TCHAR *windows_output = _twin_utf8_to_tchar(static_trace_buffer); OutputDebugString(windows_output); al_free(windows_output); } #endif /* We're intentially still writing to a file if it's set even with the * additional logging options above. */ if (trace_info.trace_file) { fprintf(trace_info.trace_file, "%s", static_trace_buffer); fflush(trace_info.trace_file); } } static_trace_buffer[0] = '\0'; errno = olderr; _al_mutex_unlock(&trace_info.trace_mutex); } void _al_shutdown_logging(void) { if (trace_info.configured) { _al_mutex_destroy(&trace_info.trace_mutex); delete_string_list(&trace_info.channels); delete_string_list(&trace_info.excluded); trace_info.configured = false; } if (trace_info.trace_file && trace_info.need_close) { fclose(trace_info.trace_file); } trace_info.trace_file = NULL; trace_info.trace_virgin = true; } /* Function: al_register_assert_handler */ void al_register_assert_handler(void (*handler)(char const *expr, char const *file, int line, char const *func)) { _al_user_assert_handler = handler; } /* Function: al_register_trace_handler */ void al_register_trace_handler(void (*handler)(char const *)) { _al_user_trace_handler = handler; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/display.c000066400000000000000000000426141473414355200160670ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * New display driver. * * By Elias Pschernig. * * Modified by Trent Gamblin. * * See readme.txt for copyright information. */ /* Title: Display routines */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_shader.h" #include "allegro5/internal/aintern_system.h" ALLEGRO_DEBUG_CHANNEL("display") /* Function: al_create_display */ ALLEGRO_DISPLAY *al_create_display(int w, int h) { ALLEGRO_SYSTEM *system; ALLEGRO_DISPLAY_INTERFACE *driver; ALLEGRO_DISPLAY *display; ALLEGRO_EXTRA_DISPLAY_SETTINGS *settings; int64_t flags; system = al_get_system_driver(); driver = system->vt->get_display_driver(); if (!driver) { ALLEGRO_ERROR("Failed to create display (no display driver)\n"); return NULL; } display = driver->create_display(w, h); if (!display) { ALLEGRO_ERROR("Failed to create display (NULL)\n"); return NULL; } ASSERT(display->vt); settings = &display->extra_settings; flags = settings->required | settings->suggested; if (!(flags & (1 << ALLEGRO_AUTO_CONVERT_BITMAPS))) { settings->settings[ALLEGRO_AUTO_CONVERT_BITMAPS] = 1; } settings->settings[ALLEGRO_DEFAULT_SHADER_PLATFORM] = _al_get_new_display_settings()->settings[ALLEGRO_DEFAULT_SHADER_PLATFORM]; display->min_w = 0; display->min_h = 0; display->max_w = 0; display->max_h = 0; display->use_constraints = false; display->vertex_cache = 0; display->num_cache_vertices = 0; display->cache_enabled = false; display->vertex_cache_size = 0; display->cache_texture = 0; al_identity_transform(&display->projview_transform); display->default_shader = NULL; _al_vector_init(&display->display_invalidated_callbacks, sizeof(void *)); _al_vector_init(&display->display_validated_callbacks, sizeof(void *)); display->render_state.write_mask = ALLEGRO_MASK_RGBA | ALLEGRO_MASK_DEPTH; display->render_state.depth_test = false; display->render_state.depth_function = ALLEGRO_RENDER_LESS; display->render_state.alpha_test = false; display->render_state.alpha_function = ALLEGRO_RENDER_ALWAYS; display->render_state.alpha_test_value = 0; _al_vector_init(&display->bitmaps, sizeof(ALLEGRO_BITMAP*)); if (settings->settings[ALLEGRO_COMPATIBLE_DISPLAY]) { al_set_target_bitmap(al_get_backbuffer(display)); } else { ALLEGRO_DEBUG("ALLEGRO_COMPATIBLE_DISPLAY not set\n"); _al_set_current_display_only(display); } if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { display->default_shader = _al_create_default_shader(display); if (!display->default_shader) { al_destroy_display(display); return NULL; } al_use_shader(display->default_shader); } /* Clear the screen */ if (settings->settings[ALLEGRO_COMPATIBLE_DISPLAY]) { al_clear_to_color(al_map_rgb(0, 0, 0)); /* TODO: * on iphone, don't kill the initial splashscreen - in fact, it's also * annoying in linux to have an extra black frame as first frame and I * suppose we never really want it */ #if 0 al_flip_display(); #endif } if (settings->settings[ALLEGRO_AUTO_CONVERT_BITMAPS]) { /* We convert video bitmaps to memory bitmaps when the display is * destroyed, so seems only fair to re-convertt hem when the * display is re-created again. */ al_convert_memory_bitmaps(); } return display; } /* Function: al_destroy_display */ void al_destroy_display(ALLEGRO_DISPLAY *display) { if (display) { /* This causes warnings and potential errors on Android because * it clears the context and Android needs this thread to have * the context bound in its destroy function and to destroy the * shader. Just skip this part on Android. */ #ifndef ALLEGRO_ANDROID ALLEGRO_BITMAP *bmp; bmp = al_get_target_bitmap(); if (bmp && _al_get_bitmap_display(bmp) == display) al_set_target_bitmap(NULL); /* This can happen if we have a current display, but the target bitmap * was a memory bitmap. */ if (display == al_get_current_display()) _al_set_current_display_only(NULL); #endif al_destroy_shader(display->default_shader); display->default_shader = NULL; ASSERT(display->vt); display->vt->destroy_display(display); } } /* Function: al_get_backbuffer */ ALLEGRO_BITMAP *al_get_backbuffer(ALLEGRO_DISPLAY *display) { if (display) { ASSERT(display->vt); return display->vt->get_backbuffer(display); } return NULL; } /* Function: al_flip_display */ void al_flip_display(void) { ALLEGRO_DISPLAY *display = al_get_current_display(); if (display) { ASSERT(display->vt); display->vt->flip_display(display); } } /* Function: al_update_display_region */ void al_update_display_region(int x, int y, int width, int height) { ALLEGRO_DISPLAY *display = al_get_current_display(); if (display) { ASSERT(display->vt); display->vt->update_display_region(display, x, y, width, height); } } /* Function: al_acknowledge_resize */ bool al_acknowledge_resize(ALLEGRO_DISPLAY *display) { ASSERT(display); ASSERT(display->vt); if (!(display->flags & ALLEGRO_FULLSCREEN)) { if (display->vt->acknowledge_resize) { return display->vt->acknowledge_resize(display); } } return false; } /* Function: al_resize_display */ bool al_resize_display(ALLEGRO_DISPLAY *display, int width, int height) { ASSERT(display); ASSERT(display->vt); ALLEGRO_INFO("Requested display resize %dx%d\n", width, height); if (display->vt->resize_display) { return display->vt->resize_display(display, width, height); } return false; } /* Function: al_is_compatible_bitmap */ bool al_is_compatible_bitmap(ALLEGRO_BITMAP *bitmap) { ALLEGRO_DISPLAY *display = al_get_current_display(); ASSERT(bitmap); if (display) { ASSERT(display->vt); return display->vt->is_compatible_bitmap(display, bitmap); } return false; } /* Function: al_get_display_width */ int al_get_display_width(ALLEGRO_DISPLAY *display) { ASSERT(display); return display->w; } /* Function: al_get_display_height */ int al_get_display_height(ALLEGRO_DISPLAY *display) { ASSERT(display); return display->h; } /* Function: al_get_display_format */ int al_get_display_format(ALLEGRO_DISPLAY *display) { ASSERT(display); return display->backbuffer_format; } /* Function: al_get_display_refresh_rate */ int al_get_display_refresh_rate(ALLEGRO_DISPLAY *display) { ASSERT(display); return display->refresh_rate; } /* Function: al_get_display_flags */ int al_get_display_flags(ALLEGRO_DISPLAY *display) { ASSERT(display); return display->flags; } /* Function: al_get_display_orientation */ int al_get_display_orientation(ALLEGRO_DISPLAY* display) { if (display && display->vt->get_orientation) return display->vt->get_orientation(display); else return ALLEGRO_DISPLAY_ORIENTATION_UNKNOWN; } /* Function: al_wait_for_vsync */ bool al_wait_for_vsync(void) { ALLEGRO_DISPLAY *display = al_get_current_display(); ASSERT(display); if (display->vt->wait_for_vsync) return display->vt->wait_for_vsync(display); else return false; } /* Function: al_set_display_icon */ void al_set_display_icon(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *icon) { ALLEGRO_BITMAP *icons[1] = { icon }; al_set_display_icons(display, 1, icons); } /* Function: al_set_display_icons */ void al_set_display_icons(ALLEGRO_DISPLAY *display, int num_icons, ALLEGRO_BITMAP *icons[]) { int i; ASSERT(display); ASSERT(num_icons >= 1); ASSERT(icons); for (i = 0; i < num_icons; i++) { ASSERT(icons[i]); } if (display->vt->set_icons) { display->vt->set_icons(display, num_icons, icons); } } /* Function: al_set_window_position */ void al_set_window_position(ALLEGRO_DISPLAY *display, int x, int y) { ASSERT(display); if (display && display->flags & ALLEGRO_FULLSCREEN) { return; } if (display && display->vt && display->vt->set_window_position) { display->vt->set_window_position(display, x, y); } } /* Function: al_get_window_position */ void al_get_window_position(ALLEGRO_DISPLAY *display, int *x, int *y) { ASSERT(x); ASSERT(y); if (display && display->vt && display->vt->get_window_position) { display->vt->get_window_position(display, x, y); } else { *x = *y = -1; } } /* Function: al_get_window_borders */ bool al_get_window_borders(ALLEGRO_DISPLAY *display, int *left, int *top, int *right, int *bottom) { if (display && display->vt && display->vt->get_window_borders) { return display->vt->get_window_borders(display, left, top, right, bottom); } else { return false; } } /* Function: al_set_window_constraints */ bool al_set_window_constraints(ALLEGRO_DISPLAY *display, int min_w, int min_h, int max_w, int max_h) { ASSERT(display); /* Perform some basic checks. */ if (min_w < 0 || min_h < 0 || max_w < 0 || max_h < 0) { return false; } if (min_w > 0 && max_w > 0 && max_w < min_w) { return false; } if (min_h > 0 && max_h > 0 && max_h < min_h) { return false; } /* Cannot constrain when fullscreen. */ if (display->flags & ALLEGRO_FULLSCREEN) { return false; } /* Cannot constrain if not resizable. */ if (!(display->flags & ALLEGRO_RESIZABLE)) { return false; } if (display && display->vt && display->vt->set_window_constraints) { return display->vt->set_window_constraints(display, min_w, min_h, max_w, max_h); } else { return false; } } /* Function: al_get_window_constraints */ bool al_get_window_constraints(ALLEGRO_DISPLAY *display, int *min_w, int *min_h, int *max_w, int *max_h) { ASSERT(display); ASSERT(min_w); ASSERT(min_h); ASSERT(max_w); ASSERT(max_h); if (display && display->vt && display->vt->get_window_constraints) { return display->vt->get_window_constraints(display, min_w, min_h, max_w, max_h); } else { return false; } } /* Function: al_set_display_flag */ bool al_set_display_flag(ALLEGRO_DISPLAY *display, int flag, bool onoff) { ASSERT(display); if (display && display->vt && display->vt->set_display_flag) { return display->vt->set_display_flag(display, flag, onoff); } return false; } /* Function: al_set_window_title */ void al_set_window_title(ALLEGRO_DISPLAY *display, const char *title) { if (display && display->vt && display->vt->set_window_title) display->vt->set_window_title(display, title); } /* Function: al_get_display_event_source */ ALLEGRO_EVENT_SOURCE *al_get_display_event_source(ALLEGRO_DISPLAY *display) { return &display->es; } /* Function: al_hold_bitmap_drawing */ void al_hold_bitmap_drawing(bool hold) { ALLEGRO_DISPLAY *current_display = al_get_current_display(); if (current_display) { if (hold && !current_display->cache_enabled) { /* * Set the hardware transformation to identity, but keep the bitmap * transform the same as it was. Relies on the fact that when bitmap * holding is turned on, al_use_transform does not update the hardware * transformation. */ ALLEGRO_TRANSFORM old, ident; al_copy_transform(&old, al_get_current_transform()); al_identity_transform(&ident); al_use_transform(&ident); current_display->cache_enabled = hold; al_use_transform(&old); } else { current_display->cache_enabled = hold; } if (!hold) { current_display->vt->flush_vertex_cache(current_display); /* * Reset the hardware transform to match the stored transform. */ al_use_transform(al_get_current_transform()); } } } /* Function: al_is_bitmap_drawing_held */ bool al_is_bitmap_drawing_held(void) { ALLEGRO_DISPLAY *current_display = al_get_current_display(); if (current_display) return current_display->cache_enabled; else return false; } void _al_add_display_invalidated_callback(ALLEGRO_DISPLAY* display, void (*display_invalidated)(ALLEGRO_DISPLAY*)) { if (_al_vector_find(&display->display_invalidated_callbacks, display_invalidated) >= 0) { return; } else { void (**callback)(ALLEGRO_DISPLAY *) = _al_vector_alloc_back(&display->display_invalidated_callbacks); *callback = display_invalidated; } } void _al_add_display_validated_callback(ALLEGRO_DISPLAY* display, void (*display_validated)(ALLEGRO_DISPLAY*)) { if (_al_vector_find(&display->display_validated_callbacks, display_validated) >= 0) { return; } else { void (**callback)(ALLEGRO_DISPLAY *) = _al_vector_alloc_back(&display->display_validated_callbacks); *callback = display_validated; } } void _al_remove_display_invalidated_callback(ALLEGRO_DISPLAY *display, void (*callback)(ALLEGRO_DISPLAY *)) { _al_vector_find_and_delete(&display->display_invalidated_callbacks, &callback); } void _al_remove_display_validated_callback(ALLEGRO_DISPLAY *display, void (*callback)(ALLEGRO_DISPLAY *)) { _al_vector_find_and_delete(&display->display_validated_callbacks, &callback); } /* Function: al_acknowledge_drawing_halt */ void al_acknowledge_drawing_halt(ALLEGRO_DISPLAY *display) { if (display->vt->acknowledge_drawing_halt) { display->vt->acknowledge_drawing_halt(display); } } /* Function: al_acknowledge_drawing_resume */ void al_acknowledge_drawing_resume(ALLEGRO_DISPLAY *display) { if (display->vt->acknowledge_drawing_resume) { display->vt->acknowledge_drawing_resume(display); } } /* Function: al_get_render_state */ int al_get_render_state(ALLEGRO_RENDER_STATE state) { ALLEGRO_DISPLAY *display = al_get_current_display(); if (!display) return -1; switch (state) { case ALLEGRO_ALPHA_TEST: return display->render_state.alpha_test; break; case ALLEGRO_WRITE_MASK: return display->render_state.write_mask; break; case ALLEGRO_DEPTH_TEST: return display->render_state.depth_test; break; case ALLEGRO_DEPTH_FUNCTION: return display->render_state.depth_function; break; case ALLEGRO_ALPHA_FUNCTION: return display->render_state.alpha_function; break; case ALLEGRO_ALPHA_TEST_VALUE: return display->render_state.alpha_test_value; break; default: ALLEGRO_ERROR("Unknown state to retrieve: %d\n", state); return -1; break; } } /* Function: al_set_render_state */ void al_set_render_state(ALLEGRO_RENDER_STATE state, int value) { ALLEGRO_DISPLAY *display = al_get_current_display(); if (!display) return; switch (state) { case ALLEGRO_ALPHA_TEST: display->render_state.alpha_test = value; break; case ALLEGRO_WRITE_MASK: display->render_state.write_mask = value; break; case ALLEGRO_DEPTH_TEST: display->render_state.depth_test = value; break; case ALLEGRO_DEPTH_FUNCTION: display->render_state.depth_function = value; break; case ALLEGRO_ALPHA_FUNCTION: display->render_state.alpha_function = value; break; case ALLEGRO_ALPHA_TEST_VALUE: display->render_state.alpha_test_value = value; break; default: ALLEGRO_WARN("Unknown state to change: %d\n", state); break; } if (display->vt && display->vt->update_render_state) { display->vt->update_render_state(display); } } /* Function: al_backup_dirty_bitmaps */ void al_backup_dirty_bitmaps(ALLEGRO_DISPLAY *display) { unsigned int i; for (i = 0; i < display->bitmaps._size; i++) { ALLEGRO_BITMAP **bptr = (ALLEGRO_BITMAP **)_al_vector_ref(&display->bitmaps, i); ALLEGRO_BITMAP *bmp = *bptr; if (_al_get_bitmap_display(bmp) == display) { if (bmp->vt && bmp->vt->backup_dirty_bitmap) { bmp->vt->backup_dirty_bitmap(bmp); } } } } /* Function: al_apply_window_constraints */ void al_apply_window_constraints(ALLEGRO_DISPLAY *display, bool onoff) { display->use_constraints = onoff; if (display->vt && display->vt->apply_window_constraints) display->vt->apply_window_constraints(display, onoff); } /* Function: al_get_display_adapter */ int al_get_display_adapter(ALLEGRO_DISPLAY *display) { int x, y, adapter, num_adapters; al_get_window_position(display, &x, &y); num_adapters = al_get_num_video_adapters(); for (adapter = 0; adapter < num_adapters; adapter++) { ALLEGRO_MONITOR_INFO mi; al_get_monitor_info(adapter, &mi); if (x >= mi.x1 && x < mi.x2 && y >= mi.y1 && y < mi.y2) { return adapter; } } return -1; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/display_settings.c000066400000000000000000001056311473414355200200060ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Additional display settings (like multisample). * * Original code from AllegroGL. * * Heavily modified by Elias Pschernig. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_display.h" #include ALLEGRO_DEBUG_CHANNEL("display") /* Function: al_set_new_display_option */ void al_set_new_display_option(int option, int value, int importance) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *extras; extras = _al_get_new_display_settings(); switch (importance) { case ALLEGRO_REQUIRE: extras->required |= (int64_t)1 << option; extras->suggested &= ~((int64_t)1 << option); break; case ALLEGRO_SUGGEST: extras->suggested |= (int64_t)1 << option; extras->required &= ~((int64_t)1 << option); break; case ALLEGRO_DONTCARE: extras->required &= ~((int64_t)1 << option); extras->suggested &= ~((int64_t)1 << option); break; } extras->settings[option] = value; } int _al_get_suggested_display_option(ALLEGRO_DISPLAY *d, int option, int default_value) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *s = &d->extra_settings; uint64_t flags = s->required | s->suggested; if (flags & ((uint64_t)1 << option)) return s->settings[option]; return default_value; } /* Function: al_get_new_display_option */ int al_get_new_display_option(int option, int *importance) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *extras; extras = _al_get_new_display_settings(); if (extras->required & ((int64_t)1 << option)) { if (importance) *importance = ALLEGRO_REQUIRE; return extras->settings[option]; } if (extras->suggested & ((int64_t)1 << option)) { if (importance) *importance = ALLEGRO_SUGGEST; return extras->settings[option]; } if (importance) *importance = ALLEGRO_DONTCARE; return 0; } /* Function: al_set_display_option */ void al_set_display_option(ALLEGRO_DISPLAY *display, int option, int value) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *extras; extras = &display->extra_settings; extras->settings[option] = value; if (display->vt->set_display_option) { display->vt->set_display_option(display, option, value); } } /* Function: al_get_display_option */ int al_get_display_option(ALLEGRO_DISPLAY *display, int option) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *extras; extras = &display->extra_settings; return extras->settings[option]; } /* Function: al_reset_new_display_options */ void al_reset_new_display_options(void) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *extras; extras = _al_get_new_display_settings(); _al_fill_display_settings(extras); } #define req ref->required #define sug ref->suggested /* _al_fill_display_settings() * Will fill in missing settings by 'guessing' what the user intended. */ void _al_fill_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref) { int all_components = (1<settings[ALLEGRO_COLOR_SIZE] = ref->settings[ALLEGRO_RED_SIZE] + ref->settings[ALLEGRO_GREEN_SIZE] + ref->settings[ALLEGRO_BLUE_SIZE] + ref->settings[ALLEGRO_ALPHA_SIZE]; /* Round depth to 8 bits */ ref->settings[ALLEGRO_COLOR_SIZE] = (ref->settings[ALLEGRO_COLOR_SIZE] + 7) / 8; } /* If only some components were set, guess the others */ else if ((req | sug) & all_components) { int avg = ((req | sug) & (1<settings[ALLEGRO_RED_SIZE]: 0) + ((req | sug) & (1<settings[ALLEGRO_GREEN_SIZE]: 0) + ((req | sug) & (1<settings[ALLEGRO_BLUE_SIZE]: 0) + ((req | sug) & (1<settings[ALLEGRO_ALPHA_SIZE]: 0); int num = ((req | sug) & (1<settings[ALLEGRO_RED_SIZE] = avg; } if (((req | sug) & (1<settings[ALLEGRO_GREEN_SIZE] = avg; } if (((req | sug) & (1<settings[ALLEGRO_BLUE_SIZE] = avg; } if (((req | sug) & (1<settings[ALLEGRO_ALPHA_SIZE] = avg; } /* If color depth wasn't defined, figure it out */ if (((req | sug) & (1<settings[ALLEGRO_COLOR_SIZE], eds->settings[ALLEGRO_RED_SIZE], eds->settings[ALLEGRO_GREEN_SIZE], eds->settings[ALLEGRO_BLUE_SIZE], eds->settings[ALLEGRO_ALPHA_SIZE], eds->settings[ALLEGRO_DEPTH_SIZE], eds->settings[ALLEGRO_STENCIL_SIZE], eds->settings[ALLEGRO_ACC_RED_SIZE], eds->settings[ALLEGRO_ACC_RED_SIZE], eds->settings[ALLEGRO_ACC_RED_SIZE], eds->settings[ALLEGRO_ACC_RED_SIZE], eds->settings[ALLEGRO_SAMPLES], eds->settings[ALLEGRO_SAMPLE_BUFFERS]); } int _al_score_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds, ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref) { int score = 0; debug_display_settings(eds); if (eds->settings[ALLEGRO_COMPATIBLE_DISPLAY] != ref->settings[ALLEGRO_COMPATIBLE_DISPLAY]) { if (req & (1<settings[ALLEGRO_VSYNC] != ref->settings[ALLEGRO_VSYNC]) { if (req & (1<settings[ALLEGRO_COLOR_SIZE] != ref->settings[ALLEGRO_COLOR_SIZE]) { if (req & (1<settings[ALLEGRO_COLOR_SIZE] < ref->settings[ALLEGRO_COLOR_SIZE]) score += (96 * eds->settings[ALLEGRO_COLOR_SIZE]) / ref->settings[ALLEGRO_COLOR_SIZE]; else score += 96 + 96 / (1 + eds->settings[ALLEGRO_COLOR_SIZE] - ref->settings[ALLEGRO_COLOR_SIZE]); } /* check colour component widths here and Allegro formatness */ if ((req & (1<settings[ALLEGRO_RED_SIZE] != ref->settings[ALLEGRO_RED_SIZE])) { ALLEGRO_DEBUG("Red depth requirement not met.\n"); return -1; } if (sug & (1<settings[ALLEGRO_RED_SIZE] < ref->settings[ALLEGRO_RED_SIZE]) { score += (16 * eds->settings[ALLEGRO_RED_SIZE]) / ref->settings[ALLEGRO_RED_SIZE]; } else { score += 16 + 16 / (1 + eds->settings[ALLEGRO_RED_SIZE] - ref->settings[ALLEGRO_RED_SIZE]); } } if ((req & (1<settings[ALLEGRO_GREEN_SIZE] != ref->settings[ALLEGRO_GREEN_SIZE])) { ALLEGRO_DEBUG("Green depth requirement not met.\n"); return -1; } if (sug & (1<settings[ALLEGRO_GREEN_SIZE] < ref->settings[ALLEGRO_GREEN_SIZE]) { score += (16 * eds->settings[ALLEGRO_GREEN_SIZE]) / ref->settings[ALLEGRO_GREEN_SIZE]; } else { score += 16 + 16 / (1 + eds->settings[ALLEGRO_GREEN_SIZE] - ref->settings[ALLEGRO_GREEN_SIZE]); } } if ((req & (1<settings[ALLEGRO_BLUE_SIZE] != ref->settings[ALLEGRO_BLUE_SIZE])) { ALLEGRO_DEBUG("Blue depth requirement not met.\n"); return -1; } if (sug & (1<settings[ALLEGRO_BLUE_SIZE] < ref->settings[ALLEGRO_BLUE_SIZE]) { score += (16 * eds->settings[ALLEGRO_BLUE_SIZE]) / ref->settings[ALLEGRO_BLUE_SIZE]; } else { score += 16 + 16 / (1 + eds->settings[ALLEGRO_BLUE_SIZE] - ref->settings[ALLEGRO_BLUE_SIZE]); } } if ((req & (1<settings[ALLEGRO_ALPHA_SIZE] != ref->settings[ALLEGRO_ALPHA_SIZE])) { ALLEGRO_DEBUG("Alpha depth requirement not met (%d instead of %d).\n", eds->settings[ALLEGRO_ALPHA_SIZE], ref->settings[ALLEGRO_ALPHA_SIZE]); return -1; } if (sug & (1<settings[ALLEGRO_ALPHA_SIZE] < ref->settings[ALLEGRO_ALPHA_SIZE]) { score += (16 * eds->settings[ALLEGRO_ALPHA_SIZE]) / ref->settings[ALLEGRO_ALPHA_SIZE]; } else { score += 16 + 16 / (1 + eds->settings[ALLEGRO_ALPHA_SIZE] - ref->settings[ALLEGRO_ALPHA_SIZE]); } } if ((req & (1<settings[ALLEGRO_ACC_RED_SIZE] != ref->settings[ALLEGRO_ACC_RED_SIZE])) { ALLEGRO_DEBUG("Accumulator Red depth requirement not met.\n"); return -1; } if (sug & (1<settings[ALLEGRO_ACC_RED_SIZE] < ref->settings[ALLEGRO_ACC_RED_SIZE]) { score += (16 * eds->settings[ALLEGRO_ACC_RED_SIZE]) / ref->settings[ALLEGRO_ACC_RED_SIZE]; } else { score += 16 + 16 / (1 + eds->settings[ALLEGRO_ACC_RED_SIZE] - ref->settings[ALLEGRO_ACC_RED_SIZE]); } } if ((req & (1<settings[ALLEGRO_ACC_GREEN_SIZE] != ref->settings[ALLEGRO_ACC_GREEN_SIZE])) { ALLEGRO_DEBUG("Accumulator Green depth requirement not met.\n"); return -1; } if (sug & (1<settings[ALLEGRO_ACC_GREEN_SIZE] < ref->settings[ALLEGRO_ACC_GREEN_SIZE]) { score += (16 * eds->settings[ALLEGRO_ACC_GREEN_SIZE]) / ref->settings[ALLEGRO_ACC_GREEN_SIZE]; } else { score += 16 + 16 / (1 + eds->settings[ALLEGRO_ACC_GREEN_SIZE] - ref->settings[ALLEGRO_ACC_GREEN_SIZE]); } } if ((req & (1<settings[ALLEGRO_ACC_BLUE_SIZE] != ref->settings[ALLEGRO_ACC_BLUE_SIZE])) { ALLEGRO_DEBUG("Accumulator Blue depth requirement not met.\n"); return -1; } if (sug & (1<settings[ALLEGRO_ACC_BLUE_SIZE] < ref->settings[ALLEGRO_ACC_BLUE_SIZE]) { score += (16 * eds->settings[ALLEGRO_ACC_BLUE_SIZE]) / ref->settings[ALLEGRO_ACC_BLUE_SIZE]; } else { score += 16 + 16 / (1 + eds->settings[ALLEGRO_ACC_BLUE_SIZE] - ref->settings[ALLEGRO_ACC_BLUE_SIZE]); } } if ((req & (1<settings[ALLEGRO_ACC_ALPHA_SIZE] != ref->settings[ALLEGRO_ACC_ALPHA_SIZE])) { ALLEGRO_DEBUG("Accumulator Alpha depth requirement not met.\n"); return -1; } if (sug & (1<settings[ALLEGRO_ACC_ALPHA_SIZE] < ref->settings[ALLEGRO_ACC_ALPHA_SIZE]) { score += (16 * eds->settings[ALLEGRO_ACC_ALPHA_SIZE]) / ref->settings[ALLEGRO_ACC_ALPHA_SIZE]; } else { score += 16 + 16 / (1 + eds->settings[ALLEGRO_ACC_ALPHA_SIZE] - ref->settings[ALLEGRO_ACC_ALPHA_SIZE]); } } if (!eds->settings[ALLEGRO_SINGLE_BUFFER] != !ref->settings[ALLEGRO_SINGLE_BUFFER]) { if (req & (1<settings[ALLEGRO_STEREO] != !ref->settings[ALLEGRO_STEREO]) { if (req & (1<settings[ALLEGRO_AUX_BUFFERS] < ref->settings[ALLEGRO_AUX_BUFFERS])) { ALLEGRO_DEBUG("Aux Buffer requirement not met.\n"); return -1; } if (sug & (1<settings[ALLEGRO_AUX_BUFFERS] < ref->settings[ALLEGRO_AUX_BUFFERS]) { score += (64 * eds->settings[ALLEGRO_AUX_BUFFERS]) / ref->settings[ALLEGRO_AUX_BUFFERS]; } else { score += 64 + 64 / (1 + eds->settings[ALLEGRO_AUX_BUFFERS] - ref->settings[ALLEGRO_AUX_BUFFERS]); } } if ((req & (1<settings[ALLEGRO_DEPTH_SIZE] != ref->settings[ALLEGRO_DEPTH_SIZE])) { ALLEGRO_DEBUG("Z-Buffer requirement not met.\n"); return -1; } if (sug & (1<settings[ALLEGRO_DEPTH_SIZE] < ref->settings[ALLEGRO_DEPTH_SIZE]) { score += (64 * eds->settings[ALLEGRO_DEPTH_SIZE]) / ref->settings[ALLEGRO_DEPTH_SIZE]; } else { score += 64 + 64 / (1 + eds->settings[ALLEGRO_DEPTH_SIZE] - ref->settings[ALLEGRO_DEPTH_SIZE]); } } if ((req & (1<settings[ALLEGRO_STENCIL_SIZE] != ref->settings[ALLEGRO_STENCIL_SIZE])) { ALLEGRO_DEBUG("Stencil depth requirement not met.\n"); return -1; } if (sug & (1<settings[ALLEGRO_STENCIL_SIZE] < ref->settings[ALLEGRO_STENCIL_SIZE]) { score += (64 * eds->settings[ALLEGRO_STENCIL_SIZE]) / ref->settings[ALLEGRO_STENCIL_SIZE]; } else { score += 64 + 64 / (1 + eds->settings[ALLEGRO_STENCIL_SIZE] - ref->settings[ALLEGRO_STENCIL_SIZE]); } } if ((req & (1<settings[ALLEGRO_RENDER_METHOD] != ref->settings[ALLEGRO_RENDER_METHOD]) || (ref->settings[ALLEGRO_RENDER_METHOD] == 2))) { ALLEGRO_DEBUG("Render Method requirement not met.\n"); return -1; } if ((sug & (1<settings[ALLEGRO_RENDER_METHOD] == ref->settings[ALLEGRO_RENDER_METHOD])) { score += 1024; } else if (eds->settings[ALLEGRO_RENDER_METHOD] == 1) { score++; /* Add 1 for hw accel */ } if ((req & (1<settings[ALLEGRO_SAMPLE_BUFFERS] != ref->settings[ALLEGRO_SAMPLE_BUFFERS])) { ALLEGRO_DEBUG("Multisample Buffers requirement not met\n"); return -1; } else if (sug & (1<settings[ALLEGRO_SAMPLE_BUFFERS] == ref->settings[ALLEGRO_SAMPLE_BUFFERS]) { score += 128; } } if ((req & (1<settings[ALLEGRO_SAMPLES] != ref->settings[ALLEGRO_SAMPLES])) { ALLEGRO_DEBUG("Multisample Samples requirement not met\n"); return -1; } if (sug & (1<settings[ALLEGRO_SAMPLES] < ref->settings[ALLEGRO_SAMPLES]) { score += (64 * eds->settings[ALLEGRO_SAMPLES]) / ref->settings[ALLEGRO_SAMPLES]; } else { score += 64 + 64 / (1 + eds->settings[ALLEGRO_SAMPLES] - ref->settings[ALLEGRO_SAMPLES]); } } if (!eds->settings[ALLEGRO_FLOAT_COLOR] != !ref->settings[ALLEGRO_FLOAT_COLOR]) { if (req & (1<settings[ALLEGRO_FLOAT_DEPTH] != !ref->settings[ALLEGRO_FLOAT_DEPTH]) { if (req & (1<score == f1->score) return f0->index - f1->index; /* lower better */ else return f1->score - f0->score; /* higher better */ } int _al_deduce_color_format(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds) { /* dummy value to check if the format was detected */ int format = ALLEGRO_PIXEL_FORMAT_ANY; if (eds->settings[ALLEGRO_RED_SIZE] == 8 && eds->settings[ALLEGRO_GREEN_SIZE] == 8 && eds->settings[ALLEGRO_BLUE_SIZE] == 8) { if (eds->settings[ALLEGRO_ALPHA_SIZE] == 8 && eds->settings[ALLEGRO_COLOR_SIZE] == 32) { if (eds->settings[ALLEGRO_ALPHA_SHIFT] == 0 && eds->settings[ALLEGRO_BLUE_SHIFT] == 8 && eds->settings[ALLEGRO_GREEN_SHIFT] == 16 && eds->settings[ALLEGRO_RED_SHIFT] == 24) { format = ALLEGRO_PIXEL_FORMAT_RGBA_8888; } else if (eds->settings[ALLEGRO_ALPHA_SHIFT] == 24 && eds->settings[ALLEGRO_RED_SHIFT] == 0 && eds->settings[ALLEGRO_GREEN_SHIFT] == 8 && eds->settings[ALLEGRO_BLUE_SHIFT] == 16) { format = ALLEGRO_PIXEL_FORMAT_ABGR_8888; } else if (eds->settings[ALLEGRO_ALPHA_SHIFT] == 24 && eds->settings[ALLEGRO_RED_SHIFT] == 16 && eds->settings[ALLEGRO_GREEN_SHIFT] == 8 && eds->settings[ALLEGRO_BLUE_SHIFT] == 0) { format = ALLEGRO_PIXEL_FORMAT_ARGB_8888; } } else if (eds->settings[ALLEGRO_ALPHA_SIZE] == 0 && eds->settings[ALLEGRO_COLOR_SIZE] == 24) { if (eds->settings[ALLEGRO_BLUE_SHIFT] == 0 && eds->settings[ALLEGRO_GREEN_SHIFT] == 8 && eds->settings[ALLEGRO_RED_SHIFT] == 16) { format = ALLEGRO_PIXEL_FORMAT_RGB_888; } else if (eds->settings[ALLEGRO_RED_SHIFT] == 0 && eds->settings[ALLEGRO_GREEN_SHIFT] == 8 && eds->settings[ALLEGRO_BLUE_SHIFT] == 16) { format = ALLEGRO_PIXEL_FORMAT_BGR_888; } } else if (eds->settings[ALLEGRO_ALPHA_SIZE] == 0 && eds->settings[ALLEGRO_COLOR_SIZE] == 32) { if (eds->settings[ALLEGRO_BLUE_SHIFT] == 0 && eds->settings[ALLEGRO_GREEN_SHIFT] == 8 && eds->settings[ALLEGRO_RED_SHIFT] == 16) { format = ALLEGRO_PIXEL_FORMAT_XRGB_8888; } else if (eds->settings[ALLEGRO_RED_SHIFT] == 0 && eds->settings[ALLEGRO_GREEN_SHIFT] == 8 && eds->settings[ALLEGRO_BLUE_SHIFT] == 16) { format = ALLEGRO_PIXEL_FORMAT_XBGR_8888; } else if (eds->settings[ALLEGRO_RED_SHIFT] == 24 && eds->settings[ALLEGRO_GREEN_SHIFT] == 16 && eds->settings[ALLEGRO_BLUE_SHIFT] == 8) { format = ALLEGRO_PIXEL_FORMAT_RGBX_8888; } } } else if (eds->settings[ALLEGRO_RED_SIZE] == 5 && eds->settings[ALLEGRO_GREEN_SIZE] == 6 && eds->settings[ALLEGRO_BLUE_SIZE] == 5) { if (eds->settings[ALLEGRO_RED_SHIFT] == 0 && eds->settings[ALLEGRO_GREEN_SHIFT] == 5 && eds->settings[ALLEGRO_BLUE_SHIFT] == 11) { format = ALLEGRO_PIXEL_FORMAT_BGR_565; } else if (eds->settings[ALLEGRO_BLUE_SHIFT] == 0 && eds->settings[ALLEGRO_GREEN_SHIFT] == 5 && eds->settings[ALLEGRO_RED_SHIFT] == 11) { format = ALLEGRO_PIXEL_FORMAT_RGB_565; } } else if (eds->settings[ALLEGRO_RED_SIZE] == 5 && eds->settings[ALLEGRO_GREEN_SIZE] == 5 && eds->settings[ALLEGRO_BLUE_SIZE] == 5) { if (eds->settings[ALLEGRO_ALPHA_SIZE] == 1 && eds->settings[ALLEGRO_COLOR_SIZE] == 16) { if (eds->settings[ALLEGRO_ALPHA_SHIFT] == 0 && eds->settings[ALLEGRO_BLUE_SHIFT] == 1 && eds->settings[ALLEGRO_GREEN_SHIFT] == 6 && eds->settings[ALLEGRO_RED_SHIFT] == 11) { format = ALLEGRO_PIXEL_FORMAT_RGBA_5551; } if (eds->settings[ALLEGRO_ALPHA_SHIFT] == 15 && eds->settings[ALLEGRO_BLUE_SHIFT] == 0 && eds->settings[ALLEGRO_GREEN_SHIFT] == 5 && eds->settings[ALLEGRO_RED_SHIFT] == 10) { format = ALLEGRO_PIXEL_FORMAT_ARGB_1555; } } } else if (eds->settings[ALLEGRO_RED_SIZE] == 4 && eds->settings[ALLEGRO_GREEN_SIZE] == 4 && eds->settings[ALLEGRO_BLUE_SIZE] == 4) { if (eds->settings[ALLEGRO_ALPHA_SIZE] == 4 && eds->settings[ALLEGRO_COLOR_SIZE] == 16) { if (eds->settings[ALLEGRO_ALPHA_SHIFT] == 12 && eds->settings[ALLEGRO_BLUE_SHIFT] == 0 && eds->settings[ALLEGRO_GREEN_SHIFT] == 4 && eds->settings[ALLEGRO_RED_SHIFT] == 8) { format = ALLEGRO_PIXEL_FORMAT_ARGB_4444; } else if (eds->settings[ALLEGRO_ALPHA_SHIFT] == 12 && eds->settings[ALLEGRO_BLUE_SHIFT] == 8 && eds->settings[ALLEGRO_GREEN_SHIFT] == 4 && eds->settings[ALLEGRO_RED_SHIFT] == 0) { format = ALLEGRO_PIXEL_FORMAT_RGBA_4444; } } } if (format == ALLEGRO_PIXEL_FORMAT_ANY) { ALLEGRO_WARN( "Could not deduce color format, sizes = (%d,%d,%d,%d,%d), shifts = (%d,%d,%d,%d)\n", eds->settings[ALLEGRO_RED_SIZE], eds->settings[ALLEGRO_GREEN_SIZE], eds->settings[ALLEGRO_BLUE_SIZE], eds->settings[ALLEGRO_ALPHA_SIZE], eds->settings[ALLEGRO_COLOR_SIZE], eds->settings[ALLEGRO_RED_SHIFT], eds->settings[ALLEGRO_GREEN_SHIFT], eds->settings[ALLEGRO_BLUE_SHIFT], eds->settings[ALLEGRO_ALPHA_SHIFT]); } return format; } void _al_set_color_components(int format, ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds, int importance) { ALLEGRO_EXTRA_DISPLAY_SETTINGS old_eds; memcpy(&old_eds, _al_get_new_display_settings(), sizeof(old_eds)); _al_set_new_display_settings(eds); al_set_new_display_option(ALLEGRO_RED_SIZE, 0, ALLEGRO_DONTCARE); al_set_new_display_option(ALLEGRO_RED_SHIFT, 0, ALLEGRO_DONTCARE); al_set_new_display_option(ALLEGRO_GREEN_SIZE, 0, ALLEGRO_DONTCARE); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 0, ALLEGRO_DONTCARE); al_set_new_display_option(ALLEGRO_BLUE_SIZE, 0, ALLEGRO_DONTCARE); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 0, ALLEGRO_DONTCARE); al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 0, ALLEGRO_DONTCARE); al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 0, ALLEGRO_DONTCARE); al_set_new_display_option(ALLEGRO_COLOR_SIZE, 0, ALLEGRO_DONTCARE); switch (format) { case ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA: al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 0, importance); break; case ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA: al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 8, importance); break; case ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA: al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 0, importance); al_set_new_display_option(ALLEGRO_COLOR_SIZE, 16, importance); break; case ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA: al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 1, importance); al_set_new_display_option(ALLEGRO_COLOR_SIZE, 16, importance); break; case ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA: al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 0, importance); al_set_new_display_option(ALLEGRO_COLOR_SIZE, 24, importance); break; case ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA: /* With OpenGL drivers, we never "know" the actual pixel * format. We use glReadPixels when we lock the screen, so * we can always lock the screen in any format we want. There * is no "display format". * * Therefore it makes no sense to fail display creation * if either an RGB or RGBX format was requested but the * other seems available only in WGL/GLX (those really report * the number of bits used for red/green/blue/alpha to us only. * They never report any "X bits".). */ al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 0, importance); al_set_new_display_option(ALLEGRO_COLOR_SIZE, 32, ALLEGRO_SUGGEST); break; case ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA: al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 8, importance); al_set_new_display_option(ALLEGRO_COLOR_SIZE, 32, importance); break; } switch (format) { case ALLEGRO_PIXEL_FORMAT_RGBA_8888: case ALLEGRO_PIXEL_FORMAT_ABGR_8888: case ALLEGRO_PIXEL_FORMAT_ARGB_8888: case ALLEGRO_PIXEL_FORMAT_RGB_888: case ALLEGRO_PIXEL_FORMAT_BGR_888: case ALLEGRO_PIXEL_FORMAT_RGBX_8888: case ALLEGRO_PIXEL_FORMAT_XRGB_8888: case ALLEGRO_PIXEL_FORMAT_XBGR_8888: al_set_new_display_option(ALLEGRO_RED_SIZE, 8, importance); al_set_new_display_option(ALLEGRO_GREEN_SIZE, 8, importance); al_set_new_display_option(ALLEGRO_BLUE_SIZE, 8, importance); break; case ALLEGRO_PIXEL_FORMAT_BGR_565: case ALLEGRO_PIXEL_FORMAT_RGB_565: al_set_new_display_option(ALLEGRO_RED_SIZE, 5, importance); al_set_new_display_option(ALLEGRO_GREEN_SIZE, 6, importance); al_set_new_display_option(ALLEGRO_BLUE_SIZE, 5, importance); break; case ALLEGRO_PIXEL_FORMAT_RGBA_5551: case ALLEGRO_PIXEL_FORMAT_ARGB_1555: al_set_new_display_option(ALLEGRO_RED_SIZE, 5, importance); al_set_new_display_option(ALLEGRO_GREEN_SIZE, 5, importance); al_set_new_display_option(ALLEGRO_BLUE_SIZE, 5, importance); break; case ALLEGRO_PIXEL_FORMAT_ARGB_4444: case ALLEGRO_PIXEL_FORMAT_RGBA_4444: al_set_new_display_option(ALLEGRO_RED_SIZE, 4, importance); al_set_new_display_option(ALLEGRO_GREEN_SIZE, 4, importance); al_set_new_display_option(ALLEGRO_BLUE_SIZE, 4, importance); break; } switch (format) { case ALLEGRO_PIXEL_FORMAT_RGBA_8888: case ALLEGRO_PIXEL_FORMAT_ABGR_8888: case ALLEGRO_PIXEL_FORMAT_ARGB_8888: al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 8, importance); al_set_new_display_option(ALLEGRO_COLOR_SIZE, 32, importance); break; case ALLEGRO_PIXEL_FORMAT_RGB_888: case ALLEGRO_PIXEL_FORMAT_BGR_888: al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 0, importance); al_set_new_display_option(ALLEGRO_COLOR_SIZE, 24, importance); break; case ALLEGRO_PIXEL_FORMAT_RGBX_8888: case ALLEGRO_PIXEL_FORMAT_XRGB_8888: case ALLEGRO_PIXEL_FORMAT_XBGR_8888: al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 0, importance); al_set_new_display_option(ALLEGRO_COLOR_SIZE, 32, importance); break; case ALLEGRO_PIXEL_FORMAT_BGR_565: case ALLEGRO_PIXEL_FORMAT_RGB_565: al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 0, importance); al_set_new_display_option(ALLEGRO_COLOR_SIZE, 16, importance); break; case ALLEGRO_PIXEL_FORMAT_RGBA_5551: case ALLEGRO_PIXEL_FORMAT_ARGB_1555: al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 1, importance); al_set_new_display_option(ALLEGRO_COLOR_SIZE, 16, importance); break; case ALLEGRO_PIXEL_FORMAT_ARGB_4444: case ALLEGRO_PIXEL_FORMAT_RGBA_4444: al_set_new_display_option(ALLEGRO_ALPHA_SIZE, 4, importance); al_set_new_display_option(ALLEGRO_COLOR_SIZE, 16, importance); break; } switch (format) { case ALLEGRO_PIXEL_FORMAT_RGBA_8888: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 8, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 16, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 24, importance); break; case ALLEGRO_PIXEL_FORMAT_ABGR_8888: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 24, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 16, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 8, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 0, importance); break; case ALLEGRO_PIXEL_FORMAT_ARGB_8888: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 24, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 8, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 16, importance); break; case ALLEGRO_PIXEL_FORMAT_RGB_888: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 8, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 16, importance); break; case ALLEGRO_PIXEL_FORMAT_BGR_888: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 16, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 8, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 0, importance); break; case ALLEGRO_PIXEL_FORMAT_XRGB_8888: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 8, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 16, importance); break; case ALLEGRO_PIXEL_FORMAT_RGBX_8888: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 8, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 16, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 24, importance); break; case ALLEGRO_PIXEL_FORMAT_XBGR_8888: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 16, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 8, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 0, importance); break; case ALLEGRO_PIXEL_FORMAT_BGR_565: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 11, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 5, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 0, importance); break; case ALLEGRO_PIXEL_FORMAT_RGB_565: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 5, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 11, importance); break; case ALLEGRO_PIXEL_FORMAT_RGBA_5551: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 1, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 6, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 11, importance); break; case ALLEGRO_PIXEL_FORMAT_ARGB_1555: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 15, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 5, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 10, importance); break; case ALLEGRO_PIXEL_FORMAT_ARGB_4444: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 12, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 4, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 8, importance); break; case ALLEGRO_PIXEL_FORMAT_RGBA_4444: al_set_new_display_option(ALLEGRO_ALPHA_SHIFT, 0, importance); al_set_new_display_option(ALLEGRO_BLUE_SHIFT, 4, importance); al_set_new_display_option(ALLEGRO_GREEN_SHIFT, 8, importance); al_set_new_display_option(ALLEGRO_RED_SHIFT, 12, importance); break; } memcpy(eds, _al_get_new_display_settings(), sizeof(*eds)); _al_set_new_display_settings(&old_eds); } allegro5-5.2.10.1/src/drawing.c000066400000000000000000000043671473414355200160600ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Simple drawing primitives. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_memdraw.h" #include "allegro5/internal/aintern_pixels.h" /* Function: al_clear_to_color */ void al_clear_to_color(ALLEGRO_COLOR color) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); ASSERT(target); if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) { _al_clear_bitmap_by_locking(target, &color); } else { ALLEGRO_DISPLAY *display = _al_get_bitmap_display(target); ASSERT(display); ASSERT(display->vt); display->vt->clear(display, &color); } } /* Function: al_clear_depth_buffer */ void al_clear_depth_buffer(float z) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); ASSERT(target); if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP) { /* has no depth buffer */ } else { ALLEGRO_DISPLAY *display = _al_get_bitmap_display(target); ASSERT(display); display->vt->clear_depth_buffer(display, z); } } /* Function: al_draw_pixel */ void al_draw_pixel(float x, float y, ALLEGRO_COLOR color) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); ASSERT(target); if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) { _al_draw_pixel_memory(target, x, y, &color); } else { ALLEGRO_DISPLAY *display = _al_get_bitmap_display(target); ASSERT(display); ASSERT(display->vt); display->vt->draw_pixel(display, x, y, &color); } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/dtor.c000066400000000000000000000151131473414355200153640ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Destructors. * * By Peter Wang. * * See readme.txt for copyright information. */ /* Title: Destructors * * This file records a list of objects created by the user and/or Allegro * itself, that need to be destroyed when Allegro is shut down. Strictly * speaking, this list should not be necessary if the user is careful to * destroy all the objects he creates. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_thread.h" #include "allegro5/internal/aintern_tls.h" #include "allegro5/internal/aintern_list.h" /* XXX The dependency on tls.c is not nice but the DllMain stuff for Windows * does not it easy to make abstract away TLS API differences. */ ALLEGRO_DEBUG_CHANNEL("dtor") struct _AL_DTOR_LIST { _AL_MUTEX mutex; _AL_LIST* dtors; }; typedef struct DTOR { char const *name; void *object; void (*func)(void*); } DTOR; /* Internal function: _al_init_destructors * Initialise a list of destructors. */ _AL_DTOR_LIST *_al_init_destructors(void) { _AL_DTOR_LIST *dtors = al_malloc(sizeof(*dtors)); _AL_MARK_MUTEX_UNINITED(dtors->mutex); _al_mutex_init(&dtors->mutex); dtors->dtors = _al_list_create(); return dtors; } /* _al_push_destructor_owner: * Increase the owner count for the current thread. When it is greater than * zero, _al_register_destructor will do nothing. * * This is required if an object to-be-registered (B) should be "owned" by an * object (A), which is responsible for destroying (B). (B) should not be * destroyed independently of (A). */ void _al_push_destructor_owner(void) { int *dtor_owner_count = _al_tls_get_dtor_owner_count(); (*dtor_owner_count)++; } /* _al_push_destructor_owner: * Decrease the owner count for the current thread. */ void _al_pop_destructor_owner(void) { int *dtor_owner_count = _al_tls_get_dtor_owner_count(); (*dtor_owner_count)--; ASSERT(*dtor_owner_count >= 0); } /* _al_run_destructors: * Run all the destructors on the list in reverse order. */ void _al_run_destructors(_AL_DTOR_LIST *dtors) { if (!dtors) { return; } /* call the destructors in reverse order */ _al_mutex_lock(&dtors->mutex); { _AL_LIST_ITEM *iter = _al_list_back(dtors->dtors); while (iter) { DTOR *dtor = _al_list_item_data(iter); void *object = dtor->object; void (*func)(void *) = dtor->func; ALLEGRO_DEBUG("calling dtor for %s %p, func %p\n", dtor->name, object, func); _al_mutex_unlock(&dtors->mutex); { (*func)(object); } _al_mutex_lock(&dtors->mutex); /* Don't do normal iteration as the destructors will possibly run * multiple destructors at once. */ iter = _al_list_back(dtors->dtors); } } _al_mutex_unlock(&dtors->mutex); } /* _al_shutdown_destructors: * Free the list of destructors. The list should be empty now. */ void _al_shutdown_destructors(_AL_DTOR_LIST *dtors) { if (!dtors) { return; } /* free resources used by the destructor subsystem */ ASSERT(_al_list_is_empty(dtors->dtors)); _al_list_destroy(dtors->dtors); _al_mutex_destroy(&dtors->mutex); al_free(dtors); } /* Internal function: _al_register_destructor * Register OBJECT to be destroyed by FUNC during Allegro shutdown. * This would be done in the object's constructor function. * * Returns a list item representing the destructor's position in the list * (possibly null). * * [thread-safe] */ _AL_LIST_ITEM *_al_register_destructor(_AL_DTOR_LIST *dtors, char const *name, void *object, void (*func)(void*)) { int *dtor_owner_count; _AL_LIST_ITEM *ret = NULL; ASSERT(object); ASSERT(func); dtor_owner_count = _al_tls_get_dtor_owner_count(); if (*dtor_owner_count > 0) return NULL; _al_mutex_lock(&dtors->mutex); { #ifdef DEBUGMODE /* make sure the object is not registered twice */ { _AL_LIST_ITEM *iter = _al_list_front(dtors->dtors); while (iter) { DTOR *dtor = _al_list_item_data(iter); ASSERT(dtor->object != object); iter = _al_list_next(dtors->dtors, iter); } } #endif /* DEBUGMODE */ /* add the destructor to the list */ { DTOR *new_dtor = al_malloc(sizeof(DTOR)); if (new_dtor) { new_dtor->object = object; new_dtor->func = func; new_dtor->name = name; ALLEGRO_DEBUG("added dtor for %s %p, func %p\n", name, object, func); ret = _al_list_push_back(dtors->dtors, new_dtor); } else { ALLEGRO_WARN("failed to add dtor for %s %p\n", name, object); } } } _al_mutex_unlock(&dtors->mutex); return ret; } /* Internal function: _al_unregister_destructor * Unregister a previously registered object. This must be called * in the normal object destroyer routine, e.g. al_destroy_timer. * * [thread-safe] */ void _al_unregister_destructor(_AL_DTOR_LIST *dtors, _AL_LIST_ITEM *dtor_item) { if (!dtor_item) { return; } _al_mutex_lock(&dtors->mutex); { DTOR *dtor = _al_list_item_data(dtor_item); ALLEGRO_DEBUG("removed dtor for %s %p\n", dtor->name, dtor->object); al_free(dtor); _al_list_erase(dtors->dtors, dtor_item); } _al_mutex_unlock(&dtors->mutex); } /* Internal function: _al_foreach_destructor * Call the callback for each registered object. * [thread-safe] */ void _al_foreach_destructor(_AL_DTOR_LIST *dtors, void (*callback)(void *object, void (*func)(void *), void *udata), void *userdata) { _al_mutex_lock(&dtors->mutex); { _AL_LIST_ITEM *iter = _al_list_front(dtors->dtors); while (iter) { DTOR *dtor = _al_list_item_data(iter); callback(dtor->object, dtor->func, userdata); iter = _al_list_next(dtors->dtors, iter); } } _al_mutex_unlock(&dtors->mutex); } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/events.c000066400000000000000000000413261473414355200157250ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Event queues. * * By Peter Wang. * * See readme.txt for copyright information. */ /* Title: Event queues * * An event queue buffers events generated by event sources that were * registered with the queue. */ #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_system.h" struct ALLEGRO_EVENT_QUEUE { _AL_VECTOR sources; /* vector of (ALLEGRO_EVENT_SOURCE *) */ _AL_VECTOR events; /* vector of ALLEGRO_EVENT, used as circular array */ unsigned int events_head; /* write end of circular array */ unsigned int events_tail; /* read end of circular array */ bool paused; _AL_MUTEX mutex; _AL_COND cond; _AL_LIST_ITEM *dtor_item; }; /* to prevent concurrent modification of user event reference counts */ static _AL_MUTEX user_event_refcount_mutex = _AL_MUTEX_UNINITED; /* forward declarations */ static void shutdown_events(void); static bool do_wait_for_event(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT *ret_event, ALLEGRO_TIMEOUT *timeout); static void copy_event(ALLEGRO_EVENT *dest, const ALLEGRO_EVENT *src); static void ref_if_user_event(ALLEGRO_EVENT *event); static void unref_if_user_event(ALLEGRO_EVENT *event); static void discard_events_of_source(ALLEGRO_EVENT_QUEUE *queue, const ALLEGRO_EVENT_SOURCE *source); /* _al_init_events: * Initialise globals for the event system. */ void _al_init_events(void) { _al_mutex_init(&user_event_refcount_mutex); _al_add_exit_func(shutdown_events, "shutdown_events"); } /* shutdown_events: * Clean up after _al_init_events. */ static void shutdown_events(void) { _al_mutex_destroy(&user_event_refcount_mutex); } /* Function: al_create_event_queue */ ALLEGRO_EVENT_QUEUE *al_create_event_queue(void) { ALLEGRO_EVENT_QUEUE *queue = al_malloc(sizeof *queue); ASSERT(queue); if (queue) { _al_vector_init(&queue->sources, sizeof(ALLEGRO_EVENT_SOURCE *)); _al_vector_init(&queue->events, sizeof(ALLEGRO_EVENT)); _al_vector_alloc_back(&queue->events); queue->events_head = 0; queue->events_tail = 0; queue->paused = false; _AL_MARK_MUTEX_UNINITED(queue->mutex); _al_mutex_init(&queue->mutex); _al_cond_init(&queue->cond); queue->dtor_item = _al_register_destructor(_al_dtor_list, "queue", queue, (void (*)(void *)) al_destroy_event_queue); } return queue; } /* Function: al_destroy_event_queue */ void al_destroy_event_queue(ALLEGRO_EVENT_QUEUE *queue) { if (queue) { _al_unregister_destructor(_al_dtor_list, queue->dtor_item); /* Unregister any event sources registered with this queue. */ while (_al_vector_is_nonempty(&queue->sources)) { ALLEGRO_EVENT_SOURCE** slot = _al_vector_ref_back(&queue->sources); al_unregister_event_source(queue, *slot); } ASSERT(_al_vector_is_empty(&queue->sources)); _al_vector_free(&queue->sources); ASSERT(queue->events_head == queue->events_tail); _al_vector_free(&queue->events); _al_cond_destroy(&queue->cond); _al_mutex_destroy(&queue->mutex); al_free(queue); } } /* Function: al_is_event_source_registered */ bool al_is_event_source_registered(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT_SOURCE *source) { ASSERT(queue); ASSERT(source); if(_al_vector_contains(&queue->sources, &source)) return true; else return false; } /* Function: al_register_event_source */ void al_register_event_source(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT_SOURCE *source) { ALLEGRO_EVENT_SOURCE **slot; ASSERT(queue); ASSERT(source); if (!_al_vector_contains(&queue->sources, &source)) { _al_event_source_on_registration_to_queue(source, queue); _al_mutex_lock(&queue->mutex); slot = _al_vector_alloc_back(&queue->sources); *slot = source; _al_mutex_unlock(&queue->mutex); } } /* Function: al_unregister_event_source */ void al_unregister_event_source(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT_SOURCE *source) { bool found; ASSERT(queue); ASSERT(source); /* Remove source from our list. */ _al_mutex_lock(&queue->mutex); found = _al_vector_find_and_delete(&queue->sources, &source); _al_mutex_unlock(&queue->mutex); if (found) { /* Tell the event source that it was unregistered. */ _al_event_source_on_unregistration_from_queue(source, queue); /* Drop all the events in the queue that belonged to the source. */ _al_mutex_lock(&queue->mutex); discard_events_of_source(queue, source); _al_mutex_unlock(&queue->mutex); } } /* Function: al_pause_event_queue */ void al_pause_event_queue(ALLEGRO_EVENT_QUEUE *queue, bool pause) { ASSERT(queue); _al_mutex_lock(&queue->mutex); queue->paused = pause; _al_mutex_unlock(&queue->mutex); } /* Function: al_is_event_queue_paused */ bool al_is_event_queue_paused(const ALLEGRO_EVENT_QUEUE *queue) { ASSERT(queue); return queue->paused; } static void heartbeat(void) { ALLEGRO_SYSTEM *system = al_get_system_driver(); if (system->vt->heartbeat) system->vt->heartbeat(); } static bool is_event_queue_empty(ALLEGRO_EVENT_QUEUE *queue) { return (queue->events_head == queue->events_tail); } /* Function: al_is_event_queue_empty */ bool al_is_event_queue_empty(ALLEGRO_EVENT_QUEUE *queue) { ASSERT(queue); heartbeat(); _al_mutex_lock(&queue->mutex); bool ret = is_event_queue_empty(queue); _al_mutex_unlock(&queue->mutex); return ret; } /* circ_array_next: * Return the next index in a circular array. */ static unsigned int circ_array_next(const _AL_VECTOR *vector, unsigned int i) { return (i + 1) % _al_vector_size(vector); } /* get_next_event_if_any: [primary thread] * Helper function. It returns a pointer to the next event in the * queue, or NULL. Optionally the event is removed from the queue. * However, the event is _not released_ (which is the caller's * responsibility). The event queue must be locked before entering * this function. */ static ALLEGRO_EVENT *get_next_event_if_any(ALLEGRO_EVENT_QUEUE *queue, bool delete) { ALLEGRO_EVENT *event; if (is_event_queue_empty(queue)) { return NULL; } event = _al_vector_ref(&queue->events, queue->events_tail); if (delete) { queue->events_tail = circ_array_next(&queue->events, queue->events_tail); } return event; } /* Function: al_get_next_event */ bool al_get_next_event(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT *ret_event) { ALLEGRO_EVENT *next_event; ASSERT(queue); ASSERT(ret_event); heartbeat(); _al_mutex_lock(&queue->mutex); next_event = get_next_event_if_any(queue, true); if (next_event) { copy_event(ret_event, next_event); /* Don't increment reference count on user events. */ } _al_mutex_unlock(&queue->mutex); return (next_event ? true : false); } /* Function: al_peek_next_event */ bool al_peek_next_event(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT *ret_event) { ALLEGRO_EVENT *next_event; ASSERT(queue); ASSERT(ret_event); heartbeat(); _al_mutex_lock(&queue->mutex); next_event = get_next_event_if_any(queue, false); if (next_event) { copy_event(ret_event, next_event); ref_if_user_event(ret_event); } _al_mutex_unlock(&queue->mutex); return (next_event ? true : false); } /* Function: al_drop_next_event */ bool al_drop_next_event(ALLEGRO_EVENT_QUEUE *queue) { ALLEGRO_EVENT *next_event; ASSERT(queue); heartbeat(); _al_mutex_lock(&queue->mutex); next_event = get_next_event_if_any(queue, true); if (next_event) { unref_if_user_event(next_event); } _al_mutex_unlock(&queue->mutex); return (next_event ? true : false); } /* Function: al_flush_event_queue */ void al_flush_event_queue(ALLEGRO_EVENT_QUEUE *queue) { unsigned int i; ASSERT(queue); heartbeat(); _al_mutex_lock(&queue->mutex); /* Decrement reference counts on all user events. */ i = queue->events_tail; while (i != queue->events_head) { ALLEGRO_EVENT *old_ev = _al_vector_ref(&queue->events, i); unref_if_user_event(old_ev); i = circ_array_next(&queue->events, i); } queue->events_head = queue->events_tail = 0; _al_mutex_unlock(&queue->mutex); } /* [primary thread] */ /* Function: al_wait_for_event */ void al_wait_for_event(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT *ret_event) { ALLEGRO_EVENT *next_event = NULL; ASSERT(queue); heartbeat(); _al_mutex_lock(&queue->mutex); { while (is_event_queue_empty(queue)) { #ifdef ALLEGRO_WAIT_EVENT_SLEEP al_rest(0.001); heartbeat(); #else _al_cond_wait(&queue->cond, &queue->mutex); #endif } if (ret_event) { next_event = get_next_event_if_any(queue, true); copy_event(ret_event, next_event); } } _al_mutex_unlock(&queue->mutex); } /* [primary thread] */ /* Function: al_wait_for_event_timed */ bool al_wait_for_event_timed(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT *ret_event, float secs) { ALLEGRO_TIMEOUT timeout; ASSERT(queue); ASSERT(secs >= 0); heartbeat(); if (secs < 0.0) al_init_timeout(&timeout, 0); else al_init_timeout(&timeout, secs); return do_wait_for_event(queue, ret_event, &timeout); } /* Function: al_wait_for_event_until */ bool al_wait_for_event_until(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT *ret_event, ALLEGRO_TIMEOUT *timeout) { ASSERT(queue); heartbeat(); return do_wait_for_event(queue, ret_event, timeout); } static bool do_wait_for_event(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT *ret_event, ALLEGRO_TIMEOUT *timeout) { bool timed_out = false; ALLEGRO_EVENT *next_event = NULL; _al_mutex_lock(&queue->mutex); { int result = 0; /* Is the queue is non-empty? If not, block on a condition * variable, which will be signaled when an event is placed into * the queue. */ while (is_event_queue_empty(queue) && (result != -1)) { result = _al_cond_timedwait(&queue->cond, &queue->mutex, timeout); } if (result == -1) timed_out = true; else if (ret_event) { next_event = get_next_event_if_any(queue, true); copy_event(ret_event, next_event); } } _al_mutex_unlock(&queue->mutex); if (timed_out) return false; return true; } /* expand_events_array: * Expand the circular array holding events. */ static void expand_events_array(ALLEGRO_EVENT_QUEUE *queue) { /* The underlying vector grows by powers of two. */ const size_t old_size = _al_vector_size(&queue->events); const size_t new_size = old_size * 2; unsigned int i; for (i = old_size; i < new_size; i++) { _al_vector_alloc_back(&queue->events); } /* Move wrapped-around elements at the start of the array to the back. */ if (queue->events_head < queue->events_tail) { for (i = 0; i < queue->events_head; i++) { ALLEGRO_EVENT *old_ev = _al_vector_ref(&queue->events, i); ALLEGRO_EVENT *new_ev = _al_vector_ref(&queue->events, old_size + i); copy_event(new_ev, old_ev); } queue->events_head += old_size; } } /* alloc_event: * * The event source must be _locked_ before calling this function. * * [runs in background threads] */ static ALLEGRO_EVENT *alloc_event(ALLEGRO_EVENT_QUEUE *queue) { ALLEGRO_EVENT *event; unsigned int adv_head; adv_head = circ_array_next(&queue->events, queue->events_head); if (adv_head == queue->events_tail) { expand_events_array(queue); adv_head = circ_array_next(&queue->events, queue->events_head); } event = _al_vector_ref(&queue->events, queue->events_head); queue->events_head = adv_head; return event; } /* copy_event: * Copies the contents of the event SRC to DEST. */ static void copy_event(ALLEGRO_EVENT *dest, const ALLEGRO_EVENT *src) { ASSERT(dest); ASSERT(src); *dest = *src; } /* Increment a user event's reference count, if the event passed is a user * event and requires it. */ static void ref_if_user_event(ALLEGRO_EVENT *event) { if (ALLEGRO_EVENT_TYPE_IS_USER(event->type)) { ALLEGRO_USER_EVENT_DESCRIPTOR *descr = event->user.__internal__descr; if (descr) { _al_mutex_lock(&user_event_refcount_mutex); descr->refcount++; _al_mutex_unlock(&user_event_refcount_mutex); } } } /* Decrement a user event's reference count, if the event passed is a user * event and requires it. */ static void unref_if_user_event(ALLEGRO_EVENT *event) { if (ALLEGRO_EVENT_TYPE_IS_USER(event->type)) { al_unref_user_event(&event->user); } } /* Internal function: _al_event_queue_push_event * Event sources call this function when they have something to add to * the queue. If a queue cannot accept the event, the event's * refcount will not be incremented. * * If no event queues can accept the event, the event should be * returned to the event source's list of recyclable events. */ void _al_event_queue_push_event(ALLEGRO_EVENT_QUEUE *queue, const ALLEGRO_EVENT *orig_event) { ALLEGRO_EVENT *new_event; ASSERT(queue); ASSERT(orig_event); if (queue->paused) return; _al_mutex_lock(&queue->mutex); { new_event = alloc_event(queue); copy_event(new_event, orig_event); ref_if_user_event(new_event); /* Wake up threads that are waiting for an event to be placed in * the queue. */ _al_cond_broadcast(&queue->cond); } _al_mutex_unlock(&queue->mutex); } /* contains_event_of_source: * Return true iff the event queue contains an event from the given source. * The queue must be locked. */ static bool contains_event_of_source(const ALLEGRO_EVENT_QUEUE *queue, const ALLEGRO_EVENT_SOURCE *source) { ALLEGRO_EVENT *event; unsigned int i; i = queue->events_tail; while (i != queue->events_head) { event = _al_vector_ref(&queue->events, i); if (event->any.source == source) { return true; } i = circ_array_next(&queue->events, i); } return false; } /* Helper to get smallest fitting power of two. */ static int pot(int x) { int y = 1; while (y < x) y *= 2; return y; } /* discard_events_of_source: * Discard all the events in the queue that belong to the source. * The queue must be locked. */ static void discard_events_of_source(ALLEGRO_EVENT_QUEUE *queue, const ALLEGRO_EVENT_SOURCE *source) { _AL_VECTOR old_events; ALLEGRO_EVENT *old_event; ALLEGRO_EVENT *new_event; size_t old_size; size_t new_size; unsigned int i; if (!contains_event_of_source(queue, source)) { return; } /* Copy elements we want to keep from the old vector to a new one. */ old_events = queue->events; _al_vector_init(&queue->events, sizeof(ALLEGRO_EVENT)); i = queue->events_tail; while (i != queue->events_head) { old_event = _al_vector_ref(&old_events, i); if (old_event->any.source != source) { new_event = _al_vector_alloc_back(&queue->events); copy_event(new_event, old_event); } else { unref_if_user_event(old_event); } i = circ_array_next(&old_events, i); } queue->events_tail = 0; queue->events_head = _al_vector_size(&queue->events); /* The circular array always needs at least one unused element. */ old_size = _al_vector_size(&queue->events); new_size = pot(old_size + 1); for (i = old_size; i < new_size; i++) { _al_vector_alloc_back(&queue->events); } _al_vector_free(&old_events); } /* Function: al_unref_user_event */ void al_unref_user_event(ALLEGRO_USER_EVENT *event) { ALLEGRO_USER_EVENT_DESCRIPTOR *descr; int refcount; ASSERT(event); descr = event->__internal__descr; if (descr) { _al_mutex_lock(&user_event_refcount_mutex); ASSERT(descr->refcount > 0); refcount = --descr->refcount; _al_mutex_unlock(&user_event_refcount_mutex); if (refcount == 0) { (descr->dtor)(event); al_free(descr); } } } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/evtsrc.c000066400000000000000000000163271473414355200157320ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Event sources. * * By Peter Wang. * * See readme.txt for copyright information. */ /* Title: Event sources */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_system.h" ALLEGRO_STATIC_ASSERT(evtsrc, sizeof(ALLEGRO_EVENT_SOURCE_REAL) <= sizeof(ALLEGRO_EVENT_SOURCE)); /* Internal function: _al_event_source_init * Initialise an event source structure. */ void _al_event_source_init(ALLEGRO_EVENT_SOURCE *es) { ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es; memset(es, 0, sizeof(*es)); _AL_MARK_MUTEX_UNINITED(this->mutex); _al_mutex_init(&this->mutex); _al_vector_init(&this->queues, sizeof(ALLEGRO_EVENT_QUEUE *)); this->data = 0; } /* Internal function: _al_event_source_free * Free the resources using by an event source structure. It * automatically unregisters the event source from all the event * queues it is currently registered with. */ void _al_event_source_free(ALLEGRO_EVENT_SOURCE *es) { ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es; /* Unregister from all queues. */ while (!_al_vector_is_empty(&this->queues)) { ALLEGRO_EVENT_QUEUE **slot = _al_vector_ref_back(&this->queues); al_unregister_event_source(*slot, es); } _al_vector_free(&this->queues); _al_mutex_destroy(&this->mutex); } /* Internal function: _al_event_source_lock * Lock the event source. See below for when you should call this function. */ void _al_event_source_lock(ALLEGRO_EVENT_SOURCE *es) { ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es; _al_mutex_lock(&this->mutex); } /* Internal function: _al_event_source_unlock * Unlock the event source. */ void _al_event_source_unlock(ALLEGRO_EVENT_SOURCE *es) { ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es; _al_mutex_unlock(&this->mutex); } /* Internal function: _al_event_source_on_registration_to_queue * This function is called by al_register_event_source() when an * event source is registered to an event queue. This gives the * event source a chance to remember which queues it is registered * to. */ void _al_event_source_on_registration_to_queue(ALLEGRO_EVENT_SOURCE *es, ALLEGRO_EVENT_QUEUE *queue) { _al_event_source_lock(es); { ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es; /* Add the queue to the source's list. */ ALLEGRO_EVENT_QUEUE **slot = _al_vector_alloc_back(&this->queues); *slot = queue; } _al_event_source_unlock(es); } /* Internal function: _al_event_source_on_unregistration_from_queue * This function is called by al_unregister_event_source() when an * event source is unregistered from a queue. */ void _al_event_source_on_unregistration_from_queue(ALLEGRO_EVENT_SOURCE *es, ALLEGRO_EVENT_QUEUE *queue) { _al_event_source_lock(es); { ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es; _al_vector_find_and_delete(&this->queues, &queue); } _al_event_source_unlock(es); } /* Internal function: _al_event_source_needs_to_generate_event * This function is called by modules that implement event sources * when some interesting thing happens. They call this to check if * they should bother generating an event of the given type, i.e. if * the given event source is actually registered with one or more * event queues. This is an optimisation to avoid allocating and * filling in unwanted event structures. * * The event source must be _locked_ before calling this function. * * [runs in background threads] */ bool _al_event_source_needs_to_generate_event(ALLEGRO_EVENT_SOURCE *es) { ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es; /* We don't consider pausing of event queues, but it does not seem worth * optimising for. */ return !_al_vector_is_empty(&this->queues); } /* Internal function: _al_event_source_emit_event * After an event structure has been filled in, it is time for the * event source to tell the event queues it knows of about the new * event. Afterwards, the caller of this function should not touch * the event any more. * * The event source must be _locked_ before calling this function. * * [runs in background threads] */ void _al_event_source_emit_event(ALLEGRO_EVENT_SOURCE *es, ALLEGRO_EVENT *event) { ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es; event->any.source = es; /* Push the event to all the queues that this event source is * registered to. */ { size_t num_queues = _al_vector_size(&this->queues); unsigned int i; ALLEGRO_EVENT_QUEUE **slot; for (i = 0; i < num_queues; i++) { slot = _al_vector_ref(&this->queues, i); _al_event_queue_push_event(*slot, event); } } } /* Function: al_init_user_event_source */ void al_init_user_event_source(ALLEGRO_EVENT_SOURCE *src) { ASSERT(src); _al_event_source_init(src); } /* Function: al_destroy_user_event_source */ void al_destroy_user_event_source(ALLEGRO_EVENT_SOURCE *src) { if (src) { _al_event_source_free(src); } } /* Function: al_emit_user_event */ bool al_emit_user_event(ALLEGRO_EVENT_SOURCE *src, ALLEGRO_EVENT *event, void (*dtor)(ALLEGRO_USER_EVENT *)) { size_t num_queues; bool rc; ASSERT(src); ASSERT(event); if (dtor) { ALLEGRO_USER_EVENT_DESCRIPTOR *descr = al_malloc(sizeof(*descr)); descr->refcount = 0; descr->dtor = dtor; event->user.__internal__descr = descr; } else { event->user.__internal__descr = NULL; } _al_event_source_lock(src); { ALLEGRO_EVENT_SOURCE_REAL *rsrc = (ALLEGRO_EVENT_SOURCE_REAL *)src; num_queues = _al_vector_size(&rsrc->queues); if (num_queues > 0) { event->any.timestamp = al_get_time(); _al_event_source_emit_event(src, event); rc = true; } else { rc = false; } } _al_event_source_unlock(src); if (dtor && !rc) { dtor(&event->user); al_free(event->user.__internal__descr); } return rc; } /* Function: al_set_event_source_data */ void al_set_event_source_data(ALLEGRO_EVENT_SOURCE *source, intptr_t data) { ALLEGRO_EVENT_SOURCE_REAL *const rsource = (ALLEGRO_EVENT_SOURCE_REAL *)source; rsource->data = data; } /* Function: al_get_event_source_data */ intptr_t al_get_event_source_data(const ALLEGRO_EVENT_SOURCE *source) { const ALLEGRO_EVENT_SOURCE_REAL *const rsource = (ALLEGRO_EVENT_SOURCE_REAL *)source; return rsource->data; } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/exitfunc.c000066400000000000000000000043501473414355200162420ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * List of functions to call at program cleanup. * * By Shawn Hargreaves. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_exitfunc.h" /* dynamic registration system for cleanup code */ struct al_exit_func { void (*funcptr)(void); const char *desc; struct al_exit_func *next; }; static struct al_exit_func *exit_func_list = NULL; /* _al_add_exit_func: * Adds a function to the list that need to be called on Allegro shutdown. * `desc' should point to a statically allocated string to help with * debugging. */ void _al_add_exit_func(void (*func)(void), const char *desc) { struct al_exit_func *n; for (n = exit_func_list; n; n = n->next) if (n->funcptr == func) return; n = al_malloc(sizeof(struct al_exit_func)); if (!n) return; n->next = exit_func_list; n->funcptr = func; n->desc = desc; exit_func_list = n; } /* _al_remove_exit_func: * Removes a function from the list that need to be called on Allegro * shutdown. */ void _al_remove_exit_func(void (*func)(void)) { struct al_exit_func *iter = exit_func_list, *prev = NULL; while (iter) { if (iter->funcptr == func) { if (prev) prev->next = iter->next; else exit_func_list = iter->next; al_free(iter); return; } prev = iter; iter = iter->next; } } /* _al_run_exit_funcs: * Run all the functions registered with _al_add_exit_func, in reverse order of * registration. */ void _al_run_exit_funcs(void) { while (exit_func_list) { void (*func)(void) = exit_func_list->funcptr; _al_remove_exit_func(func); (*func)(); } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/file.c000066400000000000000000000237001473414355200153340ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * File I/O routines. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_file.h" /* Function: al_fopen */ ALLEGRO_FILE *al_fopen(const char *path, const char *mode) { return al_fopen_interface(al_get_new_file_interface(), path, mode); } /* Function: al_fopen_interface */ ALLEGRO_FILE *al_fopen_interface(const ALLEGRO_FILE_INTERFACE *drv, const char *path, const char *mode) { ALLEGRO_FILE *f = NULL; ASSERT(drv); ASSERT(path); ASSERT(mode); if (drv->fi_fopen) { f = al_malloc(sizeof(*f)); if (!f) { al_set_errno(ENOMEM); } else { f->vtable = drv; f->userdata = drv->fi_fopen(path, mode); f->ungetc_len = 0; if (!f->userdata) { al_free(f); f = NULL; } } } return f; } /* Function: al_create_file_handle */ ALLEGRO_FILE *al_create_file_handle(const ALLEGRO_FILE_INTERFACE *drv, void *userdata) { ALLEGRO_FILE *f; ASSERT(drv); f = al_malloc(sizeof(*f)); if (!f) { al_set_errno(ENOMEM); } else { f->vtable = drv; f->userdata = userdata; f->ungetc_len = 0; } return f; } /* Function: al_fclose */ bool al_fclose(ALLEGRO_FILE *f) { if (f) { bool ret = f->vtable->fi_fclose(f); al_free(f); return ret; } al_set_errno(EINVAL); return false; } /* Function: al_fread */ size_t al_fread(ALLEGRO_FILE *f, void *ptr, size_t size) { ASSERT(f); ASSERT(ptr || size == 0); if (f->ungetc_len) { int bytes_ungetc = 0; unsigned char *cptr = ptr; while (f->ungetc_len > 0 && size > 0) { *cptr++ = f->ungetc[--f->ungetc_len]; ++bytes_ungetc; --size; } return bytes_ungetc + f->vtable->fi_fread(f, cptr, size); } else { return f->vtable->fi_fread(f, ptr, size); } } /* Function: al_fwrite */ size_t al_fwrite(ALLEGRO_FILE *f, const void *ptr, size_t size) { ASSERT(f); ASSERT(ptr || size == 0); f->ungetc_len = 0; return f->vtable->fi_fwrite(f, ptr, size); } /* Function: al_fflush */ bool al_fflush(ALLEGRO_FILE *f) { ASSERT(f); return f->vtable->fi_fflush(f); } /* Function: al_ftell */ int64_t al_ftell(ALLEGRO_FILE *f) { ASSERT(f); return f->vtable->fi_ftell(f) - f->ungetc_len; } /* Function: al_fseek */ bool al_fseek(ALLEGRO_FILE *f, int64_t offset, int whence) { ASSERT(f); /* offset can be negative */ ASSERT( whence == ALLEGRO_SEEK_SET || whence == ALLEGRO_SEEK_CUR || whence == ALLEGRO_SEEK_END ); if (f->ungetc_len) { if (whence == ALLEGRO_SEEK_CUR) { offset -= f->ungetc_len; } f->ungetc_len = 0; } return f->vtable->fi_fseek(f, offset, whence); } /* Function: al_feof */ bool al_feof(ALLEGRO_FILE *f) { ASSERT(f); return f->ungetc_len == 0 && f->vtable->fi_feof(f); } /* Function: al_ferror */ int al_ferror(ALLEGRO_FILE *f) { ASSERT(f); return f->vtable->fi_ferror(f); } /* Function: al_ferrmsg */ const char *al_ferrmsg(ALLEGRO_FILE *f) { const char *msg; ASSERT(f); msg = f->vtable->fi_ferrmsg(f); ASSERT(msg); return msg; } /* Function: al_fclearerr */ void al_fclearerr(ALLEGRO_FILE *f) { ASSERT(f); f->vtable->fi_fclearerr(f); } /* Function: al_fgetc */ int al_fgetc(ALLEGRO_FILE *f) { uint8_t c; ASSERT(f); if (al_fread(f, &c, 1) != 1) { return EOF; } return c; } /* Function: al_fputc */ int al_fputc(ALLEGRO_FILE *f, int c) { uint8_t b = (c & 0xff); ASSERT(f); if (al_fwrite(f, &b, 1) != 1) { return EOF; } return b; } /* Function: al_fread16le */ int16_t al_fread16le(ALLEGRO_FILE *f) { unsigned char b[2]; ASSERT(f); if (al_fread(f, b, 2) == 2) { return (((int16_t)b[1] << 8) | (int16_t)b[0]); } return EOF; } /* Function: al_fread32le */ int32_t al_fread32le(ALLEGRO_FILE *f) { unsigned char b[4]; ASSERT(f); if (al_fread(f, b, 4) == 4) { return (((int32_t)b[3] << 24) | ((int32_t)b[2] << 16) | ((int32_t)b[1] << 8) | (int32_t)b[0]); } return EOF; } /* Function: al_fwrite16le */ size_t al_fwrite16le(ALLEGRO_FILE *f, int16_t w) { uint8_t b1, b2; ASSERT(f); b1 = (w & 0xFF00) >> 8; b2 = w & 0x00FF; if (al_fputc(f, b2) == b2) { if (al_fputc(f, b1) == b1) { return 2; } return 1; } return 0; } /* Function: al_fwrite32le */ size_t al_fwrite32le(ALLEGRO_FILE *f, int32_t l) { uint8_t b1, b2, b3, b4; ASSERT(f); b1 = ((l & 0xFF000000L) >> 24); b2 = ((l & 0x00FF0000L) >> 16); b3 = ((l & 0x0000FF00L) >> 8); b4 = l & 0x00FF; if (al_fputc(f, b4) == b4) { if (al_fputc(f, b3) == b3) { if (al_fputc(f, b2) == b2) { if (al_fputc(f, b1) == b1) { return 4; } return 3; } return 2; } return 1; } return 0; } /* Function: al_fread16be */ int16_t al_fread16be(ALLEGRO_FILE *f) { unsigned char b[2]; ASSERT(f); if (al_fread(f, b, 2) == 2) { return (((int16_t)b[0] << 8) | (int16_t)b[1]); } return EOF; } /* Function: al_fread32be */ int32_t al_fread32be(ALLEGRO_FILE *f) { unsigned char b[4]; ASSERT(f); if (al_fread(f, b, 4) == 4) { return (((int32_t)b[0] << 24) | ((int32_t)b[1] << 16) | ((int32_t)b[2] << 8) | (int32_t)b[3]); } return EOF; } /* Function: al_fwrite16be */ size_t al_fwrite16be(ALLEGRO_FILE *f, int16_t w) { uint8_t b1, b2; ASSERT(f); b1 = (w & 0xFF00) >> 8; b2 = w & 0x00FF; if (al_fputc(f, b1) == b1) { if (al_fputc(f, b2) == b2) { return 2; } return 1; } return 0; } /* Function: al_fwrite32be */ size_t al_fwrite32be(ALLEGRO_FILE *f, int32_t l) { uint8_t b1, b2, b3, b4; ASSERT(f); b1 = ((l & 0xFF000000L) >> 24); b2 = ((l & 0x00FF0000L) >> 16); b3 = ((l & 0x0000FF00L) >> 8); b4 = l & 0x00FF; if (al_fputc(f, b1) == b1) { if (al_fputc(f, b2) == b2) { if (al_fputc(f, b3) == b3) { if (al_fputc(f, b4) == b4) { return 4; } return 3; } return 2; } return 1; } return 0; } /* Function: al_fgets */ char *al_fgets(ALLEGRO_FILE *f, char * const buf, size_t max) { char *p = buf; int c; ASSERT(f); ASSERT(buf); /* Handle silly cases. */ if (max == 0) { return NULL; } if (max == 1) { *buf = '\0'; return buf; } /* Return NULL if already at end of file. */ if ((c = al_fgetc(f)) == EOF) { return NULL; } /* Fill buffer until empty, or we reach a newline or EOF or error. */ do { *p++ = c; max--; if (max == 1 || c == '\n') break; c = al_fgetc(f); } while (c != EOF); /* Return NULL on error. */ if (c == EOF && al_ferror(f)) { return NULL; } /* Add null terminator. */ ASSERT(max >= 1); *p = '\0'; return buf; } /* Function: al_fget_ustr */ ALLEGRO_USTR *al_fget_ustr(ALLEGRO_FILE *f) { ALLEGRO_USTR *us; char buf[128]; if (!al_fgets(f, buf, sizeof(buf))) { return NULL; } us = al_ustr_new(""); do { al_ustr_append_cstr(us, buf); if (al_ustr_has_suffix_cstr(us, "\n")) break; } while (al_fgets(f, buf, sizeof(buf))); return us; } /* Function: al_fputs */ int al_fputs(ALLEGRO_FILE *f, char const *p) { size_t n; ASSERT(f); ASSERT(p); n = strlen(p); if (al_fwrite(f, p, n) != n) { return EOF; } return n; } /* Function: al_fungetc */ int al_fungetc(ALLEGRO_FILE *f, int c) { ASSERT(f != NULL); if (f->vtable->fi_fungetc) { return f->vtable->fi_fungetc(f, c); } else { /* If the interface does not provide an implementation for ungetc, * then a default one will be used. (Note that if the interface does * implement it, then this ungetc buffer will never be filled, and all * other references to it within this file will always be ignored.) */ if (f->ungetc_len == ALLEGRO_UNGETC_SIZE) { return EOF; } f->ungetc[f->ungetc_len++] = (unsigned char) c; return c; } } /* Function: al_fsize */ int64_t al_fsize(ALLEGRO_FILE *f) { ASSERT(f != NULL); return f->vtable->fi_fsize(f); } /* Function: al_get_file_userdata */ void *al_get_file_userdata(ALLEGRO_FILE *f) { ASSERT(f != NULL); return f->userdata; } /* Function: al_vfprintf */ int al_vfprintf(ALLEGRO_FILE *pfile, const char *format, va_list args) { int rv = -1; ALLEGRO_USTR *ustr = 0; size_t size = 0; bool success; if (pfile != 0 && format != 0) { ustr = al_ustr_new(""); if (ustr) { success = al_ustr_vappendf(ustr, format, args); if (success) { size = al_ustr_size(ustr); if (size > 0) { rv = al_fwrite(pfile, (const void*)(al_cstr(ustr)), size); if (rv != (int)size) { rv = -1; } } } al_ustr_free(ustr); } } return rv; } /* Function: al_fprintf */ int al_fprintf(ALLEGRO_FILE *pfile, const char *format, ...) { int rv = -1; va_list args; if (pfile != 0 && format != 0) { va_start(args, format); rv = al_vfprintf(pfile, format, args); va_end(args); } return rv; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/file_slice.c000066400000000000000000000136571473414355200165250ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * File Slices - treat a subset of a random access file * as its own file * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" typedef struct SLICE_DATA SLICE_DATA; enum { SLICE_READ = 1, SLICE_WRITE = 2, SLICE_EXPANDABLE = 4, SLICE_SEEK_END = 8 }; struct SLICE_DATA { ALLEGRO_FILE *fp; /* parent file handle */ size_t anchor; /* beginning position relative to parent */ size_t pos; /* position relative to anchor */ size_t size; /* size of slice relative to anchor */ int mode; }; static bool slice_fclose(ALLEGRO_FILE *f) { SLICE_DATA *slice = al_get_file_userdata(f); bool ret; /* seek to end of slice */ if (slice->mode & SLICE_SEEK_END) ret = al_fseek(slice->fp, slice->anchor + slice->size, ALLEGRO_SEEK_SET); else ret = true; al_free(slice); return ret; } static size_t slice_fread(ALLEGRO_FILE *f, void *ptr, size_t size) { SLICE_DATA *slice = al_get_file_userdata(f); if (!(slice->mode & SLICE_READ)) { /* no read permissions */ return 0; } if (!(slice->mode & SLICE_EXPANDABLE) && slice->pos + size > slice->size) { /* don't read past the buffer size if not expandable */ size = slice->size - slice->pos; } if (!size) { return 0; } else { /* unbuffered, read directly from parent file */ size_t b = al_fread(slice->fp, ptr, size); slice->pos += b; if (slice->pos > slice->size) slice->size = slice->pos; return b; } } static size_t slice_fwrite(ALLEGRO_FILE *f, const void *ptr, size_t size) { SLICE_DATA *slice = al_get_file_userdata(f); if (!(slice->mode & SLICE_WRITE)) { /* no write permissions */ return 0; } if (!(slice->mode & SLICE_EXPANDABLE) && slice->pos + size > slice->size) { /* don't write past the buffer size if not expandable */ size = slice->size - slice->pos; } if (!size) { return 0; } else { /* unbuffered, write directly to parent file */ size_t b = al_fwrite(slice->fp, ptr, size); slice->pos += b; if (slice->pos > slice->size) slice->size = slice->pos; return b; } } static bool slice_fflush(ALLEGRO_FILE *f) { SLICE_DATA *slice = al_get_file_userdata(f); return al_fflush(slice->fp); } static int64_t slice_ftell(ALLEGRO_FILE *f) { SLICE_DATA *slice = al_get_file_userdata(f); return slice->pos; } static bool slice_fseek(ALLEGRO_FILE *f, int64_t offset, int whence) { SLICE_DATA *slice = al_get_file_userdata(f); if (whence == ALLEGRO_SEEK_SET) { offset = slice->anchor + offset; } else if (whence == ALLEGRO_SEEK_CUR) { offset = slice->anchor + slice->pos + offset; } else if (whence == ALLEGRO_SEEK_END) { offset = slice->anchor + slice->size + offset; } else { return false; } if ((size_t) offset < slice->anchor) { offset = slice->anchor; } else if ((size_t) offset > slice->anchor + slice->size) { if (!(slice->mode & SLICE_EXPANDABLE)) { offset = slice->anchor + slice->size; } } if (al_fseek(slice->fp, offset, ALLEGRO_SEEK_SET)) { slice->pos = offset - slice->anchor; if (slice->pos > slice->size) slice->size = slice->pos; return true; } return false; } static bool slice_feof(ALLEGRO_FILE *f) { SLICE_DATA *slice = al_get_file_userdata(f); return slice->pos >= slice->size; } static int slice_ferror(ALLEGRO_FILE *f) { SLICE_DATA *slice = al_get_file_userdata(f); return al_ferror(slice->fp); } static const char *slice_ferrmsg(ALLEGRO_FILE *f) { SLICE_DATA *slice = al_get_file_userdata(f); return al_ferrmsg(slice->fp); } static void slice_fclearerr(ALLEGRO_FILE *f) { SLICE_DATA *slice = al_get_file_userdata(f); al_fclearerr(slice->fp); } static off_t slice_fsize(ALLEGRO_FILE *f) { SLICE_DATA *slice = al_get_file_userdata(f); return slice->size; } static const ALLEGRO_FILE_INTERFACE fi = { NULL, slice_fclose, slice_fread, slice_fwrite, slice_fflush, slice_ftell, slice_fseek, slice_feof, slice_ferror, slice_ferrmsg, slice_fclearerr, NULL, slice_fsize }; /* Function: al_fopen_slice */ ALLEGRO_FILE *al_fopen_slice(ALLEGRO_FILE *fp, size_t initial_size, const char *mode) { SLICE_DATA *userdata = al_calloc(1, sizeof(*userdata)); int ch; if (!userdata) { return NULL; } // OBSOLETE_V5 code should go away when the API can be changed. #ifndef OBSOLETE_V5 userdata->mode |= SLICE_SEEK_END; #endif for ( ; (ch = *mode); ++mode) { if (ch == 'r' || ch == 'R') userdata->mode |= SLICE_READ; else if (ch == 'w' || ch == 'W') userdata->mode |= SLICE_WRITE; else if (ch == 'e' || ch == 'E') userdata->mode |= SLICE_EXPANDABLE; else if (ch == 's' || ch == 'S') userdata->mode |= SLICE_SEEK_END; #ifndef OBSOLETE_V5 else if (ch == 'n' || ch == 'N') userdata->mode &= ~SLICE_SEEK_END; #endif } userdata->fp = fp; userdata->anchor = al_ftell(fp); userdata->size = initial_size; return al_create_file_handle(&fi, userdata); } allegro5-5.2.10.1/src/file_stdio.c000066400000000000000000000230521473414355200165360ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * File I/O. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" /* enable large file support in gcc/glibc */ #if defined ALLEGRO_HAVE_FTELLO && defined ALLEGRO_HAVE_FSEEKO #ifndef _LARGEFILE_SOURCE #define _LARGEFILE_SOURCE #endif #ifndef _FILE_OFFSET_BITS #define _FILE_OFFSET_BITS 64 #endif #endif #include #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_file.h" #include "allegro5/internal/aintern_wunicode.h" #include ALLEGRO_INTERNAL_HEADER #ifdef ALLEGRO_HAVE_SYS_STAT_H #include #endif ALLEGRO_DEBUG_CHANNEL("stdio") /* forward declaration */ const struct ALLEGRO_FILE_INTERFACE _al_file_interface_stdio; #ifndef PATH_MAX #define PATH_MAX 4096 #endif typedef struct { FILE *fp; int errnum; char errmsg[80]; } USERDATA; static USERDATA *get_userdata(ALLEGRO_FILE *f) { if (f) return al_get_file_userdata(f); else return NULL; } /* Function: al_fopen_fd */ ALLEGRO_FILE *al_fopen_fd(int fd, const char *mode) { ALLEGRO_FILE *f; USERDATA *userdata; FILE *fp; userdata = al_malloc(sizeof(USERDATA)); if (!userdata) return NULL; /* The fd should remain open if this function fails in any way, * so delay the fdopen() call to last. */ userdata->fp = NULL; userdata->errnum = 0; f = al_create_file_handle(&_al_file_interface_stdio, userdata); if (!f) { al_free(userdata); return NULL; } fp = fdopen(fd, mode); if (!fp) { al_set_errno(errno); al_fclose(f); return NULL; } userdata->fp = fp; return f; } static void *file_stdio_fopen(const char *path, const char *mode) { FILE *fp; USERDATA *userdata; ALLEGRO_DEBUG("opening %s %s\n", path, mode); #ifdef ALLEGRO_WINDOWS { wchar_t *wpath = _al_win_utf8_to_utf16(path); wchar_t *wmode = _al_win_utf8_to_utf16(mode); fp = _wfopen(wpath, wmode); al_free(wpath); al_free(wmode); } #else fp = fopen(path, mode); #endif if (!fp) { al_set_errno(errno); return NULL; } userdata = al_malloc(sizeof(USERDATA)); if (!userdata) { fclose(fp); return NULL; } userdata->fp = fp; userdata->errnum = 0; return userdata; } static bool file_stdio_fclose(ALLEGRO_FILE *f) { USERDATA *userdata = get_userdata(f); bool ret; if (userdata->fp == NULL) { /* This can happen in the middle of al_fopen_fd. */ ret = true; } else if (fclose(userdata->fp) == 0) { ret = true; } else { al_set_errno(errno); ret = false; } al_free(userdata); return ret; } static size_t file_stdio_fread(ALLEGRO_FILE *f, void *ptr, size_t size) { USERDATA *userdata = get_userdata(f); if (size == 1) { /* Optimise common case. */ int c = fgetc(userdata->fp); if (c == EOF) { userdata->errnum = errno; al_set_errno(errno); return 0; } *((char *)ptr) = (char)c; return 1; } else { size_t ret = fread(ptr, 1, size, userdata->fp); if (ret < size) { userdata->errnum = errno; al_set_errno(errno); } return ret; } } static size_t file_stdio_fwrite(ALLEGRO_FILE *f, const void *ptr, size_t size) { USERDATA *userdata = get_userdata(f); size_t ret; ret = fwrite(ptr, 1, size, userdata->fp); if (ret < size) { userdata->errnum = errno; al_set_errno(errno); } return ret; } static bool file_stdio_fflush(ALLEGRO_FILE *f) { USERDATA *userdata = get_userdata(f); if (fflush(userdata->fp) == EOF) { userdata->errnum = errno; al_set_errno(errno); return false; } return true; } static int64_t file_stdio_ftell(ALLEGRO_FILE *f) { USERDATA *userdata = get_userdata(f); int64_t ret; #if defined(ALLEGRO_HAVE_FTELLO) ret = ftello(userdata->fp); #elif defined(ALLEGRO_HAVE_FTELLI64) ret = _ftelli64(userdata->fp); #else ret = ftell(userdata->fp); #endif if (ret == -1) { userdata->errnum = errno; al_set_errno(errno); } return ret; } static bool file_stdio_fseek(ALLEGRO_FILE *f, int64_t offset, int whence) { USERDATA *userdata = get_userdata(f); int rc; switch (whence) { case ALLEGRO_SEEK_SET: whence = SEEK_SET; break; case ALLEGRO_SEEK_CUR: whence = SEEK_CUR; break; case ALLEGRO_SEEK_END: whence = SEEK_END; break; } #if defined(ALLEGRO_HAVE_FSEEKO) rc = fseeko(userdata->fp, offset, whence); #elif defined(ALLEGRO_HAVE_FSEEKI64) rc = _fseeki64(userdata->fp, offset, whence); #else rc = fseek(userdata->fp, offset, whence); #endif if (rc == -1) { userdata->errnum = errno; al_set_errno(errno); return false; } return true; } static bool file_stdio_feof(ALLEGRO_FILE *f) { USERDATA *userdata = get_userdata(f); return feof(userdata->fp); } static int file_stdio_ferror(ALLEGRO_FILE *f) { USERDATA *userdata = get_userdata(f); return ferror(userdata->fp); } static const char *file_stdio_ferrmsg(ALLEGRO_FILE *f) { USERDATA *userdata = get_userdata(f); if (userdata->errnum == 0) return ""; /* Note: at this time MinGW has neither strerror_r nor strerror_s. */ #if defined(ALLEGRO_HAVE_STRERROR_R) { int rc = strerror_r(userdata->errnum, userdata->errmsg, sizeof(userdata->errmsg)); if (rc == 0) { return userdata->errmsg; } } #endif #if defined(ALLEGRO_HAVE_STRERROR_S) { errno_t rc = strerror_s(userdata->errmsg, sizeof(userdata->errmsg), userdata->errnum); if (rc == 0) { return userdata->errmsg; } } #endif return ""; } static void file_stdio_fclearerr(ALLEGRO_FILE *f) { USERDATA *userdata = get_userdata(f); clearerr(userdata->fp); } static int file_stdio_fungetc(ALLEGRO_FILE *f, int c) { USERDATA *userdata = get_userdata(f); int rc; rc = ungetc(c, userdata->fp); if (rc == EOF) { userdata->errnum = errno; al_set_errno(errno); } return rc; } static off_t file_stdio_fsize(ALLEGRO_FILE *f) { int64_t old_pos; int64_t new_pos; old_pos = file_stdio_ftell(f); if (old_pos == -1) return -1; if (!file_stdio_fseek(f, 0, ALLEGRO_SEEK_END)) return -1; new_pos = file_stdio_ftell(f); if (new_pos == -1) return -1; if (!file_stdio_fseek(f, old_pos, ALLEGRO_SEEK_SET)) return -1; return new_pos; } const struct ALLEGRO_FILE_INTERFACE _al_file_interface_stdio = { file_stdio_fopen, file_stdio_fclose, file_stdio_fread, file_stdio_fwrite, file_stdio_fflush, file_stdio_ftell, file_stdio_fseek, file_stdio_feof, file_stdio_ferror, file_stdio_ferrmsg, file_stdio_fclearerr, file_stdio_fungetc, file_stdio_fsize }; /* Function: al_set_standard_file_interface */ void al_set_standard_file_interface(void) { al_set_new_file_interface(&_al_file_interface_stdio); } #define MAX_MKTEMP_TRIES 1000 static void mktemp_replace_XX(const char *template, char *dst) { static const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; size_t len = strlen(template); unsigned i; for (i=0; ifs_create_entry); return vt->fs_create_entry(path); } /* Function: al_destroy_fs_entry */ void al_destroy_fs_entry(ALLEGRO_FS_ENTRY *fh) { if (fh) { fh->vtable->fs_destroy_entry(fh); } } /* Function: al_get_fs_entry_name */ const char *al_get_fs_entry_name(ALLEGRO_FS_ENTRY *e) { ASSERT(e != NULL); return e->vtable->fs_entry_name(e); } /* Function: al_update_fs_entry */ bool al_update_fs_entry(ALLEGRO_FS_ENTRY *e) { ASSERT(e != NULL); return e->vtable->fs_update_entry(e); } /* Function: al_get_fs_entry_mode */ uint32_t al_get_fs_entry_mode(ALLEGRO_FS_ENTRY *e) { ASSERT(e != NULL); return e->vtable->fs_entry_mode(e); } /* Function: al_get_fs_entry_atime */ time_t al_get_fs_entry_atime(ALLEGRO_FS_ENTRY *e) { ASSERT(e != NULL); return e->vtable->fs_entry_atime(e); } /* Function: al_get_fs_entry_mtime */ time_t al_get_fs_entry_mtime(ALLEGRO_FS_ENTRY *e) { ASSERT(e != NULL); return e->vtable->fs_entry_mtime(e); } /* Function: al_get_fs_entry_ctime */ time_t al_get_fs_entry_ctime(ALLEGRO_FS_ENTRY *e) { ASSERT(e != NULL); return e->vtable->fs_entry_ctime(e); } /* Function: al_get_fs_entry_size */ off_t al_get_fs_entry_size(ALLEGRO_FS_ENTRY *e) { ASSERT(e != NULL); return e->vtable->fs_entry_size(e); } /* Function: al_remove_fs_entry */ bool al_remove_fs_entry(ALLEGRO_FS_ENTRY *e) { ASSERT(e != NULL); return e->vtable->fs_remove_entry(e); } /* Function: al_fs_entry_exists */ bool al_fs_entry_exists(ALLEGRO_FS_ENTRY *e) { ASSERT(e != NULL); return e->vtable->fs_entry_exists(e); } /* Function: al_open_directory */ bool al_open_directory(ALLEGRO_FS_ENTRY *e) { ASSERT(e != NULL); return e->vtable->fs_open_directory(e); } /* Function: al_close_directory */ bool al_close_directory(ALLEGRO_FS_ENTRY *e) { ASSERT(e != NULL); return e->vtable->fs_close_directory(e); } /* Function: al_read_directory */ ALLEGRO_FS_ENTRY *al_read_directory(ALLEGRO_FS_ENTRY *e) { ASSERT(e != NULL); return e->vtable->fs_read_directory(e); } /* Function: al_get_current_directory */ char *al_get_current_directory(void) { const ALLEGRO_FS_INTERFACE *vt = al_get_fs_interface(); ASSERT(vt->fs_get_current_directory); return vt->fs_get_current_directory(); } /* Function: al_change_directory */ bool al_change_directory(const char *path) { const ALLEGRO_FS_INTERFACE *vt = al_get_fs_interface(); ASSERT(vt->fs_change_directory); ASSERT(path); return vt->fs_change_directory(path); } /* Function: al_make_directory */ bool al_make_directory(const char *path) { const ALLEGRO_FS_INTERFACE *vt = al_get_fs_interface(); ASSERT(path); ASSERT(vt->fs_make_directory); return vt->fs_make_directory(path); } /* Function: al_filename_exists */ bool al_filename_exists(const char *path) { const ALLEGRO_FS_INTERFACE *vt = al_get_fs_interface(); ASSERT(path != NULL); ASSERT(vt->fs_filename_exists); return vt->fs_filename_exists(path); } /* Function: al_remove_filename */ bool al_remove_filename(const char *path) { const ALLEGRO_FS_INTERFACE *vt = al_get_fs_interface(); ASSERT(vt->fs_remove_filename); ASSERT(path != NULL); return vt->fs_remove_filename(path); } /* Function: al_open_fs_entry */ ALLEGRO_FILE *al_open_fs_entry(ALLEGRO_FS_ENTRY *e, const char *mode) { ASSERT(e != NULL); if (e->vtable->fs_open_file) return e->vtable->fs_open_file(e, mode); al_set_errno(EINVAL); return NULL; } /* Utility functions for iterating over a directory using callbacks. */ /* Function: al_for_each_fs_entry */ int al_for_each_fs_entry(ALLEGRO_FS_ENTRY *dir, int (*callback)(ALLEGRO_FS_ENTRY *dir, void *extra), void *extra) { ALLEGRO_FS_ENTRY *entry; if (!dir || !al_open_directory(dir)) { al_set_errno(ENOENT); return ALLEGRO_FOR_EACH_FS_ENTRY_ERROR; } for (entry = al_read_directory(dir); entry; entry = al_read_directory(dir)) { /* Call the callback first. */ int result = callback(entry, extra); /* Recurse if requested and needed. Only OK allows recursion. */ if (result == ALLEGRO_FOR_EACH_FS_ENTRY_OK) { if (al_get_fs_entry_mode(entry) & ALLEGRO_FILEMODE_ISDIR) { result = al_for_each_fs_entry(entry, callback, extra); } } al_destroy_fs_entry(entry); if ((result == ALLEGRO_FOR_EACH_FS_ENTRY_STOP) || (result == ALLEGRO_FOR_EACH_FS_ENTRY_ERROR)) { return result; } } return ALLEGRO_FOR_EACH_FS_ENTRY_OK; } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/fshook_stdio.c000066400000000000000000000433551473414355200171200ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * File System Hook, POSIX "driver" (not stdio). * * By Thomas Fjellstrom. * * Modified by Peter Wang. * * See readme.txt for copyright information. */ /* Eventually we will make Allegro use the Unicode (UTF-16) Windows API * globally but not yet. */ #ifndef UNICODE #define UNICODE #define _UNICODE #endif #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_wunicode.h" #include ALLEGRO_INTERNAL_HEADER ALLEGRO_DEBUG_CHANNEL("fshook") /* Enable large file support in gcc/glibc. */ #if defined ALLEGRO_HAVE_FTELLO && defined ALLEGRO_HAVE_FSEEKO #define _LARGEFILE_SOURCE #define _FILE_OFFSET_BITS 64 #endif #include #include #ifdef _MSC_VER #define _POSIX_ #include #undef _POSIX_ #include #endif #include "allegro5/internal/aintern_file.h" #include "allegro5/internal/aintern_fshook.h" #ifdef ALLEGRO_HAVE_SYS_STAT_H #include #endif #ifdef ALLEGRO_HAVE_DIRENT_H #include #include #define NAMLEN(dirent) (strlen((dirent)->d_name)) #else #define dirent direct #define NAMLEN(dirent) ((dirent)->d_namlen) #ifdef ALLEGRO_HAVE_SYS_NDIR_H #include #endif #ifdef ALLEGRO_HAVE_SYS_DIR_H #include #endif #ifdef ALLEGRO_HAVE_NDIR_H #include #endif #endif #ifndef S_IRGRP #define S_IRGRP (0) #endif #ifndef S_IWGRP #define S_IWGRP (0) #endif #ifndef S_IXGRP #define S_IXGRP (0) #endif #ifdef ALLEGRO_HAVE_SYS_TIME #include #endif #ifdef ALLEGRO_HAVE_TIME_H #include #endif #ifdef ALLEGRO_WINDOWS #include #include "fshook_win.inc" typedef wchar_t WRAP_CHAR; typedef struct _stat WRAP_STAT_TYPE; typedef _WDIR WRAP_DIR_TYPE; typedef struct _wdirent WRAP_DIRENT_TYPE; #define WRAP_LIT(s) _TEXT(s) #define WRAP_STRLEN(s) (wcslen(s)) #define WRAP_STRCMP(s1, s2) (wcscmp((s1), (s2))) #define WRAP_STAT(p, b) (_wstat((p), (b))) #define WRAP_MKDIR(p) (_wmkdir(p)) #define WRAP_RMDIR(p) (_wrmdir(p)) #define WRAP_UNLINK(p) (_wunlink(p)) #define WRAP_OPENDIR(p) (_wopendir(p)) #define WRAP_CLOSEDIR(d) (_wclosedir(d)) #define WRAP_READDIR(d) (_wreaddir(d)) #else typedef char WRAP_CHAR; typedef struct stat WRAP_STAT_TYPE; typedef DIR WRAP_DIR_TYPE; typedef struct dirent WRAP_DIRENT_TYPE; #define WRAP_LIT(s) (s) #define WRAP_STRLEN(s) (strlen(s)) #define WRAP_STRCMP(s1, s2) (strcmp((s1), (s2))) #define WRAP_STAT(p, b) (stat((p), (b))) #define WRAP_STAT_UNSLASH(p, b) (stat((p), (b))) #define WRAP_MKDIR(p) (mkdir(p, 0755)) #define WRAP_RMDIR(p) (rmdir(p)) #define WRAP_UNLINK(p) (unlink(p)) #define WRAP_OPENDIR(p) (opendir(p)) #define WRAP_CLOSEDIR(d) (closedir(d)) #define WRAP_READDIR(d) (readdir(d)) #endif #ifndef PATH_MAX #define PATH_MAX 4096 #endif typedef struct ALLEGRO_FS_ENTRY_STDIO ALLEGRO_FS_ENTRY_STDIO; struct ALLEGRO_FS_ENTRY_STDIO { ALLEGRO_FS_ENTRY fs_entry; /* must be first */ WRAP_CHAR *abs_path; #ifdef ALLEGRO_WINDOWS char *abs_path_utf8; #define ABS_PATH_UTF8 abs_path_utf8 #else #define ABS_PATH_UTF8 abs_path #endif uint32_t stat_mode; WRAP_STAT_TYPE st; WRAP_DIR_TYPE *dir; }; static void fs_update_stat_mode(ALLEGRO_FS_ENTRY_STDIO *fp_stdio); static bool fs_stdio_update_entry(ALLEGRO_FS_ENTRY *fp); /* Make an absolute path given a potentially relative path. * The result must be freed with free(), NOT al_free(). */ static WRAP_CHAR *make_absolute_path_inner(const WRAP_CHAR *tail) { #ifdef ALLEGRO_WINDOWS /* We use _wfullpath to get the proper drive letter semantics on Windows. */ wchar_t *abs_path = _wfullpath(NULL, tail, 0); /* Remove trailing backslash (_wstat fails otherwise), but NOT directly * following the drive letter. */ if (abs_path) { const size_t abs_len = WRAP_STRLEN(abs_path); if (abs_len == 3 && abs_path[1] == ':' && abs_path[2] == '\\') { /* Do not strip "C:\" */ } else if (abs_len > 1 && abs_path[abs_len - 1] == '\\') { abs_path[abs_len - 1] = '\0'; } } return abs_path; #else char cwd[PATH_MAX]; ALLEGRO_PATH *cwdpath = NULL; ALLEGRO_PATH *tailpath = NULL; char *ret = NULL; if (!getcwd(cwd, sizeof(cwd))) { ALLEGRO_WARN("Unable to get current working directory.\n"); al_set_errno(errno); goto Error; } cwdpath = al_create_path_for_directory(cwd); if (!cwdpath) { goto Error; } tailpath = al_create_path(tail); if (!tailpath) { goto Error; } if (al_rebase_path(cwdpath, tailpath)) { al_make_path_canonical(tailpath); } ret = strdup(al_path_cstr(tailpath, ALLEGRO_NATIVE_PATH_SEP)); Error: al_destroy_path(cwdpath); al_destroy_path(tailpath); return ret; #endif } static WRAP_CHAR *make_absolute_path(const char *tail) { WRAP_CHAR *abs_path = NULL; #ifdef ALLEGRO_WINDOWS wchar_t *wtail = _al_win_utf8_to_utf16(tail); if (wtail) { abs_path = make_absolute_path_inner(wtail); al_free(wtail); } #else abs_path = make_absolute_path_inner(tail); #endif return abs_path; } static ALLEGRO_FS_ENTRY *create_abs_path_entry(const WRAP_CHAR *abs_path) { ALLEGRO_FS_ENTRY_STDIO *fh; size_t len; fh = al_calloc(1, sizeof(*fh)); if (!fh) { al_set_errno(errno); return NULL; } fh->fs_entry.vtable = &_al_fs_interface_stdio; len = WRAP_STRLEN(abs_path) + 1; /* including terminator */ fh->abs_path = al_malloc(len * sizeof(WRAP_CHAR)); if (!fh->abs_path) { al_free(fh); return NULL; } memcpy(fh->abs_path, abs_path, len * sizeof(WRAP_CHAR)); #ifdef ALLEGRO_WINDOWS fh->abs_path_utf8 = _al_win_utf16_to_utf8(fh->abs_path); if (!fh->abs_path_utf8) { al_free(fh->abs_path); al_free(fh); return NULL; } #endif ALLEGRO_DEBUG("Creating entry for %s\n", fh->ABS_PATH_UTF8); fs_stdio_update_entry((ALLEGRO_FS_ENTRY *) fh); return (ALLEGRO_FS_ENTRY *) fh; } static ALLEGRO_FS_ENTRY *fs_stdio_create_entry(const char *orig_path) { ALLEGRO_FS_ENTRY *ret = NULL; WRAP_CHAR *abs_path; abs_path = make_absolute_path(orig_path); if (abs_path) { ret = create_abs_path_entry(abs_path); free(abs_path); } return ret; } #if defined(ALLEGRO_UNIX) || defined(ALLEGRO_MACOSX) static bool unix_hidden_file(const char *path) { /* Filenames beginning with dot are considered hidden. */ const char *p = strrchr(path, ALLEGRO_NATIVE_PATH_SEP); if (p) p++; else p = path; return (p[0] == '.'); } #endif static void fs_update_stat_mode(ALLEGRO_FS_ENTRY_STDIO *fp_stdio) { fp_stdio->stat_mode = 0; if (S_ISDIR(fp_stdio->st.st_mode)) fp_stdio->stat_mode |= ALLEGRO_FILEMODE_ISDIR; else /* marks special unix files as files... might want to add enum items for symlink, CHAR, BLOCK and SOCKET files. */ fp_stdio->stat_mode |= ALLEGRO_FILEMODE_ISFILE; /* if (S_ISREG(fh->st.st_mode)) fh->stat_mode |= ALLEGRO_FILEMODE_ISFILE; */ if (fp_stdio->st.st_mode & (S_IRUSR | S_IRGRP)) fp_stdio->stat_mode |= ALLEGRO_FILEMODE_READ; if (fp_stdio->st.st_mode & (S_IWUSR | S_IWGRP)) fp_stdio->stat_mode |= ALLEGRO_FILEMODE_WRITE; if (fp_stdio->st.st_mode & (S_IXUSR | S_IXGRP)) fp_stdio->stat_mode |= ALLEGRO_FILEMODE_EXECUTE; #if defined(ALLEGRO_WINDOWS) { DWORD attrib = GetFileAttributes(fp_stdio->abs_path); if (attrib & FILE_ATTRIBUTE_HIDDEN) fp_stdio->stat_mode |= ALLEGRO_FILEMODE_HIDDEN; } #endif #if defined(ALLEGRO_MACOSX) && defined(UF_HIDDEN) { /* OSX hidden files can both start with the dot as well as having this flag set... * Note that this flag does not exist on all versions of OS X (Tiger * doesn't seem to have it) so we need to test for it. */ if (fp_stdio->st.st_flags & UF_HIDDEN) fp_stdio->stat_mode |= ALLEGRO_FILEMODE_HIDDEN; } #endif #if defined(ALLEGRO_UNIX) || defined(ALLEGRO_MACOSX) if (0 == (fp_stdio->stat_mode & ALLEGRO_FILEMODE_HIDDEN)) { if (unix_hidden_file(fp_stdio->abs_path)) { fp_stdio->stat_mode |= ALLEGRO_FILEMODE_HIDDEN; } } #endif } static bool fs_stdio_update_entry(ALLEGRO_FS_ENTRY *fp) { ALLEGRO_FS_ENTRY_STDIO *fp_stdio = (ALLEGRO_FS_ENTRY_STDIO *) fp; int ret; ret = WRAP_STAT(fp_stdio->abs_path, &(fp_stdio->st)); if (ret == -1) { al_set_errno(errno); return false; } fs_update_stat_mode(fp_stdio); return true; } static bool fs_stdio_open_directory(ALLEGRO_FS_ENTRY *fp) { ALLEGRO_FS_ENTRY_STDIO *fp_stdio = (ALLEGRO_FS_ENTRY_STDIO *) fp; if (!(fp_stdio->stat_mode & ALLEGRO_FILEMODE_ISDIR)) return false; fp_stdio->dir = WRAP_OPENDIR(fp_stdio->abs_path); if (!fp_stdio->dir) { al_set_errno(errno); return false; } return true; } static bool fs_stdio_close_directory(ALLEGRO_FS_ENTRY *fp) { ALLEGRO_FS_ENTRY_STDIO *fp_stdio = (ALLEGRO_FS_ENTRY_STDIO *) fp; int rc; if (!fp_stdio->dir) { al_set_errno(ENOTDIR); return false; } rc = WRAP_CLOSEDIR(fp_stdio->dir); fp_stdio->dir = NULL; if (rc == -1) { al_set_errno(errno); return false; } return true; } static ALLEGRO_FS_ENTRY *fs_stdio_read_directory(ALLEGRO_FS_ENTRY *fp) { ALLEGRO_FS_ENTRY_STDIO *fp_stdio = (ALLEGRO_FS_ENTRY_STDIO *) fp; // FIXME: Must use readdir_r as Allegro allows file functions being // called from different threads. WRAP_DIRENT_TYPE *ent; ALLEGRO_FS_ENTRY *ret; ASSERT(fp_stdio->dir); do { ent = WRAP_READDIR(fp_stdio->dir); if (!ent) { al_set_errno(errno); return NULL; } /* Don't bother the user with these entries. */ } while (0 == WRAP_STRCMP(ent->d_name, WRAP_LIT(".")) || 0 == WRAP_STRCMP(ent->d_name, WRAP_LIT(".."))); #ifdef ALLEGRO_WINDOWS { wchar_t buf[MAX_PATH]; int buflen; buflen = _snwprintf(buf, MAX_PATH, L"%s\\%s", fp_stdio->abs_path, ent->d_name); if (buflen >= MAX_PATH) { al_set_errno(ERANGE); return NULL; } ret = create_abs_path_entry(buf); } #else { int abs_path_len = strlen(fp_stdio->abs_path); int ent_name_len = strlen(ent->d_name); char *buf = al_malloc(abs_path_len + 1 + ent_name_len + 1); if (!buf) { al_set_errno(ENOMEM); return NULL; } memcpy(buf, fp_stdio->abs_path, abs_path_len); if ( (abs_path_len >= 1) && buf[abs_path_len - 1] == ALLEGRO_NATIVE_PATH_SEP) { /* do NOT add a new separator if we have one already */ memcpy(buf + abs_path_len, ent->d_name, ent_name_len); buf[abs_path_len + ent_name_len] = '\0'; } else { /* append separator */ buf[abs_path_len] = ALLEGRO_NATIVE_PATH_SEP; memcpy(buf + abs_path_len + 1, ent->d_name, ent_name_len); buf[abs_path_len + 1 + ent_name_len] = '\0'; } ret = create_abs_path_entry(buf); al_free(buf); } #endif return ret; } static void fs_stdio_destroy_entry(ALLEGRO_FS_ENTRY *fh_) { ALLEGRO_FS_ENTRY_STDIO *fh = (ALLEGRO_FS_ENTRY_STDIO *) fh_; al_free(fh->abs_path); #ifdef ALLEGRO_WINDOWS al_free(fh->abs_path_utf8); #endif if (fh->dir) fs_stdio_close_directory(fh_); al_free(fh); } static off_t fs_stdio_entry_size(ALLEGRO_FS_ENTRY *fp) { ALLEGRO_FS_ENTRY_STDIO *ent = (ALLEGRO_FS_ENTRY_STDIO *) fp; ASSERT(ent); return ent->st.st_size; } static uint32_t fs_stdio_entry_mode(ALLEGRO_FS_ENTRY *fp) { ALLEGRO_FS_ENTRY_STDIO *ent = (ALLEGRO_FS_ENTRY_STDIO *) fp; ASSERT(ent); return ent->stat_mode; } static time_t fs_stdio_entry_atime(ALLEGRO_FS_ENTRY *fp) { ALLEGRO_FS_ENTRY_STDIO *ent = (ALLEGRO_FS_ENTRY_STDIO *) fp; ASSERT(ent); return ent->st.st_atime; } static time_t fs_stdio_entry_mtime(ALLEGRO_FS_ENTRY *fp) { ALLEGRO_FS_ENTRY_STDIO *ent = (ALLEGRO_FS_ENTRY_STDIO *) fp; ASSERT(ent); return ent->st.st_mtime; } static time_t fs_stdio_entry_ctime(ALLEGRO_FS_ENTRY *fp) { ALLEGRO_FS_ENTRY_STDIO *ent = (ALLEGRO_FS_ENTRY_STDIO *) fp; ASSERT(ent); return ent->st.st_ctime; } static char *fs_stdio_get_current_directory(void) { #ifdef ALLEGRO_WINDOWS wchar_t *wcwd; char *cwd; wcwd = _wgetcwd(NULL, 1); if (!wcwd) { al_set_errno(errno); return NULL; } cwd = _al_win_utf16_to_utf8(wcwd); free(wcwd); return cwd; #else char tmpdir[PATH_MAX]; char *cwd; if (!getcwd(tmpdir, PATH_MAX)) { al_set_errno(errno); return NULL; } cwd = al_malloc(strlen(tmpdir) + 1); if (!cwd) { al_set_errno(ENOMEM); return NULL; } return strcpy(cwd, tmpdir); #endif } static bool fs_stdio_change_directory(const char *path) { int ret = -1; #ifdef ALLEGRO_WINDOWS wchar_t *wpath = _al_win_utf8_to_utf16(path); if (wpath) { ret = _wchdir(wpath); al_free(wpath); } #else ret = chdir(path); #endif if (ret == -1) { al_set_errno(errno); return false; } return true; } static bool mkdir_exists(const WRAP_CHAR *path) { WRAP_STAT_TYPE st; if (WRAP_STAT(path, &st) == 0) { return S_ISDIR(st.st_mode); } return WRAP_MKDIR(path) == 0; } static bool do_make_directory(WRAP_CHAR *abs_path) { const WRAP_CHAR * const end = abs_path + WRAP_STRLEN(abs_path); WRAP_CHAR *p; bool ret; p = abs_path + 1; #ifdef ALLEGRO_WINDOWS /* Skip drive letter. */ if (end - abs_path >= 3 && abs_path[1] == ':' && (abs_path[2] == '\\' || abs_path[2] == '/')) { p = abs_path + 3; } #endif for ( ; p < end; p++) { const WRAP_CHAR c = *p; if (c == ALLEGRO_NATIVE_PATH_SEP || c == '/') { *p = '\0'; ret = mkdir_exists(abs_path); *p = c; if (!ret) return false; } } return mkdir_exists(abs_path); } static bool fs_stdio_make_directory(const char *tail) { bool ret = false; WRAP_CHAR *abs_path = make_absolute_path(tail); if (abs_path) { ret = do_make_directory(abs_path); free(abs_path); } return ret; } static bool fs_stdio_entry_exists(ALLEGRO_FS_ENTRY *fp) { ALLEGRO_FS_ENTRY_STDIO *fp_stdio = (ALLEGRO_FS_ENTRY_STDIO *) fp; WRAP_STAT_TYPE st; if (WRAP_STAT(fp_stdio->abs_path, &st) != 0) { if (errno != ENOENT) { al_set_errno(errno); } return false; } return true; } static bool fs_stdio_filename_exists(const char *path) { WRAP_STAT_TYPE st; bool ret = false; ASSERT(path); #ifdef ALLEGRO_WINDOWS { /* Pass an path created by _wfullpath() to avoid issues * with stat() failing when there is a trailing slash. */ wchar_t *abs_path = make_absolute_path(path); if (abs_path) { ret = (0 == WRAP_STAT(abs_path, &st)); if (!ret && errno != ENOENT) { al_set_errno(errno); } free(abs_path); } } #else ret = (0 == WRAP_STAT(path, &st)); if (!ret && errno != ENOENT) { al_set_errno(errno); } #endif return ret; } static bool fs_stdio_remove_entry(ALLEGRO_FS_ENTRY *fp) { ALLEGRO_FS_ENTRY_STDIO *fp_stdio = (ALLEGRO_FS_ENTRY_STDIO *) fp; int err; ASSERT(fp); if (fs_stdio_entry_mode(fp) & ALLEGRO_FILEMODE_ISDIR) { err = WRAP_RMDIR(fp_stdio->abs_path); } else if (fs_stdio_entry_mode(fp) & ALLEGRO_FILEMODE_ISFILE) { err = WRAP_UNLINK(fp_stdio->abs_path); } else { al_set_errno(ENOENT); return false; } if (err != 0) { al_set_errno(errno); return false; } return true; } static bool fs_stdio_remove_filename(const char *path) { ALLEGRO_FS_ENTRY *fp; bool rc; fp = fs_stdio_create_entry(path); if (!fp) { ALLEGRO_WARN("Cannot remove %s.", path); return false; } rc = fs_stdio_remove_entry(fp); fs_stdio_destroy_entry(fp); return rc; } static const char *fs_stdio_name(ALLEGRO_FS_ENTRY *fp) { ALLEGRO_FS_ENTRY_STDIO *fp_stdio = (ALLEGRO_FS_ENTRY_STDIO *) fp; return fp_stdio->ABS_PATH_UTF8; } static ALLEGRO_FILE *fs_stdio_open_file(ALLEGRO_FS_ENTRY *fp, const char *mode) { ALLEGRO_FS_ENTRY_STDIO *fp_stdio = (ALLEGRO_FS_ENTRY_STDIO *) fp; /* XXX on Windows it would be nicer to use the UTF-16 abs_path field * directly */ return al_fopen_interface(&_al_file_interface_stdio, fp_stdio->ABS_PATH_UTF8, mode); } struct ALLEGRO_FS_INTERFACE _al_fs_interface_stdio = { fs_stdio_create_entry, fs_stdio_destroy_entry, fs_stdio_name, fs_stdio_update_entry, fs_stdio_entry_mode, fs_stdio_entry_atime, fs_stdio_entry_mtime, fs_stdio_entry_ctime, fs_stdio_entry_size, fs_stdio_entry_exists, fs_stdio_remove_entry, fs_stdio_open_directory, fs_stdio_read_directory, fs_stdio_close_directory, fs_stdio_filename_exists, fs_stdio_remove_filename, fs_stdio_get_current_directory, fs_stdio_change_directory, fs_stdio_make_directory, fs_stdio_open_file }; /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/fshook_win.inc000066400000000000000000000150611473414355200171130ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Helper routines for fshook implementation on Windows. * * See LICENSE.txt for copyright information. */ #include #if defined(ALLEGRO_MSVC) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) /* * MSVC is missing the whole dirent.h so we implement the bits we need here. * The following block is copied from dirent.c from MinGW Runtime sources * version 3.15.1 with minor modifications. The code was public domain. */ #ifdef _UNICODE #define _TDIR _WDIR #define _tdirent _wdirent #define _topendir _wopendir #define _tclosedir _wclosedir #define _treaddir _wreaddir #else #error _UNICODE not defined #endif #define SUFFIX _T("*") #define SLASH _T("\\") struct _wdirent { long d_ino; /* Always zero. */ unsigned short d_reclen; /* Always zero. */ unsigned short d_namlen; /* Length of name in d_name. */ wchar_t d_name[FILENAME_MAX]; /* File name. */ }; /* * This is an internal data structure. Good programmers will not use it * except as an argument to one of the functions below. * dd_stat field is now int (was short in older versions). */ typedef struct { /* disk transfer area for this dir */ struct _wfinddata_t dd_dta; /* dirent struct to return from dir (NOTE: this makes this thread * safe as long as only one thread uses a particular DIR struct at * a time) */ struct _wdirent dd_dir; /* _findnext handle */ intptr_t dd_handle; /* * Status of search: * 0 = not started yet (next entry to read is first entry) * -1 = off the end * positive = 0 based index of next entry */ int dd_stat; /* given path for dir with search pattern (struct is extended) */ wchar_t dd_name[1]; } _WDIR; /* * opendir * * Returns a pointer to a DIR structure appropriately filled in to begin * searching a directory. */ static _TDIR *_topendir(const _TCHAR *szPath) { _TDIR *nd; unsigned int rc; _TCHAR szFullPath[MAX_PATH]; errno = 0; if (!szPath) { errno = EFAULT; return (_TDIR *) 0; } if (szPath[0] == _T('\0')) { errno = ENOTDIR; return (_TDIR*) 0; } /* Attempt to determine if the given path really is a directory. */ rc = GetFileAttributes(szPath); if (rc == (unsigned int)-1) { /* call GetLastError for more error info */ errno = ENOENT; return (_TDIR*) 0; } if (!(rc & FILE_ATTRIBUTE_DIRECTORY)) { /* Error, entry exists but not a directory. */ errno = ENOTDIR; return (_TDIR*) 0; } /* Make an absolute pathname. */ _tfullpath(szFullPath, szPath, MAX_PATH); /* Allocate enough space to store DIR structure and the complete * directory path given. */ nd = (_TDIR *) al_malloc(sizeof (_TDIR) + (_tcslen(szFullPath) + _tcslen(SLASH) + _tcslen(SUFFIX) + 1) * sizeof(_TCHAR)); if (!nd) { /* Error, out of memory. */ errno = ENOMEM; return (_TDIR*) 0; } /* Create the search expression. */ _tcscpy(nd->dd_name, szFullPath); /* Add on a slash if the path does not end with one. */ if (nd->dd_name[0] != _T('\0') && _tcsrchr(nd->dd_name, _T('/')) != nd->dd_name + _tcslen(nd->dd_name) - 1 && _tcsrchr(nd->dd_name, _T('\\')) != nd->dd_name + _tcslen(nd->dd_name) - 1) { _tcscat(nd->dd_name, SLASH); } /* Add on the search pattern */ _tcscat(nd->dd_name, SUFFIX); /* Initialize handle to -1 so that a premature closedir doesn't try * to call _findclose on it. */ nd->dd_handle = -1; /* Initialize the status. */ nd->dd_stat = 0; /* Initialize the dirent structure. ino and reclen are invalid under * Win32, and name simply points at the appropriate part of the * findfirst_t structure. */ nd->dd_dir.d_ino = 0; nd->dd_dir.d_reclen = 0; nd->dd_dir.d_namlen = 0; memset(nd->dd_dir.d_name, 0, FILENAME_MAX); return nd; } /* * readdir * * Return a pointer to a dirent structure filled with the information on the * next entry in the directory. */ static struct _tdirent* _treaddir(_TDIR* dirp) { errno = 0; /* Check for valid DIR struct. */ if (!dirp) { errno = EFAULT; return (struct _tdirent*) 0; } if (dirp->dd_stat < 0) { /* We have already returned all files in the directory * (or the structure has an invalid dd_stat). */ return (struct _tdirent*) 0; } else if (dirp->dd_stat == 0) { /* We haven't started the search yet. */ /* Start the search */ dirp->dd_handle = _tfindfirst(dirp->dd_name, &(dirp->dd_dta)); if (dirp->dd_handle == -1) { /* Whoops! Seems there are no files in that * directory. */ dirp->dd_stat = -1; } else { dirp->dd_stat = 1; } } else { /* Get the next search entry. */ if (_tfindnext(dirp->dd_handle, &(dirp->dd_dta))) { /* We are off the end or otherwise error. _findnext sets errno to ENOENT if no more file Undo this. */ DWORD winerr = GetLastError(); if (winerr == ERROR_NO_MORE_FILES) errno = 0; _findclose(dirp->dd_handle); dirp->dd_handle = -1; dirp->dd_stat = -1; } else { /* Update the status to indicate the correct * number. */ dirp->dd_stat++; } } if (dirp->dd_stat > 0) { /* Successfully got an entry. Everything about the file is * already appropriately filled in except the length of the * file name. */ dirp->dd_dir.d_namlen = (unsigned short)_tcslen(dirp->dd_dta.name); _tcscpy(dirp->dd_dir.d_name, dirp->dd_dta.name); return &dirp->dd_dir; } return (struct _tdirent*) 0; } /* * closedir * * Frees up resources allocated by opendir. */ static int _tclosedir(_TDIR* dirp) { int rc; errno = 0; rc = 0; if (!dirp) { errno = EFAULT; return -1; } if (dirp->dd_handle != -1) { rc = _findclose(dirp->dd_handle); } /* Delete the dir structure. */ al_free(dirp); return rc; } #endif /* ALLEGRO_MSVC */ /* vim: set ft=c sts=3 sw=3 et: */ allegro5-5.2.10.1/src/fullscreen_mode.c000066400000000000000000000021121473414355200175550ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Fullscreen mode queries. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_system.h" /* Function: al_get_num_display_modes */ int al_get_num_display_modes(void) { ALLEGRO_SYSTEM *system = al_get_system_driver(); return system->vt->get_num_display_modes(); } /* Function: al_get_display_mode */ ALLEGRO_DISPLAY_MODE *al_get_display_mode(int index, ALLEGRO_DISPLAY_MODE *mode) { ALLEGRO_SYSTEM *system = al_get_system_driver(); return system->vt->get_display_mode(index, mode); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/gp2xwiz/000077500000000000000000000000001473414355200156615ustar00rootroot00000000000000allegro5-5.2.10.1/src/gp2xwiz/wiz_display_fb.c000066400000000000000000000116631473414355200210410ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * GP2X Wiz framebuffer display driver * * By Trent Gamblin. * */ #include "allegro5/internal/aintern_gp2xwiz.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_opengl.h" ALLEGRO_DEBUG_CHANNEL("display") static ALLEGRO_DISPLAY_INTERFACE *gp2xwiz_vt; static bool set_gfx_mode = false; /* Create a new X11 display, which maps directly to a GLX window. */ static ALLEGRO_DISPLAY *gp2xwiz_create_display_fb(int w, int h) { (void)w; (void)h; /* Only one display allowed at a time */ if (set_gfx_mode) return NULL; lc_init_rest(); ALLEGRO_DISPLAY_GP2XWIZ_FB *d = al_calloc(1, sizeof *d); ALLEGRO_DISPLAY *display = (void *)d; ALLEGRO_SYSTEM_GP2XWIZ *system = (void *)al_get_system_driver(); display->w = 320; display->h = 240; display->vt = _al_display_gp2xwiz_framebuffer_driver(); display->refresh_rate = 60; display->flags = al_get_new_display_flags(); display->flags |= ALLEGRO_FULLSCREEN; /* Add ourself to the list of displays. */ ALLEGRO_DISPLAY_GP2XWIZ_FB **add; add = _al_vector_alloc_back(&system->system.displays); *add = d; /* Each display is an event source. */ _al_event_source_init(&display->es); /* Create a backbuffer and point it to the framebuffer */ al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); d->backbuffer = al_create_bitmap(320, 240); d->screen_mem = d->backbuffer->memory; d->backbuffer->memory = (unsigned char *)lc_fb1; set_gfx_mode = true; ALLEGRO_DEBUG("Display created successfully\n"); return display; } static void gp2xwiz_destroy_display_fb(ALLEGRO_DISPLAY *d) { ALLEGRO_SYSTEM_GP2XWIZ *s = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_GP2XWIZ_FB *wiz_disp = (void *)d; _al_vector_find_and_delete(&s->system.displays, &d); /* All bitmaps are memory bitmaps, no need to do anything */ _al_vector_free(&d->bitmaps); _al_event_source_free(&d->es); wiz_disp->backbuffer->memory = wiz_disp->screen_mem; al_destroy_bitmap(wiz_disp->backbuffer); al_free(d->vertex_cache); al_free(d); set_gfx_mode = false; } static bool gp2xwiz_set_current_display_fb(ALLEGRO_DISPLAY *d) { (void)d; return true; } static void gp2xwiz_flip_display_fb(ALLEGRO_DISPLAY *d) { (void)d; } static void gp2xwiz_update_display_region_fb(ALLEGRO_DISPLAY *d, int x, int y, int w, int h) { (void)x; (void)y; (void)w; (void)h; gp2xwiz_flip_display_fb(d); } static bool gp2xwiz_acknowledge_resize_fb(ALLEGRO_DISPLAY *d) { (void)d; return false; } static bool gp2xwiz_resize_display_fb(ALLEGRO_DISPLAY *d, int w, int h) { (void)d; (void)w; (void)h; return false; } static bool gp2xwiz_is_compatible_bitmap_fb(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { (void)display; (void)bitmap; return true; } static void gp2xwiz_get_window_position_fb(ALLEGRO_DISPLAY *display, int *x, int *y) { (void)display; *x = 0; *y = 0; } static bool gp2xwiz_wait_for_vsync_fb(ALLEGRO_DISPLAY *display) { (void)display; return false; } static ALLEGRO_BITMAP *gp2xwiz_get_backbuffer_fb(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_GP2XWIZ_FB *d = (void *)display; return d->backbuffer; } /* Obtain a reference to this driver. */ ALLEGRO_DISPLAY_INTERFACE *_al_display_gp2xwiz_framebuffer_driver(void) { if (gp2xwiz_vt) return gp2xwiz_vt; gp2xwiz_vt = al_calloc(1, sizeof *gp2xwiz_vt); gp2xwiz_vt->create_display = gp2xwiz_create_display_fb; gp2xwiz_vt->destroy_display = gp2xwiz_destroy_display_fb; gp2xwiz_vt->set_current_display = gp2xwiz_set_current_display_fb; gp2xwiz_vt->flip_display = gp2xwiz_flip_display_fb; gp2xwiz_vt->update_display_region = gp2xwiz_update_display_region_fb; gp2xwiz_vt->acknowledge_resize = gp2xwiz_acknowledge_resize_fb; gp2xwiz_vt->create_bitmap = NULL; gp2xwiz_vt->get_backbuffer = gp2xwiz_get_backbuffer_fb; gp2xwiz_vt->set_target_bitmap = NULL; gp2xwiz_vt->is_compatible_bitmap = gp2xwiz_is_compatible_bitmap_fb; gp2xwiz_vt->resize_display = gp2xwiz_resize_display_fb; gp2xwiz_vt->set_icons = NULL; gp2xwiz_vt->set_window_title = NULL; gp2xwiz_vt->set_window_position = NULL; gp2xwiz_vt->get_window_position = gp2xwiz_get_window_position_fb; gp2xwiz_vt->set_window_constraints = NULL; gp2xwiz_vt->get_window_constraints = NULL; gp2xwiz_vt->set_display_flag = NULL; gp2xwiz_vt->wait_for_vsync = gp2xwiz_wait_for_vsync_fb; return gp2xwiz_vt; } /* vi: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/gp2xwiz/wiz_display_opengl.c000066400000000000000000000162361473414355200217370ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * GP2X Wiz OpenGL display driver * * By Trent Gamblin. * */ #include "allegro5/internal/aintern_gp2xwiz.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_opengl.h" ALLEGRO_DEBUG_CHANNEL("display") static ALLEGRO_DISPLAY_INTERFACE *gp2xwiz_vt; static bool set_gfx_mode = false; /* Helper to set up GL state as we want it. */ static void setup_gl(ALLEGRO_DISPLAY *d) { ALLEGRO_OGL_EXTRAS *ogl = d->ogl_extras; glViewport(0, 0, d->w, d->h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, d->w, d->h, 0, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (!ogl->backbuffer) ogl->backbuffer = _al_ogl_create_backbuffer(d); } /* Create a new X11 display, which maps directly to a GLX window. */ static ALLEGRO_DISPLAY *gp2xwiz_create_display_ogl(int w, int h) { (void)w; (void)h; /* Only one display allowed at a time */ if (set_gfx_mode) return NULL; ALLEGRO_DISPLAY_GP2XWIZ_OGL *d = al_calloc(1, sizeof *d); ALLEGRO_DISPLAY *display = (void*)d; ALLEGRO_OGL_EXTRAS *ogl = al_calloc(1, sizeof *ogl); EGLint numConfigs; display->ogl_extras = ogl; ALLEGRO_SYSTEM_GP2XWIZ *system = (void *)al_get_system_driver(); display->w = 320; display->h = 240; display->vt = _al_display_gp2xwiz_opengl_driver(); display->refresh_rate = 60; display->flags = al_get_new_display_flags(); // FIXME: default? Is this the right place to set this? display->flags |= ALLEGRO_OPENGL; #ifdef ALLEGRO_CFG_OPENGLES2 display->flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; #endif #ifdef ALLEGRO_CFG_OPENGLES display->flags |= ALLEGRO_OPENGL_ES_PROFILE; #endif display->flags |= ALLEGRO_FULLSCREEN; /* Add ourself to the list of displays. */ ALLEGRO_DISPLAY_GP2XWIZ_OGL **add; add = _al_vector_alloc_back(&system->system.displays); *add = d; /* Each display is an event source. */ _al_event_source_init(&display->es); EGLint attrib_list[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 16, EGL_NONE }; EGLint majorVersion, minorVersion; nanoGL_Init(); d->hNativeWnd = OS_CreateWindow(); d->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(d->egl_display, &majorVersion, &minorVersion); ALLEGRO_DEBUG("EGL Version: %d.%d\n", majorVersion, minorVersion); eglChooseConfig(d->egl_display, attrib_list, &d->egl_config, 1, &numConfigs); d->egl_surface = eglCreateWindowSurface(d->egl_display, d->egl_config, d->hNativeWnd, NULL); d->egl_context = eglCreateContext(d->egl_display, d->egl_config, EGL_NO_CONTEXT, NULL); eglMakeCurrent(d->egl_display, d->egl_surface, d->egl_surface, d->egl_context); //eglSwapInterval(d->egl_display, EGL_MAX_SWAP_INTERVAL); ALLEGRO_DEBUG("GP2X Wiz window created.\n"); // FIXME: ALLEGRO_DEBUG("Calling _al_ogl_manage_extensions\n"); _al_ogl_manage_extensions(display); ALLEGRO_DEBUG("Calling _al_ogl_set_extensions\n"); _al_ogl_set_extensions(ogl->extension_api); // FIXME // We don't have this extra_settings stuff set up right //if (display->extra_settings.settings[ALLEGRO_COMPATIBLE_DISPLAY]) setup_gl(display); set_gfx_mode = true; ALLEGRO_DEBUG("Display created successfully\n"); return display; } static void gp2xwiz_destroy_display_ogl(ALLEGRO_DISPLAY *d) { ALLEGRO_SYSTEM_GP2XWIZ *s = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_GP2XWIZ_OGL *wiz_disp = (void *)d; while (d->bitmaps._size > 0) { ALLEGRO_BITMAP **bptr = _al_vector_ref_back(&d->bitmaps); ALLEGRO_BITMAP *b = *bptr; _al_convert_to_memory_bitmap(b); } _al_ogl_unmanage_extensions(d); _al_vector_find_and_delete(&s->system.displays, &d); eglMakeCurrent(wiz_disp->egl_display, 0, 0, wiz_disp->egl_context); eglDestroySurface(wiz_disp->egl_display, wiz_disp->egl_surface); eglDestroyContext(wiz_disp->egl_display, wiz_disp->egl_context); eglTerminate(wiz_disp->egl_display); al_free(wiz_disp->hNativeWnd); nanoGL_Destroy(); _al_vector_free(&d->bitmaps); _al_event_source_free(&d->es); al_free(d->ogl_extras); al_free(d->vertex_cache); al_free(d); set_gfx_mode = false; } static bool gp2xwiz_set_current_display_ogl(ALLEGRO_DISPLAY *d) { (void)d; return true; } static void gp2xwiz_flip_display_ogl(ALLEGRO_DISPLAY *d) { ALLEGRO_DISPLAY_GP2XWIZ_OGL *wiz_disp = (ALLEGRO_DISPLAY_GP2XWIZ_OGL *)d; eglSwapBuffers(wiz_disp->egl_display, wiz_disp->egl_surface); } static void gp2xwiz_update_display_region_ogl(ALLEGRO_DISPLAY *d, int x, int y, int w, int h) { (void)x; (void)y; (void)w; (void)h; gp2xwiz_flip_display_ogl(d); } static bool gp2xwiz_acknowledge_resize_ogl(ALLEGRO_DISPLAY *d) { (void)d; return false; } static bool gp2xwiz_resize_display_ogl(ALLEGRO_DISPLAY *d, int w, int h) { (void)d; (void)w; (void)h; return false; } static bool gp2xwiz_is_compatible_bitmap_ogl(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { (void)display; (void)bitmap; return true; } static void gp2xwiz_get_window_position_ogl(ALLEGRO_DISPLAY *display, int *x, int *y) { (void)display; *x = 0; *y = 0; } static bool gp2xwiz_wait_for_vsync_ogl(ALLEGRO_DISPLAY *display) { (void)display; return false; } /* Obtain a reference to this driver. */ ALLEGRO_DISPLAY_INTERFACE *_al_display_gp2xwiz_opengl_driver(void) { if (gp2xwiz_vt) return gp2xwiz_vt; gp2xwiz_vt = al_calloc(1, sizeof *gp2xwiz_vt); gp2xwiz_vt->create_display = gp2xwiz_create_display_ogl; gp2xwiz_vt->destroy_display = gp2xwiz_destroy_display_ogl; gp2xwiz_vt->set_current_display = gp2xwiz_set_current_display_ogl; gp2xwiz_vt->flip_display = gp2xwiz_flip_display_ogl; gp2xwiz_vt->update_display_region = gp2xwiz_update_display_region_ogl; gp2xwiz_vt->acknowledge_resize = gp2xwiz_acknowledge_resize_ogl; gp2xwiz_vt->create_bitmap = _al_ogl_create_bitmap; gp2xwiz_vt->get_backbuffer = _al_ogl_get_backbuffer; gp2xwiz_vt->set_target_bitmap = _al_ogl_set_target_bitmap; gp2xwiz_vt->is_compatible_bitmap = gp2xwiz_is_compatible_bitmap_ogl; gp2xwiz_vt->resize_display = gp2xwiz_resize_display_ogl; gp2xwiz_vt->set_icons = NULL; gp2xwiz_vt->set_window_title = NULL; gp2xwiz_vt->set_window_position = NULL; gp2xwiz_vt->get_window_position = gp2xwiz_get_window_position_ogl; gp2xwiz_vt->set_window_constraints = NULL; gp2xwiz_vt->get_window_constraints = NULL; gp2xwiz_vt->set_display_flag = NULL; gp2xwiz_vt->wait_for_vsync = gp2xwiz_wait_for_vsync_ogl; _al_ogl_add_drawing_functions(gp2xwiz_vt); return gp2xwiz_vt; } /* vi: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/gp2xwiz/wiz_joystick.c000066400000000000000000000133551473414355200205640ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * GP2X Wiz joystick driver * * by Trent Gamblin. * */ #include #include #include #include #include #include #include #include #include "allegro5/allegro.h" #include "allegro5/joystick.h" #include "allegro5/internal/aintern.h" #include "allegro5/platform/aintwiz.h" #include "allegro5/platform/alwiz.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_gp2xwiz.h" static ALLEGRO_JOYSTICK joy; static ALLEGRO_JOYSTICK_STATE joystate; static ALLEGRO_THREAD *wiz_joystick_thread; const int POLLS_PER_SECOND = 60; #define BUTTON(x) (buttons & x) static void joywiz_fill_joystate(ALLEGRO_JOYSTICK_STATE *state) { uint32_t buttons = lc_getbuttons(); /* Left-right axis */ if (BUTTON(BTN_LEFT)) { state->stick[0].axis[0] = -1; } else if (BUTTON(BTN_RIGHT)) { state->stick[0].axis[0] = 1; } else { state->stick[0].axis[0] = 0; } /* Up-down axis */ if (BUTTON(BTN_UP)) { state->stick[0].axis[1] = -1; } else if (BUTTON(BTN_DOWN)) { state->stick[0].axis[1] = 1; } else { state->stick[0].axis[1] = 0; } /* Other buttons */ state->button[0] = BUTTON(BTN_A); state->button[1] = BUTTON(BTN_B); state->button[2] = BUTTON(BTN_X); state->button[3] = BUTTON(BTN_Y); state->button[4] = BUTTON(BTN_L); state->button[5] = BUTTON(BTN_R); state->button[6] = BUTTON(BTN_MENU); state->button[7] = BUTTON(BTN_SELECT); state->button[8] = BUTTON(BTN_VOLUP); state->button[9] = BUTTON(BTN_VOLDOWN); } static void generate_axis_event(ALLEGRO_JOYSTICK *joy, int stick, int axis, float pos) { ALLEGRO_EVENT event; if (!_al_event_source_needs_to_generate_event(&joy->es)) return; event.joystick.type = ALLEGRO_EVENT_JOYSTICK_AXIS; event.joystick.timestamp = al_get_time(); event.joystick.stick = stick; event.joystick.axis = axis; event.joystick.pos = pos; event.joystick.button = 0; _al_event_source_emit_event(&joy->es, &event); } static void generate_button_event(ALLEGRO_JOYSTICK *joy, int button, ALLEGRO_EVENT_TYPE event_type) { ALLEGRO_EVENT event; if (!_al_event_source_needs_to_generate_event(&joy->es)) return; event.joystick.type = event_type; event.joystick.timestamp = al_get_time(); event.joystick.stick = 0; event.joystick.axis = 0; event.joystick.pos = 0.0; event.joystick.button = button; _al_event_source_emit_event(&joy->es, &event); } static void *joywiz_thread_proc(ALLEGRO_THREAD *thread, void *unused) { ALLEGRO_JOYSTICK_STATE oldstate; memset(&oldstate, 0, sizeof(ALLEGRO_JOYSTICK_STATE)); (void)unused; while (!al_get_thread_should_stop(thread)) { joywiz_fill_joystate(&joystate); if (joystate.stick[0].axis[0] != oldstate.stick[0].axis[0]) { generate_axis_event(&joy, 0, 0, joystate.stick[0].axis[0]); } if (joystate.stick[0].axis[1] != oldstate.stick[0].axis[1]) { generate_axis_event(&joy, 0, 1, joystate.stick[0].axis[1]); } int i; for (i = 0; i < 10; i++) { ALLEGRO_EVENT_TYPE type; if (oldstate.button[i] == 0) type = ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN; else type = ALLEGRO_EVENT_JOYSTICK_BUTTON_UP; if (joystate.button[i] != oldstate.button[i]) { generate_button_event(&joy, i, type); } } oldstate = joystate; al_rest(1.0/POLLS_PER_SECOND); } return NULL; } static void joywiz_fill_joy(void) { joy.info.num_sticks = 1; joy.info.num_buttons = 10; joy.info.stick[0].flags = ALLEGRO_JOYFLAG_DIGITAL; joy.info.stick[0].num_axes = 2; joy.info.stick[0].name = "Wiz D-pad"; joy.info.stick[0].axis[0].name = "Left-right axis"; joy.info.stick[0].axis[1].name = "Up-down axis"; joy.info.button[0].name = "A"; joy.info.button[1].name = "B"; joy.info.button[2].name = "X"; joy.info.button[3].name = "Y"; joy.info.button[4].name = "L"; joy.info.button[5].name = "R"; joy.info.button[6].name = "Menu"; joy.info.button[7].name = "Select"; joy.info.button[8].name = "VolUp"; joy.info.button[9].name = "VolDown"; joy.num = 0; } static bool joywiz_init_joystick(void) { lc_init_joy(); joywiz_fill_joy(); _al_event_source_init(&joy.es); memset(&joystate, 0, sizeof(ALLEGRO_JOYSTICK_STATE)); wiz_joystick_thread = al_create_thread(joywiz_thread_proc, NULL); if (!wiz_joystick_thread) { return false; } al_start_thread(wiz_joystick_thread); return true; } static void joywiz_exit_joystick(void) { al_join_thread(wiz_joystick_thread, NULL); al_destroy_thread(wiz_joystick_thread); _al_event_source_free(&joy.es); } static int joywiz_get_num_joysticks(void) { return 1; } static ALLEGRO_JOYSTICK *joywiz_get_joystick(int num) { (void)num; /* Only 1 supported now */ return &joy; } static void joywiz_release_joystick(ALLEGRO_JOYSTICK *joy) { (void)joy; } static void joywiz_get_joystick_state(ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state) { _al_event_source_lock(&joy->es); { *ret_state = joystate; } _al_event_source_unlock(&joy->es); } /* the driver vtable */ ALLEGRO_JOYSTICK_DRIVER _al_joydrv_gp2xwiz = { AL_JOY_TYPE_GP2XWIZ, "", "", "GP2X Wiz joystick", joywiz_init_joystick, joywiz_exit_joystick, joywiz_get_num_joysticks, joywiz_get_joystick, joywiz_release_joystick, joywiz_get_joystick_state }; allegro5-5.2.10.1/src/gp2xwiz/wiz_system.c000066400000000000000000000106371473414355200202510ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * GP2X Wiz system driver * * By Trent Gamblin. * */ #include #include "allegro5/allegro.h" #include "allegro5/platform/aintunix.h" #include "allegro5/internal/aintern_gp2xwiz.h" #include "allegro5/platform/aintwiz.h" static ALLEGRO_SYSTEM_INTERFACE *gp2xwiz_vt; static ALLEGRO_SYSTEM *gp2xwiz_initialize(int flags) { ALLEGRO_SYSTEM_GP2XWIZ *s; (void)flags; _al_unix_init_time(); s = al_calloc(1, sizeof *s); _al_vector_init(&s->system.displays, sizeof (ALLEGRO_DISPLAY *)); s->system.vt = gp2xwiz_vt; return &s->system; } static void gp2xwiz_shutdown_system(void) { /* Close all open displays. */ ALLEGRO_SYSTEM *s = al_get_system_driver(); ALLEGRO_SYSTEM_GP2XWIZ *sx = (void *)s; while (_al_vector_size(&s->displays) > 0) { ALLEGRO_DISPLAY **dptr = _al_vector_ref(&s->displays, 0); ALLEGRO_DISPLAY *d = *dptr; al_destroy_display(d); } _al_vector_free(&s->displays); al_free(sx); lc_exit(); } static ALLEGRO_DISPLAY_INTERFACE *gp2xwiz_get_display_driver(void) { if (al_get_new_display_flags() & ALLEGRO_OPENGL) return _al_display_gp2xwiz_opengl_driver(); else return _al_display_gp2xwiz_framebuffer_driver(); } static ALLEGRO_KEYBOARD_DRIVER *gp2xwiz_get_keyboard_driver(void) { //return _al_gp2xwiz_keyboard_driver; return NULL; } static ALLEGRO_MOUSE_DRIVER *gp2xwiz_get_mouse_driver(void) { //return _al_gp2xwiz_mouse_driver; return NULL; } static ALLEGRO_JOYSTICK_DRIVER *gp2xwiz_get_joystick_driver(void) { return _al_joystick_driver_list[0].driver; } static int gp2xwiz_get_num_video_adapters(void) { return 1; } static bool gp2xwiz_get_monitor_info(int adapter, ALLEGRO_MONITOR_INFO *info) { (void)adapter; info->x1 = 0; info->y1 = 0; info->x2 = 320; info->y2 = 240; return true; } // FIXME static bool gp2xwiz_get_cursor_position(int *ret_x, int *ret_y) { *ret_x = 0; *ret_y = 0; return true; } static bool gp2xwiz_inhibit_screensaver(bool inhibit) { (void)inhibit; return false; } static int gp2xwiz_get_num_display_modes(void) { return 1; } static ALLEGRO_DISPLAY_MODE *gp2xwiz_get_display_mode(int index, ALLEGRO_DISPLAY_MODE *mode) { (void)index; ASSERT(index == 0); mode->width = 320; mode->height = 240; mode->format = ALLEGRO_PIXEL_FORMAT_RGB_565; mode->refresh_rate = 60; return mode; } /* Internal function to get a reference to this driver. */ ALLEGRO_SYSTEM_INTERFACE *_al_system_gp2xwiz_driver(void) { if (gp2xwiz_vt) return gp2xwiz_vt; gp2xwiz_vt = al_calloc(1, sizeof *gp2xwiz_vt); gp2xwiz_vt->id = ALLEGRO_SYSTEM_ID_GP2XWIZ; gp2xwiz_vt->initialize = gp2xwiz_initialize; gp2xwiz_vt->get_display_driver = gp2xwiz_get_display_driver; gp2xwiz_vt->get_keyboard_driver = gp2xwiz_get_keyboard_driver; gp2xwiz_vt->get_mouse_driver = gp2xwiz_get_mouse_driver; gp2xwiz_vt->get_joystick_driver = gp2xwiz_get_joystick_driver; gp2xwiz_vt->get_num_display_modes = gp2xwiz_get_num_display_modes; gp2xwiz_vt->get_display_mode = gp2xwiz_get_display_mode; gp2xwiz_vt->shutdown_system = gp2xwiz_shutdown_system; gp2xwiz_vt->get_num_video_adapters = gp2xwiz_get_num_video_adapters; gp2xwiz_vt->get_monitor_info = gp2xwiz_get_monitor_info; gp2xwiz_vt->get_cursor_position = gp2xwiz_get_cursor_position; gp2xwiz_vt->get_path = _al_unix_get_path; gp2xwiz_vt->inhibit_screensaver = gp2xwiz_inhibit_screensaver; gp2xwiz_vt->get_num_display_formats = gp2xwiz_get_num_display_formats; gp2xwiz_vt->get_time = _al_unix_get_time; gp2xwiz_vt->rest = _al_unix_rest; gp2xwiz_vt->init_timeout = _al_unix_init_timeout; return gp2xwiz_vt; } /* This is a function each platform must define to register all available * system drivers. */ void _al_register_system_interfaces(void) { ALLEGRO_SYSTEM_INTERFACE **add; add = _al_vector_alloc_back(&_al_system_interfaces); *add = _al_system_gp2xwiz_driver(); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/haptic.c000066400000000000000000000176441473414355200156770ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Haptic API. * * By Beoran. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/haptic.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_haptic.h" #include "allegro5/internal/aintern_system.h" /* the active haptic driver */ static ALLEGRO_HAPTIC_DRIVER *haptic_driver = NULL; /* Function: al_install_haptic */ bool al_install_haptic(void) { ALLEGRO_SYSTEM *sysdrv; ALLEGRO_HAPTIC_DRIVER *hapdrv; if (haptic_driver) return true; sysdrv = al_get_system_driver(); ASSERT(sysdrv); /* Currently every platform only has at most one haptic driver. */ if (sysdrv->vt->get_haptic_driver) { hapdrv = sysdrv->vt->get_haptic_driver(); /* Avoid race condition in case the haptic driver generates an * event right after ->init_haptic. */ if (hapdrv && hapdrv->init_haptic()) { haptic_driver = hapdrv; _al_add_exit_func(al_uninstall_haptic, "al_uninstall_haptic"); return true; } } return false; } /* Function: al_uninstall_haptic */ void al_uninstall_haptic(void) { if (haptic_driver) { /* perform driver clean up */ haptic_driver->exit_haptic(); haptic_driver = NULL; } } /* Function: al_is_haptic_installed */ bool al_is_haptic_installed(void) { return (haptic_driver) ? true : false; } /* Function: al_is_joystick_haptic */ bool al_is_joystick_haptic(ALLEGRO_JOYSTICK *dev) { ASSERT(dev); ASSERT(haptic_driver); return haptic_driver->is_joystick_haptic(dev); } /* Function: al_is_mouse_haptic */ bool al_is_mouse_haptic(ALLEGRO_MOUSE *dev) { ASSERT(dev); ASSERT(haptic_driver); return haptic_driver->is_mouse_haptic(dev); } /* Function: al_is_keyboard_haptic */ bool al_is_keyboard_haptic(ALLEGRO_KEYBOARD *dev) { ASSERT(dev); ASSERT(haptic_driver); return haptic_driver->is_keyboard_haptic(dev); } /* Function: al_is_display_haptic */ bool al_is_display_haptic(ALLEGRO_DISPLAY *dev) { ASSERT(dev); ASSERT(haptic_driver); return haptic_driver->is_display_haptic(dev); } /* Function: al_is_touch_input_haptic */ bool al_is_touch_input_haptic(ALLEGRO_TOUCH_INPUT *dev) { ASSERT(dev); ASSERT(haptic_driver); return haptic_driver->is_touch_input_haptic(dev); } /* Function: al_get_haptic_from_joystick */ ALLEGRO_HAPTIC *al_get_haptic_from_joystick(ALLEGRO_JOYSTICK *dev) { ASSERT(dev); ASSERT(haptic_driver); return haptic_driver->get_from_joystick(dev); } /* Function: al_get_haptic_from_mouse */ ALLEGRO_HAPTIC *al_get_haptic_from_mouse(ALLEGRO_MOUSE *dev) { ASSERT(dev); ASSERT(haptic_driver); return haptic_driver->get_from_mouse(dev); } /* Function: al_get_haptic_from_keyboard */ ALLEGRO_HAPTIC *al_get_haptic_from_keyboard(ALLEGRO_KEYBOARD *dev) { ASSERT(dev); ASSERT(haptic_driver); return haptic_driver->get_from_keyboard(dev); } /* Function: al_get_haptic_from_display */ ALLEGRO_HAPTIC *al_get_haptic_from_display(ALLEGRO_DISPLAY *dev) { ASSERT(dev); ASSERT(haptic_driver); return haptic_driver->get_from_display(dev); } /* Function: al_get_haptic_from_touch_input */ ALLEGRO_HAPTIC *al_get_haptic_from_touch_input(ALLEGRO_TOUCH_INPUT *dev) { ASSERT(dev); ASSERT(haptic_driver); return haptic_driver->get_from_touch_input(dev); } /* Function: al_is_haptic_active */ bool al_is_haptic_active(ALLEGRO_HAPTIC *hap) { ASSERT(hap); ASSERT(haptic_driver); return haptic_driver->get_active(hap); } /* Function: al_get_haptic_capabilities */ int al_get_haptic_capabilities(ALLEGRO_HAPTIC *hap) { ASSERT(hap); ASSERT(haptic_driver); return haptic_driver->get_capabilities(hap); } /* Function: al_is_haptic_capable */ bool al_is_haptic_capable(ALLEGRO_HAPTIC * hap, int query) { int capabilities = al_get_haptic_capabilities(hap); return (capabilities & query) == query; } /* Function: al_get_haptic_gain */ double al_get_haptic_gain(ALLEGRO_HAPTIC *hap) { ASSERT(hap); ASSERT(haptic_driver); return haptic_driver->get_gain(hap); } /* Function: al_set_haptic_gain */ bool al_set_haptic_gain(ALLEGRO_HAPTIC *hap, double gain) { ASSERT(hap); ASSERT(haptic_driver); return haptic_driver->set_gain(hap, gain); } /* Function: al_get_haptic_autocenter */ double al_get_haptic_autocenter(ALLEGRO_HAPTIC *hap) { ASSERT(hap); ASSERT(haptic_driver); return haptic_driver->get_autocenter(hap); } /* Function: al_set_haptic_autocenter */ bool al_set_haptic_autocenter(ALLEGRO_HAPTIC *hap, double intensity) { ASSERT(hap); ASSERT(haptic_driver); return haptic_driver->set_autocenter(hap, intensity); } /* Function: al_get_max_haptic_effects */ int al_get_max_haptic_effects(ALLEGRO_HAPTIC *hap) { ASSERT(hap); ASSERT(haptic_driver); return haptic_driver->get_max_effects(hap); } /* Function: al_is_haptic_effect_ok */ bool al_is_haptic_effect_ok(ALLEGRO_HAPTIC *hap, ALLEGRO_HAPTIC_EFFECT *effect) { ASSERT(hap); ASSERT(haptic_driver); return haptic_driver->is_effect_ok(hap, effect); } /* Function: al_upload_haptic_effect */ bool al_upload_haptic_effect(ALLEGRO_HAPTIC *hap, ALLEGRO_HAPTIC_EFFECT *effect, ALLEGRO_HAPTIC_EFFECT_ID *id) { ASSERT(hap); ASSERT(haptic_driver); return haptic_driver->upload_effect(hap, effect, id); } /* Function: al_play_haptic_effect */ bool al_play_haptic_effect(ALLEGRO_HAPTIC_EFFECT_ID *id, int loop) { ASSERT(haptic_driver); ASSERT(id); return haptic_driver->play_effect(id, loop); } /* Function: al_upload_and_play_haptic_effect */ bool al_upload_and_play_haptic_effect(ALLEGRO_HAPTIC *hap, ALLEGRO_HAPTIC_EFFECT *effect, ALLEGRO_HAPTIC_EFFECT_ID *id, int loop) { ASSERT(hap); ASSERT(effect); ASSERT(id); if (!al_upload_haptic_effect(hap, effect, id)) return false; /* If playing the effect failed, unload the haptic effect automatically */ if (!al_play_haptic_effect(id, loop)) { al_release_haptic_effect(id); return false; } return true; } /* Function: al_stop_haptic_effect */ bool al_stop_haptic_effect(ALLEGRO_HAPTIC_EFFECT_ID *id) { ASSERT(id); return haptic_driver->stop_effect(id); } /* Function: al_is_haptic_effect_playing */ bool al_is_haptic_effect_playing(ALLEGRO_HAPTIC_EFFECT_ID *id) { ASSERT(id); return haptic_driver->is_effect_playing(id); } /* Function: al_get_haptic_effect_duration */ double al_get_haptic_effect_duration(ALLEGRO_HAPTIC_EFFECT * effect) { return effect->replay.delay + effect->replay.length; } /* Function: al_rumble_haptic */ bool al_rumble_haptic(ALLEGRO_HAPTIC *hap, double intensity, double duration, ALLEGRO_HAPTIC_EFFECT_ID *id) { ALLEGRO_HAPTIC_EFFECT effect; ASSERT(hap); ASSERT(id); effect.type = ALLEGRO_HAPTIC_RUMBLE; effect.data.rumble.strong_magnitude = intensity; effect.data.rumble.weak_magnitude = intensity; effect.replay.delay = 0.0; effect.replay.length = duration; return al_upload_and_play_haptic_effect(hap, &effect, id, 1); } /* Function: al_release_haptic_effect */ bool al_release_haptic_effect(ALLEGRO_HAPTIC_EFFECT_ID *id) { ASSERT(haptic_driver); ASSERT(id); return haptic_driver->release_effect(id); } /* Function: al_release_haptic */ bool al_release_haptic(ALLEGRO_HAPTIC *haptic) { ASSERT(haptic_driver); ASSERT(haptic); return haptic_driver->release(haptic); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/inline.c000066400000000000000000000025231473414355200156730ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Copies of the inline functions in allegro.h, in case anyone needs * to take the address of them, or is compiling without optimisation. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #include "allegro5/platform/alplatf.h" // apple's cross-compiler already adds the symbols for the "extern __inline__" // declared variants, so the ones here are duplicates and the linker dies #ifndef ALLEGRO_IPHONE #define AL_INLINE(type, name, args, code) \ extern type name args; \ type name args code #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #ifdef ALLEGRO_INTERNAL_HEADER #include ALLEGRO_INTERNAL_HEADER #endif /* not used now */ /* #include "allegro5/internal/aintern_atomicops.h" */ #include "allegro5/internal/aintern_float.h" #include "allegro5/internal/aintern_vector.h" #endif allegro5-5.2.10.1/src/iphone/000077500000000000000000000000001473414355200155315ustar00rootroot00000000000000allegro5-5.2.10.1/src/iphone/EAGLView.h000066400000000000000000000033041473414355200172450ustar00rootroot00000000000000#import #import #import #import #include #include #include /* This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass. The view content is basically an EAGL surface you render your OpenGL scene into. Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel. */ @interface EAGLView : UIView { @private EAGLContext *context; ALLEGRO_DISPLAY *allegro_display; /* OpenGL names for the renderbuffer and framebuffers used to render to this view */ GLuint viewRenderbuffer, viewFramebuffer; /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */ GLuint depthRenderbuffer; /* Stuff for managing ID's for touches. List held struct which connect UITouch with ID on Allegro site. * NSMutableIndexSet hold list of free id's which were used. 'next_free_touch_id' hold next unused ID. * * 'touch_list' serve actuall as dictionary which map UITouch do ID. */ _AL_LIST* touch_list; NSMutableIndexSet* touch_id_set; UITouch* primary_touch; int next_free_touch_id; float scale; } @property (nonatomic, retain) EAGLContext *context; @property GLint backingWidth; @property GLint backingHeight; - (void)make_current; - (void)flip; - (void)reset_framebuffer; - (void)set_allegro_display:(ALLEGRO_DISPLAY *)display; - (BOOL) createFramebuffer; - (void) destroyFramebuffer; - (BOOL)orientation_supported:(UIInterfaceOrientation)o; @end allegro5-5.2.10.1/src/iphone/EAGLView.m000066400000000000000000000277451473414355200172710ustar00rootroot00000000000000#import #import #import "EAGLView.h" #import "allegroAppDelegate.h" #include #include #include "allegro5/allegro_iphone.h" #include "allegro5/internal/aintern_iphone.h" ALLEGRO_DEBUG_CHANNEL("iphone") typedef struct touch_t { int id; UITouch* touch; } touch_t; /* Every UITouch have associated touch_t structure. This destructor * is used in list which held touch information. While ending touch it will * be called and memory will be freed. */ static void touch_item_dtor(void* value, void* userdata) { (void)userdata; al_free(value); } /* Search for touch_t associated with UITouch. */ static touch_t* find_touch(_AL_LIST* list, UITouch* nativeTouch) { _AL_LIST_ITEM* item; for (item = _al_list_front(list); item; item = _al_list_next(list, item)) { touch_t* touch = (touch_t*)_al_list_item_data(item); if (touch->touch == nativeTouch) return touch; } return NULL; } @implementation EAGLView @synthesize context; @synthesize backingWidth; @synthesize backingHeight; // You must implement this method + (Class)layerClass { return [CAEAGLLayer class]; } - (void)set_allegro_display:(ALLEGRO_DISPLAY *)display { ALLEGRO_DISPLAY_IPHONE *d = (ALLEGRO_DISPLAY_IPHONE *)display; allegro_display = display; // Get the layer CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; NSString *color_format = kEAGLColorFormatRGBA8; if (display->extra_settings.settings[ALLEGRO_COLOR_SIZE] == 16) color_format = kEAGLColorFormatRGB565; eaglLayer.opaque = YES; eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, color_format, kEAGLDrawablePropertyColorFormat, nil]; if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { ALLEGRO_INFO("Attempting to create ES2 context\n"); context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; if (context == nil) { ALLEGRO_WARN("ES2 context could not be created. Attempting to create ES1 context instead.\n"); display->flags &= ~ ALLEGRO_PROGRAMMABLE_PIPELINE; context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; } } else { ALLEGRO_INFO("Attempting to create ES1 context.\n"); context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; } ALLEGRO_INFO("Context is %p\n", context); if (!context || ![EAGLContext setCurrentContext:context]) { ALLEGRO_ERROR("context is nil or setCurrentContext failed.\n"); [self release]; return; } /* FIXME: Make this depend on a display setting. */ [self setMultipleTouchEnabled:YES]; ALLEGRO_INFO("Created EAGLView.\n"); } - (id)initWithFrame:(CGRect)frame { ALLEGRO_DEBUG("Creating UIView.\n"); self = [super initWithFrame:frame]; touch_list = _al_list_create(); primary_touch = NULL; touch_id_set = [[NSMutableIndexSet alloc] init]; next_free_touch_id = 1; return self; } - (void)make_current { [EAGLContext setCurrentContext:context]; glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); } - (void)reset_framebuffer { glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); } - (void)flip { glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); [context presentRenderbuffer:GL_RENDERBUFFER_OES]; } - (void)send_resize_event { ALLEGRO_DISPLAY *display = allegro_display; int x = self.frame.origin.x; int y = self.frame.origin.y; int w = self.frame.size.width; int h = self.frame.size.height; _al_event_source_lock(&display->es); if (_al_event_source_needs_to_generate_event(&display->es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_RESIZE; event.display.timestamp = al_get_time(); event.display.x = x; event.display.y = y; event.display.width = w; event.display.height = h; event.display.orientation = _al_iphone_get_orientation(display); _al_event_source_emit_event(&display->es, &event); } _al_event_source_unlock(&display->es); } - (void)layoutSubviews { [EAGLContext setCurrentContext:context]; if (!viewRenderbuffer) { [self createFramebuffer]; /* Depending on the orientation, the initial framebuffer dimensions may be * rotated so we need to update them. For example * a call to al_create_display(480, 640) will create a display of * 640x480 pixels in landscape mode. */ allegro_display->w = backingWidth; allegro_display->h = backingHeight; } [self send_resize_event]; } - (BOOL)orientation_supported:(UIInterfaceOrientation) o { if (!allegro_display) return NO; ALLEGRO_DISPLAY_IPHONE *d = (ALLEGRO_DISPLAY_IPHONE *)allegro_display; if (d->extra->adapter != 0) return NO; ALLEGRO_EXTRA_DISPLAY_SETTINGS *options = &allegro_display->extra_settings; int supported = options->settings[ALLEGRO_SUPPORTED_ORIENTATIONS]; if (o == UIInterfaceOrientationPortrait) return supported & ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES; if (o == UIInterfaceOrientationLandscapeLeft) return supported & ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES; if (o == UIInterfaceOrientationPortraitUpsideDown) return supported & ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES; if (o == UIInterfaceOrientationLandscapeRight) return supported & ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES; return NO; } - (BOOL)createFramebuffer { ALLEGRO_DISPLAY_IPHONE *d = (ALLEGRO_DISPLAY_IPHONE *)allegro_display; if (d->extra->adapter == 0 && [self respondsToSelector:@selector(contentScaleFactor)]) { scale = self.contentScaleFactor = [[UIScreen mainScreen] scale]; ALLEGRO_INFO("Screen scale is %f\n", self.contentScaleFactor); } else { scale = 1.0f; } glGenFramebuffersOES(1, &viewFramebuffer); glGenRenderbuffersOES(1, &viewRenderbuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer]; glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); ALLEGRO_INFO("Creating GL framebuffer %dx%d.\n", backingWidth, backingHeight); if (allegro_display->extra_settings.settings[ALLEGRO_DEPTH_SIZE]) { GLint depth_stencil_format; if (allegro_display->extra_settings.settings[ALLEGRO_STENCIL_SIZE]) { depth_stencil_format = GL_DEPTH24_STENCIL8_OES; } else { depth_stencil_format = GL_DEPTH_COMPONENT16_OES; } glGenRenderbuffersOES(1, &depthRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depth_stencil_format, backingWidth, backingHeight); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer); if (allegro_display->extra_settings.settings[ALLEGRO_STENCIL_SIZE]) { glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer); } } if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); return NO; } return YES; } - (void)destroyFramebuffer { glDeleteFramebuffersOES(1, &viewFramebuffer); viewFramebuffer = 0; glDeleteRenderbuffersOES(1, &viewRenderbuffer); viewRenderbuffer = 0; if (depthRenderbuffer) { glDeleteRenderbuffersOES(1, &depthRenderbuffer); depthRenderbuffer = 0; } } - (void)dealloc { if (touch_list) _al_list_destroy(touch_list); [touch_id_set release]; if ([EAGLContext currentContext] == context) { [EAGLContext setCurrentContext:nil]; } [context release]; [super dealloc]; } /* Handling of touch events. */ -(NSArray*)getSortedTouches:(NSSet*)touches { NSArray* unsorted = [NSArray arrayWithArray: [touches allObjects]]; NSArray* sorted = [unsorted sortedArrayUsingComparator: ^(id obj1, id obj2) { if ([obj1 timestamp] > [obj2 timestamp]) return (NSComparisonResult)NSOrderedDescending; else if ([obj1 timestamp] < [obj2 timestamp]) return (NSComparisonResult)NSOrderedAscending; else return (NSComparisonResult)NSOrderedSame; }]; return sorted; } // Handles the start of a touch -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { (void)event; // TODO: handle double-clicks (send two events?) // NSUInteger numTaps = [[touches anyObject] tapCount]; // Enumerate through all the touch objects. for (UITouch *nativeTouch in touches) { /* Create new touch_t and associate ID with UITouch. */ touch_t* touch = al_malloc(sizeof(touch_t)); touch->touch = nativeTouch; if ([touch_id_set count] != 0) { touch->id = [touch_id_set firstIndex]; [touch_id_set removeIndex:touch->id]; } else touch->id = next_free_touch_id++; _al_list_push_back_ex(touch_list, touch, touch_item_dtor); CGPoint p = [nativeTouch locationInView:[nativeTouch view]]; if (NULL == primary_touch) primary_touch = nativeTouch; _al_iphone_touch_input_handle_begin(touch->id, al_get_time(), p.x*scale, p.y*scale, primary_touch == nativeTouch, allegro_display); } } // Handles the continuation of a touch. -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { (void)event; touch_t* touch; // Enumerates through all touch objects for (UITouch *nativeTouch in touches) { if ((touch = find_touch(touch_list, nativeTouch))) { CGPoint p = [nativeTouch locationInView:[nativeTouch view]]; _al_iphone_touch_input_handle_move(touch->id, al_get_time(), p.x*scale, p.y*scale, primary_touch == nativeTouch, allegro_display); } } } // Handles the end of a touch event. -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { (void)event; touch_t* touch; // Enumerates through all touch objects for (UITouch *nativeTouch in touches) { if ((touch = find_touch(touch_list, nativeTouch))) { CGPoint p = [nativeTouch locationInView:[nativeTouch view]]; _al_iphone_touch_input_handle_end(touch->id, al_get_time(), p.x*scale, p.y*scale, primary_touch == nativeTouch, allegro_display); [touch_id_set addIndex:touch->id]; _al_list_remove(touch_list, touch); if (primary_touch == nativeTouch) primary_touch = NULL; } } } // Quoting Apple docs: // "The system cancelled tracking for the touch, as when (for example) the user // puts the device to his or her face." -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { (void)event; touch_t* touch; // Enumerates through all touch objects for (UITouch *nativeTouch in touches) { if ((touch = find_touch(touch_list, nativeTouch))) { CGPoint p = [nativeTouch locationInView:[nativeTouch view]]; _al_iphone_touch_input_handle_cancel(touch->id, al_get_time(), p.x*scale, p.y*scale, primary_touch == nativeTouch, allegro_display); if (primary_touch == nativeTouch) primary_touch = NULL; [touch_id_set addIndex:touch->id]; _al_list_remove(touch_list, touch); } } } -(BOOL)canBecomeFirstResponder { return YES; } -(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { (void)motion; } @end allegro5-5.2.10.1/src/iphone/ViewController.h000066400000000000000000000002701473414355200206570ustar00rootroot00000000000000#import struct ALLEGRO_DISPLAY; @interface ViewController : UIViewController { @public int adapter; struct ALLEGRO_DISPLAY *display; } - (void) create_view; @end allegro5-5.2.10.1/src/iphone/ViewController.m000066400000000000000000000071431473414355200206720ustar00rootroot00000000000000#import "ViewController.h" #import "EAGLView.h" #import #include "allegroAppDelegate.h" ALLEGRO_DEBUG_CHANNEL("iphone"); @implementation ViewController - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } - (void)loadView { } - (void)viewDidLoad { ALLEGRO_DEBUG("Loading view controller.\n"); display = NULL; } - (void)viewDidUnload { [super viewDidUnload]; } - (BOOL)shouldAutorotate { ALLEGRO_DISPLAY_IPHONE *d = (ALLEGRO_DISPLAY_IPHONE *)display; if (display == NULL) return YES; if (d->extra->adapter != 0) { return NO; } return YES; } /* Taken from Apple docs */ /* typedef enum { UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait), UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft), UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight), UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown), UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight), UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown), UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight), } UIInterfaceOrientationMask; */ - (NSUInteger)supportedInterfaceOrientations { if (!display) return UIInterfaceOrientationMaskAll; ALLEGRO_DISPLAY_IPHONE *d = (ALLEGRO_DISPLAY_IPHONE *)display; if (d->extra->adapter != 0) return UIInterfaceOrientationMaskAll; ALLEGRO_EXTRA_DISPLAY_SETTINGS *options = &display->extra_settings; int supported = options->settings[ALLEGRO_SUPPORTED_ORIENTATIONS]; int mask = 0; switch (supported) { default: case ALLEGRO_DISPLAY_ORIENTATION_ALL: mask = UIInterfaceOrientationMaskAll; break; case ALLEGRO_DISPLAY_ORIENTATION_PORTRAIT: mask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; break; case ALLEGRO_DISPLAY_ORIENTATION_LANDSCAPE: mask = UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight; break; case ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES: mask = UIInterfaceOrientationMaskPortrait; break; case ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES: mask = UIInterfaceOrientationMaskLandscapeRight; break; case ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES: mask = UIInterfaceOrientationMaskPortraitUpsideDown; break; case ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES: mask = UIInterfaceOrientationMaskLandscapeLeft; break; } return mask; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { ALLEGRO_DISPLAY_IPHONE *d = (ALLEGRO_DISPLAY_IPHONE *)display; if (display == NULL) return YES; if (d->extra->adapter != 0) { return NO; } EAGLView *view = (EAGLView *)al_iphone_get_view(display); if (view) { return [view orientation_supported:interfaceOrientation]; } return NO; } - (void) create_view { UIScreen *screen; if (adapter == 0) screen = [UIScreen mainScreen]; else screen = [[UIScreen screens] objectAtIndex:adapter]; self.view = [[EAGLView alloc] initWithFrame:[screen bounds]]; [self.view release]; } @end allegro5-5.2.10.1/src/iphone/allegroAppDelegate.h000066400000000000000000000011401473414355200214170ustar00rootroot00000000000000#import #include #import "ViewController.h" struct ALLEGRO_DISPLAY_IPHONE_EXTRA { bool failed; ViewController *vc; UIWindow *window; int adapter; bool disconnected; }; @class EAGLView; @interface allegroAppDelegate : NSObject { @public ALLEGRO_DISPLAY *main_display; } + (void)run:(int)argc:(char **)argv; - (void)add_view:(NSValue *)value; - (void)orientation_change:(NSNotification *)notification; - (void)setupScreenConnectionNotificationHandlers; - (void)add_screen:(UIScreen *)screen; @end allegro5-5.2.10.1/src/iphone/allegroAppDelegate.m000066400000000000000000000513541473414355200214400ustar00rootroot00000000000000#import "allegroAppDelegate.h" #import "EAGLView.h" #import #include #include "allegro5/allegro_opengl.h" #include "allegro5/allegro_iphone.h" #include "allegro5/internal/aintern_opengl.h" ALLEGRO_DEBUG_CHANNEL("iphone") void _al_iphone_run_user_main(void); static allegroAppDelegate *global_delegate; static UIApplication *app = NULL; static volatile bool waiting_for_program_halt = false; static bool disconnect_wait = false; static UIScreen *airplay_screen = NULL; static bool airplay_connected = false; ALLEGRO_MUTEX *_al_iphone_display_hotplug_mutex = NULL; /* Screen handling */ @interface iphone_screen : NSObject { @public int adapter; UIScreen *screen; UIWindow *window; ViewController *vc; EAGLView *view; ALLEGRO_DISPLAY *display; } @end @implementation iphone_screen @end void _al_iphone_disconnect(ALLEGRO_DISPLAY *display) { (void)display; disconnect_wait = false; } static NSMutableArray *iphone_screens; static int iphone_get_adapter(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_IPHONE *d = (ALLEGRO_DISPLAY_IPHONE *)display; return d->extra->adapter; } static iphone_screen *iphone_get_screen_by_adapter(int adapter) { al_lock_mutex(_al_iphone_display_hotplug_mutex); int num = [iphone_screens count]; int i; iphone_screen *ret = NULL; for (i = 0; i < num; i++) { iphone_screen *scr = [iphone_screens objectAtIndex:i]; if (scr->adapter == adapter) { ret = scr; break; } } al_unlock_mutex(_al_iphone_display_hotplug_mutex); return ret; } static iphone_screen *iphone_get_screen(ALLEGRO_DISPLAY *display) { int adapter = iphone_get_adapter(display); return iphone_get_screen_by_adapter(adapter); } bool _al_iphone_is_display_connected(ALLEGRO_DISPLAY *display) { iphone_screen *scr = iphone_get_screen(display); return scr && (scr->display == display); } static void iphone_remove_screen(UIScreen *screen) { al_lock_mutex(_al_iphone_display_hotplug_mutex); int num_screens = [iphone_screens count]; int i; for (i = 1; i < num_screens; i++) { iphone_screen *scr = iphone_get_screen_by_adapter(i); if (scr->screen == screen) { [iphone_screens removeObjectAtIndex:i]; [scr release]; break; } } al_unlock_mutex(_al_iphone_display_hotplug_mutex); } void _al_iphone_destroy_screen(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_IPHONE *d = (ALLEGRO_DISPLAY_IPHONE *)display; if (d->extra->adapter == 0) { global_delegate->main_display = NULL; } al_free(d->extra); } // create iphone_screen for all currently attached screens static void iphone_create_screens(void) { iphone_screens = [[NSMutableArray alloc] init]; _al_iphone_display_hotplug_mutex = al_create_mutex_recursive(); if ([UIScreen respondsToSelector:NSSelectorFromString(@"screens")]) { int num_screens; int i; num_screens = [[UIScreen screens] count];; for (i = 0; i < num_screens && i < 2; i++) { if (i == 1) { airplay_screen = [[UIScreen screens] objectAtIndex:i]; continue; } [global_delegate add_screen:[[UIScreen screens] objectAtIndex:i]]; } } else { [global_delegate add_screen:[UIScreen mainScreen]]; } } /* Function: al_iphone_get_window */ UIWindow *al_iphone_get_window(ALLEGRO_DISPLAY *display) { al_lock_mutex(_al_iphone_display_hotplug_mutex); iphone_screen *scr = iphone_get_screen(display); if (scr == NULL) { al_unlock_mutex(_al_iphone_display_hotplug_mutex); return NULL; } al_unlock_mutex(_al_iphone_display_hotplug_mutex); return scr->window; } /* Function: al_iphone_get_view */ UIView *al_iphone_get_view(ALLEGRO_DISPLAY *display) { iphone_screen *scr = iphone_get_screen(display); if (scr == NULL) { return NULL; } return scr->vc.view; } static int iphone_orientation_to_allegro(UIDeviceOrientation orientation) { switch (orientation) { case UIDeviceOrientationPortrait: return ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES; case UIDeviceOrientationPortraitUpsideDown: return ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES; case UIDeviceOrientationLandscapeRight: return ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES; case UIDeviceOrientationLandscapeLeft: return ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES; case UIDeviceOrientationFaceUp: return ALLEGRO_DISPLAY_ORIENTATION_FACE_UP; case UIDeviceOrientationFaceDown: return ALLEGRO_DISPLAY_ORIENTATION_FACE_DOWN; default: return ALLEGRO_DISPLAY_ORIENTATION_UNKNOWN; } } static void iphone_send_orientation_event(ALLEGRO_DISPLAY* display, int orientation) { _al_event_source_lock(&display->es); if (_al_event_source_needs_to_generate_event(&display->es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_ORIENTATION; event.display.timestamp = al_get_time(); event.display.source = display; event.display.orientation = orientation; _al_event_source_emit_event(&display->es, &event); } _al_event_source_unlock(&display->es); } void _al_iphone_acknowledge_drawing_halt(ALLEGRO_DISPLAY *display) { (void)display; waiting_for_program_halt = false; } /* Function: al_iphone_set_statusbar_orientation */ void al_iphone_set_statusbar_orientation(int o) { UIInterfaceOrientation orientation = UIInterfaceOrientationPortrait; if (o == ALLEGRO_IPHONE_STATUSBAR_ORIENTATION_PORTRAIT) orientation = UIInterfaceOrientationPortrait; else if (o == ALLEGRO_IPHONE_STATUSBAR_ORIENTATION_PORTRAIT_UPSIDE_DOWN) orientation = UIInterfaceOrientationPortraitUpsideDown; else if (o == ALLEGRO_IPHONE_STATUSBAR_ORIENTATION_LANDSCAPE_RIGHT) orientation = UIInterfaceOrientationLandscapeRight; else if (o == ALLEGRO_IPHONE_STATUSBAR_ORIENTATION_LANDSCAPE_LEFT) orientation = UIInterfaceOrientationLandscapeLeft; [app setStatusBarOrientation:orientation animated:NO]; } bool _al_iphone_add_view(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_IPHONE *d = (ALLEGRO_DISPLAY_IPHONE *)display; d->extra = al_calloc(1, sizeof(ALLEGRO_DISPLAY_IPHONE_EXTRA)); int adapter = al_get_new_display_adapter(); if (adapter < 0) adapter = 0; d->extra->adapter = adapter; /* This is the same as * [global_delegate.view add_view]; * except it will run in the main thread. */ [global_delegate performSelectorOnMainThread: @selector(add_view:) withObject: [NSValue valueWithPointer:display] waitUntilDone: YES]; if (d->extra->failed) { return false; } /* There are two ways to get orientation information under ios - but they seem * to be mutually exclusive (just my experience, the documentation never says * they are). * One method has 6 orientations including face up and face down and is * independent of the screen orientations, just directly using the accelerometer * to determine how the device is positioned relative to gravity. The other * method has 4 orientations and simply tells how the view controller thinks * the user interface should be rotated. * * Supporting both at the same time is a) slightly confusing since we'd need * two sets of query functions and events and b) does not seem to work due to * the mutual exclusivity. * * Now normally using just the 4-orientation way would appear to be the best * choice as you can always use the accelerometer anyway to get the actual * 3d orientation and otherwise are likely more concerned with the orientation * things are being displayed at right now (instead of just seeing FACE_UP which * would not tell you). * * But to stay compatible with how things worked at first we still support the * 6-orientations way as well - but only if the display has a sole supported * orientation of ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES. */ ALLEGRO_EXTRA_DISPLAY_SETTINGS *options = &display->extra_settings; int supported = options->settings[ALLEGRO_SUPPORTED_ORIENTATIONS]; if (supported == ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES) { [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; } return true; } void _al_iphone_make_view_current(ALLEGRO_DISPLAY *display) { iphone_screen *scr = iphone_get_screen(display); if (scr) [scr->view make_current]; } void _al_iphone_recreate_framebuffer(ALLEGRO_DISPLAY *display) { iphone_screen *scr = iphone_get_screen(display); if (scr) { EAGLView *view = scr->view; [view destroyFramebuffer]; [view createFramebuffer]; display->w = view.backingWidth; display->h = view.backingHeight; _al_ogl_resize_backbuffer(display->ogl_extras->backbuffer, display->w, display->h); } } void _al_iphone_flip_view(ALLEGRO_DISPLAY *display) { iphone_screen *scr = iphone_get_screen(display); if (scr) [scr->view flip]; } void _al_iphone_reset_framebuffer(ALLEGRO_DISPLAY *display) { iphone_screen *scr = iphone_get_screen(display); if (scr) [scr->view reset_framebuffer]; } /* Use a frequency to start receiving events at the freuqency, 0 to shut off * the accelerometer (according to Apple, it drains a bit of battery while on). */ void _al_iphone_accelerometer_control(int frequency) { if (frequency) { [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / frequency)]; [[UIAccelerometer sharedAccelerometer] setDelegate:global_delegate]; } else { [[UIAccelerometer sharedAccelerometer] setDelegate:nil]; } } int _al_iphone_get_num_video_adapters(void) { if (![UIScreen respondsToSelector:NSSelectorFromString(@"screens")]) { return 1; } return [[UIScreen screens] count]; } void _al_iphone_get_screen_size(int adapter, int *w, int *h) { iphone_screen *scr = iphone_get_screen_by_adapter(adapter); UIScreen *screen = scr->screen; if (NULL != screen) { CGRect bounds = [screen bounds]; CGFloat scale = 1.0f; if (adapter == 0 && [screen respondsToSelector:NSSelectorFromString(@"scale")]) { scale = [screen scale]; } *w = (int)(bounds.size.width * scale); *h = (int)(bounds.size.height * scale); } else { ASSERT("You should never see this message, unless Apple changed their policy and allows for removing screens from iDevices." && false); } } int _al_iphone_get_orientation(ALLEGRO_DISPLAY *display) { if (display) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *options = &display->extra_settings; int supported = options->settings[ALLEGRO_SUPPORTED_ORIENTATIONS]; if (supported != ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES) { iphone_screen *scr = iphone_get_screen(display); UIInterfaceOrientation o = scr->vc.interfaceOrientation; UIDeviceOrientation od = (int)o; /* They are compatible. */ return iphone_orientation_to_allegro(od); } } UIDevice* device = [UIDevice currentDevice]; if (NULL != device) return iphone_orientation_to_allegro([device orientation]); else return ALLEGRO_DISPLAY_ORIENTATION_UNKNOWN; } @implementation allegroAppDelegate + (void)run:(int)argc:(char **)argv { UIApplicationMain(argc, argv, nil, @"allegroAppDelegate"); } - (void)orientation_change:(NSNotification *)notification { (void)notification; int orientation = _al_iphone_get_orientation(NULL); if (main_display == NULL) return; iphone_send_orientation_event(main_display, orientation); } - (void)applicationDidFinishLaunching:(UIApplication *)application { ALLEGRO_INFO("App launched.\n"); global_delegate = self; app = application; iphone_create_screens(); // Register for device orientation notifications // Note: The notifications won't be generated unless they are enabled, which // we do elsewhere. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientation_change:) name:UIDeviceOrientationDidChangeNotification object:nil]; // Register for screen connect/disconnect notifications [self setupScreenConnectionNotificationHandlers]; _al_iphone_run_user_main(); } /* This may never get called on iOS 4 */ - (void)applicationWillTerminate:(UIApplication *)application { (void)application; ALLEGRO_EVENT event; ALLEGRO_DISPLAY *d = main_display; ALLEGRO_SYSTEM_IPHONE *iphone = (void *)al_get_system_driver(); iphone->wants_shutdown = true; ALLEGRO_INFO("Terminating.\n"); [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; _al_event_source_lock(&d->es); if (_al_event_source_needs_to_generate_event(&d->es)) { event.display.type = ALLEGRO_EVENT_DISPLAY_CLOSE; event.display.timestamp = al_get_time(); _al_event_source_emit_event(&d->es, &event); } _al_event_source_unlock(&d->es); /* When this method returns, the application terminates - so lets wait a bit * so the user app can shutdown properly, e.g. to save state as is usually * required by iphone apps. */ _al_iphone_await_termination(); } - (void)applicationWillResignActive:(UIApplication *)application { ALLEGRO_DISPLAY *d = main_display; ALLEGRO_EVENT event; (void)application; ALLEGRO_INFO("Application becoming inactive.\n"); _al_event_source_lock(&d->es); if (_al_event_source_needs_to_generate_event(&d->es)) { event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_OUT; event.display.timestamp = al_current_time(); _al_event_source_emit_event(&d->es, &event); } _al_event_source_unlock(&d->es); } - (void)applicationDidBecomeActive:(UIApplication *)application { ALLEGRO_DISPLAY *d = main_display; ALLEGRO_EVENT event; (void)application; ALLEGRO_INFO("Application becoming active.\n"); if (!d) return; _al_event_source_lock(&d->es); if (_al_event_source_needs_to_generate_event(&d->es)) { event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_IN; event.display.timestamp = al_current_time(); _al_event_source_emit_event(&d->es, &event); } _al_event_source_unlock(&d->es); } - (void)applicationDidEnterBackground:(UIApplication *)application { ALLEGRO_DISPLAY *d = main_display; ALLEGRO_EVENT event; (void)application; ALLEGRO_INFO("Application entering background.\n"); waiting_for_program_halt = true; _al_event_source_lock(&d->es); if (_al_event_source_needs_to_generate_event(&d->es)) { event.display.type = ALLEGRO_EVENT_DISPLAY_HALT_DRAWING; event.display.timestamp = al_current_time(); _al_event_source_emit_event(&d->es, &event); } _al_event_source_unlock(&d->es); while (waiting_for_program_halt) { // do nothing, this should be quick al_rest(0.001); } } - (void)applicationWillEnterForeground:(UIApplication *)application { ALLEGRO_DISPLAY *d = main_display; ALLEGRO_EVENT event; (void)application; ALLEGRO_INFO("Application coming back to foreground.\n"); _al_event_source_lock(&d->es); if (_al_event_source_needs_to_generate_event(&d->es)) { event.display.type = ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING; event.display.timestamp = al_current_time(); _al_event_source_emit_event(&d->es, &event); } _al_event_source_unlock(&d->es); } /* Note: This must be called from the main thread. Ask Apple why - but I tried * it and otherwise things simply don't work (the screen just stays black). */ - (void)add_view:(NSValue *)value { ALLEGRO_DISPLAY *d = [value pointerValue]; ALLEGRO_DISPLAY_IPHONE *disp = (ALLEGRO_DISPLAY_IPHONE *)d; int adapter = iphone_get_adapter(d); if (adapter == 0) { main_display = d; } iphone_screen *scr = iphone_get_screen_by_adapter(adapter); scr->display = d; ViewController *vc = scr->vc; vc->display = d; EAGLView *view = (EAGLView *)vc.view; [view set_allegro_display:d]; [scr->window addSubview:view]; if (adapter == 0) { [view becomeFirstResponder]; [scr->window makeKeyAndVisible]; } else { scr->window.hidden = NO; } disp->extra->failed = false; disp->extra->vc = vc; disp->extra->window = scr->window; } - (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration { (void)accelerometer; _al_iphone_generate_joystick_event(acceleration.x, acceleration.y, acceleration.z); } - (void)setupScreenConnectionNotificationHandlers { /* Screen connect/disconnect notifications were added in iOS 3.2 */ NSString *reqSysVer = @"3.2"; NSString *currSysVer = [[UIDevice currentDevice] systemVersion]; BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending); if (osVersionSupported) { NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(handleScreenConnectNotification:) name:UIScreenDidConnectNotification object:nil]; [center addObserver:self selector:@selector(handleScreenDisconnectNotification:) name:UIScreenDidDisconnectNotification object:nil]; } } - (void)handleScreenConnectNotification:(NSNotification*)aNotification { airplay_screen = [aNotification object]; ALLEGRO_DISPLAY *display = main_display; if (!display) return; _al_event_source_lock(&display->es); if (_al_event_source_needs_to_generate_event(&display->es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_CONNECTED; event.display.timestamp = al_get_time(); event.display.source = display; _al_event_source_emit_event(&display->es, &event); } _al_event_source_unlock(&display->es); } - (void)handleScreenDisconnectNotification:(NSNotification*)aNotification { ALLEGRO_DISPLAY *display = main_display; ALLEGRO_DISPLAY_IPHONE *idisplay = (ALLEGRO_DISPLAY_IPHONE *)display; ALLEGRO_DISPLAY_IPHONE_EXTRA *extra; if (!display) return; extra = idisplay->extra; extra->disconnected = true; disconnect_wait = true; _al_event_source_lock(&display->es); if (_al_event_source_needs_to_generate_event(&display->es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_DISCONNECTED; event.display.timestamp = al_get_time(); event.display.source = display; _al_event_source_emit_event(&display->es, &event); } _al_event_source_unlock(&display->es); if (airplay_connected) { // wait for user to destroy display while (disconnect_wait) al_rest(0.001); iphone_remove_screen([aNotification object]); airplay_connected = false; } } - (void)dealloc { [super dealloc]; } - (void)add_screen:(UIScreen *)screen { int i; if (screen == [UIScreen mainScreen]) { i = 0; } else { for (i = 0; i < (int)[[UIScreen screens] count]; i++) { if ([[UIScreen screens] objectAtIndex:i] == screen) break; } } if (i != 0) { if ([screen respondsToSelector:NSSelectorFromString(@"availableModes")]) { NSArray *a = [screen availableModes]; int j; UIScreenMode *largest = NULL; for (j = 0; j < (int)[a count]; j++) { UIScreenMode *m = [a objectAtIndex:j]; float w = m.size.width; float h = m.size.height; if ((largest == NULL) || (w+h > largest.size.width+largest.size.height)) { largest = m; } } if (largest) { screen.currentMode = largest; } } } iphone_screen *scr = iphone_get_screen_by_adapter(i); bool add = scr == NULL; UIWindow *window = [[UIWindow alloc] initWithFrame:[screen bounds]]; if ([window respondsToSelector:NSSelectorFromString(@"screen")]) { window.screen = screen; } ViewController *vc = [[ViewController alloc] init]; vc->adapter = i; [vc create_view]; // Doesn't work on iOS < 4. NSString *reqSysVer = @"4.0"; NSString *currSysVer = [[UIDevice currentDevice] systemVersion]; BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending); if (osVersionSupported) { window.rootViewController = vc; } if (add) scr = [[iphone_screen alloc] init]; scr->adapter = i; scr->screen = screen; scr->window = window; scr->vc = vc; scr->view = (EAGLView *)vc.view; scr->display = NULL; if (add) { al_lock_mutex(_al_iphone_display_hotplug_mutex); [iphone_screens addObject:scr]; al_unlock_mutex(_al_iphone_display_hotplug_mutex); } } @end void _al_iphone_connect_airplay(void) { [global_delegate performSelectorOnMainThread: @selector(add_screen:) withObject:airplay_screen waitUntilDone:TRUE]; airplay_connected = true; } allegro5-5.2.10.1/src/iphone/iphone.h000066400000000000000000000002131473414355200171600ustar00rootroot00000000000000#ifndef __al_included_iphone_h #define __al_included_iphone_h void _al_iphone_acknowledge_drawing_halt(ALLEGRO_DISPLAY *display); #endif allegro5-5.2.10.1/src/iphone/iphone_clipboard.m000066400000000000000000000044321473414355200212130ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * MacOS X clipboard handling. * * By Beoran. * * See readme.txt for copyright information. */ #include #include #include #include #include #include #include #include "iphone.h" #include "allegroAppDelegate.h" #include ALLEGRO_DEBUG_CHANNEL("iphone") #ifndef ALLEGRO_IPHONE #error Something is wrong with the makefile #endif /* Ensure that we have the right version number available. */ #ifndef NSAppKitVersionNumber10_6 #define NSAppKitVersionNumber10_6 1038 #endif static char *iphone_get_clipboard_text(ALLEGRO_DISPLAY *display) { const char *utf8; NSString *pbtext; size_t size; char *text; pbtext = [[UIPasteboard generalPasteboard] string]; if (pbtext == nil) return NULL; utf8 = [pbtext UTF8String]; size = strlen(utf8); text = al_malloc(size+1); text = _al_sane_strncpy(text, utf8, size+1); return text; } static bool iphone_set_clipboard_text(ALLEGRO_DISPLAY *display, const char *text) { NSData *data = [NSData dataWithBytes:text length:strlen(text)]; [[UIPasteboard generalPasteboard] setData:data forPasteboardType:(NSString *)kUTTypeUTF8PlainText]; return true; } static bool iphone_has_clipboard_text(ALLEGRO_DISPLAY *display) { NSString *pbtext; pbtext = [[UIPasteboard generalPasteboard] string]; return (pbtext != nil); } void _al_iphone_add_clipboard_functions(ALLEGRO_DISPLAY_INTERFACE *vt) { vt->set_clipboard_text = iphone_set_clipboard_text; vt->get_clipboard_text = iphone_get_clipboard_text; vt->has_clipboard_text = iphone_has_clipboard_text; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/iphone/iphone_display.m000066400000000000000000000303551473414355200207240ustar00rootroot00000000000000#include #include #include #include #include #include #include "iphone.h" #include "allegroAppDelegate.h" ALLEGRO_DEBUG_CHANNEL("iphone") static ALLEGRO_DISPLAY_INTERFACE *vt; static float _screen_iscale = 1.0; static float _screen_x, _screen_y; static float _screen_w, _screen_h; static bool _screen_hack; bool _al_iphone_is_display_connected(ALLEGRO_DISPLAY *display); void _al_iphone_connect_airplay(void); extern ALLEGRO_MUTEX *_al_iphone_display_hotplug_mutex; void _al_iphone_setup_opengl_view(ALLEGRO_DISPLAY *d, bool manage_backbuffer) { int w, h; w = d->w; h = d->h; _al_iphone_reset_framebuffer(d); _screen_w = w; _screen_h = h; if (manage_backbuffer) { _al_ogl_setup_gl(d); } } void _al_iphone_translate_from_screen(ALLEGRO_DISPLAY *d, int *x, int *y) { if (!_screen_hack) return; // See _al_iphone_setup_opengl_view float ox = *x, oy = *y; if (d->w >= d->h) { *x = _screen_x + oy * _screen_iscale; *y = _screen_y + (_screen_w - ox) * _screen_iscale; } else { // TODO } } void _al_iphone_clip(ALLEGRO_BITMAP const *bitmap, int x_1, int y_1, int x_2, int y_2) { ALLEGRO_BITMAP *oglb = (void *)(bitmap->parent ? bitmap->parent : bitmap); int h = oglb->h; glScissor(x_1, h - y_2, x_2 - x_1, y_2 - y_1); } static void set_rgba8888(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds) { eds->settings[ALLEGRO_RED_SIZE] = 8; eds->settings[ALLEGRO_GREEN_SIZE] = 8; eds->settings[ALLEGRO_BLUE_SIZE] = 8; eds->settings[ALLEGRO_ALPHA_SIZE] = 8; eds->settings[ALLEGRO_RED_SHIFT] = 0; eds->settings[ALLEGRO_GREEN_SHIFT] = 8; eds->settings[ALLEGRO_BLUE_SHIFT] = 16; eds->settings[ALLEGRO_ALPHA_SHIFT] = 24; eds->settings[ALLEGRO_COLOR_SIZE] = 32; } static void set_rgb565(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds) { eds->settings[ALLEGRO_RED_SIZE] = 5; eds->settings[ALLEGRO_GREEN_SIZE] = 6; eds->settings[ALLEGRO_BLUE_SIZE] = 5; eds->settings[ALLEGRO_ALPHA_SIZE] = 0; eds->settings[ALLEGRO_RED_SHIFT] = 0; eds->settings[ALLEGRO_GREEN_SHIFT] = 5; eds->settings[ALLEGRO_BLUE_SHIFT] = 11; eds->settings[ALLEGRO_ALPHA_SHIFT] = 0; eds->settings[ALLEGRO_COLOR_SIZE] = 16; } #define VISUALS_COUNT 6 void _al_iphone_update_visuals(void) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref; ALLEGRO_SYSTEM_IPHONE *system = (void *)al_get_system_driver(); ref = _al_get_new_display_settings(); /* If we aren't called the first time, only updated scores. */ if (system->visuals) { for (int i = 0; i < system->visuals_count; i++) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = system->visuals[i]; eds->score = _al_score_display_settings(eds, ref); } return; } system->visuals = al_calloc(1, VISUALS_COUNT * sizeof(*system->visuals)); system->visuals_count = VISUALS_COUNT; for (int i = 0; i < VISUALS_COUNT; i++) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = al_calloc(1, sizeof *eds); eds->settings[ALLEGRO_RENDER_METHOD] = 1; eds->settings[ALLEGRO_COMPATIBLE_DISPLAY] = 1; eds->settings[ALLEGRO_SWAP_METHOD] = 2; eds->settings[ALLEGRO_VSYNC] = 1; eds->settings[ALLEGRO_SUPPORTED_ORIENTATIONS] = ref->settings[ALLEGRO_SUPPORTED_ORIENTATIONS]; switch (i) { case 0: set_rgba8888(eds); break; case 1: set_rgb565(eds); break; case 2: set_rgba8888(eds); eds->settings[ALLEGRO_DEPTH_SIZE] = 16; break; case 3: set_rgb565(eds); eds->settings[ALLEGRO_DEPTH_SIZE] = 16; break; case 4: set_rgba8888(eds); eds->settings[ALLEGRO_DEPTH_SIZE] = 24; eds->settings[ALLEGRO_STENCIL_SIZE] = 8; break; case 5: set_rgb565(eds); eds->settings[ALLEGRO_DEPTH_SIZE] = 24; eds->settings[ALLEGRO_STENCIL_SIZE] = 8; break; } eds->score = _al_score_display_settings(eds, ref); eds->index = i; system->visuals[i] = eds; } } static ALLEGRO_DISPLAY *iphone_create_display(int w, int h) { ALLEGRO_DISPLAY_IPHONE *d = al_calloc(1, sizeof *d); ALLEGRO_DISPLAY *display = (void*)d; ALLEGRO_OGL_EXTRAS *ogl = al_calloc(1, sizeof *ogl); display->ogl_extras = ogl; display->vt = _al_get_iphone_display_interface(); display->flags = al_get_new_display_flags(); int adapter; adapter = al_get_new_display_adapter(); if (adapter < 0) adapter = 0; if (adapter == 1) { _al_iphone_connect_airplay(); } if (display->flags & ALLEGRO_FULLSCREEN_WINDOW) { _al_iphone_get_screen_size(adapter, &w, &h); } display->w = w; display->h = h; ALLEGRO_SYSTEM_IPHONE *system = (void *)al_get_system_driver(); /* Add ourself to the list of displays. */ ALLEGRO_DISPLAY_IPHONE **add; add = _al_vector_alloc_back(&system->system.displays); *add = d; /* Each display is an event source. */ _al_event_source_init(&display->es); _al_iphone_update_visuals(); ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds[system->visuals_count]; memcpy(eds, system->visuals, sizeof(*eds) * system->visuals_count); qsort(eds, system->visuals_count, sizeof(*eds), _al_display_settings_sorter); ALLEGRO_INFO("Chose visual no. %i\n", eds[0]->index); memcpy(&display->extra_settings, eds[0], sizeof(ALLEGRO_EXTRA_DISPLAY_SETTINGS)); display->flags |= ALLEGRO_OPENGL; #ifdef ALLEGRO_CFG_OPENGLES2 display->flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; #endif #ifdef ALLEGRO_CFG_OPENGLES display->flags |= ALLEGRO_OPENGL_ES_PROFILE; #endif /* This will add an OpenGL view with an OpenGL context, then return. */ if (!_al_iphone_add_view(display)) { /* FIXME: cleanup */ return NULL; } _al_iphone_make_view_current(display); /* FIXME: there is some sort of race condition somewhere. */ al_rest(1.0); _al_ogl_manage_extensions(display); _al_ogl_set_extensions(ogl->extension_api); _al_iphone_setup_opengl_view(display, true); int ndisplays = system->system.displays._size; [[UIApplication sharedApplication] setIdleTimerDisabled:(ndisplays > 1)]; /* Fill in opengl version */ const int v = display->ogl_extras->ogl_info.version; display->extra_settings.settings[ALLEGRO_OPENGL_MAJOR_VERSION] = (v >> 24) & 0xFF; display->extra_settings.settings[ALLEGRO_OPENGL_MINOR_VERSION] = (v >> 16) & 0xFF; return display; } static void iphone_destroy_display(ALLEGRO_DISPLAY *d) { ALLEGRO_DISPLAY_IPHONE *idisplay = (ALLEGRO_DISPLAY_IPHONE *)d; ALLEGRO_DISPLAY_IPHONE_EXTRA *extra = idisplay->extra; bool disconnected = extra->disconnected; _al_set_current_display_only(d); while (d->bitmaps._size > 0) { ALLEGRO_BITMAP **bptr = (ALLEGRO_BITMAP **)_al_vector_ref_back(&d->bitmaps); ALLEGRO_BITMAP *b = *bptr; _al_convert_to_memory_bitmap(b); } _al_event_source_free(&d->es); _al_iphone_destroy_screen(d); if (disconnected) { _al_iphone_disconnect(d); } ALLEGRO_SYSTEM_IPHONE *system = (void *)al_get_system_driver(); _al_vector_find_and_delete(&system->system.displays, &d); [[UIApplication sharedApplication] setIdleTimerDisabled:FALSE]; } static bool iphone_set_current_display(ALLEGRO_DISPLAY *d) { (void)d; _al_iphone_make_view_current(d); _al_ogl_update_render_state(d); return true; } static int iphone_get_orientation(ALLEGRO_DISPLAY *d) { return _al_iphone_get_orientation(d); } /* There can be only one window and only one OpenGL context, so all bitmaps * are compatible. */ static bool iphone_is_compatible_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { (void)display; (void)bitmap; return true; } /* Resizing is not possible. */ static bool iphone_resize_display(ALLEGRO_DISPLAY *d, int w, int h) { (void)d; (void)w; (void)h; return false; } /* The icon must be provided in the Info.plist file, it cannot be changed * at runtime. */ static void iphone_set_icons(ALLEGRO_DISPLAY *d, int num_icons, ALLEGRO_BITMAP *bitmaps[]) { (void)d; (void)num_icons; (void)bitmaps; } /* There is no way to leave fullscreen so no window title is visible. */ static void iphone_set_window_title(ALLEGRO_DISPLAY *display, char const *title) { (void)display; (void)title; } /* The window always spans the entire screen right now. */ static void iphone_set_window_position(ALLEGRO_DISPLAY *display, int x, int y) { (void)display; (void)x; (void)y; } /* The window cannot be constrained. */ static bool iphone_set_window_constraints(ALLEGRO_DISPLAY *display, int min_w, int min_h, int max_w, int max_h) { (void)display; (void)min_w; (void)min_h; (void)max_w; (void)max_h; return false; } /* Always fullscreen. */ static bool iphone_set_display_flag(ALLEGRO_DISPLAY *display, int flag, bool onoff) { (void)display; (void)flag; (void)onoff; return false; } static void iphone_get_window_position(ALLEGRO_DISPLAY *display, int *x, int *y) { (void)display; *x = 0; *y = 0; } /* The window cannot be constrained. */ static bool iphone_get_window_constraints(ALLEGRO_DISPLAY *display, int *min_w, int *min_h, int *max_w, int *max_h) { (void)display; (void)min_w; (void)min_h; (void)max_w; (void)max_h; return false; } static bool iphone_wait_for_vsync(ALLEGRO_DISPLAY *display) { (void)display; return false; } static void iphone_flip_display(ALLEGRO_DISPLAY *d) { _al_iphone_flip_view(d); } static void iphone_update_display_region(ALLEGRO_DISPLAY *d, int x, int y, int w, int h) { (void)x; (void)y; (void)w; (void)h; iphone_flip_display(d); } static bool iphone_acknowledge_resize(ALLEGRO_DISPLAY *d) { _al_iphone_recreate_framebuffer(d); _al_iphone_setup_opengl_view(d, true); return true; } static bool iphone_set_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_MOUSE_CURSOR *cursor) { (void)display; (void)cursor; return false; } static bool iphone_set_system_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id) { (void)display; (void)cursor_id; return false; } static bool iphone_show_mouse_cursor(ALLEGRO_DISPLAY *display) { (void)display; return false; } static bool iphone_hide_mouse_cursor(ALLEGRO_DISPLAY *display) { (void)display; return false; } /* Obtain a reference to this driver. */ ALLEGRO_DISPLAY_INTERFACE *_al_get_iphone_display_interface(void) { if (vt) return vt; vt = al_calloc(1, sizeof *vt); vt->create_display = iphone_create_display; vt->destroy_display = iphone_destroy_display; vt->set_current_display = iphone_set_current_display; vt->flip_display = iphone_flip_display; vt->update_display_region = iphone_update_display_region; vt->acknowledge_resize = iphone_acknowledge_resize; vt->create_bitmap = _al_ogl_create_bitmap; vt->get_backbuffer = _al_ogl_get_backbuffer; vt->set_target_bitmap = _al_ogl_set_target_bitmap; vt->get_orientation = iphone_get_orientation; vt->is_compatible_bitmap = iphone_is_compatible_bitmap; vt->resize_display = iphone_resize_display; vt->set_icons = iphone_set_icons; vt->set_window_title = iphone_set_window_title; vt->set_window_position = iphone_set_window_position; vt->get_window_position = iphone_get_window_position; vt->set_window_constraints = iphone_set_window_constraints; vt->get_window_constraints = iphone_get_window_constraints; vt->set_display_flag = iphone_set_display_flag; vt->wait_for_vsync = iphone_wait_for_vsync; vt->set_mouse_cursor = iphone_set_mouse_cursor; vt->set_system_mouse_cursor = iphone_set_system_mouse_cursor; vt->show_mouse_cursor = iphone_show_mouse_cursor; vt->hide_mouse_cursor = iphone_hide_mouse_cursor; vt->acknowledge_drawing_halt = _al_iphone_acknowledge_drawing_halt; vt->update_render_state = _al_ogl_update_render_state; _al_ogl_add_drawing_functions(vt); _al_iphone_add_clipboard_functions(vt); return vt; } allegro5-5.2.10.1/src/iphone/iphone_joystick.m000066400000000000000000000065361473414355200211220ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_iphone.h" ALLEGRO_DEBUG_CHANNEL("iphone") typedef struct ALLEGRO_JOYSTICK_IPHONE { ALLEGRO_JOYSTICK parent; ALLEGRO_JOYSTICK_STATE joystate; } ALLEGRO_JOYSTICK_IPHONE; static ALLEGRO_JOYSTICK_IPHONE the_joystick; static bool initialized; static bool ijoy_init_joystick(void) { ALLEGRO_JOYSTICK_IPHONE *ijoy; ALLEGRO_JOYSTICK *joy; ijoy = &the_joystick; memset(ijoy, 0, sizeof *ijoy); joy = (void *)ijoy; /* Fill in the joystick information fields. */ joy->info.num_sticks = 1; joy->info.num_buttons = 0; joy->info.stick[0].name = "Accelerometer"; joy->info.stick[0].num_axes = 3; joy->info.stick[0].axis[0].name = "X"; joy->info.stick[0].axis[1].name = "Y"; joy->info.stick[0].axis[2].name = "Z"; joy->info.stick[0].flags = ALLEGRO_JOYFLAG_ANALOGUE; // TODO: What's a good frequency to use here? _al_iphone_accelerometer_control(60); initialized = true; return true; } static void ijoy_exit_joystick(void) { _al_iphone_accelerometer_control(0); initialized = false; } static bool ijoy_reconfigure_joysticks(void) { return false; } static int ijoy_num_joysticks(void) { return 1; } static ALLEGRO_JOYSTICK *ijoy_get_joystick(int num) { if (num != 0) return NULL; ALLEGRO_DEBUG("Joystick %d acquired.\n", num); return &the_joystick.parent; } static void ijoy_release_joystick(ALLEGRO_JOYSTICK *joy) { (void)joy; ALLEGRO_DEBUG("Joystick released.\n"); initialized = false; } static void ijoy_get_joystick_state(ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state) { ALLEGRO_JOYSTICK_IPHONE *ijoy = (void *)joy; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); _al_event_source_lock(es); *ret_state = ijoy->joystate; _al_event_source_unlock(es); } void _al_iphone_generate_joystick_event(float x, float y, float z) { if (!initialized) return; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); ALLEGRO_EVENT event; _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { float pos[] = {x, y, z}; for (int i = 0; i < 3; i++) { event.joystick.type = ALLEGRO_EVENT_JOYSTICK_AXIS; event.joystick.timestamp = al_get_time(); event.joystick.stick = 0; event.joystick.axis = i; event.joystick.pos = pos[i]; event.joystick.button = 0; _al_event_source_emit_event(es, &event); } } _al_event_source_unlock(es); } static char const *ijoy_get_name(ALLEGRO_JOYSTICK *joy) { (void)joy; return "Accelerometer"; } static bool ijoy_get_active(ALLEGRO_JOYSTICK *joy) { (void)joy; return true; } static ALLEGRO_JOYSTICK_DRIVER iphone_joystick_driver = { AL_ID('I', 'P', 'H', 'O'), "", "", "iphone joystick", ijoy_init_joystick, ijoy_exit_joystick, ijoy_reconfigure_joysticks, ijoy_num_joysticks, ijoy_get_joystick, ijoy_release_joystick, ijoy_get_joystick_state, ijoy_get_name, ijoy_get_active }; ALLEGRO_JOYSTICK_DRIVER *_al_get_iphone_joystick_driver(void) { return &iphone_joystick_driver; } allegro5-5.2.10.1/src/iphone/iphone_keyboard.c000066400000000000000000000024141473414355200210400ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/internal/aintern_events.h" static ALLEGRO_KEYBOARD the_keyboard; static bool iphone_init_keyboard(void) { memset(&the_keyboard, 0, sizeof the_keyboard); _al_event_source_init(&the_keyboard.es); return true; } static void iphone_exit_keyboard(void) { _al_event_source_free(&the_keyboard.es); } static ALLEGRO_KEYBOARD *iphone_get_keyboard(void) { return &the_keyboard; } static bool iphone_set_keyboard_leds(int leds) { (void)leds; return false; } static char const *iphone_keycode_to_name(int keycode) { (void)keycode; return "none"; } static void iphone_get_keyboard_state(ALLEGRO_KEYBOARD_STATE *ret_state) { memset(ret_state, 0, sizeof *ret_state); } static void iphone_clear_keyboard_state(void) { return; } static ALLEGRO_KEYBOARD_DRIVER iphone_keyboard_driver = { AL_ID('I','P','H','O'), "", "", "iphone keyboard", iphone_init_keyboard, iphone_exit_keyboard, iphone_get_keyboard, iphone_set_keyboard_leds, iphone_keycode_to_name, iphone_get_keyboard_state, iphone_clear_keyboard_state }; ALLEGRO_KEYBOARD_DRIVER *_al_get_iphone_keyboard_driver(void) { return &iphone_keyboard_driver; } allegro5-5.2.10.1/src/iphone/iphone_main.m000066400000000000000000000042051473414355200201760ustar00rootroot00000000000000#import #import "allegroAppDelegate.h" #include #include #include ALLEGRO_DEBUG_CHANNEL("iphone") /* Not that there could ever be any arguments on iphone... */ static int global_argc; static char **global_argv; extern int _al_mangled_main(int, char **); /* We run the user's "main" in its own thread. */ static void *user_main(ALLEGRO_THREAD *thread, void *arg) { (void)thread; ALLEGRO_INFO("Starting user main.\n"); _al_mangled_main(global_argc, global_argv); ALLEGRO_INFO("User main has returned.\n"); ALLEGRO_SYSTEM_IPHONE *iphone = (void *)al_get_system_driver(); al_lock_mutex(iphone->mutex); iphone->has_shutdown = true; al_signal_cond(iphone->cond); al_unlock_mutex(iphone->mutex); /* Apple does not allow iphone applications to shutdown and provides * no API for it: * http://developer.apple.com/iphone/library/qa/qa2008/qa1561.html * * Therefore we only call exit here if the user actually returned from * there main - in that case crashing the app is better then freezing it. */ if (!iphone->wants_shutdown) exit(0); /* "crash grazefully" */ return arg; } /* There really is no point running the user main before the application * has finished launching, so this function is called back when we receive * the applicationDidFinishLaunching message. */ void _al_iphone_run_user_main(void) { ALLEGRO_THREAD *thread = al_create_thread(user_main, NULL); al_start_thread(thread); } void _al_iphone_init_path(void) { /* On iphone, data always can only be in the resource bundle. So we set * the initial path to that. As each app is sandboxed, there is not much * else to access anyway. */ NSFileManager *fm = [NSFileManager defaultManager]; NSBundle *mainBundle = [NSBundle mainBundle]; NSString *string = [mainBundle resourcePath]; [fm changeCurrentDirectoryPath:string]; } int main(int argc, char **argv) { global_argc = argc; global_argv = argv; [allegroAppDelegate run:argc:argv]; ASSERT(false); /* can never reach */ return 0; } allegro5-5.2.10.1/src/iphone/iphone_mouse.m000066400000000000000000000064331473414355200204070ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/internal/aintern_mouse.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_iphone.h" typedef struct ALLEGRO_MOUSE_IPHONE { ALLEGRO_MOUSE parent; ALLEGRO_MOUSE_STATE state; } ALLEGRO_MOUSE_IPHONE; static ALLEGRO_MOUSE_IPHONE the_mouse; static bool imouse_installed; /* * Helper to generate a mouse event. */ void _al_iphone_generate_mouse_event(unsigned int type, int x, int y, unsigned int button, ALLEGRO_DISPLAY *d) { ALLEGRO_EVENT event; _al_event_source_lock(&the_mouse.parent.es); _al_iphone_translate_from_screen(d, &x, &y); the_mouse.state.x = x; the_mouse.state.y = y; if (type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { the_mouse.state.buttons |= (1 << button); } else if (type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { the_mouse.state.buttons &= ~(1 << button); } the_mouse.state.pressure = the_mouse.state.buttons ? 1.0 : 0.0; // TODO if (_al_event_source_needs_to_generate_event(&the_mouse.parent.es)) { event.mouse.type = type; event.mouse.timestamp = al_get_time(); event.mouse.display = d; event.mouse.x = x; event.mouse.y = y; event.mouse.z = 0; event.mouse.w = 0; event.mouse.dx = 0; // TODO event.mouse.dy = 0; // TODO event.mouse.dz = 0; // TODO event.mouse.dw = 0; // TODO event.mouse.button = button; event.mouse.pressure = the_mouse.state.pressure; _al_event_source_emit_event(&the_mouse.parent.es, &event); } _al_event_source_unlock(&the_mouse.parent.es); } static void imouse_exit(void); static bool imouse_init(void) { if (imouse_installed) imouse_exit(); memset(&the_mouse, 0, sizeof the_mouse); _al_event_source_init(&the_mouse.parent.es); imouse_installed = true; return true; } static void imouse_exit(void) { if (!imouse_installed) return; imouse_installed = false; _al_event_source_free(&the_mouse.parent.es); } static ALLEGRO_MOUSE *imouse_get_mouse(void) { ASSERT(imouse_installed); return (ALLEGRO_MOUSE *)&the_mouse; } /* We report multi-touch as different buttons. */ static unsigned int imouse_get_mouse_num_buttons(void) { return 5; } static unsigned int imouse_get_mouse_num_axes(void) { return 2; } /* Hard to accomplish on a touch screen. */ static bool imouse_set_mouse_xy(ALLEGRO_DISPLAY *display, int x, int y) { (void)display; (void)x; (void)y; return false; } static bool imouse_set_mouse_axis(int which, int z) { (void)which; (void)z; return false; } /* static void imouse_get_state(ALLEGRO_MOUSE_STATE *ret_state) { ASSERT(imouse_installed); _al_event_source_lock(&the_mouse.parent.es); { *ret_state = the_mouse.state; } _al_event_source_unlock(&the_mouse.parent.es); } */ void imouse_get_state(ALLEGRO_MOUSE_STATE *ret_state); static ALLEGRO_MOUSE_DRIVER iphone_mouse_driver = { AL_ID('I', 'P', 'H', 'O'), "", "", "iphone mouse", imouse_init, imouse_exit, imouse_get_mouse, imouse_get_mouse_num_buttons, imouse_get_mouse_num_axes, imouse_set_mouse_xy, imouse_set_mouse_axis, imouse_get_state }; ALLEGRO_MOUSE_DRIVER *_al_get_iphone_mouse_driver(void) { return &iphone_mouse_driver; } allegro5-5.2.10.1/src/iphone/iphone_path.m000066400000000000000000000031171473414355200202070ustar00rootroot00000000000000#import #include #include ALLEGRO_PATH *_al_iphone_get_path(int id) { char str[PATH_MAX]; NSString *string; NSArray *array; NSBundle *mainBundle; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; switch (id) { case ALLEGRO_USER_HOME_PATH: string = NSHomeDirectory(); break; case ALLEGRO_TEMP_PATH: string = NSTemporaryDirectory(); break; case ALLEGRO_RESOURCES_PATH: mainBundle = [NSBundle mainBundle]; string = [mainBundle resourcePath]; break; case ALLEGRO_USER_SETTINGS_PATH: case ALLEGRO_USER_DATA_PATH: array = NSSearchPathForDirectoriesInDomains( NSApplicationSupportDirectory, NSUserDomainMask, TRUE); string = (NSString *)[array objectAtIndex:0]; break; case ALLEGRO_USER_DOCUMENTS_PATH: array = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, TRUE); string = (NSString *)[array objectAtIndex:0]; break; case ALLEGRO_EXENAME_PATH: { uint32_t size = sizeof(str); if (_NSGetExecutablePath(str, &size) != 0) { [pool drain]; return NULL; } [pool drain]; return al_create_path(str); } default: [pool drain]; return NULL; } sprintf(str, "%s", [string UTF8String]); [pool drain]; return al_create_path_for_directory(str); } allegro5-5.2.10.1/src/iphone/iphone_system.c000066400000000000000000000061561473414355200205730ustar00rootroot00000000000000#include #include #include ALLEGRO_DEBUG_CHANNEL("iphone") ALLEGRO_SYSTEM_IPHONE *iphone; static ALLEGRO_SYSTEM_INTERFACE *vt; extern ALLEGRO_MUTEX *_al_iphone_display_hotplug_mutex; /* al_init will call this. */ ALLEGRO_SYSTEM *iphone_initialize(int flags) { (void)flags; iphone = al_calloc(1, sizeof *iphone); ALLEGRO_SYSTEM *sys = &iphone->system; iphone->mutex = al_create_mutex(); iphone->cond = al_create_cond(); sys->vt = _al_get_iphone_system_interface(); _al_vector_init(&sys->displays, sizeof (ALLEGRO_DISPLAY_IPHONE *)); _al_unix_init_time(); _al_iphone_init_path(); return sys; } static void iphone_shutdown_system(void) { al_destroy_mutex(_al_iphone_display_hotplug_mutex); } /* This is called from the termination message - it has to return soon as the * user expects the app to close when it is closed. */ void _al_iphone_await_termination(void) { ALLEGRO_INFO("Application awaiting termination.\n"); al_lock_mutex(iphone->mutex); while (!iphone->has_shutdown) { al_wait_cond(iphone->cond, iphone->mutex); } al_unlock_mutex(iphone->mutex); } static ALLEGRO_DISPLAY_INTERFACE *iphone_get_display_driver(void) { return _al_get_iphone_display_interface(); } static int iphone_get_num_video_adapters(void) { return _al_iphone_get_num_video_adapters(); } static bool iphone_get_monitor_info(int adapter, ALLEGRO_MONITOR_INFO *info) { int w, h; _al_iphone_get_screen_size(adapter, &w, &h); info->x1 = 0; info->y1 = 0; info->x2 = w; info->y2 = h; return true; } /* There is no cursor. */ static bool iphone_get_cursor_position(int *ret_x, int *ret_y) { (void)ret_x; (void)ret_y; return false; } ALLEGRO_SYSTEM_INTERFACE *_al_get_iphone_system_interface(void) { if (vt) return vt; vt = al_calloc(1, sizeof *vt); vt->id = ALLEGRO_SYSTEM_ID_IPHONE; vt->initialize = iphone_initialize; vt->get_display_driver = iphone_get_display_driver; vt->get_keyboard_driver = _al_get_iphone_keyboard_driver; vt->get_mouse_driver = _al_get_iphone_mouse_driver; vt->get_touch_input_driver = _al_get_iphone_touch_input_driver; vt->get_joystick_driver = _al_get_iphone_joystick_driver; //xglx_vt->get_num_display_modes = _al_xglx_get_num_display_modes; //xglx_vt->get_display_mode = _al_xglx_get_display_mode; //xglx_vt->shutdown_system = xglx_shutdown_system; vt->shutdown_system = iphone_shutdown_system; vt->get_num_video_adapters = iphone_get_num_video_adapters; vt->get_monitor_info = iphone_get_monitor_info; vt->get_cursor_position = iphone_get_cursor_position; vt->get_path = _al_iphone_get_path; //xglx_vt->inhibit_screensaver = xglx_inhibit_screensaver; return vt; } /* This is a function each platform must define to register all available * system drivers. */ void _al_register_system_interfaces(void) { ALLEGRO_SYSTEM_INTERFACE **add; add = _al_vector_alloc_back(&_al_system_interfaces); *add = _al_get_iphone_system_interface(); } allegro5-5.2.10.1/src/iphone/iphone_touch_input.m000066400000000000000000000230651473414355200216200ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * iPhone family device touch input driver. * * By Michał Cichoń. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_touch_input.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_iphone.h" static ALLEGRO_TOUCH_INPUT_STATE touch_input_state; static ALLEGRO_MOUSE_STATE mouse_state; static ALLEGRO_TOUCH_INPUT touch_input; static bool installed = false; static void generate_touch_input_event(unsigned int type, double timestamp, int id, float x, float y, float dx, float dy, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_EVENT event; bool want_touch_event = _al_event_source_needs_to_generate_event(&touch_input.es); bool want_mouse_emulation_event; if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_5_0_x) { want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && al_is_mouse_installed(); } else { want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && primary && al_is_mouse_installed(); } if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_NONE) want_mouse_emulation_event = false; else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_INCLUSIVE) want_touch_event = al_is_mouse_installed() ? (want_touch_event && !primary) : want_touch_event; else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_EXCLUSIVE) want_touch_event = al_is_mouse_installed() ? false : want_touch_event; if (!want_touch_event && !want_mouse_emulation_event) return; if (want_touch_event) { event.touch.type = type; event.touch.display = (ALLEGRO_DISPLAY*)disp; event.touch.timestamp = timestamp; event.touch.id = id; event.touch.x = x; event.touch.y = y; event.touch.dx = dx; event.touch.dy = dy; event.touch.primary = primary; _al_event_source_lock(&touch_input.es); _al_event_source_emit_event(&touch_input.es, &event); _al_event_source_unlock(&touch_input.es); } if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_NONE) { _al_event_source_lock(&touch_input.mouse_emulation_es); if (want_mouse_emulation_event) { switch (type) { case ALLEGRO_EVENT_TOUCH_BEGIN: type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN; break; case ALLEGRO_EVENT_TOUCH_CANCEL: case ALLEGRO_EVENT_TOUCH_END: type = ALLEGRO_EVENT_MOUSE_BUTTON_UP; break; case ALLEGRO_EVENT_TOUCH_MOVE: type = ALLEGRO_EVENT_MOUSE_AXES; break; } event.mouse.type = type; event.mouse.timestamp = timestamp; event.mouse.display = (ALLEGRO_DISPLAY*)disp; event.mouse.x = (int)x; event.mouse.y = (int)y; event.mouse.dx = (int)dx; event.mouse.dy = (int)dy; event.mouse.dz = 0; event.mouse.dw = 0; if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) { event.mouse.button = 1; } else { event.mouse.button = id; } event.mouse.pressure = 1.0; if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) { al_set_mouse_xy(event.mouse.display, event.mouse.x, event.mouse.y); } _al_event_source_emit_event(&touch_input.mouse_emulation_es, &event); } mouse_state.x = (int)x; mouse_state.y = (int)y; if (type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) mouse_state.buttons |= id; else if (type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) mouse_state.buttons &= ~id; _al_event_source_unlock(&touch_input.mouse_emulation_es); } } static bool init_touch_input(void) { if (installed) return false; memset(&touch_input_state, 0, sizeof(touch_input_state)); memset(&mouse_state, 0, sizeof(mouse_state)); _al_event_source_init(&touch_input.es); _al_event_source_init(&touch_input.mouse_emulation_es); touch_input.mouse_emulation_mode = ALLEGRO_MOUSE_EMULATION_TRANSPARENT; installed = true; return true; } static void exit_touch_input(void) { if (!installed) return; memset(&touch_input_state, 0, sizeof(touch_input_state)); memset(&mouse_state, 0, sizeof(mouse_state)); _al_event_source_free(&touch_input.es); _al_event_source_free(&touch_input.mouse_emulation_es); installed = false; } static ALLEGRO_TOUCH_INPUT* get_touch_input(void) { return &touch_input; } static void get_touch_input_state(ALLEGRO_TOUCH_INPUT_STATE *ret_state) { _al_event_source_lock(&touch_input.es); *ret_state = touch_input_state; _al_event_source_unlock(&touch_input.es); } static void set_mouse_emulation_mode(int mode) { if (touch_input.mouse_emulation_mode != mode) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) { ALLEGRO_TOUCH_STATE* touch = touch_input_state.touches + i; if (touch->id > 0) { _al_iphone_touch_input_handle_cancel(touch->id, al_get_time(), touch->x, touch->y, touch->primary, touch->display); } } touch_input.mouse_emulation_mode = mode; } } static ALLEGRO_TOUCH_STATE* find_free_touch_state() { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) if (touch_input_state.touches[i].id <= 0) return touch_input_state.touches + i; return NULL; } static ALLEGRO_TOUCH_STATE* find_touch_state_with_id(int id) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) if (touch_input_state.touches[i].id == id) return touch_input_state.touches + i; return NULL; } void _al_iphone_touch_input_handle_begin(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_TOUCH_STATE* state = find_free_touch_state(); (void)primary; if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->id = id; state->x = x; state->y = y; state->dx = 0.0f; state->dy = 0.0f; state->primary = primary; state->display = disp; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_BEGIN, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); } void _al_iphone_touch_input_handle_end(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_TOUCH_STATE* state = find_touch_state_with_id(id); (void)primary; if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_END, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); _al_event_source_lock(&touch_input.es); memset(state, 0, sizeof(ALLEGRO_TOUCH_STATE)); _al_event_source_unlock(&touch_input.es); } void _al_iphone_touch_input_handle_move(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_TOUCH_STATE* state = find_touch_state_with_id(id); (void)primary; if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_MOVE, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); } void _al_iphone_touch_input_handle_cancel(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_TOUCH_STATE* state = find_touch_state_with_id(id); (void)primary; if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_CANCEL, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); _al_event_source_lock(&touch_input.es); memset(state, 0, sizeof(ALLEGRO_TOUCH_STATE)); _al_event_source_unlock(&touch_input.es); } /* the driver vtable */ #define TOUCH_INPUT_IPHONE AL_ID('I','T','I','D') static ALLEGRO_TOUCH_INPUT_DRIVER touch_input_driver = { TOUCH_INPUT_IPHONE, init_touch_input, exit_touch_input, get_touch_input, get_touch_input_state, set_mouse_emulation_mode, NULL }; ALLEGRO_TOUCH_INPUT_DRIVER *_al_get_iphone_touch_input_driver(void) { return &touch_input_driver; } void imouse_get_state(ALLEGRO_MOUSE_STATE *ret_state) { _al_event_source_lock(&touch_input.es); *ret_state = mouse_state; _al_event_source_unlock(&touch_input.es); } allegro5-5.2.10.1/src/joynu.c000066400000000000000000000135621473414355200155660ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * New joystick API. * * By Peter Wang. * * See readme.txt for copyright information. */ /* Title: Joystick routines */ #define ALLEGRO_NO_COMPATIBILITY #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_system.h" /* the active joystick driver */ static ALLEGRO_JOYSTICK_DRIVER *new_joystick_driver = NULL; static ALLEGRO_EVENT_SOURCE es; /* Function: al_install_joystick */ bool al_install_joystick(void) { ALLEGRO_SYSTEM *sysdrv; ALLEGRO_JOYSTICK_DRIVER *joydrv; if (new_joystick_driver) return true; sysdrv = al_get_system_driver(); ASSERT(sysdrv); /* Currently every platform only has at most one joystick driver. */ if (sysdrv->vt->get_joystick_driver) { joydrv = sysdrv->vt->get_joystick_driver(); /* Avoid race condition in case the joystick driver generates an * event right after ->init_joystick. */ _al_event_source_init(&es); if (joydrv && joydrv->init_joystick()) { new_joystick_driver = joydrv; _al_add_exit_func(al_uninstall_joystick, "al_uninstall_joystick"); return true; } _al_event_source_free(&es); } return false; } /* Function: al_uninstall_joystick */ void al_uninstall_joystick(void) { if (new_joystick_driver) { /* perform driver clean up */ new_joystick_driver->exit_joystick(); _al_event_source_free(&es); new_joystick_driver = NULL; } } /* Function: al_is_joystick_installed */ bool al_is_joystick_installed(void) { return (new_joystick_driver) ? true : false; } /* Function: al_reconfigure_joysticks */ bool al_reconfigure_joysticks(void) { if (!new_joystick_driver) return false; /* XXX only until Windows and Mac joystick drivers are updated */ if (!new_joystick_driver->reconfigure_joysticks) { new_joystick_driver->num_joysticks(); return true; } return new_joystick_driver->reconfigure_joysticks(); } /* Function: al_get_joystick_event_source */ ALLEGRO_EVENT_SOURCE *al_get_joystick_event_source(void) { if (!new_joystick_driver) return NULL; return &es; } void _al_generate_joystick_event(ALLEGRO_EVENT *event) { ASSERT(new_joystick_driver); _al_event_source_lock(&es); if (_al_event_source_needs_to_generate_event(&es)) { _al_event_source_emit_event(&es, event); } _al_event_source_unlock(&es); } /* Function: al_get_num_joysticks */ int al_get_num_joysticks(void) { if (new_joystick_driver) return new_joystick_driver->num_joysticks(); return 0; } /* Function: al_get_joystick */ ALLEGRO_JOYSTICK * al_get_joystick(int num) { ASSERT(new_joystick_driver); ASSERT(num >= 0); return new_joystick_driver->get_joystick(num); } /* Function: al_release_joystick */ void al_release_joystick(ALLEGRO_JOYSTICK *joy) { ASSERT(new_joystick_driver); ASSERT(joy); new_joystick_driver->release_joystick(joy); } /* Function: al_get_joystick_active */ bool al_get_joystick_active(ALLEGRO_JOYSTICK *joy) { ASSERT(joy); return new_joystick_driver->get_active(joy); } /* Function: al_get_joystick_name */ const char *al_get_joystick_name(ALLEGRO_JOYSTICK *joy) { ASSERT(joy); return new_joystick_driver->get_name(joy); } /* Function: al_get_joystick_num_sticks */ int al_get_joystick_num_sticks(ALLEGRO_JOYSTICK *joy) { ASSERT(joy); return joy->info.num_sticks; } /* Function: al_get_joystick_stick_flags */ int al_get_joystick_stick_flags(ALLEGRO_JOYSTICK *joy, int stick) { ASSERT(joy); ASSERT(stick >= 0); if (stick < joy->info.num_sticks) return joy->info.stick[stick].flags; return 0; } /* Function: al_get_joystick_stick_name */ const char *al_get_joystick_stick_name(ALLEGRO_JOYSTICK *joy, int stick) { ASSERT(joy); ASSERT(stick >= 0); if (stick < joy->info.num_sticks) return joy->info.stick[stick].name; return NULL; } /* Function: al_get_joystick_num_axes */ int al_get_joystick_num_axes(ALLEGRO_JOYSTICK *joy, int stick) { ASSERT(joy); if (stick < joy->info.num_sticks) return joy->info.stick[stick].num_axes; return 0; } /* Function: al_get_joystick_axis_name */ const char *al_get_joystick_axis_name(ALLEGRO_JOYSTICK *joy, int stick, int axis) { ASSERT(joy); ASSERT(stick >= 0); ASSERT(axis >= 0); if (stick < joy->info.num_sticks) if (axis < joy->info.stick[stick].num_axes) return joy->info.stick[stick].axis[axis].name; return NULL; } /* Function: al_get_joystick_num_buttons */ int al_get_joystick_num_buttons(ALLEGRO_JOYSTICK *joy) { ASSERT(joy); return joy->info.num_buttons; } /* Function: al_get_joystick_button_name */ const char *al_get_joystick_button_name(ALLEGRO_JOYSTICK *joy, int button) { ASSERT(joy); ASSERT(button >= 0); if (button < joy->info.num_buttons) return joy->info.button[button].name; return NULL; } /* Function: al_get_joystick_state */ void al_get_joystick_state(ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state) { ASSERT(new_joystick_driver); ASSERT(joy); ASSERT(ret_state); new_joystick_driver->get_joystick_state(joy, ret_state); } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/keybdnu.c000066400000000000000000000246701473414355200160650ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * New keyboard API. * * By Peter Wang. * * See readme.txt for copyright information. */ /* Title: Keyboard routines */ #define ALLEGRO_NO_COMPATIBILITY #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/internal/aintern_system.h" /* the active keyboard driver */ static ALLEGRO_KEYBOARD_DRIVER *new_keyboard_driver = NULL; /* Provide a default naming for the most common keys. Keys whose * mapping changes dependind on the layout aren't listed - it's up to * the keyboard driver to do that. All keyboard drivers should * provide their own implementation though, especially if they use * positional mapping. */ const char *_al_keyboard_common_names[/* leave empty */] = { "(none)", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "PAD 0", "PAD 1", "PAD 2", "PAD 3", "PAD 4", "PAD 5", "PAD 6", "PAD 7", "PAD 8", "PAD 9", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "ESCAPE", "KEY60", "KEY61", "KEY62", "BACKSPACE", "TAB", "KEY65", "KEY66", "ENTER", "KEY68", "KEY69", "BACKSLASH", "KEY71", "KEY72", "KEY73", "KEY74", "SPACE", "INSERT", "DELETE", "HOME", "END", "PGUP", "PGDN", "LEFT", "RIGHT", "UP", "DOWN", "PAD /", "PAD *", "PAD -", "PAD +", "PAD DELETE", "PAD ENTER", "PRINTSCREEN","PAUSE", "KEY94", "KEY95", "KEY96", "KEY97", "KEY98", "KEY99", "KEY100", "KEY101", "KEY102", "PAD =", "KEY104", "KEY105", "KEY106", "KEY107", "KEY108", "KEY109", "KEY110", "KEY111", "KEY112", "KEY113", "KEY114", "KEY115", "KEY116", "KEY117", "KEY118", "KEY119", "KEY120", "KEY121", "KEY122", "KEY123", "KEY124", "KEY125", "KEY126", "KEY127", "KEY128", "KEY129", "KEY130", "KEY131", "KEY132", "KEY133", "KEY134", "KEY135", "KEY136", "KEY137", "KEY138", "KEY139", "KEY140", "KEY141", "KEY142", "KEY143", "KEY144", "KEY145", "KEY146", "KEY147", "KEY148", "KEY149", "KEY150", "KEY151", "KEY152", "KEY153", "KEY154", "KEY155", "KEY156", "KEY157", "KEY158", "KEY159", "KEY160", "KEY161", "KEY162", "KEY163", "KEY164", "KEY165", "KEY166", "KEY167", "KEY168", "KEY169", "KEY170", "KEY171", "KEY172", "KEY173", "KEY174", "KEY175", "KEY176", "KEY177", "KEY178", "KEY179", "KEY180", "KEY181", "KEY182", "KEY183", "KEY184", "KEY185", "KEY186", "KEY187", "KEY188", "KEY189", "KEY190", "KEY191", "KEY192", "KEY193", "KEY194", "KEY195", "KEY196", "KEY197", "KEY198", "KEY199", "KEY200", "KEY201", "KEY202", "KEY203", "KEY204", "KEY205", "KEY206", "KEY207", "KEY208", "KEY209", "KEY210", "KEY211", "KEY212", "KEY213", "KEY214", "LSHIFT", "RSHIFT", "LCTRL", "RCTRL", "ALT", "ALTGR", "LWIN", "RWIN", "MENU", "SCROLLLOCK", "NUMLOCK", "CAPSLOCK" }; ALLEGRO_STATIC_ASSERT(keybdnu, sizeof(_al_keyboard_common_names) / sizeof(_al_keyboard_common_names[0]) == ALLEGRO_KEY_MAX); /* Function: al_is_keyboard_installed */ bool al_is_keyboard_installed(void) { return (new_keyboard_driver ? true : false); } /* Function: al_install_keyboard */ bool al_install_keyboard(void) { if (new_keyboard_driver) return true; //FIXME: seems A4/A5 driver list stuff doesn't quite agree right now if (al_get_system_driver()->vt->get_keyboard_driver) { new_keyboard_driver = al_get_system_driver()->vt->get_keyboard_driver(); if (!new_keyboard_driver->init_keyboard()) { new_keyboard_driver = NULL; return false; } _al_add_exit_func(al_uninstall_keyboard, "al_uninstall_keyboard"); return true; } return false; /* if (system_driver->keyboard_drivers) driver_list = system_driver->keyboard_drivers(); else driver_list = _al_keyboard_driver_list; for (i=0; driver_list[i].driver; i++) { new_keyboard_driver = driver_list[i].driver; name = get_config_text(new_keyboard_driver->keydrv_ascii_name); new_keyboard_driver->keydrv_name = name; new_keyboard_driver->keydrv_desc = name; if (new_keyboard_driver->init_keyboard()) break; } if (!driver_list[i].driver) { new_keyboard_driver = NULL; return false; } //set_leds(-1); _al_add_exit_func(al_uninstall_keyboard, "al_uninstall_keyboard"); return true; */ } /* Function: al_uninstall_keyboard */ void al_uninstall_keyboard(void) { if (!new_keyboard_driver) return; //set_leds(-1); new_keyboard_driver->exit_keyboard(); new_keyboard_driver = NULL; } /* This was in the public API but its only purpose is now served by * al_get_keyboard_event_source(). */ static ALLEGRO_KEYBOARD *al_get_keyboard(void) { ASSERT(new_keyboard_driver); { ALLEGRO_KEYBOARD *kbd = new_keyboard_driver->get_keyboard(); ASSERT(kbd); return kbd; } } /* Function: al_can_set_keyboard_leds */ bool al_can_set_keyboard_leds(void) { ASSERT(new_keyboard_driver); return new_keyboard_driver->set_keyboard_leds; } /* Function: al_set_keyboard_leds */ bool al_set_keyboard_leds(int leds) { ASSERT(new_keyboard_driver); if (new_keyboard_driver->set_keyboard_leds) return new_keyboard_driver->set_keyboard_leds(leds); return false; } /* Function: al_keycode_to_name */ const char *al_keycode_to_name(int keycode) { const char *name = NULL; ASSERT(new_keyboard_driver); ASSERT((keycode >= 0) && (keycode < ALLEGRO_KEY_MAX)); if (new_keyboard_driver->keycode_to_name) name = new_keyboard_driver->keycode_to_name(keycode); if (!name) name = _al_keyboard_common_names[keycode]; ASSERT(name); return name; } /* Function: al_get_keyboard_state */ void al_get_keyboard_state(ALLEGRO_KEYBOARD_STATE *ret_state) { ASSERT(new_keyboard_driver); ASSERT(ret_state); new_keyboard_driver->get_keyboard_state(ret_state); } /* Function: al_clear_keyboard_state */ void al_clear_keyboard_state(ALLEGRO_DISPLAY *display) { ASSERT(new_keyboard_driver); if (display) { ALLEGRO_EVENT_SOURCE *es = al_get_keyboard_event_source(); ALLEGRO_KEYBOARD_STATE ks; al_get_keyboard_state(&ks); _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { int keycode; for (keycode = ALLEGRO_KEY_A; keycode < ALLEGRO_KEY_MAX; keycode++) { if (al_key_down(&ks, keycode)) { ALLEGRO_EVENT event; event.keyboard.type = ALLEGRO_EVENT_KEY_UP; event.keyboard.timestamp = al_get_time(); event.keyboard.display = display; event.keyboard.keycode = keycode; event.keyboard.unichar = 0; event.keyboard.modifiers = 0; _al_event_source_emit_event(es, &event); } } } _al_event_source_unlock(es); } new_keyboard_driver->clear_keyboard_state(); } /* Function: al_key_down */ bool al_key_down(const ALLEGRO_KEYBOARD_STATE *state, int keycode) { return _AL_KEYBOARD_STATE_KEY_DOWN(*state, keycode); } /* Function: al_get_keyboard_event_source */ ALLEGRO_EVENT_SOURCE *al_get_keyboard_event_source(void) { ALLEGRO_KEYBOARD *keyboard = al_get_keyboard(); return (keyboard) ? &keyboard->es : NULL; } static int match_key_name(const char *s) { int i; /* Some key names are not intuitive, but this is all we've got. */ for (i = 1; i < ALLEGRO_KEY_MAX; i++) { if (0 == _al_stricmp(s, _al_keyboard_common_names[i])) return i; } return 0; } static unsigned int match_modifier(const char *s) { if (0 == _al_stricmp(s, "SHIFT")) return ALLEGRO_KEYMOD_SHIFT; if (0 == _al_stricmp(s, "CTRL")) return ALLEGRO_KEYMOD_CTRL; if (0 == _al_stricmp(s, "ALT")) return ALLEGRO_KEYMOD_ALT; if (0 == _al_stricmp(s, "LWIN")) return ALLEGRO_KEYMOD_LWIN; if (0 == _al_stricmp(s, "RWIN")) return ALLEGRO_KEYMOD_RWIN; if (0 == _al_stricmp(s, "ALTGR")) return ALLEGRO_KEYMOD_ALTGR; if (0 == _al_stricmp(s, "COMMAND")) return ALLEGRO_KEYMOD_COMMAND; return 0; } int _al_parse_key_binding(const char *s, unsigned int *modifiers) { ALLEGRO_USTR *us; unsigned start = 0; int keycode = 0; us = al_ustr_new(s); al_ustr_trim_ws(us); *modifiers = 0; while (start < al_ustr_size(us)) { /* XXX not all keys can be bound due to a conflict with the delimiter * characters */ int end = al_ustr_find_set_cstr(us, start, "+-"); unsigned int mod; /* Last component must be a key. */ if (end == -1) { keycode = match_key_name(al_cstr(us) + start); break; } /* Otherwise must be a modifier. */ al_ustr_set_chr(us, end, '\0'); mod = match_modifier(al_cstr(us) + start); if (!mod) { break; } (*modifiers) |= mod; start = end + 1; } al_ustr_free(us); return keycode; } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/libc.c000066400000000000000000000044201473414355200153240ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Emulation for libc routines that may be missing on some platforms. * * By Michael Bukin. * * Henrik Stokseth added _al_sane_realloc() and _al_sane_strncpy() functions. * * _al_srand() and _al_rand() functions based on code by Paul Pridham. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include #include static int _al_rand_seed = 0; /* _al_stricmp: * Case-insensitive comparison of 7-bit ASCII strings. */ int _al_stricmp(const char *s1, const char *s2) { int c1, c2; ASSERT(s1); ASSERT(s2); do { c1 = tolower(*(s1++)); c2 = tolower(*(s2++)); } while ((c1) && (c1 == c2)); return c1 - c2; } /* _al_sane_realloc: * al_realloc() substitution with guaranteed behaviour. */ void *_al_sane_realloc(void *ptr, size_t size) { void *tmp_ptr; tmp_ptr = NULL; if (ptr && size) { tmp_ptr = al_realloc(ptr, size); if (!tmp_ptr && ptr) al_free(ptr); } else if (!size) { tmp_ptr = NULL; if (ptr) al_free(ptr); } else if (!ptr) { tmp_ptr = al_malloc(size); } return tmp_ptr; } /* _al_sane_strncpy: * strncpy() substitution which properly null terminates a string. */ char *_al_sane_strncpy(char *dest, const char *src, size_t n) { if (n <= 0) return dest; dest[0] = '\0'; strncat(dest, src, n - 1); return dest; } /* _al_srand: * Seed initialization routine for rand() replacement. */ void _al_srand(int seed) { _al_rand_seed = seed; } /* _al_rand: * Simple rand() replacement with guaranteed randomness in the lower 16 bits. */ int _al_rand(void) { _al_rand_seed = (_al_rand_seed + 1) * 1103515245 + 12345; return ((_al_rand_seed >> 16) & _AL_RAND_MAX); } allegro5-5.2.10.1/src/linux/000077500000000000000000000000001473414355200154065ustar00rootroot00000000000000allegro5-5.2.10.1/src/linux/lhaptic.c000066400000000000000000000511351473414355200172030ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Linux haptic (force-feedback) device driver. * * By Beoran. * * See LICENSE.txt for copyright information. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern_haptic.h" #include "allegro5/internal/aintern_ljoynu.h" #include "allegro5/platform/aintunix.h" #ifdef ALLEGRO_HAVE_LINUX_INPUT_H #include ALLEGRO_DEBUG_CHANNEL("lhaptic") /* For compatibility with older kernels. */ #ifndef input_event_sec #define input_event_sec time.tv_sec #define input_event_usec time.tv_usec #endif /* Support at most 32 haptic devices. */ #define HAPTICS_MAX 32 /* Support at most 16 effects per device. */ #define HAPTICS_EFFECTS_MAX 16 typedef struct { struct ALLEGRO_HAPTIC parent; /* must be first */ bool active; int fd; int flags; int effects[HAPTICS_EFFECTS_MAX]; } ALLEGRO_HAPTIC_LINUX; #define LONG_BITS (sizeof(long) * 8) #define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS) /* Tests if a bit in an array of longs is set. */ #define TEST_BIT(nr, addr) \ ((1UL << ((nr) % LONG_BITS)) & (addr)[(nr) / LONG_BITS]) /* forward declarations */ static bool lhap_init_haptic(void); static void lhap_exit_haptic(void); static bool lhap_is_mouse_haptic(ALLEGRO_MOUSE *dev); static bool lhap_is_joystick_haptic(ALLEGRO_JOYSTICK *); static bool lhap_is_keyboard_haptic(ALLEGRO_KEYBOARD *dev); static bool lhap_is_display_haptic(ALLEGRO_DISPLAY *dev); static bool lhap_is_touch_input_haptic(ALLEGRO_TOUCH_INPUT *dev); static ALLEGRO_HAPTIC *lhap_get_from_mouse(ALLEGRO_MOUSE *dev); static ALLEGRO_HAPTIC *lhap_get_from_joystick(ALLEGRO_JOYSTICK *dev); static ALLEGRO_HAPTIC *lhap_get_from_keyboard(ALLEGRO_KEYBOARD *dev); static ALLEGRO_HAPTIC *lhap_get_from_display(ALLEGRO_DISPLAY *dev); static ALLEGRO_HAPTIC *lhap_get_from_touch_input(ALLEGRO_TOUCH_INPUT *dev); static bool lhap_release(ALLEGRO_HAPTIC *haptic); static bool lhap_get_active(ALLEGRO_HAPTIC *hap); static int lhap_get_capabilities(ALLEGRO_HAPTIC *dev); static double lhap_get_gain(ALLEGRO_HAPTIC *dev); static bool lhap_set_gain(ALLEGRO_HAPTIC *dev, double); static int lhap_get_max_effects(ALLEGRO_HAPTIC *dev); static bool lhap_is_effect_ok(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *eff); static bool lhap_upload_effect(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *eff, ALLEGRO_HAPTIC_EFFECT_ID *id); static bool lhap_play_effect(ALLEGRO_HAPTIC_EFFECT_ID *id, int loop); static bool lhap_stop_effect(ALLEGRO_HAPTIC_EFFECT_ID *id); static bool lhap_is_effect_playing(ALLEGRO_HAPTIC_EFFECT_ID *id); static bool lhap_release_effect(ALLEGRO_HAPTIC_EFFECT_ID *id); static double lhap_get_autocenter(ALLEGRO_HAPTIC *dev); static bool lhap_set_autocenter(ALLEGRO_HAPTIC *dev, double); static void lhap_timerclear(struct input_event *evt); ALLEGRO_HAPTIC_DRIVER _al_hapdrv_linux = { _ALLEGRO_HAPDRV_LINUX, "", "", "Linux haptic(s)", lhap_init_haptic, lhap_exit_haptic, lhap_is_mouse_haptic, lhap_is_joystick_haptic, lhap_is_keyboard_haptic, lhap_is_display_haptic, lhap_is_touch_input_haptic, lhap_get_from_mouse, lhap_get_from_joystick, lhap_get_from_keyboard, lhap_get_from_display, lhap_get_from_touch_input, lhap_get_active, lhap_get_capabilities, lhap_get_gain, lhap_set_gain, lhap_get_max_effects, lhap_is_effect_ok, lhap_upload_effect, lhap_play_effect, lhap_stop_effect, lhap_is_effect_playing, lhap_release_effect, lhap_release, lhap_get_autocenter, lhap_set_autocenter }; static ALLEGRO_HAPTIC_LINUX haptics[HAPTICS_MAX]; static ALLEGRO_MUTEX *haptic_mutex = NULL; struct CAP_MAP { int linux_bit; int allegro_bit; }; static const struct CAP_MAP cap_map[] = { { FF_PERIODIC, ALLEGRO_HAPTIC_PERIODIC }, { FF_RUMBLE, ALLEGRO_HAPTIC_RUMBLE }, { FF_CONSTANT, ALLEGRO_HAPTIC_CONSTANT }, { FF_SPRING, ALLEGRO_HAPTIC_SPRING }, { FF_FRICTION, ALLEGRO_HAPTIC_FRICTION }, { FF_DAMPER, ALLEGRO_HAPTIC_DAMPER }, { FF_INERTIA, ALLEGRO_HAPTIC_INERTIA }, { FF_RAMP, ALLEGRO_HAPTIC_RAMP }, { FF_SQUARE, ALLEGRO_HAPTIC_SQUARE }, { FF_TRIANGLE, ALLEGRO_HAPTIC_TRIANGLE }, { FF_SINE, ALLEGRO_HAPTIC_SINE }, { FF_SAW_UP, ALLEGRO_HAPTIC_SAW_UP }, { FF_SAW_DOWN, ALLEGRO_HAPTIC_SAW_DOWN }, { FF_CUSTOM, ALLEGRO_HAPTIC_CUSTOM }, { FF_GAIN, ALLEGRO_HAPTIC_GAIN }, { FF_AUTOCENTER, ALLEGRO_HAPTIC_AUTOCENTER }, { -1, -1 } }; static bool lhap_init_haptic(void) { int i; ASSERT(haptic_mutex == NULL); haptic_mutex = al_create_mutex(); if (!haptic_mutex) return false; for (i = 0; i < HAPTICS_MAX; i++) { haptics[i].active = false; } return true; } static ALLEGRO_HAPTIC_LINUX *lhap_get_available_haptic(void) { int i; for (i = 0; i < HAPTICS_MAX; i++) { if (!haptics[i].active) { haptics[i].active = true; return &haptics[i]; } } return NULL; } /* Converts a generic haptic device to a Linux-specific one. */ static ALLEGRO_HAPTIC_LINUX *lhap_from_al(ALLEGRO_HAPTIC *hap) { return (ALLEGRO_HAPTIC_LINUX *)hap; } static void lhap_exit_haptic(void) { ASSERT(haptic_mutex); al_destroy_mutex(haptic_mutex); haptic_mutex = NULL; } static bool lhap_type2lin(__u16 *res, int type) { ASSERT(res); switch (type) { case ALLEGRO_HAPTIC_RUMBLE: (*res) = FF_RUMBLE; break; case ALLEGRO_HAPTIC_PERIODIC: (*res) = FF_PERIODIC; break; case ALLEGRO_HAPTIC_CONSTANT: (*res) = FF_CONSTANT; break; case ALLEGRO_HAPTIC_SPRING: (*res) = FF_SPRING; break; case ALLEGRO_HAPTIC_FRICTION: (*res) = FF_FRICTION; break; case ALLEGRO_HAPTIC_DAMPER: (*res) = FF_DAMPER; break; case ALLEGRO_HAPTIC_INERTIA: (*res) = FF_INERTIA; break; case ALLEGRO_HAPTIC_RAMP: (*res) = FF_RAMP; break; default: return false; } return true; } static bool lhap_wave2lin(__u16 *res, int type) { ASSERT(res); switch (type) { case ALLEGRO_HAPTIC_SQUARE: (*res) = FF_SQUARE; break; case ALLEGRO_HAPTIC_TRIANGLE: (*res) = FF_TRIANGLE; break; case ALLEGRO_HAPTIC_SINE: (*res) = FF_SINE; break; case ALLEGRO_HAPTIC_SAW_UP: (*res) = FF_SAW_UP; break; case ALLEGRO_HAPTIC_SAW_DOWN: (*res) = FF_SAW_DOWN; break; case ALLEGRO_HAPTIC_CUSTOM: (*res) = FF_CUSTOM; break; default: return false; } return true; } /* Converts the time in seconds to a Linux-compatible time. * Return false if out of bounds. */ static bool lhap_time2lin(__u16 *res, double sec) { ASSERT(res); if (sec < 0.0 || sec > 32.767) return false; (*res) = (__u16) round(sec * 1000.0); return true; } /* Converts the time in seconds to a Linux-compatible time. * Return false if out of bounds. This one allows negative times. */ static bool lhap_stime2lin(__s16 *res, double sec) { ASSERT(res); if (sec < -32.767 || sec > 32.767) return false; (*res) = (__s16) round(sec * 1000.0); return true; } /* Converts replay data to Linux-compatible data. */ static bool lhap_replay2lin(struct ff_replay *lin, struct ALLEGRO_HAPTIC_REPLAY *al) { return lhap_time2lin(&lin->delay, al->delay) && lhap_time2lin(&lin->length, al->length); } /* Converts the level in range 0.0 to 1.0 to a Linux-compatible level. * Returns false if out of bounds. */ static bool lhap_level2lin(__u16 *res, double level) { ASSERT(res); if (level < 0.0 || level > 1.0) return false; *res = (__u16) round(level * (double)0x7fff); return true; } /* Converts the level in range -1.0 to 1.0 to a Linux-compatible level. * Returns false if out of bounds. */ static bool lhap_slevel2lin(__s16 *res, double level) { ASSERT(res); if (level < -1.0 || level > 1.0) return false; *res = (__s16) round(level * (double)0x7ffe); return true; } /* Converts an Allegro haptic effect envelope to Linux input API. */ static bool lhap_envelope2lin(struct ff_envelope *lin, struct ALLEGRO_HAPTIC_ENVELOPE *al) { return lhap_time2lin(&lin->attack_length, al->attack_length) && lhap_time2lin(&lin->fade_length, al->fade_length) && lhap_level2lin(&lin->attack_level, al->attack_level) && lhap_level2lin(&lin->fade_level, al->fade_level); } /* Converts a rumble effect to Linux input API. */ static bool lhap_rumble2lin(struct ff_rumble_effect *lin, struct ALLEGRO_HAPTIC_RUMBLE_EFFECT *al) { return lhap_level2lin(&lin->strong_magnitude, al->strong_magnitude) && lhap_level2lin(&lin->weak_magnitude, al->weak_magnitude); } /* Converts a constant effect to Linux input API. */ static bool lhap_constant2lin(struct ff_constant_effect *lin, struct ALLEGRO_HAPTIC_CONSTANT_EFFECT *al) { return lhap_envelope2lin(&lin->envelope, &al->envelope) && lhap_slevel2lin(&lin->level, al->level); } /* Converts a ramp effect to Linux input API. */ static bool lhap_ramp2lin(struct ff_ramp_effect *lin, struct ALLEGRO_HAPTIC_RAMP_EFFECT *al) { return lhap_envelope2lin(&lin->envelope, &al->envelope) && lhap_slevel2lin(&lin->start_level, al->start_level) && lhap_slevel2lin(&lin->end_level, al->end_level); } /* Converts a ramp effect to Linux input API. */ static bool lhap_condition2lin(struct ff_condition_effect *lin, struct ALLEGRO_HAPTIC_CONDITION_EFFECT *al) { return lhap_slevel2lin(&lin->center, al->center) && lhap_level2lin(&lin->deadband, al->deadband) && lhap_slevel2lin(&lin->right_coeff, al->right_coeff) && lhap_level2lin(&lin->right_saturation, al->right_saturation) && lhap_slevel2lin(&lin->left_coeff, al->left_coeff) && lhap_level2lin(&lin->left_saturation, al->left_saturation); } /* Converts a periodic effect to linux input API. */ static bool lhap_periodic2lin(struct ff_periodic_effect *lin, struct ALLEGRO_HAPTIC_PERIODIC_EFFECT *al) { /* Custom data is not supported yet, because currently no Linux * haptic driver supports it. */ if (al->custom_data) return false; return lhap_slevel2lin(&lin->magnitude, al->magnitude) && lhap_stime2lin(&lin->offset, al->offset) && lhap_time2lin(&lin->period, al->period) && lhap_time2lin(&lin->phase, al->phase) && lhap_wave2lin(&lin->waveform, al->waveform) && lhap_envelope2lin(&lin->envelope, &al->envelope); } /* Converts Allegro haptic effect to Linux input API. */ static bool lhap_effect2lin(struct ff_effect *lin, ALLEGRO_HAPTIC_EFFECT *al) { memset(lin, 0, sizeof(*lin)); if (!lhap_type2lin(&lin->type, al->type)) return false; /* lin_effect->replay = effect->re; */ lin->direction = (__u16) round(((double)0xC000 * al->direction.angle) / (2 * M_PI)); lin->id = -1; if (!lhap_replay2lin(&lin->replay, &al->replay)) return false; switch (lin->type) { case FF_RUMBLE: return lhap_rumble2lin(&lin->u.rumble, &al->data.rumble); case FF_PERIODIC: return lhap_periodic2lin(&lin->u.periodic, &al->data.periodic); case FF_CONSTANT: return lhap_constant2lin(&lin->u.constant, &al->data.constant); case FF_RAMP: return lhap_ramp2lin(&lin->u.ramp, &al->data.ramp); case FF_SPRING: /* fall through */ case FF_FRICTION: /* fall through */ case FF_DAMPER: /* fall through */ case FF_INERTIA: return lhap_condition2lin(&lin->u.condition[0], &al->data.condition); default: return false; } } static bool lhap_get_active(ALLEGRO_HAPTIC *haptic) { ALLEGRO_HAPTIC_LINUX *lhap = lhap_from_al(haptic); return lhap->active; } static bool lhap_is_mouse_haptic(ALLEGRO_MOUSE *mouse) { (void)mouse; return false; } static bool lhap_fd_can_ff(int fd) { long bitmask[NLONGS(EV_CNT)] = { 0 }; if (ioctl(fd, EVIOCGBIT(0, sizeof(bitmask)), bitmask) < 0) { return false; } if (TEST_BIT(EV_FF, bitmask)) { return true; } return false; } static bool lhap_is_joystick_haptic(ALLEGRO_JOYSTICK *joy) { ALLEGRO_JOYSTICK_LINUX *ljoy = (ALLEGRO_JOYSTICK_LINUX *) joy; if (!al_is_joystick_installed()) return false; if (!al_get_joystick_active(joy)) return false; if (ljoy->fd <= 0) return false; return lhap_fd_can_ff(ljoy->fd); } static bool lhap_is_display_haptic(ALLEGRO_DISPLAY *dev) { (void)dev; return false; } static bool lhap_is_keyboard_haptic(ALLEGRO_KEYBOARD *dev) { (void)dev; return false; } static bool lhap_is_touch_input_haptic(ALLEGRO_TOUCH_INPUT *dev) { (void)dev; return false; } static ALLEGRO_HAPTIC *lhap_get_from_mouse(ALLEGRO_MOUSE *mouse) { (void)mouse; return NULL; } static bool get_haptic_capabilities(int fd, int *capabilities) { unsigned long bitmask[NLONGS(FF_CNT)] = { 0 }; int caps; int i; if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(bitmask)), bitmask) < 0) { ALLEGRO_ERROR("EVIOCGBIT failed for fd %d", fd); return false; } caps = 0; for (i = 0; cap_map[i].allegro_bit >= 0; i++) { if (TEST_BIT(cap_map[i].linux_bit, bitmask)) { caps |= cap_map[i].allegro_bit; } } (*capabilities) = caps; ALLEGRO_INFO("Capabilities: 0x%x\n", caps); return true; } static ALLEGRO_HAPTIC *lhap_get_from_joystick(ALLEGRO_JOYSTICK *joy) { ALLEGRO_JOYSTICK_LINUX *ljoy = (ALLEGRO_JOYSTICK_LINUX *) joy; ALLEGRO_HAPTIC_LINUX *lhap; int i; if (!al_is_joystick_haptic(joy)) return NULL; al_lock_mutex(haptic_mutex); lhap = lhap_get_available_haptic(); if (!lhap) { al_unlock_mutex(haptic_mutex); return NULL; } lhap->parent.device = joy; lhap->parent.from = _AL_HAPTIC_FROM_JOYSTICK; lhap->fd = ljoy->fd; lhap->active = true; for (i = 0; i < HAPTICS_EFFECTS_MAX; i++) { lhap->effects[i] = -1; /* not in use */ } lhap->parent.gain = 1.0; get_haptic_capabilities(lhap->fd, &lhap->flags); al_unlock_mutex(haptic_mutex); return &lhap->parent; } static ALLEGRO_HAPTIC *lhap_get_from_display(ALLEGRO_DISPLAY *dev) { (void)dev; return NULL; } static ALLEGRO_HAPTIC *lhap_get_from_keyboard(ALLEGRO_KEYBOARD *dev) { (void)dev; return NULL; } static ALLEGRO_HAPTIC *lhap_get_from_touch_input(ALLEGRO_TOUCH_INPUT *dev) { (void)dev; return NULL; } static int lhap_get_capabilities(ALLEGRO_HAPTIC *dev) { ALLEGRO_HAPTIC_LINUX *lhap = lhap_from_al(dev); return lhap->flags; } static double lhap_get_gain(ALLEGRO_HAPTIC *dev) { ALLEGRO_HAPTIC_LINUX *lhap = lhap_from_al(dev); (void)dev; if(!al_is_haptic_capable(dev, ALLEGRO_HAPTIC_GAIN)) { return 0.0; } /* Unfortunately there seems to be no API to GET gain, only to set?! * So, return the stored gain. */ return lhap->parent.gain; } static bool lhap_set_gain(ALLEGRO_HAPTIC *dev, double gain) { ALLEGRO_HAPTIC_LINUX *lhap = lhap_from_al(dev); struct input_event ie; lhap->parent.gain = gain; lhap_timerclear(&ie); ie.type = EV_FF; ie.code = FF_GAIN; ie.value = (__s32) ((double)0xFFFF * gain); if (write(lhap->fd, &ie, sizeof(ie)) < 0) { return false; } return true; } static bool lhap_set_autocenter(ALLEGRO_HAPTIC *dev, double autocenter) { ALLEGRO_HAPTIC_LINUX *lhap = lhap_from_al(dev); struct input_event ie; lhap->parent.autocenter = autocenter; lhap_timerclear(&ie); ie.type = EV_FF; ie.code = FF_AUTOCENTER; ie.value = (__s32) ((double)0xFFFF * autocenter); if (write(lhap->fd, &ie, sizeof(ie)) < 0) { return false; } return true; } static double lhap_get_autocenter(ALLEGRO_HAPTIC *dev) { ALLEGRO_HAPTIC_LINUX *lhap = lhap_from_al(dev); (void)dev; if(!al_is_haptic_capable(dev, ALLEGRO_HAPTIC_AUTOCENTER)) { return 0.0; } /* Unfortunately there seems to be no API to GET gain, only to set?! * So, return the stored autocenter. */ return lhap->parent.autocenter; } int lhap_get_max_effects(ALLEGRO_HAPTIC *dev) { ALLEGRO_HAPTIC_LINUX *lhap = lhap_from_al(dev); int n_effects; if (ioctl(lhap->fd, EVIOCGEFFECTS, &n_effects) < 0) { ALLEGRO_WARN("EVIOCGEFFECTS failed on fd %d\n", lhap->fd); n_effects = HAPTICS_EFFECTS_MAX; } if (n_effects < HAPTICS_EFFECTS_MAX) return n_effects; else return HAPTICS_EFFECTS_MAX; } static bool lhap_is_effect_ok(ALLEGRO_HAPTIC *haptic, ALLEGRO_HAPTIC_EFFECT *effect) { int caps; struct ff_effect leff; caps = al_get_haptic_capabilities(haptic); if (caps & effect->type) { return lhap_effect2lin(&leff, effect); } return false; } static bool lhap_upload_effect(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *effect, ALLEGRO_HAPTIC_EFFECT_ID *id) { ALLEGRO_HAPTIC_LINUX *lhap = lhap_from_al(dev); struct ff_effect leff; int found; int i; ASSERT(dev); ASSERT(id); ASSERT(effect); /* Set id's values to indicate failure. */ id->_haptic = NULL; id->_id = -1; id->_handle = -1; if (!lhap_effect2lin(&leff, effect)) { ALLEGRO_WARN("lhap_effect2lin failed"); return false; } /* Find empty spot for effect . */ found = -1; for (i = 0; i < al_get_max_haptic_effects(dev); i++) { if (lhap->effects[i] < 0) { found = i; break; } } /* No more space for an effect. */ if (found < 0) { ALLEGRO_WARN("No free effect slot."); return false; } /* Upload effect. */ leff.id = -1; if (ioctl(lhap->fd, EVIOCSFF, &leff) < 0) { ALLEGRO_ERROR("EVIOCSFF failed for fd %d\n", lhap->fd); return false; } id->_haptic = dev; id->_id = found; id->_handle = leff.id; id->_effect_duration = al_get_haptic_effect_duration(effect); id->_playing = false; /* XXX should be bool or something? */ lhap->effects[i] = found; return true; } static bool lhap_play_effect(ALLEGRO_HAPTIC_EFFECT_ID *id, int loops) { ALLEGRO_HAPTIC_LINUX *lhap = (ALLEGRO_HAPTIC_LINUX *) id->_haptic; struct input_event play; int fd; double now; double duration; if (!lhap) return false; fd = lhap->fd; lhap_timerclear(&play); play.type = EV_FF; play.code = id->_handle; loops = (loops < 0) ? 1 : loops; play.value = loops; /* play: 1, stop: 0 */ if (write(fd, (const void *)&play, sizeof(play)) < 0) { ALLEGRO_ERROR("Effect play failed.\n"); return false; } now = al_get_time(); duration = loops * id->_effect_duration; id->_playing = true; id->_start_time = now; id->_end_time = now + duration; return true; } static bool lhap_stop_effect(ALLEGRO_HAPTIC_EFFECT_ID *id) { ALLEGRO_HAPTIC_LINUX *lhap = (ALLEGRO_HAPTIC_LINUX *) id->_haptic; struct input_event play; if (!lhap) return false; memset(&play, 0, sizeof(play)); play.type = EV_FF; play.code = id->_handle; play.value = 0; if (write(lhap->fd, (const void *)&play, sizeof(play)) < 0) { ALLEGRO_ERROR("Stop effect failed.\n"); return false; } id->_playing = false; return true; } static bool lhap_is_effect_playing(ALLEGRO_HAPTIC_EFFECT_ID *id) { ASSERT(id); /* Since AFAICS there is no Linux API to test this, use a timer to check * if the effect has been playing long enough to be finished or not. */ return (id->_playing && al_get_time() < id->_end_time); } static bool lhap_release_effect(ALLEGRO_HAPTIC_EFFECT_ID *id) { ALLEGRO_HAPTIC_LINUX *lhap = (ALLEGRO_HAPTIC_LINUX *)id->_haptic; lhap_stop_effect(id); if (ioctl(lhap->fd, EVIOCRMFF, id->_handle) < 0) { ALLEGRO_ERROR("EVIOCRMFF failed.\n"); return false; } lhap->effects[id->_id] = -1; /* not in use */ return true; } static bool lhap_release(ALLEGRO_HAPTIC *haptic) { ALLEGRO_HAPTIC_LINUX *lhap = lhap_from_al(haptic); ASSERT(haptic); if (!lhap->active) return false; lhap->active = false; lhap->fd = -1; return true; } void lhap_timerclear(struct input_event* evt) { evt->input_event_sec = 0; evt->input_event_usec = 0; } #endif /* ALLEGRO_HAVE_LINUX_INPUT_H */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/linux/ljoynu.c000066400000000000000000000646001473414355200171000ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Linux joystick driver. * * By George Foot and Peter Wang. * * Updated for new joystick API by Peter Wang. * * See readme.txt for copyright information. */ #include #include #include #include #include #include #include #define ALLEGRO_NO_KEY_DEFINES #define ALLEGRO_NO_COMPATIBILITY #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/platform/aintunix.h" #ifdef ALLEGRO_HAVE_LINUX_INPUT_H /* To be safe, include sys/types.h before linux/joystick.h to avoid conflicting * definitions of fd_set. */ #include #include #if defined(ALLEGRO_HAVE_SYS_INOTIFY_H) #define SUPPORT_HOTPLUG #include #endif #ifndef KEY_CNT #define KEY_CNT (KEY_MAX+1) #endif #ifndef ABS_CNT #define ABS_CNT (ABS_MAX+1) #endif ALLEGRO_DEBUG_CHANNEL("ljoy"); #include "allegro5/internal/aintern_ljoynu.h" #define LONG_BITS (sizeof(long) * 8) #define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS) /* Tests if a bit in an array of longs is set. */ #define TEST_BIT(nr, addr) \ ((1UL << ((nr) % LONG_BITS)) & (addr)[(nr) / LONG_BITS]) /* We only accept the axes ABS_X to ABS_HAT3Y as real joystick axes. * The axes ABS_PRESSURE, ABS_DISTANCE, ABS_TILT_X, ABS_TILT_Y, * ABS_TOOL_WIDTH are for use by a drawing tablet. * ABS_VOLUME is for volume sliders or key pairs on some keyboards. * Other axes up to ABS_MISC may exist, such as on the PS3, but they are * most likely not useful. */ #define LJOY_AXIS_RANGE_START (ABS_X) #define LJOY_AXIS_RANGE_END (ABS_HAT3Y + 1) /* The range of potential joystick button codes in the Linux input API * is from BTN_MISC to BTN_GEAR_UP. */ #define LJOY_BTN_RANGE_START (BTN_MISC) #if !defined(ALLEGRO_ANDROID) && defined(BTN_TRIGGER_HAPPY) #define LJOY_BTN_RANGE_END (BTN_TRIGGER_HAPPY40 + 1) #else #define LJOY_BTN_RANGE_END (BTN_GEAR_UP + 1) #endif /* forward declarations */ static bool ljoy_init_joystick(void); static void ljoy_exit_joystick(void); static bool ljoy_reconfigure_joysticks(void); static int ljoy_num_joysticks(void); static ALLEGRO_JOYSTICK *ljoy_get_joystick(int num); static void ljoy_release_joystick(ALLEGRO_JOYSTICK *joy_); static void ljoy_get_joystick_state(ALLEGRO_JOYSTICK *joy_, ALLEGRO_JOYSTICK_STATE *ret_state); static const char *ljoy_get_name(ALLEGRO_JOYSTICK *joy_); static bool ljoy_get_active(ALLEGRO_JOYSTICK *joy_); static void ljoy_process_new_data(void *data); static void ljoy_generate_axis_event(ALLEGRO_JOYSTICK_LINUX *joy, int stick, int axis, float pos); static void ljoy_generate_button_event(ALLEGRO_JOYSTICK_LINUX *joy, int button, ALLEGRO_EVENT_TYPE event_type); /* the driver vtable */ ALLEGRO_JOYSTICK_DRIVER _al_joydrv_linux = { _ALLEGRO_JOYDRV_LINUX, "", "", "Linux joystick(s)", ljoy_init_joystick, ljoy_exit_joystick, ljoy_reconfigure_joysticks, ljoy_num_joysticks, ljoy_get_joystick, ljoy_release_joystick, ljoy_get_joystick_state, ljoy_get_name, ljoy_get_active }; static unsigned num_joysticks; /* number of joysticks known to the user */ static _AL_VECTOR joysticks; /* of ALLEGRO_JOYSTICK_LINUX pointers */ static volatile bool config_needs_merging; static ALLEGRO_MUTEX *config_mutex; #ifdef SUPPORT_HOTPLUG static int inotify_fd = -1; static ALLEGRO_THREAD *hotplug_thread; static ALLEGRO_MUTEX *hotplug_mutex; static ALLEGRO_COND *hotplug_cond; static bool hotplug_ended = false; #endif /* Return true if a joystick-related button or key: * * BTN_MISC to BTN_9 for miscellaneous input, * BTN_JOYSTICK to BTN_DEAD for joysticks, * BTN_GAMEPAD to BTN_THUMBR for game pads, * BTN_WHEEL, BTN_GEAR_DOWN, BTN_GEAR_UP for steering wheels, * BTN_TRIGGER_HAPPY_n buttons just in case. */ static bool is_joystick_button(int i) { ASSERT(i >= LJOY_BTN_RANGE_START && i < LJOY_BTN_RANGE_END); return (i >= BTN_MISC && i <= BTN_9) || (i >= BTN_JOYSTICK && i <= BTN_DEAD) || (i >= BTN_GAMEPAD && i <= BTN_THUMBR) || (i >= BTN_WHEEL && i <= BTN_GEAR_UP) #if !defined(ALLEGRO_ANDROID) && defined(BTN_TRIGGER_HAPPY) || (i >= BTN_TRIGGER_HAPPY && i <= BTN_TRIGGER_HAPPY40) #endif ; } static bool is_single_axis_throttle(int i) { ASSERT(i >= LJOY_AXIS_RANGE_START && i < LJOY_AXIS_RANGE_END); /* Consider all these types of axis as throttle axis. */ return i == ABS_THROTTLE || i == ABS_RUDDER || i == ABS_WHEEL || i == ABS_GAS || i == ABS_BRAKE || i == ABS_PRESSURE || i == ABS_DISTANCE || i == ABS_TOOL_WIDTH; } static bool is_hat_axis(int i) { return (i >= ABS_HAT0X && i <= ABS_HAT3Y); } /* Check if the device has at least once joystick-related button. */ static bool have_joystick_button(int fd) { unsigned long key_bits[NLONGS(KEY_CNT)] = {0}; int i; if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) < 0) return false; for (i = LJOY_BTN_RANGE_START; i < LJOY_BTN_RANGE_END; i++) { if (TEST_BIT(i, key_bits) && is_joystick_button(i)) return true; } return false; } /* Check if the device has at least one joystick-related absolute axis. * Some devices, like (wireless) keyboards, may actually have absolute axes * such as a volume axis for the volume up/down buttons. * Also, some devices like a PS3 controller report many unusual axes, probably * used in nonstandard ways by the PS3 console. All such axes are ignored by * this function and by this driver. */ static bool have_joystick_axis(int fd) { unsigned long abs_bits[NLONGS(ABS_CNT)] = {0}; int i; if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits) < 0) return false; for (i = LJOY_AXIS_RANGE_START; i < LJOY_AXIS_RANGE_END; i++) { if (TEST_BIT(i, abs_bits)) return true; } return false; } static bool ljoy_detect_device_name(int num, ALLEGRO_USTR *device_name) { char key[80]; const char *value; struct stat stbuf; al_ustr_truncate(device_name, 0); snprintf(key, sizeof(key), "device%d", num); value = al_get_config_value(al_get_system_config(), "joystick", key); if (value) al_ustr_assign_cstr(device_name, value); return (stat(al_cstr(device_name), &stbuf) == 0); } static ALLEGRO_JOYSTICK_LINUX *ljoy_by_device_name( const ALLEGRO_USTR *device_name) { unsigned i; for (i = 0; i < _al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_LINUX **slot = _al_vector_ref(&joysticks, i); ALLEGRO_JOYSTICK_LINUX *joy = *slot; if (joy && al_ustr_equal(device_name, joy->device_name)) return joy; } return NULL; } static void ljoy_generate_configure_event(void) { ALLEGRO_EVENT event; event.joystick.type = ALLEGRO_EVENT_JOYSTICK_CONFIGURATION; event.joystick.timestamp = al_get_time(); _al_generate_joystick_event(&event); } static ALLEGRO_JOYSTICK_LINUX *ljoy_allocate_structure(void) { ALLEGRO_JOYSTICK_LINUX **slot; ALLEGRO_JOYSTICK_LINUX *joy; unsigned i; for (i = 0; i < _al_vector_size(&joysticks); i++) { slot = _al_vector_ref(&joysticks, i); joy = *slot; if (joy->config_state == LJOY_STATE_UNUSED) return joy; } joy = al_calloc(1, sizeof *joy); slot = _al_vector_alloc_back(&joysticks); *slot = joy; return joy; } static void inactivate_joy(ALLEGRO_JOYSTICK_LINUX *joy) { int i; if (joy->config_state == LJOY_STATE_UNUSED) return; joy->config_state = LJOY_STATE_UNUSED; _al_unix_stop_watching_fd(joy->fd); close(joy->fd); joy->fd = -1; for (i = 0; i < joy->parent.info.num_sticks; i++) al_free((void *)joy->parent.info.stick[i].name); for (i = 0; i < joy->parent.info.num_buttons; i++) al_free((void *)joy->parent.info.button[i].name); memset(&joy->parent.info, 0, sizeof(joy->parent.info)); memset(&joy->joystate, 0, sizeof(joy->joystate)); al_ustr_free(joy->device_name); joy->device_name = NULL; } static void set_axis_mapping(AXIS_MAPPING *map, int stick, int axis, const struct input_absinfo *absinfo) { map->stick = stick; map->axis = axis; map->min = absinfo->minimum; map->max = absinfo->maximum; map->value = absinfo->value; map->fuzz = absinfo->fuzz; map->flat = absinfo->flat; } static bool fill_joystick_axes(ALLEGRO_JOYSTICK_LINUX *joy, int fd) { unsigned long abs_bits[NLONGS(ABS_CNT)] = {0}; int stick; int axis; int name_sticks; int name_throttles; int res, i; /* Scan the axes to get their properties. */ res = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits); if (res < 0) return false; stick = 0; axis = 0; name_sticks = 0; name_throttles = 0; for (i = LJOY_AXIS_RANGE_START; i < LJOY_AXIS_RANGE_END; i++) { struct input_absinfo absinfo; if (!TEST_BIT(i, abs_bits)) continue; if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) continue; if (is_single_axis_throttle(i)) { /* One axis throttle. */ name_throttles++; joy->parent.info.stick[stick].flags = ALLEGRO_JOYFLAG_ANALOGUE; joy->parent.info.stick[stick].num_axes = 1; joy->parent.info.stick[stick].axis[0].name = "X"; joy->parent.info.stick[stick].name = al_malloc(32); snprintf((char *)joy->parent.info.stick[stick].name, 32, "Throttle %d", name_throttles); set_axis_mapping(&joy->axis_mapping[i], stick, 0, &absinfo); stick++; } else { /* Regular axis, two axis stick. */ if (axis == 0) { /* First axis of new joystick. */ name_sticks++; if (is_hat_axis(i)) { joy->parent.info.stick[stick].flags = ALLEGRO_JOYFLAG_DIGITAL; } else { joy->parent.info.stick[stick].flags = ALLEGRO_JOYFLAG_ANALOGUE; } joy->parent.info.stick[stick].num_axes = 2; joy->parent.info.stick[stick].axis[0].name = "X"; joy->parent.info.stick[stick].axis[1].name = "Y"; joy->parent.info.stick[stick].name = al_malloc(32); snprintf((char *)joy->parent.info.stick[stick].name, 32, "Stick %d", name_sticks); set_axis_mapping(&joy->axis_mapping[i], stick, axis, &absinfo); axis++; } else { /* Second axis. */ ASSERT(axis == 1); set_axis_mapping(&joy->axis_mapping[i], stick, axis, &absinfo); stick++; axis = 0; } } } joy->parent.info.num_sticks = stick; return true; } static bool fill_joystick_buttons(ALLEGRO_JOYSTICK_LINUX *joy, int fd) { unsigned long key_bits[NLONGS(KEY_CNT)] = {0}; int b; int i; if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) < 0) return false; b = 0; for (i = LJOY_BTN_RANGE_START; i < LJOY_BTN_RANGE_END; i++) { if (TEST_BIT(i, key_bits) && is_joystick_button(i)) { joy->button_mapping[b].ev_code = i; ALLEGRO_DEBUG("Input event code %d maps to button %d\n", i, b); joy->parent.info.button[b].name = al_malloc(32); snprintf((char *)joy->parent.info.button[b].name, 32, "B%d", b+1); b++; if (b == _AL_MAX_JOYSTICK_BUTTONS) break; } } joy->parent.info.num_buttons = b; /* Clear the rest. */ for (; b < _AL_MAX_JOYSTICK_BUTTONS; b++) { joy->button_mapping[b].ev_code = -1; } return true; } static void ljoy_device(ALLEGRO_USTR *device_name) { ALLEGRO_JOYSTICK_LINUX *joy = ljoy_by_device_name(device_name); if (joy) { ALLEGRO_DEBUG("Device %s still exists\n", al_cstr(device_name)); joy->marked = true; return; } /* Try to open the device. The device must be opened in O_RDWR mode to * allow writing of haptic effects! The haptic driver for linux * reuses the joystick driver's fd. */ int fd = open(al_cstr(device_name), O_RDWR|O_NONBLOCK); if (fd == -1) { ALLEGRO_WARN("Failed to open device %s\n", al_cstr(device_name)); return; } /* The device must have at least one joystick-related axis, and one * joystick-related button. Some devices, such as mouse pads, have ABS_X * and ABS_Y axes like a joystick but not joystick-related buttons. By * checking for both axes and buttons, such devices can be excluded. */ if (!have_joystick_button(fd) || !have_joystick_axis(fd)) { ALLEGRO_DEBUG("Device %s not a joystick\n", al_cstr(device_name)); close(fd); return; } ALLEGRO_DEBUG("Device %s is new\n", al_cstr(device_name)); joy = ljoy_allocate_structure(); joy->fd = fd; joy->device_name = al_ustr_dup(device_name); joy->config_state = LJOY_STATE_BORN; joy->marked = true; config_needs_merging = true; if (ioctl(fd, EVIOCGNAME(sizeof(joy->name)), joy->name) < 0) strcpy(joy->name, "Unknown"); /* Map Linux input API axis and button numbers to ours, and fill in * information. */ if (!fill_joystick_axes(joy, fd) || !fill_joystick_buttons(joy, fd)) { ALLEGRO_ERROR("fill_joystick_info failed %s\n", al_cstr(device_name)); inactivate_joy(joy); close(fd); return; } /* Register the joystick with the fdwatch subsystem. */ _al_unix_start_watching_fd(joy->fd, ljoy_process_new_data, joy); } static void ljoy_scan(bool configure) { int num; ALLEGRO_USTR *device_name; const ALLEGRO_FS_INTERFACE *fs_interface; unsigned i; int t; /* Clear mark bits. */ for (i = 0; i < _al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_LINUX **joypp = _al_vector_ref(&joysticks, i); (*joypp)->marked = false; } /* Make sure we're using stdio. */ fs_interface = al_get_fs_interface(); al_set_standard_fs_interface(); device_name = al_ustr_new(""); /* First try to read devices from allegro.cfg. */ for (num = 0; num < 32; num++) { if (!ljoy_detect_device_name(num, device_name)) continue; ljoy_device(device_name); } /* Then scan /dev/input/by-path for *-event-joystick devices and if * no device is found there scan all files in /dev/input. * Note: That last step might be overkill, we probably don't need * to support non-evdev kernels any longer. */ static char const *folders[] = {"/dev/input/by-path", "/dev/input"}; for (t = 0; t < 2; t++) { bool found = false; ALLEGRO_FS_ENTRY *dir = al_create_fs_entry(folders[t]); if (al_open_directory(dir)) { static char const *suffix = "-event-joystick"; while (true) { ALLEGRO_FS_ENTRY *dev = al_read_directory(dir); if (!dev) { break; } if (al_get_fs_entry_mode(dev) & ALLEGRO_FILEMODE_ISDIR) { al_destroy_fs_entry(dev); continue; } char const *path = al_get_fs_entry_name(dev); /* In the second pass in /dev/input we don't filter anymore. In the first pass, in /dev/input/by-path, strlen(path) > strlen(suffix). */ if (t == 1 || strcmp(suffix, path + strlen(path) - strlen(suffix)) == 0) { found = true; al_ustr_assign_cstr(device_name, path); ljoy_device(device_name); } al_destroy_fs_entry(dev); } al_close_directory(dir); } al_destroy_fs_entry(dir); if (found) { /* Don't scan the second folder if we found something in the * first as it would be duplicates. */ break; } ALLEGRO_WARN("Could not find joysticks in %s\n", folders[t]); } al_ustr_free(device_name); /* Restore the fs interface. */ al_set_fs_interface(fs_interface); /* Schedule unmarked structures to be inactivated. */ for (i = 0; i < _al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_LINUX **joypp = _al_vector_ref(&joysticks, i); ALLEGRO_JOYSTICK_LINUX *joy = *joypp; if (joy->config_state == LJOY_STATE_ALIVE && !joy->marked) { ALLEGRO_DEBUG("Device %s to be inactivated\n", al_cstr(joy->device_name)); joy->config_state = LJOY_STATE_DYING; config_needs_merging = true; } } /* Generate a configure event if necessary. * Even if we generated one before that the user hasn't responded to, * we don't know if the user received it so always generate it. */ if (config_needs_merging && configure) { ljoy_generate_configure_event(); } } static void ljoy_merge(void) { unsigned i; config_needs_merging = false; num_joysticks = 0; for (i = 0; i < _al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_LINUX **slot = _al_vector_ref(&joysticks, i); ALLEGRO_JOYSTICK_LINUX *joy = *slot; switch (joy->config_state) { case LJOY_STATE_UNUSED: break; case LJOY_STATE_BORN: case LJOY_STATE_ALIVE: joy->config_state = LJOY_STATE_ALIVE; num_joysticks++; break; case LJOY_STATE_DYING: inactivate_joy(joy); break; } } ALLEGRO_DEBUG("Merge done, num_joysticks=%d\n", num_joysticks); } #ifdef SUPPORT_HOTPLUG /* ljoy_config_dev_changed: [fdwatch thread] * Called when the /dev hierarchy changes. */ static void ljoy_config_dev_changed(void *data) { char buf[128]; (void)data; /* Empty the event buffer. We only care that some inotify event was sent but it * doesn't matter what it is since we are going to do a full scan anyway once * the timer_fd fires. */ while (read(inotify_fd, buf, sizeof(buf)) > 0) { } al_signal_cond(hotplug_cond); } static void *hotplug_proc(ALLEGRO_THREAD *thread, void *data) { (void)data; while (!al_get_thread_should_stop(thread)) { if (!hotplug_ended) { al_wait_cond(hotplug_cond, hotplug_mutex); } if (hotplug_ended) { break; } al_rest(1); al_lock_mutex(config_mutex); ljoy_scan(true); al_unlock_mutex(config_mutex); } hotplug_ended = false; return NULL; } #endif /* ljoy_init_joystick: [primary thread] * Initialise the joystick driver. */ static bool ljoy_init_joystick(void) { _al_vector_init(&joysticks, sizeof(ALLEGRO_JOYSTICK_LINUX *)); num_joysticks = 0; if (!(config_mutex = al_create_mutex())) { return false; } // Scan for joysticks ljoy_scan(false); ljoy_merge(); #ifdef SUPPORT_HOTPLUG if (!(hotplug_mutex = al_create_mutex())) { al_destroy_mutex(config_mutex); return false; } if (!(hotplug_cond = al_create_cond())) { al_destroy_mutex(config_mutex); al_destroy_mutex(hotplug_mutex); return false; } if (!(hotplug_thread = al_create_thread(hotplug_proc, NULL))) { al_destroy_mutex(config_mutex); al_destroy_mutex(hotplug_mutex); al_destroy_cond(hotplug_cond); return false; } al_start_thread(hotplug_thread); inotify_fd = inotify_init(); if (inotify_fd != -1) { fcntl(inotify_fd, F_SETFL, O_NONBLOCK); /* Modern Linux probably only needs to monitor /dev/input. */ inotify_add_watch(inotify_fd, "/dev/input", IN_CREATE|IN_DELETE); _al_unix_start_watching_fd(inotify_fd, ljoy_config_dev_changed, NULL); ALLEGRO_INFO("Hotplugging enabled\n"); } else { ALLEGRO_WARN("Hotplugging not enabled\n"); if (inotify_fd != -1) { close(inotify_fd); inotify_fd = -1; } } #endif return true; } /* ljoy_exit_joystick: [primary thread] * Shut down the joystick driver. */ static void ljoy_exit_joystick(void) { int i; #ifdef SUPPORT_HOTPLUG if (inotify_fd != -1) { _al_unix_stop_watching_fd(inotify_fd); close(inotify_fd); inotify_fd = -1; } hotplug_ended = true; al_signal_cond(hotplug_cond); al_join_thread(hotplug_thread, NULL); #endif al_destroy_mutex(config_mutex); config_mutex = NULL; for (i = 0; i < (int)_al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_LINUX **slot = _al_vector_ref(&joysticks, i); inactivate_joy(*slot); al_free(*slot); } _al_vector_free(&joysticks); num_joysticks = 0; } /* ljoy_reconfigure_joysticks: [primary thread] */ static bool ljoy_reconfigure_joysticks(void) { bool ret = false; al_lock_mutex(config_mutex); if (config_needs_merging) { ljoy_merge(); ret = true; } al_unlock_mutex(config_mutex); return ret; } /* ljoy_num_joysticks: [primary thread] * * Return the number of joysticks available on the system. */ static int ljoy_num_joysticks(void) { return num_joysticks; } /* ljoy_get_joystick: [primary thread] * * Returns the address of a ALLEGRO_JOYSTICK structure for the device * number NUM. */ static ALLEGRO_JOYSTICK *ljoy_get_joystick(int num) { ALLEGRO_JOYSTICK *ret = NULL; unsigned i; ASSERT(num >= 0); al_lock_mutex(config_mutex); for (i = 0; i < _al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_LINUX **slot = _al_vector_ref(&joysticks, i); ALLEGRO_JOYSTICK_LINUX *joy = *slot; if (ACTIVE_STATE(joy->config_state)) { if (num == 0) { ret = (ALLEGRO_JOYSTICK *)joy; break; } num--; } } al_unlock_mutex(config_mutex); return ret; } /* ljoy_release_joystick: [primary thread] * * Close the device for a joystick then free the joystick structure. */ static void ljoy_release_joystick(ALLEGRO_JOYSTICK *joy_) { (void)joy_; } /* ljoy_get_joystick_state: [primary thread] * * Copy the internal joystick state to a user-provided structure. */ static void ljoy_get_joystick_state(ALLEGRO_JOYSTICK *joy_, ALLEGRO_JOYSTICK_STATE *ret_state) { ALLEGRO_JOYSTICK_LINUX *joy = (ALLEGRO_JOYSTICK_LINUX *) joy_; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); _al_event_source_lock(es); { *ret_state = joy->joystate; } _al_event_source_unlock(es); } static const char *ljoy_get_name(ALLEGRO_JOYSTICK *joy_) { ALLEGRO_JOYSTICK_LINUX *joy = (ALLEGRO_JOYSTICK_LINUX *)joy_; return joy->name; } static bool ljoy_get_active(ALLEGRO_JOYSTICK *joy_) { ALLEGRO_JOYSTICK_LINUX *joy = (ALLEGRO_JOYSTICK_LINUX *)joy_; return ACTIVE_STATE(joy->config_state); } static int map_button_number(const ALLEGRO_JOYSTICK_LINUX *joy, int ev_code) { int b; for (b = 0; b < _AL_MAX_JOYSTICK_BUTTONS; b++) { if (joy->button_mapping[b].ev_code == ev_code) return b; } return -1; } static float norm_pos(const AXIS_MAPPING *map, float value) { const float range = (float)map->max - (float)map->min; return ((value - (float)map->min) / range) * 2.0f - 1.0f; } /* ljoy_process_new_data: [fdwatch thread] * * Process new data arriving in the joystick's fd. */ static void ljoy_process_new_data(void *data) { ALLEGRO_JOYSTICK_LINUX *joy = data; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); if (!es) { // Joystick driver not fully initialized return; } _al_event_source_lock(es); { struct input_event input_events[32]; int bytes, nr, i; while ((bytes = read(joy->fd, &input_events, sizeof input_events)) > 0) { nr = bytes / sizeof(struct input_event); for (i = 0; i < nr; i++) { int type = input_events[i].type; int code = input_events[i].code; int value = input_events[i].value; if (type == EV_KEY) { int number = map_button_number(joy, code); if (number >= 0) { if (value) joy->joystate.button[number] = 32767; else joy->joystate.button[number] = 0; ljoy_generate_button_event(joy, number, (value ? ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN : ALLEGRO_EVENT_JOYSTICK_BUTTON_UP)); } } else if (type == EV_ABS) { int number = code; if (number < TOTAL_JOYSTICK_AXES) { const AXIS_MAPPING *map = &joy->axis_mapping[number]; int stick = map->stick; int axis = map->axis; float pos = norm_pos(map, value); joy->joystate.stick[stick].axis[axis] = pos; ljoy_generate_axis_event(joy, stick, axis, pos); } } } } } _al_event_source_unlock(es); } /* ljoy_generate_axis_event: [fdwatch thread] * * Helper to generate an event after an axis is moved. * The joystick must be locked BEFORE entering this function. */ static void ljoy_generate_axis_event(ALLEGRO_JOYSTICK_LINUX *joy, int stick, int axis, float pos) { ALLEGRO_EVENT event; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); if (!_al_event_source_needs_to_generate_event(es)) return; event.joystick.type = ALLEGRO_EVENT_JOYSTICK_AXIS; event.joystick.timestamp = al_get_time(); event.joystick.id = (ALLEGRO_JOYSTICK *)joy; event.joystick.stick = stick; event.joystick.axis = axis; event.joystick.pos = pos; event.joystick.button = 0; _al_event_source_emit_event(es, &event); } /* ljoy_generate_button_event: [fdwatch thread] * * Helper to generate an event after a button is pressed or released. * The joystick must be locked BEFORE entering this function. */ static void ljoy_generate_button_event(ALLEGRO_JOYSTICK_LINUX *joy, int button, ALLEGRO_EVENT_TYPE event_type) { ALLEGRO_EVENT event; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); if (!_al_event_source_needs_to_generate_event(es)) return; event.joystick.type = event_type; event.joystick.timestamp = al_get_time(); event.joystick.id = (ALLEGRO_JOYSTICK *)joy; event.joystick.stick = 0; event.joystick.axis = 0; event.joystick.pos = 0.0; event.joystick.button = button; _al_event_source_emit_event(es, &event); } #endif /* ALLEGRO_HAVE_LINUX_INPUT_H */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/linux/lkeybdnu.c000066400000000000000000000504351473414355200173760ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Linux console keyboard driver. * * By Marek Habersack, modified by George Foot. * * Modified for the new keyboard API by Peter Wang. * * See readme.txt for copyright information. * *--- * Recommended reading: * * - "Kernel Korner: The Linux keyboard driver" by Andries E. Brouwer * http://www.linuxjournal.com/article.php?sid=1080 * * - Console Programming HOWTO * * TODO: diacriticals */ #define ALLEGRO_NO_COMPATIBILITY #include #include #include #include #include #include #include #include #include #include #include #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_driver.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/platform/aintlnx.h" #include "allegro5/platform/aintunix.h" ALLEGRO_DEBUG_CHANNEL("keyboard") #define PREFIX_I "al-ckey INFO: " #define PREFIX_W "al-ckey WARNING: " #define PREFIX_E "al-ckey ERROR: " typedef struct ALLEGRO_KEYBOARD_LINUX { ALLEGRO_KEYBOARD parent; int fd; struct termios startup_termio; struct termios work_termio; int startup_kbmode; ALLEGRO_KEYBOARD_STATE state; unsigned int modifiers; // Quit if Ctrl-Alt-Del is pressed. bool three_finger_flag; // Whether to let the LED lights if the . bool key_led_flag; } ALLEGRO_KEYBOARD_LINUX; /* the one and only keyboard object */ static ALLEGRO_KEYBOARD_LINUX the_keyboard; /* the pid to kill when three finger saluting */ static pid_t main_pid; /* forward declarations */ static bool lkeybd_init_keyboard(void); static void lkeybd_exit_keyboard(void); static ALLEGRO_KEYBOARD *lkeybd_get_keyboard(void); static bool lkeybd_set_keyboard_leds(int leds); static void lkeybd_get_keyboard_state(ALLEGRO_KEYBOARD_STATE *ret_state); static void lkeybd_clear_keyboard_state(void); static void process_new_data(void *unused); static void process_character(unsigned char ch); static void handle_key_press(int mycode, unsigned int ascii); static void handle_key_release(int mycode); /* the driver vtable */ #define KEYDRV_LINUX AL_ID('L','N','X','C') static ALLEGRO_KEYBOARD_DRIVER keydrv_linux = { KEYDRV_LINUX, "", "", "Linux console keyboard", lkeybd_init_keyboard, lkeybd_exit_keyboard, lkeybd_get_keyboard, lkeybd_set_keyboard_leds, NULL, /* const char *keycode_to_name(int keycode) */ lkeybd_get_keyboard_state, lkeybd_clear_keyboard_state }; /* list the available drivers */ _AL_DRIVER_INFO _al_linux_keyboard_driver_list[] = { { KEYDRV_LINUX, &keydrv_linux, true }, { 0, NULL, 0 } }; /* * Various ugly things. */ #define KB_MODIFIERS (ALLEGRO_KEYMOD_SHIFT | ALLEGRO_KEYMOD_CTRL | ALLEGRO_KEYMOD_ALT | \ ALLEGRO_KEYMOD_ALTGR | ALLEGRO_KEYMOD_LWIN | ALLEGRO_KEYMOD_RWIN | \ ALLEGRO_KEYMOD_MENU) #define KB_LED_FLAGS (ALLEGRO_KEYMOD_SCROLLLOCK | ALLEGRO_KEYMOD_NUMLOCK | \ ALLEGRO_KEYMOD_CAPSLOCK) /* lookup table for converting kernel keycodes into Allegro format */ static unsigned char kernel_to_mycode[128] = { /* 0x00 */ 0, ALLEGRO_KEY_ESCAPE, ALLEGRO_KEY_1, ALLEGRO_KEY_2, /* 0x04 */ ALLEGRO_KEY_3, ALLEGRO_KEY_4, ALLEGRO_KEY_5, ALLEGRO_KEY_6, /* 0x08 */ ALLEGRO_KEY_7, ALLEGRO_KEY_8, ALLEGRO_KEY_9, ALLEGRO_KEY_0, /* 0x0C */ ALLEGRO_KEY_MINUS, ALLEGRO_KEY_EQUALS, ALLEGRO_KEY_BACKSPACE, ALLEGRO_KEY_TAB, /* 0x10 */ ALLEGRO_KEY_Q, ALLEGRO_KEY_W, ALLEGRO_KEY_E, ALLEGRO_KEY_R, /* 0x14 */ ALLEGRO_KEY_T, ALLEGRO_KEY_Y, ALLEGRO_KEY_U, ALLEGRO_KEY_I, /* 0x18 */ ALLEGRO_KEY_O, ALLEGRO_KEY_P, ALLEGRO_KEY_OPENBRACE, ALLEGRO_KEY_CLOSEBRACE, /* 0x1C */ ALLEGRO_KEY_ENTER, ALLEGRO_KEY_LCTRL, ALLEGRO_KEY_A, ALLEGRO_KEY_S, /* 0x20 */ ALLEGRO_KEY_D, ALLEGRO_KEY_F, ALLEGRO_KEY_G, ALLEGRO_KEY_H, /* 0x24 */ ALLEGRO_KEY_J, ALLEGRO_KEY_K, ALLEGRO_KEY_L, ALLEGRO_KEY_SEMICOLON, /* 0x28 */ ALLEGRO_KEY_QUOTE, ALLEGRO_KEY_TILDE, ALLEGRO_KEY_LSHIFT, ALLEGRO_KEY_BACKSLASH, /* 0x2C */ ALLEGRO_KEY_Z, ALLEGRO_KEY_X, ALLEGRO_KEY_C, ALLEGRO_KEY_V, /* 0x30 */ ALLEGRO_KEY_B, ALLEGRO_KEY_N, ALLEGRO_KEY_M, ALLEGRO_KEY_COMMA, /* 0x34 */ ALLEGRO_KEY_FULLSTOP, ALLEGRO_KEY_SLASH, ALLEGRO_KEY_RSHIFT, ALLEGRO_KEY_PAD_ASTERISK, /* 0x38 */ ALLEGRO_KEY_ALT, ALLEGRO_KEY_SPACE, ALLEGRO_KEY_CAPSLOCK, ALLEGRO_KEY_F1, /* 0x3C */ ALLEGRO_KEY_F2, ALLEGRO_KEY_F3, ALLEGRO_KEY_F4, ALLEGRO_KEY_F5, /* 0x40 */ ALLEGRO_KEY_F6, ALLEGRO_KEY_F7, ALLEGRO_KEY_F8, ALLEGRO_KEY_F9, /* 0x44 */ ALLEGRO_KEY_F10, ALLEGRO_KEY_NUMLOCK, ALLEGRO_KEY_SCROLLLOCK, ALLEGRO_KEY_PAD_7, /* 0x48 */ ALLEGRO_KEY_PAD_8, ALLEGRO_KEY_PAD_9, ALLEGRO_KEY_PAD_MINUS, ALLEGRO_KEY_PAD_4, /* 0x4C */ ALLEGRO_KEY_PAD_5, ALLEGRO_KEY_PAD_6, ALLEGRO_KEY_PAD_PLUS, ALLEGRO_KEY_PAD_1, /* 0x50 */ ALLEGRO_KEY_PAD_2, ALLEGRO_KEY_PAD_3, ALLEGRO_KEY_PAD_0, ALLEGRO_KEY_PAD_DELETE, /* 0x54 */ ALLEGRO_KEY_PRINTSCREEN, 0, ALLEGRO_KEY_BACKSLASH2, ALLEGRO_KEY_F11, /* 0x58 */ ALLEGRO_KEY_F12, 0, 0, 0, /* 0x5C */ 0, 0, 0, 0, /* 0x60 */ ALLEGRO_KEY_PAD_ENTER, ALLEGRO_KEY_RCTRL, ALLEGRO_KEY_PAD_SLASH, ALLEGRO_KEY_PRINTSCREEN, /* 0x64 */ ALLEGRO_KEY_ALTGR, ALLEGRO_KEY_PAUSE, ALLEGRO_KEY_HOME, ALLEGRO_KEY_UP, /* 0x68 */ ALLEGRO_KEY_PGUP, ALLEGRO_KEY_LEFT, ALLEGRO_KEY_RIGHT, ALLEGRO_KEY_END, /* 0x6C */ ALLEGRO_KEY_DOWN, ALLEGRO_KEY_PGDN, ALLEGRO_KEY_INSERT, ALLEGRO_KEY_DELETE, /* 0x70 */ 0, 0, 0, 0, /* 0x74 */ 0, 0, 0, ALLEGRO_KEY_PAUSE, /* 0x78 */ 0, 0, 0, 0, /* 0x7C */ 0, ALLEGRO_KEY_LWIN, ALLEGRO_KEY_RWIN, ALLEGRO_KEY_MENU /* "Two keys are unusual in the sense that their keycode is not constant, * but depends on modifiers. The PrintScrn key will yield keycode 84 when * combined with either Alt key, but keycode 99 otherwise. The Pause key * will yield keycode 101 when combined with either Ctrl key, but keycode * 119 otherwise. (This has historic reasons, but might change, to free * keycodes 99 and 119 for other purposes.)" */ }; /* convert kernel keycodes for numpad keys into ASCII characters */ #define NUM_PAD_KEYS 17 static const char pad_asciis[NUM_PAD_KEYS] = { '0','1','2','3','4','5','6','7','8','9', '+','-','*','/','\r',',','.' }; static const char pad_asciis_no_numlock[NUM_PAD_KEYS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '+', '-', '*', '/', '\r', 0, 0 }; /* convert Allegro format keycodes into ALLEGRO_KEYMOD_* */ static const unsigned int modifier_table[ALLEGRO_KEY_MAX - ALLEGRO_KEY_MODIFIERS] = { ALLEGRO_KEYMOD_SHIFT, ALLEGRO_KEYMOD_SHIFT, ALLEGRO_KEYMOD_CTRL, ALLEGRO_KEYMOD_CTRL, ALLEGRO_KEYMOD_ALT, ALLEGRO_KEYMOD_ALTGR, ALLEGRO_KEYMOD_LWIN, ALLEGRO_KEYMOD_RWIN, ALLEGRO_KEYMOD_MENU, ALLEGRO_KEYMOD_SCROLLLOCK, ALLEGRO_KEYMOD_NUMLOCK, ALLEGRO_KEYMOD_CAPSLOCK }; /* keycode_to_char: [fdwatch thread] * Helper function. * KEYCODE is a Linux kernel keycode, not an Allegro keycode. * * In the process of doing the translation, we may find that the user * has pressed a key that for VT switching. In that case a negative * number is returned, the absolute value of which is the VT to * switch to. Yes, ugly. */ static int keycode_to_char(int keycode) { const unsigned int modifiers = the_keyboard.modifiers; struct kbentry kbe; int keymap; int ascii; /* build kernel keymap number */ keymap = 0; if (modifiers & ALLEGRO_KEYMOD_SHIFT) keymap |= 1; if (modifiers & ALLEGRO_KEYMOD_ALTGR) keymap |= 2; if (modifiers & ALLEGRO_KEYMOD_CTRL) keymap |= 4; if (modifiers & ALLEGRO_KEYMOD_ALT) keymap |= 8; /* map keycode to type and value */ kbe.kb_table = keymap; kbe.kb_index = keycode; ioctl(the_keyboard.fd, KDGKBENT, &kbe); if (keycode == KEY_BACKSPACE) ascii = 8; else { if (kbe.kb_value == K_NOSUCHMAP) { /* invalid keymaps */ /* FIXME: Maybe we should just redo the */ /* ioctl with keymap 0? */ ascii = 0; } else { /* most keys come here */ ascii = KVAL(kbe.kb_value); } } /* finally do some things based on key type */ switch (KTYP(kbe.kb_value)) { case KT_CONS: /* VT switch key -- return a negative number */ return -( KVAL(kbe.kb_value)+1 ); case KT_LETTER: /* apply capslock translation. */ if (modifiers & ALLEGRO_KEYMOD_CAPSLOCK) return ascii ^ 0x20; else return ascii; case KT_LATIN: case KT_ASCII: return ascii; case KT_PAD: { int val = KVAL(kbe.kb_value); if (modifiers & ALLEGRO_KEYMOD_NUMLOCK) { if ((val >= 0) && (val < NUM_PAD_KEYS)) ascii = pad_asciis[val]; } else { if ((val >= 0) && (val < NUM_PAD_KEYS)) ascii = pad_asciis_no_numlock[val]; } return ascii; } case KT_SPEC: if (keycode == KEY_ENTER) return '\r'; else return 0; default: /* dunno */ return 0; } } /* lkeybd_init_keyboard: [primary thread] * Initialise the keyboard driver. */ static bool lkeybd_init_keyboard(void) { bool can_restore_termio_and_kbmode = false; memset(&the_keyboard, 0, sizeof the_keyboard); /* if (__al_linux_use_console()) return false; */ the_keyboard.fd = open("/dev/tty", O_RDWR); /* Save the current terminal attributes, which we will restore when * we close up shop. */ if (tcgetattr(the_keyboard.fd, &the_keyboard.startup_termio) != 0) { goto Error; } /* Save previous keyboard mode (probably XLATE). */ if (ioctl(the_keyboard.fd, KDGKBMODE, &the_keyboard.startup_kbmode) != 0) { //goto Error; } can_restore_termio_and_kbmode = false; /* Set terminal attributes we need. * * Input modes (c_iflag): We want to disable: * - stripping bytes to 7 bits * - ignoring of carriage returns * - translating of carriage returns to newlines, and vice versa * - start/stop control on input and output * * Control modes (c_cflag): We want 8 bits per byte. * * Local modes (c_lflag: We want to disable: * - canonical (line by line) input * - echoing input back to the display * - interpretation of signal characters * * The c_iflag, c_lflag settings come from svgalib. Allegro 4 * simply set them to 0, which is a bit crude. */ the_keyboard.work_termio = the_keyboard.startup_termio; the_keyboard.work_termio.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); the_keyboard.work_termio.c_cflag &= ~CSIZE; the_keyboard.work_termio.c_cflag |= CS8; the_keyboard.work_termio.c_lflag &= ~(ICANON | ECHO | ISIG); if (tcsetattr(the_keyboard.fd, TCSANOW, &the_keyboard.work_termio) != 0) { goto Error; } /* Set the keyboard mode to mediumraw. */ if (ioctl(the_keyboard.fd, KDSKBMODE, K_MEDIUMRAW) != 0) { //goto Error; } the_keyboard.three_finger_flag = true; the_keyboard.key_led_flag = true; const char *value = al_get_config_value(al_get_system_config(), "keyboard", "enable_three_finger_exit"); if (value) { the_keyboard.three_finger_flag = !strncmp(value, "true", 4); } value = al_get_config_value(al_get_system_config(), "keyboard", "enable_key_led_toggle"); if (value) { the_keyboard.key_led_flag = !strncmp(value, "true", 4); } ALLEGRO_DEBUG("Three finger flag enabled: %s\n", the_keyboard.three_finger_flag ? "true" : "false"); ALLEGRO_DEBUG("Key LED toggle enabled: %s\n", the_keyboard.key_led_flag ? "true" : "false"); /* Initialise the keyboard object for use as an event source. */ _al_event_source_init(&the_keyboard.parent.es); /* Start watching for data on the fd. */ _al_unix_start_watching_fd(the_keyboard.fd, process_new_data, NULL); /* Get the pid, which we use for the three finger salute */ main_pid = getpid(); return true; Error: if (can_restore_termio_and_kbmode) { tcsetattr(the_keyboard.fd, TCSANOW, &the_keyboard.startup_termio); ioctl(the_keyboard.fd, KDSKBMODE, the_keyboard.startup_kbmode); } close(the_keyboard.fd); /* __al_linux_leave_console(); */ return false; } /* lkeybd_exit_keyboard: [primary thread] * Shut down the keyboard driver. */ static void lkeybd_exit_keyboard(void) { _al_unix_stop_watching_fd(the_keyboard.fd); _al_event_source_free(&the_keyboard.parent.es); /* Restore terminal attrs, keyboard mode, and reset the LED mode. */ tcsetattr(the_keyboard.fd, TCSANOW, &the_keyboard.startup_termio); ioctl(the_keyboard.fd, KDSKBMODE, the_keyboard.startup_kbmode); ioctl(the_keyboard.fd, KDSETLED, 8); close(the_keyboard.fd); //__al_linux_leave_console(); /* This may help catch bugs in the user program, since the pointer * we return to the user is always the same. */ memset(&the_keyboard, 0, sizeof the_keyboard); } /* lkeybd_get_keyboard: * Returns the address of a ALLEGRO_KEYBOARD structure representing the keyboard. */ static ALLEGRO_KEYBOARD *lkeybd_get_keyboard(void) { return (ALLEGRO_KEYBOARD *)&the_keyboard; } /* lkeybd_set_keyboard_leds: * Updates the LED state. */ static bool lkeybd_set_keyboard_leds(int leds) { int val = 0; if (leds & ALLEGRO_KEYMOD_SCROLLLOCK) val |= LED_SCR; if (leds & ALLEGRO_KEYMOD_NUMLOCK) val |= LED_NUM; if (leds & ALLEGRO_KEYMOD_CAPSLOCK) val |= LED_CAP; return (ioctl(the_keyboard.fd, KDSETLED, val) == 0) ? true : false; } /* lkeybd_get_keyboard_state: [primary thread] * Copy the current keyboard state into RET_STATE, with any necessary locking. */ static void lkeybd_get_keyboard_state(ALLEGRO_KEYBOARD_STATE *ret_state) { _al_event_source_lock(&the_keyboard.parent.es); { *ret_state = the_keyboard.state; } _al_event_source_unlock(&the_keyboard.parent.es); } /* lkeybd_clear_keyboard_state: [primary thread] * Clear the current keyboard state, with any necessary locking. */ static void lkeybd_clear_keyboard_state(void) { _al_event_source_lock(&the_keyboard.parent.es); { memset(&the_keyboard.state, 0, sizeof(the_keyboard.state)); } _al_event_source_unlock(&the_keyboard.parent.es); } /* process_new_data: [fdwatch thread] * Process new data arriving in the keyboard's fd. */ static void process_new_data(void *unused) { _al_event_source_lock(&the_keyboard.parent.es); { unsigned char buf[128]; size_t bytes_read; unsigned int ch; bytes_read = read(the_keyboard.fd, &buf, sizeof(buf)); for (ch = 0; ch < bytes_read; ch++) process_character(buf[ch]); } _al_event_source_unlock(&the_keyboard.parent.es); (void)unused; } /* process_character: [fdwatch thread] * This is where most of the work gets done. CH is a byte read in * from the keyboard's fd. This function finds the Allegro equivalent * of that key code, figures out which ASCII character that key * generates (if any), and then calls the handle_key_press() and * handle_key_release() functions with that information. It also does * some things with modifier keys. */ static void process_character(unsigned char ch) { /* read kernel's keycode and convert to Allegro's keycode */ int keycode = ch & 0x7f; bool press = !(ch & 0x80); int mycode = kernel_to_mycode[keycode]; /* if the key was something weird we don't understand, skip it */ if (mycode == 0) return; /* process modifiers */ if (mycode >= ALLEGRO_KEY_MODIFIERS) { int flag = modifier_table[mycode - ALLEGRO_KEY_MODIFIERS]; if (press) { if (flag & KB_MODIFIERS) the_keyboard.modifiers |= flag; else if ((flag & KB_LED_FLAGS) && the_keyboard.key_led_flag) the_keyboard.modifiers ^= flag; } else { /* XXX: if the user presses LCTRL, then RCTRL, then releases * LCTRL, the ALLEGRO_KEYMOD_CTRL modifier should still be on. */ if (flag & KB_MODIFIERS) the_keyboard.modifiers &= ~flag; } } /* call the handlers */ if (press) { int ascii = keycode_to_char(keycode); /* switch VT if the user requested so */ if (ascii < 0) { int console = -ascii; int last_console; ioctl(the_keyboard.fd, VT_OPENQRY, &last_console); if (console < last_console) if (ioctl(the_keyboard.fd, VT_ACTIVATE, console) == 0) return; } handle_key_press(mycode, ascii); } else { handle_key_release(mycode); } /* three-finger salute for killing the program */ if ((the_keyboard.three_finger_flag) && ((mycode == ALLEGRO_KEY_DELETE) || (mycode == ALLEGRO_KEY_END)) && (the_keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) && (the_keyboard.modifiers & ALLEGRO_KEYMOD_ALT)) { kill(main_pid, SIGTERM); } } /* handle_key_press: [fdwatch thread] * Helper: stuff to do when a key is pressed. */ static void handle_key_press(int mycode, unsigned int ascii) { ALLEGRO_EVENT_TYPE event_type; ALLEGRO_EVENT event; event_type = (_AL_KEYBOARD_STATE_KEY_DOWN(the_keyboard.state, mycode) ? ALLEGRO_EVENT_KEY_CHAR : ALLEGRO_EVENT_KEY_DOWN); /* Maintain the key_down array. */ _AL_KEYBOARD_STATE_SET_KEY_DOWN(the_keyboard.state, mycode); /* Generate key press/repeat events if necessary. */ if (!_al_event_source_needs_to_generate_event(&the_keyboard.parent.es)) return; event.keyboard.type = event_type; event.keyboard.timestamp = al_get_time(); event.keyboard.display = NULL; event.keyboard.keycode = mycode; event.keyboard.unichar = ascii; event.keyboard.modifiers = the_keyboard.modifiers; _al_event_source_emit_event(&the_keyboard.parent.es, &event); /* The first press should generate a KEY_CHAR also */ if (event_type == ALLEGRO_EVENT_KEY_DOWN) { event.keyboard.type = ALLEGRO_EVENT_KEY_CHAR; event.keyboard.timestamp = al_get_time(); _al_event_source_emit_event(&the_keyboard.parent.es, &event); } } /* handle_key_release: [fdwatch thread] * Helper: stuff to do when a key is released. */ static void handle_key_release(int mycode) { ALLEGRO_EVENT event; /* This can happen, e.g. when we are switching back into a VT with * ALT+Fn, we only get the release event of the function key. */ if (!_AL_KEYBOARD_STATE_KEY_DOWN(the_keyboard.state, mycode)) return; /* Maintain the key_down array. */ _AL_KEYBOARD_STATE_CLEAR_KEY_DOWN(the_keyboard.state, mycode); /* Generate key release events if necessary. */ if (!_al_event_source_needs_to_generate_event(&the_keyboard.parent.es)) return; event.keyboard.type = ALLEGRO_EVENT_KEY_UP; event.keyboard.timestamp = al_get_time(); event.keyboard.display = NULL; event.keyboard.keycode = mycode; event.keyboard.unichar = 0; event.keyboard.modifiers = the_keyboard.modifiers; _al_event_source_emit_event(&the_keyboard.parent.es, &event); } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ allegro5-5.2.10.1/src/linux/lmsedrv.c000066400000000000000000000032571473414355200172350ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Linux console mouse driver list. * * By George Foot. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_driver.h" #include "allegro5/platform/aintunix.h" #include "allegro5/platform/aintlnx.h" #ifdef ALLEGRO_RASPBERRYPI #include "allegro5/internal/aintern_raspberrypi.h" #endif /* list the available drivers */ _AL_DRIVER_INFO _al_linux_mouse_driver_list[] = { /* These drivers have not been updated for the new mouse API. * They may be updated as required, although the evdev driver * should be fine on modern kernels --pw */ /* { MOUSEDRV_LINUX_GPMDATA, &mousedrv_linux_gpmdata, true },*/ /* { MOUSEDRV_LINUX_MS, &mousedrv_linux_ms, true },*/ /* { MOUSEDRV_LINUX_IMS, &mousedrv_linux_ims, true },*/ /* { MOUSEDRV_LINUX_PS2, &mousedrv_linux_ps2, true },*/ /* { MOUSEDRV_LINUX_IPS2, &mousedrv_linux_ips2, true },*/ #if defined ALLEGRO_HAVE_LINUX_INPUT_H || defined ALLEGRO_RASPBERRYPI { AL_MOUSEDRV_LINUX_EVDEV, &_al_mousedrv_linux_evdev, true }, #endif { 0, NULL, 0 } }; allegro5-5.2.10.1/src/linux/lmseev.c000066400000000000000000000500401473414355200170440ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Linux console mouse driver for event interface (EVDEV). * * By Annie Testes. * * Handles all inputs that fill evdev with informations * about movement and click. * * Hacked for new mouse API by Peter Wang. * * See readme.txt for copyright information. */ #define ALLEGRO_NO_COMPATIBILITY #include "allegro5/allegro.h" #ifdef ALLEGRO_HAVE_LINUX_INPUT_H ALLEGRO_DEBUG_CHANNEL("lmseev"); #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_mouse.h" #include "allegro5/platform/aintunix.h" #include "allegro5/platform/aintlnx.h" #ifdef ALLEGRO_RASPBERRYPI #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_vector.h" #endif #include #include #include #include #define PREFIX_I "al-evdev INFO: " #define PREFIX_W "al-evdev WARNING: " #define PREFIX_E "al-evdev ERROR: " typedef struct AL_MOUSE_EVDEV { ALLEGRO_MOUSE parent; int fd; ALLEGRO_MOUSE_STATE state; } AL_MOUSE_EVDEV; /* the one and only mouse object */ static AL_MOUSE_EVDEV the_mouse; /* forward declarations */ static void process_new_data(void *unused); static void process_event(struct input_event *event); static void handle_button_event(unsigned int button, bool is_down); static void handle_axis_event(int dx, int dy, int dz); static void generate_mouse_event(unsigned int type, int x, int y, int z, int dx, int dy, int dz, unsigned int button); bool _al_evdev_set_mouse_range(int x1, int y1, int x2, int y2); /* * Tools data */ /* Tool mode * This mode is the behavior the user sees, it is not the way the device * reports the position. * Tools that send relative informations can only be in relative mode, * tools that send absolute informations can be either in absolute mode or in * relative mode */ typedef enum { MODE_RELATIVE, MODE_ABSOLUTE } MODE; typedef struct TOOL { int tool_id; /* One of the BTN_TOOL_... from linux/input.h */ MODE mode; /* Relative or absolute */ } TOOL; static TOOL tools[] = { { BTN_TOOL_MOUSE, MODE_RELATIVE }, { BTN_TOOL_PEN, MODE_ABSOLUTE }, { BTN_TOOL_RUBBER, MODE_ABSOLUTE }, { BTN_TOOL_BRUSH, MODE_ABSOLUTE }, { BTN_TOOL_PENCIL, MODE_ABSOLUTE }, { BTN_TOOL_AIRBRUSH, MODE_ABSOLUTE }, { BTN_TOOL_FINGER, MODE_ABSOLUTE }, { BTN_TOOL_LENS, MODE_ABSOLUTE }, { -1, MODE_ABSOLUTE } /* No tool */ }; /* Default tool, in case the device does not send a tool id */ static TOOL *default_tool = tools + 0; static TOOL *no_tool = tools + (sizeof(tools)/sizeof(tools[0]) - 1); static TOOL *current_tool; /* find_tool: * Returns the tool with id 'tool_id' which is one of the BTN_TOOL_... defined * in linux/input.h. Returns 'default_tool' if not found. */ static TOOL *find_tool(int tool_id) { TOOL *t; for (t=tools; t!=no_tool; t++) { if (t->tool_id == tool_id) return t; } return default_tool; } /* * Pointer axis */ typedef struct AXIS { int in_min; /* For absolute mode */ int in_max; /* For absolute mode */ int out_min; /* For absolute mode */ int out_max; /* For absolute mode */ float speed; /* For set_mouse_speed */ int mickeys; /* For get_mouse_mickeys */ float scale; /* Scale factor, because tablet mice generate more movement than common mice */ int in_abs; /* Current absolute position, used for absolute input, whether the output is absolute or relative */ int out_abs; /* Position on the screen */ } AXIS; #define IN_RANGE(axis) ( (axis).in_max-(axis).in_min+1 ) #define OUT_RANGE(axis) ( (axis).out_max-(axis).out_min+1 ) /* in_to_screen: * maps an input absolute position to a screen position */ static int in_to_screen(const AXIS *axis, int v) { return (((v-axis->in_min) * OUT_RANGE(*axis)) / IN_RANGE(*axis)) + axis->out_min; } /* rel_event: * returns the new screen position, given the input relative one. * The tool mode is always relative */ static int rel_event(AXIS *axis, int v) { /* When input only send relative events, the mode is always relative */ int ret = axis->out_abs + v*axis->speed; axis->mickeys += v; axis->in_abs += v; return ret; } /* abs_event: * returns the new screen position, given the input absolute one, * and depending on the tool mode */ static int abs_event(AXIS *axis, MODE mode, int v) { if (mode == MODE_ABSOLUTE) { axis->mickeys = 0; /* No mickeys in absolute mode */ axis->in_abs = v; return in_to_screen(axis, v); } else { /* Input is absolute, but tool is relative */ int value = (v-axis->in_abs)*axis->scale; axis->mickeys += value; axis->in_abs = v; return axis->out_abs + value*axis->speed; } } /* get_axis_value: * returns the input absolute position */ static void get_axis_value(int fd, AXIS *axis, int type) { int abs[5]; int ret = ioctl(fd, EVIOCGABS(type), abs); if (ret>=0) { axis->in_abs = abs[0]; } } /* has_event: * returns true if the device generates the event */ static int has_event(int fd, unsigned short type, unsigned short code) { const unsigned int len = sizeof(unsigned long)*8; const unsigned int max = _ALLEGRO_MAX(EV_MAX, _ALLEGRO_MAX(KEY_MAX, _ALLEGRO_MAX(REL_MAX, _ALLEGRO_MAX(ABS_MAX, _ALLEGRO_MAX(LED_MAX, _ALLEGRO_MAX(SND_MAX, FF_MAX)))))); unsigned long bits[(max+len-1)/len]; if (ioctl(fd, EVIOCGBIT(type, max), bits)) { return (bits[code/len] >> (code%len)) & 1; } return 0; } /* get_num_buttons: * return the number of buttons */ static int get_num_buttons(int fd) { if (has_event(fd, EV_KEY, BTN_MIDDLE)) return 3; if (has_event(fd, EV_KEY, BTN_RIGHT)) return 2; if (has_event(fd, EV_KEY, BTN_MOUSE)) return 1; return 0; /* Not a mouse */ } /* The three axis: horizontal, vertical and wheel */ static AXIS x_axis; static AXIS y_axis; static AXIS z_axis; /* * Initialization functions */ /* init_axis: * initialize an AXIS structure, from the device and the config file */ static void init_axis(int fd, AXIS *axis, const char *name, const char *section, int type) { #if 0 char tmp1[256]; /* config string */ char tmp2[256]; /* format string */ char tmp3[256]; /* Converted 'name' */ #endif int abs[5]; /* values given by the input */ int config_speed; (void)name; (void)section; config_speed = 1; axis->scale = 1; /* Ask the input */ if (ioctl(fd, EVIOCGABS(type), abs)>=0) { if (axis->in_min==0) axis->in_min=abs[1]; if (axis->in_max==0) axis->in_max=abs[2]; axis->in_abs = abs[0]; axis->scale = 320.0*config_speed/IN_RANGE(*axis); } if (axis->in_min>axis->in_max) { axis->in_min = axis->in_max = 0; axis->scale = 1; } axis->out_min = INT_MIN; axis->out_max = INT_MAX; axis->speed = 1; axis->mickeys = 0; } /* init_tablet: * initialize the tools and axis */ static void init_tablet(int fd) { int default_abs = default_tool->mode==MODE_ABSOLUTE; if (default_abs) { default_tool->mode = MODE_ABSOLUTE; } else { default_tool->mode = MODE_RELATIVE; } init_axis(fd, &x_axis, "x", "mouse", ABS_X); init_axis(fd, &y_axis, "y", "mouse", ABS_Y); init_axis(fd, &z_axis, "z", "mouse", ABS_Z); } /* * Process input functions */ /* process_key: [fdwatch thread] * process events of type key (button clicks and vicinity events are currently * supported) */ static void process_key(const struct input_event *event) { switch (event->code) { /* Buttons click * if event->value is 1 the button has just been pressed * if event->value is 0 the button has just been released */ case BTN_LEFT: /* Mouse */ case BTN_TOUCH: /* Stylus */ handle_button_event(1, event->value); break; case BTN_RIGHT: /* Mouse */ case BTN_STYLUS: /* Stylus */ handle_button_event(2, event->value); break; case BTN_MIDDLE: /* Mouse */ case BTN_STYLUS2: /* Stylus */ handle_button_event(3, event->value); break; /* Vicinity events * if event->value is 1, the tool enters the tablet vicinity * if event->value is 0, the tool leaves the tablet vicinity */ case BTN_TOOL_MOUSE: case BTN_TOOL_PEN: case BTN_TOOL_RUBBER: case BTN_TOOL_BRUSH: case BTN_TOOL_PENCIL: case BTN_TOOL_AIRBRUSH: case BTN_TOOL_FINGER: case BTN_TOOL_LENS: if (event->value) { current_tool = find_tool(event->code); get_axis_value(the_mouse.fd, &x_axis, ABS_X); get_axis_value(the_mouse.fd, &y_axis, ABS_Y); get_axis_value(the_mouse.fd, &z_axis, ABS_Z); #ifdef ABS_WHEEL /* absent in 2.2.x */ get_axis_value(the_mouse.fd, &z_axis, ABS_WHEEL); #endif } else { current_tool = no_tool; } break; } } /* [fdwatch thread] */ static void handle_button_event(unsigned int button, bool is_down) { unsigned int event_type; if (is_down) { the_mouse.state.buttons |= (1 << (button-1)); event_type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN; } else { the_mouse.state.buttons &=~ (1 << (button-1)); event_type = ALLEGRO_EVENT_MOUSE_BUTTON_UP; } generate_mouse_event( event_type, the_mouse.state.x, the_mouse.state.y, the_mouse.state.z, 0, 0, 0, button); } /* process_rel: [fdwatch thread] * process relative events (x, y and z movement are currently supported) */ static void process_rel(const struct input_event *event) { /* The device can send a report when there's no tool */ if (current_tool!=no_tool) { switch (event->code) { case REL_X: x_axis.out_abs = rel_event(&x_axis, event->value); handle_axis_event(x_axis.mickeys, 0, 0); x_axis.mickeys = 0; break; case REL_Y: y_axis.out_abs = rel_event(&y_axis, event->value); handle_axis_event(0, y_axis.mickeys, 0); y_axis.mickeys = 0; break; #ifdef REL_WHEEL /* absent in 2.2.x */ case REL_WHEEL: #endif case REL_Z: z_axis.out_abs = rel_event(&z_axis, event->value); handle_axis_event(0, 0, z_axis.mickeys); z_axis.mickeys = 0; break; } } } /* process_abs: [fdwatch thread] * process absolute events (x, y and z movement are currently supported) * TODO: missing handle_axis_event calls */ static void process_abs(const struct input_event *event) { /* The device can send a report when there's no tool */ if (current_tool!=no_tool) { switch (event->code) { case ABS_X: x_axis.out_abs = abs_event(&x_axis, current_tool->mode, event->value); break; case ABS_Y: y_axis.out_abs = abs_event(&y_axis, current_tool->mode, event->value); break; #ifdef ABS_WHEEL /* absent in 2.2.x */ case ABS_WHEEL: #endif case ABS_Z: z_axis.out_abs = abs_event(&z_axis, current_tool->mode, event->value); break; } } } /* [fdwatch thread] */ static void handle_axis_event(int dx, int dy, int dz) { if (current_tool != no_tool) { x_axis.out_abs = _ALLEGRO_CLAMP(x_axis.out_min, x_axis.out_abs, x_axis.out_max); y_axis.out_abs = _ALLEGRO_CLAMP(y_axis.out_min, y_axis.out_abs, y_axis.out_max); /* There's no range for z */ the_mouse.state.x = x_axis.out_abs; the_mouse.state.y = y_axis.out_abs; the_mouse.state.z = z_axis.out_abs * al_get_mouse_wheel_precision(); dz *= al_get_mouse_wheel_precision(); generate_mouse_event( ALLEGRO_EVENT_MOUSE_AXES, the_mouse.state.x, the_mouse.state.y, the_mouse.state.z, dx, dy, dz, 0); } } /* open_mouse_device: * Open the specified device file and check that it is a mouse device. * Returns the file descriptor if successful or a negative number on error. */ static int open_mouse_device (const char *device_file) { int fd; fd = open (device_file, O_RDONLY | O_NONBLOCK); if (fd >= 0) { ALLEGRO_DEBUG("Opened device %s\n", device_file); /* The device is a mouse if it has a BTN_MOUSE */ if (has_event(fd, EV_KEY, BTN_MOUSE)) { ALLEGRO_DEBUG("Device %s was a mouse.\n", device_file); } else { ALLEGRO_DEBUG("Device %s was not mouse, closing.\n", device_file); close(fd); fd = -1; } } return fd; } /* mouse_init: * Here we open the mouse device, initialise anything that needs it, * and chain to the framework init routine. */ static bool mouse_init (void) { /* char tmp1[128], tmp2[128]; const char *udevice; */ /* Set the current tool */ current_tool = default_tool; /* try several /dev/input/event * devices. */ const char *device_name[] = { "/dev/input/event0", "/dev/input/event1", "/dev/input/event2", "/dev/input/event3", NULL }; int i; ALLEGRO_DEBUG("Trying /dev/input/event[0-3] devices\n"); for (i=0; device_name[i]; i++) { the_mouse.fd = open_mouse_device (device_name[i]); if (the_mouse.fd >= 0) break; } if (!device_name[i]) { return false; } /* Init the tablet data */ init_tablet(the_mouse.fd); /* Initialise the mouse object for use as an event source. */ _al_event_source_init(&the_mouse.parent.es); /* Start watching for data on the fd. */ _al_unix_start_watching_fd(the_mouse.fd, process_new_data, &the_mouse); return true; } /* mouse_exit: * Chain to the framework, then uninitialise things. */ static void mouse_exit (void) { _al_unix_stop_watching_fd(the_mouse.fd); _al_event_source_free(&the_mouse.parent.es); close(the_mouse.fd); /* This may help catch bugs in the user program, since the pointer * we return to the user is always the same. */ memset(&the_mouse, 0, sizeof the_mouse); the_mouse.fd = -1; } /* mouse_get_mouse: * Returns the address of a ALLEGRO_MOUSE structure representing the mouse. */ static ALLEGRO_MOUSE *mouse_get_mouse(void) { return (ALLEGRO_MOUSE *)&the_mouse; } /* mouse_get_mouse_num_buttons: * Return the number of buttons on the mouse. */ static unsigned int mouse_get_mouse_num_buttons(void) { ASSERT(the_mouse.fd >= 0); return get_num_buttons(the_mouse.fd); } /* mouse_get_mouse_num_axes: * Return the number of axes on the mouse. */ static unsigned int mouse_get_mouse_num_axes(void) { ASSERT(the_mouse.fd >= 0); /* XXX get the right number later */ return 3; } /* mouse_set_mouse_xy: * */ static bool mouse_set_mouse_xy(ALLEGRO_DISPLAY *display, int x, int y) { (void)display; _al_event_source_lock(&the_mouse.parent.es); { int dx, dy; x_axis.out_abs = _ALLEGRO_CLAMP(x_axis.out_min, x, x_axis.out_max); y_axis.out_abs = _ALLEGRO_CLAMP(y_axis.out_min, y, y_axis.out_max); x_axis.mickeys = 0; y_axis.mickeys = 0; dx = x_axis.out_abs - the_mouse.state.x; dy = y_axis.out_abs - the_mouse.state.y; if ((dx != 0) && (dy != 0)) { the_mouse.state.x = x_axis.out_abs; the_mouse.state.y = y_axis.out_abs; generate_mouse_event( ALLEGRO_EVENT_MOUSE_AXES, the_mouse.state.x, the_mouse.state.y, the_mouse.state.z, dx, dy, 0, 0); } } _al_event_source_unlock(&the_mouse.parent.es); return true; } /* mouse_set_mouse_axis: * * Number of mickeys to cross the screen horizontally: speed * 320. */ static bool mouse_set_mouse_axis(int which, int z) { if (which != 2) { return false; } _al_event_source_lock(&the_mouse.parent.es); { int dz; z_axis.out_abs = z; dz = z_axis.out_abs - the_mouse.state.z; if (dz != 0) { the_mouse.state.z = z_axis.out_abs; generate_mouse_event( ALLEGRO_EVENT_MOUSE_AXES, the_mouse.state.x, the_mouse.state.y, the_mouse.state.z, 0, 0, dz, 0); } } _al_event_source_unlock(&the_mouse.parent.es); return true; } /* mouse_set_mouse_range: * */ bool _al_evdev_set_mouse_range(int x1, int y1, int x2, int y2) { _al_event_source_lock(&the_mouse.parent.es); { int dx, dy; x_axis.out_min = x1; y_axis.out_min = y1; x_axis.out_max = x2; y_axis.out_max = y2; x_axis.out_abs = _ALLEGRO_CLAMP(x_axis.out_min, x_axis.out_abs, x_axis.out_max); y_axis.out_abs = _ALLEGRO_CLAMP(y_axis.out_min, y_axis.out_abs, y_axis.out_max); dx = x_axis.out_abs - the_mouse.state.x; dy = y_axis.out_abs - the_mouse.state.y; if ((dx != 0) && (dy != 0)) { the_mouse.state.x = x_axis.out_abs; the_mouse.state.y = y_axis.out_abs; generate_mouse_event( ALLEGRO_EVENT_MOUSE_AXES, the_mouse.state.x, the_mouse.state.y, the_mouse.state.z, dx, dy, 0, 0); } } _al_event_source_unlock(&the_mouse.parent.es); return true; } /* mouse_get_state: * Copy the current mouse state into RET_STATE, with any necessary locking. */ static void mouse_get_state(ALLEGRO_MOUSE_STATE *ret_state) { _al_event_source_lock(&the_mouse.parent.es); { *ret_state = the_mouse.state; } _al_event_source_unlock(&the_mouse.parent.es); } /* process_new_data: [fdwatch thread] * Process new data arriving in the keyboard's fd. */ static void process_new_data(void *data) { ASSERT((AL_MOUSE_EVDEV *)data == &the_mouse); _al_event_source_lock(&the_mouse.parent.es); { struct input_event events[32]; int bytes, nr, i; while ((bytes = read(the_mouse.fd, &events, sizeof events)) > 0) { nr = bytes / sizeof(events[0]); for (i = 0; i < nr; i++) { process_event(&events[i]); } } } _al_event_source_unlock(&the_mouse.parent.es); } /* [fdwatch thread] */ static void process_event(struct input_event *event) { switch (event->type) { case EV_KEY: process_key(event); break; case EV_REL: process_rel(event); break; case EV_ABS: process_abs(event); break; } } /* [fdwatch thread] */ static void generate_mouse_event(unsigned int type, int x, int y, int z, int dx, int dy, int dz, unsigned int button) { ALLEGRO_EVENT event; if (!_al_event_source_needs_to_generate_event(&the_mouse.parent.es)) return; event.mouse.type = type; event.mouse.timestamp = al_get_time(); event.mouse.display = NULL; event.mouse.x = x; event.mouse.y = y; event.mouse.z = z; event.mouse.dx = dx; event.mouse.dy = dy; event.mouse.dz = dz; event.mouse.button = button; event.mouse.pressure = 0.0; /* TODO */ _al_event_source_emit_event(&the_mouse.parent.es, &event); } /* the driver vtable */ ALLEGRO_MOUSE_DRIVER _al_mousedrv_linux_evdev = { AL_MOUSEDRV_LINUX_EVDEV, "", "", "Linux EVDEV mouse (and tablet)", mouse_init, mouse_exit, mouse_get_mouse, mouse_get_mouse_num_buttons, mouse_get_mouse_num_axes, mouse_set_mouse_xy, mouse_set_mouse_axis, mouse_get_state }; #endif /* ALLEGRO_HAVE_LINUX_INPUT_H */ /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ allegro5-5.2.10.1/src/macosx/000077500000000000000000000000001473414355200155415ustar00rootroot00000000000000allegro5-5.2.10.1/src/macosx/hidjoy-10.4.m000066400000000000000000000377551473414355200176060ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * HID Joystick driver routines for MacOS X. * * By Angelo Mottola. * * See readme.txt for copyright information. */ #include "allegro5/allegro5.h" #include "allegro5/platform/aintosx.h" #import #import #import #ifndef ALLEGRO_MACOSX #error something is wrong with the makefile #endif ALLEGRO_DEBUG_CHANNEL("MacOSX") #define _AL_MAX_JOYSTICKS 8 static bool init_joystick(void); static void exit_joystick(void); static int num_joysticks(void); static ALLEGRO_JOYSTICK* get_joystick(int); static void release_joystick(ALLEGRO_JOYSTICK*); static void get_joystick_state(ALLEGRO_JOYSTICK*, ALLEGRO_JOYSTICK_STATE*); /* OSX HID Joystick * Maintains an array of links which connect a HID cookie to * an element in the ALLEGRO_JOYSTICK_STATE structure. */ typedef struct { ALLEGRO_JOYSTICK parent; struct { IOHIDElementCookie cookie; int* ppressed; } button_link[_AL_MAX_JOYSTICK_BUTTONS]; struct { IOHIDElementCookie cookie; SInt32 intvalue; float* pvalue; float offset; float multiplier; int stick, axis; } axis_link[_AL_MAX_JOYSTICK_AXES * _AL_MAX_JOYSTICK_STICKS]; int num_axis_links; ALLEGRO_JOYSTICK_STATE state; IOHIDDeviceInterface122** interface; IOHIDQueueInterface** queue; CFRunLoopSourceRef source; } ALLEGRO_JOYSTICK_OSX; static ALLEGRO_JOYSTICK_OSX joysticks[_AL_MAX_JOYSTICKS]; static unsigned int joystick_count; /* create_device_iterator: * Create an iterator which will match all joysticks/ * gamepads on the system. */ static io_iterator_t create_device_iterator(UInt16 usage) { NSMutableDictionary* matching; io_iterator_t iter; matching = (NSMutableDictionary*) IOServiceMatching(kIOHIDDeviceKey); // Add in our criteria: [matching setObject:[NSNumber numberWithShort: usage] forKey: (NSString*) CFSTR(kIOHIDPrimaryUsageKey)]; [matching setObject:[NSNumber numberWithShort: kHIDPage_GenericDesktop] forKey: (NSString*) CFSTR(kIOHIDPrimaryUsagePageKey)]; // Get the iterator IOReturn err = IOServiceGetMatchingServices(kIOMasterPortDefault, (CFDictionaryRef) matching, &iter); return (err == kIOReturnSuccess) ? iter : 0; } /* create_interface: * Create the interface to access this device, via * the intermediate plug-in interface */ static BOOL create_interface(io_object_t device, IOHIDDeviceInterface122*** interface) { io_name_t class_name; IOReturn err = IOObjectGetClass(device,class_name); SInt32 score; IOCFPlugInInterface** plugin; err = IOCreatePlugInInterfaceForService(device, kIOHIDDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score); (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID122), (LPVOID) interface); (*plugin)->Release(plugin); return YES; } /* joystick_callback: * Called when an event occurs on the joystick event queue * target: the joystick * refcon: always null * sender: the queue */ static void joystick_callback(void *target, IOReturn result, void *refcon __attribute__((unused)), void *sender) { ALLEGRO_JOYSTICK_OSX* joy = (ALLEGRO_JOYSTICK_OSX*) target; IOHIDQueueInterface** queue = (IOHIDQueueInterface**) sender; AbsoluteTime past = {0,0}; ALLEGRO_EVENT_SOURCE *src = al_get_joystick_event_source(); if (src == NULL) { return; } _al_event_source_lock(src); while (result == kIOReturnSuccess) { IOHIDEventStruct event; result = (*queue)->getNextEvent(queue, &event, past, 0); if (result == kIOReturnSuccess) { int i; for (i=0; iparent.info.num_buttons; ++i) { if (joy->button_link[i].cookie == event.elementCookie) { int newvalue = event.value; if (*joy->button_link[i].ppressed != newvalue) { *joy->button_link[i].ppressed = newvalue; // emit event ALLEGRO_EVENT evt; if (newvalue) evt.type = ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN; else evt.type = ALLEGRO_EVENT_JOYSTICK_BUTTON_UP; evt.joystick.button = i; _al_event_source_emit_event(src, &evt); } } } for (i=0; inum_axis_links; ++i) { if (joy->axis_link[i].cookie == event.elementCookie) { SInt32 newvalue = event.value; if (joy->axis_link[i].intvalue != newvalue) { joy->axis_link[i].intvalue = newvalue; *joy->axis_link[i].pvalue = (joy->axis_link[i].offset + newvalue) * joy->axis_link[i].multiplier; // emit event ALLEGRO_EVENT evt; evt.type = ALLEGRO_EVENT_JOYSTICK_AXIS; evt.joystick.axis = joy->axis_link[i].axis; evt.joystick.pos = *joy->axis_link[i].pvalue; evt.joystick.stick = joy->axis_link[i].stick; _al_event_source_emit_event(src, &evt); } } } } } _al_event_source_unlock(src); } /* add_device: * Create the joystick structure for this device * and add it to the 'joysticks' vector * TODO this only works for simple joysticks and * only allows access to the primary X & Y axes. * In reality there can be more axes than this and * more that one distinct controller handled by the same * interface. * We should iterate through the application collections to * find the joysticks then through the physical collections * therein to identify the individual sticks. */ static void add_device(io_object_t device) { ALLEGRO_JOYSTICK_OSX* joy; NSArray* elements = nil; int num_buttons = 0; BOOL have_x = NO, have_y = NO; IOReturn err; joy = &joysticks[joystick_count++]; memset(joy, 0, sizeof(*joy)); joy->parent.info.num_sticks = 0; joy->parent.info.num_buttons = 0; IOHIDDeviceInterface122** interface; create_interface(device, &interface); // Open the device err = (*interface)->open(interface, 0); // Create an event queue IOHIDQueueInterface** queue = (*interface)->allocQueue(interface); err = (*queue)->create(queue, 0, 8); // Create a source err = (*queue)->createAsyncEventSource(queue, &joy->source); err = (*queue)->setEventCallout(queue, joystick_callback, joy, NULL); joy->queue = queue; (*interface)->copyMatchingElements(interface, NULL, (CFArrayRef*) &elements); NSEnumerator* enumerator = [elements objectEnumerator]; NSDictionary* element; while ((element = (NSDictionary*) [enumerator nextObject])) { short usage = [((NSNumber*) [element objectForKey: (NSString*) CFSTR(kIOHIDElementUsageKey)]) shortValue]; short usage_page = [((NSNumber*) [element objectForKey: (NSString*) CFSTR(kIOHIDElementUsagePageKey)]) shortValue]; if (usage_page == kHIDPage_Button && num_buttons < _AL_MAX_JOYSTICK_BUTTONS) { joy->button_link[num_buttons].cookie = (IOHIDElementCookie) [((NSNumber*) [element objectForKey: (NSString*) CFSTR(kIOHIDElementCookieKey)]) pointerValue]; joy->button_link[num_buttons].ppressed = &joy->state.button[num_buttons]; // Use the provided name or make one up. NSString* name = (NSString*) [element objectForKey: (NSString*) CFSTR(kIOHIDElementNameKey)]; if (name == nil) { name = [NSString stringWithFormat:@"Button %d", (num_buttons+1)]; } ALLEGRO_INFO("Found button named \"%s\"\n", [name UTF8String]); // Say that we want events from this button err = (*queue)->addElement(queue, joy->button_link[num_buttons].cookie, 0); if (err != 0) { ALLEGRO_WARN("Button named \"%s\" NOT added to event queue\n", [name UTF8String]); } else { joy->parent.info.button[num_buttons].name = strdup([name UTF8String]); ++num_buttons; } } if (usage_page == kHIDPage_GenericDesktop) { if ((usage == kHIDUsage_GD_X) && (!have_x)) { NSNumber* minValue = (NSNumber*) [element objectForKey: (NSString*) CFSTR(kIOHIDElementMinKey)]; NSNumber* maxValue = (NSNumber*) [element objectForKey: (NSString*) CFSTR(kIOHIDElementMaxKey)]; joy->axis_link[0].axis = 0; joy->axis_link[0].stick = 0; joy->axis_link[0].offset = - ([minValue floatValue] + [maxValue floatValue]) / 2.0f; joy->axis_link[0].multiplier = 2.0f / ([maxValue floatValue] - [minValue floatValue]); joy->axis_link[0].cookie = (IOHIDElementCookie) [((NSNumber*) [element objectForKey: (NSString*) CFSTR(kIOHIDElementCookieKey)]) pointerValue]; joy->axis_link[0].pvalue = &joy->state.stick[0].axis[0]; NSString* name = (NSString*) [element objectForKey: (NSString*) CFSTR(kIOHIDElementNameKey)]; if (name == nil) { name = @"X-axis"; } ALLEGRO_INFO("Found X-axis named \"%s\"\n", [name UTF8String]); // Say that we want events from this axis err = (*queue)->addElement(queue, joy->axis_link[0].cookie, 0); if (err != 0) { ALLEGRO_WARN("X-axis named \"%s\" NOT added to event queue\n", [name UTF8String]); } else { have_x = YES; joy->parent.info.stick[0].axis[0].name = strdup([name UTF8String]); } } if ((usage == kHIDUsage_GD_Y) && (!have_y)) { NSNumber* minValue = (NSNumber*) [element objectForKey: (NSString*) CFSTR(kIOHIDElementMinKey)]; NSNumber* maxValue = (NSNumber*) [element objectForKey: (NSString*) CFSTR(kIOHIDElementMaxKey)]; joy->axis_link[1].axis = 1; joy->axis_link[1].stick = 0; joy->axis_link[1].offset = - ([minValue floatValue] + [maxValue floatValue]) / 2.0f; joy->axis_link[1].multiplier = 2.0f / ([maxValue floatValue] - [minValue floatValue]); joy->axis_link[1].cookie = (IOHIDElementCookie) [((NSNumber*) [element objectForKey: (NSString*) CFSTR(kIOHIDElementCookieKey)]) pointerValue]; joy->axis_link[1].pvalue = &joy->state.stick[0].axis[1]; NSString* name = (NSString*) [element objectForKey: (NSString*) CFSTR(kIOHIDElementNameKey)]; if (name == nil) { name = @"Y-axis"; } ALLEGRO_INFO("Found Y-axis named \"%s\"\n", [name UTF8String]); // Say that we want events from this axis err = (*queue)->addElement(queue, joy->axis_link[1].cookie, 0); if (err != 0) { ALLEGRO_WARN("Y-axis named \"%s\" NOT added to event queue\n", [name UTF8String]); } else { have_y = YES; joy->parent.info.stick[0].axis[1].name = strdup([name UTF8String]); } } } } joy->parent.info.num_buttons = num_buttons; if (have_x && have_y) { joy->parent.info.stick[0].name = strdup("Primary axis"); joy->parent.info.num_sticks = 1; joy->parent.info.stick[0].num_axes = 2; joy->num_axis_links = 2; } joy->interface = interface; joystick_callback(joy,kIOReturnSuccess,NULL,queue); [elements release]; } // FIXME! static const char *get_joystick_name(ALLEGRO_JOYSTICK *joy_) { (void)joy_; return "Joystick"; } static bool get_joystick_active(ALLEGRO_JOYSTICK *joy_) { (void)joy_; return true; } static bool reconfigure_joysticks(void) { return false; } ALLEGRO_JOYSTICK_DRIVER* _al_osx_get_joystick_driver_10_4(void) { static ALLEGRO_JOYSTICK_DRIVER* vt = NULL; if (vt == NULL) { vt = al_malloc(sizeof(*vt)); memset(vt, 0, sizeof(*vt)); vt->joydrv_ascii_name = "OSX HID Driver"; vt->init_joystick = init_joystick; vt->exit_joystick = exit_joystick; vt->num_joysticks = num_joysticks; vt->get_joystick = get_joystick; vt->release_joystick = release_joystick; vt->get_joystick_state = get_joystick_state; vt->reconfigure_joysticks = reconfigure_joysticks; vt->get_name = get_joystick_name; vt->get_active = get_joystick_active; } return vt; } /* init_joystick: * Initializes the HID joystick driver. */ static bool init_joystick(void) { joystick_count = 0; io_iterator_t iterator; io_object_t device; iterator = create_device_iterator(kHIDUsage_GD_GamePad); if (iterator != 0) { while ((device = IOIteratorNext(iterator))) { add_device(device); } IOObjectRelease(iterator); } iterator = create_device_iterator(kHIDUsage_GD_Joystick); if (iterator != 0) { while ((device = IOIteratorNext(iterator))) { add_device(device); } IOObjectRelease(iterator); } /* Ensure the source is added and started on the main thread */ dispatch_sync(dispatch_get_main_queue(), ^{ unsigned int i; CFRunLoopRef current = CFRunLoopGetCurrent(); for (i=0; isource,kCFRunLoopDefaultMode); (*joy->queue)->start(joy->queue); } }); return true; } /* exit_joystick: * Shuts down the HID joystick driver. */ static void exit_joystick(void) { /* Ensure the source is stopped and removed on the main thread */ dispatch_sync(dispatch_get_main_queue(), ^{ unsigned int i; CFRunLoopRef current = CFRunLoopGetCurrent(); for (i=0; iqueue)->stop(joy->queue); CFRunLoopRemoveSource(current,joy->source,kCFRunLoopDefaultMode); } }); unsigned int i; for (i=0; i< joystick_count; ++i) { ALLEGRO_JOYSTICK_OSX* joy = &joysticks[i]; CFRelease(joy->source); if (joy->queue) { (*joy->queue)->dispose(joy->queue); (*joy->queue)->Release(joy->queue); } if (joy->interface) { (*joy->interface)->close(joy->interface); (*joy->interface)->Release(joy->interface); } int a, b, s; /* Free everything we might have created * (all fields set to NULL initially so this is OK.) */ for (b = 0; b < _AL_MAX_JOYSTICK_BUTTONS; ++ b) { al_free((void*) joy->parent.info.button[b].name); } for (s = 0; s < _AL_MAX_JOYSTICK_STICKS; ++s) { al_free((void*) joy->parent.info.stick[s].name); for (a = 0; a < _AL_MAX_JOYSTICK_AXES; ++a) { al_free((void*) joy->parent.info.stick[s].axis[a].name); } } } } /* num_joysticks: * Return number of active joysticks */ static int num_joysticks(void) { return joystick_count; } /* get_joystick: * Get a pointer to a joystick structure */ static ALLEGRO_JOYSTICK* get_joystick(int index) { ALLEGRO_JOYSTICK* joy = NULL; if (index >= 0 && index < (int) joystick_count) { joy = (ALLEGRO_JOYSTICK *)&joysticks[index]; } return joy; } /* release_joystick: * Release a pointer that has been obtained */ static void release_joystick(ALLEGRO_JOYSTICK* joy __attribute__((unused)) ) { // No-op } /* get_joystick_state: * Get the current status of a joystick */ static void get_joystick_state(ALLEGRO_JOYSTICK* ajoy, ALLEGRO_JOYSTICK_STATE* state) { ALLEGRO_JOYSTICK_OSX* joy = (ALLEGRO_JOYSTICK_OSX*) ajoy; memcpy(state, &joy->state,sizeof(*state)); } /* Local variables: */ /* c-basic-offset: 3 */ /* indent-tabs-mode: nil */ /* End: */ allegro5-5.2.10.1/src/macosx/hidjoy.m000066400000000000000000000544071473414355200172170ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * HID Joystick driver routines for MacOS X. * * By Angelo Mottola. * New API (Leopard) support and hotplugging by Trent Gamblin. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/platform/aintosx.h" #import #import #ifndef ALLEGRO_MACOSX #error something is wrong with the makefile #endif #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 #import /* State transitions: * unused -> born * born -> alive * born -> dying * active -> dying * dying -> unused */ typedef enum { JOY_STATE_UNUSED, JOY_STATE_BORN, JOY_STATE_ALIVE, JOY_STATE_DYING } CONFIG_STATE; // These values can be found in the USB HID Usage Tables: // http://www.usb.org/developers/hidpage #define GENERIC_DESKTOP_USAGE_PAGE 0x01 #define JOYSTICK_USAGE_NUMBER 0x04 #define GAMEPAD_USAGE_NUMBER 0x05 typedef struct { ALLEGRO_JOYSTICK parent; IOHIDElementRef buttons[_AL_MAX_JOYSTICK_BUTTONS]; IOHIDElementRef axes[_AL_MAX_JOYSTICK_STICKS][_AL_MAX_JOYSTICK_AXES]; IOHIDElementRef dpad; int dpad_stick; int dpad_axis_vert; int dpad_axis_horiz; long min[_AL_MAX_JOYSTICK_STICKS][_AL_MAX_JOYSTICK_AXES]; long max[_AL_MAX_JOYSTICK_STICKS][_AL_MAX_JOYSTICK_AXES]; CONFIG_STATE cfg_state; ALLEGRO_JOYSTICK_STATE state; IOHIDDeviceRef ident; char *name; } ALLEGRO_JOYSTICK_OSX; static IOHIDManagerRef hidManagerRef; static _AL_VECTOR joysticks; static CONFIG_STATE new_joystick_state = JOY_STATE_ALIVE; static bool initialized = false; static ALLEGRO_MUTEX *add_mutex; ALLEGRO_DEBUG_CHANNEL("MacOSX") // function to create matching dictionary (for devices) static CFMutableDictionaryRef CreateDeviceMatchingDictionary( UInt32 inUsagePage, UInt32 inUsage ) { // create a dictionary to add usage page/usages to CFMutableDictionaryRef result = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); if (result) { // Add key for device type to refine the matching dictionary. CFNumberRef pageCFNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &inUsagePage ); if (pageCFNumberRef) { CFStringRef usage_page = CFSTR(kIOHIDDeviceUsagePageKey); CFDictionarySetValue( result, usage_page, pageCFNumberRef ); CFRelease(pageCFNumberRef); // note: the usage is only valid if the usage page is also defined CFNumberRef usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &inUsage ); if (usageCFNumberRef) { CFStringRef usage_key = CFSTR(kIOHIDDeviceUsageKey); CFDictionarySetValue( result, usage_key, usageCFNumberRef ); CFRelease(usageCFNumberRef); } } } return result; } static ALLEGRO_JOYSTICK_OSX *find_joystick(IOHIDDeviceRef ident) { int i; for (i = 0; i < (int)_al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_OSX *joy = *(ALLEGRO_JOYSTICK_OSX **)_al_vector_ref(&joysticks, i); if (ident == joy->ident) { return joy; } } return NULL; } static const char *get_element_name(IOHIDElementRef elem, const char *default_name) { CFStringRef name = IOHIDElementGetName(elem); if (name) { return CFStringGetCStringPtr(name, kCFStringEncodingUTF8); } else return default_name; } static void joy_null(ALLEGRO_JOYSTICK_OSX *joy) { int i, j; // NULL the parent for (i = 0; i < _AL_MAX_JOYSTICK_BUTTONS; i++) { joy->parent.info.button[i].name = NULL; } for (i = 0; i < _AL_MAX_JOYSTICK_STICKS; i++) { joy->parent.info.stick[i].name = NULL; for (j = 0; j < _AL_MAX_JOYSTICK_AXES; j++) { joy->parent.info.stick[i].axis[j].name = NULL; } } } static void add_axis(ALLEGRO_JOYSTICK_OSX *joy, int stick_index, int axis_index, int min, int max, char *name, IOHIDElementRef elem) { if (axis_index >= _AL_MAX_JOYSTICK_AXES) return; joy->min[stick_index][axis_index] = min; joy->max[stick_index][axis_index] = max; joy->parent.info.stick[stick_index].axis[axis_index].name = name; joy->parent.info.stick[stick_index].num_axes++; joy->axes[stick_index][axis_index] = elem; } static void add_elements(CFArrayRef elements, ALLEGRO_JOYSTICK_OSX *joy) { int i; char default_name[100]; int stick_class = -1; int axis_index = 0; bool old_style = _al_get_joystick_compat_version() < AL_ID(5, 2, 10, 0); joy_null(joy); for (i = 0; i < CFArrayGetCount(elements); i++) { IOHIDElementRef elem = (IOHIDElementRef)CFArrayGetValueAtIndex( elements, i ); int usage = IOHIDElementGetUsage(elem); int usage_page = IOHIDElementGetUsagePage(elem); if (IOHIDElementGetType(elem) == kIOHIDElementTypeInput_Button) { int idx; if (old_style) idx = usage - 1; else { idx = joy->parent.info.num_buttons; // 0x09 is the Button Page. if (usage_page != 0x09) continue; } if (idx >= 0 && idx < _AL_MAX_JOYSTICK_BUTTONS && !joy->buttons[idx]) { joy->buttons[idx] = elem; sprintf(default_name, "Button %d", idx); const char *name = get_element_name(elem, default_name); char *str = al_malloc(strlen(name)+1); strcpy(str, name); joy->parent.info.button[idx].name = str; joy->parent.info.num_buttons++; } } else if ( IOHIDElementGetType(elem) == kIOHIDElementTypeInput_Misc) { long min = IOHIDElementGetLogicalMin(elem); long max = IOHIDElementGetLogicalMax(elem); int new_stick_class = -1; int stick_index = joy->parent.info.num_sticks - 1; switch (usage) { case kHIDUsage_GD_X: case kHIDUsage_GD_Y: case kHIDUsage_GD_Z: new_stick_class = 1; break; case kHIDUsage_GD_Rx: case kHIDUsage_GD_Ry: case kHIDUsage_GD_Rz: new_stick_class = 2; break; case kHIDUsage_GD_Hatswitch: new_stick_class = 3; break; } if (new_stick_class < 0) continue; if (stick_class != new_stick_class) { if (joy->parent.info.num_sticks >= _AL_MAX_JOYSTICK_STICKS-1) break; joy->parent.info.num_sticks++; stick_index++; axis_index = 0; stick_class = new_stick_class; char *buf = al_malloc(20); sprintf(buf, "Stick %d", stick_index); joy->parent.info.stick[stick_index].name = buf; } else axis_index++; if (stick_class == 3) { joy->dpad_stick = stick_index; joy->dpad = elem; joy->dpad_axis_horiz = axis_index; sprintf(default_name, "Axis %i", axis_index); char *str = al_malloc(strlen(default_name)+1); strcpy(str, default_name); joy->parent.info.stick[stick_index].axis[axis_index].name = str; ++axis_index; joy->dpad_axis_vert = axis_index; sprintf(default_name, "Axis %i", axis_index); str = al_malloc(strlen(default_name)+1); strcpy(str, default_name); add_axis(joy, stick_index, axis_index, min, max, str, elem); joy->parent.info.stick[stick_index].axis[axis_index].name = str; joy->parent.info.stick[stick_index].num_axes = 2; } else { sprintf(default_name, "Axis %i", axis_index); const char *name = get_element_name(elem, default_name); char *str = al_malloc(strlen(name)+1); strcpy(str, name); add_axis(joy, stick_index, axis_index, min, max, str, elem); } } } } static void osx_joy_generate_configure_event(void) { if (!initialized) return; ALLEGRO_EVENT event; event.joystick.type = ALLEGRO_EVENT_JOYSTICK_CONFIGURATION; event.joystick.timestamp = al_current_time(); _al_generate_joystick_event(&event); } static void add_joystick_device(IOHIDDeviceRef ref, bool emit_reconfigure_event) { al_lock_mutex(add_mutex); ALLEGRO_JOYSTICK_OSX *joy = find_joystick(ref); if (joy && (joy->cfg_state == JOY_STATE_BORN || joy->cfg_state == JOY_STATE_ALIVE)) { al_unlock_mutex(add_mutex); return; } if (joy == NULL) { joy = al_calloc(1, sizeof(ALLEGRO_JOYSTICK_OSX)); joy->ident = ref; ALLEGRO_JOYSTICK_OSX **back = _al_vector_alloc_back(&joysticks); *back = joy; } joy->cfg_state = new_joystick_state; CFArrayRef elements = IOHIDDeviceCopyMatchingElements( ref, NULL, kIOHIDOptionsTypeNone ); add_elements(elements, joy); CFRelease(elements); al_unlock_mutex(add_mutex); if (emit_reconfigure_event) osx_joy_generate_configure_event(); ALLEGRO_INFO("Found joystick (%d buttons, %d sticks)\n", joy->parent.info.num_buttons, joy->parent.info.num_sticks); } static int enumerate_and_create_initial_joystick_devices(IOHIDManagerRef manager) { int i; int num_joysticks_enumerated = 0; CFSetRef devices = IOHIDManagerCopyDevices(manager); if (devices == NULL) { // There are no devices to enumerate } else { CFIndex num_devices = CFSetGetCount(devices); IOHIDDeviceRef *device_arr = al_calloc(num_devices, sizeof(IOHIDDeviceRef)); CFSetGetValues(devices, (const void **) device_arr); for (i = 0; i < num_devices; i++) { IOHIDDeviceRef dev = device_arr[i]; add_joystick_device(dev, false); num_joysticks_enumerated++; } al_free(device_arr); CFRelease(devices); } return num_joysticks_enumerated; } static void device_add_callback( void *context, IOReturn result, void *sender, IOHIDDeviceRef ref ) { (void)context; (void)result; (void)sender; add_joystick_device(ref, true); } static void device_remove_callback( void *context, IOReturn result, void *sender, IOHIDDeviceRef ref ) { (void)context; (void)result; (void)sender; int i; for (i = 0; i < (int)_al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_OSX *joy = *(ALLEGRO_JOYSTICK_OSX **)_al_vector_ref(&joysticks, i); if (joy->ident == ref) { joy->cfg_state = JOY_STATE_DYING; osx_joy_generate_configure_event(); return; } } } static void osx_joy_generate_axis_event(ALLEGRO_JOYSTICK_OSX *joy, int stick, int axis, float pos) { joy->state.stick[stick].axis[axis] = pos; ALLEGRO_EVENT event; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); if (!_al_event_source_needs_to_generate_event(es)) return; event.joystick.type = ALLEGRO_EVENT_JOYSTICK_AXIS; event.joystick.timestamp = al_current_time(); event.joystick.id = (ALLEGRO_JOYSTICK *)joy; event.joystick.stick = stick; event.joystick.axis = axis; event.joystick.pos = pos; event.joystick.button = 0; _al_event_source_emit_event(es, &event); } static void osx_joy_generate_button_event(ALLEGRO_JOYSTICK_OSX *joy, int button, ALLEGRO_EVENT_TYPE event_type) { joy->state.button[button] = event_type == ALLEGRO_EVENT_JOYSTICK_BUTTON_UP ? 0 : 1;; ALLEGRO_EVENT event; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); if (!_al_event_source_needs_to_generate_event(es)) return; event.joystick.type = event_type; event.joystick.timestamp = al_current_time(); event.joystick.id = (ALLEGRO_JOYSTICK *)joy; event.joystick.stick = 0; event.joystick.axis = 0; event.joystick.pos = 0.0; event.joystick.button = button; _al_event_source_emit_event(es, &event); } #define MAX_HAT_DIRECTIONS 8 struct HAT_MAPPING { int axisV; int axisH; } hat_mapping[MAX_HAT_DIRECTIONS] = { { -1, 0 }, // 0 { -1, 1 }, // 1 { 0, 1 }, // 2 { 1, 1 }, // 3 { 1, 0 }, // 4 { 1, -1 }, // 5 { 0, -1 }, // 6 { -1, -1 }, // 7 }; static void value_callback( void *context, IOReturn result, void *sender, IOHIDValueRef value ) { if (!initialized) return; (void)context; (void)result; (void)sender; IOHIDElementRef elem = IOHIDValueGetElement(value); IOHIDDeviceRef ref = IOHIDElementGetDevice(elem); ALLEGRO_JOYSTICK_OSX *joy = find_joystick(ref); if (!joy) return; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); _al_event_source_lock(es); int i; for (i = 0; i < joy->parent.info.num_buttons; i++) { if (joy->buttons[i] == elem) { ALLEGRO_EVENT_TYPE type; if (IOHIDValueGetIntegerValue(value) == 0) type = ALLEGRO_EVENT_JOYSTICK_BUTTON_UP; else type = ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN; osx_joy_generate_button_event(joy, i, type); goto done; } } int int_value = IOHIDValueGetIntegerValue(value); int min = joy->min[joy->dpad_stick][1]; int max = joy->max[joy->dpad_stick][1]; if (joy->dpad == elem){ if (int_value >= min && int_value <= max) { int index = int_value - min; if (index < MAX_HAT_DIRECTIONS) { osx_joy_generate_axis_event(joy, joy->dpad_stick, joy->dpad_axis_vert, (float)hat_mapping[index].axisV); osx_joy_generate_axis_event(joy, joy->dpad_stick, joy->dpad_axis_horiz, (float)hat_mapping[index].axisH); } } else { osx_joy_generate_axis_event(joy, joy->dpad_stick, joy->dpad_axis_vert, 0); osx_joy_generate_axis_event(joy, joy->dpad_stick, joy->dpad_axis_horiz, 0); } goto done; } int stick = -1; int axis = -1; for (stick = 0; stick < joy->parent.info.num_sticks; stick++) { for(axis = 0; axis < joy->parent.info.stick[stick].num_axes; ++axis) { if (joy->axes[stick][axis] == elem) { goto gen_axis_event; } } } // Unknown event goto done; gen_axis_event: { float pos; long min = joy->min[stick][axis]; long max = joy->max[stick][axis]; if (min < 0) { if (int_value < 0) pos = -(float)int_value/min; else pos = (float)int_value/max; } else { pos = ((float)int_value/max*2) - 1; } osx_joy_generate_axis_event(joy, stick, axis, pos); } done: _al_event_source_unlock(es); } /* init_joystick: * Initializes the HID joystick driver. */ static bool init_joystick(void) { add_mutex = al_create_mutex(); hidManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, kIOHIDOptionsTypeNone ); if (CFGetTypeID(hidManagerRef) != IOHIDManagerGetTypeID()) { ALLEGRO_ERROR("Unable to create HID Manager\n"); return false; } // Set which devices we want to match CFMutableDictionaryRef criteria0 = CreateDeviceMatchingDictionary( GENERIC_DESKTOP_USAGE_PAGE, JOYSTICK_USAGE_NUMBER ); CFMutableDictionaryRef criteria1 = CreateDeviceMatchingDictionary( GENERIC_DESKTOP_USAGE_PAGE, GAMEPAD_USAGE_NUMBER ); CFMutableDictionaryRef criteria_list[] = { criteria0, criteria1 }; CFArrayRef criteria = CFArrayCreate( kCFAllocatorDefault, (const void **)criteria_list, 2, NULL ); IOHIDManagerSetDeviceMatchingMultiple( hidManagerRef, criteria ); CFRelease(criteria0); CFRelease(criteria1); CFRelease(criteria); /* Register for plug/unplug notifications */ IOHIDManagerRegisterDeviceMatchingCallback( hidManagerRef, device_add_callback, NULL ); IOHIDManagerRegisterDeviceRemovalCallback( hidManagerRef, device_remove_callback, NULL ); // Register for value changes IOHIDManagerRegisterInputValueCallback( hidManagerRef, value_callback, NULL ); IOHIDManagerScheduleWithRunLoop( hidManagerRef, CFRunLoopGetMain(), kCFRunLoopDefaultMode ); _al_vector_init(&joysticks, sizeof(ALLEGRO_JOYSTICK_OSX *)); al_lock_mutex(add_mutex); IOReturn ret = IOHIDManagerOpen( hidManagerRef, kIOHIDOptionsTypeSeizeDevice ); al_unlock_mutex(add_mutex); if (ret != kIOReturnSuccess) { return false; } int num_joysticks_created = enumerate_and_create_initial_joystick_devices(hidManagerRef); if (num_joysticks_created > 0) osx_joy_generate_configure_event(); new_joystick_state = JOY_STATE_BORN; initialized = true; return true; } /* exit_joystick: * Shuts down the HID joystick driver. */ static void exit_joystick(void) { al_destroy_mutex(add_mutex); IOHIDManagerUnscheduleFromRunLoop( hidManagerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); // Unregister from value changes IOHIDManagerRegisterInputValueCallback( hidManagerRef, NULL, NULL ); IOHIDManagerClose( hidManagerRef, kIOHIDOptionsTypeNone ); CFRelease(hidManagerRef); _al_vector_free(&joysticks); initialized = false; } /* num_joysticks: * Return number of active joysticks */ static int num_joysticks(void) { int i; int count = 0; for (i = 0; i < (int)_al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_OSX *joy = *(ALLEGRO_JOYSTICK_OSX **)_al_vector_ref(&joysticks, i); if (joy->cfg_state == JOY_STATE_ALIVE) { count++; } } return count; } /* get_joystick: * Get a pointer to a joystick structure */ static ALLEGRO_JOYSTICK* get_joystick(int index) { ASSERT(index >= 0 && index < (int)_al_vector_size(&joysticks)); int i; int count = 0; for (i = 0; i < (int)_al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_OSX *joy = *(ALLEGRO_JOYSTICK_OSX **)_al_vector_ref(&joysticks, i); if (joy->cfg_state == JOY_STATE_ALIVE || joy->cfg_state == JOY_STATE_DYING) { if (count == index) { return (ALLEGRO_JOYSTICK *)joy; } count++; } } return NULL; } /* release_joystick: * Release a pointer that has been obtained */ static void release_joystick(ALLEGRO_JOYSTICK* joy __attribute__((unused)) ) { // No-op } /* get_joystick_state: * Get the current status of a joystick */ static void get_joystick_state(ALLEGRO_JOYSTICK *joy_, ALLEGRO_JOYSTICK_STATE *ret_state) { ALLEGRO_JOYSTICK_OSX *joy = (ALLEGRO_JOYSTICK_OSX *) joy_; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); _al_event_source_lock(es); { *ret_state = joy->state; } _al_event_source_unlock(es); } static bool reconfigure_joysticks(void) { int i; bool ret = false; for (i = 0; i < (int)_al_vector_size(&joysticks); i++) { ALLEGRO_JOYSTICK_OSX *joy = *(ALLEGRO_JOYSTICK_OSX **)_al_vector_ref(&joysticks, i); if (joy->cfg_state == JOY_STATE_DYING) { joy->cfg_state = JOY_STATE_UNUSED; for (i = 0; i < _AL_MAX_JOYSTICK_BUTTONS; i++) { al_free((char *)joy->parent.info.button[i].name); } for (i = 0; i < _AL_MAX_JOYSTICK_STICKS; i++) { int j; al_free(joy->parent.info.stick[i].name); for (j = 0; j < _AL_MAX_JOYSTICK_AXES; j++) { al_free(joy->parent.info.stick[i].axis[j].name); } } joy_null(joy); memset(joy->buttons, 0, _AL_MAX_JOYSTICK_BUTTONS*sizeof(IOHIDElementRef)); memset(&joy->state, 0, sizeof(ALLEGRO_JOYSTICK_STATE)); joy->dpad=0; } else if (joy->cfg_state == JOY_STATE_BORN) joy->cfg_state = JOY_STATE_ALIVE; else continue; ret = true; } return ret; } static const char *get_joystick_name(ALLEGRO_JOYSTICK *joy_) { ALLEGRO_JOYSTICK_OSX *joy = (ALLEGRO_JOYSTICK_OSX *)joy_; CFStringRef str; str = IOHIDDeviceGetProperty(joy->ident, CFSTR(kIOHIDProductKey)); if (str) { CFIndex length = CFStringGetLength(str); CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; if (joy->name) { al_free(joy->name); } joy->name = (char *)al_malloc(maxSize); if (joy->name) { if (CFStringGetCString(str, joy->name, maxSize, kCFStringEncodingUTF8)) { return joy->name; } } } return "Joystick"; } static bool get_joystick_active(ALLEGRO_JOYSTICK *joy_) { ALLEGRO_JOYSTICK_OSX *joy = (ALLEGRO_JOYSTICK_OSX *)joy_; return joy->cfg_state == JOY_STATE_ALIVE || joy->cfg_state == JOY_STATE_DYING; } ALLEGRO_JOYSTICK_DRIVER* _al_osx_get_joystick_driver_10_5(void) { static ALLEGRO_JOYSTICK_DRIVER* vt = NULL; if (vt == NULL) { vt = al_malloc(sizeof(*vt)); memset(vt, 0, sizeof(*vt)); vt->joydrv_ascii_name = "OSX HID Driver"; vt->init_joystick = init_joystick; vt->exit_joystick = exit_joystick; vt->reconfigure_joysticks = reconfigure_joysticks; vt->num_joysticks = num_joysticks; vt->get_joystick = get_joystick; vt->release_joystick = release_joystick; vt->get_joystick_state = get_joystick_state; vt->get_name = get_joystick_name; vt->get_active = get_joystick_active; } return vt; } #endif // Leopard+ #ifndef NSAppKitVersionNumber10_5 #define NSAppKitVersionNumber10_5 949 #endif ALLEGRO_JOYSTICK_DRIVER* _al_osx_get_joystick_driver_10_4(void); ALLEGRO_JOYSTICK_DRIVER* _al_osx_get_joystick_driver_10_5(void); ALLEGRO_JOYSTICK_DRIVER* _al_osx_get_joystick_driver(void) { if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_5) { return _al_osx_get_joystick_driver_10_5(); } else { return _al_osx_get_joystick_driver_10_4(); } } /* Local variables: */ /* c-basic-offset: 3 */ /* indent-tabs-mode: nil */ /* End: */ allegro5-5.2.10.1/src/macosx/hidman.m000066400000000000000000000422711473414355200171650ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * MacOS X HID Manager access routines. * * By Angelo Mottola. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/platform/aintosx.h" #ifndef ALLEGRO_MACOSX #error Something is wrong with the makefile #endif #define USAGE(p, u) (((p)<<16)+(u)) static void hid_store_element_data(CFTypeRef element, int type, HID_DEVICE *device, int app, int collection, int index); static void hid_scan_physical_collection(CFTypeRef properties, HID_DEVICE *device, int app, int collection); static void hid_scan_application_collection(CFMutableDictionaryRef properties, HID_DEVICE *device); static HID_DEVICE* add_device(HID_DEVICE_COLLECTION*); /* add_element: * Add a new, blank element to a device. * This is later specialized into a button * axis or whatever */ static HID_ELEMENT* add_element(HID_DEVICE* d) { HID_ELEMENT* e; if (d->element==NULL) { d->capacity=8; d->element=al_malloc(d->capacity*sizeof(HID_ELEMENT)); } if (d->num_elements>=d->capacity) { d->capacity*=2; d->element=al_realloc(d->element, d->capacity*sizeof(HID_ELEMENT)); } e=&d->element[d->num_elements++]; memset(e, 0, sizeof(HID_ELEMENT)); return e; } /* i_val: * Helper method - get an integer value from a dictionary * Defaults to 0 if the value is not found; in practice this * should not occur. */ static int i_val(CFTypeRef d, CFStringRef key) { int ans; CFTypeRef num = CFDictionaryGetValue(d, key); if (num) CFNumberGetValue(num, kCFNumberIntType, &ans); else ans = 0; return ans; } /* hid_store_element_data: * Parse this HID element, break it down and store the * relevant data in the device structure */ static void hid_store_element_data(CFTypeRef element, int type, HID_DEVICE *device, int app, int col, int idx) { HID_ELEMENT *hid_element; CFTypeRef type_ref; const char *name; hid_element = add_element(device); hid_element->type = type; hid_element->index = idx; hid_element->col = col; hid_element->app = app; hid_element->cookie = (IOHIDElementCookie) i_val(element, CFSTR(kIOHIDElementCookieKey)); hid_element->min = i_val(element, CFSTR(kIOHIDElementMinKey)); hid_element->max = i_val(element, CFSTR(kIOHIDElementMaxKey)); type_ref = CFDictionaryGetValue(element, CFSTR(kIOHIDElementNameKey)); if ((type_ref) && (name = CFStringGetCStringPtr(type_ref, CFStringGetSystemEncoding()))) hid_element->name = strdup(name); else hid_element->name = NULL; } /* hid_scan_application: * scan the elements that make up one 'application' * i.e. one unit like a joystick. */ static void hid_scan_application(CFTypeRef properties, HID_DEVICE *device, int app) { CFTypeRef array_ref, element; int type, usage_page, usage; int i; int axis=0; int stick=0; array_ref = CFDictionaryGetValue(properties, CFSTR(kIOHIDElementKey)); if ((array_ref) && (CFGetTypeID(array_ref) == CFArrayGetTypeID())) { for (i = 0; i < CFArrayGetCount(array_ref); i++) { element = CFArrayGetValueAtIndex(array_ref, i); if (CFGetTypeID(element) == CFDictionaryGetTypeID()) { type = i_val(element, CFSTR(kIOHIDElementTypeKey)); usage = i_val(element, CFSTR(kIOHIDElementUsageKey)); usage_page = i_val(element, CFSTR(kIOHIDElementUsagePageKey)); if (type == kIOHIDElementTypeCollection) { /* It is a collection; recurse into it, if it is part of the * generic desktop (sometimes the whole joystick is wrapped * up inside a collection like this. */ if (usage_page == kHIDPage_GenericDesktop) hid_scan_application(element, device, app); } else { switch (usage_page) { case kHIDPage_GenericDesktop: switch (usage) { case kHIDUsage_GD_Pointer: if (axis!=0) { /* already have some elements in this stick */ ++stick; axis=0; } hid_scan_physical_collection(element, device, app, stick); ++stick; break; case kHIDUsage_GD_X: hid_store_element_data(element, HID_ELEMENT_AXIS_PRIMARY_X, device, app, stick, axis++); break; case kHIDUsage_GD_Y: hid_store_element_data(element, HID_ELEMENT_AXIS_PRIMARY_Y, device, app, stick, axis++); break; case kHIDUsage_GD_Z: case kHIDUsage_GD_Rx: case kHIDUsage_GD_Ry: case kHIDUsage_GD_Rz: hid_store_element_data(element, HID_ELEMENT_AXIS, device,app, stick, axis++); break; case kHIDUsage_GD_Slider: case kHIDUsage_GD_Dial: case kHIDUsage_GD_Wheel: /* If we've already seen some axes on this stick, move to the next one */ if (axis > 0) { ++stick; axis=0; } hid_store_element_data(element, HID_ELEMENT_STANDALONE_AXIS, device, app, stick++, 0); break; case kHIDUsage_GD_Hatswitch: /* If we've already seen some axes on this stick, move to the next one */ if (axis > 0) { ++stick; axis=0; } hid_store_element_data(element, HID_ELEMENT_HAT, device, app, stick++, 0); break; } break; case kHIDPage_Button: hid_store_element_data(element, HID_ELEMENT_BUTTON, device, app, 0, usage-1); break; } } if (axis>=2) { ++stick; axis=0; } } } } } /* hid_scan_physical_collection: * scan the elements that make up one 'stick' */ static void hid_scan_physical_collection(CFTypeRef properties, HID_DEVICE *device, int app, int stick) { CFTypeRef array_ref, element; int type, usage_page, usage; int i; int axis=0; array_ref = CFDictionaryGetValue(properties, CFSTR(kIOHIDElementKey)); if ((array_ref) && (CFGetTypeID(array_ref) == CFArrayGetTypeID())) { for (i = 0; i < CFArrayGetCount(array_ref); i++) { element = CFArrayGetValueAtIndex(array_ref, i); if (CFGetTypeID(element) == CFDictionaryGetTypeID()) { type = i_val(element, CFSTR(kIOHIDElementTypeKey)); usage = i_val(element, CFSTR(kIOHIDElementUsageKey)); usage_page = i_val(element, CFSTR(kIOHIDElementUsagePageKey)); switch (usage_page) { case kHIDPage_GenericDesktop: switch (usage) { case kHIDUsage_GD_X: hid_store_element_data(element, HID_ELEMENT_AXIS_PRIMARY_X, device, app, stick, axis++); break; case kHIDUsage_GD_Y: hid_store_element_data(element, HID_ELEMENT_AXIS_PRIMARY_Y, device, app, stick, axis++); break; case kHIDUsage_GD_Z: case kHIDUsage_GD_Rx: case kHIDUsage_GD_Ry: case kHIDUsage_GD_Rz: hid_store_element_data(element, HID_ELEMENT_AXIS, device,app, stick, axis++); break; } break; case kHIDPage_Button: hid_store_element_data(element, HID_ELEMENT_BUTTON, device, app, 0, usage-1); break; } } } } } /* hid_scan_application_collection: * Scan the elements array; each element will be an 'application' * i.e. one joystick, gamepad or mouse * */ static void hid_scan_application_collection(CFMutableDictionaryRef properties, HID_DEVICE *device) { CFTypeRef array_ref, element; int usage, usage_page; int i; array_ref = CFDictionaryGetValue(properties, CFSTR(kIOHIDElementKey)); if ((array_ref) && (CFGetTypeID(array_ref) == CFArrayGetTypeID())) { for (i = 0; i < CFArrayGetCount(array_ref); i++) { element = CFArrayGetValueAtIndex(array_ref, i); if (CFGetTypeID(element) == CFDictionaryGetTypeID()) { usage=i_val(element, CFSTR(kIOHIDElementUsageKey)); usage_page=i_val(element, CFSTR(kIOHIDElementUsagePageKey)); switch (USAGE(usage_page, usage)) { case USAGE(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick): device->type=HID_JOYSTICK; hid_scan_application(element, device, device->cur_app); device->cur_app++; break; case USAGE(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad): device->type=HID_GAMEPAD; hid_scan_application(element, device, device->cur_app); device->cur_app++; break; case USAGE(kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse): device->type=HID_MOUSE; hid_scan_application(element, device, device->cur_app); device->cur_app++; break; } } } } } /* get_usb_properties: * Get a property dictionary from the USB plane. */ static CFMutableDictionaryRef get_usb_properties(io_object_t device) { io_registry_entry_t parent, grandparent; CFMutableDictionaryRef usb_properties = NULL; if (IORegistryEntryGetParentEntry(device, kIOServicePlane, &parent) == KERN_SUCCESS) { if (IORegistryEntryGetParentEntry(parent, kIOServicePlane, &grandparent) == KERN_SUCCESS) { IORegistryEntryCreateCFProperties (grandparent, &usb_properties, kCFAllocatorDefault, kNilOptions); IOObjectRelease(grandparent); } IOObjectRelease(parent); } return usb_properties; } #if OSX_HID_PSEUDO_SCAN /* * Pseudo scan - for development purposes, if someone has hardware * that isn't parsed by this code, you can ask them to dump _their_ scan * as a plist, then reload it here in order to debug it. */ HID_DEVICE_COLLECTION *_al_osx_hid_scan(int type, HID_DEVICE_COLLECTION* col) { HID_DEVICE* this_device; NSDictionary* properties = nil; NSString* filename; switch (type) { case HID_GAMEPAD: filename = @"gamepad.plist"; break; case HID_JOYSTICK: filename = @"joystick.plist"; break; case HID_MOUSE: filename = @"mouse.plist"; break; default: filename = nil; break; } if (filename != nil) properties = [NSDictionary dictionaryWithContentsOfFile:filename]; if (properties) { this_device = add_device(col); this_device->manufacturer = strdup([((NSString*) [properties objectForKey: @kIOHIDManufacturerKey]) lossyCString]); this_device->product = strdup([((NSString*) [properties objectForKey: @kIOHIDProductKey]) lossyCString]); hid_scan_application_collection((CFDictionaryRef) properties, this_device); [properties release]; } return col; } #else /* _get_matching_services: * get iterator for corresponding services */ static IOReturn _get_matching_services(mach_port_t master_port, int usage_page, int usage, io_iterator_t *hid_object_iterator) { CFMutableDictionaryRef class_dictionary = NULL; CFNumberRef usage_ref = NULL; CFNumberRef usage_page_ref = NULL; class_dictionary = IOServiceMatching(kIOHIDDeviceKey); if (class_dictionary) { /* Add key for device type to refine the matching dictionary. */ usage_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); usage_page_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage_page); CFDictionarySetValue(class_dictionary, CFSTR(kIOHIDDeviceUsageKey), usage_ref); CFDictionarySetValue(class_dictionary, CFSTR(kIOHIDDeviceUsagePageKey), usage_page_ref); } IOReturn result = IOServiceGetMatchingServices(master_port, class_dictionary, hid_object_iterator); if (usage_ref) CFRelease(usage_ref); if (usage_page_ref) CFRelease(usage_page_ref); return result; } /* _al_osx_hid_scan: * Scan the hid manager for devices of type 'type', * and append to the collection col */ HID_DEVICE_COLLECTION *_al_osx_hid_scan(int type, HID_DEVICE_COLLECTION* col) { ASSERT(col); HID_DEVICE *this_device; mach_port_t master_port = 0; io_iterator_t hid_object_iterator = 0; io_object_t hid_device = 0; int usage, usage_page; CFTypeRef type_ref; CFMutableDictionaryRef properties = NULL, usb_properties = NULL; IOCFPlugInInterface **plugin_interface = NULL; IOReturn result; const char *string; SInt32 score = 0; int error; usage_page = kHIDPage_GenericDesktop; switch (type) { case HID_MOUSE: usage = kHIDUsage_GD_Mouse; break; case HID_JOYSTICK: usage = kHIDUsage_GD_Joystick; break; case HID_GAMEPAD: usage=kHIDUsage_GD_GamePad; break; } result = IOMasterPort(bootstrap_port, &master_port); if (result == kIOReturnSuccess) { result = _get_matching_services(master_port, usage_page, usage, &hid_object_iterator); if ((type == HID_MOUSE) && (hid_object_iterator == IO_OBJECT_NULL)) { /* in case of a mouse, GD_Mouse must not be true but can also be a pointing device */ result = _get_matching_services(master_port, usage_page, kHIDUsage_GD_Pointer, &hid_object_iterator); } if ((result == kIOReturnSuccess) && (hid_object_iterator)) { /* Ok, we have a list of attached HID devices; scan them. */ while ((hid_device = IOIteratorNext(hid_object_iterator))!=0) { if ((IORegistryEntryCreateCFProperties(hid_device, &properties, kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS) && (properties != NULL)) { error = false; this_device = add_device(col); this_device->type = type; if (col->count==0) { this_device->cur_app=0; } else { this_device->cur_app=col->devices[col->count-1].cur_app; } /* * Mac OS X currently is not mirroring all USB properties * to HID page so need to look at USB device page also. */ usb_properties = get_usb_properties(hid_device); type_ref = CFDictionaryGetValue(properties, CFSTR(kIOHIDManufacturerKey)); if (!type_ref) type_ref = CFDictionaryGetValue(usb_properties, CFSTR("USB Vendor Name")); if ((type_ref) && (string = CFStringGetCStringPtr(type_ref, CFStringGetSystemEncoding()))) this_device->manufacturer = strdup(string); else this_device->manufacturer = NULL; type_ref = CFDictionaryGetValue(properties, CFSTR(kIOHIDProductKey)); if (!type_ref) type_ref = CFDictionaryGetValue(usb_properties, CFSTR("USB Product Name")); if ((type_ref) && (string = CFStringGetCStringPtr(type_ref, CFStringGetSystemEncoding()))) this_device->product = strdup(string); else this_device->product = NULL; type_ref = CFDictionaryGetValue(usb_properties, CFSTR("USB Address")); if ((type == HID_MOUSE) && (!type_ref)) { /* Not an USB mouse. Must be integrated trackpad: we report it as a single button mouse */ add_element(this_device)->type = HID_ELEMENT_BUTTON; } else { /* Scan for device elements */ this_device->num_elements = 0; hid_scan_application_collection(properties, this_device); } this_device->interface = NULL; if ((type == HID_JOYSTICK) || (type == HID_GAMEPAD)) { /* Joystick or gamepad device: create HID interface */ if (IOCreatePlugInInterfaceForService(hid_device, kIOHIDDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin_interface, &score) != kIOReturnSuccess) error = true; else { if ((*plugin_interface)->QueryInterface(plugin_interface, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void *)&(this_device->interface)) != S_OK) error = true; (*plugin_interface)->Release(plugin_interface); if ((*(this_device->interface))->open(this_device->interface, 0) != KERN_SUCCESS) error = true; } } if (error) { if (this_device->manufacturer) al_free(this_device->manufacturer); if (this_device->product) al_free(this_device->product); if (this_device->interface) (*(this_device->interface))->Release(this_device->interface); this_device->interface=NULL; --col->count; } CFRelease(properties); CFRelease(usb_properties); } } IOObjectRelease(hid_object_iterator); } mach_port_deallocate(mach_task_self(), master_port); } return col; } #endif /* add_device: * add a new device to a collection */ static HID_DEVICE* add_device(HID_DEVICE_COLLECTION* o) { HID_DEVICE* d; if (o->devices==NULL) { o->count=0; o->capacity=1; o->devices=al_malloc(o->capacity*sizeof(HID_DEVICE)); } if (o->count>=o->capacity) { o->capacity*=2; o->devices=al_realloc(o->devices, o->capacity*sizeof(HID_DEVICE)); } d=&o->devices[o->count]; memset(d, 0, sizeof(HID_DEVICE)); /* Chain onto the preceding app count */ if (o->count>0) d->cur_app = o->devices[o->count-1].cur_app; ++o->count; return d; } /* _al_osx_hid_free: * Release the memory taken up by a collection */ void _al_osx_hid_free(HID_DEVICE_COLLECTION *col) { HID_DEVICE *device; HID_ELEMENT *element; int i, j; for (i = 0; i < col->count; i++) { device = &col->devices[i]; if (device->manufacturer) al_free(device->manufacturer); if (device->product) al_free(device->product); for (j = 0; j < device->num_elements; j++) { element = &device->element[j]; if (element->name) al_free(element->name); } al_free(device->element); if (device->interface) { (*(device->interface))->close(device->interface); (*(device->interface))->Release(device->interface); } } al_free(col->devices); } /* Local variables: */ /* c-basic-offset: 3 */ /* indent-tabs-mode: nil */ /* End: */ allegro5-5.2.10.1/src/macosx/keybd.m000066400000000000000000000346361473414355200170310ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * MacOS X keyboard module. * * By Angelo Mottola. * * Based on Unix/X11 version by Michael Bukin. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_driver.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/platform/aintosx.h" #import #ifndef ALLEGRO_MACOSX #error Something is wrong with the makefile #endif /* Dictionary to translate OS X modifier codes to Allegro modifier codes * and key codes. */ static unsigned const int mod_info[5][3] = { { NSAlphaShiftKeyMask, ALLEGRO_KEYMOD_CAPSLOCK, ALLEGRO_KEY_CAPSLOCK }, { NSShiftKeyMask, ALLEGRO_KEYMOD_SHIFT, ALLEGRO_KEY_LSHIFT }, { NSControlKeyMask, ALLEGRO_KEYMOD_CTRL, ALLEGRO_KEY_LCTRL }, { NSAlternateKeyMask, ALLEGRO_KEYMOD_ALT, ALLEGRO_KEY_ALT }, { NSCommandKeyMask, ALLEGRO_KEYMOD_COMMAND, ALLEGRO_KEY_COMMAND } }; static bool osx_keyboard_init(void); static void osx_keyboard_exit(void); static ALLEGRO_KEYBOARD* osx_get_keyboard(void); static ALLEGRO_KEYBOARD keyboard; static ALLEGRO_KEYBOARD_STATE kbdstate; static UInt32 dead_key_state; /* translate_modifier_flags: * Translate a bitmask of OS X modifier flags to Allegro's modifier flags */ static int translate_modifier_flags(int osx_mods) { int allegro_mods = 0; int i; for (i = 0; i < 5; i++) { if (osx_mods & mod_info[i][0]) allegro_mods |= mod_info[i][1]; } return allegro_mods; } /* _al_osx_switch_keyboard_focus: * Handle a focus switch event. */ void _al_osx_switch_keyboard_focus(ALLEGRO_DISPLAY *dpy, bool switch_in) { _al_event_source_lock(&keyboard.es); if (switch_in) kbdstate.display = dpy; else kbdstate.display = NULL; _al_event_source_unlock(&keyboard.es); } static void _handle_key_press(ALLEGRO_DISPLAY* dpy, int unicode, int scancode, int modifiers, bool is_repeat) { _al_event_source_lock(&keyboard.es); { /* Generate the press event if necessary. */ if (_al_event_source_needs_to_generate_event(&keyboard.es)) { ALLEGRO_EVENT event; event.keyboard.type = ALLEGRO_EVENT_KEY_DOWN; event.keyboard.timestamp = al_get_time(); event.keyboard.display = dpy; event.keyboard.keycode = scancode; event.keyboard.unichar = 0; event.keyboard.modifiers = modifiers; event.keyboard.repeat = false; if (!is_repeat) { _al_event_source_emit_event(&keyboard.es, &event); } if (unicode != 0) { if (unicode < 0) { unicode = 0; } event.keyboard.type = ALLEGRO_EVENT_KEY_CHAR; event.keyboard.unichar = unicode; event.keyboard.modifiers = modifiers; event.keyboard.repeat = is_repeat; _al_event_source_emit_event(&keyboard.es, &event); } } } /* Maintain the kbdstate array. */ _AL_KEYBOARD_STATE_SET_KEY_DOWN(kbdstate, scancode); _al_event_source_unlock(&keyboard.es); } static void _handle_key_release(ALLEGRO_DISPLAY* dpy, int modifiers, int scancode) { _al_event_source_lock(&keyboard.es); { /* Generate the release event if necessary. */ if (_al_event_source_needs_to_generate_event(&keyboard.es)) { ALLEGRO_EVENT event; event.keyboard.type = ALLEGRO_EVENT_KEY_UP; event.keyboard.timestamp = al_get_time(); event.keyboard.display = dpy; event.keyboard.keycode = scancode; event.keyboard.unichar = 0; event.keyboard.modifiers = modifiers; _al_event_source_emit_event(&keyboard.es, &event); } } /* Maintain the kbdstate array. */ _AL_KEYBOARD_STATE_CLEAR_KEY_DOWN(kbdstate, scancode); _al_event_source_unlock(&keyboard.es); } /* Mac keycode to Allegro scancode conversion table */ static const int mac_to_scancode[128] = { /* 0x00 */ ALLEGRO_KEY_A, ALLEGRO_KEY_S, ALLEGRO_KEY_D, ALLEGRO_KEY_F, /* 0x04 */ ALLEGRO_KEY_H, ALLEGRO_KEY_G, ALLEGRO_KEY_Z, ALLEGRO_KEY_X, /* 0x08 */ ALLEGRO_KEY_C, ALLEGRO_KEY_V, ALLEGRO_KEY_BACKSLASH2, ALLEGRO_KEY_B, /* 0x0c */ ALLEGRO_KEY_Q, ALLEGRO_KEY_W, ALLEGRO_KEY_E, ALLEGRO_KEY_R, /* 0x10 */ ALLEGRO_KEY_Y, ALLEGRO_KEY_T, ALLEGRO_KEY_1, ALLEGRO_KEY_2, /* 0x14 */ ALLEGRO_KEY_3, ALLEGRO_KEY_4, ALLEGRO_KEY_6, ALLEGRO_KEY_5, /* 0x18 */ ALLEGRO_KEY_EQUALS, ALLEGRO_KEY_9, ALLEGRO_KEY_7, ALLEGRO_KEY_MINUS, /* 0x1c */ ALLEGRO_KEY_8, ALLEGRO_KEY_0, ALLEGRO_KEY_CLOSEBRACE, ALLEGRO_KEY_O, /* 0x20 */ ALLEGRO_KEY_U, ALLEGRO_KEY_OPENBRACE, ALLEGRO_KEY_I, ALLEGRO_KEY_P, /* 0x24 */ ALLEGRO_KEY_ENTER, ALLEGRO_KEY_L, ALLEGRO_KEY_J, ALLEGRO_KEY_QUOTE, /* 0x28 */ ALLEGRO_KEY_K, ALLEGRO_KEY_SEMICOLON, ALLEGRO_KEY_BACKSLASH, ALLEGRO_KEY_COMMA, /* 0x2c */ ALLEGRO_KEY_SLASH, ALLEGRO_KEY_N, ALLEGRO_KEY_M, ALLEGRO_KEY_FULLSTOP, /* 0x30 */ ALLEGRO_KEY_TAB, ALLEGRO_KEY_SPACE, ALLEGRO_KEY_BACKQUOTE, ALLEGRO_KEY_BACKSPACE, /* 0x34 */ ALLEGRO_KEY_ENTER, ALLEGRO_KEY_ESCAPE, 0, ALLEGRO_KEY_COMMAND, /* 0x38 */ ALLEGRO_KEY_LSHIFT, ALLEGRO_KEY_CAPSLOCK, ALLEGRO_KEY_ALT, ALLEGRO_KEY_LEFT, /* 0x3c */ ALLEGRO_KEY_RIGHT, ALLEGRO_KEY_DOWN, ALLEGRO_KEY_UP, 0, /* 0x40 */ 0, ALLEGRO_KEY_PAD_DELETE, 0, ALLEGRO_KEY_PAD_ASTERISK, /* 0x44 */ 0, ALLEGRO_KEY_PAD_PLUS, 0, ALLEGRO_KEY_NUMLOCK, /* 0x48 */ 0, 0, 0, ALLEGRO_KEY_PAD_SLASH, /* 0x4c */ ALLEGRO_KEY_PAD_ENTER,0, ALLEGRO_KEY_PAD_MINUS, 0, /* 0x50 */ 0, ALLEGRO_KEY_PAD_EQUALS, ALLEGRO_KEY_PAD_0, ALLEGRO_KEY_PAD_1, /* 0x54 */ ALLEGRO_KEY_PAD_2, ALLEGRO_KEY_PAD_3, ALLEGRO_KEY_PAD_4, ALLEGRO_KEY_PAD_5, /* 0x58 */ ALLEGRO_KEY_PAD_6, ALLEGRO_KEY_PAD_7, 0, ALLEGRO_KEY_PAD_8, /* 0x5c */ ALLEGRO_KEY_PAD_9, 0, 0, 0, /* 0x60 */ ALLEGRO_KEY_F5, ALLEGRO_KEY_F6, ALLEGRO_KEY_F7, ALLEGRO_KEY_F3, /* 0x64 */ ALLEGRO_KEY_F8, ALLEGRO_KEY_F9, 0, ALLEGRO_KEY_F11, /* 0x68 */ 0, ALLEGRO_KEY_PRINTSCREEN,0, ALLEGRO_KEY_SCROLLLOCK, /* 0x6c */ 0, ALLEGRO_KEY_F10, 0, ALLEGRO_KEY_F12, /* 0x70 */ 0, ALLEGRO_KEY_PAUSE, ALLEGRO_KEY_INSERT, ALLEGRO_KEY_HOME, /* 0x74 */ ALLEGRO_KEY_PGUP, ALLEGRO_KEY_DELETE, ALLEGRO_KEY_F4, ALLEGRO_KEY_END, /* 0x78 */ ALLEGRO_KEY_F2, ALLEGRO_KEY_PGDN, ALLEGRO_KEY_F1, ALLEGRO_KEY_LEFT, /* 0x7c */ ALLEGRO_KEY_RIGHT, ALLEGRO_KEY_DOWN, ALLEGRO_KEY_UP, 0 }; /* get_state: * Copy a snapshot of the keyboard state into the user's structure */ static void get_state(ALLEGRO_KEYBOARD_STATE *ret_state) { _al_event_source_lock(&keyboard.es); { memcpy(ret_state, &kbdstate, sizeof(ALLEGRO_KEYBOARD_STATE)); } _al_event_source_unlock(&keyboard.es); } /* clear_state: * Clear the keyboard state */ static void clear_state(void) { _al_event_source_lock(&keyboard.es); { memset(&kbdstate, 0, sizeof(kbdstate)); } _al_event_source_unlock(&keyboard.es); } static ALLEGRO_KEYBOARD_DRIVER keyboard_macosx = { KEYBOARD_MACOSX, "", "", "MacOS X keyboard", osx_keyboard_init, osx_keyboard_exit, osx_get_keyboard, NULL, // ALLEGRO_METHOD(bool, set_leds, (int leds)); NULL, // ALLEGRO_METHOD(const char *, keycode_to_name, (int keycode)); get_state, clear_state, }; _AL_DRIVER_INFO _al_keyboard_driver_list[] = { { KEYBOARD_MACOSX, &keyboard_macosx, 1 }, { 0, NULL, 0 } }; /* _al_osx_get_keyboard_driver: * Returns the keyboard driver. */ ALLEGRO_KEYBOARD_DRIVER* _al_osx_get_keyboard_driver(void) { return &keyboard_macosx; } /* _al_osx_keyboard_handler: * Keyboard "interrupt" handler. */ void _al_osx_keyboard_handler(int pressed, NSEvent *event, ALLEGRO_DISPLAY* dpy) { /* We need to distinguish between the raw character code (needed for * ctrl and alt) and the "shifted" character code when neither of these * is held down. This is needed to get the correct behavior when caps * lock is on (ie, letters are upper case) */ int scancode = mac_to_scancode[[event keyCode]]; /* Translate OS X modifier flags to Allegro modifier flags */ int key_shifts = translate_modifier_flags([event modifierFlags]); if (pressed) { int32_t unichar = 0; bool new_input = _al_get_keyboard_compat_version() >= AL_ID(5, 2, 10, 0); NSString *characters = [event characters]; UniChar character = ([characters length] > 0) ? [characters characterAtIndex: 0] : 0; if (new_input) { /* https://stackoverflow.com/a/22677690 */ TISInputSourceRef keyboard_input = TISCopyCurrentKeyboardInputSource(); CFDataRef layout_data = TISGetInputSourceProperty(keyboard_input, kTISPropertyUnicodeKeyLayoutData); const UCKeyboardLayout *layout = (const UCKeyboardLayout *)CFDataGetBytePtr(layout_data); CGEventFlags modifier_flags = [event modifierFlags]; UInt32 modifier_key_state = (modifier_flags >> 16) & 0xff; UniChar unicode_string[5]; unicode_string[4] = 0; UniCharCount unicode_length; UCKeyTranslate(layout, [event keyCode], kUCKeyActionDown, modifier_key_state, LMGetKbdType(), 0, &dead_key_state, 4, &unicode_length, unicode_string); if (unicode_length > 0) { ALLEGRO_USTR *ustr = al_ustr_new_from_utf16(unicode_string); /* TODO: Possibly add an option to emit multiple events here. * At the moment, we take the last key, because when an invalid * dead key combination is entered, unicode string contains a character * representaiton of the dead key + the last pressed key. * We opt to return the last pressed key. */ unichar = al_ustr_get(ustr, al_ustr_offset(ustr, (int)unicode_length - 1)); if (unichar < 0) unichar = 0; /* For some reason, pad enter sends a ^C. */ else if (scancode == ALLEGRO_KEY_PAD_ENTER && unichar == 3) unichar = '\r'; /* This is here to override the Ctrl/Cmd fixes for backspace. */ else if (scancode == ALLEGRO_KEY_BACKSPACE) unichar = '\b'; /* For some reason, Ctrl- sends capital version of the character, and not the correct invisible character. */ else if (key_shifts & ALLEGRO_KEYMOD_CTRL) unichar = character; /* For some reason, Cmd- converts characters to Ctrl-. */ else if (key_shifts & ALLEGRO_KEYMOD_COMMAND) unichar = character; al_ustr_free(ustr); } CFRelease(keyboard_input); } else unichar = character; /* Apple maps function, arrow, and other keys to Unicode points. https://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT We want to generate CHAR events for them, so we'll override the translation logic. _handle_key_press will set the unichar back to 0 for these keys. */ if (character >= 0xF700 && character <= 0xF747) { /* The old input did not handle this key (delete) correctly. We preserve the old behavior. */ if (new_input && character == 0xF728) unichar = 127; else unichar = -1; } bool is_repeat = pressed ? ([event isARepeat] == YES) : false; _handle_key_press(dpy, unichar, scancode, key_shifts, is_repeat); } else { _handle_key_release(dpy, key_shifts, scancode); } } /* _al_osx_keyboard_modifier: * Handles keyboard modifiers changes. */ void _al_osx_keyboard_modifiers(unsigned int modifiers, ALLEGRO_DISPLAY* dpy) { static unsigned int old_modifiers = 0; int i, changed; int key_shifts; /* Translate OS X modifier flags to Allegro modifier flags */ key_shifts = translate_modifier_flags(modifiers); for (i = 0; i < 5; i++) { changed = (modifiers ^ old_modifiers) & mod_info[i][0]; if (changed) { if (modifiers & mod_info[i][0]) { _handle_key_press(dpy, 0, mod_info[i][2], key_shifts, false); if (i == 0) { /* Caps lock requires special handling */ _handle_key_release(dpy, key_shifts, mod_info[0][2]); } } else { if (i == 0) { _handle_key_press(dpy, 0, mod_info[0][2], key_shifts, false); } _handle_key_release(dpy, key_shifts, mod_info[i][2]); } } } old_modifiers = modifiers; } /* osx_keyboard_init: * Installs the keyboard handler. */ static bool osx_keyboard_init(void) { memset(&keyboard, 0, sizeof keyboard); _al_osx_keyboard_was_installed(YES); _al_event_source_init(&keyboard.es); return true; } /* osx_keyboard_exit: * Removes the keyboard handler. */ static void osx_keyboard_exit(void) { _al_event_source_free(&keyboard.es); _al_osx_keyboard_was_installed(NO); } /* osx_get_keyboard: * Returns the keyboard object. */ static ALLEGRO_KEYBOARD* osx_get_keyboard(void) { return &keyboard; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/macosx/osx_app_delegate.m000066400000000000000000000255561473414355200212370ustar00rootroot00000000000000 #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/platform/aintosx.h" #ifdef __LP64__ /* FIXME: the following prototype and enum definition appear to needed in * 64 bit mode on 10.5 (Leopard). Apple's documentation indicates that * "deprecated features" are not available in 64 bit, but * UpdateSystemActivity is not deprecated and the documentation likewise * suggests that all that should be required is to #include CoreServices.h * or Power.h. However, this does not appear to work... for now, this * should work ok. * On 10.6 (Snow Leopard) these defines cause a problem, so they are * disabled. */ extern OSErr UpdateSystemActivity(uint8_t activity); #if 0 enum { OverallAct = 0, /* Delays idle sleep by small amount */ UsrActivity = 1, /* Delays idle sleep and dimming by timeout time */ NetActivity = 2, /* Delays idle sleep and power cycling by small amount */ HDActivity = 3, /* Delays hard drive spindown and idle sleep by small amount */ IdleActivity = 4 /* Delays idle sleep by timeout time */ }; #endif #endif extern NSBundle *_al_osx_bundle; /* For compatibility with the unix code */ static int __crt0_argc; static char **__crt0_argv; static int (*user_main)(int, char **); static char *arg0, *arg1 = NULL; static BOOL in_bundle(void) { /* This comes from the ADC tips & tricks section: how to detect if the app * lives inside a bundle */ FSRef processRef; ProcessSerialNumber psn = { 0, kCurrentProcess }; FSCatalogInfo processInfo; GetProcessBundleLocation(&psn, &processRef); FSGetCatalogInfo(&processRef, kFSCatInfoNodeFlags, &processInfo, NULL, NULL, NULL); if (processInfo.nodeFlags & kFSNodeIsDirectoryMask) return YES; else return NO; } @interface AllegroAppDelegate : NSObject { NSTimer* activity; } - (void) dealloc; - (BOOL)application: (NSApplication *)theApplication openFile: (NSString *)filename; - (void)applicationDidFinishLaunching: (NSNotification *)aNotification; - (void)applicationDidChangeScreenParameters: (NSNotification *)aNotification; + (void)app_main: (id)arg; - (NSApplicationTerminateReply) applicationShouldTerminate: (id)sender; - (void) updateSystemActivity:(NSTimer*) timer; - (void) setInhibitScreenSaver: (NSNumber*) inhibit; @end @interface AllegroWindowDelegate : NSObject - (BOOL)windowShouldClose: (id)sender; - (void)windowDidDeminiaturize: (NSNotification *)aNotification; @end @implementation AllegroAppDelegate /* setInhibitScreenSaver: * If inhibit is YES, set up an infrequent timer to call * updateSystemActivity: to prevent the screen saver from activating * Must be called from the main thread (osx_inhibit_screensaver ensures * this) * Has no effect if inhibit is YES and the timer is already active * or if inhibit is NO and the timer is not active */ -(void) setInhibitScreenSaver: (NSNumber *) inhibit { if ([inhibit boolValue] == YES) { if (activity == nil) { // Schedule every 30 seconds activity = [NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(updateSystemActivity:) userInfo:nil repeats:YES]; [activity retain]; } // else already active } else { // OK to send message to nil if timer wasn't set. [activity invalidate]; [activity release]; activity = nil; } } /* updateSystemActivity: * called by a timer to inform the system that there is still activity and * therefore do not dim the screen/start the screensaver */ -(void) updateSystemActivity: (NSTimer*) timer { (void)timer; UpdateSystemActivity(UsrActivity); } -(void) dealloc { [activity invalidate]; [activity release]; [super dealloc]; } - (BOOL)application: (NSApplication *)theApplication openFile: (NSString *)filename { NSData* data = [filename dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; (void)theApplication; if (data != nil) { unsigned int len = 1 + [data length]; arg1 = al_malloc(len); memset(arg1, 0, len); #if MAC_OS_X_VERSION_MIN_REQUIRED >= 110000 [data getBytes: arg1 length:len]; #else [data getBytes: arg1]; #endif return YES; } else { return NO; } } /* applicationDidFinishLaunching: * Called when the app is ready to run. */ - (void)applicationDidFinishLaunching: (NSNotification *)aNotification { NSString* exename, *resdir; NSFileManager* fm; BOOL isDir; (void)aNotification; if (in_bundle() == YES) { /* In a bundle, so chdir to the containing directory, * or to the 'magic' resource directory if it exists. * (see the readme.osx file for more info) */ _al_osx_bundle = [NSBundle mainBundle]; exename = [[_al_osx_bundle executablePath] lastPathComponent]; resdir = [[_al_osx_bundle resourcePath] stringByAppendingPathComponent: exename]; fm = [NSFileManager defaultManager]; if ([fm fileExistsAtPath: resdir isDirectory: &isDir] && isDir) { /* Yes, it exists inside the bundle */ [fm changeCurrentDirectoryPath: resdir]; } else { /* No, change to the 'standard' OSX resource directory if it exists*/ if ([fm fileExistsAtPath: [_al_osx_bundle resourcePath] isDirectory: &isDir] && isDir) { [fm changeCurrentDirectoryPath: [_al_osx_bundle resourcePath]]; } /* It doesn't exist - this is unusual for a bundle. Don't chdir */ } arg0 = strdup([[_al_osx_bundle bundlePath] fileSystemRepresentation]); if (arg1) { static char *args[2]; args[0] = arg0; args[1] = arg1; __crt0_argv = args; __crt0_argc = 2; } else { __crt0_argv = &arg0; __crt0_argc = 1; } } /* else: not in a bundle so don't chdir */ [NSThread detachNewThreadSelector: @selector(app_main:) toTarget: [AllegroAppDelegate class] withObject: nil]; return; } /* applicationDidChangeScreenParameters: * Invoked when the screen did change resolution/color depth. */ - (void)applicationDidChangeScreenParameters: (NSNotification *)aNotification { /* no-op */ (void)aNotification; } /* Call the user main() */ static void call_user_main(void) { exit(user_main(__crt0_argc, __crt0_argv)); } /* app_main: * Thread dedicated to the user program; real main() gets called here. */ + (void)app_main: (id)arg { (void)arg; call_user_main(); } /* applicationShouldTerminate: * Called upon Command-Q or "Quit" menu item selection. * Post a message but do not quit directly */ - (NSApplicationTerminateReply) applicationShouldTerminate: (id)sender { (void)sender; _al_osx_post_quit(); return NSTerminateCancel; } /* end of AllegroAppDelegate implementation */ @end /* This prevents warnings that 'NSApplication might not * respond to setAppleMenu' on OS X 10.4+ */ @interface NSApplication(AllegroOSX) - (void)setAppleMenu:(NSMenu *)menu; @end /* Helper macro to add entries to the menu */ #define add_menu(name, sel, eq) \ [menu addItem: [[[NSMenuItem alloc] \ initWithTitle: name \ action: @selector(sel) \ keyEquivalent: eq] autorelease]] \ int _al_osx_run_main(int argc, char **argv, int (*real_main)(int, char **)) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; AllegroAppDelegate *app_delegate = [[AllegroAppDelegate alloc] init]; NSMenu *menu; NSMenuItem *temp_item; user_main = real_main; __crt0_argc = argc; __crt0_argv = argv; #ifdef OSX_BOOTSTRAP_DETECTION if (!_al_osx_bootstrap_ok()) /* not safe to use NSApplication */ call_user_main(); #endif [NSApplication sharedApplication]; /* Load the main menu nib if possible */ if ((!in_bundle()) || ([NSBundle loadNibNamed: @"MainMenu" owner: NSApp] == NO)) { /* Didn't load the nib; create a default menu programmatically */ NSString* title = nil; NSDictionary* app_dictionary = [[NSBundle mainBundle] infoDictionary]; if (app_dictionary) { title = [app_dictionary objectForKey: @"CFBundleName"]; } if (title == nil) { title = [[NSProcessInfo processInfo] processName]; } NSMenu* main_menu = [[NSMenu alloc] initWithTitle: @""]; [NSApp setMainMenu: main_menu]; /* Add application ("Apple") menu */ menu = [[NSMenu alloc] initWithTitle: @"Apple menu"]; temp_item = [[NSMenuItem alloc] initWithTitle: @"" action: NULL keyEquivalent: @""]; [main_menu addItem: temp_item]; [main_menu setSubmenu: menu forItem: temp_item]; [temp_item release]; add_menu([@"Hide " stringByAppendingString: title], hide:, @"h"); add_menu(@"Hide Others", hideOtherApplications:, @""); add_menu(@"Show All", unhideAllApplications:, @""); [menu addItem: [NSMenuItem separatorItem]]; add_menu([@"Quit " stringByAppendingString: title], terminate:, @"q"); [NSApp setAppleMenu: menu]; [menu release]; /* Add "Window" menu */ menu = [[NSMenu alloc] initWithTitle: @"Window"]; temp_item = [[NSMenuItem alloc] initWithTitle: @"" action: NULL keyEquivalent: @""]; [main_menu addItem: temp_item]; [main_menu setSubmenu: menu forItem: temp_item]; [temp_item release]; /* Add menu entries */ add_menu(@"Minimize", performMiniaturize:, @"M"); add_menu(@"Bring All to Front", arrangeInFront:, @""); [NSApp setWindowsMenu:menu]; [menu release]; [main_menu release]; } // setDelegate: doesn't retain the delegate here (a Cocoa convention) // therefore we don't release it. [NSApp setDelegate: app_delegate]; [pool drain]; [NSApp run]; /* Can never get here */ [app_delegate release]; return 0; } allegro5-5.2.10.1/src/macosx/osxclipboard.m000066400000000000000000000075601473414355200204200ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * MacOS X clipboard handling. * * By Beoran. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_driver.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/internal/aintern_osxclipboard.h" #include "allegro5/platform/aintosx.h" #include "./osxgl.h" #ifndef ALLEGRO_MACOSX #error Something is wrong with the makefile #endif /* Ensure that we have the right version number available. */ #ifndef NSAppKitVersionNumber10_6 #define NSAppKitVersionNumber10_6 1038 #endif static NSString *osx_get_text_format(ALLEGRO_DISPLAY *display) { (void) display; #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 return NSStringPboardType; #else /* This is now the preferred way of version checking, Gestalt has been deprecated. */ if ( floor(NSAppKitVersionNumber) < NSAppKitVersionNumber10_6 ) { return NSPasteboardTypeString; } else { return NSStringPboardType; } #endif } static bool osx_set_clipboard_text(ALLEGRO_DISPLAY *display, const char *text) { NSAutoreleasePool *pool; NSPasteboard *pasteboard; NSString *format = osx_get_text_format(display); BOOL ok; pool = [[NSAutoreleasePool alloc] init]; if (!pool) return false; pasteboard = [NSPasteboard generalPasteboard]; if (!pasteboard) return false; /* First clear the clipboard, otherwise the setString will fail. */ [pasteboard clearContents]; ok = [pasteboard setString:[NSString stringWithUTF8String:text] forType:format]; [pool release]; return ok == YES; } static char * osx_get_clipboard_text(ALLEGRO_DISPLAY *display) { NSAutoreleasePool *pool; NSPasteboard *pasteboard; NSString *format = osx_get_text_format(display); NSString *available; char *text; pool = [[NSAutoreleasePool alloc] init]; pasteboard = [NSPasteboard generalPasteboard]; available = [pasteboard availableTypeFromArray: [NSArray arrayWithObject:format]]; if ([available isEqualToString:format]) { NSString* string; const char *utf8; string = [pasteboard stringForType:format]; if (string == nil) { text = NULL; } else { size_t size; utf8 = [string UTF8String]; size = strlen(utf8); text = al_malloc(size+1); text = _al_sane_strncpy(text, utf8, size+1); } } else { text = NULL; } [pool release]; return text; } static bool osx_has_clipboard_text(ALLEGRO_DISPLAY *display) { NSAutoreleasePool *pool; NSPasteboard *pasteboard; NSString *format = osx_get_text_format(display); NSString *available; bool result = false; pool = [[NSAutoreleasePool alloc] init]; pasteboard = [NSPasteboard generalPasteboard]; available = [pasteboard availableTypeFromArray: [NSArray arrayWithObject:format]]; if ([available isEqualToString:format]) { NSString* string; string = [pasteboard stringForType:format]; if (string != nil) { result = true; } } [pool release]; return result; } void _al_osx_add_clipboard_functions(ALLEGRO_DISPLAY_INTERFACE *vt) { vt->set_clipboard_text = osx_set_clipboard_text; vt->get_clipboard_text = osx_get_clipboard_text; vt->has_clipboard_text = osx_has_clipboard_text; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/macosx/osxgl.h000066400000000000000000000027431473414355200170540ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/platform/aintosx.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/opengl/gl_ext.h" /* Number of pixel format attributes we can set */ #define AL_OSX_NUM_PFA 64 @interface ALWindow : NSWindow { ALLEGRO_DISPLAY* display; } @property ALLEGRO_DISPLAY *display; @end /* This is our version of ALLEGRO_DISPLAY with driver specific extra data. */ typedef struct ALLEGRO_DISPLAY_OSX_WIN { ALLEGRO_DISPLAY parent; int depth; NSOpenGLContext* ctx; NSOpenGLPixelFormatAttribute attributes[AL_OSX_NUM_PFA]; ALWindow* win; NSView* view; NSCursor* cursor; CGDirectDisplayID display_id; BOOL show_cursor; NSTrackingArea *tracking; unsigned int display_group; BOOL in_fullscreen; BOOL single_buffer; CGDisplayModeRef original_mode; BOOL send_halt_events; ALLEGRO_MUTEX *halt_mutex; ALLEGRO_COND *halt_cond; BOOL halt_event_acknowledged; /* For new (10.14+) vsyncing. */ CVDisplayLinkRef display_link; ALLEGRO_MUTEX *flip_mutex; ALLEGRO_COND *flip_cond; int num_flips; /* These two store the old window size when restoring from a FS window. */ int old_w; int old_h; } ALLEGRO_DISPLAY_OSX_WIN; /* This is our version of ALLEGRO_MOUSE_CURSOR */ typedef struct ALLEGRO_MOUSE_CURSOR_OSX { NSCursor *cursor; } ALLEGRO_MOUSE_CURSOR_OSX; allegro5-5.2.10.1/src/macosx/osxgl.m000066400000000000000000002601251473414355200170610ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * MacOS X OpenGL gfx driver * * By Peter Hull. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_osxclipboard.h" #include "allegro5/platform/aintosx.h" #include "./osxgl.h" #include "allegro5/allegro_osx.h" #ifndef ALLEGRO_MACOSX #error something is wrong with the makefile #endif #import #import ALLEGRO_DEBUG_CHANNEL("MacOSX") /* Many Cocoa methods can only be called from the main thread, but Allegro runs the user's code on a separate thread or threads. It relies on `dispatch_sync` or `[NSObject performSelectorOnMainThread:withObject:waitUntilDone:]` to make sure the operation happens on the main thread. Comments on functions in this file indicate their thread requirements, if any. #define EXTRA_THREAD_CHECKS to catch any issues during development (don't leave it defined though.) */ #undef EXTRA_THREAD_CHECKS #ifdef EXTRA_THREAD_CHECKS #define ASSERT_MAIN_THREAD() NSCAssert([NSThread isMainThread], @"Must be run on main thread") #define ASSERT_USER_THREAD() NSCAssert(![NSThread isMainThread], @"Must be run on user thread") #else #define ASSERT_MAIN_THREAD() #define ASSERT_USER_THREAD() #endif /* This constant isn't available on OS X < 10.7, define * it here so the library can be built on < 10.7 (10.6 * tested so far.) */ #if (MAC_OS_X_VERSION_MAX_ALLOWED < 1070 && !defined(NSWindowCollectionBehaviorFullScreenPrimary)) enum { NSWindowCollectionBehaviorFullScreenPrimary = (1 << 7) }; #endif /* Defines */ #define MINIMUM_WIDTH 48 #define MINIMUM_HEIGHT 48 /* Unsigned integer; data type only avaliable for OS X >= 10.5 */ #if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 typedef unsigned int NSUInteger; #endif /* Module Variables */ static BOOL _osx_mouse_installed = NO, _osx_keyboard_installed = NO; static NSPoint last_window_pos; static unsigned int next_display_group = 1; /* The parameters are passed to initialiseDisplay manually, as it runs * in a separate thread which renders TLS values incorrect. */ typedef struct OSX_DISPLAY_PARAMS { ALLEGRO_DISPLAY_OSX_WIN* dpy; int new_window_pos_x; int new_window_pos_y; int new_display_adapter; /* A copy of the new window title. */ char* new_window_title; } _OSX_DISPLAY_PARAMS; /* Dictionary to map Allegro's DISPLAY_OPTIONS to OS X * PixelFormatAttributes. * The first column is Allegro's name, the second column is the OS X * PixelFormatAttribute (or 0), the third column indicates whether we * need an extra parameter or not (eg, colour depth). */ static const unsigned int allegro_to_osx_settings[][3] = { { ALLEGRO_RED_SIZE, 0, 0}, // Not supported per component { ALLEGRO_GREEN_SIZE, 0, 0}, // Not supported per component { ALLEGRO_BLUE_SIZE, 0, 0}, // Not supported per component { ALLEGRO_ALPHA_SIZE, NSOpenGLPFAAlphaSize, 1}, { ALLEGRO_RED_SHIFT, 0, 0}, // Not available { ALLEGRO_GREEN_SHIFT, 0, 0}, // Not available { ALLEGRO_BLUE_SHIFT, 0, 0}, // Not available { ALLEGRO_ALPHA_SHIFT, 0, 0}, // Not available { ALLEGRO_ACC_RED_SIZE, NSOpenGLPFAAccumSize, 1}, // Correct? { ALLEGRO_ACC_GREEN_SIZE, NSOpenGLPFAAccumSize, 1}, // Correct? { ALLEGRO_ACC_BLUE_SIZE, NSOpenGLPFAAccumSize, 1}, // Correct? { ALLEGRO_ACC_ALPHA_SIZE, NSOpenGLPFAAccumSize, 1}, // Correct? { ALLEGRO_STEREO, NSOpenGLPFAStereo, 0}, { ALLEGRO_AUX_BUFFERS, NSOpenGLPFAAuxBuffers, 1}, { ALLEGRO_COLOR_SIZE, NSOpenGLPFAColorSize, 1}, { ALLEGRO_DEPTH_SIZE, NSOpenGLPFADepthSize, 1}, { ALLEGRO_STENCIL_SIZE, NSOpenGLPFAStencilSize, 1}, { ALLEGRO_SAMPLE_BUFFERS, NSOpenGLPFASampleBuffers, 1}, { ALLEGRO_SAMPLES, NSOpenGLPFASamples, 1}, //{ ALLEGRO_RENDER_METHOD, NSOpenGLPFAAccelerated, 0}, handled separately { ALLEGRO_FLOAT_COLOR, NSOpenGLPFAColorFloat, 0}, { ALLEGRO_FLOAT_DEPTH, 0, 0}, //{ ALLEGRO_SINGLE_BUFFER , 0, 0}, handled separately { ALLEGRO_SWAP_METHOD, 0, 0}, { ALLEGRO_COMPATIBLE_DISPLAY, 0, 0}, { ALLEGRO_DISPLAY_OPTIONS_COUNT, 0, 0} }; static const int number_of_settings = sizeof(allegro_to_osx_settings)/sizeof(*allegro_to_osx_settings); static const char *allegro_pixel_format_names[] = { "ALLEGRO_RED_SIZE", "ALLEGRO_GREEN_SIZE", "ALLEGRO_BLUE_SIZE", "ALLEGRO_ALPHA_SIZE", "ALLEGRO_RED_SHIFT", "ALLEGRO_GREEN_SHIFT", "ALLEGRO_BLUE_SHIFT", "ALLEGRO_ALPHA_SHIFT", "ALLEGRO_ACC_RED_SIZE", "ALLEGRO_ACC_GREEN_SIZE", "ALLEGRO_ACC_BLUE_SIZE", "ALLEGRO_ACC_ALPHA_SIZE", "ALLEGRO_STEREO", "ALLEGRO_AUX_BUFFERS", "ALLEGRO_COLOR_SIZE", "ALLEGRO_DEPTH_SIZE", "ALLEGRO_STENCIL_SIZE", "ALLEGRO_SAMPLE_BUFFERS", "ALLEGRO_SAMPLES", "ALLEGRO_RENDER_METHOD", "ALLEGRO_FLOAT_COLOR", "ALLEGRO_FLOAT_DEPTH", "ALLEGRO_SINGLE_BUFFER", "ALLEGRO_SWAP_METHOD", "ALLEGRO_COMPATIBLE_DISPLAY", "ALLEGRO_DISPLAY_OPTIONS_COUNT" }; /* Module functions */ ALLEGRO_DISPLAY_INTERFACE* _al_osx_get_display_driver(void); ALLEGRO_DISPLAY_INTERFACE* _al_osx_get_display_driver_win(void); ALLEGRO_DISPLAY_INTERFACE* _al_osx_get_display_driver_fs(void); static NSOpenGLContext* osx_create_shareable_context(NSOpenGLPixelFormat* fmt, unsigned int* group); static bool set_display_flag(ALLEGRO_DISPLAY *display, int flag, bool onoff); static bool resize_display_win(ALLEGRO_DISPLAY *d, int w, int h); static bool resize_display_win_main_thread(ALLEGRO_DISPLAY *d, int w, int h); static void clear_to_black(NSOpenGLContext *context) { /* Clear and flush (for double buffering) */ glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); [context flushBuffer]; glClear(GL_COLOR_BUFFER_BIT); } static NSTrackingArea *create_tracking_area(NSView *view) { NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate | NSTrackingActiveAlways; return [[NSTrackingArea alloc] initWithRect:[view bounds] options:options owner:view userInfo:nil]; } /* _al_osx_change_cursor: * Actually change the current cursor. This can be called fom any thread * but ensures that the change is only called from the main thread. */ static void _al_osx_change_cursor(ALLEGRO_DISPLAY_OSX_WIN *dpy, NSCursor* cursor) { NSCursor* old = dpy->cursor; dpy->cursor = [cursor retain]; [old release]; if (dpy->show_cursor) [cursor performSelectorOnMainThread: @selector(set) withObject: nil waitUntilDone: NO]; } /* _al_osx_keyboard_was_installed: * Called by the keyboard driver when the driver is installed or uninstalled. * Set the variable so we can decide to pass events or not. */ void _al_osx_keyboard_was_installed(BOOL install) { _osx_keyboard_installed = install; } /* The main additions to this view are event-handling functions */ #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 @interface ALOpenGLView : NSOpenGLView #else @interface ALOpenGLView : NSOpenGLView #endif { /* This is passed onto the event functions so we know where the event came from */ ALLEGRO_DISPLAY* dpy_ptr; } -(void)setAllegroDisplay: (ALLEGRO_DISPLAY*) ptr; -(ALLEGRO_DISPLAY*) allegroDisplay; -(void) reshape; -(BOOL) acceptsFirstResponder; -(void) keyDown:(NSEvent*) event; -(void) keyUp:(NSEvent*) event; -(void) flagsChanged:(NSEvent*) event; -(void) mouseDown: (NSEvent*) evt; -(void) mouseUp: (NSEvent*) evt; -(void) mouseDragged: (NSEvent*) evt; -(void) rightMouseDown: (NSEvent*) evt; -(void) rightMouseUp: (NSEvent*) evt; -(void) rightMouseDragged: (NSEvent*) evt; -(void) otherMouseDown: (NSEvent*) evt; -(void) otherMouseUp: (NSEvent*) evt; -(void) otherMouseDragged: (NSEvent*) evt; -(void) mouseMoved: (NSEvent*) evt; -(void) cursorUpdate: (NSEvent*) evt; -(void) scrollWheel: (NSEvent*) evt; -(void) viewDidMoveToWindow; -(void) viewWillMoveToWindow: (NSWindow*) newWindow; -(void) mouseEntered: (NSEvent*) evt; -(void) mouseExited: (NSEvent*) evt; -(void) viewWillStartLiveResize; -(void) viewDidEndLiveResize; /* Window delegate methods */ -(void) windowDidBecomeMain:(NSNotification*) notification; -(void) windowDidResignMain:(NSNotification*) notification; -(void) windowDidResize:(NSNotification*) notification; -(void) enterFullScreenWindowMode; -(void) exitFullScreenWindowMode; -(void) finishExitingFullScreenWindowMode; -(void) maximize; -(NSRect) windowWillUseStandardFrame: (NSWindow *) window defaultFrame: (NSRect) newFrame; @end @implementation ALWindow @synthesize display; -(BOOL) canBecomeKeyWindow { return YES; } // main thread only -(void) zoom:(id)sender { self.display->flags ^= ALLEGRO_MAXIMIZED; [super zoom:sender]; } @end /* _al_osx_mouse_was_installed: * Called by the mouse driver when the driver is installed or uninstalled. * Set the variable so we can decide to pass events or not, and notify all * existing displays that they need to set up their tracking areas. * User thread only */ void _al_osx_mouse_was_installed(BOOL install) { ASSERT_USER_THREAD(); if (_osx_mouse_installed == install) { // done it already return; } _osx_mouse_installed = install; _AL_VECTOR* dpys = &al_get_system_driver()->displays; dispatch_sync(dispatch_get_main_queue(), ^{ unsigned int i; for (i = 0; i < _al_vector_size(dpys); ++i) { ALLEGRO_DISPLAY_OSX_WIN* dpy = *(ALLEGRO_DISPLAY_OSX_WIN**) _al_vector_ref(dpys, i); NSWindow* window = dpy->win; if (window) { [window setAcceptsMouseMovedEvents: _osx_mouse_installed]; } } }); } @implementation ALOpenGLView -(void) prepareOpenGL { [super prepareOpenGL]; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if ([self respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) { [self setWantsBestResolutionOpenGLSurface:YES]; } #endif } /* setDisplay: * Set the display this view is associated with */ -(void) setAllegroDisplay: (ALLEGRO_DISPLAY*) ptr { dpy_ptr = ptr; } /* display * return the display this view is associated with */ -(ALLEGRO_DISPLAY*) allegroDisplay { return dpy_ptr; } /* reshape * Called when the view changes size */ - (void) reshape { [super reshape]; ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; if (dpy->tracking) { [self removeTrackingArea: dpy->tracking]; dpy->tracking = create_tracking_area(self); [self addTrackingArea: dpy->tracking]; } } /* acceptsFirstResponder * Overridden to return YES, so that * this view will receive events */ -(BOOL) acceptsFirstResponder { return YES; } /* Keyboard event handler */ -(void) keyDown:(NSEvent*) event { if (_osx_keyboard_installed) _al_osx_keyboard_handler(true, event, dpy_ptr); } -(void) keyUp:(NSEvent*) event { if (_osx_keyboard_installed) _al_osx_keyboard_handler(false, event, dpy_ptr); } -(void) flagsChanged:(NSEvent*) event { if (_osx_keyboard_installed) { _al_osx_keyboard_modifiers([event modifierFlags], dpy_ptr); } } /* Mouse handling */ -(void) mouseDown: (NSEvent*) evt { if (_osx_mouse_installed) _al_osx_mouse_generate_event(evt, dpy_ptr); } -(void) mouseUp: (NSEvent*) evt { if (_osx_mouse_installed) _al_osx_mouse_generate_event(evt, dpy_ptr); } -(void) mouseDragged: (NSEvent*) evt { if (_osx_mouse_installed) _al_osx_mouse_generate_event(evt, dpy_ptr); } -(void) rightMouseDown: (NSEvent*) evt { if (_osx_mouse_installed) _al_osx_mouse_generate_event(evt, dpy_ptr); } -(void) rightMouseUp: (NSEvent*) evt { if (_osx_mouse_installed) _al_osx_mouse_generate_event(evt, dpy_ptr); } -(void) rightMouseDragged: (NSEvent*) evt { if (_osx_mouse_installed) _al_osx_mouse_generate_event(evt, dpy_ptr); } -(void) otherMouseDown: (NSEvent*) evt { if (_osx_mouse_installed) _al_osx_mouse_generate_event(evt, dpy_ptr); } -(void) otherMouseUp: (NSEvent*) evt { if (_osx_mouse_installed) _al_osx_mouse_generate_event(evt, dpy_ptr); } -(void) otherMouseDragged: (NSEvent*) evt { if (_osx_mouse_installed) _al_osx_mouse_generate_event(evt, dpy_ptr); } -(void) mouseMoved: (NSEvent*) evt { if (_osx_mouse_installed) _al_osx_mouse_generate_event(evt, dpy_ptr); } -(void) cursorUpdate: (NSEvent*) evt { if (_osx_mouse_installed) { ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; _al_osx_change_cursor(dpy, dpy->cursor); } } -(void) scrollWheel: (NSEvent*) evt { if (_osx_mouse_installed) _al_osx_mouse_generate_event(evt, dpy_ptr); } /* Cursor handling */ - (void) viewDidMoveToWindow { ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; if (dpy->tracking) { [self removeTrackingArea: dpy->tracking]; } dpy->tracking = create_tracking_area(self); [self addTrackingArea: dpy->tracking]; } - (void) viewWillMoveToWindow: (NSWindow*) newWindow { ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; (void)newWindow; if (([self window] != nil) && (dpy->tracking != 0)) { [self removeTrackingArea:dpy->tracking]; dpy->tracking = 0; } } -(void) mouseEntered: (NSEvent*) evt { ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; ALLEGRO_EVENT_SOURCE* src = &([self allegroDisplay]->es); if (dpy->show_cursor) { [dpy->cursor set]; } else { [NSCursor hide]; } _al_event_source_lock(src); _al_osx_switch_mouse_focus(dpy_ptr, true); _al_event_source_unlock(src); _al_osx_mouse_generate_event(evt, dpy_ptr); } -(void) mouseExited: (NSEvent*) evt { ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; ALLEGRO_EVENT_SOURCE* src = &([self allegroDisplay]->es); if (!dpy->show_cursor) { [NSCursor unhide]; } _al_event_source_lock(src); _al_osx_switch_mouse_focus(dpy_ptr, false); _al_event_source_unlock(src); _al_osx_mouse_generate_event(evt, dpy_ptr); } /* windowShouldClose: * Veto the close and post a message */ - (BOOL)windowShouldClose:(id)sender { (void)sender; ALLEGRO_EVENT_SOURCE* src = &([self allegroDisplay]->es); _al_event_source_lock(src); ALLEGRO_EVENT evt; evt.type = ALLEGRO_EVENT_DISPLAY_CLOSE; _al_event_source_emit_event(src, &evt); _al_event_source_unlock(src); return NO; } #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1074 -(void) viewDidChangeBackingProperties { [super viewDidChangeBackingProperties]; if (!(al_get_display_flags(dpy_ptr) & ALLEGRO_RESIZABLE) && dpy_ptr->ogl_extras) { resize_display_win_main_thread(dpy_ptr, al_get_display_width(dpy_ptr), al_get_display_height(dpy_ptr)); } else { ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; NSWindow *window = dpy->win; NSRect rc = [window frame]; NSRect content = [window contentRectForFrameRect: rc]; content = [self convertRectToBacking: content]; ALLEGRO_EVENT_SOURCE *es = &dpy->parent.es; _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_RESIZE; event.display.timestamp = al_get_time(); event.display.width = NSWidth(content); event.display.height = NSHeight(content); _al_event_source_emit_event(es, &event); ALLEGRO_INFO("Window finished resizing %d x %d\n", event.display.width, event.display.height); } _al_event_source_unlock(es); } } #endif -(void) viewWillStartLiveResize { ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; ALLEGRO_EVENT_SOURCE *es = &dpy->parent.es; if (dpy->send_halt_events) { al_lock_mutex(dpy->halt_mutex); dpy->halt_event_acknowledged = false; al_unlock_mutex(dpy->halt_mutex); _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_HALT_DRAWING; event.display.timestamp = al_get_time(); _al_event_source_emit_event(es, &event); } _al_event_source_unlock(es); al_lock_mutex(dpy->halt_mutex); while (!dpy->halt_event_acknowledged) { al_wait_cond(dpy->halt_cond, dpy->halt_mutex); } al_unlock_mutex(dpy->halt_mutex); } } -(void) viewDidEndLiveResize { [super viewDidEndLiveResize]; ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; NSWindow *window = dpy->win; NSRect rc = [window frame]; NSRect content = [window contentRectForFrameRect: rc]; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 content = [self convertRectToBacking: content]; #endif ALLEGRO_EVENT_SOURCE *es = &dpy->parent.es; _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_RESIZE; event.display.timestamp = al_get_time(); event.display.width = NSWidth(content); event.display.height = NSHeight(content); _al_event_source_emit_event(es, &event); ALLEGRO_INFO("Window finished resizing %d x %d\n", event.display.width, event.display.height); if (dpy->send_halt_events) { event.display.type = ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING; _al_event_source_emit_event(es, &event); } } _al_event_source_unlock(es); dpy->old_w = NSWidth(content); dpy->old_h = NSWidth(content); } /* Window switch in/out */ -(void) windowDidBecomeMain:(NSNotification*) notification { (void)notification; ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; ALLEGRO_EVENT_SOURCE* src = &([self allegroDisplay]->es); _al_event_source_lock(src); ALLEGRO_EVENT evt; evt.type = ALLEGRO_EVENT_DISPLAY_SWITCH_IN; _al_event_source_emit_event(src, &evt); _al_osx_switch_keyboard_focus(dpy_ptr, true); _al_event_source_unlock(src); _al_osx_change_cursor(dpy, dpy->cursor); } -(void) windowDidResignMain:(NSNotification*) notification { (void)notification; ALLEGRO_EVENT_SOURCE* src = &([self allegroDisplay]->es); _al_event_source_lock(src); ALLEGRO_EVENT evt; evt.type = ALLEGRO_EVENT_DISPLAY_SWITCH_OUT; _al_event_source_emit_event(src, &evt); _al_osx_switch_keyboard_focus(dpy_ptr, false); _al_event_source_unlock(src); } -(void) windowDidResize:(NSNotification*) notification { (void)notification; ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; NSWindow *window = dpy->win; NSRect rc = [window frame]; NSRect content = [window contentRectForFrameRect: rc]; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 content = [self convertRectToBacking: content]; #endif ALLEGRO_EVENT_SOURCE *es = &dpy->parent.es; /* Restore max. constraints when the window has been un-maximized. * Note: isZoomed will return false in FullScreen mode. */ if (dpy_ptr->use_constraints && !(dpy_ptr->flags & ALLEGRO_FULLSCREEN_WINDOW) && ![window isZoomed]) { float scale_factor = 1.0; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if ([window respondsToSelector:@selector(backingScaleFactor)]) { scale_factor = [window backingScaleFactor]; } #endif NSSize max_size; max_size.width = (dpy_ptr->max_w > 0) ? dpy_ptr->max_w / scale_factor : FLT_MAX; max_size.height = (dpy_ptr->max_h > 0) ? dpy_ptr->max_h / scale_factor : FLT_MAX; [window setContentMaxSize: max_size]; } _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_RESIZE; event.display.timestamp = al_get_time(); event.display.width = NSWidth(content); event.display.height = NSHeight(content); _al_event_source_emit_event(es, &event); ALLEGRO_INFO("Window was resized %d x %d\n", event.display.width, event.display.height); } _al_event_source_unlock(es); } -(void)windowWillEnterFullScreen:(NSNotification *)notification { (void)notification; ALLEGRO_DISPLAY *display = dpy_ptr; display->flags |= ALLEGRO_FULLSCREEN_WINDOW; } -(void)windowWillExitFullScreen:(NSNotification *)notification { (void)notification; ALLEGRO_DISPLAY *display = dpy_ptr; display->flags &= ~ALLEGRO_FULLSCREEN_WINDOW; } -(void) enterFullScreenWindowMode { #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 ALLEGRO_DISPLAY_OSX_WIN *dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; int flags = NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar; [dict setObject:[NSNumber numberWithInt: flags] forKey:NSFullScreenModeApplicationPresentationOptions]; /* HACK? For some reason, we need to disable the chrome. If we don't, the fullscreen window will be created with space left over for it. Are we creating a fullscreen window in the wrong way? */ [dpy->win setStyleMask: [dpy->win styleMask] & ~NSWindowStyleMaskTitled]; [dpy->view enterFullScreenMode: [dpy->win screen] withOptions: dict]; [dict release]; #endif } /* Toggles maximize state. In OSX 10.10 this is the same as double clicking the title bar. */ -(void) maximize { ALLEGRO_DISPLAY_OSX_WIN *dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; [dpy->win performZoom: nil]; } /* Called by NSWindow's zoom: method while determining the frame * a window may be zoomed to. * We use it to update max. constraints values when the window changes * its maximized state. */ -(NSRect) windowWillUseStandardFrame: (NSWindow *) window defaultFrame: (NSRect) newFrame { NSSize max_size; if (dpy_ptr->use_constraints) { if (dpy_ptr->flags & ALLEGRO_MAXIMIZED) { max_size.width = FLT_MAX; max_size.height = FLT_MAX; newFrame.size.width = max_size.width; newFrame.size.height = max_size.height; } else { float scale_factor = 1.0; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if ([window respondsToSelector:@selector(backingScaleFactor)]) { scale_factor = [window backingScaleFactor]; } #endif max_size.width = (dpy_ptr->max_w > 0) ? dpy_ptr->max_w / scale_factor : FLT_MAX; max_size.height = (dpy_ptr->max_h > 0) ? dpy_ptr->max_h / scale_factor : FLT_MAX; } [window setContentMaxSize: max_size]; } return newFrame; } -(void) exitFullScreenWindowMode { ALLEGRO_DISPLAY_OSX_WIN *dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; /* Going from a fullscreen window to a smaller window, the mouse may end up outside * the window when it was inside before (not possible the other way.) This causes a * crash. To avoid it, remove the tracking area and add it back after exiting fullscreen. * (my theory) */ [dpy->win orderOut: dpy->view]; [self exitFullScreenModeWithOptions: nil]; /* Restore the title bar disabled in enterFullScreenWindowMode. */ if (!(dpy_ptr->flags & ALLEGRO_FRAMELESS)) { [dpy->win setStyleMask: [dpy->win styleMask] | NSWindowStyleMaskTitled]; } } -(void) finishExitingFullScreenWindowMode { ALLEGRO_DISPLAY_OSX_WIN *dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy_ptr; [dpy->win center]; [dpy->win makeKeyAndOrderFront: dpy->view]; [[self window] makeFirstResponder: self]; } /* End of ALOpenGLView implementation */ @end /* set_current_display: * Set the current windowed display to be current. */ static bool set_current_display(ALLEGRO_DISPLAY* d) { ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) d; if (dpy->ctx != nil) { [dpy->ctx makeCurrentContext]; } _al_ogl_set_extensions(d->ogl_extras->extension_api); return true; } /* Helper to set up GL state as we want it. */ static void setup_gl(ALLEGRO_DISPLAY *d) { ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) d; [dpy->ctx performSelectorOnMainThread:@selector(update) withObject:nil waitUntilDone:YES]; _al_ogl_setup_gl(d); } /* Fills the array of NSOpenGLPixelFormatAttributes, which has a specfied * maximum size, with the options appropriate for the display. */ static void osx_set_opengl_pixelformat_attributes(ALLEGRO_DISPLAY_OSX_WIN *dpy) { int i, n; bool want_double_buffer; NSOpenGLPixelFormatAttribute *a; ALLEGRO_EXTRA_DISPLAY_SETTINGS *extras; /* The following combination of flags indicates that multi-sampling is * requested. */ const int sample_flags = (1<attributes, 0, AL_OSX_NUM_PFA*sizeof(*dpy->attributes)); /* We normally want a double buffer */ want_double_buffer = true; /* Begin with the first attribute */ a = dpy->attributes; /* First, check the display flags, so we know if we want a fullscreen * mode or a windowed mode. */ if (dpy->parent.flags & ALLEGRO_FULLSCREEN) { *a = NSOpenGLPFAFullScreen; a++; // Take over the screen. *a = NSOpenGLPFAScreenMask; a++; *a = CGDisplayIDToOpenGLDisplayMask(dpy->display_id); a++; } else { *a = NSOpenGLPFAWindow; a++; } /* Find the requested colour depth */ if (extras) dpy->depth = extras->settings[ALLEGRO_COLOR_SIZE]; if (!dpy->depth) { /* Use default */ NSScreen *screen; int adapter = al_get_new_display_adapter(); if ((adapter >= 0) && (adapter < al_get_num_video_adapters())) { screen = [[NSScreen screens] objectAtIndex: adapter]; } else { screen = [NSScreen mainScreen]; } dpy->depth = NSBitsPerPixelFromDepth([screen depth]); if (dpy->depth == 24) dpy->depth = 32; if (dpy->depth == 15) dpy->depth = 16; ALLEGRO_DEBUG("Using default colour depth %d\n", dpy->depth); } *a = NSOpenGLPFAColorSize; a++; *a = dpy->depth; a++; /* Say we don't need an exact match for the depth of the colour buffer. * FIXME: right now, this is set whenever nothing is required or * something is suggested. Probably need finer control over this... */ if (!extras || !(extras->required) || extras->suggested) { *a = NSOpenGLPFAClosestPolicy; a++; } /* Should we set double buffering? If it's not required we don't care * and go with the default. */ if (extras && (extras->required & (1 << ALLEGRO_SINGLE_BUFFER)) && extras->settings[ALLEGRO_SINGLE_BUFFER]) { want_double_buffer = false; dpy->single_buffer = true; } if (want_double_buffer) { *a = NSOpenGLPFADoubleBuffer; a++; } /* Detect if multi-sampling is requested */ /* Or "NSOpenGLPFASupersample" ? */ if (extras && (extras->required & sample_flags) && (extras->settings[ALLEGRO_SAMPLES]||extras->settings[ALLEGRO_SAMPLE_BUFFERS])) { *a = NSOpenGLPFAMultisample; a++; } /* Now go through all other options, if set */ for (n = 0; n < number_of_settings; n++) { i = allegro_to_osx_settings[n][0]; if (allegro_to_osx_settings[n][1] && extras && ((extras->required & (1 << i)) || (extras->suggested & (1 << i)))) { /* Need to distinguish between boolean attributes and settings that * require a value. */ if (allegro_to_osx_settings[n][2]) { /* Value */ /* We must make sure the value is non-zero because the list are * building is 0-terminated. */ if (extras->settings[i]) { *a = allegro_to_osx_settings[n][1]; a++; *a = extras->settings[i]; a++; ALLEGRO_DEBUG("Passing pixel format attribute %s = %d\n", allegro_pixel_format_names[n], extras->settings[i]); } } else if (extras->settings[i]) { /* Boolean, just turn this on */ *a = allegro_to_osx_settings[n][1]; a++; ALLEGRO_DEBUG("Passing pixel format attribute %s = %d\n", allegro_pixel_format_names[n], extras->settings[i]); } } } /* Accelerated is always preferred, so we only set this for required not * for suggested. */ if (extras->required & ALLEGRO_RENDER_METHOD) { *a++ = NSOpenGLPFAAccelerated; } } /* Set the extra_settings[] array in the display, to report which options * we have selected. */ static void osx_get_opengl_pixelformat_attributes(ALLEGRO_DISPLAY_OSX_WIN *dpy) { int n; if (!dpy) return; /* Clear list of settings (none selected) */ memset(&dpy->parent.extra_settings, 0, sizeof(dpy->parent.extra_settings)); #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 /* Get the pixel format associated with the OpenGL context. * We use the Carbon API rather than the Cocoa API because that way we * can use the same code in Windowed mode as in fullscreen mode (we * don't have an NSOpenGLView in fullscreen mode). */ CGLContextObj ctx = [dpy->ctx CGLContextObj]; CGLPixelFormatObj pixel_format = CGLGetPixelFormat(ctx); GLint screen_id; CGLGetVirtualScreen(ctx, &screen_id); ALLEGRO_DEBUG("Screen has ID %d\n", (int)screen_id); for (n = 0; n < number_of_settings; n++) { /* Go through the list of options and relist the ones that we have * set to Allegro's option list. */ CGLPixelFormatAttribute attrib = allegro_to_osx_settings[n][1]; /* Skip options that don't exist on OS X */ if (attrib == 0) continue; /* Get value for this attribute */ GLint value; CGLDescribePixelFormat(pixel_format, screen_id, attrib, &value); int al_setting = allegro_to_osx_settings[n][0]; if (allegro_to_osx_settings[n][2] == 0) /* Boolean attribute */ value = 1; dpy->parent.extra_settings.settings[al_setting] = value; ALLEGRO_DEBUG("Pixel format attribute %s set to %d\n", allegro_pixel_format_names[n], value); } #else /* CGLGetPixelFormat does not exist on Tiger, so we need to do something * else. * FIXME: right now, we just return the settings that were chosen by the * user. To be correct, we should query the pixelformat corresponding to * the display, using the NSOpenGLView pixelFormat method and the * NSOpenGLPixelFormat getValues:forAttribute:forVirtualScreen: method, * for which we need to know the logical screen number that the display * is on. That doesn't work for fullscreen modes though... */ NSOpenGLPixelFormatAttribute *attributes = dpy->attributes; for (n = 0; n < number_of_settings; n++) { /* Go through the list of options and relist the ones that we have * set to Allegro's option list. */ NSOpenGLPixelFormatAttribute *a = dpy->attributes; while (*a) { if (*a == allegro_to_osx_settings[n][1]) { int al_setting = allegro_to_osx_settings[n][0]; int value = 1; if (allegro_to_osx_settings[n][2]) value = a[1]; dpy->parent.extra_settings.settings[al_setting] = value; ALLEGRO_DEBUG("Setting pixel format attribute %d to %d\n", al_setting, value); } /* Advance to next option */ if (allegro_to_osx_settings[n][2]) /* Has a parameter in the list */ a++; a++; } } #endif dpy->parent.extra_settings.settings[ALLEGRO_COMPATIBLE_DISPLAY] = 1; // Fill in the missing colour format options, as best we can ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = &dpy->parent.extra_settings; if (eds->settings[ALLEGRO_COLOR_SIZE] == 0) { eds->settings[ALLEGRO_COLOR_SIZE] = 32; eds->settings[ALLEGRO_RED_SIZE] = 8; eds->settings[ALLEGRO_GREEN_SIZE] = 8; eds->settings[ALLEGRO_BLUE_SIZE] = 8; eds->settings[ALLEGRO_ALPHA_SIZE] = 8; eds->settings[ALLEGRO_RED_SHIFT] = 0; eds->settings[ALLEGRO_GREEN_SHIFT] = 8; eds->settings[ALLEGRO_BLUE_SHIFT] = 16; eds->settings[ALLEGRO_ALPHA_SHIFT] = 24; } else { int size = eds->settings[ALLEGRO_ALPHA_SIZE]; if (!size) { switch (eds->settings[ALLEGRO_COLOR_SIZE]) { case 32: size = 8; break; case 16: size = 5; break; case 8: size = 8; break; } } if (!eds->settings[ALLEGRO_RED_SIZE]) eds->settings[ALLEGRO_RED_SIZE] = size; if (!eds->settings[ALLEGRO_BLUE_SIZE]) eds->settings[ALLEGRO_BLUE_SIZE] = size; if (!eds->settings[ALLEGRO_GREEN_SIZE]) eds->settings[ALLEGRO_GREEN_SIZE] = size; if (!eds->settings[ALLEGRO_RED_SHIFT]) eds->settings[ALLEGRO_RED_SHIFT] = 0; if (!eds->settings[ALLEGRO_GREEN_SHIFT]) eds->settings[ALLEGRO_GREEN_SHIFT] = eds->settings[ALLEGRO_RED_SIZE]; if (!eds->settings[ALLEGRO_BLUE_SHIFT]) eds->settings[ALLEGRO_BLUE_SHIFT] = eds->settings[ALLEGRO_GREEN_SIZE]+eds->settings[ALLEGRO_GREEN_SHIFT]; if (!eds->settings[ALLEGRO_ALPHA_SHIFT]) eds->settings[ALLEGRO_ALPHA_SHIFT] = eds->settings[ALLEGRO_BLUE_SIZE]+eds->settings[ALLEGRO_BLUE_SHIFT]; } } /* This function must be run on the main thread */ static void osx_run_fullscreen_display(ALLEGRO_DISPLAY_OSX_WIN* dpy) { ASSERT_MAIN_THREAD(); ALLEGRO_DISPLAY* display = &dpy->parent; while (dpy->in_fullscreen) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; // Collect an event NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES]; // Process it as required. switch ([event type]) { case NSEventTypeKeyDown: _al_osx_keyboard_handler(true,event,display); break; case NSEventTypeKeyUp: _al_osx_keyboard_handler(false,event,display); break; case NSEventTypeFlagsChanged: _al_osx_keyboard_modifiers([event modifierFlags],display); break; case NSEventTypeLeftMouseDown: case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseDown: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseDown: case NSEventTypeOtherMouseUp: case NSEventTypeMouseMoved: case NSEventTypeLeftMouseDragged: case NSEventTypeRightMouseDragged: case NSEventTypeOtherMouseDragged: if (_osx_mouse_installed) _al_osx_mouse_generate_event(event, display); break; default: [NSApp sendEvent: event]; break; } [pool release]; } } /* osx_create_shareable_context: * * Create an NSOpenGLContext with a given pixel format. If possible, make * the context compatible with one that has already been created and * assigned to a display. If this can't be done, create an unshared one * (which may itself be shared in the future) * Each context is given a group number so that all shared contexts have the * same group number. * * Parameters: * fmt - The pixel format to use * group - Pointer to the assigned group for the new context * * Returns: * The new context or nil if it cannot be created. */ static NSOpenGLContext* osx_create_shareable_context(NSOpenGLPixelFormat* fmt, unsigned int* group) { // Iterate through all existing displays and try and find one that's compatible _AL_VECTOR* dpys = &al_get_system_driver()->displays; unsigned int i; NSOpenGLContext* compat = nil; for (i = 0; i < _al_vector_size(dpys); ++i) { ALLEGRO_DISPLAY_OSX_WIN* other = *(ALLEGRO_DISPLAY_OSX_WIN**) _al_vector_ref(dpys, i); compat = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext: other->ctx]; if (compat != nil) { // OK, we can share with this one *group = other->display_group; ALLEGRO_DEBUG("Sharing display group %d\n", *group); break; } } if (compat == nil) { // Set to a new group *group = next_display_group++; ALLEGRO_DEBUG("Creating new display group %d\n", *group); compat = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext: nil]; } return compat; } #ifndef NSAppKitVersionNumber10_7 #define NSAppKitVersionNumber10_7 1138 #endif static CVReturn display_link_callback(CVDisplayLinkRef display_link, const CVTimeStamp *now, const CVTimeStamp *output_time, CVOptionFlags flags_in, CVOptionFlags *flags_out, void *user_info) { (void)display_link; (void)now; (void)output_time; (void)flags_in; (void)flags_out; ALLEGRO_DISPLAY_OSX_WIN *dpy = (ALLEGRO_DISPLAY_OSX_WIN*)user_info; al_lock_mutex(dpy->flip_mutex); dpy->num_flips += 1; al_signal_cond(dpy->flip_cond); al_unlock_mutex(dpy->flip_mutex); return kCVReturnSuccess; } static void init_new_vsync(ALLEGRO_DISPLAY_OSX_WIN *dpy) { dpy->flip_cond = al_create_cond(); dpy->flip_mutex = al_create_mutex(); CVDisplayLinkCreateWithActiveCGDisplays(&dpy->display_link); CVDisplayLinkSetOutputCallback(dpy->display_link, &display_link_callback, dpy); CGLContextObj ctx = [dpy->ctx CGLContextObj]; CGLPixelFormatObj pixel_format = CGLGetPixelFormat(ctx); CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(dpy->display_link, ctx, pixel_format); CVDisplayLinkStart(dpy->display_link); } static void init_halt_events(ALLEGRO_DISPLAY_OSX_WIN *dpy) { const char* value = al_get_config_value(al_get_system_config(), "osx", "allow_live_resize"); if (value && strcmp(value, "false") == 0) { dpy->send_halt_events = true; } else { dpy->send_halt_events = false; } dpy->halt_mutex = al_create_mutex(); dpy->halt_cond = al_create_cond(); } /* create_display_fs: * Create a fullscreen display - capture the display */ static ALLEGRO_DISPLAY* create_display_fs(int w, int h) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; ALLEGRO_DEBUG("Switching to fullscreen mode sized %dx%d\n", w, h); #define IS_LION (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_7) if (al_get_new_display_adapter() >= al_get_num_video_adapters()) { [pool drain]; return NULL; } ALLEGRO_DISPLAY_OSX_WIN* dpy = al_malloc(sizeof(ALLEGRO_DISPLAY_OSX_WIN)); if (dpy == NULL) { [pool drain]; return NULL; } memset(dpy, 0, sizeof(*dpy)); ALLEGRO_DISPLAY* display = &dpy->parent; /* Set up the ALLEGRO_DISPLAY part */ display->vt = _al_osx_get_display_driver_fs(); display->refresh_rate = al_get_new_display_refresh_rate(); display->flags = al_get_new_display_flags() | ALLEGRO_OPENGL | ALLEGRO_FULLSCREEN; #ifdef ALLEGRO_CFG_OPENGLES2 display.flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; #endif #ifdef ALLEGRO_CFG_OPENGLES display.flags |= ALLEGRO_OPENGL_ES_PROFILE; #endif display->w = w; display->h = h; _al_event_source_init(&display->es); dpy->cursor = [[NSCursor arrowCursor] retain]; dpy->display_id = CGMainDisplayID(); init_halt_events(dpy); /* Get display ID for the requested display */ if (al_get_new_display_adapter() > 0) { int adapter = al_get_new_display_adapter(); NSScreen *screen = [[NSScreen screens] objectAtIndex: adapter]; NSDictionary *dict = [screen deviceDescription]; NSNumber *display_id = [dict valueForKey: @"NSScreenNumber"]; #if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 dpy->display_id = [display_id intValue]; #else dpy->display_id = [display_id integerValue]; #endif //dpy->display_id = (CGDirectDisplayID)[display_id pointerValue]; } // Set up a pixel format to describe the mode we want. osx_set_opengl_pixelformat_attributes(dpy); NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: dpy->attributes]; if (fmt == nil) { ALLEGRO_DEBUG("Could not set pixel format\n"); [pool drain]; return NULL; } // Create a context which shares with any other contexts with the same format NSOpenGLContext* context = osx_create_shareable_context(fmt, &dpy->display_group); [fmt release]; if (context == nil) { ALLEGRO_DEBUG("Could not create rendering context\n"); [pool drain]; return NULL; } dpy->ctx = context; // Prevent other apps from writing to this display and switch it to our // chosen mode. #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 CGDisplayCapture(dpy->display_id); CFDictionaryRef mode = CGDisplayBestModeForParametersAndRefreshRate(dpy->display_id, dpy->depth, w, h, display->refresh_rate, NULL); CGDisplaySwitchToMode(dpy->display_id, mode); #else CGDisplayModeRef mode = NULL; CFArrayRef modes = NULL; CFStringRef pixel_format = NULL; int i; /* Set pixel format string */ if (dpy->depth == 32) pixel_format = CFSTR(IO32BitDirectPixels); if (dpy->depth == 16) pixel_format = CFSTR(IO16BitDirectPixels); if (dpy->depth == 8) pixel_format = CFSTR(IO8BitIndexedPixels); modes = CGDisplayCopyAllDisplayModes(dpy->display_id, NULL); for (i = 0; i < CFArrayGetCount(modes); i++) { CGDisplayModeRef try_mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(try_mode); /* Found mode with matching size/colour depth */ if ( w == (int)CGDisplayModeGetWidth(try_mode) && h == (int)CGDisplayModeGetHeight(try_mode) && CFStringCompare(pixel_encoding, pixel_format, 1) == 0) { mode = try_mode; CFRelease(pixel_encoding); break; } /* Found mode with matching size; colour depth does not match, but * it's the best so far. */ if ( w == (int)CGDisplayModeGetWidth(try_mode) && h == (int)CGDisplayModeGetHeight(try_mode) && mode == NULL) { mode = try_mode; } CFRelease(pixel_encoding); } CFRelease(modes); if (!mode) { /* Trouble! - we can't find a nice mode to set. */ [dpy->ctx clearDrawable]; CGDisplayRelease(dpy->display_id); al_free(dpy); [pool drain]; return NULL; } /* Switch display mode */ dpy->original_mode = CGDisplayCopyDisplayMode(dpy->display_id); CGDisplayCapture(dpy->display_id); CGDisplaySetDisplayMode(dpy->display_id, mode, NULL); #endif NSRect rect = NSMakeRect(0, 0, w, h); NSString* title = [NSString stringWithUTF8String: al_get_new_window_title()]; dispatch_sync(dispatch_get_main_queue(), ^{ dpy->win = [[ALWindow alloc] initWithContentRect:rect styleMask:(IS_LION ? NSWindowStyleMaskBorderless : 0) backing:NSBackingStoreBuffered defer:NO]; [dpy->win setTitle: title]; [dpy->win setAcceptsMouseMovedEvents:YES]; [dpy->win setViewsNeedDisplay:NO]; NSView *window_view = [[NSView alloc] initWithFrame:rect]; [window_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; [[dpy->win contentView] addSubview:window_view]; [dpy->win setLevel:CGShieldingWindowLevel()]; [context setView:window_view]; [context update]; [window_view release]; [dpy->win setHasShadow:NO]; [dpy->win setOpaque:YES]; [dpy->win makeKeyAndOrderFront:nil]; }); // This is set per-thread [context makeCurrentContext]; // Set up the Allegro OpenGL implementation display->ogl_extras = al_malloc(sizeof(ALLEGRO_OGL_EXTRAS)); memset(display->ogl_extras, 0, sizeof(ALLEGRO_OGL_EXTRAS)); _al_ogl_manage_extensions(&dpy->parent); _al_ogl_set_extensions(dpy->parent.ogl_extras->extension_api); display->ogl_extras->is_shared = true; /* Retrieve the options that were set */ osx_get_opengl_pixelformat_attributes(dpy); /* Turn on vsyncing possibly. The old way doesn't work on new OSX's, but works better than the new way when it does work. */ #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 if (_al_get_new_display_settings()->settings[ALLEGRO_VSYNC] == 1) { init_new_vsync(dpy); } #else if (_al_get_new_display_settings()->settings[ALLEGRO_VSYNC] == 1) { GLint swapInterval = 1; [dpy->ctx setValues:&swapInterval forParameter: NSOpenGLCPSwapInterval]; } else { GLint swapInterval = 0; [dpy->ctx setValues:&swapInterval forParameter: NSOpenGLCPSwapInterval]; } #endif /* Set up GL as we want */ setup_gl(display); clear_to_black(dpy->ctx); /* Add to the display list */ ALLEGRO_DISPLAY **add = _al_vector_alloc_back(&al_get_system_driver()->displays); *add = display; dpy->in_fullscreen = YES; // Begin the 'private' event loop // Necessary because there's no NSResponder (i.e. a view) to collect // events from the window server. dispatch_sync(dispatch_get_main_queue(), ^{ osx_run_fullscreen_display(dpy); }); [pool drain]; _al_osx_tell_dock(); return &dpy->parent; } #if 0 /* Alternative, Cocoa-based mode switching. * Works, but I can't get the display to respond to a resize request * properly - EG */ static ALLEGRO_DISPLAY* create_display_fs(int w, int h) { ALLEGRO_DEBUG("Creating full screen mode sized %dx%d\n", w, h); if (al_get_new_display_adapter() >= al_get_num_video_adapters()) return NULL; ALLEGRO_DISPLAY_OSX_WIN* dpy = al_malloc(sizeof(ALLEGRO_DISPLAY_OSX_WIN)); if (dpy == NULL) { return NULL; } memset(dpy, 0, sizeof(*dpy)); /* Set up the ALLEGRO_DISPLAY part */ dpy->parent.vt = _al_osx_get_display_driver_win(); dpy->parent.refresh_rate = al_get_new_display_refresh_rate(); dpy->parent.flags = al_get_new_display_flags() | ALLEGRO_OPENGL | ALLEGRO_FULLSCREEN; #ifdef ALLEGRO_CFG_OPENGLES2 dpy->parent.flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; #endif #ifdef ALLEGRO_CFG_OPENGLES dpy->parent.flags |= ALLEGRO_OPENGL_ES_PROFILE; #endif dpy->parent.w = w; dpy->parent.h = h; _al_event_source_init(&dpy->parent.es); osx_change_cursor(dpy, [NSCursor arrowCursor]); dpy->show_cursor = YES; init_halt_events(dpy); // Set up a pixel format to describe the mode we want. osx_set_opengl_pixelformat_attributes(dpy); // Clear last window position to 0 if there are no other open windows if (_al_vector_is_empty(&al_get_system_driver()->displays)) { last_window_pos = NSZeroPoint; } /* OSX specific part - finish the initialisation on the main thread */ [ALDisplayHelper performSelectorOnMainThread: @selector(initialiseDisplay:) withObject: [NSValue valueWithPointer:dpy] waitUntilDone: YES]; [dpy->ctx makeCurrentContext]; [dpy->ctx setFullScreen]; NSScreen *screen = [dpy->win screen]; NSDictionary *dict = [screen deviceDescription]; NSNumber *display_id = [dict valueForKey: @"NSScreenNumber"]; dpy->display_id = [display_id integerValue]; //dpy->display_id = (CGDirectDisplayID)[display_id pointerValue]; CGDisplayCapture(dpy->display_id); #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 CFDictionaryRef mode = CGDisplayBestModeForParametersAndRefreshRate(dpy->display_id, dpy->depth, w, h, dpy->parent.refresh_rate, NULL); CGDisplaySwitchToMode(dpy->display_id, mode); #else CGDisplayModeRef mode = NULL; CFArrayRef modes = NULL; CFStringRef pixel_format = NULL; int i; /* Set pixel format string */ if (dpy->depth == 32) pixel_format = CFSTR(IO32BitDirectPixels); if (dpy->depth == 16) pixel_format = CFSTR(IO16BitDirectPixels); if (dpy->depth == 8) pixel_format = CFSTR(IO8BitIndexedPixels); modes = CGDisplayCopyAllDisplayModes(dpy->display_id, NULL); for (i = 0; i < CFArrayGetCount(modes); i++) { CGDisplayModeRef try_mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(try_mode); /* Found mode with matching size/colour depth */ if ( w == (int)CGDisplayModeGetWidth(try_mode) && h == (int)CGDisplayModeGetHeight(try_mode) && CFStringCompare(pixel_encoding, pixel_format, 1) == 0) { mode = try_mode; CFRelease(pixel_encoding); break; } /* Found mode with matching size; colour depth does not match, but * it's the best so far. */ if ( w == (int)CGDisplayModeGetWidth(try_mode) && h == (int)CGDisplayModeGetHeight(try_mode) && mode == NULL) { mode = try_mode; } CFRelease(pixel_encoding); } if (!mode) { /* Trouble! - we can't find a nice mode to set. */ [dpy->ctx clearDrawable]; CGDisplayRelease(dpy->display_id); [dpy->win close]; al_free(dpy); return NULL; } /* Switch display mode */ CFDictionaryRef options = CFDictionaryCreate(NULL, NULL, NULL, 0, NULL, NULL); CGDisplaySetDisplayMode(dpy->display_id, mode, NULL); CFRelease(options); CFRelease(modes); #endif [[dpy->win contentView] enterFullScreenMode: screen withOptions: nil]; // Set up the Allegro OpenGL implementation dpy->parent.ogl_extras = al_malloc(sizeof(ALLEGRO_OGL_EXTRAS)); memset(dpy->parent.ogl_extras, 0, sizeof(ALLEGRO_OGL_EXTRAS)); _al_ogl_manage_extensions(&dpy->parent); _al_ogl_set_extensions(dpy->parent.ogl_extras->extension_api); dpy->parent.ogl_extras->is_shared = true; /* Retrieve the options that were set */ osx_get_opengl_pixelformat_attributes(dpy); /* Turn on vsyncing possibly. The old way doesn't work on new OSX's, but works better than the new way when it does work. */ #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 if (_al_get_new_display_settings()->settings[ALLEGRO_VSYNC] == 1) { init_new_vsync(dpy); } #else if (_al_get_new_display_settings()->settings[ALLEGRO_VSYNC] == 1) { GLint swapInterval = 1; [dpy->ctx setValues:&swapInterval forParameter: NSOpenGLCPSwapInterval]; } else { GLint swapInterval = 0; [dpy->ctx setValues:&swapInterval forParameter: NSOpenGLCPSwapInterval]; } #endif /* Set up GL as we want */ setup_gl(&dpy->parent); clear_to_black(dpy->ctx); /* Add to the display list */ ALLEGRO_DISPLAY **add = _al_vector_alloc_back(&al_get_system_driver()->displays); *add = &dpy->parent; dpy->in_fullscreen = YES; return &dpy->parent; } #endif /* create_display_win: * Create a windowed display - create the window with an ALOpenGLView * to be its content view * Call from user thread. */ static ALLEGRO_DISPLAY* create_display_win(int w, int h) { ASSERT_USER_THREAD(); NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; /* Create a temporary view so that we can check whether a fullscreen * window can be created. */ if (al_get_new_display_flags() & ALLEGRO_FULLSCREEN_WINDOW) { __block BOOL ok; dispatch_sync(dispatch_get_main_queue(), ^{ NSRect rc = NSMakeRect(0, 0, w, h); ALOpenGLView* view = [[ALOpenGLView alloc] initWithFrame: rc]; ok = [view respondsToSelector: @selector(enterFullScreenMode:withOptions:)]; [view release]; }); if (!ok) { ALLEGRO_DEBUG("Cannot create FULLSCREEN_WINDOW"); return NULL; } } ALLEGRO_DEBUG("Creating window sized %dx%d\n", w, h); if (al_get_new_display_adapter() >= al_get_num_video_adapters()) { [pool drain]; return NULL; } ALLEGRO_DISPLAY_OSX_WIN* dpy = al_malloc(sizeof(ALLEGRO_DISPLAY_OSX_WIN)); if (dpy == NULL) { [pool drain]; return NULL; } memset(dpy, 0, sizeof(*dpy)); ALLEGRO_DISPLAY* display = &dpy->parent; /* Set up the ALLEGRO_DISPLAY part */ display->vt = _al_osx_get_display_driver_win(); display->refresh_rate = al_get_new_display_refresh_rate(); display->flags = al_get_new_display_flags() | ALLEGRO_OPENGL | ALLEGRO_WINDOWED; #ifdef ALLEGRO_CFG_OPENGLES2 display->flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; #endif #ifdef ALLEGRO_CFG_OPENGLES display->flags |= ALLEGRO_OPENGL_ES_PROFILE; #endif display->w = w; display->h = h; dpy->old_w = w; dpy->old_h = h; _al_event_source_init(&display->es); _al_osx_change_cursor(dpy, [NSCursor arrowCursor]); dpy->show_cursor = YES; init_halt_events(dpy); // Set up a pixel format to describe the mode we want. osx_set_opengl_pixelformat_attributes(dpy); // Clear last window position to 0 if there are no other open windows if (_al_vector_is_empty(&al_get_system_driver()->displays)) { last_window_pos = NSZeroPoint; } /* Get the new window position. This is stored in TLS, so we need to do * this before calling initialise_display, which runs on a different * thread. */ int x, y; int adapter = al_get_new_display_adapter(); const char* title = al_get_new_window_title(); al_get_new_window_position(&x, &y); /* OSX specific part - finish the initialisation on the main thread */ dispatch_sync(dispatch_get_main_queue(), ^{ NSRect rc = NSMakeRect(0, 0, w, h); ALWindow *alwin = dpy->win = [ALWindow alloc]; NSWindow* win = alwin; NSScreen *screen; unsigned int mask = (display->flags & ALLEGRO_FRAMELESS) ? NSWindowStyleMaskBorderless : (NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskMiniaturizable); if (display->flags & ALLEGRO_RESIZABLE) mask |= NSWindowStyleMaskResizable; if (display->flags & ALLEGRO_FULLSCREEN) mask |= NSWindowStyleMaskResizable; if ((adapter >= 0) && (adapter < al_get_num_video_adapters())) { screen = [[NSScreen screens] objectAtIndex: adapter]; } else { screen = [NSScreen mainScreen]; } float screen_scale_factor = 1.0; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if ([screen respondsToSelector:@selector(backingScaleFactor)]) { screen_scale_factor = [screen backingScaleFactor]; } #endif rc.size.width /= screen_scale_factor; rc.size.height /= screen_scale_factor; [win initWithContentRect: rc styleMask: mask backing: NSBackingStoreBuffered defer: NO screen: screen ]; alwin.display = (ALLEGRO_DISPLAY *)dpy; if (display->flags & ALLEGRO_RESIZABLE) { if ([win respondsToSelector:NSSelectorFromString(@"setCollectionBehavior:")]) { [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; } } NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: dpy->attributes]; ALOpenGLView* view = [[ALOpenGLView alloc] initWithFrame: rc]; dpy->ctx = osx_create_shareable_context(fmt, &dpy->display_group); if (dpy->ctx == nil) { ALLEGRO_DEBUG("Could not create rendering context\n"); [view release]; [fmt release]; return; } dpy->view = view; /* Hook up the view to its display */ [view setAllegroDisplay: &dpy->parent]; [view setOpenGLContext: dpy->ctx]; [view setPixelFormat: fmt]; /* Realize the window on the main thread */ [win setContentView: view]; [win setDelegate: view]; [win setReleasedWhenClosed: YES]; [win setAcceptsMouseMovedEvents: _osx_mouse_installed]; [win setTitle: [NSString stringWithUTF8String: title]]; /* Set minimum size, otherwise the window can be resized so small we can't * grab the handle any more to make it bigger */ [win setMinSize: NSMakeSize(MINIMUM_WIDTH / screen_scale_factor, MINIMUM_HEIGHT / screen_scale_factor)]; /* Maximize the window and update its width & height information */ if (display->flags & ALLEGRO_MAXIMIZED) { [win setFrame: [screen visibleFrame] display: true animate: false]; NSRect content = [win contentRectForFrameRect: [win frame]]; display->w = content.size.width; display->h = content.size.height; } /* Place the window, respecting the location set by the user with * al_set_new_window_position(). * If the user never called al_set_new_window_position, we simply let * the window manager pick a suitable location. * * CAUTION: the window manager under OS X requires that x and y be in * the range -16000 ... 16000 (approximately, probably the range of a * signed 16 bit integer). Should we check for this? */ if ((x != INT_MAX) && (y != INT_MAX)) { /* The user gave us window coordinates */ NSRect rc = [win frame]; NSPoint origin; int primary_y = _al_osx_get_primary_screen_y(); /* We need to modify the y coordinate, cf. set_window_position */ origin.x = x / screen_scale_factor; origin.y = primary_y / screen_scale_factor - rc.size.height - y / screen_scale_factor; [win setFrameOrigin: origin]; } else { [win center]; } [win makeKeyAndOrderFront:nil]; if (mask != NSWindowStyleMaskBorderless) { [win makeMainWindow]; } [fmt release]; [view release]; if (display->flags & ALLEGRO_FULLSCREEN_WINDOW) { NSRect sc = [[dpy->win screen] frame]; dpy->parent.w = sc.size.width; dpy->parent.h = sc.size.height; } }); [dpy->ctx makeCurrentContext]; /* Print out OpenGL version info */ ALLEGRO_INFO("OpenGL Version: %s\n", glGetString(GL_VERSION)); ALLEGRO_INFO("Vendor: %s\n", glGetString(GL_VENDOR)); ALLEGRO_INFO("Renderer: %s\n", glGetString(GL_RENDERER)); /* Set up a pixel format to describe the mode we want. */ osx_set_opengl_pixelformat_attributes(dpy); /* Retrieve the options that were set */ // Note: This initializes dpy->extra_settings osx_get_opengl_pixelformat_attributes(dpy); // Set up the Allegro OpenGL implementation display->ogl_extras = al_malloc(sizeof(ALLEGRO_OGL_EXTRAS)); memset(display->ogl_extras, 0, sizeof(ALLEGRO_OGL_EXTRAS)); _al_ogl_manage_extensions(display); _al_ogl_set_extensions(display->ogl_extras->extension_api); display->ogl_extras->is_shared = true; /* Turn on vsyncing possibly. The old way doesn't work on new OSX's, but works better than the new way when it does work. */ #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 if (_al_get_new_display_settings()->settings[ALLEGRO_VSYNC] == 1) { init_new_vsync(dpy); } #else if (_al_get_new_display_settings()->settings[ALLEGRO_VSYNC] == 1) { GLint swapInterval = 1; [dpy->ctx setValues:&swapInterval forParameter: NSOpenGLCPSwapInterval]; } else { GLint swapInterval = 0; [dpy->ctx setValues:&swapInterval forParameter: NSOpenGLCPSwapInterval]; } #endif /* Set up GL as we want */ setup_gl(display); clear_to_black(dpy->ctx); /* Add to the display list */ ALLEGRO_DISPLAY **add = _al_vector_alloc_back(&al_get_system_driver()->displays); *add = display; dpy->in_fullscreen = NO; if (display->flags & ALLEGRO_FULLSCREEN_WINDOW) { display->flags ^= ALLEGRO_FULLSCREEN_WINDOW; /* Not set yet */ set_display_flag(display, ALLEGRO_FULLSCREEN_WINDOW, true); } [pool drain]; _al_osx_tell_dock(); return display; } /* destroy_display: * Destroy display, actually close the window or exit fullscreen on the main thread * Called from user thread */ static void destroy_display(ALLEGRO_DISPLAY* d) { ASSERT_USER_THREAD(); NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; ALLEGRO_DISPLAY *old_dpy = al_get_current_display(); ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) d; ALLEGRO_DISPLAY_OSX_WIN* other = NULL; unsigned int i; // Set the display as the current display; needed because we need to // make the context current. if (old_dpy != d) { _al_set_current_display_only(d); } /* First of all, save video bitmaps attached to this display. */ // Check for other displays in this display group _AL_VECTOR* dpys = &al_get_system_driver()->displays; for (i = 0; i < _al_vector_size(dpys); ++i) { ALLEGRO_DISPLAY_OSX_WIN* d = *(ALLEGRO_DISPLAY_OSX_WIN**) _al_vector_ref(dpys, i); if (d->display_group == dpy->display_group && (d!=dpy)) { other = d; break; } } if (other != NULL) { // Found another compatible display. Transfer our bitmaps to it. _AL_VECTOR* bmps = &dpy->parent.bitmaps; for (i = 0; i<_al_vector_size(bmps); ++i) { ALLEGRO_BITMAP **add = _al_vector_alloc_back(&other->parent.bitmaps); ALLEGRO_BITMAP **ref = _al_vector_ref(bmps, i); *add = *ref; (*add)->_display = &(other->parent); } } else { // This is the last in its group. Convert all its bitmaps to memory bmps while (dpy->parent.bitmaps._size > 0) { ALLEGRO_BITMAP **bptr = _al_vector_ref_back(&dpy->parent.bitmaps); ALLEGRO_BITMAP *bmp = *bptr; _al_convert_to_memory_bitmap(bmp); } } _al_vector_free(&dpy->parent.bitmaps); ALLEGRO_DISPLAY* display = &dpy->parent; ALLEGRO_OGL_EXTRAS *ogl = display->ogl_extras; _al_vector_find_and_delete(&al_get_system_driver()->displays, &display); if (ogl->backbuffer) { _al_ogl_destroy_backbuffer(ogl->backbuffer); ogl->backbuffer = NULL; ALLEGRO_DEBUG("destroy backbuffer.\n"); } dispatch_sync(dispatch_get_main_queue(), ^{ // Disconnect from its view or exit fullscreen mode [dpy->ctx clearDrawable]; // Unlock the screen if (display->flags & ALLEGRO_FULLSCREEN) { CGDisplaySetDisplayMode(dpy->display_id, dpy->original_mode, NULL); CGDisplayModeRelease(dpy->original_mode); #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 if (dpy->win) { [dpy->view exitFullScreenModeWithOptions: nil]; } #endif CGDisplayRelease(dpy->display_id); dpy->in_fullscreen = false; } else if (display->flags & ALLEGRO_FULLSCREEN_WINDOW) { #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 if (dpy->win) { [dpy->view exitFullScreenModeWithOptions: nil]; } #endif } if (dpy->win) { // Destroy the containing window if there is one [dpy->win close]; dpy->win = nil; } }); _al_ogl_unmanage_extensions(&dpy->parent); [dpy->ctx release]; [dpy->cursor release]; _al_event_source_free(&d->es); al_free(d->ogl_extras); // Restore original display from before this function was called. // If the display we just destroyed is actually current, set the current // display to NULL. if (old_dpy != d) _al_set_current_display_only(old_dpy); else { // Is this redundant? --pw _al_set_current_display_only(NULL); } al_destroy_cond(dpy->halt_cond); al_destroy_mutex(dpy->halt_mutex); if (dpy->flip_mutex) { al_destroy_mutex(dpy->flip_mutex); al_destroy_cond(dpy->flip_cond); CVDisplayLinkRelease(dpy->display_link); } al_free(d->vertex_cache); al_free(d); [pool drain]; } /* create_display: * Create a display either fullscreen or windowed depending on flags * Call from user thread */ static ALLEGRO_DISPLAY* create_display(int w, int h) { ASSERT_USER_THREAD(); int flags = al_get_new_display_flags(); if (flags & ALLEGRO_FULLSCREEN) { return create_display_fs(w,h); } else { return create_display_win(w,h); } } /* Note: in windowed mode, contexts always behave like single-buffered * though in fact they are composited offscreen */ static void flip_display(ALLEGRO_DISPLAY *disp) { ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) disp; ALLEGRO_BITMAP *old_target = NULL; if (!((ALLEGRO_BITMAP_EXTRA_OPENGL *)disp->ogl_extras->opengl_target->extra)->is_backbuffer) { old_target = al_get_target_bitmap(); al_set_target_backbuffer(disp); } if (dpy->flip_mutex) { al_lock_mutex(dpy->flip_mutex); int old_flips = dpy->num_flips; while (dpy->num_flips == old_flips) { al_wait_cond(dpy->flip_cond, dpy->flip_mutex); } dpy->num_flips = 0; al_unlock_mutex(dpy->flip_mutex); } if (dpy->single_buffer) { glFlush(); } else { [dpy->ctx flushBuffer]; } if (old_target) { al_set_target_bitmap(old_target); } } static void update_display_region(ALLEGRO_DISPLAY *disp, int x, int y, int width, int height) { (void)x; (void)y; (void)width; (void)height; flip_display(disp); } /* _al_osx_create_mouse_cursor: * creates a custom system cursor from the bitmap bmp. * (x_focus, y_focus) indicates the cursor hot-spot. */ ALLEGRO_MOUSE_CURSOR *_al_osx_create_mouse_cursor(ALLEGRO_BITMAP *bmp, int x_focus, int y_focus) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; ALLEGRO_MOUSE_CURSOR_OSX *cursor = NULL; if (!bmp) { [pool drain]; return NULL; } NSImage* cursor_image = NSImageFromAllegroBitmap(bmp); cursor = al_malloc(sizeof *cursor); cursor->cursor = [[NSCursor alloc] initWithImage: cursor_image hotSpot: NSMakePoint(x_focus, y_focus)]; [cursor_image release]; [pool drain]; return (ALLEGRO_MOUSE_CURSOR *)cursor; } /* _al_osx_destroy_mouse_cursor: * destroys a mouse cursor previously created with _al_osx_create_mouse_cursor */ void _al_osx_destroy_mouse_cursor(ALLEGRO_MOUSE_CURSOR *curs) { ALLEGRO_MOUSE_CURSOR_OSX *cursor = (ALLEGRO_MOUSE_CURSOR_OSX *) curs; unsigned i; if (!cursor) return; /* XXX not at all thread safe */ _AL_VECTOR* dpys = &al_get_system_driver()->displays; for (i = 0; i < _al_vector_size(dpys); ++i) { ALLEGRO_DISPLAY* dpy = *(ALLEGRO_DISPLAY**) _al_vector_ref(dpys, i); ALLEGRO_DISPLAY_OSX_WIN *osx_dpy = (ALLEGRO_DISPLAY_OSX_WIN*) dpy; if (osx_dpy->cursor == cursor->cursor) { _al_osx_change_cursor(osx_dpy, [NSCursor arrowCursor]); } } [cursor->cursor release]; al_free(cursor); } /* osx_set_mouse_cursor: * change the mouse cursor for the active window to the cursor previously * allocated by osx_create_mouse_cursor */ static bool osx_set_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_MOUSE_CURSOR *cursor) { ALLEGRO_DISPLAY_OSX_WIN *dpy = (ALLEGRO_DISPLAY_OSX_WIN *)display; ALLEGRO_MOUSE_CURSOR_OSX *osxcursor = (ALLEGRO_MOUSE_CURSOR_OSX *)cursor; _al_osx_change_cursor(dpy, osxcursor->cursor); return true; } /* osx_set_system_mouse_cursor: * change the mouse cursor to one of the system default cursors. * NOTE: Allegro defines four of these, but OS X has no dedicated "busy" or * "question" cursors, so we just set an arrow in those cases. */ static bool osx_set_system_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id) { ALLEGRO_DISPLAY_OSX_WIN *dpy = (ALLEGRO_DISPLAY_OSX_WIN *)display; NSCursor *requested_cursor = NULL; switch (cursor_id) { case ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT: case ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW: case ALLEGRO_SYSTEM_MOUSE_CURSOR_BUSY: case ALLEGRO_SYSTEM_MOUSE_CURSOR_QUESTION: case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE: case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_SW: case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW: case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_SE: case ALLEGRO_SYSTEM_MOUSE_CURSOR_PROGRESS: case ALLEGRO_SYSTEM_MOUSE_CURSOR_ALT_SELECT: requested_cursor = [NSCursor arrowCursor]; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE: requested_cursor = [NSCursor operationNotAllowedCursor]; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT: requested_cursor = [NSCursor IBeamCursor]; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N: requested_cursor = [NSCursor resizeUpCursor]; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_S: requested_cursor = [NSCursor resizeDownCursor]; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E: requested_cursor = [NSCursor resizeRightCursor]; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_W: requested_cursor = [NSCursor resizeLeftCursor]; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_PRECISION: requested_cursor = [NSCursor crosshairCursor]; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_LINK: requested_cursor = [NSCursor pointingHandCursor]; break; default: return false; } _al_osx_change_cursor(dpy, requested_cursor); return true; } /* (show|hide)_cursor: Cursor show or hide. The same function works for both windowed and fullscreen. */ static bool show_cursor(ALLEGRO_DISPLAY *d) { ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) d; dpy->show_cursor = YES; [NSCursor unhide]; return true; } static bool hide_cursor(ALLEGRO_DISPLAY *d) { ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) d; dpy->show_cursor = NO; [NSCursor hide]; return true; } /* Call from main thread. */ static bool acknowledge_resize_display_win_main_thread(ALLEGRO_DISPLAY *d) { ASSERT_MAIN_THREAD(); ALLEGRO_DISPLAY_OSX_WIN *dpy = (ALLEGRO_DISPLAY_OSX_WIN *)d; NSWindow* window = dpy->win; NSRect frame = [window frame]; NSRect content = [window contentRectForFrameRect: frame]; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 content = [window convertRectToBacking: content]; #endif /* At any moment when a window has been changed its size we either * clear ALLEGRO_MAXIMIZED flag (e.g. resize was done by a human) * or restore the flag back (at the end of live resize caused by zoom). * Note: affects zoom:(id)sender (if you will debug it). */ if (!(d->flags & ALLEGRO_FULLSCREEN_WINDOW) && ![window isZoomed]) d->flags &= ~ALLEGRO_MAXIMIZED; else if (!(d->flags & ALLEGRO_MAXIMIZED)) d->flags |= ALLEGRO_MAXIMIZED; d->w = NSWidth(content); d->h = NSHeight(content); return true; } /* Call from user thread */ static bool acknowledge_resize_display_win(ALLEGRO_DISPLAY *d) { ASSERT_USER_THREAD(); dispatch_sync(dispatch_get_main_queue(), ^{ acknowledge_resize_display_win_main_thread(d); }); // must be done on the thread the user calls it from, not the main thread setup_gl(d); return true; } /* resize_display_win * Change the size of the display by altering the window size or changing the screen mode * This must be called from the User thread */ static bool resize_display_win(ALLEGRO_DISPLAY *d, int w, int h) { ASSERT_USER_THREAD(); /* Don't resize a fullscreen window */ if (d->flags & ALLEGRO_FULLSCREEN_WINDOW) { return false; } bool __block rc; dispatch_sync(dispatch_get_main_queue(), ^{ rc = resize_display_win_main_thread(d, w, h); }); // must be done on the thread the user calls it from, not the main thread setup_gl(d); // Only update the old values in response to user-initiated resizes. ALLEGRO_DISPLAY_OSX_WIN *dpy = (ALLEGRO_DISPLAY_OSX_WIN *)d; dpy->old_w = w; dpy->old_h = h; return rc; } /* resize_display_win_main_thread * Change the size of the display by altering the window size or changing the screen mode * This must be called from the Main thread */ static bool resize_display_win_main_thread(ALLEGRO_DISPLAY *d, int w, int h) { ASSERT_MAIN_THREAD(); ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) d; NSWindow* window = dpy->win; NSRect current; float scale_factor = 1.0; NSRect content = NSMakeRect(0.0f, 0.0f, (float) w, (float) h); current = [window frame]; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 content = [window convertRectFromBacking: content]; if ([window respondsToSelector:@selector(backingScaleFactor)]) { scale_factor = [window backingScaleFactor]; } #endif w = _ALLEGRO_MAX(w, MINIMUM_WIDTH / scale_factor); h = _ALLEGRO_MAX(h, MINIMUM_HEIGHT / scale_factor); if (d->use_constraints) { if (d->min_w > 0 && w < d->min_w) { w = d->min_w; } if (d->min_h > 0 && h < d->min_h) { h = d->min_h; } /* Don't use max. constraints when a window is maximized. */ if (!(d->flags & ALLEGRO_MAXIMIZED)) { if (d->max_w > 0 && w > d->max_w) { w = d->max_w; } if (d->max_h > 0 && h > d->max_h) { h = d->max_h; } } } /* Set new width & height values to content rectangle * before calling 'set_frame' below. */ content.size.width = w / scale_factor; content.size.height = h / scale_factor; NSRect rc = [window frameRectForContentRect: content]; rc.origin = current.origin; [window setFrame: rc display: YES animate: NO]; clear_to_black(dpy->ctx); return acknowledge_resize_display_win_main_thread(d); } static bool resize_display_fs(ALLEGRO_DISPLAY *d, int w, int h) { ALLEGRO_DEBUG("Resize full screen display to %d x %d\n", w, h); bool success = true; ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) d; #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 CFDictionaryRef current = CGDisplayCurrentMode(dpy->display_id); CFNumberRef bps = (CFNumberRef) CFDictionaryGetValue(current, kCGDisplayBitsPerPixel); int b; CFNumberGetValue(bps, kCFNumberSInt32Type,&b); CFDictionaryRef mode = CGDisplayBestModeForParameters(dpy->display_id, b, w, h, NULL); [dpy->ctx clearDrawable]; CGError err = CGDisplaySwitchToMode(dpy->display_id, mode); success = (err == kCGErrorSuccess); #else CGDisplayModeRef current = CGDisplayCopyDisplayMode(dpy->display_id); CFStringRef bps = CGDisplayModeCopyPixelEncoding(current); CFRelease(current); CGDisplayModeRef mode = NULL; CFArrayRef modes = NULL; int i; modes = CGDisplayCopyAllDisplayModes(dpy->display_id, NULL); for (i = 0; i < CFArrayGetCount(modes); i++) { CGDisplayModeRef try_mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(try_mode); /* Found mode with matching size/colour depth */ if ( w == (int)CGDisplayModeGetWidth(try_mode) && h == (int)CGDisplayModeGetHeight(try_mode) && CFStringCompare(pixel_encoding, bps, 1) == 0) { mode = try_mode; CFRelease(pixel_encoding); break; } CFRelease(pixel_encoding); } CFRelease(bps); CFRelease(modes); if (!mode) { ALLEGRO_DEBUG("Can't resize fullscreen display\n"); return false; } /* Switch display mode */ [dpy->ctx clearDrawable]; CFDictionaryRef options = CFDictionaryCreate(NULL, NULL, NULL, 0, NULL, NULL); CGDisplaySetDisplayMode(dpy->display_id, mode, NULL); CFRelease(options); #endif d->w = w; d->h = h; [dpy->ctx setFullScreen]; _al_ogl_resize_backbuffer(d->ogl_extras->backbuffer, d->w, d->h); setup_gl(d); return success; } static bool is_compatible_bitmap(ALLEGRO_DISPLAY* disp, ALLEGRO_BITMAP* bmp) { return (_al_get_bitmap_display(bmp) == disp) || (((ALLEGRO_DISPLAY_OSX_WIN*) _al_get_bitmap_display(bmp))->display_group == ((ALLEGRO_DISPLAY_OSX_WIN*) disp)->display_group); } /* set_window_position: * Set the position of the window that owns this display * Slightly complicated because Allegro measures from the top down to * the top left corner, OS X from the bottom up to the bottom left corner. * Call from user thread. */ static void set_window_position(ALLEGRO_DISPLAY* display, int x, int y) { ASSERT_USER_THREAD(); ALLEGRO_DISPLAY_OSX_WIN* d = (ALLEGRO_DISPLAY_OSX_WIN*) display; NSWindow* window = d->win; int primary_y = _al_osx_get_primary_screen_y(); float global_scale_factor = _al_osx_get_global_scale_factor(); /* Because the extended plane (see get_monitor_info) has holes in it, we need to * search which destination monitor to actually use. */ NSArray *screen_list = [NSScreen screens]; int found_screen = -1; for (int i = 0; i < al_get_num_video_adapters(); i++) { ALLEGRO_MONITOR_INFO info; al_get_monitor_info(i, &info); if (x > info.x1 && x < info.x2 && y > info.y1 && y < info.y2) { found_screen = i; break; } } if (found_screen < 0) return; NSScreen *screen = [screen_list objectAtIndex:found_screen]; NSRect screen_rc = [screen frame]; /* Set the frame on the main thread. Because this is where * the window's frame was initially set, this is where it should be * modified too. */ dispatch_sync(dispatch_get_main_queue(), ^{ NSRect rc = [window frame]; float scale_factor = 1.0; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if ([screen respondsToSelector:@selector(backingScaleFactor)]) { scale_factor = [screen backingScaleFactor]; } #endif /* These two expressions are the inverses of get_window_position formulas. */ rc.origin.x = (x + screen_rc.origin.x * scale_factor - screen_rc.origin.x * global_scale_factor) / scale_factor; /* XXX: Handle non-resizeable displays! */ rc.origin.y = (y + scale_factor * rc.size.height - scale_factor * (screen_rc.origin.y + screen_rc.size.height) - ((primary_y - screen_rc.origin.y - screen_rc.size.height) * global_scale_factor)) / (-scale_factor); [window setFrame: rc display: YES animate: NO]; }); } /* get_window_position: * Get the position of the window that owns this display. See comment for * set_window_position. * Call from user thread. */ static void get_window_position(ALLEGRO_DISPLAY* display, int* px, int* py) { ASSERT_USER_THREAD(); ALLEGRO_DISPLAY_OSX_WIN* d = (ALLEGRO_DISPLAY_OSX_WIN*) display; NSWindow* window = d->win; int primary_y = _al_osx_get_primary_screen_y(); float global_scale_factor = _al_osx_get_global_scale_factor(); dispatch_sync(dispatch_get_main_queue(), ^{ NSRect rc = [window frame]; float scale_factor = 1.0; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if ([window respondsToSelector:@selector(backingScaleFactor)]) { scale_factor = [window backingScaleFactor]; } #endif NSRect screen_rc = [[window screen] frame]; /* Use global scale to find the origin of the screen and then use the * local scale to handle the relative coordinates. */ *px = (int) (screen_rc.origin.x * global_scale_factor + (rc.origin.x - screen_rc.origin.x) * scale_factor); *py = (int)((primary_y - screen_rc.origin.y - screen_rc.size.height) * global_scale_factor) - (int)(scale_factor * (rc.size.height + rc.origin.y - screen_rc.origin.y - screen_rc.size.height)); }); } static bool set_window_constraints(ALLEGRO_DISPLAY* display, int min_w, int min_h, int max_w, int max_h) { if (min_w > 0 && min_w < MINIMUM_WIDTH) { min_w = MINIMUM_WIDTH; } if (min_h > 0 && min_h < MINIMUM_HEIGHT) { min_h = MINIMUM_HEIGHT; } display->min_w = min_w; display->min_h = min_h; display->max_w = max_w; display->max_h = max_h; return true; } static bool get_window_constraints(ALLEGRO_DISPLAY* display, int* min_w, int* min_h, int* max_w, int* max_h) { *min_w = display->min_w; *min_h = display->min_h; *max_w = display->max_w; *max_h = display->max_h; return true; } /* apply_window_constraints: * Tell Cocoa about new window min/max size. * Resize the window if needed. * Call from user thread. */ static void apply_window_constraints(ALLEGRO_DISPLAY *display, bool onoff) { ASSERT_USER_THREAD(); ALLEGRO_DISPLAY_OSX_WIN* d = (ALLEGRO_DISPLAY_OSX_WIN*) display; NSWindow* window = d->win; float __block scale_factor = 1.0; NSSize max_size; NSSize min_size; dispatch_sync(dispatch_get_main_queue(), ^{ #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if ([window respondsToSelector:@selector(backingScaleFactor)]) { scale_factor = [window backingScaleFactor]; } #endif }); if (onoff) { min_size.width = display->min_w / scale_factor; min_size.height = display->min_h / scale_factor; if (display->max_w > 0) max_size.width = display->max_w / scale_factor; else max_size.width = FLT_MAX; if (display->max_h > 0) max_size.height = display->max_h / scale_factor; else max_size.height = FLT_MAX; al_resize_display(display, display->w, display->h); } else { min_size.width = MINIMUM_WIDTH / scale_factor; min_size.height = MINIMUM_HEIGHT / scale_factor; max_size.width = FLT_MAX; max_size.height = FLT_MAX; } dispatch_sync(dispatch_get_main_queue(), ^{ [window setContentMaxSize:max_size]; [window setContentMinSize:min_size]; }); } /* set_window_title: * Set the title of the window with this display * Call from user thread */ static void set_window_title(ALLEGRO_DISPLAY *display, const char *title) { ASSERT_USER_THREAD(); ALLEGRO_DISPLAY_OSX_WIN* dpy = (ALLEGRO_DISPLAY_OSX_WIN*) display; NSString* string = [[NSString alloc] initWithUTF8String:title]; [dpy->win performSelectorOnMainThread:@selector(setTitle:) withObject:string waitUntilDone:YES]; [string release]; } /* set_icons: * Set the icon - OS X doesn't have per-window icons so * ignore the display parameter * Call from user thread */ static void set_icons(ALLEGRO_DISPLAY *display, int num_icons, ALLEGRO_BITMAP* bitmaps[]) { ASSERT_USER_THREAD(); /* Multiple icons not yet implemented. */ ALLEGRO_BITMAP *bitmap = bitmaps[num_icons - 1]; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSImage *image = NSImageFromAllegroBitmap(bitmap); (void)display; [NSApp performSelectorOnMainThread: @selector(setApplicationIconImage:) withObject: image waitUntilDone: YES]; [image release]; [pool drain]; } /* set_display_flag: * Change settings for an already active display * Call from user thread. */ static bool set_display_flag(ALLEGRO_DISPLAY *display, int flag, bool onoff) { ASSERT_USER_THREAD(); #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 return false; #else if (!display) return false; ALLEGRO_DISPLAY_OSX_WIN *dpy = (ALLEGRO_DISPLAY_OSX_WIN *)display; ALWindow *win = dpy->win; if (!win) return false; bool __block need_setup_gl = false; bool __block retcode = true; dispatch_sync(dispatch_get_main_queue(), ^{ NSWindowStyleMask mask = [win styleMask]; ALOpenGLView *view = (ALOpenGLView *)dpy->view; switch (flag) { case ALLEGRO_FRAMELESS: if (onoff) display->flags |= ALLEGRO_FRAMELESS; else display->flags &= ~ALLEGRO_FRAMELESS; /* BUGS: - This causes the keyboard focus to be lost. - On 10.10, disabling the frameless mode causes the title bar to be partially drawn (resizing the window makes it appear again). */ ALLEGRO_DEBUG("Toggle FRAME for display %p to %d\n", dpy, onoff); if (onoff) mask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable); else mask |= NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; NSString *title = [win title]; [win setStyleMask:mask]; /* When going from frameless to frameful, the title gets reset, so we have to manually put it back. */ [win setTitle:title]; break; case ALLEGRO_RESIZABLE: ALLEGRO_DEBUG("Toggle RESIZABLE for display %p to %d\n", dpy, onoff); if (onoff) { display->flags |= ALLEGRO_RESIZABLE; mask |= NSWindowStyleMaskResizable; } else { display->flags &= ~ALLEGRO_RESIZABLE; mask &= ~NSWindowStyleMaskResizable; } [win setStyleMask:mask]; break; case ALLEGRO_MAXIMIZED: retcode= true; if ((!!(display->flags & ALLEGRO_MAXIMIZED)) == onoff) break; if (onoff) display->flags |= ALLEGRO_MAXIMIZED; else display->flags &= ~ALLEGRO_MAXIMIZED; [view maximize]; break; case ALLEGRO_FULLSCREEN_WINDOW: if (onoff) { [view enterFullScreenWindowMode]; NSRect sc = [[win screen] frame]; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 sc = [win convertRectToBacking: sc]; #endif resize_display_win_main_thread(display, sc.size.width, sc.size.height); display->flags |= ALLEGRO_FULLSCREEN_WINDOW; } else { [view exitFullScreenWindowMode]; display->flags &= ~ALLEGRO_FULLSCREEN_WINDOW; resize_display_win_main_thread(display, dpy->old_w, dpy->old_h); [view finishExitingFullScreenWindowMode]; } need_setup_gl = true; break; default: retcode = false; break; } }); if (need_setup_gl) { setup_gl(display); } return retcode; #endif } static void acknowledge_drawing_halt(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_OSX_WIN *dpy = (ALLEGRO_DISPLAY_OSX_WIN *)display; al_lock_mutex(dpy->halt_mutex); dpy->halt_event_acknowledged = true; al_signal_cond(dpy->halt_cond); al_unlock_mutex(dpy->halt_mutex); } ALLEGRO_DISPLAY_INTERFACE* _al_osx_get_display_driver_win(void) { static ALLEGRO_DISPLAY_INTERFACE* vt = NULL; if (vt == NULL) { vt = al_malloc(sizeof(*vt)); memset(vt, 0, sizeof(ALLEGRO_DISPLAY_INTERFACE)); vt->create_display = create_display_win; vt->destroy_display = destroy_display; vt->set_current_display = set_current_display; vt->flip_display = flip_display; vt->update_display_region = update_display_region; vt->resize_display = resize_display_win; vt->acknowledge_resize = acknowledge_resize_display_win; vt->create_bitmap = _al_ogl_create_bitmap; vt->set_target_bitmap = _al_ogl_set_target_bitmap; vt->get_backbuffer = _al_ogl_get_backbuffer; vt->is_compatible_bitmap = is_compatible_bitmap; vt->show_mouse_cursor = show_cursor; vt->hide_mouse_cursor = hide_cursor; vt->set_mouse_cursor = osx_set_mouse_cursor; vt->set_system_mouse_cursor = osx_set_system_mouse_cursor; vt->get_window_position = get_window_position; vt->set_window_position = set_window_position; vt->get_window_constraints = get_window_constraints; vt->set_window_constraints = set_window_constraints; vt->apply_window_constraints = apply_window_constraints; vt->set_window_title = set_window_title; vt->set_display_flag = set_display_flag; vt->set_icons = set_icons; vt->update_render_state = _al_ogl_update_render_state; vt->acknowledge_drawing_halt = acknowledge_drawing_halt; _al_ogl_add_drawing_functions(vt); _al_osx_add_clipboard_functions(vt); } return vt; } ALLEGRO_DISPLAY_INTERFACE* _al_osx_get_display_driver_fs(void) { static ALLEGRO_DISPLAY_INTERFACE* vt = NULL; if (vt == NULL) { vt = al_malloc(sizeof(*vt)); memset(vt, 0, sizeof(ALLEGRO_DISPLAY_INTERFACE)); vt->create_display = create_display_fs; vt->destroy_display = destroy_display; vt->set_current_display = set_current_display; vt->flip_display = flip_display; vt->resize_display = resize_display_fs; vt->create_bitmap = _al_ogl_create_bitmap; vt->set_target_bitmap = _al_ogl_set_target_bitmap; vt->show_mouse_cursor = show_cursor; vt->hide_mouse_cursor = hide_cursor; vt->set_mouse_cursor = osx_set_mouse_cursor; vt->set_system_mouse_cursor = osx_set_system_mouse_cursor; vt->get_backbuffer = _al_ogl_get_backbuffer; vt->is_compatible_bitmap = is_compatible_bitmap; vt->update_render_state = _al_ogl_update_render_state; _al_ogl_add_drawing_functions(vt); } return vt; } /* Mini VT just for creating displays */ ALLEGRO_DISPLAY_INTERFACE* _al_osx_get_display_driver(void) { static ALLEGRO_DISPLAY_INTERFACE* vt = NULL; if (vt == NULL) { vt = al_malloc(sizeof(*vt)); memset(vt, 0, sizeof(ALLEGRO_DISPLAY_INTERFACE)); vt->create_display = create_display; } return vt; } /* Function: al_osx_get_window */ NSWindow* al_osx_get_window(ALLEGRO_DISPLAY *display) { if (!display) return NULL; return ((ALLEGRO_DISPLAY_OSX_WIN *)display)->win; } allegro5-5.2.10.1/src/macosx/qzmouse.m000066400000000000000000000334551473414355200174340ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * MacOS X mouse driver. * * By Angelo Mottola. * * Modified for 4.9 mouse API by Peter Hull. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_driver.h" #include "allegro5/internal/aintern_mouse.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/platform/aintosx.h" #include "./osxgl.h" #ifndef ALLEGRO_MACOSX #error Something is wrong with the makefile #endif ALLEGRO_DEBUG_CHANNEL("MacOSX"); typedef struct ALLEGRO_MOUSE AL_MOUSE; typedef struct ALLEGRO_MOUSE_STATE AL_MOUSE_STATE; static bool osx_init_mouse(void); static unsigned int osx_get_mouse_num_buttons(void); static unsigned int osx_get_mouse_num_axes(void); static bool osx_set_mouse_axis(int axis, int value); static ALLEGRO_MOUSE* osx_get_mouse(void); /* Mouse info - includes extra info for OS X */ static struct { ALLEGRO_MOUSE parent; unsigned int button_count; unsigned int axis_count; int minx, miny, maxx, maxy; ALLEGRO_MOUSE_STATE state; float z_axis, w_axis; BOOL warped; int warped_x, warped_y; NSCursor* cursor; } osx_mouse; void _al_osx_clear_mouse_state(void) { memset(&osx_mouse.state, 0, sizeof(ALLEGRO_MOUSE_STATE)); } /* _al_osx_switch_keyboard_focus: * Handle a focus switch event. */ void _al_osx_switch_mouse_focus(ALLEGRO_DISPLAY *dpy, bool switch_in) { _al_event_source_lock(&osx_mouse.parent.es); if (switch_in) osx_mouse.state.display = dpy; else osx_mouse.state.display = NULL; _al_event_source_unlock(&osx_mouse.parent.es); } /* osx_get_mouse: * Return the Allegro mouse structure */ static ALLEGRO_MOUSE* osx_get_mouse(void) { return (ALLEGRO_MOUSE*) &osx_mouse.parent; } /* _al_osx_mouse_generate_event: * Convert an OS X mouse event to an Allegro event * and push it into a queue. * First check that the event is wanted. */ void _al_osx_mouse_generate_event(NSEvent* evt, ALLEGRO_DISPLAY* dpy) { NSPoint pos; int type, b_change = 0, b = 0; float pressure = 0.0; float dx = 0, dy = 0, dz = 0, dw = 0; switch ([evt type]) { case NSMouseMoved: type = ALLEGRO_EVENT_MOUSE_AXES; dx = [evt deltaX]; dy = [evt deltaY]; pressure = [evt pressure]; break; case NSLeftMouseDragged: case NSRightMouseDragged: case NSOtherMouseDragged: type = ALLEGRO_EVENT_MOUSE_AXES; b = [evt buttonNumber]+1; dx = [evt deltaX]; dy = [evt deltaY]; pressure = [evt pressure]; break; case NSLeftMouseDown: case NSRightMouseDown: case NSOtherMouseDown: type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN; b = [evt buttonNumber]+1; b_change = 1; osx_mouse.state.buttons |= (1 << (b-1)); pressure = [evt pressure]; break; case NSLeftMouseUp: case NSRightMouseUp: case NSOtherMouseUp: type = ALLEGRO_EVENT_MOUSE_BUTTON_UP; b = [evt buttonNumber]+1; b_change = 1; osx_mouse.state.buttons &= ~(1 << (b-1)); pressure = [evt pressure]; break; case NSScrollWheel: type = ALLEGRO_EVENT_MOUSE_AXES; dx = 0; dy = 0; osx_mouse.w_axis += al_get_mouse_wheel_precision() * [evt deltaX]; osx_mouse.z_axis += al_get_mouse_wheel_precision() * [evt deltaY]; dw = osx_mouse.w_axis - osx_mouse.state.w; dz = osx_mouse.z_axis - osx_mouse.state.z; break; case NSMouseEntered: type = ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY; b = [evt buttonNumber]+1; dx = [evt deltaX]; dy = [evt deltaY]; break; case NSMouseExited: type = ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY; b = [evt buttonNumber]+1; dx = [evt deltaX]; dy = [evt deltaY]; break; default: return; } pos = [evt locationInWindow]; BOOL within = true; float scaling_factor = 1.0; if ([evt window]) { NSRect frm = [[[evt window] contentView] frame]; within = NSMouseInRect(pos, frm, NO); // Y-coordinates in OS X start from the bottom. pos.y = NSHeight(frm) - pos.y; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 scaling_factor = [[evt window] backingScaleFactor]; #endif } else { pos.y = [[NSScreen mainScreen] frame].size.height - pos.y; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 scaling_factor = [[NSScreen mainScreen] backingScaleFactor]; #endif } dx *= scaling_factor; dy *= scaling_factor; if (osx_mouse.warped && type == ALLEGRO_EVENT_MOUSE_AXES) { dx -= osx_mouse.warped_x; dy -= osx_mouse.warped_y; osx_mouse.warped = FALSE; } _al_event_source_lock(&osx_mouse.parent.es); if ((within || b_change || type == ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY) && _al_event_source_needs_to_generate_event(&osx_mouse.parent.es)) { ALLEGRO_EVENT new_event; ALLEGRO_MOUSE_EVENT* mouse_event = &new_event.mouse; mouse_event->type = type; // Note: we use 'allegro time' rather than the time stamp // from the event mouse_event->timestamp = al_get_time(); mouse_event->display = dpy; mouse_event->button = b; mouse_event->x = pos.x * scaling_factor; mouse_event->y = pos.y * scaling_factor; mouse_event->z = osx_mouse.z_axis; mouse_event->w = osx_mouse.w_axis; mouse_event->dx = dx; mouse_event->dy = dy; mouse_event->dz = dz; mouse_event->dw = dw; mouse_event->pressure = pressure; _al_event_source_emit_event(&osx_mouse.parent.es, &new_event); } // Record current state osx_mouse.state.x = pos.x * scaling_factor; osx_mouse.state.y = pos.y * scaling_factor; osx_mouse.state.w = osx_mouse.w_axis; osx_mouse.state.z = osx_mouse.z_axis; osx_mouse.state.pressure = pressure; _al_event_source_unlock(&osx_mouse.parent.es); } /* osx_init_mouse: * Initializes the driver. */ static bool osx_init_mouse(void) { /* NOTE: This function is deprecated, however until we have a better fix * or it is removed, we can used it. The problem without calling this * function is that after synthesizing events (as with al_set_mouse_xy) * there is an unacceptably long delay in receiving new events (mouse * locks up for about 0.5 seconds.) */ CGSetLocalEventsSuppressionInterval(0.0); NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; HID_DEVICE_COLLECTION devices={0,0,NULL}; int i = 0, j = 0; int axes = 0, buttons = 0; int max_axes = 0, max_buttons = 0; HID_DEVICE* device = nil; NSString* desc = nil; _al_osx_hid_scan(HID_MOUSE, &devices); ALLEGRO_INFO("Detected %d pointing devices\n", devices.count); for (i=0; imanufacturer ? device->manufacturer : "", device->product ? device->product : ""]; ALLEGRO_INFO("Device %d is a \"%s\"\n", i, [desc UTF8String]); for (j = 0; j < device->num_elements; j++) { switch (device->element[j].type) { case HID_ELEMENT_BUTTON: buttons++; break; case HID_ELEMENT_AXIS: case HID_ELEMENT_AXIS_PRIMARY_X: case HID_ELEMENT_AXIS_PRIMARY_Y: case HID_ELEMENT_STANDALONE_AXIS: axes ++; break; } } ALLEGRO_INFO("Detected %d axes and %d buttons\n", axes, buttons); /* When mouse events reach the application, it is not clear which * device generated them, so effectively the largest number of * buttons and axes reported corresponds to the device that the * application "sees" */ if (axes > max_axes) max_axes = axes; if (buttons > max_buttons) max_buttons = buttons; } _al_osx_hid_free(&devices); ALLEGRO_INFO("Device effectively has %d axes and %d buttons\n", axes, buttons); if (max_buttons <= 0) return false; _al_event_source_init(&osx_mouse.parent.es); osx_mouse.button_count = max_buttons; osx_mouse.axis_count = max_axes; osx_mouse.warped = FALSE; memset(&osx_mouse.state, 0, sizeof(ALLEGRO_MOUSE_STATE)); _al_osx_mouse_was_installed(YES); [pool drain]; return true; } /* osx_exit_mouse: * Shut down the mouse driver */ static void osx_exit_mouse(void) { _al_osx_mouse_was_installed(NO); } /* osx_get_mouse_num_buttons: * Return the number of buttons on the mouse */ static unsigned int osx_get_mouse_num_buttons(void) { return osx_mouse.button_count; } /* osx_get_mouse_num_buttons: * Return the number of buttons on the mouse */ static unsigned int osx_get_mouse_num_axes(void) { return osx_mouse.axis_count; } static void osx_get_mouse_state(ALLEGRO_MOUSE_STATE *ret_state) { _al_event_source_lock(&osx_mouse.parent.es); memcpy(ret_state, &osx_mouse.state, sizeof(ALLEGRO_MOUSE_STATE)); _al_event_source_unlock(&osx_mouse.parent.es); } /* osx_set_mouse_xy: * Set the current mouse position */ static bool osx_set_mouse_xy(ALLEGRO_DISPLAY *dpy_, int x, int y) { CGPoint pos; CGDirectDisplayID display = 0; ALLEGRO_DISPLAY_OSX_WIN *dpy = (ALLEGRO_DISPLAY_OSX_WIN *)dpy_; float scaling_factor = 1.0; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 scaling_factor = [[NSScreen mainScreen] backingScaleFactor]; #endif x /= scaling_factor; y /= scaling_factor; if ((dpy) && !(dpy->parent.flags & ALLEGRO_FULLSCREEN) && !(dpy->parent.flags & ALLEGRO_FULLSCREEN_WINDOW) && (dpy->win)) { NSWindow *window = dpy->win; NSRect content = [window contentRectForFrameRect: [window frame]]; NSRect frame = [[window screen] frame]; CGRect rect = { { NSMinX(frame), NSMinY(frame) }, { NSWidth(frame), NSHeight(frame) } }; CGDirectDisplayID displays[16]; CGDisplayCount displayCount; if ((CGGetDisplaysWithRect(rect, 16, displays, &displayCount) == 0) && (displayCount >= 1)) display = displays[0]; CGPoint point_pos = CGPointMake(x, y); #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 point_pos = NSPointToCGPoint([[window contentView] convertPointFromBacking: NSPointFromCGPoint(point_pos)]); #endif pos.x = content.origin.x + point_pos.x; pos.y = rect.size.height - content.origin.y - content.size.height + point_pos.y; } else { if (dpy) display = dpy->display_id; pos.x = x; pos.y = y; } _al_event_source_lock(&osx_mouse.parent.es); if (_al_event_source_needs_to_generate_event(&osx_mouse.parent.es)) { ALLEGRO_EVENT new_event; ALLEGRO_MOUSE_EVENT* mouse_event = &new_event.mouse; mouse_event->type = ALLEGRO_EVENT_MOUSE_WARPED; // Note: we use 'allegro time' rather than the time stamp // from the event mouse_event->timestamp = al_get_time(); mouse_event->display = (ALLEGRO_DISPLAY *)dpy; mouse_event->button = 0; mouse_event->x = x; mouse_event->y = y; mouse_event->z = osx_mouse.z_axis; mouse_event->dx = x - osx_mouse.state.x; mouse_event->dy = y - osx_mouse.state.y; mouse_event->dz = 0; mouse_event->pressure = osx_mouse.state.pressure; if (mouse_event->dx || mouse_event->dy) { osx_mouse.warped = TRUE; osx_mouse.warped_x = mouse_event->dx; osx_mouse.warped_y = mouse_event->dy; _al_event_source_emit_event(&osx_mouse.parent.es, &new_event); } } CGDisplayMoveCursorToPoint(display, pos); osx_mouse.state.x = x; osx_mouse.state.y = y; _al_event_source_unlock(&osx_mouse.parent.es); return true; } /* osx_set_mouse_axis: * Set the axis value of the mouse */ static bool osx_set_mouse_axis(int axis, int value) { bool result = false; _al_event_source_lock(&osx_mouse.parent.es); switch (axis) { case 0: case 1: // By design, this doesn't apply to (x, y) break; case 2: osx_mouse.z_axis = value; result = true; break; case 3: osx_mouse.w_axis = value; result = true; break; } /* XXX generate an event if the axis value changed */ _al_event_source_unlock(&osx_mouse.parent.es); return result; } /* Mouse driver */ static ALLEGRO_MOUSE_DRIVER osx_mouse_driver = { 0, //int msedrv_id; "OSXMouse", //const char *msedrv_name; "Driver for Mac OS X",// const char *msedrv_desc; "OSX Mouse", //const char *msedrv_ascii_name; osx_init_mouse, //AL_METHOD(bool, init_mouse, (void)); osx_exit_mouse, //AL_METHOD(void, exit_mouse, (void)); osx_get_mouse, //AL_METHOD(ALLEGRO_MOUSE*, get_mouse, (void)); osx_get_mouse_num_buttons, //AL_METHOD(unsigned int, get_mouse_num_buttons, (void)); osx_get_mouse_num_axes, //AL_METHOD(unsigned int, get_mouse_num_axes, (void)); osx_set_mouse_xy, //AL_METHOD(bool, set_mouse_xy, (int x, int y)); osx_set_mouse_axis, //AL_METHOD(bool, set_mouse_axis, (int which, int value)); osx_get_mouse_state, //AL_METHOD(void, get_mouse_state, (ALLEGRO_MOUSE_STATE *ret_state)); }; ALLEGRO_MOUSE_DRIVER* _al_osx_get_mouse_driver(void) { return &osx_mouse_driver; } /* list the available drivers */ _AL_DRIVER_INFO _al_mouse_driver_list[] = { { 1, &osx_mouse_driver, 1 }, { 0, NULL, 0 } }; /* Local variables: */ /* c-basic-offset: 3 */ /* indent-tabs-mode: nil */ /* End: */ allegro5-5.2.10.1/src/macosx/system.m000066400000000000000000000601561473414355200172530ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * MacOS X system driver. * * By Angelo Mottola. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/platform/aintosx.h" #include "allegro5/internal/aintern_osxclipboard.h" #include #ifndef ALLEGRO_MACOSX #error something is wrong with the makefile #endif #import #include #include #include ALLEGRO_DEBUG_CHANNEL("MacOSX") /* These are used to warn the dock about the application */ struct CPSProcessSerNum { UInt32 lo; UInt32 hi; }; extern OSErr CPSGetCurrentProcess(struct CPSProcessSerNum *psn); extern OSErr CPSEnableForegroundOperation(struct CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); extern OSErr CPSSetFrontProcess(struct CPSProcessSerNum *psn); static ALLEGRO_SYSTEM* osx_sys_init(int flags); ALLEGRO_SYSTEM_INTERFACE *_al_system_osx_driver(void); static void osx_sys_exit(void); /* Global variables */ NSBundle *_al_osx_bundle = NULL; static _AL_VECTOR osx_display_modes; static ALLEGRO_SYSTEM osx_system; /* _al_osx_tell_dock: * Tell the dock about us; promote us from a console app to a graphical app * with dock icon and menu */ void _al_osx_tell_dock(void) { if (_al_osx_bundle != NULL) { /* If in a bundle, the dock will recognise us automatically */ return; } ProcessSerialNumber psn = { 0, kCurrentProcess }; TransformProcessType(&psn, kProcessTransformToForegroundApplication); [[NSApplication sharedApplication] performSelectorOnMainThread: @selector(activateIgnoringOtherApps:) withObject: [NSNumber numberWithBool:YES] waitUntilDone: YES]; } /* _al_osx_bootstrap_ok: * Check if the current bootstrap context is privilege. If it's not, we can't * use NSApplication, and instead have to go directly to main. * Returns 1 if ok, 0 if not. */ #ifdef OSX_BOOTSTRAP_DETECTION int _al_osx_bootstrap_ok(void) { static int _ok = -1; mach_port_t bp; kern_return_t ret; CFMachPortRef cfport; /* If have tested once, just return that answer */ if (_ok >= 0) return _ok; cfport = CFMachPortCreate(NULL, NULL, NULL, NULL); task_get_bootstrap_port(mach_task_self(), &bp); ret = bootstrap_register(bp, "bootstrap-ok-test", CFMachPortGetPort(cfport)); CFRelease(cfport); _ok = (ret == KERN_SUCCESS) ? 1 : 0; return _ok; } #endif /* osx_sys_init: * Initalizes the MacOS X system driver. */ static ALLEGRO_SYSTEM* osx_sys_init(int flags) { (void)flags; #ifdef OSX_BOOTSTRAP_DETECTION /* If we're in the 'dead bootstrap' environment, the Mac driver won't work. */ if (!_al_osx_bootstrap_ok()) { return NULL; } #endif /* Initialise the vt and display list */ osx_system.vt = _al_system_osx_driver(); _al_vector_init(&osx_system.displays, sizeof(ALLEGRO_DISPLAY*)); // `_al_osx_tell_dock` is better done after creating a display. Support old behavior for compatability. bool do_osx_tell_dock = true; const char* osx_tell_dock_outside_bundle_value = al_get_config_value(al_get_system_config(), "compatibility", "osx_tell_dock_outside_bundle"); if (osx_tell_dock_outside_bundle_value && strcmp(osx_tell_dock_outside_bundle_value, "false") == 0) do_osx_tell_dock = false; if (do_osx_tell_dock) { /* If in a bundle, the dock will recognise us automatically */ _al_osx_tell_dock(); } /* Mark the beginning of time. */ _al_unix_init_time(); _al_vector_init(&osx_display_modes, sizeof(ALLEGRO_DISPLAY_MODE)); ALLEGRO_DEBUG("system driver initialised.\n"); return &osx_system; } /* osx_sys_exit: * Shuts down the system driver. */ static void osx_sys_exit(void) { _al_vector_free(&osx_display_modes); ALLEGRO_DEBUG("system driver shutdown.\n"); } /* * _al_osx_get_num_display_modes: * Gets the number of available display modes */ static int _al_osx_get_num_display_modes(void) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *extras = _al_get_new_display_settings(); ALLEGRO_EXTRA_DISPLAY_SETTINGS temp; int refresh_rate = al_get_new_display_refresh_rate(); int adapter = al_get_new_display_adapter(); int depth = 0; CGDirectDisplayID display; CFArrayRef modes; CFIndex i; if (extras) depth = extras->settings[ALLEGRO_COLOR_SIZE]; memset(&temp, 0, sizeof(ALLEGRO_EXTRA_DISPLAY_SETTINGS)); display = CGMainDisplayID(); /* Get display ID for the requested display */ if (adapter > 0) { NSScreen *screen = [[NSScreen screens] objectAtIndex: adapter]; NSDictionary *dict = [screen deviceDescription]; NSNumber *display_id = [dict valueForKey: @"NSScreenNumber"]; /* FIXME (how?): in 64 bit-mode, this generates a warning, because * CGDirectDisplayID is apparently 32 bit whereas a pointer is 64 * bit. Considering that a CGDirectDisplayID is supposed to be a * pointer as well (according to the documentation available on-line) * it is not quite clear what the correct way to do this would be. */ display = (CGDirectDisplayID) [display_id pointerValue]; } _al_vector_free(&osx_display_modes); #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 /* Note: modes is owned by OSX and must not be released */ modes = CGDisplayAvailableModes(display); ALLEGRO_INFO("detected %d display modes.\n", (int)CFArrayGetCount(modes)); for (i = 0; i < CFArrayGetCount(modes); i++) { ALLEGRO_DISPLAY_MODE *mode; CFDictionaryRef dict = (CFDictionaryRef)CFArrayGetValueAtIndex(modes, i); CFNumberRef number; int value, samples; number = CFDictionaryGetValue(dict, kCGDisplayBitsPerPixel); CFNumberGetValue(number, kCFNumberIntType, &value); ALLEGRO_INFO("Mode %d has colour depth %d.\n", (int)i, value); if (depth && value != depth) { ALLEGRO_WARN("Skipping mode %d (requested colour depth %d).\n", (int)i, depth); continue; } number = CFDictionaryGetValue(dict, kCGDisplayRefreshRate); CFNumberGetValue(number, kCFNumberIntType, &value); ALLEGRO_INFO("Mode %d has colour depth %d.\n", (int)i, value); if (refresh_rate && value != refresh_rate) { ALLEGRO_WARN("Skipping mode %d (requested refresh rate %d).\n", (int)i, refresh_rate); continue; } mode = (ALLEGRO_DISPLAY_MODE *)_al_vector_alloc_back(&osx_display_modes); number = CFDictionaryGetValue(dict, kCGDisplayWidth); CFNumberGetValue(number, kCFNumberIntType, &mode->width); number = CFDictionaryGetValue(dict, kCGDisplayHeight); CFNumberGetValue(number, kCFNumberIntType, &mode->height); number = CFDictionaryGetValue(dict, kCGDisplayRefreshRate); CFNumberGetValue(number, kCFNumberIntType, &mode->refresh_rate); ALLEGRO_INFO("Mode %d is %dx%d@%dHz\n", (int)i, mode->width, mode->height, mode->refresh_rate); number = CFDictionaryGetValue(dict, kCGDisplayBitsPerPixel); CFNumberGetValue(number, kCFNumberIntType, &temp.settings[ALLEGRO_COLOR_SIZE]); number = CFDictionaryGetValue(dict, kCGDisplaySamplesPerPixel); CFNumberGetValue(number, kCFNumberIntType, &samples); number = CFDictionaryGetValue(dict, kCGDisplayBitsPerSample); CFNumberGetValue(number, kCFNumberIntType, &value); ALLEGRO_INFO("Mode %d has %d bits per pixel, %d samples per pixel and %d bits per sample\n", (int)i, temp.settings[ALLEGRO_COLOR_SIZE], samples, value); if (samples >= 3) { temp.settings[ALLEGRO_RED_SIZE] = value; temp.settings[ALLEGRO_GREEN_SIZE] = value; temp.settings[ALLEGRO_BLUE_SIZE] = value; if (samples == 4) temp.settings[ALLEGRO_ALPHA_SIZE] = value; } _al_fill_display_settings(&temp); mode->format = _al_deduce_color_format(&temp); } #else modes = CGDisplayCopyAllDisplayModes(display, NULL); ALLEGRO_INFO("detected %d display modes.\n", (int)CFArrayGetCount(modes)); for (i = 0; i < CFArrayGetCount(modes); i++) { ALLEGRO_DISPLAY_MODE *amode; CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(mode); int bpp = 0, mode_refresh_rate, samples = 0, value = 0; /* Determine pixel format. Whever thought this was a better idea than * having query functions for each of these properties should be * spoken to very harshly in a very severe voice. */ if (CFStringCompare(pixel_encoding, CFSTR(kIO16BitFloatPixels), 1) == 0) { bpp = 64; samples = 3; value = 16; } if (CFStringCompare(pixel_encoding, CFSTR(kIO32BitFloatPixels), 1) == 0) { bpp = 128; samples = 3; value = 32; } if (CFStringCompare(pixel_encoding, CFSTR(kIO64BitDirectPixels), 1) == 0) { bpp = 64; samples = 3; value = 16; } if (CFStringCompare(pixel_encoding, CFSTR(kIO30BitDirectPixels), 1) == 0) { bpp = 32; samples = 3; value = 10; } if (CFStringCompare(pixel_encoding, CFSTR(IO32BitDirectPixels), 1) == 0) { bpp = 32; samples = 3; value = 8; } if (CFStringCompare(pixel_encoding, CFSTR(IO16BitDirectPixels), 1) == 0) { bpp = 16; samples = 3; value = 5; } if (CFStringCompare(pixel_encoding, CFSTR(IO8BitIndexedPixels), 1) == 0) { bpp = 8; samples = 1; value = 8; } CFRelease(pixel_encoding); /* Check if this mode is ok in terms of depth and refresh rate */ ALLEGRO_INFO("Mode %d has colour depth %d.\n", (int)i, bpp); if (depth && bpp != depth) { ALLEGRO_WARN("Skipping mode %d (requested colour depth %d).\n", (int)i, depth); continue; } mode_refresh_rate = CGDisplayModeGetRefreshRate(mode); ALLEGRO_INFO("Mode %d has a refresh rate of %d.\n", (int)i, mode_refresh_rate); if (refresh_rate && mode_refresh_rate != refresh_rate) { ALLEGRO_WARN("Skipping mode %d (requested refresh rate %d).\n", (int)i, refresh_rate); continue; } /* Yes, it's fine */ amode = (ALLEGRO_DISPLAY_MODE *)_al_vector_alloc_back(&osx_display_modes); amode->width = CGDisplayModeGetWidth(mode); amode->height = CGDisplayModeGetHeight(mode); amode->refresh_rate = mode_refresh_rate; ALLEGRO_INFO("Mode %d is %dx%d@%dHz\n", (int)i, amode->width, amode->height, amode->refresh_rate); temp.settings[ALLEGRO_COLOR_SIZE] = bpp; ALLEGRO_INFO("Mode %d has %d bits per pixel, %d samples per pixel and %d bits per sample\n", (int)i, temp.settings[ALLEGRO_COLOR_SIZE], samples, value); if (samples >= 3) { temp.settings[ALLEGRO_RED_SIZE] = value; temp.settings[ALLEGRO_GREEN_SIZE] = value; temp.settings[ALLEGRO_BLUE_SIZE] = value; if (samples == 4) temp.settings[ALLEGRO_ALPHA_SIZE] = value; } _al_fill_display_settings(&temp); amode->format = _al_deduce_color_format(&temp); } CFRelease(modes); #endif return _al_vector_size(&osx_display_modes); } /* * _al_osx_get_num_display_modes: * Gets the number of available display modes */ static ALLEGRO_DISPLAY_MODE *_al_osx_get_display_mode(int index, ALLEGRO_DISPLAY_MODE *mode) { if ((unsigned)index >= _al_vector_size(&osx_display_modes)) return NULL; memcpy(mode, _al_vector_ref(&osx_display_modes, index), sizeof(ALLEGRO_DISPLAY_MODE)); return mode; } /* osx_get_num_video_adapters: * Return the number of video adapters i.e displays */ static int osx_get_num_video_adapters(void) { NSArray *screen_list; int num = 0; screen_list = [NSScreen screens]; if (screen_list) num = [screen_list count]; ALLEGRO_INFO("Detected %d displays\n", num); return num; } int _al_osx_get_primary_screen_y(void) { int count = osx_get_num_video_adapters(); if (count == 0) { return 0; } NSArray *screen_list = [NSScreen screens]; NSScreen *primary_screen = [screen_list objectAtIndex: 0]; NSRect primary_rc = [primary_screen frame]; return (int) (primary_rc.origin.y + primary_rc.size.height); } float _al_osx_get_global_scale_factor(void) { int count = osx_get_num_video_adapters(); if (count == 0) { return 1.; } float global_scale_factor = 1.; NSArray *screen_list = [NSScreen screens]; for (int i = 0; i < count; i++) { NSScreen *screen = [screen_list objectAtIndex: i]; float scale_factor = 1.0; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if ([screen respondsToSelector:@selector(backingScaleFactor)]) { scale_factor = [screen backingScaleFactor]; } #endif if (scale_factor > global_scale_factor) { global_scale_factor = scale_factor; } } return global_scale_factor; } /* osx_get_monitor_info: * Return the details of one monitor */ static bool osx_get_monitor_info(int adapter, ALLEGRO_MONITOR_INFO* info) { int count = osx_get_num_video_adapters(); int primary_y = _al_osx_get_primary_screen_y(); float global_scale_factor = _al_osx_get_global_scale_factor(); if (adapter < count) { NSScreen *screen = [[NSScreen screens] objectAtIndex: adapter]; NSRect rc = [screen frame]; float scale_factor = 1.0; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if ([screen respondsToSelector:@selector(backingScaleFactor)]) { scale_factor = [screen backingScaleFactor]; } #endif /* * The goal is to use top-left origin, y-down coordinate system * where units are individual pixels. We need to make sure the monitors * do not overlap, as otherwise we can't implement `al_set_window_position`. * We do this by creating an extended 2D plane which uses a global scale * factor with slots for the monitors. The slots are big enough * to fit monitors with the largest scale factor, but otherwise contain * empty space. When calling `al_get/set_window_position` we * transform from this extended plane to the visual coordinates used by the OS. * * OSX uses bottom-left, y-up coordinate system, so we need to flip things around. */ info->x1 = (int) rc.origin.x * global_scale_factor; info->x2 = (int) (rc.origin.x * global_scale_factor + rc.size.width * scale_factor); info->y1 = (int) (global_scale_factor * (primary_y - (rc.size.height + rc.origin.y))); info->y2 = (int) (info->y1 + scale_factor * rc.size.height); ALLEGRO_INFO("Display %d has coordinates (%d, %d) - (%d, %d)\n", adapter, info->x1, info->y1, info->x2, info->y2); return true; } else { return false; } /* CGDisplayCount count; // Assume no more than 16 monitors connected static const int max_displays = 16; CGDirectDisplayID displays[max_displays]; CGError err = CGGetActiveDisplayList(max_displays, displays, &count); if (err == kCGErrorSuccess && adapter >= 0 && adapter < (int) count) { CGRect rc = CGDisplayBounds(displays[adapter]); info->x1 = (int) rc.origin.x; info->x2 = (int) (rc.origin.x + rc.size.width); info->y1 = (int) rc.origin.y; info->y2 = (int) (rc.origin.y + rc.size.height); ALLEGRO_INFO("Display %d has coordinates (%d, %d) - (%d, %d)\n", adapter, info->x1, info->y1, info->x2, info->y2); return true; } else { return false; } */ } /* osx_get_monitor_dpi: * Return the dots per inch value of one monitor */ static int osx_get_monitor_dpi(int adapter) { int count = osx_get_num_video_adapters(); if (adapter < count) { NSScreen *screen = [[NSScreen screens] objectAtIndex: adapter]; NSRect rc = [screen frame]; rc = [screen convertRectToBacking: rc]; NSDictionary *description = [screen deviceDescription]; CGSize size = CGDisplayScreenSize([[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); float dpi_hori = rc.size.width / (_AL_INCHES_PER_MM * size.width); float dpi_vert = rc.size.height / (_AL_INCHES_PER_MM * size.height); return sqrt(dpi_hori * dpi_vert); } else { return 0; } } /* osx_inhibit_screensaver: * Stops the screen dimming/screen saver activation if inhibit is true * otherwise re-enable normal behaviour. The last call takes force (i.e * it does not count the calls to inhibit/uninhibit. * Always returns true */ static bool osx_inhibit_screensaver(bool inhibit) { // Send a message to the App's delegate always on the main thread NSObject* delegate = [NSApp delegate]; [delegate performSelectorOnMainThread: @selector(setInhibitScreenSaver:) withObject: [NSNumber numberWithBool:inhibit ? YES : NO] waitUntilDone: NO]; ALLEGRO_INFO("Stop screensaver\n"); return true; } /* NSImageFromAllegroBitmap: * Create an NSImage from an Allegro bitmap * This could definitely be speeded up if necessary. */ NSImage* NSImageFromAllegroBitmap(ALLEGRO_BITMAP* bmp) { int w = al_get_bitmap_width(bmp); int h = al_get_bitmap_height(bmp); NSImage* img = [[NSImage alloc] initWithSize: NSMakeSize((float) w, (float) h)]; NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL // Allocate memory yourself pixelsWide:w pixelsHigh:h bitsPerSample: 8 samplesPerPixel: 4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow: 0 // Calculate yourself bitsPerPixel:0 ];// Calculate yourself al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); int x, y; for (y = 0; y 1 */ static bool osx_get_cursor_position(int *x, int *y) { NSPoint p = [NSEvent mouseLocation]; NSRect r = [[NSScreen mainScreen] frame]; *x = p.x; *y = r.size.height - p.y; return true; } static void osx_thread_init(ALLEGRO_THREAD *thread) { } static void osx_thread_exit(ALLEGRO_THREAD *thread) { } /* Internal function to get a reference to this driver. */ ALLEGRO_SYSTEM_INTERFACE *_al_system_osx_driver(void) { static ALLEGRO_SYSTEM_INTERFACE* vt = NULL; if (vt == NULL) { vt = al_malloc(sizeof(*vt)); memset(vt, 0, sizeof(*vt)); vt->id = ALLEGRO_SYSTEM_ID_MACOSX; vt->initialize = osx_sys_init; vt->get_display_driver = _al_osx_get_display_driver; vt->get_keyboard_driver = _al_osx_get_keyboard_driver; vt->get_mouse_driver = _al_osx_get_mouse_driver; vt->get_joystick_driver = _al_osx_get_joystick_driver; vt->get_num_display_modes = _al_osx_get_num_display_modes; vt->get_display_mode = _al_osx_get_display_mode; vt->shutdown_system = osx_sys_exit; vt->get_num_video_adapters = osx_get_num_video_adapters; vt->get_monitor_info = osx_get_monitor_info; vt->get_monitor_dpi = osx_get_monitor_dpi; vt->create_mouse_cursor = _al_osx_create_mouse_cursor; vt->destroy_mouse_cursor = _al_osx_destroy_mouse_cursor; vt->get_cursor_position = osx_get_cursor_position; vt->get_path = _al_osx_get_path; vt->inhibit_screensaver = osx_inhibit_screensaver; vt->thread_init = osx_thread_init; vt->thread_exit = osx_thread_exit; vt->get_time = _al_unix_get_time; vt->rest = _al_unix_rest; vt->init_timeout = _al_unix_init_timeout; }; return vt; } /* This is a function each platform must define to register all available * system drivers. */ void _al_register_system_interfaces() { ALLEGRO_SYSTEM_INTERFACE **add; add = _al_vector_alloc_back(&_al_system_interfaces); *add = _al_system_osx_driver(); } /* Implementation of get_path */ ALLEGRO_PATH *_al_osx_get_path(int id) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString* ans = nil; NSArray* paths = nil; NSString *org_name = [[NSString alloc] initWithUTF8String: al_get_org_name()]; NSString *app_name = [[NSString alloc] initWithUTF8String: al_get_app_name()]; ALLEGRO_PATH *path = NULL; switch (id) { case ALLEGRO_RESOURCES_PATH: if (_al_osx_bundle) { ans = [_al_osx_bundle resourcePath]; path = al_create_path_for_directory([ans UTF8String]); } else { /* Otherwise, return the executable pathname */ path = _al_osx_get_path(ALLEGRO_EXENAME_PATH); al_set_path_filename(path, NULL); } break; case ALLEGRO_TEMP_PATH: ans = NSTemporaryDirectory(); path = al_create_path_for_directory([ans UTF8String]); break; case ALLEGRO_USER_DATA_PATH: paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); if ([paths count] > 0) ans = [paths objectAtIndex: 0]; if (ans != nil) { /* Append program name */ ans = [[ans stringByAppendingPathComponent: org_name] stringByAppendingPathComponent: app_name]; } path = al_create_path_for_directory([ans UTF8String]); break; case ALLEGRO_USER_HOME_PATH: ans = NSHomeDirectory(); path = al_create_path_for_directory([ans UTF8String]); break; case ALLEGRO_USER_DOCUMENTS_PATH: paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); if ([paths count] > 0) ans = [paths objectAtIndex: 0]; path = al_create_path_for_directory([ans UTF8String]); break; case ALLEGRO_EXENAME_PATH: { char exepath[PATH_MAX]; uint32_t size = sizeof(exepath); if (_NSGetExecutablePath(exepath, &size) == 0) ans = [NSString stringWithUTF8String: exepath]; path = al_create_path([ans UTF8String]); break; } case ALLEGRO_USER_SETTINGS_PATH: paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); if ([paths count] > 0) ans = [paths objectAtIndex: 0]; if (ans != nil) { /* Append program name */ ans = [[ans stringByAppendingPathComponent: org_name] stringByAppendingPathComponent: app_name]; } path = al_create_path_for_directory([ans UTF8String]); break; default: break; } [org_name release]; [app_name release]; [pool drain]; return path; } /* _al_osx_post_quit * called when the user clicks the quit menu or cmd-Q. * Currently just sends a window close event to all windows. * This is a bit unsatisfactory */ void _al_osx_post_quit(void) { unsigned int i; _AL_VECTOR* dpys = &al_get_system_driver()->displays; // Iterate through all existing displays for (i = 0; i < _al_vector_size(dpys); ++i) { ALLEGRO_DISPLAY* dpy = *(ALLEGRO_DISPLAY**) _al_vector_ref(dpys, i); ALLEGRO_EVENT_SOURCE* src = &(dpy->es); _al_event_source_lock(src); ALLEGRO_EVENT evt; evt.type = ALLEGRO_EVENT_DISPLAY_CLOSE; // Send event _al_event_source_emit_event(src, &evt); _al_event_source_unlock(src); } } /* Local variables: */ /* c-basic-offset: 3 */ /* indent-tabs-mode: nil */ /* End: */ allegro5-5.2.10.1/src/math.c000066400000000000000000000422031473414355200153450ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Fixed point math routines and lookup tables. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #include #include "allegro5/allegro.h" #ifdef ALLEGRO_MSVC #define hypotf(x, y) _hypotf((x), (y)) #endif al_fixed _al_fix_cos_tbl[512] = { /* precalculated fixed point (16.16) cosines for a full circle (0-255) */ 65536L, 65531L, 65516L, 65492L, 65457L, 65413L, 65358L, 65294L, 65220L, 65137L, 65043L, 64940L, 64827L, 64704L, 64571L, 64429L, 64277L, 64115L, 63944L, 63763L, 63572L, 63372L, 63162L, 62943L, 62714L, 62476L, 62228L, 61971L, 61705L, 61429L, 61145L, 60851L, 60547L, 60235L, 59914L, 59583L, 59244L, 58896L, 58538L, 58172L, 57798L, 57414L, 57022L, 56621L, 56212L, 55794L, 55368L, 54934L, 54491L, 54040L, 53581L, 53114L, 52639L, 52156L, 51665L, 51166L, 50660L, 50146L, 49624L, 49095L, 48559L, 48015L, 47464L, 46906L, 46341L, 45769L, 45190L, 44604L, 44011L, 43412L, 42806L, 42194L, 41576L, 40951L, 40320L, 39683L, 39040L, 38391L, 37736L, 37076L, 36410L, 35738L, 35062L, 34380L, 33692L, 33000L, 32303L, 31600L, 30893L, 30182L, 29466L, 28745L, 28020L, 27291L, 26558L, 25821L, 25080L, 24335L, 23586L, 22834L, 22078L, 21320L, 20557L, 19792L, 19024L, 18253L, 17479L, 16703L, 15924L, 15143L, 14359L, 13573L, 12785L, 11996L, 11204L, 10411L, 9616L, 8820L, 8022L, 7224L, 6424L, 5623L, 4821L, 4019L, 3216L, 2412L, 1608L, 804L, 0L, -804L, -1608L, -2412L, -3216L, -4019L, -4821L, -5623L, -6424L, -7224L, -8022L, -8820L, -9616L, -10411L, -11204L, -11996L, -12785L, -13573L, -14359L, -15143L, -15924L, -16703L, -17479L, -18253L, -19024L, -19792L, -20557L, -21320L, -22078L, -22834L, -23586L, -24335L, -25080L, -25821L, -26558L, -27291L, -28020L, -28745L, -29466L, -30182L, -30893L, -31600L, -32303L, -33000L, -33692L, -34380L, -35062L, -35738L, -36410L, -37076L, -37736L, -38391L, -39040L, -39683L, -40320L, -40951L, -41576L, -42194L, -42806L, -43412L, -44011L, -44604L, -45190L, -45769L, -46341L, -46906L, -47464L, -48015L, -48559L, -49095L, -49624L, -50146L, -50660L, -51166L, -51665L, -52156L, -52639L, -53114L, -53581L, -54040L, -54491L, -54934L, -55368L, -55794L, -56212L, -56621L, -57022L, -57414L, -57798L, -58172L, -58538L, -58896L, -59244L, -59583L, -59914L, -60235L, -60547L, -60851L, -61145L, -61429L, -61705L, -61971L, -62228L, -62476L, -62714L, -62943L, -63162L, -63372L, -63572L, -63763L, -63944L, -64115L, -64277L, -64429L, -64571L, -64704L, -64827L, -64940L, -65043L, -65137L, -65220L, -65294L, -65358L, -65413L, -65457L, -65492L, -65516L, -65531L, -65536L, -65531L, -65516L, -65492L, -65457L, -65413L, -65358L, -65294L, -65220L, -65137L, -65043L, -64940L, -64827L, -64704L, -64571L, -64429L, -64277L, -64115L, -63944L, -63763L, -63572L, -63372L, -63162L, -62943L, -62714L, -62476L, -62228L, -61971L, -61705L, -61429L, -61145L, -60851L, -60547L, -60235L, -59914L, -59583L, -59244L, -58896L, -58538L, -58172L, -57798L, -57414L, -57022L, -56621L, -56212L, -55794L, -55368L, -54934L, -54491L, -54040L, -53581L, -53114L, -52639L, -52156L, -51665L, -51166L, -50660L, -50146L, -49624L, -49095L, -48559L, -48015L, -47464L, -46906L, -46341L, -45769L, -45190L, -44604L, -44011L, -43412L, -42806L, -42194L, -41576L, -40951L, -40320L, -39683L, -39040L, -38391L, -37736L, -37076L, -36410L, -35738L, -35062L, -34380L, -33692L, -33000L, -32303L, -31600L, -30893L, -30182L, -29466L, -28745L, -28020L, -27291L, -26558L, -25821L, -25080L, -24335L, -23586L, -22834L, -22078L, -21320L, -20557L, -19792L, -19024L, -18253L, -17479L, -16703L, -15924L, -15143L, -14359L, -13573L, -12785L, -11996L, -11204L, -10411L, -9616L, -8820L, -8022L, -7224L, -6424L, -5623L, -4821L, -4019L, -3216L, -2412L, -1608L, -804L, 0L, 804L, 1608L, 2412L, 3216L, 4019L, 4821L, 5623L, 6424L, 7224L, 8022L, 8820L, 9616L, 10411L, 11204L, 11996L, 12785L, 13573L, 14359L, 15143L, 15924L, 16703L, 17479L, 18253L, 19024L, 19792L, 20557L, 21320L, 22078L, 22834L, 23586L, 24335L, 25080L, 25821L, 26558L, 27291L, 28020L, 28745L, 29466L, 30182L, 30893L, 31600L, 32303L, 33000L, 33692L, 34380L, 35062L, 35738L, 36410L, 37076L, 37736L, 38391L, 39040L, 39683L, 40320L, 40951L, 41576L, 42194L, 42806L, 43412L, 44011L, 44604L, 45190L, 45769L, 46341L, 46906L, 47464L, 48015L, 48559L, 49095L, 49624L, 50146L, 50660L, 51166L, 51665L, 52156L, 52639L, 53114L, 53581L, 54040L, 54491L, 54934L, 55368L, 55794L, 56212L, 56621L, 57022L, 57414L, 57798L, 58172L, 58538L, 58896L, 59244L, 59583L, 59914L, 60235L, 60547L, 60851L, 61145L, 61429L, 61705L, 61971L, 62228L, 62476L, 62714L, 62943L, 63162L, 63372L, 63572L, 63763L, 63944L, 64115L, 64277L, 64429L, 64571L, 64704L, 64827L, 64940L, 65043L, 65137L, 65220L, 65294L, 65358L, 65413L, 65457L, 65492L, 65516L, 65531L }; al_fixed _al_fix_tan_tbl[256] = { /* precalculated fixed point (16.16) tangents for a half circle (0-127) */ 0L, 804L, 1609L, 2414L, 3220L, 4026L, 4834L, 5644L, 6455L, 7268L, 8083L, 8901L, 9721L, 10545L, 11372L, 12202L, 13036L, 13874L, 14717L, 15564L, 16416L, 17273L, 18136L, 19005L, 19880L, 20762L, 21650L, 22546L, 23449L, 24360L, 25280L, 26208L, 27146L, 28093L, 29050L, 30018L, 30996L, 31986L, 32988L, 34002L, 35030L, 36071L, 37126L, 38196L, 39281L, 40382L, 41500L, 42636L, 43790L, 44963L, 46156L, 47369L, 48605L, 49863L, 51145L, 52451L, 53784L, 55144L, 56532L, 57950L, 59398L, 60880L, 62395L, 63947L, 65536L, 67165L, 68835L, 70548L, 72308L, 74116L, 75974L, 77887L, 79856L, 81885L, 83977L, 86135L, 88365L, 90670L, 93054L, 95523L, 98082L, 100736L, 103493L, 106358L, 109340L, 112447L, 115687L, 119071L, 122609L, 126314L, 130198L, 134276L, 138564L, 143081L, 147847L, 152884L, 158218L, 163878L, 169896L, 176309L, 183161L, 190499L, 198380L, 206870L, 216043L, 225990L, 236817L, 248648L, 261634L, 275959L, 291845L, 309568L, 329472L, 351993L, 377693L, 407305L, 441808L, 482534L, 531352L, 590958L, 665398L, 761030L, 888450L, 1066730L,1334016L,1779314L,2669641L,5340086L, -2147483647L,-5340086L,-2669641L,-1779314L,-1334016L,-1066730L,-888450L,-761030L, -665398L,-590958L,-531352L,-482534L,-441808L,-407305L,-377693L,-351993L, -329472L,-309568L,-291845L,-275959L,-261634L,-248648L,-236817L,-225990L, -216043L,-206870L,-198380L,-190499L,-183161L,-176309L,-169896L,-163878L, -158218L,-152884L,-147847L,-143081L,-138564L,-134276L,-130198L,-126314L, -122609L,-119071L,-115687L,-112447L,-109340L,-106358L,-103493L,-100736L, -98082L, -95523L, -93054L, -90670L, -88365L, -86135L, -83977L, -81885L, -79856L, -77887L, -75974L, -74116L, -72308L, -70548L, -68835L, -67165L, -65536L, -63947L, -62395L, -60880L, -59398L, -57950L, -56532L, -55144L, -53784L, -52451L, -51145L, -49863L, -48605L, -47369L, -46156L, -44963L, -43790L, -42636L, -41500L, -40382L, -39281L, -38196L, -37126L, -36071L, -35030L, -34002L, -32988L, -31986L, -30996L, -30018L, -29050L, -28093L, -27146L, -26208L, -25280L, -24360L, -23449L, -22546L, -21650L, -20762L, -19880L, -19005L, -18136L, -17273L, -16416L, -15564L, -14717L, -13874L, -13036L, -12202L, -11372L, -10545L, -9721L, -8901L, -8083L, -7268L, -6455L, -5644L, -4834L, -4026L, -3220L, -2414L, -1609L, -804L }; al_fixed _al_fix_acos_tbl[513] = { /* precalculated fixed point (16.16) inverse cosines (-1 to 1) */ 0x800000L, 0x7C65C7L, 0x7AE75AL, 0x79C19EL, 0x78C9BEL, 0x77EF25L, 0x772953L, 0x76733AL, 0x75C991L, 0x752A10L, 0x74930CL, 0x740345L, 0x7379C1L, 0x72F5BAL, 0x72768FL, 0x71FBBCL, 0x7184D3L, 0x711174L, 0x70A152L, 0x703426L, 0x6FC9B5L, 0x6F61C9L, 0x6EFC36L, 0x6E98D1L, 0x6E3777L, 0x6DD805L, 0x6D7A5EL, 0x6D1E68L, 0x6CC40BL, 0x6C6B2FL, 0x6C13C1L, 0x6BBDAFL, 0x6B68E6L, 0x6B1558L, 0x6AC2F5L, 0x6A71B1L, 0x6A217EL, 0x69D251L, 0x698420L, 0x6936DFL, 0x68EA85L, 0x689F0AL, 0x685465L, 0x680A8DL, 0x67C17DL, 0x67792CL, 0x673194L, 0x66EAAFL, 0x66A476L, 0x665EE5L, 0x6619F5L, 0x65D5A2L, 0x6591E7L, 0x654EBFL, 0x650C26L, 0x64CA18L, 0x648890L, 0x64478CL, 0x640706L, 0x63C6FCL, 0x63876BL, 0x63484FL, 0x6309A5L, 0x62CB6AL, 0x628D9CL, 0x625037L, 0x621339L, 0x61D69FL, 0x619A68L, 0x615E90L, 0x612316L, 0x60E7F7L, 0x60AD31L, 0x6072C3L, 0x6038A9L, 0x5FFEE3L, 0x5FC56EL, 0x5F8C49L, 0x5F5372L, 0x5F1AE7L, 0x5EE2A7L, 0x5EAAB0L, 0x5E7301L, 0x5E3B98L, 0x5E0473L, 0x5DCD92L, 0x5D96F3L, 0x5D6095L, 0x5D2A76L, 0x5CF496L, 0x5CBEF2L, 0x5C898BL, 0x5C545EL, 0x5C1F6BL, 0x5BEAB0L, 0x5BB62DL, 0x5B81E1L, 0x5B4DCAL, 0x5B19E7L, 0x5AE638L, 0x5AB2BCL, 0x5A7F72L, 0x5A4C59L, 0x5A1970L, 0x59E6B6L, 0x59B42AL, 0x5981CCL, 0x594F9BL, 0x591D96L, 0x58EBBDL, 0x58BA0EL, 0x588889L, 0x58572DL, 0x5825FAL, 0x57F4EEL, 0x57C40AL, 0x57934DL, 0x5762B5L, 0x573243L, 0x5701F5L, 0x56D1CCL, 0x56A1C6L, 0x5671E4L, 0x564224L, 0x561285L, 0x55E309L, 0x55B3ADL, 0x558471L, 0x555555L, 0x552659L, 0x54F77BL, 0x54C8BCL, 0x549A1BL, 0x546B98L, 0x543D31L, 0x540EE7L, 0x53E0B9L, 0x53B2A7L, 0x5384B0L, 0x5356D4L, 0x532912L, 0x52FB6BL, 0x52CDDDL, 0x52A068L, 0x52730CL, 0x5245C9L, 0x52189EL, 0x51EB8BL, 0x51BE8FL, 0x5191AAL, 0x5164DCL, 0x513825L, 0x510B83L, 0x50DEF7L, 0x50B280L, 0x50861FL, 0x5059D2L, 0x502D99L, 0x500175L, 0x4FD564L, 0x4FA967L, 0x4F7D7DL, 0x4F51A6L, 0x4F25E2L, 0x4EFA30L, 0x4ECE90L, 0x4EA301L, 0x4E7784L, 0x4E4C19L, 0x4E20BEL, 0x4DF574L, 0x4DCA3AL, 0x4D9F10L, 0x4D73F6L, 0x4D48ECL, 0x4D1DF1L, 0x4CF305L, 0x4CC829L, 0x4C9D5AL, 0x4C729AL, 0x4C47E9L, 0x4C1D45L, 0x4BF2AEL, 0x4BC826L, 0x4B9DAAL, 0x4B733BL, 0x4B48D9L, 0x4B1E84L, 0x4AF43BL, 0x4AC9FEL, 0x4A9FCDL, 0x4A75A7L, 0x4A4B8DL, 0x4A217EL, 0x49F77AL, 0x49CD81L, 0x49A393L, 0x4979AFL, 0x494FD5L, 0x492605L, 0x48FC3FL, 0x48D282L, 0x48A8CFL, 0x487F25L, 0x485584L, 0x482BECL, 0x48025DL, 0x47D8D6L, 0x47AF57L, 0x4785E0L, 0x475C72L, 0x47330AL, 0x4709ABL, 0x46E052L, 0x46B701L, 0x468DB7L, 0x466474L, 0x463B37L, 0x461201L, 0x45E8D0L, 0x45BFA6L, 0x459682L, 0x456D64L, 0x45444BL, 0x451B37L, 0x44F229L, 0x44C920L, 0x44A01CL, 0x44771CL, 0x444E21L, 0x44252AL, 0x43FC38L, 0x43D349L, 0x43AA5FL, 0x438178L, 0x435894L, 0x432FB4L, 0x4306D8L, 0x42DDFEL, 0x42B527L, 0x428C53L, 0x426381L, 0x423AB2L, 0x4211E5L, 0x41E91AL, 0x41C051L, 0x41978AL, 0x416EC5L, 0x414601L, 0x411D3EL, 0x40F47CL, 0x40CBBBL, 0x40A2FBL, 0x407A3CL, 0x40517DL, 0x4028BEL, 0x400000L, 0x3FD742L, 0x3FAE83L, 0x3F85C4L, 0x3F5D05L, 0x3F3445L, 0x3F0B84L, 0x3EE2C2L, 0x3EB9FFL, 0x3E913BL, 0x3E6876L, 0x3E3FAFL, 0x3E16E6L, 0x3DEE1BL, 0x3DC54EL, 0x3D9C7FL, 0x3D73ADL, 0x3D4AD9L, 0x3D2202L, 0x3CF928L, 0x3CD04CL, 0x3CA76CL, 0x3C7E88L, 0x3C55A1L, 0x3C2CB7L, 0x3C03C8L, 0x3BDAD6L, 0x3BB1DFL, 0x3B88E4L, 0x3B5FE4L, 0x3B36E0L, 0x3B0DD7L, 0x3AE4C9L, 0x3ABBB5L, 0x3A929CL, 0x3A697EL, 0x3A405AL, 0x3A1730L, 0x39EDFFL, 0x39C4C9L, 0x399B8CL, 0x397249L, 0x3948FFL, 0x391FAEL, 0x38F655L, 0x38CCF6L, 0x38A38EL, 0x387A20L, 0x3850A9L, 0x38272AL, 0x37FDA3L, 0x37D414L, 0x37AA7CL, 0x3780DBL, 0x375731L, 0x372D7EL, 0x3703C1L, 0x36D9FBL, 0x36B02BL, 0x368651L, 0x365C6DL, 0x36327FL, 0x360886L, 0x35DE82L, 0x35B473L, 0x358A59L, 0x356033L, 0x353602L, 0x350BC5L, 0x34E17CL, 0x34B727L, 0x348CC5L, 0x346256L, 0x3437DAL, 0x340D52L, 0x33E2BBL, 0x33B817L, 0x338D66L, 0x3362A6L, 0x3337D7L, 0x330CFBL, 0x32E20FL, 0x32B714L, 0x328C0AL, 0x3260F0L, 0x3235C6L, 0x320A8CL, 0x31DF42L, 0x31B3E7L, 0x31887CL, 0x315CFFL, 0x313170L, 0x3105D0L, 0x30DA1EL, 0x30AE5AL, 0x308283L, 0x305699L, 0x302A9CL, 0x2FFE8BL, 0x2FD267L, 0x2FA62EL, 0x2F79E1L, 0x2F4D80L, 0x2F2109L, 0x2EF47DL, 0x2EC7DBL, 0x2E9B24L, 0x2E6E56L, 0x2E4171L, 0x2E1475L, 0x2DE762L, 0x2DBA37L, 0x2D8CF4L, 0x2D5F98L, 0x2D3223L, 0x2D0495L, 0x2CD6EEL, 0x2CA92CL, 0x2C7B50L, 0x2C4D59L, 0x2C1F47L, 0x2BF119L, 0x2BC2CFL, 0x2B9468L, 0x2B65E5L, 0x2B3744L, 0x2B0885L, 0x2AD9A7L, 0x2AAAABL, 0x2A7B8FL, 0x2A4C53L, 0x2A1CF7L, 0x29ED7BL, 0x29BDDCL, 0x298E1CL, 0x295E3AL, 0x292E34L, 0x28FE0BL, 0x28CDBDL, 0x289D4BL, 0x286CB3L, 0x283BF6L, 0x280B12L, 0x27DA06L, 0x27A8D3L, 0x277777L, 0x2745F2L, 0x271443L, 0x26E26AL, 0x26B065L, 0x267E34L, 0x264BD6L, 0x26194AL, 0x25E690L, 0x25B3A7L, 0x25808EL, 0x254D44L, 0x2519C8L, 0x24E619L, 0x24B236L, 0x247E1FL, 0x2449D3L, 0x241550L, 0x23E095L, 0x23ABA2L, 0x237675L, 0x23410EL, 0x230B6AL, 0x22D58AL, 0x229F6BL, 0x22690DL, 0x22326EL, 0x21FB8DL, 0x21C468L, 0x218CFFL, 0x215550L, 0x211D59L, 0x20E519L, 0x20AC8EL, 0x2073B7L, 0x203A92L, 0x20011DL, 0x1FC757L, 0x1F8D3DL, 0x1F52CFL, 0x1F1809L, 0x1EDCEAL, 0x1EA170L, 0x1E6598L, 0x1E2961L, 0x1DECC7L, 0x1DAFC9L, 0x1D7264L, 0x1D3496L, 0x1CF65BL, 0x1CB7B1L, 0x1C7895L, 0x1C3904L, 0x1BF8FAL, 0x1BB874L, 0x1B7770L, 0x1B35E8L, 0x1AF3DAL, 0x1AB141L, 0x1A6E19L, 0x1A2A5EL, 0x19E60BL, 0x19A11BL, 0x195B8AL, 0x191551L, 0x18CE6CL, 0x1886D4L, 0x183E83L, 0x17F573L, 0x17AB9BL, 0x1760F6L, 0x17157BL, 0x16C921L, 0x167BE0L, 0x162DAFL, 0x15DE82L, 0x158E4FL, 0x153D0BL, 0x14EAA8L, 0x14971AL, 0x144251L, 0x13EC3FL, 0x1394D1L, 0x133BF5L, 0x12E198L, 0x1285A2L, 0x1227FBL, 0x11C889L, 0x11672FL, 0x1103CAL, 0x109E37L, 0x10364BL, 0xFCBDAL, 0xF5EAEL, 0xEEE8CL, 0xE7B2DL, 0xE0444L, 0xD8971L, 0xD0A46L, 0xC863FL, 0xBFCBBL, 0xB6CF4L, 0xAD5F0L, 0xA366FL, 0x98CC6L, 0x8D6ADL, 0x810DBL, 0x73642L, 0x63E62L, 0x518A6L, 0x39A39L, 0x0L }; /* Function: al_fixatan * Fixed point inverse tangent. Does a binary search on the tan table. */ al_fixed al_fixatan(al_fixed x) { int a, b, c; /* for binary search */ al_fixed d; /* difference value for search */ if (x >= 0) { /* search the first part of tan table */ a = 0; b = 127; } else { /* search the second half instead */ a = 128; b = 255; } do { c = (a + b) >> 1; d = x - _al_fix_tan_tbl[c]; if (d > 0) a = c + 1; else if (d < 0) b = c - 1; } while ((a <= b) && (d)); if (x >= 0) return ((long)c) << 15; return (-0x00800000L + (((long)c) << 15)); } /* Function: al_fixatan2 * Like the libc atan2, but for fixed point numbers. */ al_fixed al_fixatan2(al_fixed y, al_fixed x) { al_fixed r; if (x==0) { if (y==0) { al_set_errno(EDOM); return 0L; } else return ((y < 0) ? -0x00400000L : 0x00400000L); } al_set_errno(0); r = al_fixdiv(y, x); if (al_get_errno()) { al_set_errno(0); return ((y < 0) ? -0x00400000L : 0x00400000L); } r = al_fixatan(r); if (x >= 0) return r; if (y >= 0) return 0x00800000L + r; return r - 0x00800000L; } /* Enum: al_fixtorad_r * Ratios for converting between radians and fixed point angles. * 2pi/256 */ const al_fixed al_fixtorad_r = (al_fixed)1608; /* Enum: al_radtofix_r * Ratios for converting between radians and fixed point angles. * 256/2pi */ const al_fixed al_radtofix_r = (al_fixed)2670177; /* Function: al_fixsqrt * Fixed point square root routine for non-i386. */ al_fixed al_fixsqrt(al_fixed x) { if (x > 0) return al_ftofix(sqrt(al_fixtof(x))); if (x < 0) al_set_errno(EDOM); return 0; } /* Function: al_fixhypot * Fixed point sqrt (x*x+y*y) for non-i386. */ al_fixed al_fixhypot(al_fixed x, al_fixed y) { return al_ftofix(hypotf(al_fixtof(x), al_fixtof(y))); } /* These prototypes exist for documentation only. */ /* Function: al_itofix */ al_fixed al_itofix(int x); /* Function: al_fixtoi */ int al_fixtoi(al_fixed x); /* Function: al_fixfloor */ int al_fixfloor(al_fixed x); /* Function: al_fixceil */ int al_fixceil(al_fixed x); /* Function: al_ftofix */ al_fixed al_ftofix(double x); /* Function: al_fixtof */ double al_fixtof(al_fixed x); /* Function: al_fixadd */ al_fixed al_fixadd(al_fixed x, al_fixed y); /* Function: al_fixsub */ al_fixed al_fixsub(al_fixed x, al_fixed y); /* Function: al_fixmul */ al_fixed al_fixmul(al_fixed x, al_fixed y); /* Function: al_fixdiv */ al_fixed al_fixdiv(al_fixed x, al_fixed y); /* Function: al_fixcos */ al_fixed al_fixcos(al_fixed x); /* Function: al_fixsin */ al_fixed al_fixsin(al_fixed x); /* Function: al_fixtan */ al_fixed al_fixtan(al_fixed x); /* Function: al_fixacos */ al_fixed al_fixacos(al_fixed x); /* Function: al_fixasin */ al_fixed al_fixasin(al_fixed x); allegro5-5.2.10.1/src/memblit.c000066400000000000000000000276001473414355200160510ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Memory bitmap drawing routines * */ #define _AL_NO_BLEND_INLINE_FUNC #include "allegro5/allegro.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_blend.h" #include "allegro5/internal/aintern_convert.h" #include "allegro5/internal/aintern_memblit.h" #include "allegro5/internal/aintern_transform.h" #include "allegro5/internal/aintern_tri_soft.h" #include #define MIN _ALLEGRO_MIN #define MAX _ALLEGRO_MAX static void _al_draw_transformed_scaled_bitmap_memory( ALLEGRO_BITMAP *src, ALLEGRO_COLOR tint, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, int flags); static void _al_draw_bitmap_region_memory_fast(ALLEGRO_BITMAP *bitmap, int sx, int sy, int sw, int sh, int dx, int dy, int flags); /* The CLIPPER macro takes pre-clipped coordinates for both the source * and destination bitmaps and clips them as necessary, taking sub- * bitmaps into consideration. The wr and hr parameters are the ratio of * source width & height to destination width & height _before_ clipping. * * First the left (top) coordinates are moved inward. Then the right * (bottom) coordinates are moved inward. The changes are applied * simultaneously to the complementary bitmap with scaling taken into * consideration. * * The coordinates are modified, and the sub-bitmaps are set to the * parent bitmaps. If nothing needs to be drawn, the macro exits the * function. */ #define CLIPPER(src, sx, sy, sw, sh, dest, dx, dy, dw, dh, wr, hr, flags)\ { \ float cl = dest->cl, cr = dest->cr_excl; \ float ct = dest->ct, cb = dest->cb_excl; \ float sx_ = 0, sy_ = 0, sw_ = 0, sh_ = 0; \ bool hflip = false, vflip = false; \ if (dw < 0) { \ hflip = true; \ dx += dw; \ dw = -dw; \ sx_ = sx; sw_ = sw; \ } \ if (dh < 0) { \ vflip = true; \ dy += dh; \ dh = -dh; \ sy_ = sy; sh_ = sh; \ } \ \ if (dest->parent) { \ dx += dest->xofs; \ dy += dest->yofs; \ \ cl += dest->xofs; \ if (cl >= dest->parent->w) { \ return; \ } \ else if (cl < 0) { \ cl = 0; \ } \ \ ct += dest->yofs; \ if (ct >= dest->parent->h) { \ return; \ } \ else if (ct < 0) { \ ct = 0; \ } \ \ cr = MIN(dest->parent->w, cr + dest->xofs); \ cb = MIN(dest->parent->h, cb + dest->yofs); \ \ dest = dest->parent; \ } \ \ if (dx < cl) { \ const int d = cl - dx; \ dx = cl; \ dw -= d; \ sx += d * wr; \ sw -= d * wr; \ } \ \ if (dx + dw > cr) { \ const int d = dx + dw - cr; \ dw -= d; \ sw -= d * wr; \ } \ \ if (dy < ct) { \ const int d = ct - dy; \ dy = ct; \ dh -= d; \ sy += d * hr; \ sh -= d * hr; \ } \ \ if (dy + dh > cb) { \ const int d = dy + dh - cb; \ dh -= d; \ sh -= d * hr; \ } \ \ if (sh <= 0 || sw <= 0) return; \ \ if (hflip) {dx += dw; dw = -dw; sx = sx_ + sw_ - sw + sx_ - sx; dx--;} \ if (vflip) {dy += dh; dh = -dh; sy = sy_ + sh_ - sh + sy_ - sy; dy--;} \ } void _al_draw_bitmap_region_memory(ALLEGRO_BITMAP *src, ALLEGRO_COLOR tint, int sx, int sy, int sw, int sh, int dx, int dy, int flags) { int op, src_mode, dst_mode; int op_alpha, src_alpha, dst_alpha; float xtrans, ytrans; ASSERT(src->parent == NULL); al_get_separate_bitmap_blender(&op, &src_mode, &dst_mode, &op_alpha, &src_alpha, &dst_alpha); if (_AL_DEST_IS_ZERO && _AL_SRC_NOT_MODIFIED_TINT_WHITE && _al_transform_is_translation(al_get_current_transform(), &xtrans, &ytrans)) { _al_draw_bitmap_region_memory_fast(src, sx, sy, sw, sh, dx + xtrans, dy + ytrans, flags); return; } /* We used to have special cases for translation/scaling only, but the * general version received much more optimisation and ended up being * faster. */ _al_draw_transformed_scaled_bitmap_memory(src, tint, sx, sy, sw, sh, dx, dy, sw, sh, flags); } static void _al_draw_transformed_bitmap_memory(ALLEGRO_BITMAP *src, ALLEGRO_COLOR tint, int sx, int sy, int sw, int sh, int dw, int dh, ALLEGRO_TRANSFORM* local_trans, int flags) { float xsf[4], ysf[4]; int tl = 0, tr = 1, bl = 3, br = 2; int tmp; ALLEGRO_VERTEX v[4]; ASSERT(_al_pixel_format_is_real(al_get_bitmap_format(src))); /* Decide what order to take corners in. */ if (flags & ALLEGRO_FLIP_VERTICAL) { tl = 3; tr = 2; bl = 0; br = 1; } else { tl = 0; tr = 1; bl = 3; br = 2; } if (flags & ALLEGRO_FLIP_HORIZONTAL) { tmp = tl; tl = tr; tr = tmp; tmp = bl; bl = br; br = tmp; } xsf[0] = 0; ysf[0] = 0; xsf[1] = dw; ysf[1] = 0; xsf[2] = 0; ysf[2] = dh; al_transform_coordinates(local_trans, &xsf[0], &ysf[0]); al_transform_coordinates(local_trans, &xsf[1], &ysf[1]); al_transform_coordinates(local_trans, &xsf[2], &ysf[2]); v[tl].x = xsf[0]; v[tl].y = ysf[0]; v[tl].z = 0; v[tl].u = sx; v[tl].v = sy; v[tl].color = tint; v[tr].x = xsf[1]; v[tr].y = ysf[1]; v[tr].z = 0; v[tr].u = sx + sw; v[tr].v = sy; v[tr].color = tint; v[br].x = xsf[2] + xsf[1] - xsf[0]; v[br].y = ysf[2] + ysf[1] - ysf[0]; v[br].z = 0; v[br].u = sx + sw; v[br].v = sy + sh; v[br].color = tint; v[bl].x = xsf[2]; v[bl].y = ysf[2]; v[bl].z = 0; v[bl].u = sx; v[bl].v = sy + sh; v[bl].color = tint; al_lock_bitmap(src, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); _al_triangle_2d(src, &v[tl], &v[tr], &v[br]); _al_triangle_2d(src, &v[tl], &v[br], &v[bl]); al_unlock_bitmap(src); } static void _al_draw_transformed_scaled_bitmap_memory( ALLEGRO_BITMAP *src, ALLEGRO_COLOR tint, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, int flags) { ALLEGRO_TRANSFORM local_trans; al_identity_transform(&local_trans); al_translate_transform(&local_trans, dx, dy); al_compose_transform(&local_trans, al_get_current_transform()); _al_draw_transformed_bitmap_memory(src, tint, sx, sy, sw, sh, dw, dh, &local_trans, flags); } static void _al_draw_bitmap_region_memory_fast(ALLEGRO_BITMAP *bitmap, int sx, int sy, int sw, int sh, int dx, int dy, int flags) { ALLEGRO_LOCKED_REGION *src_region; ALLEGRO_LOCKED_REGION *dst_region; ALLEGRO_BITMAP *dest = al_get_target_bitmap(); int dw = sw, dh = sh; ASSERT(_al_pixel_format_is_real(al_get_bitmap_format(bitmap))); ASSERT(_al_pixel_format_is_real(al_get_bitmap_format(dest))); ASSERT(bitmap->parent == NULL); /* Currently the only flags are for flipping, which is handled as negative * scaling. */ ASSERT(flags == 0); (void)flags; CLIPPER(bitmap, sx, sy, sw, sh, dest, dx, dy, dw, dh, 1, 1, flags) if (!(src_region = al_lock_bitmap_region(bitmap, sx, sy, sw, sh, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY))) { return; } if (!(dst_region = al_lock_bitmap_region(dest, dx, dy, sw, sh, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY))) { al_unlock_bitmap(bitmap); return; } /* will detect if no conversion is needed */ _al_convert_bitmap_data( src_region->data, src_region->format, src_region->pitch, dst_region->data, dst_region->format, dst_region->pitch, 0, 0, 0, 0, sw, sh); al_unlock_bitmap(bitmap); al_unlock_bitmap(dest); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/memdraw.c000066400000000000000000000110731473414355200160510ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Memory bitmap drawing routines * * Based on Michael Bukin's C drawing functions. * * Conversion to the new API by Trent Gamblin. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_blend.h" #include "allegro5/internal/aintern_memdraw.h" #include "allegro5/internal/aintern_pixels.h" /* generic versions of the video memory access helpers */ /* FIXME: why do we need macros for this? */ #define bmp_write16(addr, c) (*((uint16_t *)(addr)) = (c)) #define bmp_write32(addr, c) (*((uint32_t *)(addr)) = (c)) #define bmp_read16(addr) (*((uint16_t *)(addr))) #define bmp_read32(addr) (*((uint32_t *)(addr))) typedef struct { float x[4]; } float4; void _al_draw_pixel_memory(ALLEGRO_BITMAP *bitmap, float x, float y, ALLEGRO_COLOR *color) { ALLEGRO_COLOR result; int ix, iy; /* * Probably not worth it to check for identity */ al_transform_coordinates(al_get_current_transform(), &x, &y); ix = (int)x; iy = (int)y; _al_blend_memory(color, bitmap, ix, iy, &result); _al_put_pixel(bitmap, ix, iy, result); } void _al_clear_bitmap_by_locking(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR *color) { ALLEGRO_LOCKED_REGION *lr; int x1, y1, w, h; int x, y; unsigned char *line_ptr; /* This function is not just used on memory bitmaps, but also on OpenGL * video bitmaps which are not the current target, or when locked. */ ASSERT(bitmap); ASSERT((al_get_bitmap_flags(bitmap) & (ALLEGRO_MEMORY_BITMAP | _ALLEGRO_INTERNAL_OPENGL)) || _al_pixel_format_is_compressed(al_get_bitmap_format(bitmap))); x1 = bitmap->cl; y1 = bitmap->ct; w = bitmap->cr_excl - x1; h = bitmap->cb_excl - y1; if (w <= 0 || h <= 0) return; /* XXX what about pre-locked bitmaps? */ lr = al_lock_bitmap_region(bitmap, x1, y1, w, h, ALLEGRO_PIXEL_FORMAT_ANY, 0); if (!lr) return; /* Write a single pixel so we can get the raw value. */ _al_put_pixel(bitmap, x1, y1, *color); /* Fill in the region. */ line_ptr = lr->data; switch (lr->pixel_size) { case 2: { int pixel_value = bmp_read16(line_ptr); for (y = y1; y < y1 + h; y++) { if (pixel_value == 0) { /* fast path */ memset(line_ptr, 0, 2 * w); } else { uint16_t *data = (uint16_t *)line_ptr; for (x = 0; x < w; x++) { bmp_write16(data, pixel_value); data++; } } line_ptr += lr->pitch; } break; } case 3: { int pixel_value = _AL_READ3BYTES(line_ptr); for (y = y1; y < y1 + h; y++) { unsigned char *data = (unsigned char *)line_ptr; if (pixel_value == 0) { /* fast path */ memset(data, 0, 3 * w); } else { for (x = 0; x < w; x++) { _AL_WRITE3BYTES(data, pixel_value); data += 3; } } line_ptr += lr->pitch; } break; } case 4: { int pixel_value = bmp_read32(line_ptr); for (y = y1; y < y1 + h; y++) { uint32_t *data = (uint32_t *)line_ptr; /* Special casing pixel_value == 0 doesn't seem to make any * difference to speed, so don't bother. */ for (x = 0; x < w; x++) { bmp_write32(data, pixel_value); data++; } line_ptr += lr->pitch; } break; } case sizeof(float4): { float4 *data = (float4 *)line_ptr; float4 pixel_value = *data; for (y = y1; y < y1 + h; y++) { data = (float4 *)line_ptr; for (x = 0; x < w; x++) { *data = pixel_value; data++; } line_ptr += lr->pitch; } break; } default: ASSERT(false); break; } al_unlock_bitmap(bitmap); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/memory.c000066400000000000000000000034551473414355200157320ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Memory management routines. * * By Peter Wang. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" /* globals */ static ALLEGRO_MEMORY_INTERFACE *mem = NULL; /* Function: al_set_memory_interface */ void al_set_memory_interface(ALLEGRO_MEMORY_INTERFACE *memory_interface) { mem = memory_interface; } /* Function: al_malloc_with_context */ void *al_malloc_with_context(size_t n, int line, const char *file, const char *func) { if (mem) return mem->mi_malloc(n, line, file, func); else return malloc(n); } /* Function: al_free_with_context */ void al_free_with_context(void *ptr, int line, const char *file, const char *func) { if (mem) mem->mi_free(ptr, line, file, func); else free(ptr); } /* Function: al_realloc_with_context */ void *al_realloc_with_context(void *ptr, size_t n, int line, const char *file, const char *func) { if (mem) return mem->mi_realloc(ptr, n, line, file, func); else return realloc(ptr, n); } /* Function: al_calloc_with_context */ void *al_calloc_with_context(size_t count, size_t n, int line, const char *file, const char *func) { if (mem) return mem->mi_calloc(count, n, line, file, func); else return calloc(count, n); } /* vim: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/src/misc/000077500000000000000000000000001473414355200152025ustar00rootroot00000000000000allegro5-5.2.10.1/src/misc/aatree.c000066400000000000000000000103671473414355200166160ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * AA tree, a type of self-balancing search tree. * * By Peter Wang. */ /* prettier */ #define _AL_AATREE Aatree #include "allegro5/allegro.h" #include "allegro5/internal/aintern_aatree.h" struct DelInfo { const void *key; _al_cmp_t compare; Aatree *last; Aatree *deleted; }; static Aatree nil = { 0, &nil, &nil, NULL, NULL }; static Aatree *skew(Aatree *T) { if (T == &nil) return T; if (T->left->level == T->level) { Aatree *L = T->left; T->left = L->right; L->right = T; return L; } return T; } static Aatree *split(Aatree *T) { if (T == &nil) return T; if (T->level == T->right->right->level) { Aatree *R = T->right; T->right = R->left; R->left = T; R->level = R->level + 1; return R; } return T; } static Aatree *singleton(const void *key, void *value) { Aatree *T = al_malloc(sizeof(Aatree)); T->level = 1; T->left = &nil; T->right = &nil; T->key = key; T->value = value; return T; } static Aatree *doinsert(Aatree *T, const void *key, void *value, _al_cmp_t compare) { int cmp; if (T == &nil) { return singleton(key, value); } cmp = compare(key, T->key); if (cmp < 0) { T->left = doinsert(T->left, key, value, compare); } else if (cmp > 0) { T->right = doinsert(T->right, key, value, compare); } else { /* Already exists. We don't yet return any indication of this. */ return T; } T = skew(T); T = split(T); return T; } Aatree *_al_aa_insert(Aatree *T, const void *key, void *value, _al_cmp_t compare) { if (T == NULL) T = &nil; return doinsert(T, key, value, compare); } void *_al_aa_search(const Aatree *T, const void *key, _al_cmp_t compare) { if (T == NULL) return NULL; while (T != &nil) { int cmp = compare(key, T->key); if (cmp == 0) return T->value; T = (cmp < 0) ? T->left : T->right; } return NULL; } static Aatree *dodelete(struct DelInfo *info, Aatree *T, void **ret_value) { if (T == &nil) return T; /* Search down the tree and set pointers last and deleted. */ info->last = T; if (info->compare(info->key, T->key) < 0) { T->left = dodelete(info, T->left, ret_value); } else { info->deleted = T; T->right = dodelete(info, T->right, ret_value); } /* At the bottom of the tree we remove the element if it is present. */ if (T == info->last && info->deleted != &nil && info->compare(info->key, info->deleted->key) == 0) { Aatree *right = T->right; *ret_value = info->deleted->value; info->deleted->key = T->key; info->deleted->value = T->value; info->deleted = &nil; al_free(T); return right; } /* On the way back, we rebalance. */ if (T->left->level < T->level - 1 || T->right->level < T->level - 1) { T->level--; if (T->right->level > T->level) { T->right->level = T->level; } T = skew(T); T->right = skew(T->right); T->right->right = skew(T->right->right); T = split(T); T->right = split(T->right); } return T; } /* ret_value is only set if the item was found and deleted. * The caller should set it to some distinct value, e.g. NULL, * to detect if no item was found. */ Aatree *_al_aa_delete(Aatree *T, const void *key, _al_cmp_t compare, void **ret_value) { struct DelInfo info; info.key = key; info.compare = compare; info.last = &nil; info.deleted = &nil; if (T) { T = dodelete(&info, T, ret_value); if (T == &nil) T = NULL; } return T; } void _al_aa_free(Aatree *T) { if (T && T != &nil) { _al_aa_free(T->left); _al_aa_free(T->right); al_free(T); } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/misc/bstrlib.c000066400000000000000000002654751473414355200170320ustar00rootroot00000000000000/* * This source file has had its exported symbols prefixed with _al_ or _AL_ * for the Allegro project. */ /* * This source file is part of the _al_bstring string library. This code was * written by Paul Hsieh in 2002-2008, and is covered by the BSD open source * license and the GPL. Refer to the accompanying documentation for details * on usage and license. */ /* * bstrlib.c * * This file is the core module for implementing the _al_bstring functions. */ #include #include #include #include #include #include #include "allegro5/allegro.h" #include "allegro5/internal/bstrlib.h" #define bstr__alloc(x) al_malloc(x) #define bstr__free(p) al_free(p) #define bstr__realloc(p, x) al_realloc((p), (x)) /* Optionally include a mechanism for debugging memory */ #if defined(MEMORY_DEBUG) || defined(BSTRLIB_MEMORY_DEBUG) #include "memdbg.h" #endif #ifndef bstr__alloc #define bstr__alloc(x) malloc (x) #endif #ifndef bstr__free #define bstr__free(p) free (p) #endif #ifndef bstr__realloc #define bstr__realloc(p,x) realloc ((p), (x)) #endif #ifndef bstr__memcpy #define bstr__memcpy(d,s,l) memcpy ((d), (s), (l)) #endif #ifndef bstr__memmove #define bstr__memmove(d,s,l) memmove ((d), (s), (l)) #endif #ifndef bstr__memset #define bstr__memset(d,c,l) memset ((d), (c), (l)) #endif #ifndef bstr__memcmp #define bstr__memcmp(d,c,l) memcmp ((d), (c), (l)) #endif #ifndef bstr__memchr #define bstr__memchr(s,c,l) memchr ((s), (c), (l)) #endif /* Just a length safe wrapper for memmove. */ #define bBlockCopy(D,S,L) { if ((L) > 0) bstr__memmove ((D),(S),(L)); } /* Compute the snapped size for a given requested size. By snapping to powers of 2 like this, repeated reallocations are avoided. */ static int snapUpSize (int i) { if (i < 8) { i = 8; } else { unsigned int j; j = (unsigned int) i; j |= (j >> 1); j |= (j >> 2); j |= (j >> 4); j |= (j >> 8); /* Ok, since int >= 16 bits */ #if (UINT_MAX != 0xffff) j |= (j >> 16); /* For 32 bit int systems */ #if (UINT_MAX > 0xffffffffUL) j |= (j >> 32); /* For 64 bit int systems */ #endif #endif /* Least power of two greater than i */ j++; if ((int) j >= i) i = (int) j; } return i; } /* int _al_balloc (_al_bstring b, int len) * * Increase the size of the memory backing the _al_bstring b to at least len. */ int _al_balloc (_al_bstring b, int olen) { int len; if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen <= 0 || b->mlen < b->slen || olen <= 0) { return _AL_BSTR_ERR; } if (olen >= b->mlen) { unsigned char * x; if ((len = snapUpSize (olen)) <= b->mlen) return _AL_BSTR_OK; /* Assume probability of a non-moving realloc is 0.125 */ if (7 * b->mlen < 8 * b->slen) { /* If slen is close to mlen in size then use realloc to reduce the memory defragmentation */ reallocStrategy:; x = (unsigned char *) bstr__realloc (b->data, (size_t) len); if (x == NULL) { /* Since we failed, try allocating the tighest possible allocation */ if (NULL == (x = (unsigned char *) bstr__realloc (b->data, (size_t) (len = olen)))) { return _AL_BSTR_ERR; } } } else { /* If slen is not close to mlen then avoid the penalty of copying the extra bytes that are allocated, but not considered part of the string */ if (NULL == (x = (unsigned char *) bstr__alloc ((size_t) len))) { /* Perhaps there is no available memory for the two allocations to be in memory at once */ goto reallocStrategy; } else { if (b->slen) bstr__memcpy ((char *) x, (char *) b->data, (size_t) b->slen); bstr__free (b->data); } } b->data = x; b->mlen = len; b->data[b->slen] = (unsigned char) '\0'; } return _AL_BSTR_OK; } /* int _al_ballocmin (_al_bstring b, int len) * * Set the size of the memory backing the _al_bstring b to len or b->slen+1, * whichever is larger. Note that repeated use of this function can degrade * performance. */ int _al_ballocmin (_al_bstring b, int len) { unsigned char * s; if (b == NULL || b->data == NULL || (b->slen+1) < 0 || b->mlen <= 0 || b->mlen < b->slen || len <= 0) { return _AL_BSTR_ERR; } if (len < b->slen + 1) len = b->slen + 1; if (len != b->mlen) { s = (unsigned char *) bstr__realloc (b->data, (size_t) len); if (NULL == s) return _AL_BSTR_ERR; s[b->slen] = (unsigned char) '\0'; b->data = s; b->mlen = len; } return _AL_BSTR_OK; } /* _al_bstring _al_bfromcstr (const char * str) * * Create a _al_bstring which contains the contents of the '\0' terminated char * * buffer str. */ _al_bstring _al_bfromcstr (const char * str) { _al_bstring b; int i; size_t j; if (str == NULL) return NULL; j = (strlen) (str); i = snapUpSize ((int) (j + (2 - (j != 0)))); if (i <= (int) j) return NULL; b = (_al_bstring) bstr__alloc (sizeof (struct _al_tagbstring)); if (NULL == b) return NULL; b->slen = (int) j; if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) { bstr__free (b); return NULL; } bstr__memcpy (b->data, str, j+1); return b; } /* _al_bstring _al_bfromcstralloc (int mlen, const char * str) * * Create a _al_bstring which contains the contents of the '\0' terminated char * * buffer str. The memory buffer backing the string is at least len * characters in length. */ _al_bstring _al_bfromcstralloc (int mlen, const char * str) { _al_bstring b; int i; size_t j; if (str == NULL) return NULL; j = (strlen) (str); i = snapUpSize ((int) (j + (2 - (j != 0)))); if (i <= (int) j) return NULL; b = (_al_bstring) bstr__alloc (sizeof (struct _al_tagbstring)); if (b == NULL) return NULL; b->slen = (int) j; if (i < mlen) i = mlen; if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) { bstr__free (b); return NULL; } bstr__memcpy (b->data, str, j+1); return b; } /* _al_bstring _al_blk2bstr (const void * blk, int len) * * Create a _al_bstring which contains the content of the block blk of length * len. */ _al_bstring _al_blk2bstr (const void * blk, int len) { _al_bstring b; int i; if (blk == NULL || len < 0) return NULL; b = (_al_bstring) bstr__alloc (sizeof (struct _al_tagbstring)); if (b == NULL) return NULL; b->slen = len; i = len + (2 - (len != 0)); i = snapUpSize (i); b->mlen = i; b->data = (unsigned char *) bstr__alloc ((size_t) b->mlen); if (b->data == NULL) { bstr__free (b); return NULL; } if (len > 0) bstr__memcpy (b->data, blk, (size_t) len); b->data[len] = (unsigned char) '\0'; return b; } /* char * _al_bstr2cstr (_al_const_bstring s, char z) * * Create a '\0' terminated char * buffer which is equal to the contents of * the _al_bstring s, except that any contained '\0' characters are converted * to the character in z. This returned value should be freed with a * _al_bcstrfree () call, by the calling application. */ char * _al_bstr2cstr (_al_const_bstring b, char z) { int i, l; char * r; if (b == NULL || b->slen < 0 || b->data == NULL) return NULL; l = b->slen; r = (char *) bstr__alloc ((size_t) (l + 1)); if (r == NULL) return r; for (i=0; i < l; i ++) { r[i] = (char) ((b->data[i] == '\0') ? z : (char) (b->data[i])); } r[l] = (unsigned char) '\0'; return r; } /* int _al_bcstrfree (char * s) * * Frees a C-string generated by _al_bstr2cstr (). This is normally unnecessary * since it just wraps a call to bstr__free (), however, if bstr__alloc () * and bstr__free () have been redefined as a macros within the bstrlib * module (via defining them in memdbg.h after defining * BSTRLIB_MEMORY_DEBUG) with some difference in behaviour from the std * library functions, then this allows a correct way of freeing the memory * that allows higher level code to be independent from these macro * redefinitions. */ int _al_bcstrfree (char * s) { if (s) { bstr__free (s); return _AL_BSTR_OK; } return _AL_BSTR_ERR; } /* int _al_bconcat (_al_bstring b0, _al_const_bstring b1) * * Concatenate the _al_bstring b1 to the _al_bstring b0. */ int _al_bconcat (_al_bstring b0, _al_const_bstring b1) { int len, d; _al_bstring aux = (_al_bstring) b1; if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL) return _AL_BSTR_ERR; d = b0->slen; len = b1->slen; if ((d | (b0->mlen - d) | len | (d + len)) < 0) return _AL_BSTR_ERR; if (b0->mlen <= d + len + 1) { ptrdiff_t pd = b1->data - b0->data; if (0 <= pd && pd < b0->mlen) { if (NULL == (aux = _al_bstrcpy (b1))) return _AL_BSTR_ERR; } if (_al_balloc (b0, d + len + 1) != _AL_BSTR_OK) { if (aux != b1) _al_bdestroy (aux); return _AL_BSTR_ERR; } } bBlockCopy (&b0->data[d], &aux->data[0], (size_t) len); b0->data[d + len] = (unsigned char) '\0'; b0->slen = d + len; if (aux != b1) _al_bdestroy (aux); return _AL_BSTR_OK; } /* int _al_bconchar (_al_bstring b, char c) / * * Concatenate the single character c to the _al_bstring b. */ int _al_bconchar (_al_bstring b, char c) { int d; if (b == NULL) return _AL_BSTR_ERR; d = b->slen; if ((d | (b->mlen - d)) < 0 || _al_balloc (b, d + 2) != _AL_BSTR_OK) return _AL_BSTR_ERR; b->data[d] = (unsigned char) c; b->data[d + 1] = (unsigned char) '\0'; b->slen++; return _AL_BSTR_OK; } /* int _al_bcatcstr (_al_bstring b, const char * s) * * Concatenate a char * string to a _al_bstring. */ int _al_bcatcstr (_al_bstring b, const char * s) { char * d; int i, l; if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen || b->mlen <= 0 || s == NULL) return _AL_BSTR_ERR; /* Optimistically concatenate directly */ l = b->mlen - b->slen; d = (char *) &b->data[b->slen]; for (i=0; i < l; i++) { if ((*d++ = *s++) == '\0') { b->slen += i; return _AL_BSTR_OK; } } b->slen += i; /* Need to explicitely resize and concatenate tail */ return _al_bcatblk (b, (const void *) s, (int) strlen (s)); } /* int _al_bcatblk (_al_bstring b, const void * s, int len) * * Concatenate a fixed length buffer to a _al_bstring. */ int _al_bcatblk (_al_bstring b, const void * s, int len) { int nl; if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen || b->mlen <= 0 || s == NULL || len < 0) return _AL_BSTR_ERR; if (0 > (nl = b->slen + len)) return _AL_BSTR_ERR; /* Overflow? */ if (b->mlen <= nl && 0 > _al_balloc (b, nl + 1)) return _AL_BSTR_ERR; bBlockCopy (&b->data[b->slen], s, (size_t) len); b->slen = nl; b->data[nl] = (unsigned char) '\0'; return _AL_BSTR_OK; } /* _al_bstring _al_bstrcpy (_al_const_bstring b) * * Create a copy of the _al_bstring b. */ _al_bstring _al_bstrcpy (_al_const_bstring b) { _al_bstring b0; int i,j; /* Attempted to copy an invalid string? */ if (b == NULL || b->slen < 0 || b->data == NULL) return NULL; b0 = (_al_bstring) bstr__alloc (sizeof (struct _al_tagbstring)); if (b0 == NULL) { /* Unable to allocate memory for string header */ return NULL; } i = b->slen; j = snapUpSize (i + 1); b0->data = (unsigned char *) bstr__alloc (j); if (b0->data == NULL) { j = i + 1; b0->data = (unsigned char *) bstr__alloc (j); if (b0->data == NULL) { /* Unable to allocate memory for string data */ bstr__free (b0); return NULL; } } b0->mlen = j; b0->slen = i; if (i) bstr__memcpy ((char *) b0->data, (char *) b->data, i); b0->data[b0->slen] = (unsigned char) '\0'; return b0; } /* int _al_bassign (_al_bstring a, _al_const_bstring b) * * Overwrite the string a with the contents of string b. */ int _al_bassign (_al_bstring a, _al_const_bstring b) { if (b == NULL || b->data == NULL || b->slen < 0) return _AL_BSTR_ERR; if (b->slen != 0) { if (_al_balloc (a, b->slen) != _AL_BSTR_OK) return _AL_BSTR_ERR; bstr__memmove (a->data, b->data, b->slen); } else { if (a == NULL || a->data == NULL || a->mlen < a->slen || a->slen < 0 || a->mlen == 0) return _AL_BSTR_ERR; } a->data[b->slen] = (unsigned char) '\0'; a->slen = b->slen; return _AL_BSTR_OK; } /* int _al_bassignmidstr (_al_bstring a, _al_const_bstring b, int left, int len) * * Overwrite the string a with the middle of contents of string b * starting from position left and running for a length len. left and * len are clamped to the ends of b as with the function _al_bmidstr. */ int _al_bassignmidstr (_al_bstring a, _al_const_bstring b, int left, int len) { if (b == NULL || b->data == NULL || b->slen < 0) return _AL_BSTR_ERR; if (left < 0) { len += left; left = 0; } if (len > b->slen - left) len = b->slen - left; if (a == NULL || a->data == NULL || a->mlen < a->slen || a->slen < 0 || a->mlen == 0) return _AL_BSTR_ERR; if (len > 0) { if (_al_balloc (a, len) != _AL_BSTR_OK) return _AL_BSTR_ERR; bstr__memmove (a->data, b->data + left, len); a->slen = len; } else { a->slen = 0; } a->data[a->slen] = (unsigned char) '\0'; return _AL_BSTR_OK; } /* int _al_bassigncstr (_al_bstring a, const char * str) * * Overwrite the string a with the contents of char * string str. Note that * the _al_bstring a must be a well defined and writable _al_bstring. If an error * occurs _AL_BSTR_ERR is returned however a may be partially overwritten. */ int _al_bassigncstr (_al_bstring a, const char * str) { int i; size_t len; if (a == NULL || a->data == NULL || a->mlen < a->slen || a->slen < 0 || a->mlen == 0 || NULL == str) return _AL_BSTR_ERR; for (i=0; i < a->mlen; i++) { if ('\0' == (a->data[i] = str[i])) { a->slen = i; return _AL_BSTR_OK; } } a->slen = i; len = strlen (str + i); if (len > INT_MAX || i + len + 1 > INT_MAX || 0 > _al_balloc (a, (int) (i + len + 1))) return _AL_BSTR_ERR; bBlockCopy (a->data + i, str + i, (size_t) len + 1); a->slen += (int) len; return _AL_BSTR_OK; } /* int _al_bassignblk (_al_bstring a, const void * s, int len) * * Overwrite the string a with the contents of the block (s, len). Note that * the _al_bstring a must be a well defined and writable _al_bstring. If an error * occurs _AL_BSTR_ERR is returned and a is not overwritten. */ int _al_bassignblk (_al_bstring a, const void * s, int len) { if (a == NULL || a->data == NULL || a->mlen < a->slen || a->slen < 0 || a->mlen == 0 || NULL == s || len + 1 < 1) return _AL_BSTR_ERR; if (len + 1 > a->mlen && 0 > _al_balloc (a, len + 1)) return _AL_BSTR_ERR; bBlockCopy (a->data, s, (size_t) len); a->data[len] = (unsigned char) '\0'; a->slen = len; return _AL_BSTR_OK; } /* int _al_btrunc (_al_bstring b, int n) * * Truncate the _al_bstring to at most n characters. */ int _al_btrunc (_al_bstring b, int n) { if (n < 0 || b == NULL || b->data == NULL || b->mlen < b->slen || b->slen < 0 || b->mlen <= 0) return _AL_BSTR_ERR; if (b->slen > n) { b->slen = n; b->data[n] = (unsigned char) '\0'; } return _AL_BSTR_OK; } #define upcase(c) (toupper ((unsigned char) c)) #define downcase(c) (tolower ((unsigned char) c)) #define wspace(c) (isspace ((unsigned char) c)) /* int _al_btoupper (_al_bstring b) * * Convert contents of _al_bstring to upper case. */ int _al_btoupper (_al_bstring b) { int i, len; if (b == NULL || b->data == NULL || b->mlen < b->slen || b->slen < 0 || b->mlen <= 0) return _AL_BSTR_ERR; for (i=0, len = b->slen; i < len; i++) { b->data[i] = (unsigned char) upcase (b->data[i]); } return _AL_BSTR_OK; } /* int _al_btolower (_al_bstring b) * * Convert contents of _al_bstring to lower case. */ int _al_btolower (_al_bstring b) { int i, len; if (b == NULL || b->data == NULL || b->mlen < b->slen || b->slen < 0 || b->mlen <= 0) return _AL_BSTR_ERR; for (i=0, len = b->slen; i < len; i++) { b->data[i] = (unsigned char) downcase (b->data[i]); } return _AL_BSTR_OK; } /* int _al_bstricmp (_al_const_bstring b0, _al_const_bstring b1) * * Compare two strings without differentiating between case. The return * value is the difference of the values of the characters where the two * strings first differ after lower case transformation, otherwise 0 is * returned indicating that the strings are equal. If the lengths are * different, then a difference from 0 is given, but if the first extra * character is '\0', then it is taken to be the value UCHAR_MAX+1. */ int _al_bstricmp (_al_const_bstring b0, _al_const_bstring b1) { int i, v, n; if (_al_bdata (b0) == NULL || b0->slen < 0 || _al_bdata (b1) == NULL || b1->slen < 0) return SHRT_MIN; if ((n = b0->slen) > b1->slen) n = b1->slen; else if (b0->slen == b1->slen && b0->data == b1->data) return _AL_BSTR_OK; for (i = 0; i < n; i ++) { v = (char) downcase (b0->data[i]) - (char) downcase (b1->data[i]); if (0 != v) return v; } if (b0->slen > n) { v = (char) downcase (b0->data[n]); if (v) return v; return UCHAR_MAX + 1; } if (b1->slen > n) { v = - (char) downcase (b1->data[n]); if (v) return v; return - (int) (UCHAR_MAX + 1); } return _AL_BSTR_OK; } /* int _al_bstrnicmp (_al_const_bstring b0, _al_const_bstring b1, int n) * * Compare two strings without differentiating between case for at most n * characters. If the position where the two strings first differ is * before the nth position, the return value is the difference of the values * of the characters, otherwise 0 is returned. If the lengths are different * and less than n characters, then a difference from 0 is given, but if the * first extra character is '\0', then it is taken to be the value * UCHAR_MAX+1. */ int _al_bstrnicmp (_al_const_bstring b0, _al_const_bstring b1, int n) { int i, v, m; if (_al_bdata (b0) == NULL || b0->slen < 0 || _al_bdata (b1) == NULL || b1->slen < 0 || n < 0) return SHRT_MIN; m = n; if (m > b0->slen) m = b0->slen; if (m > b1->slen) m = b1->slen; if (b0->data != b1->data) { for (i = 0; i < m; i ++) { v = (char) downcase (b0->data[i]); v -= (char) downcase (b1->data[i]); if (v != 0) return b0->data[i] - b1->data[i]; } } if (n == m || b0->slen == b1->slen) return _AL_BSTR_OK; if (b0->slen > m) { v = (char) downcase (b0->data[m]); if (v) return v; return UCHAR_MAX + 1; } v = - (char) downcase (b1->data[m]); if (v) return v; return - (int) (UCHAR_MAX + 1); } /* int _al_biseqcaseless (_al_const_bstring b0, _al_const_bstring b1) * * Compare two strings for equality without differentiating between case. * If the strings differ other than in case, 0 is returned, if the strings * are the same, 1 is returned, if there is an error, -1 is returned. If * the length of the strings are different, this function is O(1). '\0' * termination characters are not treated in any special way. */ int _al_biseqcaseless (_al_const_bstring b0, _al_const_bstring b1) { int i, n; if (_al_bdata (b0) == NULL || b0->slen < 0 || _al_bdata (b1) == NULL || b1->slen < 0) return _AL_BSTR_ERR; if (b0->slen != b1->slen) return _AL_BSTR_OK; if (b0->data == b1->data || b0->slen == 0) return 1; for (i=0, n=b0->slen; i < n; i++) { if (b0->data[i] != b1->data[i]) { unsigned char c = (unsigned char) downcase (b0->data[i]); if (c != (unsigned char) downcase (b1->data[i])) return 0; } } return 1; } /* int _al_bisstemeqcaselessblk (_al_const_bstring b0, const void * blk, int len) * * Compare beginning of string b0 with a block of memory of length len * without differentiating between case for equality. If the beginning of b0 * differs from the memory block other than in case (or if b0 is too short), * 0 is returned, if the strings are the same, 1 is returned, if there is an * error, -1 is returned. '\0' characters are not treated in any special * way. */ int _al_bisstemeqcaselessblk (_al_const_bstring b0, const void * blk, int len) { int i; if (_al_bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0) return _AL_BSTR_ERR; if (b0->slen < len) return _AL_BSTR_OK; if (b0->data == (const unsigned char *) blk || len == 0) return 1; for (i = 0; i < len; i ++) { if (b0->data[i] != ((const unsigned char *) blk)[i]) { if (downcase (b0->data[i]) != downcase (((const unsigned char *) blk)[i])) return 0; } } return 1; } /* * int _al_bltrimws (_al_bstring b) * * Delete whitespace contiguous from the left end of the string. */ int _al_bltrimws (_al_bstring b) { int i, len; if (b == NULL || b->data == NULL || b->mlen < b->slen || b->slen < 0 || b->mlen <= 0) return _AL_BSTR_ERR; for (len = b->slen, i = 0; i < len; i++) { if (!wspace (b->data[i])) { return _al_bdelete (b, 0, i); } } b->data[0] = (unsigned char) '\0'; b->slen = 0; return _AL_BSTR_OK; } /* * int _al_brtrimws (_al_bstring b) * * Delete whitespace contiguous from the right end of the string. */ int _al_brtrimws (_al_bstring b) { int i; if (b == NULL || b->data == NULL || b->mlen < b->slen || b->slen < 0 || b->mlen <= 0) return _AL_BSTR_ERR; for (i = b->slen - 1; i >= 0; i--) { if (!wspace (b->data[i])) { if (b->mlen > i) b->data[i+1] = (unsigned char) '\0'; b->slen = i + 1; return _AL_BSTR_OK; } } b->data[0] = (unsigned char) '\0'; b->slen = 0; return _AL_BSTR_OK; } /* * int _al_btrimws (_al_bstring b) * * Delete whitespace contiguous from both ends of the string. */ int _al_btrimws (_al_bstring b) { int i, j; if (b == NULL || b->data == NULL || b->mlen < b->slen || b->slen < 0 || b->mlen <= 0) return _AL_BSTR_ERR; for (i = b->slen - 1; i >= 0; i--) { if (!wspace (b->data[i])) { if (b->mlen > i) b->data[i+1] = (unsigned char) '\0'; b->slen = i + 1; for (j = 0; wspace (b->data[j]); j++) {} return _al_bdelete (b, 0, j); } } b->data[0] = (unsigned char) '\0'; b->slen = 0; return _AL_BSTR_OK; } /* int _al_biseq (_al_const_bstring b0, _al_const_bstring b1) * * Compare the string b0 and b1. If the strings differ, 0 is returned, if * the strings are the same, 1 is returned, if there is an error, -1 is * returned. If the length of the strings are different, this function is * O(1). '\0' termination characters are not treated in any special way. */ int _al_biseq (_al_const_bstring b0, _al_const_bstring b1) { if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL || b0->slen < 0 || b1->slen < 0) return _AL_BSTR_ERR; if (b0->slen != b1->slen) return _AL_BSTR_OK; if (b0->data == b1->data || b0->slen == 0) return 1; return !bstr__memcmp (b0->data, b1->data, b0->slen); } /* int _al_bisstemeqblk (_al_const_bstring b0, const void * blk, int len) * * Compare beginning of string b0 with a block of memory of length len for * equality. If the beginning of b0 differs from the memory block (or if b0 * is too short), 0 is returned, if the strings are the same, 1 is returned, * if there is an error, -1 is returned. '\0' characters are not treated in * any special way. */ int _al_bisstemeqblk (_al_const_bstring b0, const void * blk, int len) { int i; if (_al_bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0) return _AL_BSTR_ERR; if (b0->slen < len) return _AL_BSTR_OK; if (b0->data == (const unsigned char *) blk || len == 0) return 1; for (i = 0; i < len; i ++) { if (b0->data[i] != ((const unsigned char *) blk)[i]) return _AL_BSTR_OK; } return 1; } /* int _al_biseqcstr (_al_const_bstring b, const char *s) * * Compare the _al_bstring b and char * string s. The C string s must be '\0' * terminated at exactly the length of the _al_bstring b, and the contents * between the two must be identical with the _al_bstring b with no '\0' * characters for the two contents to be considered equal. This is * equivalent to the condition that their current contents will be always be * equal when comparing them in the same format after converting one or the * other. If the strings are equal 1 is returned, if they are unequal 0 is * returned and if there is a detectable error _AL_BSTR_ERR is returned. */ int _al_biseqcstr (_al_const_bstring b, const char * s) { int i; if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return _AL_BSTR_ERR; for (i=0; i < b->slen; i++) { if (s[i] == '\0' || b->data[i] != (unsigned char) s[i]) return _AL_BSTR_OK; } return s[i] == '\0'; } /* int _al_biseqcstrcaseless (_al_const_bstring b, const char *s) * * Compare the _al_bstring b and char * string s. The C string s must be '\0' * terminated at exactly the length of the _al_bstring b, and the contents * between the two must be identical except for case with the _al_bstring b with * no '\0' characters for the two contents to be considered equal. This is * equivalent to the condition that their current contents will be always be * equal ignoring case when comparing them in the same format after * converting one or the other. If the strings are equal, except for case, * 1 is returned, if they are unequal regardless of case 0 is returned and * if there is a detectable error _AL_BSTR_ERR is returned. */ int _al_biseqcstrcaseless (_al_const_bstring b, const char * s) { int i; if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return _AL_BSTR_ERR; for (i=0; i < b->slen; i++) { if (s[i] == '\0' || (b->data[i] != (unsigned char) s[i] && downcase (b->data[i]) != (unsigned char) downcase (s[i]))) return _AL_BSTR_OK; } return s[i] == '\0'; } /* int _al_bstrcmp (_al_const_bstring b0, _al_const_bstring b1) * * Compare the string b0 and b1. If there is an error, SHRT_MIN is returned, * otherwise a value less than or greater than zero, indicating that the * string pointed to by b0 is lexicographically less than or greater than * the string pointed to by b1 is returned. If the the string lengths are * unequal but the characters up until the length of the shorter are equal * then a value less than, or greater than zero, indicating that the string * pointed to by b0 is shorter or longer than the string pointed to by b1 is * returned. 0 is returned if and only if the two strings are the same. If * the length of the strings are different, this function is O(n). Like its * standard C library counter part strcmp, the comparison does not proceed * past any '\0' termination characters encountered. */ int _al_bstrcmp (_al_const_bstring b0, _al_const_bstring b1) { int i, v, n; if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL || b0->slen < 0 || b1->slen < 0) return SHRT_MIN; n = b0->slen; if (n > b1->slen) n = b1->slen; if (b0->slen == b1->slen && (b0->data == b1->data || b0->slen == 0)) return _AL_BSTR_OK; for (i = 0; i < n; i ++) { v = ((char) b0->data[i]) - ((char) b1->data[i]); if (v != 0) return v; if (b0->data[i] == (unsigned char) '\0') return _AL_BSTR_OK; } if (b0->slen > n) return 1; if (b1->slen > n) return -1; return _AL_BSTR_OK; } /* int _al_bstrncmp (_al_const_bstring b0, _al_const_bstring b1, int n) * * Compare the string b0 and b1 for at most n characters. If there is an * error, SHRT_MIN is returned, otherwise a value is returned as if b0 and * b1 were first truncated to at most n characters then _al_bstrcmp was called * with these new strings are paremeters. If the length of the strings are * different, this function is O(n). Like its standard C library counter * part strcmp, the comparison does not proceed past any '\0' termination * characters encountered. */ int _al_bstrncmp (_al_const_bstring b0, _al_const_bstring b1, int n) { int i, v, m; if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL || b0->slen < 0 || b1->slen < 0) return SHRT_MIN; m = n; if (m > b0->slen) m = b0->slen; if (m > b1->slen) m = b1->slen; if (b0->data != b1->data) { for (i = 0; i < m; i ++) { v = ((char) b0->data[i]) - ((char) b1->data[i]); if (v != 0) return v; if (b0->data[i] == (unsigned char) '\0') return _AL_BSTR_OK; } } if (n == m || b0->slen == b1->slen) return _AL_BSTR_OK; if (b0->slen > m) return 1; return -1; } /* _al_bstring _al_bmidstr (_al_const_bstring b, int left, int len) * * Create a _al_bstring which is the substring of b starting from position left * and running for a length len (clamped by the end of the _al_bstring b.) If * b is detectably invalid, then NULL is returned. The section described * by (left, len) is clamped to the boundaries of b. */ _al_bstring _al_bmidstr (_al_const_bstring b, int left, int len) { if (b == NULL || b->slen < 0 || b->data == NULL) return NULL; if (left < 0) { len += left; left = 0; } if (len > b->slen - left) len = b->slen - left; if (len <= 0) return _al_bfromcstr (""); return _al_blk2bstr (b->data + left, len); } /* int _al_bdelete (_al_bstring b, int pos, int len) * * Removes characters from pos to pos+len-1 inclusive and shifts the tail of * the _al_bstring starting from pos+len to pos. len must be positive for this * call to have any effect. The section of the string described by (pos, * len) is clamped to boundaries of the _al_bstring b. */ int _al_bdelete (_al_bstring b, int pos, int len) { /* Clamp to left side of _al_bstring */ if (pos < 0) { len += pos; pos = 0; } if (len < 0 || b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen || b->mlen <= 0) return _AL_BSTR_ERR; if (len > 0 && pos < b->slen) { if (pos + len >= b->slen) { b->slen = pos; } else { bBlockCopy ((char *) (b->data + pos), (char *) (b->data + pos + len), b->slen - (pos+len)); b->slen -= len; } b->data[b->slen] = (unsigned char) '\0'; } return _AL_BSTR_OK; } /* int _al_bdestroy (_al_bstring b) * * Free up the _al_bstring. Note that if b is detectably invalid or not writable * then no action is performed and _AL_BSTR_ERR is returned. Like a freed memory * allocation, dereferences, writes or any other action on b after it has * been bdestroyed is undefined. */ int _al_bdestroy (_al_bstring b) { if (b == NULL || b->slen < 0 || b->mlen <= 0 || b->mlen < b->slen || b->data == NULL) return _AL_BSTR_ERR; bstr__free (b->data); /* In case there is any stale usage, there is one more chance to notice this error. */ b->slen = -1; b->mlen = -__LINE__; b->data = NULL; bstr__free (b); return _AL_BSTR_OK; } /* int _al_binstr (_al_const_bstring b1, int pos, _al_const_bstring b2) * * Search for the _al_bstring b2 in b1 starting from position pos, and searching * forward. If it is found then return with the first position where it is * found, otherwise return _AL_BSTR_ERR. Note that this is just a brute force * string searcher that does not attempt clever things like the Boyer-Moore * search algorithm. Because of this there are many degenerate cases where * this can take much longer than it needs to. */ int _al_binstr (_al_const_bstring b1, int pos, _al_const_bstring b2) { int j, ii, ll, lf; unsigned char * d0; unsigned char c0; register unsigned char * d1; register unsigned char c1; register int i; if (b1 == NULL || b1->data == NULL || b1->slen < 0 || b2 == NULL || b2->data == NULL || b2->slen < 0) return _AL_BSTR_ERR; if (b1->slen == pos) return (b2->slen == 0)?pos:_AL_BSTR_ERR; if (b1->slen < pos || pos < 0) return _AL_BSTR_ERR; if (b2->slen == 0) return pos; /* No space to find such a string? */ if ((lf = b1->slen - b2->slen + 1) <= pos) return _AL_BSTR_ERR; /* An obvious alias case */ if (b1->data == b2->data && pos == 0) return 0; i = pos; d0 = b2->data; d1 = b1->data; ll = b2->slen; /* Peel off the b2->slen == 1 case */ c0 = d0[0]; if (1 == ll) { for (;i < lf; i++) if (c0 == d1[i]) return i; return _AL_BSTR_ERR; } c1 = c0; j = 0; lf = b1->slen - 1; ii = -1; if (i < lf) do { /* Unrolled current character test */ if (c1 != d1[i]) { if (c1 != d1[1+i]) { i += 2; continue; } i++; } /* Take note if this is the start of a potential match */ if (0 == j) ii = i; /* Shift the test character down by one */ j++; i++; /* If this isn't past the last character continue */ if (j < ll) { c1 = d0[j]; continue; } N0:; /* If no characters mismatched, then we matched */ if (i == ii+j) return ii; /* Shift back to the beginning */ i -= j; j = 0; c1 = c0; } while (i < lf); /* Deal with last case if unrolling caused a misalignment */ if (i == lf && ll == j+1 && c1 == d1[i]) goto N0; return _AL_BSTR_ERR; } /* int _al_binstrr (_al_const_bstring b1, int pos, _al_const_bstring b2) * * Search for the _al_bstring b2 in b1 starting from position pos, and searching * backward. If it is found then return with the first position where it is * found, otherwise return _AL_BSTR_ERR. Note that this is just a brute force * string searcher that does not attempt clever things like the Boyer-Moore * search algorithm. Because of this there are many degenerate cases where * this can take much longer than it needs to. */ int _al_binstrr (_al_const_bstring b1, int pos, _al_const_bstring b2) { int j, i, l; unsigned char * d0, * d1; if (b1 == NULL || b1->data == NULL || b1->slen < 0 || b2 == NULL || b2->data == NULL || b2->slen < 0) return _AL_BSTR_ERR; if (b1->slen == pos && b2->slen == 0) return pos; if (b1->slen < pos || pos < 0) return _AL_BSTR_ERR; if (b2->slen == 0) return pos; /* Obvious alias case */ if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return 0; i = pos; if ((l = b1->slen - b2->slen) < 0) return _AL_BSTR_ERR; /* If no space to find such a string then snap back */ if (l + 1 <= i) i = l; j = 0; d0 = b2->data; d1 = b1->data; l = b2->slen; for (;;) { if (d0[j] == d1[i + j]) { j ++; if (j >= l) return i; } else { i --; if (i < 0) break; j=0; } } return _AL_BSTR_ERR; } /* int _al_binstrcaseless (_al_const_bstring b1, int pos, _al_const_bstring b2) * * Search for the _al_bstring b2 in b1 starting from position pos, and searching * forward but without regard to case. If it is found then return with the * first position where it is found, otherwise return _AL_BSTR_ERR. Note that * this is just a brute force string searcher that does not attempt clever * things like the Boyer-Moore search algorithm. Because of this there are * many degenerate cases where this can take much longer than it needs to. */ int _al_binstrcaseless (_al_const_bstring b1, int pos, _al_const_bstring b2) { int j, i, l, ll; unsigned char * d0, * d1; if (b1 == NULL || b1->data == NULL || b1->slen < 0 || b2 == NULL || b2->data == NULL || b2->slen < 0) return _AL_BSTR_ERR; if (b1->slen == pos) return (b2->slen == 0)?pos:_AL_BSTR_ERR; if (b1->slen < pos || pos < 0) return _AL_BSTR_ERR; if (b2->slen == 0) return pos; l = b1->slen - b2->slen + 1; /* No space to find such a string? */ if (l <= pos) return _AL_BSTR_ERR; /* An obvious alias case */ if (b1->data == b2->data && pos == 0) return _AL_BSTR_OK; i = pos; j = 0; d0 = b2->data; d1 = b1->data; ll = b2->slen; for (;;) { if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) { j ++; if (j >= ll) return i; } else { i ++; if (i >= l) break; j=0; } } return _AL_BSTR_ERR; } /* int _al_binstrrcaseless (_al_const_bstring b1, int pos, _al_const_bstring b2) * * Search for the _al_bstring b2 in b1 starting from position pos, and searching * backward but without regard to case. If it is found then return with the * first position where it is found, otherwise return _AL_BSTR_ERR. Note that * this is just a brute force string searcher that does not attempt clever * things like the Boyer-Moore search algorithm. Because of this there are * many degenerate cases where this can take much longer than it needs to. */ int _al_binstrrcaseless (_al_const_bstring b1, int pos, _al_const_bstring b2) { int j, i, l; unsigned char * d0, * d1; if (b1 == NULL || b1->data == NULL || b1->slen < 0 || b2 == NULL || b2->data == NULL || b2->slen < 0) return _AL_BSTR_ERR; if (b1->slen == pos && b2->slen == 0) return pos; if (b1->slen < pos || pos < 0) return _AL_BSTR_ERR; if (b2->slen == 0) return pos; /* Obvious alias case */ if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return _AL_BSTR_OK; i = pos; if ((l = b1->slen - b2->slen) < 0) return _AL_BSTR_ERR; /* If no space to find such a string then snap back */ if (l + 1 <= i) i = l; j = 0; d0 = b2->data; d1 = b1->data; l = b2->slen; for (;;) { if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) { j ++; if (j >= l) return i; } else { i --; if (i < 0) break; j=0; } } return _AL_BSTR_ERR; } /* int _al_bstrchrp (_al_const_bstring b, int c, int pos) * * Search for the character c in b forwards from the position pos * (inclusive). */ int _al_bstrchrp (_al_const_bstring b, int c, int pos) { unsigned char * p; if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return _AL_BSTR_ERR; p = (unsigned char *) bstr__memchr ((b->data + pos), (unsigned char) c, (b->slen - pos)); if (p) return (int) (p - b->data); return _AL_BSTR_ERR; } /* int _al_bstrrchrp (_al_const_bstring b, int c, int pos) * * Search for the character c in b backwards from the position pos in string * (inclusive). */ int _al_bstrrchrp (_al_const_bstring b, int c, int pos) { int i; if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return _AL_BSTR_ERR; for (i=pos; i >= 0; i--) { if (b->data[i] == (unsigned char) c) return i; } return _AL_BSTR_ERR; } #if !defined (BSTRLIB_AGGRESSIVE_MEMORY_FOR_SPEED_TRADEOFF) #define LONG_LOG_BITS_QTY (3) #define LONG_BITS_QTY (1 << LONG_LOG_BITS_QTY) #define LONG_TYPE unsigned char #define CFCLEN ((1 << CHAR_BIT) / LONG_BITS_QTY) struct charField { LONG_TYPE content[CFCLEN]; }; #define testInCharField(cf,c) ((cf)->content[(c) >> LONG_LOG_BITS_QTY] & (((long)1) << ((c) & (LONG_BITS_QTY-1)))) #define setInCharField(cf,idx) { \ unsigned int c = (unsigned int) (idx); \ (cf)->content[c >> LONG_LOG_BITS_QTY] |= (LONG_TYPE) (1ul << (c & (LONG_BITS_QTY-1))); \ } #else #define CFCLEN (1 << CHAR_BIT) struct charField { unsigned char content[CFCLEN]; }; #define testInCharField(cf,c) ((cf)->content[(unsigned char) (c)]) #define setInCharField(cf,idx) (cf)->content[(unsigned int) (idx)] = ~0 #endif /* Convert a _al_bstring to charField */ static int buildCharField (struct charField * cf, _al_const_bstring b) { int i; if (b == NULL || b->data == NULL || b->slen <= 0) return _AL_BSTR_ERR; memset ((void *) cf->content, 0, sizeof (struct charField)); for (i=0; i < b->slen; i++) { setInCharField (cf, b->data[i]); } return _AL_BSTR_OK; } static void invertCharField (struct charField * cf) { int i; for (i=0; i < CFCLEN; i++) cf->content[i] = ~cf->content[i]; } /* Inner engine for _al_binchr */ static int binchrCF (const unsigned char * data, int len, int pos, const struct charField * cf) { int i; for (i=pos; i < len; i++) { unsigned char c = (unsigned char) data[i]; if (testInCharField (cf, c)) return i; } return _AL_BSTR_ERR; } /* int _al_binchr (_al_const_bstring b0, int pos, _al_const_bstring b1); * * Search for the first position in b0 starting from pos or after, in which * one of the characters in b1 is found and return it. If such a position * does not exist in b0, then _AL_BSTR_ERR is returned. */ int _al_binchr (_al_const_bstring b0, int pos, _al_const_bstring b1) { struct charField chrs; if (pos < 0 || b0 == NULL || b0->data == NULL || b0->slen <= pos) return _AL_BSTR_ERR; if (1 == b1->slen) return _al_bstrchrp (b0, b1->data[0], pos); if (0 > buildCharField (&chrs, b1)) return _AL_BSTR_ERR; return binchrCF (b0->data, b0->slen, pos, &chrs); } /* Inner engine for _al_binchrr */ static int binchrrCF (const unsigned char * data, int pos, const struct charField * cf) { int i; for (i=pos; i >= 0; i--) { unsigned int c = (unsigned int) data[i]; if (testInCharField (cf, c)) return i; } return _AL_BSTR_ERR; } /* int _al_binchrr (_al_const_bstring b0, int pos, _al_const_bstring b1); * * Search for the last position in b0 no greater than pos, in which one of * the characters in b1 is found and return it. If such a position does not * exist in b0, then _AL_BSTR_ERR is returned. */ int _al_binchrr (_al_const_bstring b0, int pos, _al_const_bstring b1) { struct charField chrs; if (pos < 0 || b0 == NULL || b0->data == NULL || b1 == NULL || b0->slen < pos) return _AL_BSTR_ERR; if (pos == b0->slen) pos--; if (1 == b1->slen) return _al_bstrrchrp (b0, b1->data[0], pos); if (0 > buildCharField (&chrs, b1)) return _AL_BSTR_ERR; return binchrrCF (b0->data, pos, &chrs); } /* int _al_bninchr (_al_const_bstring b0, int pos, _al_const_bstring b1); * * Search for the first position in b0 starting from pos or after, in which * none of the characters in b1 is found and return it. If such a position * does not exist in b0, then _AL_BSTR_ERR is returned. */ int _al_bninchr (_al_const_bstring b0, int pos, _al_const_bstring b1) { struct charField chrs; if (pos < 0 || b0 == NULL || b0->data == NULL || b0->slen <= pos) return _AL_BSTR_ERR; if (buildCharField (&chrs, b1) < 0) return _AL_BSTR_ERR; invertCharField (&chrs); return binchrCF (b0->data, b0->slen, pos, &chrs); } /* int _al_bninchrr (_al_const_bstring b0, int pos, _al_const_bstring b1); * * Search for the last position in b0 no greater than pos, in which none of * the characters in b1 is found and return it. If such a position does not * exist in b0, then _AL_BSTR_ERR is returned. */ int _al_bninchrr (_al_const_bstring b0, int pos, _al_const_bstring b1) { struct charField chrs; if (pos < 0 || b0 == NULL || b0->data == NULL || b0->slen < pos) return _AL_BSTR_ERR; if (pos == b0->slen) pos--; if (buildCharField (&chrs, b1) < 0) return _AL_BSTR_ERR; invertCharField (&chrs); return binchrrCF (b0->data, pos, &chrs); } /* int _al_bsetstr (_al_bstring b0, int pos, _al_bstring b1, unsigned char fill) * * Overwrite the string b0 starting at position pos with the string b1. If * the position pos is past the end of b0, then the character "fill" is * appended as necessary to make up the gap between the end of b0 and pos. * If b1 is NULL, it behaves as if it were a 0-length string. */ int _al_bsetstr (_al_bstring b0, int pos, _al_const_bstring b1, unsigned char fill) { int d, newlen; ptrdiff_t pd; _al_bstring aux = (_al_bstring) b1; if (pos < 0 || b0 == NULL || b0->slen < 0 || NULL == b0->data || b0->mlen < b0->slen || b0->mlen <= 0) return _AL_BSTR_ERR; if (b1 != NULL && (b1->slen < 0 || b1->data == NULL)) return _AL_BSTR_ERR; d = pos; /* Aliasing case */ if (NULL != aux) { if ((pd = (ptrdiff_t) (b1->data - b0->data)) >= 0 && pd < (ptrdiff_t) b0->mlen) { if (NULL == (aux = _al_bstrcpy (b1))) return _AL_BSTR_ERR; } d += aux->slen; } /* Increase memory size if necessary */ if (_al_balloc (b0, d + 1) != _AL_BSTR_OK) { if (aux != b1) _al_bdestroy (aux); return _AL_BSTR_ERR; } newlen = b0->slen; /* Fill in "fill" character as necessary */ if (pos > newlen) { bstr__memset (b0->data + b0->slen, (int) fill, (size_t) (pos - b0->slen)); newlen = pos; } /* Copy b1 to position pos in b0. */ if (aux != NULL) { bBlockCopy ((char *) (b0->data + pos), (char *) aux->data, aux->slen); if (aux != b1) _al_bdestroy (aux); } /* Indicate the potentially increased size of b0 */ if (d > newlen) newlen = d; b0->slen = newlen; b0->data[newlen] = (unsigned char) '\0'; return _AL_BSTR_OK; } /* int _al_binsert (_al_bstring b1, int pos, _al_bstring b2, unsigned char fill) * * Inserts the string b2 into b1 at position pos. If the position pos is * past the end of b1, then the character "fill" is appended as necessary to * make up the gap between the end of b1 and pos. Unlike _al_bsetstr, _al_binsert * does not allow b2 to be NULL. */ int _al_binsert (_al_bstring b1, int pos, _al_const_bstring b2, unsigned char fill) { int d, l; ptrdiff_t pd; _al_bstring aux = (_al_bstring) b2; if (pos < 0 || b1 == NULL || b2 == NULL || b1->slen < 0 || b2->slen < 0 || b1->mlen < b1->slen || b1->mlen <= 0) return _AL_BSTR_ERR; /* Aliasing case */ if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->mlen) { if (NULL == (aux = _al_bstrcpy (b2))) return _AL_BSTR_ERR; } /* Compute the two possible end pointers */ d = b1->slen + aux->slen; l = pos + aux->slen; if ((d|l) < 0) return _AL_BSTR_ERR; if (l > d) { /* Inserting past the end of the string */ if (_al_balloc (b1, l + 1) != _AL_BSTR_OK) { if (aux != b2) _al_bdestroy (aux); return _AL_BSTR_ERR; } bstr__memset (b1->data + b1->slen, (int) fill, (size_t) (pos - b1->slen)); b1->slen = l; } else { /* Inserting in the middle of the string */ if (_al_balloc (b1, d + 1) != _AL_BSTR_OK) { if (aux != b2) _al_bdestroy (aux); return _AL_BSTR_ERR; } bBlockCopy (b1->data + l, b1->data + pos, d - l); b1->slen = d; } bBlockCopy (b1->data + pos, aux->data, aux->slen); b1->data[b1->slen] = (unsigned char) '\0'; if (aux != b2) _al_bdestroy (aux); return _AL_BSTR_OK; } /* int _al_breplace (_al_bstring b1, int pos, int len, _al_bstring b2, * unsigned char fill) * * Replace a section of a string from pos for a length len with the string b2. * fill is used is pos > b1->slen. */ int _al_breplace (_al_bstring b1, int pos, int len, _al_const_bstring b2, unsigned char fill) { int pl, ret; ptrdiff_t pd; _al_bstring aux = (_al_bstring) b2; if (pos < 0 || len < 0 || (pl = pos + len) < 0 || b1 == NULL || b2 == NULL || b1->data == NULL || b2->data == NULL || b1->slen < 0 || b2->slen < 0 || b1->mlen < b1->slen || b1->mlen <= 0) return _AL_BSTR_ERR; /* Straddles the end? */ if (pl >= b1->slen) { if ((ret = _al_bsetstr (b1, pos, b2, fill)) < 0) return ret; if (pos + b2->slen < b1->slen) { b1->slen = pos + b2->slen; b1->data[b1->slen] = (unsigned char) '\0'; } return ret; } /* Aliasing case */ if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->slen) { if (NULL == (aux = _al_bstrcpy (b2))) return _AL_BSTR_ERR; } if (aux->slen > len) { if (_al_balloc (b1, b1->slen + aux->slen - len) != _AL_BSTR_OK) { if (aux != b2) _al_bdestroy (aux); return _AL_BSTR_ERR; } } if (aux->slen != len) bstr__memmove (b1->data + pos + aux->slen, b1->data + pos + len, b1->slen - (pos + len)); bstr__memcpy (b1->data + pos, aux->data, aux->slen); b1->slen += aux->slen - len; b1->data[b1->slen] = (unsigned char) '\0'; if (aux != b2) _al_bdestroy (aux); return _AL_BSTR_OK; } /* int _al_bfindreplace (_al_bstring b, _al_const_bstring find, _al_const_bstring repl, * int pos) * * Replace all occurrences of a find string with a replace string after a * given point in a _al_bstring. */ typedef int (*instr_fnptr) (_al_const_bstring s1, int pos, _al_const_bstring s2); static int findreplaceengine (_al_bstring b, _al_const_bstring find, _al_const_bstring repl, int pos, instr_fnptr instr) { int i, ret, slen, mlen, delta, acc; int * d; int static_d[32]; ptrdiff_t pd; _al_bstring auxf = (_al_bstring) find; _al_bstring auxr = (_al_bstring) repl; if (b == NULL || b->data == NULL || find == NULL || find->data == NULL || repl == NULL || repl->data == NULL || pos < 0 || find->slen <= 0 || b->mlen < 0 || b->slen > b->mlen || b->mlen <= 0 || b->slen < 0 || repl->slen < 0) return _AL_BSTR_ERR; if (pos > b->slen - find->slen) return _AL_BSTR_OK; /* Alias with find string */ pd = (ptrdiff_t) (find->data - b->data); if ((ptrdiff_t) (pos - find->slen) < pd && pd < (ptrdiff_t) b->slen) { if (NULL == (auxf = _al_bstrcpy (find))) return _AL_BSTR_ERR; } /* Alias with repl string */ pd = (ptrdiff_t) (repl->data - b->data); if ((ptrdiff_t) (pos - repl->slen) < pd && pd < (ptrdiff_t) b->slen) { if (NULL == (auxr = _al_bstrcpy (repl))) { if (auxf != find) _al_bdestroy (auxf); return _AL_BSTR_ERR; } } delta = auxf->slen - auxr->slen; /* in-place replacement since find and replace strings are of equal length */ if (delta == 0) { while ((pos = instr (b, pos, auxf)) >= 0) { bstr__memcpy (b->data + pos, auxr->data, auxr->slen); pos += auxf->slen; } if (auxf != find) _al_bdestroy (auxf); if (auxr != repl) _al_bdestroy (auxr); return _AL_BSTR_OK; } /* shrinking replacement since auxf->slen > auxr->slen */ if (delta > 0) { acc = 0; while ((i = instr (b, pos, auxf)) >= 0) { if (acc && i > pos) bstr__memmove (b->data + pos - acc, b->data + pos, i - pos); if (auxr->slen) bstr__memcpy (b->data + i - acc, auxr->data, auxr->slen); acc += delta; pos = i + auxf->slen; } if (acc) { i = b->slen; if (i > pos) bstr__memmove (b->data + pos - acc, b->data + pos, i - pos); b->slen -= acc; b->data[b->slen] = (unsigned char) '\0'; } if (auxf != find) _al_bdestroy (auxf); if (auxr != repl) _al_bdestroy (auxr); return _AL_BSTR_OK; } /* expanding replacement since find->slen < repl->slen. Its a lot more complicated. */ mlen = 32; d = (int *) static_d; /* Avoid malloc for trivial cases */ acc = slen = 0; while ((pos = instr (b, pos, auxf)) >= 0) { if (slen + 1 >= mlen) { int sl; int * t; mlen += mlen; sl = sizeof (int *) * mlen; if (static_d == d) d = NULL; if (sl < mlen || NULL == (t = (int *) bstr__realloc (d, sl))) { ret = _AL_BSTR_ERR; goto done; } if (NULL == d) bstr__memcpy (t, static_d, sizeof (static_d)); d = t; } d[slen] = pos; slen++; acc -= delta; pos += auxf->slen; if (pos < 0 || acc < 0) { ret = _AL_BSTR_ERR; goto done; } } d[slen] = b->slen; if (_AL_BSTR_OK == (ret = _al_balloc (b, b->slen + acc + 1))) { b->slen += acc; for (i = slen-1; i >= 0; i--) { int s, l; s = d[i] + auxf->slen; l = d[i+1] - s; if (l) { bstr__memmove (b->data + s + acc, b->data + s, l); } if (auxr->slen) { bstr__memmove (b->data + s + acc - auxr->slen, auxr->data, auxr->slen); } acc += delta; } b->data[b->slen] = (unsigned char) '\0'; } done:; if (static_d == d) d = NULL; bstr__free (d); if (auxf != find) _al_bdestroy (auxf); if (auxr != repl) _al_bdestroy (auxr); return ret; } /* int _al_bfindreplace (_al_bstring b, _al_const_bstring find, _al_const_bstring repl, * int pos) * * Replace all occurrences of a find string with a replace string after a * given point in a _al_bstring. */ int _al_bfindreplace (_al_bstring b, _al_const_bstring find, _al_const_bstring repl, int pos) { return findreplaceengine (b, find, repl, pos, _al_binstr); } /* int _al_bfindreplacecaseless (_al_bstring b, _al_const_bstring find, _al_const_bstring repl, * int pos) * * Replace all occurrences of a find string, ignoring case, with a replace * string after a given point in a _al_bstring. */ int _al_bfindreplacecaseless (_al_bstring b, _al_const_bstring find, _al_const_bstring repl, int pos) { return findreplaceengine (b, find, repl, pos, _al_binstrcaseless); } /* int _al_binsertch (_al_bstring b, int pos, int len, unsigned char fill) * * Inserts the character fill repeatedly into b at position pos for a * length len. If the position pos is past the end of b, then the * character "fill" is appended as necessary to make up the gap between the * end of b and the position pos + len. */ int _al_binsertch (_al_bstring b, int pos, int len, unsigned char fill) { int d, l, i; if (pos < 0 || b == NULL || b->slen < 0 || b->mlen < b->slen || b->mlen <= 0 || len < 0) return _AL_BSTR_ERR; /* Compute the two possible end pointers */ d = b->slen + len; l = pos + len; if ((d|l) < 0) return _AL_BSTR_ERR; if (l > d) { /* Inserting past the end of the string */ if (_al_balloc (b, l + 1) != _AL_BSTR_OK) return _AL_BSTR_ERR; pos = b->slen; b->slen = l; } else { /* Inserting in the middle of the string */ if (_al_balloc (b, d + 1) != _AL_BSTR_OK) return _AL_BSTR_ERR; for (i = d - 1; i >= l; i--) { b->data[i] = b->data[i - len]; } b->slen = d; } for (i=pos; i < l; i++) b->data[i] = fill; b->data[b->slen] = (unsigned char) '\0'; return _AL_BSTR_OK; } /* int _al_bpattern (_al_bstring b, int len) * * Replicate the _al_bstring, b in place, end to end repeatedly until it * surpasses len characters, then chop the result to exactly len characters. * This function operates in-place. The function will return with _AL_BSTR_ERR * if b is NULL or of length 0, otherwise _AL_BSTR_OK is returned. */ int _al_bpattern (_al_bstring b, int len) { int i, d; d = _al_blength (b); if (d <= 0 || len < 0 || _al_balloc (b, len + 1) != _AL_BSTR_OK) return _AL_BSTR_ERR; if (len > 0) { if (d == 1) return _al_bsetstr (b, len, NULL, b->data[0]); for (i = d; i < len; i++) b->data[i] = b->data[i - d]; } b->data[len] = (unsigned char) '\0'; b->slen = len; return _AL_BSTR_OK; } #define BS_BUFF_SZ (1024) /* int _al_breada (_al_bstring b, _al_bNread readPtr, void * parm) * * Use a finite buffer fread-like function readPtr to concatenate to the * _al_bstring b the entire contents of file-like source data in a roughly * efficient way. */ int _al_breada (_al_bstring b, _al_bNread readPtr, void * parm) { int i, l, n; if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen || b->mlen <= 0 || readPtr == NULL) return _AL_BSTR_ERR; i = b->slen; for (n=i+16; ; n += ((n < BS_BUFF_SZ) ? n : BS_BUFF_SZ)) { if (_AL_BSTR_OK != _al_balloc (b, n + 1)) return _AL_BSTR_ERR; l = (int) readPtr ((void *) (b->data + i), 1, n - i, parm); i += l; b->slen = i; if (i < n) break; } b->data[i] = (unsigned char) '\0'; return _AL_BSTR_OK; } /* _al_bstring _al_bread (_al_bNread readPtr, void * parm) * * Use a finite buffer fread-like function readPtr to create a _al_bstring * filled with the entire contents of file-like source data in a roughly * efficient way. */ _al_bstring _al_bread (_al_bNread readPtr, void * parm) { _al_bstring buff; if (0 > _al_breada (buff = _al_bfromcstr (""), readPtr, parm)) { _al_bdestroy (buff); return NULL; } return buff; } /* int _al_bassigngets (_al_bstring b, _al_bNgetc getcPtr, void * parm, char terminator) * * Use an fgetc-like single character stream reading function (getcPtr) to * obtain a sequence of characters which are concatenated to the end of the * _al_bstring b. The stream read is terminated by the passed in terminator * parameter. * * If getcPtr returns with a negative number, or the terminator character * (which is appended) is read, then the stream reading is halted and the * function returns with a partial result in b. If there is an empty partial * result, 1 is returned. If no characters are read, or there is some other * detectable error, _AL_BSTR_ERR is returned. */ int _al_bassigngets (_al_bstring b, _al_bNgetc getcPtr, void * parm, char terminator) { int c, d, e; if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen || b->mlen <= 0 || getcPtr == NULL) return _AL_BSTR_ERR; d = 0; e = b->mlen - 2; while ((c = getcPtr (parm)) >= 0) { if (d > e) { b->slen = d; if (_al_balloc (b, d + 2) != _AL_BSTR_OK) return _AL_BSTR_ERR; e = b->mlen - 2; } b->data[d] = (unsigned char) c; d++; if (c == terminator) break; } b->data[d] = (unsigned char) '\0'; b->slen = d; return d == 0 && c < 0; } /* int _al_bgetsa (_al_bstring b, _al_bNgetc getcPtr, void * parm, char terminator) * * Use an fgetc-like single character stream reading function (getcPtr) to * obtain a sequence of characters which are concatenated to the end of the * _al_bstring b. The stream read is terminated by the passed in terminator * parameter. * * If getcPtr returns with a negative number, or the terminator character * (which is appended) is read, then the stream reading is halted and the * function returns with a partial result concatentated to b. If there is * an empty partial result, 1 is returned. If no characters are read, or * there is some other detectable error, _AL_BSTR_ERR is returned. */ int _al_bgetsa (_al_bstring b, _al_bNgetc getcPtr, void * parm, char terminator) { int c, d, e; if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen || b->mlen <= 0 || getcPtr == NULL) return _AL_BSTR_ERR; d = b->slen; e = b->mlen - 2; while ((c = getcPtr (parm)) >= 0) { if (d > e) { b->slen = d; if (_al_balloc (b, d + 2) != _AL_BSTR_OK) return _AL_BSTR_ERR; e = b->mlen - 2; } b->data[d] = (unsigned char) c; d++; if (c == terminator) break; } b->data[d] = (unsigned char) '\0'; b->slen = d; return d == 0 && c < 0; } /* _al_bstring _al_bgets (_al_bNgetc getcPtr, void * parm, char terminator) * * Use an fgetc-like single character stream reading function (getcPtr) to * obtain a sequence of characters which are concatenated into a _al_bstring. * The stream read is terminated by the passed in terminator function. * * If getcPtr returns with a negative number, or the terminator character * (which is appended) is read, then the stream reading is halted and the * result obtained thus far is returned. If no characters are read, or * there is some other detectable error, NULL is returned. */ _al_bstring _al_bgets (_al_bNgetc getcPtr, void * parm, char terminator) { _al_bstring buff; if (0 > _al_bgetsa (buff = _al_bfromcstr (""), getcPtr, parm, terminator) || 0 >= buff->slen) { _al_bdestroy (buff); buff = NULL; } return buff; } struct _al_bStream { _al_bstring buff; /* Buffer for over-reads */ void * parm; /* The stream handle for core stream */ _al_bNread readFnPtr; /* fread compatible fnptr for core stream */ int isEOF; /* track file's EOF state */ int maxBuffSz; }; /* struct _al_bStream * _al_bsopen (_al_bNread readPtr, void * parm) * * Wrap a given open stream (described by a fread compatible function * pointer and stream handle) into an open _al_bStream suitable for the _al_bstring * library streaming functions. */ struct _al_bStream * _al_bsopen (_al_bNread readPtr, void * parm) { struct _al_bStream * s; if (readPtr == NULL) return NULL; s = (struct _al_bStream *) bstr__alloc (sizeof (struct _al_bStream)); if (s == NULL) return NULL; s->parm = parm; s->buff = _al_bfromcstr (""); s->readFnPtr = readPtr; s->maxBuffSz = BS_BUFF_SZ; s->isEOF = 0; return s; } /* int _al_bsbufflength (struct _al_bStream * s, int sz) * * Set the length of the buffer used by the _al_bStream. If sz is zero, the * length is not set. This function returns with the previous length. */ int _al_bsbufflength (struct _al_bStream * s, int sz) { int oldSz; if (s == NULL || sz < 0) return _AL_BSTR_ERR; oldSz = s->maxBuffSz; if (sz > 0) s->maxBuffSz = sz; return oldSz; } int _al_bseof (const struct _al_bStream * s) { if (s == NULL || s->readFnPtr == NULL) return _AL_BSTR_ERR; return s->isEOF && (s->buff->slen == 0); } /* void * _al_bsclose (struct _al_bStream * s) * * Close the _al_bStream, and return the handle to the stream that was originally * used to open the given stream. */ void * _al_bsclose (struct _al_bStream * s) { void * parm; if (s == NULL) return NULL; s->readFnPtr = NULL; if (s->buff) _al_bdestroy (s->buff); s->buff = NULL; parm = s->parm; s->parm = NULL; s->isEOF = 1; bstr__free (s); return parm; } /* int _al_bsreadlna (_al_bstring r, struct _al_bStream * s, char terminator) * * Read a _al_bstring terminated by the terminator character or the end of the * stream from the _al_bStream (s) and return it into the parameter r. This * function may read additional characters from the core stream that are not * returned, but will be retained for subsequent read operations. */ int _al_bsreadlna (_al_bstring r, struct _al_bStream * s, char terminator) { int i, l, ret, rlo; char * b; struct _al_tagbstring x; if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0 || r->slen < 0 || r->mlen < r->slen) return _AL_BSTR_ERR; l = s->buff->slen; if (_AL_BSTR_OK != _al_balloc (s->buff, s->maxBuffSz + 1)) return _AL_BSTR_ERR; b = (char *) s->buff->data; x.data = (unsigned char *) b; /* First check if the current buffer holds the terminator */ b[l] = terminator; /* Set sentinel */ for (i=0; b[i] != terminator; i++) ; if (i < l) { x.slen = i + 1; ret = _al_bconcat (r, &x); s->buff->slen = l; if (_AL_BSTR_OK == ret) _al_bdelete (s->buff, 0, i + 1); return _AL_BSTR_OK; } rlo = r->slen; /* If not then just concatenate the entire buffer to the output */ x.slen = l; if (_AL_BSTR_OK != _al_bconcat (r, &x)) return _AL_BSTR_ERR; /* Perform direct in-place reads into the destination to allow for the minimum of data-copies */ for (;;) { if (_AL_BSTR_OK != _al_balloc (r, r->slen + s->maxBuffSz + 1)) return _AL_BSTR_ERR; b = (char *) (r->data + r->slen); l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm); if (l <= 0) { r->data[r->slen] = (unsigned char) '\0'; s->buff->slen = 0; s->isEOF = 1; /* If nothing was read return with an error message */ return _AL_BSTR_ERR & -(r->slen == rlo); } b[l] = terminator; /* Set sentinel */ for (i=0; b[i] != terminator; i++) ; if (i < l) break; r->slen += l; } /* Terminator found, push over-read back to buffer */ i++; r->slen += i; s->buff->slen = l - i; bstr__memcpy (s->buff->data, b + i, l - i); r->data[r->slen] = (unsigned char) '\0'; return _AL_BSTR_OK; } /* int _al_bsreadlnsa (_al_bstring r, struct _al_bStream * s, _al_bstring term) * * Read a _al_bstring terminated by any character in the term string or the end * of the stream from the _al_bStream (s) and return it into the parameter r. * This function may read additional characters from the core stream that * are not returned, but will be retained for subsequent read operations. */ int _al_bsreadlnsa (_al_bstring r, struct _al_bStream * s, _al_const_bstring term) { int i, l, ret, rlo; unsigned char * b; struct _al_tagbstring x; struct charField cf; if (s == NULL || s->buff == NULL || r == NULL || term == NULL || term->data == NULL || r->mlen <= 0 || r->slen < 0 || r->mlen < r->slen) return _AL_BSTR_ERR; if (term->slen == 1) return _al_bsreadlna (r, s, term->data[0]); if (term->slen < 1 || buildCharField (&cf, term)) return _AL_BSTR_ERR; l = s->buff->slen; if (_AL_BSTR_OK != _al_balloc (s->buff, s->maxBuffSz + 1)) return _AL_BSTR_ERR; b = (unsigned char *) s->buff->data; x.data = b; /* First check if the current buffer holds the terminator */ b[l] = term->data[0]; /* Set sentinel */ for (i=0; !testInCharField (&cf, b[i]); i++) ; if (i < l) { x.slen = i + 1; ret = _al_bconcat (r, &x); s->buff->slen = l; if (_AL_BSTR_OK == ret) _al_bdelete (s->buff, 0, i + 1); return _AL_BSTR_OK; } rlo = r->slen; /* If not then just concatenate the entire buffer to the output */ x.slen = l; if (_AL_BSTR_OK != _al_bconcat (r, &x)) return _AL_BSTR_ERR; /* Perform direct in-place reads into the destination to allow for the minimum of data-copies */ for (;;) { if (_AL_BSTR_OK != _al_balloc (r, r->slen + s->maxBuffSz + 1)) return _AL_BSTR_ERR; b = (unsigned char *) (r->data + r->slen); l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm); if (l <= 0) { r->data[r->slen] = (unsigned char) '\0'; s->buff->slen = 0; s->isEOF = 1; /* If nothing was read return with an error message */ return _AL_BSTR_ERR & -(r->slen == rlo); } b[l] = term->data[0]; /* Set sentinel */ for (i=0; !testInCharField (&cf, b[i]); i++) ; if (i < l) break; r->slen += l; } /* Terminator found, push over-read back to buffer */ i++; r->slen += i; s->buff->slen = l - i; bstr__memcpy (s->buff->data, b + i, l - i); r->data[r->slen] = (unsigned char) '\0'; return _AL_BSTR_OK; } /* int _al_bsreada (_al_bstring r, struct _al_bStream * s, int n) * * Read a _al_bstring of length n (or, if it is fewer, as many bytes as is * remaining) from the _al_bStream. This function may read additional * characters from the core stream that are not returned, but will be * retained for subsequent read operations. This function will not read * additional characters from the core stream beyond virtual stream pointer. */ int _al_bsreada (_al_bstring r, struct _al_bStream * s, int n) { int l, ret, orslen; char * b; struct _al_tagbstring x; if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0 || r->slen < 0 || r->mlen < r->slen || n <= 0) return _AL_BSTR_ERR; n += r->slen; if (n <= 0) return _AL_BSTR_ERR; l = s->buff->slen; orslen = r->slen; if (0 == l) { if (s->isEOF) return _AL_BSTR_ERR; if (r->mlen > n) { l = (int) s->readFnPtr (r->data + r->slen, 1, n - r->slen, s->parm); if (0 >= l || l > n - r->slen) { s->isEOF = 1; return _AL_BSTR_ERR; } r->slen += l; r->data[r->slen] = (unsigned char) '\0'; return 0; } } if (_AL_BSTR_OK != _al_balloc (s->buff, s->maxBuffSz + 1)) return _AL_BSTR_ERR; b = (char *) s->buff->data; x.data = (unsigned char *) b; do { if (l + r->slen >= n) { x.slen = n - r->slen; ret = _al_bconcat (r, &x); s->buff->slen = l; if (_AL_BSTR_OK == ret) _al_bdelete (s->buff, 0, x.slen); return _AL_BSTR_ERR & -(r->slen == orslen); } x.slen = l; if (_AL_BSTR_OK != _al_bconcat (r, &x)) break; l = n - r->slen; if (l > s->maxBuffSz) l = s->maxBuffSz; l = (int) s->readFnPtr (b, 1, l, s->parm); } while (l > 0); if (l < 0) l = 0; if (l == 0) s->isEOF = 1; s->buff->slen = l; return _AL_BSTR_ERR & -(r->slen == orslen); } /* int _al_bsreadln (_al_bstring r, struct _al_bStream * s, char terminator) * * Read a _al_bstring terminated by the terminator character or the end of the * stream from the _al_bStream (s) and return it into the parameter r. This * function may read additional characters from the core stream that are not * returned, but will be retained for subsequent read operations. */ int _al_bsreadln (_al_bstring r, struct _al_bStream * s, char terminator) { if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0) return _AL_BSTR_ERR; if (_AL_BSTR_OK != _al_balloc (s->buff, s->maxBuffSz + 1)) return _AL_BSTR_ERR; r->slen = 0; return _al_bsreadlna (r, s, terminator); } /* int _al_bsreadlns (_al_bstring r, struct _al_bStream * s, _al_bstring term) * * Read a _al_bstring terminated by any character in the term string or the end * of the stream from the _al_bStream (s) and return it into the parameter r. * This function may read additional characters from the core stream that * are not returned, but will be retained for subsequent read operations. */ int _al_bsreadlns (_al_bstring r, struct _al_bStream * s, _al_const_bstring term) { if (s == NULL || s->buff == NULL || r == NULL || term == NULL || term->data == NULL || r->mlen <= 0) return _AL_BSTR_ERR; if (term->slen == 1) return _al_bsreadln (r, s, term->data[0]); if (term->slen < 1) return _AL_BSTR_ERR; if (_AL_BSTR_OK != _al_balloc (s->buff, s->maxBuffSz + 1)) return _AL_BSTR_ERR; r->slen = 0; return _al_bsreadlnsa (r, s, term); } /* int _al_bsread (_al_bstring r, struct _al_bStream * s, int n) * * Read a _al_bstring of length n (or, if it is fewer, as many bytes as is * remaining) from the _al_bStream. This function may read additional * characters from the core stream that are not returned, but will be * retained for subsequent read operations. This function will not read * additional characters from the core stream beyond virtual stream pointer. */ int _al_bsread (_al_bstring r, struct _al_bStream * s, int n) { if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0 || n <= 0) return _AL_BSTR_ERR; if (_AL_BSTR_OK != _al_balloc (s->buff, s->maxBuffSz + 1)) return _AL_BSTR_ERR; r->slen = 0; return _al_bsreada (r, s, n); } /* int _al_bsunread (struct _al_bStream * s, _al_const_bstring b) * * Insert a _al_bstring into the _al_bStream at the current position. These * characters will be read prior to those that actually come from the core * stream. */ int _al_bsunread (struct _al_bStream * s, _al_const_bstring b) { if (s == NULL || s->buff == NULL) return _AL_BSTR_ERR; return _al_binsert (s->buff, 0, b, (unsigned char) '?'); } /* int _al_bspeek (_al_bstring r, const struct _al_bStream * s) * * Return the currently buffered characters from the _al_bStream that will be * read prior to reads from the core stream. */ int _al_bspeek (_al_bstring r, const struct _al_bStream * s) { if (s == NULL || s->buff == NULL) return _AL_BSTR_ERR; return _al_bassign (r, s->buff); } /* _al_bstring _al_bjoin (const struct _al_bstrList * bl, _al_const_bstring sep); * * Join the entries of a _al_bstrList into one _al_bstring by sequentially * concatenating them with the sep string in between. If there is an error * NULL is returned, otherwise a _al_bstring with the correct result is returned. */ _al_bstring _al_bjoin (const struct _al_bstrList * bl, _al_const_bstring sep) { _al_bstring b; int i, c, v; if (bl == NULL || bl->qty < 0) return NULL; if (sep != NULL && (sep->slen < 0 || sep->data == NULL)) return NULL; for (i = 0, c = 1; i < bl->qty; i++) { v = bl->entry[i]->slen; if (v < 0) return NULL; /* Invalid input */ c += v; if (c < 0) return NULL; /* Wrap around ?? */ } if (sep != NULL) c += (bl->qty - 1) * sep->slen; b = (_al_bstring) bstr__alloc (sizeof (struct _al_tagbstring)); if (NULL == b) return NULL; /* Out of memory */ b->data = (unsigned char *) bstr__alloc (c); if (b->data == NULL) { bstr__free (b); return NULL; } b->mlen = c; b->slen = c-1; for (i = 0, c = 0; i < bl->qty; i++) { if (i > 0 && sep != NULL) { bstr__memcpy (b->data + c, sep->data, sep->slen); c += sep->slen; } v = bl->entry[i]->slen; bstr__memcpy (b->data + c, bl->entry[i]->data, v); c += v; } b->data[c] = (unsigned char) '\0'; return b; } #define BSSSC_BUFF_LEN (256) /* int _al_bssplitscb (struct _al_bStream * s, _al_const_bstring splitStr, * int (* cb) (void * parm, int ofs, _al_const_bstring entry), void * parm) * * Iterate the set of disjoint sequential substrings read from a stream * divided by any of the characters in splitStr. An empty splitStr causes * the whole stream to be iterated once. * * Note: At the point of calling the cb function, the _al_bStream pointer is * pointed exactly at the position right after having read the split * character. The cb function can act on the stream by causing the _al_bStream * pointer to move, and _al_bssplitscb will continue by starting the next split * at the position of the pointer after the return from cb. * * However, if the cb causes the _al_bStream s to be destroyed then the cb must * return with a negative value, otherwise _al_bssplitscb will continue in an * undefined manner. */ int _al_bssplitscb (struct _al_bStream * s, _al_const_bstring splitStr, int (* cb) (void * parm, int ofs, _al_const_bstring entry), void * parm) { struct charField chrs; _al_bstring buff; int i, p, ret; if (cb == NULL || s == NULL || s->readFnPtr == NULL || splitStr == NULL || splitStr->slen < 0) return _AL_BSTR_ERR; if (NULL == (buff = _al_bfromcstr (""))) return _AL_BSTR_ERR; if (splitStr->slen == 0) { while (_al_bsreada (buff, s, BSSSC_BUFF_LEN) >= 0) ; if ((ret = cb (parm, 0, buff)) > 0) ret = 0; } else { buildCharField (&chrs, splitStr); ret = p = i = 0; for (;;) { if (i >= buff->slen) { _al_bsreada (buff, s, BSSSC_BUFF_LEN); if (i >= buff->slen) { if (0 < (ret = cb (parm, p, buff))) ret = 0; break; } } if (testInCharField (&chrs, buff->data[i])) { struct _al_tagbstring t; unsigned char c; _al_blk2tbstr (t, buff->data + i + 1, buff->slen - (i + 1)); if ((ret = _al_bsunread (s, &t)) < 0) break; buff->slen = i; c = buff->data[i]; buff->data[i] = (unsigned char) '\0'; if ((ret = cb (parm, p, buff)) < 0) break; buff->data[i] = c; buff->slen = 0; p += i + 1; i = -1; } i++; } } _al_bdestroy (buff); return ret; } /* int _al_bssplitstrcb (struct _al_bStream * s, _al_const_bstring splitStr, * int (* cb) (void * parm, int ofs, _al_const_bstring entry), void * parm) * * Iterate the set of disjoint sequential substrings read from a stream * divided by the entire substring splitStr. An empty splitStr causes * each character of the stream to be iterated. * * Note: At the point of calling the cb function, the _al_bStream pointer is * pointed exactly at the position right after having read the split * character. The cb function can act on the stream by causing the _al_bStream * pointer to move, and _al_bssplitscb will continue by starting the next split * at the position of the pointer after the return from cb. * * However, if the cb causes the _al_bStream s to be destroyed then the cb must * return with a negative value, otherwise _al_bssplitscb will continue in an * undefined manner. */ int _al_bssplitstrcb (struct _al_bStream * s, _al_const_bstring splitStr, int (* cb) (void * parm, int ofs, _al_const_bstring entry), void * parm) { _al_bstring buff; int i, p, ret; if (cb == NULL || s == NULL || s->readFnPtr == NULL || splitStr == NULL || splitStr->slen < 0) return _AL_BSTR_ERR; if (splitStr->slen == 1) return _al_bssplitscb (s, splitStr, cb, parm); if (NULL == (buff = _al_bfromcstr (""))) return _AL_BSTR_ERR; if (splitStr->slen == 0) { for (i=0; _al_bsreada (buff, s, BSSSC_BUFF_LEN) >= 0; i++) { if ((ret = cb (parm, 0, buff)) < 0) { _al_bdestroy (buff); return ret; } buff->slen = 0; } return _AL_BSTR_OK; } else { ret = p = i = 0; for (i=p=0;;) { if ((ret = _al_binstr (buff, 0, splitStr)) >= 0) { struct _al_tagbstring t; _al_blk2tbstr (t, buff->data, ret); i = ret + splitStr->slen; if ((ret = cb (parm, p, &t)) < 0) break; p += i; _al_bdelete (buff, 0, i); } else { _al_bsreada (buff, s, BSSSC_BUFF_LEN); if (_al_bseof (s)) { if ((ret = cb (parm, p, buff)) > 0) ret = 0; break; } } } } _al_bdestroy (buff); return ret; } /* int _al_bstrListCreate (void) * * Create a _al_bstrList. */ struct _al_bstrList * _al_bstrListCreate (void) { struct _al_bstrList * sl = (struct _al_bstrList *) bstr__alloc (sizeof (struct _al_bstrList)); if (sl) { sl->entry = (_al_bstring *) bstr__alloc (1*sizeof (_al_bstring)); if (!sl->entry) { bstr__free (sl); sl = NULL; } else { sl->qty = 0; sl->mlen = 1; } } return sl; } /* int _al_bstrListDestroy (struct _al_bstrList * sl) * * Destroy a _al_bstrList that has been created by _al_bsplit, _al_bsplits or _al_bstrListCreate. */ int _al_bstrListDestroy (struct _al_bstrList * sl) { int i; if (sl == NULL || sl->qty < 0) return _AL_BSTR_ERR; for (i=0; i < sl->qty; i++) { if (sl->entry[i]) { _al_bdestroy (sl->entry[i]); sl->entry[i] = NULL; } } sl->qty = -1; sl->mlen = -1; bstr__free (sl->entry); sl->entry = NULL; bstr__free (sl); return _AL_BSTR_OK; } /* int _al_bstrListAlloc (struct _al_bstrList * sl, int msz) * * Ensure that there is memory for at least msz number of entries for the * list. */ int _al_bstrListAlloc (struct _al_bstrList * sl, int msz) { _al_bstring * l; int smsz; size_t nsz; if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return _AL_BSTR_ERR; if (sl->mlen >= msz) return _AL_BSTR_OK; smsz = snapUpSize (msz); nsz = ((size_t) smsz) * sizeof (_al_bstring); if (nsz < (size_t) smsz) return _AL_BSTR_ERR; l = (_al_bstring *) bstr__realloc (sl->entry, nsz); if (!l) { smsz = msz; nsz = ((size_t) smsz) * sizeof (_al_bstring); l = (_al_bstring *) bstr__realloc (sl->entry, nsz); if (!l) return _AL_BSTR_ERR; } sl->mlen = smsz; sl->entry = l; return _AL_BSTR_OK; } /* int _al_bstrListAllocMin (struct _al_bstrList * sl, int msz) * * Try to allocate the minimum amount of memory for the list to include at * least msz entries or sl->qty whichever is greater. */ int _al_bstrListAllocMin (struct _al_bstrList * sl, int msz) { _al_bstring * l; size_t nsz; if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return _AL_BSTR_ERR; if (msz < sl->qty) msz = sl->qty; if (sl->mlen == msz) return _AL_BSTR_OK; nsz = ((size_t) msz) * sizeof (_al_bstring); if (nsz < (size_t) msz) return _AL_BSTR_ERR; l = (_al_bstring *) bstr__realloc (sl->entry, nsz); if (!l) return _AL_BSTR_ERR; sl->mlen = msz; sl->entry = l; return _AL_BSTR_OK; } /* int _al_bsplitcb (_al_const_bstring str, unsigned char splitChar, int pos, * int (* cb) (void * parm, int ofs, int len), void * parm) * * Iterate the set of disjoint sequential substrings over str divided by the * character in splitChar. * * Note: Non-destructive modification of str from within the cb function * while performing this split is not undefined. _al_bsplitcb behaves in * sequential lock step with calls to cb. I.e., after returning from a cb * that return a non-negative integer, _al_bsplitcb continues from the position * 1 character after the last detected split character and it will halt * immediately if the length of str falls below this point. However, if the * cb function destroys str, then it *must* return with a negative value, * otherwise _al_bsplitcb will continue in an undefined manner. */ int _al_bsplitcb (_al_const_bstring str, unsigned char splitChar, int pos, int (* cb) (void * parm, int ofs, int len), void * parm) { int i, p, ret; if (cb == NULL || str == NULL || pos < 0 || pos > str->slen) return _AL_BSTR_ERR; p = pos; do { for (i=p; i < str->slen; i++) { if (str->data[i] == splitChar) break; } if ((ret = cb (parm, p, i - p)) < 0) return ret; p = i + 1; } while (p <= str->slen); return _AL_BSTR_OK; } /* int _al_bsplitscb (_al_const_bstring str, _al_const_bstring splitStr, int pos, * int (* cb) (void * parm, int ofs, int len), void * parm) * * Iterate the set of disjoint sequential substrings over str divided by any * of the characters in splitStr. An empty splitStr causes the whole str to * be iterated once. * * Note: Non-destructive modification of str from within the cb function * while performing this split is not undefined. _al_bsplitscb behaves in * sequential lock step with calls to cb. I.e., after returning from a cb * that return a non-negative integer, _al_bsplitscb continues from the position * 1 character after the last detected split character and it will halt * immediately if the length of str falls below this point. However, if the * cb function destroys str, then it *must* return with a negative value, * otherwise _al_bsplitscb will continue in an undefined manner. */ int _al_bsplitscb (_al_const_bstring str, _al_const_bstring splitStr, int pos, int (* cb) (void * parm, int ofs, int len), void * parm) { struct charField chrs; int i, p, ret; if (cb == NULL || str == NULL || pos < 0 || pos > str->slen || splitStr == NULL || splitStr->slen < 0) return _AL_BSTR_ERR; if (splitStr->slen == 0) { if ((ret = cb (parm, 0, str->slen)) > 0) ret = 0; return ret; } if (splitStr->slen == 1) return _al_bsplitcb (str, splitStr->data[0], pos, cb, parm); buildCharField (&chrs, splitStr); p = pos; do { for (i=p; i < str->slen; i++) { if (testInCharField (&chrs, str->data[i])) break; } if ((ret = cb (parm, p, i - p)) < 0) return ret; p = i + 1; } while (p <= str->slen); return _AL_BSTR_OK; } /* int _al_bsplitstrcb (_al_const_bstring str, _al_const_bstring splitStr, int pos, * int (* cb) (void * parm, int ofs, int len), void * parm) * * Iterate the set of disjoint sequential substrings over str divided by the * substring splitStr. An empty splitStr causes the whole str to be * iterated once. * * Note: Non-destructive modification of str from within the cb function * while performing this split is not undefined. _al_bsplitstrcb behaves in * sequential lock step with calls to cb. I.e., after returning from a cb * that return a non-negative integer, _al_bsplitscb continues from the position * 1 character after the last detected split character and it will halt * immediately if the length of str falls below this point. However, if the * cb function destroys str, then it *must* return with a negative value, * otherwise _al_bsplitscb will continue in an undefined manner. */ int _al_bsplitstrcb (_al_const_bstring str, _al_const_bstring splitStr, int pos, int (* cb) (void * parm, int ofs, int len), void * parm) { int i, p, ret; if (cb == NULL || str == NULL || pos < 0 || pos > str->slen || splitStr == NULL || splitStr->slen < 0) return _AL_BSTR_ERR; if (0 == splitStr->slen) { for (i=pos; i < str->slen; i++) { if ((ret = cb (parm, i, 1)) < 0) return ret; } return _AL_BSTR_OK; } if (splitStr->slen == 1) return _al_bsplitcb (str, splitStr->data[0], pos, cb, parm); for (i=p=pos; i <= str->slen - splitStr->slen; i++) { if (0 == bstr__memcmp (splitStr->data, str->data + i, splitStr->slen)) { if ((ret = cb (parm, p, i - p)) < 0) return ret; i += splitStr->slen; p = i; } } if ((ret = cb (parm, p, str->slen - p)) < 0) return ret; return _AL_BSTR_OK; } struct genBstrList { _al_bstring b; struct _al_bstrList * bl; }; static int bscb (void * parm, int ofs, int len) { struct genBstrList * g = (struct genBstrList *) parm; if (g->bl->qty >= g->bl->mlen) { int mlen = g->bl->mlen * 2; _al_bstring * tbl; while (g->bl->qty >= mlen) { if (mlen < g->bl->mlen) return _AL_BSTR_ERR; mlen += mlen; } tbl = (_al_bstring *) bstr__realloc (g->bl->entry, sizeof (_al_bstring) * mlen); if (tbl == NULL) return _AL_BSTR_ERR; g->bl->entry = tbl; g->bl->mlen = mlen; } g->bl->entry[g->bl->qty] = _al_bmidstr (g->b, ofs, len); g->bl->qty++; return _AL_BSTR_OK; } /* struct _al_bstrList * _al_bsplit (_al_const_bstring str, unsigned char splitChar) * * Create an array of sequential substrings from str divided by the character * splitChar. */ struct _al_bstrList * _al_bsplit (_al_const_bstring str, unsigned char splitChar) { struct genBstrList g; if (str == NULL || str->data == NULL || str->slen < 0) return NULL; g.bl = (struct _al_bstrList *) bstr__alloc (sizeof (struct _al_bstrList)); if (g.bl == NULL) return NULL; g.bl->mlen = 4; g.bl->entry = (_al_bstring *) bstr__alloc (g.bl->mlen * sizeof (_al_bstring)); if (NULL == g.bl->entry) { bstr__free (g.bl); return NULL; } g.b = (_al_bstring) str; g.bl->qty = 0; if (_al_bsplitcb (str, splitChar, 0, bscb, &g) < 0) { _al_bstrListDestroy (g.bl); return NULL; } return g.bl; } /* struct _al_bstrList * _al_bsplitstr (_al_const_bstring str, _al_const_bstring splitStr) * * Create an array of sequential substrings from str divided by the entire * substring splitStr. */ struct _al_bstrList * _al_bsplitstr (_al_const_bstring str, _al_const_bstring splitStr) { struct genBstrList g; if (str == NULL || str->data == NULL || str->slen < 0) return NULL; g.bl = (struct _al_bstrList *) bstr__alloc (sizeof (struct _al_bstrList)); if (g.bl == NULL) return NULL; g.bl->mlen = 4; g.bl->entry = (_al_bstring *) bstr__alloc (g.bl->mlen * sizeof (_al_bstring)); if (NULL == g.bl->entry) { bstr__free (g.bl); return NULL; } g.b = (_al_bstring) str; g.bl->qty = 0; if (_al_bsplitstrcb (str, splitStr, 0, bscb, &g) < 0) { _al_bstrListDestroy (g.bl); return NULL; } return g.bl; } /* struct _al_bstrList * _al_bsplits (_al_const_bstring str, _al_bstring splitStr) * * Create an array of sequential substrings from str divided by any of the * characters in splitStr. An empty splitStr causes a single entry _al_bstrList * containing a copy of str to be returned. */ struct _al_bstrList * _al_bsplits (_al_const_bstring str, _al_const_bstring splitStr) { struct genBstrList g; if ( str == NULL || str->slen < 0 || str->data == NULL || splitStr == NULL || splitStr->slen < 0 || splitStr->data == NULL) return NULL; g.bl = (struct _al_bstrList *) bstr__alloc (sizeof (struct _al_bstrList)); if (g.bl == NULL) return NULL; g.bl->mlen = 4; g.bl->entry = (_al_bstring *) bstr__alloc (g.bl->mlen * sizeof (_al_bstring)); if (NULL == g.bl->entry) { bstr__free (g.bl); return NULL; } g.b = (_al_bstring) str; g.bl->qty = 0; if (_al_bsplitscb (str, splitStr, 0, bscb, &g) < 0) { _al_bstrListDestroy (g.bl); return NULL; } return g.bl; } #if defined (__TURBOC__) && !defined (__BORLANDC__) # ifndef BSTRLIB_NOVSNP # define BSTRLIB_NOVSNP # endif #endif /* Give WATCOM C/C++, MSVC some latitude for their non-support of vsnprintf */ #if defined(__WATCOMC__) || defined(_MSC_VER) #define exvsnprintf(r,b,n,f,a) {r = _vsnprintf (b,n,f,a);} #else #ifdef BSTRLIB_NOVSNP /* This is just a hack. If you are using a system without a vsnprintf, it is not recommended that _al_bformat be used at all. */ #define exvsnprintf(r,b,n,f,a) {vsprintf (b,f,a); r = -1;} #define START_VSNBUFF (256) #else #ifdef __GNUC__ /* Something is making gcc complain about this prototype not being here, so I've just gone ahead and put it in. */ /* Commented out in Allegro source because vsnprintf seems to be defined as a * macro that calls compiler builtins sometimes, e.g. Mac OS X 10.6. */ /* extern int vsnprintf (char *buf, size_t count, const char *format, va_list arg); */ #endif #define exvsnprintf(r,b,n,f,a) {r = vsnprintf (b,n,f,a);} #endif #endif #if !defined (BSTRLIB_NOVSNP) #ifndef START_VSNBUFF #define START_VSNBUFF (16) #endif /* On IRIX vsnprintf returns n-1 when the operation would overflow the target buffer, WATCOM and MSVC both return -1, while C99 requires that the returned value be exactly what the length would be if the buffer would be large enough. This leads to the idea that if the return value is larger than n, then changing n to the return value will reduce the number of iterations required. */ /* int _al_bformata (_al_bstring b, const char * fmt, ...) * * After the first parameter, it takes the same parameters as printf (), but * rather than outputting results to stdio, it appends the results to * a _al_bstring which contains what would have been output. Note that if there * is an early generation of a '\0' character, the _al_bstring will be truncated * to this end point. */ int _al_bformata (_al_bstring b, const char * fmt, ...) { va_list arglist; _al_bstring buff; int n, r; if (b == NULL || fmt == NULL || b->data == NULL || b->mlen <= 0 || b->slen < 0 || b->slen > b->mlen) return _AL_BSTR_ERR; /* Since the length is not determinable beforehand, a search is performed using the truncating "vsnprintf" call (to avoid buffer overflows) on increasing potential sizes for the output result. */ if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF; if (NULL == (buff = _al_bfromcstralloc (n + 2, ""))) { n = 1; if (NULL == (buff = _al_bfromcstralloc (n + 2, ""))) return _AL_BSTR_ERR; } for (;;) { va_start (arglist, fmt); exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist); va_end (arglist); buff->data[n] = (unsigned char) '\0'; buff->slen = (int) (strlen) ((char *) buff->data); if (buff->slen < n) break; if (r > n) n = r; else n += n; if (_AL_BSTR_OK != _al_balloc (buff, n + 2)) { _al_bdestroy (buff); return _AL_BSTR_ERR; } } r = _al_bconcat (b, buff); _al_bdestroy (buff); return r; } /* int _al_bassignformat (_al_bstring b, const char * fmt, ...) * * After the first parameter, it takes the same parameters as printf (), but * rather than outputting results to stdio, it outputs the results to * the _al_bstring parameter b. Note that if there is an early generation of a * '\0' character, the _al_bstring will be truncated to this end point. */ int _al_bassignformat (_al_bstring b, const char * fmt, ...) { va_list arglist; _al_bstring buff; int n, r; if (b == NULL || fmt == NULL || b->data == NULL || b->mlen <= 0 || b->slen < 0 || b->slen > b->mlen) return _AL_BSTR_ERR; /* Since the length is not determinable beforehand, a search is performed using the truncating "vsnprintf" call (to avoid buffer overflows) on increasing potential sizes for the output result. */ if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF; if (NULL == (buff = _al_bfromcstralloc (n + 2, ""))) { n = 1; if (NULL == (buff = _al_bfromcstralloc (n + 2, ""))) return _AL_BSTR_ERR; } for (;;) { va_start (arglist, fmt); exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist); va_end (arglist); buff->data[n] = (unsigned char) '\0'; buff->slen = (int) (strlen) ((char *) buff->data); if (buff->slen < n) break; if (r > n) n = r; else n += n; if (_AL_BSTR_OK != _al_balloc (buff, n + 2)) { _al_bdestroy (buff); return _AL_BSTR_ERR; } } r = _al_bassign (b, buff); _al_bdestroy (buff); return r; } /* _al_bstring _al_bformat (const char * fmt, ...) * * Takes the same parameters as printf (), but rather than outputting results * to stdio, it forms a _al_bstring which contains what would have been output. * Note that if there is an early generation of a '\0' character, the * _al_bstring will be truncated to this end point. */ _al_bstring _al_bformat (const char * fmt, ...) { va_list arglist; _al_bstring buff; int n, r; if (fmt == NULL) return NULL; /* Since the length is not determinable beforehand, a search is performed using the truncating "vsnprintf" call (to avoid buffer overflows) on increasing potential sizes for the output result. */ if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF; if (NULL == (buff = _al_bfromcstralloc (n + 2, ""))) { n = 1; if (NULL == (buff = _al_bfromcstralloc (n + 2, ""))) return NULL; } for (;;) { va_start (arglist, fmt); exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist); va_end (arglist); buff->data[n] = (unsigned char) '\0'; buff->slen = (int) (strlen) ((char *) buff->data); if (buff->slen < n) break; if (r > n) n = r; else n += n; if (_AL_BSTR_OK != _al_balloc (buff, n + 2)) { _al_bdestroy (buff); return NULL; } } return buff; } /* int _al_bvcformata (_al_bstring b, int count, const char * fmt, va_list arglist) * * The _al_bvcformata function formats data under control of the format control * string fmt and attempts to append the result to b. The fmt parameter is * the same as that of the printf function. The variable argument list is * replaced with arglist, which has been initialized by the va_start macro. * The size of the output is upper bounded by count. If the required output * exceeds count, the string b is not augmented with any contents and a value * below _AL_BSTR_ERR is returned. If a value below -count is returned then it * is recommended that the negative of this value be used as an update to the * count in a subsequent pass. On other errors, such as running out of * memory, parameter errors or numeric wrap around _AL_BSTR_ERR is returned. * _AL_BSTR_OK is returned when the output is successfully generated and * appended to b. * * Note: There is no sanity checking of arglist, and this function is * destructive of the contents of b from the b->slen point onward. If there * is an early generation of a '\0' character, the _al_bstring will be truncated * to this end point. */ int _al_bvcformata (_al_bstring b, int count, const char * fmt, va_list arg) { int n, r, l; if (b == NULL || fmt == NULL || count <= 0 || b->data == NULL || b->mlen <= 0 || b->slen < 0 || b->slen > b->mlen) return _AL_BSTR_ERR; if (count > (n = b->slen + count) + 2) return _AL_BSTR_ERR; if (_AL_BSTR_OK != _al_balloc (b, n + 2)) return _AL_BSTR_ERR; exvsnprintf (r, (char *) b->data + b->slen, count + 2, fmt, arg); /* Did the operation complete successfully within bounds? */ if (n >= (l = b->slen + (int) (strlen) ((const char *) b->data + b->slen))) { b->slen = l; return _AL_BSTR_OK; } /* Abort, since the buffer was not large enough. The return value tries to help set what the retry length should be. */ b->data[b->slen] = '\0'; if (r > count+1) l = r; else { l = count+count; if (count > l) l = INT_MAX; } n = -l; if (n > _AL_BSTR_ERR-1) n = _AL_BSTR_ERR-1; return n; } #endif allegro5-5.2.10.1/src/misc/bstrlib.txt000066400000000000000000004553601473414355200174210ustar00rootroot00000000000000Better String library --------------------- by Paul Hsieh The bstring library is an attempt to provide improved string processing functionality to the C and C++ language. At the heart of the bstring library (Bstrlib for short) is the management of "bstring"s which are a significant improvement over '\0' terminated char buffers. =============================================================================== Motivation ---------- The standard C string library has serious problems: 1) Its use of '\0' to denote the end of the string means knowing a string's length is O(n) when it could be O(1). 2) It imposes an interpretation for the character value '\0'. 3) gets() always exposes the application to a buffer overflow. 4) strtok() modifies the string its parsing and thus may not be usable in programs which are re-entrant or multithreaded. 5) fgets has the unusual semantic of ignoring '\0's that occur before '\n's are consumed. 6) There is no memory management, and actions performed such as strcpy, strcat and sprintf are common places for buffer overflows. 7) strncpy() doesn't '\0' terminate the destination in some cases. 8) Passing NULL to C library string functions causes an undefined NULL pointer access. 9) Parameter aliasing (overlapping, or self-referencing parameters) within most C library functions has undefined behavior. 10) Many C library string function calls take integer parameters with restricted legal ranges. Parameters passed outside these ranges are not typically detected and cause undefined behavior. So the desire is to create an alternative string library that does not suffer from the above problems and adds in the following functionality: 1) Incorporate string functionality seen from other languages. a) MID$() - from BASIC b) split()/join() - from Python c) string/char x n - from Perl 2) Implement analogs to functions that combine stream IO and char buffers without creating a dependency on stream IO functionality. 3) Implement the basic text editor-style functions insert, delete, find, and replace. 4) Implement reference based sub-string access (as a generalization of pointer arithmetic.) 5) Implement runtime write protection for strings. There is also a desire to avoid "API-bloat". So functionality that can be implemented trivially in other functionality is omitted. So there is no left$() or right$() or reverse() or anything like that as part of the core functionality. Explaining Bstrings ------------------- A bstring is basically a header which wraps a pointer to a char buffer. Lets start with the declaration of a struct tagbstring: struct tagbstring { int mlen; int slen; unsigned char * data; }; This definition is considered exposed, not opaque (though it is neither necessary nor recommended that low level maintenance of bstrings be performed whenever the abstract interfaces are sufficient). The mlen field (usually) describes a lower bound for the memory allocated for the data field. The slen field describes the exact length for the bstring. The data field is a single contiguous buffer of unsigned chars. Note that the existence of a '\0' character in the unsigned char buffer pointed to by the data field does not necessarily denote the end of the bstring. To be a well formed modifiable bstring the mlen field must be at least the length of the slen field, and slen must be non-negative. Furthermore, the data field must point to a valid buffer in which access to the first mlen characters has been acquired. So the minimal check for correctness is: (slen >= 0 && mlen >= slen && data != NULL) bstrings returned by bstring functions can be assumed to be either NULL or satisfy the above property. (When bstrings are only readable, the mlen >= slen restriction is not required; this is discussed later in this section.) A bstring itself is just a pointer to a struct tagbstring: typedef struct tagbstring * bstring; Note that use of the prefix "tag" in struct tagbstring is required to work around the inconsistency between C and C++'s struct namespace usage. This definition is also considered exposed. Bstrlib basically manages bstrings allocated as a header and an associated data-buffer. Since the implementation is exposed, they can also be constructed manually. Functions which mutate bstrings assume that the header and data buffer have been malloced; the bstring library may perform al_free() or al_realloc() on both the header and data buffer of any bstring parameter. Functions which return bstring's create new bstrings. The string memory is freed by a bdestroy() call (or using the bstrFree macro). The following related typedef is also provided: typedef const struct tagbstring * const_bstring; which is also considered exposed. These are directly bstring compatible (no casting required) but are just used for parameters which are meant to be non-mutable. So in general, bstring parameters which are read as input but not meant to be modified will be declared as const_bstring, and bstring parameters which may be modified will be declared as bstring. This convention is recommended for user written functions as well. Since bstrings maintain interoperability with C library char-buffer style strings, all functions which modify, update or create bstrings also append a '\0' character into the position slen + 1. This trailing '\0' character is not required for bstrings input to the bstring functions; this is provided solely as a convenience for interoperability with standard C char-buffer functionality. Analogs for the ANSI C string library functions have been created when they are necessary, but have also been left out when they are not. In particular there are no functions analogous to fwrite, or puts just for the purposes of bstring. The ->data member of any string is exposed, and therefore can be used just as easily as char buffers for C functions which read strings. For those that wish to hand construct bstrings, the following should be kept in mind: 1) While bstrlib can accept constructed bstrings without terminating '\0' characters, the rest of the C language string library will not function properly on such non-terminated strings. This is obvious but must be kept in mind. 2) If it is intended that a constructed bstring be written to by the bstring library functions then the data portion should be allocated by the malloc function and the slen and mlen fields should be entered properly. The struct tagbstring header is not reallocated, and only freed by bdestroy. 3) Writing arbitrary '\0' characters at various places in the string will not modify its length as perceived by the bstring library functions. In fact, '\0' is a legitimate non-terminating character for a bstring to contain. 4) For read only parameters, bstring functions do not check the mlen. I.e., the minimal correctness requirements are reduced to: (slen >= 0 && data != NULL) Better pointer arithmetic ------------------------- One built-in feature of '\0' terminated char * strings, is that its very easy and fast to obtain a reference to the tail of any string using pointer arithmetic. Bstrlib does one better by providing a way to get a reference to any substring of a bstring (or any other length delimited block of memory.) So rather than just having pointer arithmetic, with bstrlib one essentially has segment arithmetic. This is achieved using the macro blk2tbstr() which builds a reference to a block of memory and the macro bmid2tbstr() which builds a reference to a segment of a bstring. Bstrlib also includes functions for direct consumption of memory blocks into bstrings, namely bcatblk () and blk2bstr (). One scenario where this can be extremely useful is when string contains many substrings which one would like to pass as read-only reference parameters to some string consuming function without the need to allocate entire new containers for the string data. More concretely, imagine parsing a command line string whose parameters are space delimited. This can only be done for tails of the string with '\0' terminated char * strings. Improved NULL semantics and error handling ------------------------------------------ Unless otherwise noted, if a NULL pointer is passed as a bstring or any other detectably illegal parameter, the called function will return with an error indicator (either NULL or BSTR_ERR) rather than simply performing a NULL pointer access, or having undefined behavior. To illustrate the value of this, consider the following example: strcpy (p = malloc (13 * sizeof (char)), "Hello,"); strcat (p, " World"); This is not correct because malloc may return NULL (due to an out of memory condition), and the behaviour of strcpy is undefined if either of its parameters are NULL. However: bstrcat (p = bfromcstr ("Hello,"), q = bfromcstr (" World")); bdestroy (q); is well defined, because if either p or q are assigned NULL (indicating a failure to allocate memory) both bstrcat and bdestroy will recognize it and perform no detrimental action. Note that it is not necessary to check any of the members of a returned bstring for internal correctness (in particular the data member does not need to be checked against NULL when the header is non-NULL), since this is assured by the bstring library itself. bStreams -------- In addition to the bgets and bread functions, bstrlib can abstract streams with a high performance read only stream called a bStream. In general, the idea is to open a core stream (with something like fopen) then pass its handle as well as a bNread function pointer (like fread) to the bsopen function which will return a handle to an open bStream. Then the functions bsread, bsreadln or bsreadlns can be called to read portions of the stream. Finally, the bsclose function is called to close the bStream -- it will return a handle to the original (core) stream. So bStreams, essentially, wrap other streams. The bStreams have two main advantages over the bgets and bread (as well as fgets/ungetc) paradigms: 1) Improved functionality via the bunread function which allows a stream to unread characters, giving the bStream stack-like functionality if so desired. 2) A very high performance bsreadln function. The C library function fgets() (and the bgets function) can typically be written as a loop on top of fgetc(), thus paying all of the overhead costs of calling fgetc on a per character basis. bsreadln will read blocks at a time, thus amortizing the overhead of fread calls over many characters at once. However, clearly bStreams are suboptimal or unusable for certain kinds of streams (stdin) or certain usage patterns (a few spotty, or non-sequential reads from a slow stream.) For those situations, using bgets will be more appropriate. The semantics of bStreams allows practical construction of layerable data streams. What this means is that by writing a bNread compatible function on top of a bStream, one can construct a new bStream on top of it. This can be useful for writing multi-pass parsers that don't actually read the entire input more than once and don't require the use of intermediate storage. Aliasing -------- Aliasing occurs when a function is given two parameters which point to data structures which overlap in the memory they occupy. While this does not disturb read only functions, for many libraries this can make functions that write to these memory locations malfunction. This is a common problem of the C standard library and especially the string functions in the C standard library. The C standard string library is entirely char by char oriented (as is bstring) which makes conforming implementations alias safe for some scenarios. However no actual detection of aliasing is typically performed, so it is easy to find cases where the aliasing will cause anomolous or undesirable behaviour (consider: strcat (p, p).) The C99 standard includes the "restrict" pointer modifier which allows the compiler to document and assume a no-alias condition on usage. However, only the most trivial cases can be caught (if at all) by the compiler at compile time, and thus there is no actual enforcement of non-aliasing. Bstrlib, by contrast, permits aliasing and is completely aliasing safe, in the C99 sense of aliasing. That is to say, under the assumption that pointers of incompatible types from distinct objects can never alias, bstrlib is completely aliasing safe. (In practice this means that the data buffer portion of any bstring and header of any bstring are assumed to never alias.) With the exception of the reference building macros, the library behaves as if all read-only parameters are first copied and replaced by temporary non-aliased parameters before any writing to any output bstring is performed (though actual copying is extremely rarely ever done.) Besides being a useful safety feature, bstring searching/comparison functions can improve to O(1) execution when aliasing is detected. Note that aliasing detection and handling code in Bstrlib is generally extremely cheap. There is almost never any appreciable performance penalty for using aliased parameters. Reenterancy ----------- Nearly every function in Bstrlib is a leaf function, and is completely reenterable with the exception of writing to common bstrings. The split functions which use a callback mechanism requires only that the source string not be destroyed by the callback function unless the callback function returns with an error status (note that Bstrlib functions which return an error do not modify the string in any way.) The string can in fact be modified by the callback and the behaviour is deterministic. See the documentation of the various split functions for more details. Undefined scenarios ------------------- One of the basic important premises for Bstrlib is to not to increase the propogation of undefined situations from parameters that are otherwise legal in of themselves. In particular, except for extremely marginal cases, usages of bstrings that use the bstring library functions alone cannot lead to any undefined action. But due to C/C++ language and library limitations, there is no way to define a non-trivial library that is completely without undefined operations. All such possible undefined operations are described below: 1) bstrings or struct tagbstrings that are not explicitely initialized cannot be passed as a parameter to any bstring function. 2) The members of the NULL bstring cannot be accessed directly. (Though all APIs and macros detect the NULL bstring.) 3) A bstring whose data member has not been obtained from a malloc or compatible call and which is write accessible passed as a writable parameter will lead to undefined results. (i.e., do not writeAllow any constructed bstrings unless the data portion has been obtained from the heap.) 4) If the headers of two strings alias but are not identical (which can only happen via a defective manual construction), then passing them to a bstring function in which one is writable is not defined. 5) If the mlen member is larger than the actual accessible length of the data member for a writable bstring, or if the slen member is larger than the readable length of the data member for a readable bstring, then the corresponding bstring operations are undefined. 6) Any bstring definition whose header or accessible data portion has been assigned to inaccessible or otherwise illegal memory clearly cannot be acted upon by the bstring library in any way. 7) Destroying the source of an incremental split from within the callback and not returning with a negative value (indicating that it should abort) will lead to undefined behaviour. (Though *modifying* or adjusting the state of the source data, even if those modification fail within the bstrlib API, has well defined behavior.) 8) Modifying a bstring which is write protected by direct access has undefined behavior. While this may seem like a long list, with the exception of invalid uses of the writeAllow macro, and source destruction during an iterative split without an accompanying abort, no usage of the bstring API alone can cause any undefined scenario to occurr. I.e., the policy of restricting usage of bstrings to the bstring API can significantly reduce the risk of runtime errors (in practice it should eliminate them) related to string manipulation due to undefined action. C++ wrapper ----------- A C++ wrapper has been created to enable bstring functionality for C++ in the most natural (for C++ programers) way possible. The mandate for the C++ wrapper is different from the base C bstring library. Since the C++ language has far more abstracting capabilities, the CBString structure is considered fully abstracted -- i.e., hand generated CBStrings are not supported (though conversion from a struct tagbstring is allowed) and all detectable errors are manifest as thrown exceptions. - The C++ class definitions are all under the namespace Bstrlib. bstrwrap.h enables this namespace (with a using namespace Bstrlib; directive at the end) unless the macro BSTRLIB_DONT_ASSUME_NAMESPACE has been defined before it is included. - Erroneous accesses results in an exception being thrown. The exception parameter is of type "struct CBStringException" which is derived from std::exception if STL is used. A verbose description of the error message can be obtained from the what() method. - CBString is a C++ structure derived from a struct tagbstring. An address of a CBString cast to a bstring must not be passed to bdestroy. The bstring C API has been made C++ safe and can be used directly in a C++ project. - It includes constructors which can take a char, '\0' terminated char buffer, tagbstring, (char, repeat-value), a length delimited buffer or a CBStringList to initialize it. - Concatenation is performed with the + and += operators. Comparisons are done with the ==, !=, <, >, <= and >= operators. Note that == and != use the biseq call, while <, >, <= and >= use bstrcmp. - CBString's can be directly cast to const character buffers. - CBString's can be directly cast to double, float, int or unsigned int so long as the CBString are decimal representations of those types (otherwise an exception will be thrown). Converting the other way should be done with the format(a) method(s). - CBString contains the length, character and [] accessor methods. The character and [] accessors are aliases of each other. If the bounds for the string are exceeded, an exception is thrown. To avoid the overhead for this check, first cast the CBString to a (const char *) and use [] to dereference the array as normal. Note that the character and [] accessor methods allows both reading and writing of individual characters. - The methods: format, formata, find, reversefind, findcaseless, reversefindcaseless, midstr, insert, insertchrs, replace, findreplace, findreplacecaseless, remove, findchr, nfindchr, alloc, toupper, tolower, gets, read are analogous to the functions that can be found in the C API. - The caselessEqual and caselessCmp methods are analogous to biseqcaseless and bstricmp functions respectively. - Note that just like the bformat function, the format and formata methods do not automatically cast CBStrings into char * strings for "%s"-type substitutions: CBString w("world"); CBString h("Hello"); CBString hw; /* The casts are necessary */ hw.format ("%s, %s", (const char *)h, (const char *)w); - The methods trunc and repeat have been added instead of using pattern. - ltrim, rtrim and trim methods have been added. These remove characters from a given character string set (defaulting to the whitespace characters) from either the left, right or both ends of the CBString, respectively. - The method setsubstr is also analogous in functionality to bsetstr, except that it cannot be passed NULL. Instead the method fill and the fill-style constructor have been supplied to enable this functionality. - The writeprotect(), writeallow() and iswriteprotected() methods are analogous to the bwriteprotect(), bwriteallow() and biswriteprotected() macros in the C API. Write protection semantics in CBString are stronger than with the C API in that indexed character assignment is checked for write protection. However, unlike with the C API, a write protected CBString can be destroyed by the destructor. - CBStream is a C++ structure which wraps a struct bStream (its not derived from it, since destruction is slightly different). It is constructed by passing in a bNread function pointer and a stream parameter cast to void *. This structure includes methods for detecting eof, setting the buffer length, reading the whole stream or reading entries line by line or block by block, an unread function, and a peek function. - If STL is available, the CBStringList structure is derived from a vector of CBString with various split methods. The split method has been overloaded to accept either a character or CBString as the second parameter (when the split parameter is a CBString any character in that CBString is used as a seperator). The splitstr method takes a CBString as a substring seperator. Joins can be performed via a CBString constructor which takes a CBStringList as a parameter, or just using the CBString::join() method. - If there is proper support for std::iostreams, then the >> and << operators and the getline() function have been added (with semantics the same as those for std::string). Multithreading -------------- A mutable bstring is kind of analogous to a small (two entry) linked list allocated by malloc, with all aliasing completely under programmer control. I.e., manipulation of one bstring will never affect any other distinct bstring unless explicitely constructed to do so by the programmer via hand construction or via building a reference. Bstrlib also does not use any static or global storage, so there are no hidden unremovable race conditions. Bstrings are also clearly not inherently thread local. So just like char *'s, bstrings can be passed around from thread to thread and shared and so on, so long as modifications to a bstring correspond to some kind of exclusive access lock as should be expected (or if the bstring is read-only, which can be enforced by bstring write protection) for any sort of shared object in a multithreaded environment. Bsafe module ------------ For convenience, a bsafe module has been included. The idea is that if this module is included, inadvertant usage of the most dangerous C functions will be overridden and lead to an immediate run time abort. Of course, it should be emphasized that usage of this module is completely optional. The intention is essentially to provide an option for creating project safety rules which can be enforced mechanically rather than socially. This is useful for larger, or open development projects where its more difficult to enforce social rules or "coding conventions". Problems not solved ------------------- Bstrlib is written for the C and C++ languages, which have inherent weaknesses that cannot be easily solved: 1. Memory leaks: Forgetting to call bdestroy on a bstring that is about to be unreferenced, just as forgetting to call free on a heap buffer that is about to be dereferenced. Though bstrlib itself is leak free. 2. Read before write usage: In C, declaring an auto bstring does not automatically fill it with legal/valid contents. This problem has been somewhat mitigated in C++. (The bstrDeclare and bstrFree macros from bstraux can be used to help mitigate this problem.) Other problems not addressed: 3. Built-in mutex usage to automatically avoid all bstring internal race conditions in multitasking environments: The problem with trying to implement such things at this low a level is that it is typically more efficient to use locks in higher level primitives. There is also no platform independent way to implement locks or mutexes. 4. Unicode/widecharacter support. Note that except for spotty support of wide characters, the default C standard library does not address any of these problems either. Configurable compilation options -------------------------------- All configuration options are meant solely for the purpose of compiler compatibility. Configuration options are not meant to change the semantics or capabilities of the library, except where it is unavoidable. Since some C++ compilers don't include the Standard Template Library and some have the options of disabling exception handling, a number of macros can be used to conditionally compile support for each of this: BSTRLIB_CAN_USE_STL - defining this will enable the used of the Standard Template Library. Defining BSTRLIB_CAN_USE_STL overrides the BSTRLIB_CANNOT_USE_STL macro. BSTRLIB_CANNOT_USE_STL - defining this will disable the use of the Standard Template Library. Defining BSTRLIB_CAN_USE_STL overrides the BSTRLIB_CANNOT_USE_STL macro. BSTRLIB_CAN_USE_IOSTREAM - defining this will enable the used of streams from class std. Defining BSTRLIB_CAN_USE_IOSTREAM overrides the BSTRLIB_CANNOT_USE_IOSTREAM macro. BSTRLIB_CANNOT_USE_IOSTREAM - defining this will disable the use of streams from class std. Defining BSTRLIB_CAN_USE_IOSTREAM overrides the BSTRLIB_CANNOT_USE_IOSTREAM macro. BSTRLIB_THROWS_EXCEPTIONS - defining this will enable the exception handling within bstring. Defining BSTRLIB_THROWS_EXCEPTIONS overrides the BSTRLIB_DOESNT_THROWS_EXCEPTIONS macro. BSTRLIB_DOESNT_THROW_EXCEPTIONS - defining this will disable the exception handling within bstring. Defining BSTRLIB_THROWS_EXCEPTIONS overrides the BSTRLIB_DOESNT_THROW_EXCEPTIONS macro. Note that these macros must be defined consistently throughout all modules that use CBStrings including bstrwrap.cpp. Some older C compilers do not support functions such as vsnprintf. This is handled by the following macro variables: BSTRLIB_NOVSNP - defining this indicates that the compiler does not support vsnprintf. This will cause bformat and bformata to not be declared. Note that for some compilers, such as Turbo C, this is set automatically. Defining BSTRLIB_NOVSNP overrides the BSTRLIB_VSNP_OK macro. BSTRLIB_VSNP_OK - defining this will disable the autodetection of compilers the do not support of compilers that do not support vsnprintf. Defining BSTRLIB_NOVSNP overrides the BSTRLIB_VSNP_OK macro. Semantic compilation options ---------------------------- Bstrlib comes with very few compilation options for changing the semantics of of the library. These are described below. BSTRLIB_DONT_ASSUME_NAMESPACE - Defining this before including bstrwrap.h will disable the automatic enabling of the Bstrlib namespace for the C++ declarations. BSTRLIB_DONT_USE_VIRTUAL_DESTRUCTOR - Defining this will make the CBString destructor non-virtual. BSTRLIB_MEMORY_DEBUG - Defining this will cause the bstrlib modules bstrlib.c and bstrwrap.cpp to invoke a #include "memdbg.h". memdbg.h has to be supplied by the user. Note that these macros must be defined consistently throughout all modules that use bstrings or CBStrings including bstrlib.c, bstraux.c and bstrwrap.cpp. =============================================================================== Files ----- bstrlib.c - C implementaion of bstring functions. bstrlib.h - C header file for bstring functions. bstraux.c - C example that implements trivial additional functions. bstraux.h - C header for bstraux.c bstest.c - C unit/regression test for bstrlib.c bstrwrap.cpp - C++ implementation of CBString. bstrwrap.h - C++ header file for CBString. test.cpp - C++ unit/regression test for bstrwrap.cpp bsafe.c - C runtime stubs to abort usage of unsafe C functions. bsafe.h - C header file for bsafe.c functions. C projects need only include bstrlib.h and compile/link bstrlib.c to use the bstring library. C++ projects need to additionally include bstrwrap.h and compile/link bstrwrap.cpp. For both, there may be a need to make choices about feature configuration as described in the "Configurable compilation options" in the section above. Other files that are included in this archive are: license.txt - The BSD license for Bstrlib gpl.txt - The GPL version 2 security.txt - A security statement useful for auditting Bstrlib porting.txt - A guide to porting Bstrlib bstrlib.txt - This file =============================================================================== The functions ------------- extern bstring bfromcstr (const char * str); Take a standard C library style '\0' terminated char buffer and generate a bstring with the same contents as the char buffer. If an error occurs NULL is returned. So for example: bstring b = bfromcstr ("Hello"); if (!b) { fprintf (stderr, "Out of memory"); } else { puts ((char *) b->data); } .......................................................................... extern bstring bfromcstralloc (int mlen, const char * str); Create a bstring which contains the contents of the '\0' terminated char * buffer str. The memory buffer backing the bstring is at least mlen characters in length. If an error occurs NULL is returned. So for example: bstring b = bfromcstralloc (64, someCstr); if (b) b->data[63] = 'x'; The idea is that this will set the 64th character of b to 'x' if it is at least 64 characters long otherwise do nothing. And we know this is well defined so long as b was successfully created, since it will have been allocated with at least 64 characters. .......................................................................... extern bstring blk2bstr (const void * blk, int len); Create a bstring whose contents are described by the contiguous buffer pointing to by blk with a length of len bytes. Note that this function creates a copy of the data in blk, rather than simply referencing it. Compare with the blk2tbstr macro. If an error occurs NULL is returned. .......................................................................... extern char * bstr2cstr (const_bstring s, char z); Create a '\0' terminated char buffer which contains the contents of the bstring s, except that any contained '\0' characters are converted to the character in z. This returned value should be freed with bcstrfree(), by the caller. If an error occurs NULL is returned. .......................................................................... extern int bcstrfree (char * s); Frees a C-string generated by bstr2cstr (). This is normally unnecessary since it just wraps a call to free (), however, if malloc () and free () have been redefined as a macros within the bstrlib module (via macros in the memdbg.h backdoor) with some difference in behaviour from the std library functions, then this allows a correct way of freeing the memory that allows higher level code to be independent from these macro redefinitions. .......................................................................... extern bstring bstrcpy (const_bstring b1); Make a copy of the passed in bstring. The copied bstring is returned if there is no error, otherwise NULL is returned. .......................................................................... extern int bassign (bstring a, const_bstring b); Overwrite the bstring a with the contents of bstring b. Note that the bstring a must be a well defined and writable bstring. If an error occurs BSTR_ERR is returned and a is not overwritten. .......................................................................... int bassigncstr (bstring a, const char * str); Overwrite the string a with the contents of char * string str. Note that the bstring a must be a well defined and writable bstring. If an error occurs BSTR_ERR is returned and a may be partially overwritten. .......................................................................... int bassignblk (bstring a, const void * s, int len); Overwrite the string a with the contents of the block (s, len). Note that the bstring a must be a well defined and writable bstring. If an error occurs BSTR_ERR is returned and a is not overwritten. .......................................................................... extern int bassignmidstr (bstring a, const_bstring b, int left, int len); Overwrite the bstring a with the middle of contents of bstring b starting from position left and running for a length len. left and len are clamped to the ends of b as with the function bmidstr. Note that the bstring a must be a well defined and writable bstring. If an error occurs BSTR_ERR is returned and a is not overwritten. .......................................................................... extern bstring bmidstr (const_bstring b, int left, int len); Create a bstring which is the substring of b starting from position left and running for a length len (clamped by the end of the bstring b.) If there was no error, the value of this constructed bstring is returned otherwise NULL is returned. .......................................................................... extern int bdelete (bstring s1, int pos, int len); Removes characters from pos to pos+len-1 and shifts the tail of the bstring starting from pos+len to pos. len must be positive for this call to have any effect. The section of the bstring described by (pos, len) is clamped to boundaries of the bstring b. The value BSTR_OK is returned if the operation is successful, otherwise BSTR_ERR is returned. .......................................................................... extern int bconcat (bstring b0, const_bstring b1); Concatenate the bstring b1 to the end of bstring b0. The value BSTR_OK is returned if the operation is successful, otherwise BSTR_ERR is returned. .......................................................................... extern int bconchar (bstring b, char c); Concatenate the character c to the end of bstring b. The value BSTR_OK is returned if the operation is successful, otherwise BSTR_ERR is returned. .......................................................................... extern int bcatcstr (bstring b, const char * s); Concatenate the char * string s to the end of bstring b. The value BSTR_OK is returned if the operation is successful, otherwise BSTR_ERR is returned. .......................................................................... extern int bcatblk (bstring b, const void * s, int len); Concatenate a fixed length buffer (s, len) to the end of bstring b. The value BSTR_OK is returned if the operation is successful, otherwise BSTR_ERR is returned. .......................................................................... extern int biseq (const_bstring b0, const_bstring b1); Compare the bstring b0 and b1 for equality. If the bstrings differ, 0 is returned, if the bstrings are the same, 1 is returned, if there is an error, -1 is returned. If the length of the bstrings are different, this function has O(1) complexity. Contained '\0' characters are not treated as a termination character. Note that the semantics of biseq are not completely compatible with bstrcmp because of its different treatment of the '\0' character. .......................................................................... extern int bisstemeqblk (const_bstring b, const void * blk, int len); Compare beginning of bstring b0 with a block of memory of length len for equality. If the beginning of b0 differs from the memory block (or if b0 is too short), 0 is returned, if the bstrings are the same, 1 is returned, if there is an error, -1 is returned. .......................................................................... extern int biseqcaseless (const_bstring b0, const_bstring b1); Compare two bstrings for equality without differentiating between case. If the bstrings differ other than in case, 0 is returned, if the bstrings are the same, 1 is returned, if there is an error, -1 is returned. If the length of the bstrings are different, this function is O(1). '\0' termination characters are not treated in any special way. .......................................................................... extern int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len); Compare beginning of bstring b0 with a block of memory of length len without differentiating between case for equality. If the beginning of b0 differs from the memory block other than in case (or if b0 is too short), 0 is returned, if the bstrings are the same, 1 is returned, if there is an error, -1 is returned. .......................................................................... extern int biseqcstr (const_bstring b, const char *s); Compare the bstring b and char * bstring s. The C string s must be '\0' terminated at exactly the length of the bstring b, and the contents between the two must be identical with the bstring b with no '\0' characters for the two contents to be considered equal. This is equivalent to the condition that their current contents will be always be equal when comparing them in the same format after converting one or the other. If they are equal 1 is returned, if they are unequal 0 is returned and if there is a detectable error BSTR_ERR is returned. .......................................................................... extern int biseqcstrcaseless (const_bstring b, const char *s); Compare the bstring b and char * string s. The C string s must be '\0' terminated at exactly the length of the bstring b, and the contents between the two must be identical except for case with the bstring b with no '\0' characters for the two contents to be considered equal. This is equivalent to the condition that their current contents will be always be equal ignoring case when comparing them in the same format after converting one or the other. If they are equal, except for case, 1 is returned, if they are unequal regardless of case 0 is returned and if there is a detectable error BSTR_ERR is returned. .......................................................................... extern int bstrcmp (const_bstring b0, const_bstring b1); Compare the bstrings b0 and b1 for ordering. If there is an error, SHRT_MIN is returned, otherwise a value less than or greater than zero, indicating that the bstring pointed to by b0 is lexicographically less than or greater than the bstring pointed to by b1 is returned. If the bstring lengths are unequal but the characters up until the length of the shorter are equal then a value less than, or greater than zero, indicating that the bstring pointed to by b0 is shorter or longer than the bstring pointed to by b1 is returned. 0 is returned if and only if the two bstrings are the same. If the length of the bstrings are different, this function is O(n). Like its standard C library counter part, the comparison does not proceed past any '\0' termination characters encountered. The seemingly odd error return value, merely provides slightly more granularity than the undefined situation given in the C library function strcmp. The function otherwise behaves very much like strcmp(). Note that the semantics of bstrcmp are not completely compatible with biseq because of its different treatment of the '\0' termination character. .......................................................................... extern int bstrncmp (const_bstring b0, const_bstring b1, int n); Compare the bstrings b0 and b1 for ordering for at most n characters. If there is an error, SHRT_MIN is returned, otherwise a value is returned as if b0 and b1 were first truncated to at most n characters then bstrcmp was called with these new bstrings are paremeters. If the length of the bstrings are different, this function is O(n). Like its standard C library counter part, the comparison does not proceed past any '\0' termination characters encountered. The seemingly odd error return value, merely provides slightly more granularity than the undefined situation given in the C library function strncmp. The function otherwise behaves very much like strncmp(). .......................................................................... extern int bstricmp (const_bstring b0, const_bstring b1); Compare two bstrings without differentiating between case. The return value is the difference of the values of the characters where the two bstrings first differ, otherwise 0 is returned indicating that the bstrings are equal. If the lengths are different, then a difference from 0 is given, but if the first extra character is '\0', then it is taken to be the value UCHAR_MAX+1. .......................................................................... extern int bstrnicmp (const_bstring b0, const_bstring b1, int n); Compare two bstrings without differentiating between case for at most n characters. If the position where the two bstrings first differ is before the nth position, the return value is the difference of the values of the characters, otherwise 0 is returned. If the lengths are different and less than n characters, then a difference from 0 is given, but if the first extra character is '\0', then it is taken to be the value UCHAR_MAX+1. .......................................................................... extern int bdestroy (bstring b); Deallocate the bstring passed. Passing NULL in as a parameter will have no effect. Note that both the header and the data portion of the bstring will be freed. No other bstring function which modifies one of its parameters will free or reallocate the header. Because of this, in general, bdestroy cannot be called on any declared struct tagbstring even if it is not write protected. A bstring which is write protected cannot be destroyed via the bdestroy call. Any attempt to do so will result in no action taken, and BSTR_ERR will be returned. Note to C++ users: Passing in a CBString cast to a bstring will lead to undefined behavior (free will be called on the header, rather than the CBString destructor.) Instead just use the ordinary C++ language facilities to dealloc a CBString. .......................................................................... extern int binstr (const_bstring s1, int pos, const_bstring s2); Search for the bstring s2 in s1 starting at position pos and looking in a forward (increasing) direction. If it is found then it returns with the first position after pos where it is found, otherwise it returns BSTR_ERR. The algorithm used is brute force; O(m*n). .......................................................................... extern int binstrr (const_bstring s1, int pos, const_bstring s2); Search for the bstring s2 in s1 starting at position pos and looking in a backward (decreasing) direction. If it is found then it returns with the first position after pos where it is found, otherwise return BSTR_ERR. Note that the current position at pos is tested as well -- so to be disjoint from a previous forward search it is recommended that the position be backed up (decremented) by one position. The algorithm used is brute force; O(m*n). .......................................................................... extern int binstrcaseless (const_bstring s1, int pos, const_bstring s2); Search for the bstring s2 in s1 starting at position pos and looking in a forward (increasing) direction but without regard to case. If it is found then it returns with the first position after pos where it is found, otherwise it returns BSTR_ERR. The algorithm used is brute force; O(m*n). .......................................................................... extern int binstrrcaseless (const_bstring s1, int pos, const_bstring s2); Search for the bstring s2 in s1 starting at position pos and looking in a backward (decreasing) direction but without regard to case. If it is found then it returns with the first position after pos where it is found, otherwise return BSTR_ERR. Note that the current position at pos is tested as well -- so to be disjoint from a previous forward search it is recommended that the position be backed up (decremented) by one position. The algorithm used is brute force; O(m*n). .......................................................................... extern int binchr (const_bstring b0, int pos, const_bstring b1); Search for the first position in b0 starting from pos or after, in which one of the characters in b1 is found. This function has an execution time of O(b0->slen + b1->slen). If such a position does not exist in b0, then BSTR_ERR is returned. .......................................................................... extern int binchrr (const_bstring b0, int pos, const_bstring b1); Search for the last position in b0 no greater than pos, in which one of the characters in b1 is found. This function has an execution time of O(b0->slen + b1->slen). If such a position does not exist in b0, then BSTR_ERR is returned. .......................................................................... extern int bninchr (const_bstring b0, int pos, const_bstring b1); Search for the first position in b0 starting from pos or after, in which none of the characters in b1 is found and return it. This function has an execution time of O(b0->slen + b1->slen). If such a position does not exist in b0, then BSTR_ERR is returned. .......................................................................... extern int bninchrr (const_bstring b0, int pos, const_bstring b1); Search for the last position in b0 no greater than pos, in which none of the characters in b1 is found and return it. This function has an execution time of O(b0->slen + b1->slen). If such a position does not exist in b0, then BSTR_ERR is returned. .......................................................................... extern int bstrchr (const_bstring b, int c); Search for the character c in the bstring b forwards from the start of the bstring. Returns the position of the found character or BSTR_ERR if it is not found. NOTE: This has been implemented as a macro on top of bstrchrp (). .......................................................................... extern int bstrrchr (const_bstring b, int c); Search for the character c in the bstring b backwards from the end of the bstring. Returns the position of the found character or BSTR_ERR if it is not found. NOTE: This has been implemented as a macro on top of bstrrchrp (). .......................................................................... extern int bstrchrp (const_bstring b, int c, int pos); Search for the character c in b forwards from the position pos (inclusive). Returns the position of the found character or BSTR_ERR if it is not found. .......................................................................... extern int bstrrchrp (const_bstring b, int c, int pos); Search for the character c in b backwards from the position pos in bstring (inclusive). Returns the position of the found character or BSTR_ERR if it is not found. .......................................................................... extern int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill); Overwrite the bstring b0 starting at position pos with the bstring b1. If the position pos is past the end of b0, then the character "fill" is appended as necessary to make up the gap between the end of b0 and pos. If b1 is NULL, it behaves as if it were a 0-length bstring. The value BSTR_OK is returned if the operation is successful, otherwise BSTR_ERR is returned. .......................................................................... extern int binsert (bstring s1, int pos, const_bstring s2, unsigned char fill); Inserts the bstring s2 into s1 at position pos. If the position pos is past the end of s1, then the character "fill" is appended as necessary to make up the gap between the end of s1 and pos. The value BSTR_OK is returned if the operation is successful, otherwise BSTR_ERR is returned. .......................................................................... extern int binsertch (bstring s1, int pos, int len, unsigned char fill); Inserts the character fill repeatedly into s1 at position pos for a length len. If the position pos is past the end of s1, then the character "fill" is appended as necessary to make up the gap between the end of s1 and the position pos + len (exclusive). The value BSTR_OK is returned if the operation is successful, otherwise BSTR_ERR is returned. .......................................................................... extern int breplace (bstring b1, int pos, int len, const_bstring b2, unsigned char fill); Replace a section of a bstring from pos for a length len with the bstring b2. If the position pos is past the end of b1 then the character "fill" is appended as necessary to make up the gap between the end of b1 and pos. .......................................................................... extern int bfindreplace (bstring b, const_bstring find, const_bstring replace, int position); Replace all occurrences of the find substring with a replace bstring after a given position in the bstring b. The find bstring must have a length > 0 otherwise BSTR_ERR is returned. This function does not perform recursive per character replacement; that is to say successive searches resume at the position after the last replace. So for example: bfindreplace (a0 = bfromcstr("aabaAb"), a1 = bfromcstr("a"), a2 = bfromcstr("aa"), 0); Should result in changing a0 to "aaaabaaAb". This function performs exactly (b->slen - position) bstring comparisons, and data movement is bounded above by character volume equivalent to size of the output bstring. .......................................................................... extern int bfindreplacecaseless (bstring b, const_bstring find, const_bstring replace, int position); Replace all occurrences of the find substring, ignoring case, with a replace bstring after a given position in the bstring b. The find bstring must have a length > 0 otherwise BSTR_ERR is returned. This function does not perform recursive per character replacement; that is to say successive searches resume at the position after the last replace. So for example: bfindreplacecaseless (a0 = bfromcstr("AAbaAb"), a1 = bfromcstr("a"), a2 = bfromcstr("aa"), 0); Should result in changing a0 to "aaaabaaaab". This function performs exactly (b->slen - position) bstring comparisons, and data movement is bounded above by character volume equivalent to size of the output bstring. .......................................................................... extern int balloc (bstring b, int length); Increase the allocated memory backing the data buffer for the bstring b to a length of at least length. If the memory backing the bstring b is already large enough, not action is performed. This has no effect on the bstring b that is visible to the bstring API. Usually this function will only be used when a minimum buffer size is required coupled with a direct access to the ->data member of the bstring structure. Be warned that like any other bstring function, the bstring must be well defined upon entry to this function. I.e., doing something like: b->slen *= 2; /* ?? Most likely incorrect */ balloc (b, b->slen); is invalid, and should be implemented as: int t; if (BSTR_OK == balloc (b, t = (b->slen * 2))) b->slen = t; This function will return with BSTR_ERR if b is not detected as a valid bstring or length is not greater than 0, otherwise BSTR_OK is returned. .......................................................................... extern int ballocmin (bstring b, int length); Change the amount of memory backing the bstring b to at least length. This operation will never truncate the bstring data including the extra terminating '\0' and thus will not decrease the length to less than b->slen + 1. Note that repeated use of this function may cause performance problems (realloc may be called on the bstring more than the O(log(INT_MAX)) times). This function will return with BSTR_ERR if b is not detected as a valid bstring or length is not greater than 0, otherwise BSTR_OK is returned. So for example: if (BSTR_OK == ballocmin (b, 64)) b->data[63] = 'x'; The idea is that this will set the 64th character of b to 'x' if it is at least 64 characters long otherwise do nothing. And we know this is well defined so long as the ballocmin call was successfully, since it will ensure that b has been allocated with at least 64 characters. .......................................................................... int btrunc (bstring b, int n); Truncate the bstring to at most n characters. This function will return with BSTR_ERR if b is not detected as a valid bstring or n is less than 0, otherwise BSTR_OK is returned. .......................................................................... extern int bpattern (bstring b, int len); Replicate the starting bstring, b, end to end repeatedly until it surpasses len characters, then chop the result to exactly len characters. This function operates in-place. This function will return with BSTR_ERR if b is NULL or of length 0, otherwise BSTR_OK is returned. .......................................................................... extern int btoupper (bstring b); Convert contents of bstring to upper case. This function will return with BSTR_ERR if b is NULL or of length 0, otherwise BSTR_OK is returned. .......................................................................... extern int btolower (bstring b); Convert contents of bstring to lower case. This function will return with BSTR_ERR if b is NULL or of length 0, otherwise BSTR_OK is returned. .......................................................................... extern int bltrimws (bstring b); Delete whitespace contiguous from the left end of the bstring. This function will return with BSTR_ERR if b is NULL or of length 0, otherwise BSTR_OK is returned. .......................................................................... extern int brtrimws (bstring b); Delete whitespace contiguous from the right end of the bstring. This function will return with BSTR_ERR if b is NULL or of length 0, otherwise BSTR_OK is returned. .......................................................................... extern int btrimws (bstring b); Delete whitespace contiguous from both ends of the bstring. This function will return with BSTR_ERR if b is NULL or of length 0, otherwise BSTR_OK is returned. .......................................................................... extern int bstrListCreate (void); Create an empty struct bstrList. The struct bstrList output structure is declared as follows: struct bstrList { int qty, mlen; bstring * entry; }; The entry field actually is an array with qty number entries. The mlen record counts the maximum number of bstring's for which there is memory in the entry record. The Bstrlib API does *NOT* include a comprehensive set of functions for full management of struct bstrList in an abstracted way. The reason for this is because aliasing semantics of the list are best left to the user of this function, and performance varies wildly depending on the assumptions made. For a complete list of bstring data type it is recommended that the C++ public std::vector be used, since its semantics are usage are more standard. .......................................................................... extern int bstrListDestroy (struct bstrList * sl); Destroy a struct bstrList structure that was returned by the bsplit function. Note that this will destroy each bstring in the ->entry array as well. See bstrListCreate() above for structure of struct bstrList. .......................................................................... extern int bstrListAlloc (struct bstrList * sl, int msz); Ensure that there is memory for at least msz number of entries for the list. .......................................................................... extern int bstrListAllocMin (struct bstrList * sl, int msz); Try to allocate the minimum amount of memory for the list to include at least msz entries or sl->qty whichever is greater. .......................................................................... extern struct bstrList * bsplit (bstring str, unsigned char splitChar); Create an array of sequential substrings from str divided by the character splitChar. Successive occurrences of the splitChar will be divided by empty bstring entries, following the semantics from the Python programming language. To reclaim the memory from this output structure, bstrListDestroy () should be called. See bstrListCreate() above for structure of struct bstrList. .......................................................................... extern struct bstrList * bsplits (bstring str, const_bstring splitStr); Create an array of sequential substrings from str divided by any character contained in splitStr. An empty splitStr causes a single entry bstrList containing a copy of str to be returned. See bstrListCreate() above for structure of struct bstrList. .......................................................................... extern struct bstrList * bsplitstr (bstring str, const_bstring splitStr); Create an array of sequential substrings from str divided by the entire substring splitStr. An empty splitStr causes a single entry bstrList containing a copy of str to be returned. See bstrListCreate() above for structure of struct bstrList. .......................................................................... extern bstring bjoin (const struct bstrList * bl, const_bstring sep); Join the entries of a bstrList into one bstring by sequentially concatenating them with the sep bstring in between. If sep is NULL, it is treated as if it were the empty bstring. Note that: bjoin (l = bsplit (b, s->data[0]), s); should result in a copy of b, if s->slen is 1. If there is an error NULL is returned, otherwise a bstring with the correct result is returned. See bstrListCreate() above for structure of struct bstrList. .......................................................................... extern int bsplitcb (const_bstring str, unsigned char splitChar, int pos, int (* cb) (void * parm, int ofs, int len), void * parm); Iterate the set of disjoint sequential substrings over str starting at position pos divided by the character splitChar. The parm passed to bsplitcb is passed on to cb. If the function cb returns a value < 0, then further iterating is halted and this value is returned by bsplitcb. Note: Non-destructive modification of str from within the cb function while performing this split is not undefined. bsplitcb behaves in sequential lock step with calls to cb. I.e., after returning from a cb that return a non-negative integer, bsplitcb continues from the position 1 character after the last detected split character and it will halt immediately if the length of str falls below this point. However, if the cb function destroys str, then it *must* return with a negative value, otherwise bsplitcb will continue in an undefined manner. This function is provided as an incremental alternative to bsplit that is abortable and which does not impose additional memory allocation. .......................................................................... extern int bsplitscb (const_bstring str, const_bstring splitStr, int pos, int (* cb) (void * parm, int ofs, int len), void * parm); Iterate the set of disjoint sequential substrings over str starting at position pos divided by any of the characters in splitStr. An empty splitStr causes the whole str to be iterated once. The parm passed to bsplitcb is passed on to cb. If the function cb returns a value < 0, then further iterating is halted and this value is returned by bsplitcb. Note: Non-destructive modification of str from within the cb function while performing this split is not undefined. bsplitscb behaves in sequential lock step with calls to cb. I.e., after returning from a cb that return a non-negative integer, bsplitscb continues from the position 1 character after the last detected split character and it will halt immediately if the length of str falls below this point. However, if the cb function destroys str, then it *must* return with a negative value, otherwise bsplitscb will continue in an undefined manner. This function is provided as an incremental alternative to bsplits that is abortable and which does not impose additional memory allocation. .......................................................................... extern int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos, int (* cb) (void * parm, int ofs, int len), void * parm); Iterate the set of disjoint sequential substrings over str starting at position pos divided by the entire substring splitStr. An empty splitStr causes each character of str to be iterated. The parm passed to bsplitcb is passed on to cb. If the function cb returns a value < 0, then further iterating is halted and this value is returned by bsplitcb. Note: Non-destructive modification of str from within the cb function while performing this split is not undefined. bsplitstrcb behaves in sequential lock step with calls to cb. I.e., after returning from a cb that return a non-negative integer, bsplitstrcb continues from the position 1 character after the last detected split character and it will halt immediately if the length of str falls below this point. However, if the cb function destroys str, then it *must* return with a negative value, otherwise bsplitscb will continue in an undefined manner. This function is provided as an incremental alternative to bsplitstr that is abortable and which does not impose additional memory allocation. .......................................................................... extern bstring bformat (const char * fmt, ...); Takes the same parameters as printf (), but rather than outputting results to stdio, it forms a bstring which contains what would have been output. Note that if there is an early generation of a '\0' character, the bstring will be truncated to this end point. Note that %s format tokens correspond to '\0' terminated char * buffers, not bstrings. To print a bstring, first dereference data element of the the bstring: /* b1->data needs to be '\0' terminated, so tagbstrings generated by blk2tbstr () might not be suitable. */ b0 = bformat ("Hello, %s", b1->data); Note that if the BSTRLIB_NOVSNP macro has been set when bstrlib has been compiled the bformat function is not present. .......................................................................... extern int bformata (bstring b, const char * fmt, ...); In addition to the initial output buffer b, bformata takes the same parameters as printf (), but rather than outputting results to stdio, it appends the results to the initial bstring parameter. Note that if there is an early generation of a '\0' character, the bstring will be truncated to this end point. Note that %s format tokens correspond to '\0' terminated char * buffers, not bstrings. To print a bstring, first dereference data element of the the bstring: /* b1->data needs to be '\0' terminated, so tagbstrings generated by blk2tbstr () might not be suitable. */ bformata (b0 = bfromcstr ("Hello"), ", %s", b1->data); Note that if the BSTRLIB_NOVSNP macro has been set when bstrlib has been compiled the bformata function is not present. .......................................................................... extern int bassignformat (bstring b, const char * fmt, ...); After the first parameter, it takes the same parameters as printf (), but rather than outputting results to stdio, it outputs the results to the bstring parameter b. Note that if there is an early generation of a '\0' character, the bstring will be truncated to this end point. Note that %s format tokens correspond to '\0' terminated char * buffers, not bstrings. To print a bstring, first dereference data element of the the bstring: /* b1->data needs to be '\0' terminated, so tagbstrings generated by blk2tbstr () might not be suitable. */ bassignformat (b0 = bfromcstr ("Hello"), ", %s", b1->data); Note that if the BSTRLIB_NOVSNP macro has been set when bstrlib has been compiled the bassignformat function is not present. .......................................................................... extern int bvcformata (bstring b, int count, const char * fmt, va_list arglist); The bvcformata function formats data under control of the format control string fmt and attempts to append the result to b. The fmt parameter is the same as that of the printf function. The variable argument list is replaced with arglist, which has been initialized by the va_start macro. The size of the output is upper bounded by count. If the required output exceeds count, the string b is not augmented with any contents and a value below BSTR_ERR is returned. If a value below -count is returned then it is recommended that the negative of this value be used as an update to the count in a subsequent pass. On other errors, such as running out of memory, parameter errors or numeric wrap around BSTR_ERR is returned. BSTR_OK is returned when the output is successfully generated and appended to b. Note: There is no sanity checking of arglist, and this function is destructive of the contents of b from the b->slen point onward. If there is an early generation of a '\0' character, the bstring will be truncated to this end point. Although this function is part of the external API for Bstrlib, the interface and semantics (length limitations, and unusual return codes) are fairly atypical. The real purpose for this function is to provide an engine for the bvformata macro. Note that if the BSTRLIB_NOVSNP macro has been set when bstrlib has been compiled the bvcformata function is not present. .......................................................................... extern bstring bread (bNread readPtr, void * parm); typedef size_t (* bNread) (void *buff, size_t elsize, size_t nelem, void *parm); Read an entire stream into a bstring, verbatum. The readPtr function pointer is compatible with fread sematics, except that it need not obtain the stream data from a file. The intention is that parm would contain the stream data context/state required (similar to the role of the FILE* I/O stream parameter of fread.) Abstracting the block read function allows for block devices other than file streams to be read if desired. Note that there is an ANSI compatibility issue if "fread" is used directly; see the ANSI issues section below. .......................................................................... extern int breada (bstring b, bNread readPtr, void * parm); Read an entire stream and append it to a bstring, verbatum. Behaves like bread, except that it appends it results to the bstring b. BSTR_ERR is returned on error, otherwise 0 is returned. .......................................................................... extern bstring bgets (bNgetc getcPtr, void * parm, char terminator); typedef int (* bNgetc) (void * parm); Read a bstring from a stream. As many bytes as is necessary are read until the terminator is consumed or no more characters are available from the stream. If read from the stream, the terminator character will be appended to the end of the returned bstring. The getcPtr function must have the same semantics as the fgetc C library function (i.e., returning an integer whose value is negative when there are no more characters available, otherwise the value of the next available unsigned character from the stream.) The intention is that parm would contain the stream data context/state required (similar to the role of the FILE* I/O stream parameter of fgets.) If no characters are read, or there is some other detectable error, NULL is returned. bgets will never call the getcPtr function more often than necessary to construct its output (including a single call, if required, to determine that the stream contains no more characters.) Abstracting the character stream function and terminator character allows for different stream devices and string formats other than '\n' terminated lines in a file if desired (consider \032 terminated email messages, in a UNIX mailbox for example.) For files, this function can be used analogously as fgets as follows: fp = fopen ( ... ); if (fp) b = bgets ((bNgetc) fgetc, fp, '\n'); (Note that only one terminator character can be used, and that '\0' is not assumed to terminate the stream in addition to the terminator character. This is consistent with the semantics of fgets.) .......................................................................... extern int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator); Read from a stream and concatenate to a bstring. Behaves like bgets, except that it appends it results to the bstring b. The value 1 is returned if no characters are read before a negative result is returned from getcPtr. Otherwise BSTR_ERR is returned on error, and 0 is returned in other normal cases. .......................................................................... extern int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator); Read from a stream and concatenate to a bstring. Behaves like bgets, except that it assigns the results to the bstring b. The value 1 is returned if no characters are read before a negative result is returned from getcPtr. Otherwise BSTR_ERR is returned on error, and 0 is returned in other normal cases. .......................................................................... extern struct bStream * bsopen (bNread readPtr, void * parm); Wrap a given open stream (described by a fread compatible function pointer and stream handle) into an open bStream suitable for the bstring library streaming functions. .......................................................................... extern void * bsclose (struct bStream * s); Close the bStream, and return the handle to the stream that was originally used to open the given stream. If s is NULL or detectably invalid, NULL will be returned. .......................................................................... extern int bsbufflength (struct bStream * s, int sz); Set the length of the buffer used by the bStream. If sz is the macro BSTR_BS_BUFF_LENGTH_GET (which is 0), the length is not set. If s is NULL or sz is negative, the function will return with BSTR_ERR, otherwise this function returns with the previous length. .......................................................................... extern int bsreadln (bstring r, struct bStream * s, char terminator); Read a bstring terminated by the terminator character or the end of the stream from the bStream (s) and return it into the parameter r. The matched terminator, if found, appears at the end of the line read. If the stream has been exhausted of all available data, before any can be read, BSTR_ERR is returned. This function may read additional characters into the stream buffer from the core stream that are not returned, but will be retained for subsequent read operations. When reading from high speed streams, this function can perform significantly faster than bgets. .......................................................................... extern int bsreadlna (bstring r, struct bStream * s, char terminator); Read a bstring terminated by the terminator character or the end of the stream from the bStream (s) and concatenate it to the parameter r. The matched terminator, if found, appears at the end of the line read. If the stream has been exhausted of all available data, before any can be read, BSTR_ERR is returned. This function may read additional characters into the stream buffer from the core stream that are not returned, but will be retained for subsequent read operations. When reading from high speed streams, this function can perform significantly faster than bgets. .......................................................................... extern int bsreadlns (bstring r, struct bStream * s, bstring terminators); Read a bstring terminated by any character in the terminators bstring or the end of the stream from the bStream (s) and return it into the parameter r. This function may read additional characters from the core stream that are not returned, but will be retained for subsequent read operations. .......................................................................... extern int bsreadlnsa (bstring r, struct bStream * s, bstring terminators); Read a bstring terminated by any character in the terminators bstring or the end of the stream from the bStream (s) and concatenate it to the parameter r. If the stream has been exhausted of all available data, before any can be read, BSTR_ERR is returned. This function may read additional characters from the core stream that are not returned, but will be retained for subsequent read operations. .......................................................................... extern int bsread (bstring r, struct bStream * s, int n); Read a bstring of length n (or, if it is fewer, as many bytes as is remaining) from the bStream. This function will read the minimum required number of additional characters from the core stream. When the stream is at the end of the file BSTR_ERR is returned, otherwise BSTR_OK is returned. .......................................................................... extern int bsreada (bstring r, struct bStream * s, int n); Read a bstring of length n (or, if it is fewer, as many bytes as is remaining) from the bStream and concatenate it to the parameter r. This function will read the minimum required number of additional characters from the core stream. When the stream is at the end of the file BSTR_ERR is returned, otherwise BSTR_OK is returned. .......................................................................... extern int bsunread (struct bStream * s, const_bstring b); Insert a bstring into the bStream at the current position. These characters will be read prior to those that actually come from the core stream. .......................................................................... extern int bspeek (bstring r, const struct bStream * s); Return the number of currently buffered characters from the bStream that will be read prior to reads from the core stream, and append it to the the parameter r. .......................................................................... extern int bssplitscb (struct bStream * s, const_bstring splitStr, int (* cb) (void * parm, int ofs, const_bstring entry), void * parm); Iterate the set of disjoint sequential substrings over the stream s divided by any character from the bstring splitStr. The parm passed to bssplitscb is passed on to cb. If the function cb returns a value < 0, then further iterating is halted and this return value is returned by bssplitscb. Note: At the point of calling the cb function, the bStream pointer is pointed exactly at the position right after having read the split character. The cb function can act on the stream by causing the bStream pointer to move, and bssplitscb will continue by starting the next split at the position of the pointer after the return from cb. However, if the cb causes the bStream s to be destroyed then the cb must return with a negative value, otherwise bssplitscb will continue in an undefined manner. This function is provided as way to incrementally parse through a file or other generic stream that in total size may otherwise exceed the practical or desired memory available. As with the other split callback based functions this is abortable and does not impose additional memory allocation. .......................................................................... extern int bssplitstrcb (struct bStream * s, const_bstring splitStr, int (* cb) (void * parm, int ofs, const_bstring entry), void * parm); Iterate the set of disjoint sequential substrings over the stream s divided by the entire substring splitStr. The parm passed to bssplitstrcb is passed on to cb. If the function cb returns a value < 0, then further iterating is halted and this return value is returned by bssplitstrcb. Note: At the point of calling the cb function, the bStream pointer is pointed exactly at the position right after having read the split character. The cb function can act on the stream by causing the bStream pointer to move, and bssplitstrcb will continue by starting the next split at the position of the pointer after the return from cb. However, if the cb causes the bStream s to be destroyed then the cb must return with a negative value, otherwise bssplitscb will continue in an undefined manner. This function is provided as way to incrementally parse through a file or other generic stream that in total size may otherwise exceed the practical or desired memory available. As with the other split callback based functions this is abortable and does not impose additional memory allocation. .......................................................................... extern int bseof (const struct bStream * s); Return the defacto "EOF" (end of file) state of a stream (1 if the bStream is in an EOF state, 0 if not, and BSTR_ERR if stream is closed or detectably erroneous.) When the readPtr callback returns a value <= 0 the stream reaches its "EOF" state. Note that bunread with non-empty content will essentially turn off this state, and the stream will not be in its "EOF" state so long as its possible to read more data out of it. Also note that the semantics of bseof() are slightly different from something like feof(). I.e., reaching the end of the stream does not necessarily guarantee that bseof() will return with a value indicating that this has happened. bseof() will only return indicating that it has reached the "EOF" and an attempt has been made to read past the end of the bStream. The macros ---------- The macros described below are shown in a prototype form indicating their intended usage. Note that the parameters passed to these macros will be referenced multiple times. As with all macros, programmer care is required to guard against unintended side effects. int blengthe (const_bstring b, int err); Returns the length of the bstring. If the bstring is NULL err is returned. .......................................................................... int blength (const_bstring b); Returns the length of the bstring. If the bstring is NULL, the length returned is 0. .......................................................................... int bchare (const_bstring b, int p, int c); Returns the p'th character of the bstring b. If the position p refers to a position that does not exist in the bstring or the bstring is NULL, then c is returned. .......................................................................... char bchar (const_bstring b, int p); Returns the p'th character of the bstring b. If the position p refers to a position that does not exist in the bstring or the bstring is NULL, then '\0' is returned. .......................................................................... char * bdatae (bstring b, char * err); Returns the char * data portion of the bstring b. If b is NULL, err is returned. .......................................................................... char * bdata (bstring b); Returns the char * data portion of the bstring b. If b is NULL, NULL is returned. .......................................................................... char * bdataofse (bstring b, int ofs, char * err); Returns the char * data portion of the bstring b offset by ofs. If b is NULL, err is returned. .......................................................................... char * bdataofs (bstring b, int ofs); Returns the char * data portion of the bstring b offset by ofs. If b is NULL, NULL is returned. .......................................................................... struct tagbstring var = bsStatic ("..."); The bsStatic macro allows for static declarations of literal string constants as struct tagbstring structures. The resulting tagbstring does not need to be freed or destroyed. Note that this macro is only well defined for string literal arguments. For more general string pointers, use the btfromcstr macro. The resulting struct tagbstring is permanently write protected. Attempts to write to this struct tagbstring from any bstrlib function will lead to BSTR_ERR being returned. Invoking the bwriteallow macro onto this struct tagbstring has no effect. .......................................................................... <- bsStaticBlkParms ("...") The bsStaticBlkParms macro emits a pair of comma seperated parameters corresponding to the block parameters for the block functions in Bstrlib (i.e., blk2bstr, bcatblk, blk2tbstr, bisstemeqblk, bisstemeqcaselessblk.) Note that this macro is only well defined for string literal arguments. Examples: bstring b = blk2bstr (bsStaticBlkParms ("Fast init. ")); bcatblk (b, bsStaticBlkParms ("No frills fast concatenation.")); These are faster than using bfromcstr() and bcatcstr() respectively because the length of the inline string is known as a compile time constant. Also note that seperate struct tagbstring declarations for holding the output of a bsStatic() macro are not required. .......................................................................... void btfromcstr (struct tagbstring& t, const char * s); Fill in the tagbstring t with the '\0' terminated char buffer s. This action is purely reference oriented; no memory management is done. The data member is just assigned s, and slen is assigned the strlen of s. The s parameter is accessed exactly once in this macro. The resulting struct tagbstring is initially write protected. Attempts to write to this struct tagbstring in a write protected state from any bstrlib function will lead to BSTR_ERR being returned. Invoke the bwriteallow on this struct tagbstring to make it writeable (though this requires that s be obtained from a function compatible with malloc.) .......................................................................... void btfromblk (struct tagbstring& t, void * s, int len); Fill in the tagbstring t with the data buffer s with length len. This action is purely reference oriented; no memory management is done. The data member of t is just assigned s, and slen is assigned len. Note that the buffer is not appended with a '\0' character. The s and len parameters are accessed exactly once each in this macro. The resulting struct tagbstring is initially write protected. Attempts to write to this struct tagbstring in a write protected state from any bstrlib function will lead to BSTR_ERR being returned. Invoke the bwriteallow on this struct tagbstring to make it writeable (though this requires that s be obtained from a function compatible with malloc.) .......................................................................... void btfromblkltrimws (struct tagbstring& t, void * s, int len); Fill in the tagbstring t with the data buffer s with length len after it has been left trimmed. This action is purely reference oriented; no memory management is done. The data member of t is just assigned to a pointer inside the buffer s. Note that the buffer is not appended with a '\0' character. The s and len parameters are accessed exactly once each in this macro. The resulting struct tagbstring is permanently write protected. Attempts to write to this struct tagbstring from any bstrlib function will lead to BSTR_ERR being returned. Invoking the bwriteallow macro onto this struct tagbstring has no effect. .......................................................................... void btfromblkrtrimws (struct tagbstring& t, void * s, int len); Fill in the tagbstring t with the data buffer s with length len after it has been right trimmed. This action is purely reference oriented; no memory management is done. The data member of t is just assigned to a pointer inside the buffer s. Note that the buffer is not appended with a '\0' character. The s and len parameters are accessed exactly once each in this macro. The resulting struct tagbstring is permanently write protected. Attempts to write to this struct tagbstring from any bstrlib function will lead to BSTR_ERR being returned. Invoking the bwriteallow macro onto this struct tagbstring has no effect. .......................................................................... void btfromblktrimws (struct tagbstring& t, void * s, int len); Fill in the tagbstring t with the data buffer s with length len after it has been left and right trimmed. This action is purely reference oriented; no memory management is done. The data member of t is just assigned to a pointer inside the buffer s. Note that the buffer is not appended with a '\0' character. The s and len parameters are accessed exactly once each in this macro. The resulting struct tagbstring is permanently write protected. Attempts to write to this struct tagbstring from any bstrlib function will lead to BSTR_ERR being returned. Invoking the bwriteallow macro onto this struct tagbstring has no effect. .......................................................................... void bmid2tbstr (struct tagbstring& t, bstring b, int pos, int len); Fill the tagbstring t with the substring from b, starting from position pos with a length len. The segment is clamped by the boundaries of the bstring b. This action is purely reference oriented; no memory management is done. Note that the buffer is not appended with a '\0' character. Note that the t parameter to this macro may be accessed multiple times. Note that the contents of t will become undefined if the contents of b change or are destroyed. The resulting struct tagbstring is permanently write protected. Attempts to write to this struct tagbstring in a write protected state from any bstrlib function will lead to BSTR_ERR being returned. Invoking the bwriteallow macro on this struct tagbstring will have no effect. .......................................................................... void bvformata (int& ret, bstring b, const char * format, lastarg); Append the bstring b with printf like formatting with the format control string, and the arguments taken from the ... list of arguments after lastarg passed to the containing function. If the containing function does not have ... parameters or lastarg is not the last named parameter before the ... then the results are undefined. If successful, the results are appended to b and BSTR_OK is assigned to ret. Otherwise BSTR_ERR is assigned to ret. Example: void dbgerror (FILE * fp, const char * fmt, ...) { int ret; bstring b; bvformata (ret, b = bfromcstr ("DBG: "), fmt, fmt); if (BSTR_OK == ret) fputs ((char *) bdata (b), fp); bdestroy (b); } Note that if the BSTRLIB_NOVSNP macro was set when bstrlib had been compiled the bvformata macro will not link properly. If the BSTRLIB_NOVSNP macro has been set, the bvformata macro will not be available. .......................................................................... void bwriteprotect (struct tagbstring& t); Disallow bstring from being written to via the bstrlib API. Attempts to write to the resulting tagbstring from any bstrlib function will lead to BSTR_ERR being returned. Note: bstrings which are write protected cannot be destroyed via bdestroy. Note to C++ users: Setting a CBString as write protected will not prevent it from being destroyed by the destructor. .......................................................................... void bwriteallow (struct tagbstring& t); Allow bstring to be written to via the bstrlib API. Note that such an action makes the bstring both writable and destroyable. If the bstring is not legitimately writable (as is the case for struct tagbstrings initialized with a bsStatic value), the results of this are undefined. Note that invoking the bwriteallow macro may increase the number of reallocs by one more than necessary for every call to bwriteallow interleaved with any bstring API which writes to this bstring. .......................................................................... int biswriteprotected (struct tagbstring& t); Returns 1 if the bstring is write protected, otherwise 0 is returned. =============================================================================== The bstest module ----------------- The bstest module is just a unit test for the bstrlib module. For correct implementations of bstrlib, it should execute with 0 failures being reported. This test should be utilized if modifications/customizations to bstrlib have been performed. It tests each core bstrlib function with bstrings of every mode (read-only, NULL, static and mutable) and ensures that the expected semantics are observed (including results that should indicate an error). It also tests for aliasing support. Passing bstest is a necessary but not a sufficient condition for ensuring the correctness of the bstrlib module. The test module --------------- The test module is just a unit test for the bstrwrap module. For correct implementations of bstrwrap, it should execute with 0 failures being reported. This test should be utilized if modifications/customizations to bstrwrap have been performed. It tests each core bstrwrap function with CBStrings write protected or not and ensures that the expected semantics are observed (including expected exceptions.) Note that exceptions cannot be disabled to run this test. Passing test is a necessary but not a sufficient condition for ensuring the correctness of the bstrwrap module. =============================================================================== Using Bstring and CBString as an alternative to the C library ------------------------------------------------------------- First let us give a table of C library functions and the alternative bstring functions and CBString methods that should be used instead of them. C-library Bstring alternative CBString alternative --------- ------------------- -------------------- gets bgets ::gets strcpy bassign = operator strncpy bassignmidstr ::midstr strcat bconcat += operator strncat bconcat + btrunc += operator + ::trunc strtok bsplit, bsplits ::split sprintf b(assign)format ::format snprintf b(assign)format + btrunc ::format + ::trunc vsprintf bvformata bvformata vsnprintf bvformata + btrunc bvformata + btrunc vfprintf bvformata + fputs use bvformata + fputs strcmp biseq, bstrcmp comparison operators. strncmp bstrncmp, memcmp bstrncmp, memcmp strlen ->slen, blength ::length strdup bstrcpy constructor strset bpattern ::fill strstr binstr ::find strpbrk binchr ::findchr stricmp bstricmp cast & use bstricmp strlwr btolower cast & use btolower strupr btoupper cast & use btoupper strrev bReverse (aux module) cast & use bReverse strchr bstrchr cast & use bstrchr strspnp use strspn use strspn ungetc bsunread bsunread The top 9 C functions listed here are troublesome in that they impose memory management in the calling function. The Bstring and CBstring interfaces have built-in memory management, so there is far less code with far less potential for buffer overrun problems. strtok can only be reliably called as a "leaf" calculation, since it (quite bizarrely) maintains hidden internal state. And gets is well known to be broken no matter what. The Bstrlib alternatives do not suffer from those sorts of problems. The substitute for strncat can be performed with higher performance by using the blk2tbstr macro to create a presized second operand for bconcat. C-library Bstring alternative CBString alternative --------- ------------------- -------------------- strspn strspn acceptable strspn acceptable strcspn strcspn acceptable strcspn acceptable strnset strnset acceptable strnset acceptable printf printf acceptable printf acceptable puts puts acceptable puts acceptable fprintf fprintf acceptable fprintf acceptable fputs fputs acceptable fputs acceptable memcmp memcmp acceptable memcmp acceptable Remember that Bstring (and CBstring) functions will automatically append the '\0' character to the character data buffer. So by simply accessing the data buffer directly, ordinary C string library functions can be called directly on them. Note that bstrcmp is not the same as memcmp in exactly the same way that strcmp is not the same as memcmp. C-library Bstring alternative CBString alternative --------- ------------------- -------------------- fread balloc + fread ::alloc + fread fgets balloc + fgets ::alloc + fgets These are odd ones because of the exact sizing of the buffer required. The Bstring and CBString alternatives requires that the buffers are forced to hold at least the prescribed length, then just use fread or fgets directly. However, typically the automatic memory management of Bstring and CBstring will make the typical use of fgets and fread to read specifically sized strings unnecessary. Implementation Choices ---------------------- Overhead: ......... The bstring library has more overhead versus straight char buffers for most functions. This overhead is essentially just the memory management and string header allocation. This overhead usually only shows up for small string manipulations. The performance loss has to be considered in light of the following: 1) What would be the performance loss of trying to write this management code in one's own application? 2) Since the bstring library source code is given, a sufficiently powerful modern inlining globally optimizing compiler can remove function call overhead. Since the data type is exposed, a developer can replace any unsatisfactory function with their own inline implementation. And that is besides the main point of what the better string library is mainly meant to provide. Any overhead lost has to be compared against the value of the safe abstraction for coupling memory management and string functionality. Performance of the C interface: ............................... The algorithms used have performance advantages versus the analogous C library functions. For example: 1. bfromcstr/blk2str/bstrcpy versus strcpy/strdup. By using memmove instead of strcpy, the break condition of the copy loop is based on an independent counter (that should be allocated in a register) rather than having to check the results of the load. Modern out-of-order executing CPUs can parallelize the final branch mis-predict penality with the loading of the source string. Some CPUs will also tend to have better built-in hardware support for counted memory moves than load-compare-store. (This is a minor, but non-zero gain.) 2. biseq versus strcmp. If the strings are unequal in length, bsiseq will return in O(1) time. If the strings are aliased, or have aliased data buffers, biseq will return in O(1) time. strcmp will always be O(k), where k is the length of the common prefix or the whole string if they are identical. 3. ->slen versus strlen. ->slen is obviously always O(1), while strlen is always O(n) where n is the length of the string. 4. bconcat versus strcat. Both rely on precomputing the length of the destination string argument, which will favor the bstring library. On iterated concatenations the performance difference can be enormous. 5. bsreadln versus fgets. The bsreadln function reads large blocks at a time from the given stream, then parses out lines from the buffers directly. Some C libraries will implement fgets as a loop over single fgetc calls. Testing indicates that the bsreadln approach can be several times faster for fast stream devices (such as a file that has been entirely cached.) 6. bsplits/bsplitscb versus strspn. Accelerators for the set of match characters are generated only once. Practical testing indicates that in general Bstrlib is never signifcantly slower than the C library for common operations, while very often having a performance advantage that ranges from significant to massive. Even for functions like b(n)inchr versus str(c)spn() (where, in theory, there is no advantage for the Bstrlib architecture) the performance of Bstrlib is vastly superior to most tested C library implementations. Some of Bstrlib's extra functionality also lead to inevitable performance advantages over typical C solutions. For example, using the blk2tbstr macro, one can (in O(1) time) generate an internal substring by reference while not disturbing the original string. If disturbing the original string is not an option, typically, a comparable C solution would have to make a copy of the substring to provide similar functionality. Another example is reverse character set scanning -- the str(c)spn functions only scan in a forward direction which can complicate some parsing algorithms. Where high performance char * based algorithms are available, Bstrlib can still leverage them by accessing the ->data field on bstrings. So realistically Bstrlib can never be significantly slower than any standard '\0' terminated char * based solutions. Performance of the C++ interface: ................................. The C++ interface has been designed with an emphasis on abstraction and safety first. However, since it is substantially a wrapper for the C bstring functions, for longer strings the performance comments described in the "Performance of the C interface" section above still apply. Note that the (CBString *) type can be directly cast to a (bstring) type, and passed as parameters to the C functions (though a CBString must never be passed to bdestroy.) Probably the most controversial choice is performing full bounds checking on the [] operator. This decision was made because 1) the fast alternative of not bounds checking is still available by first casting the CBString to a (const char *) buffer or to a (struct tagbstring) then derefencing .data and 2) because the lack of bounds checking is seen as one of the main weaknesses of C/C++ versus other languages. This check being done on every access leads to individual character extraction being actually slower than other languages in this one respect (other language's compilers will normally dedicate more resources on hoisting or removing bounds checking as necessary) but otherwise bring C++ up to the level of other languages in terms of functionality. It is common for other C++ libraries to leverage the abstractions provided by C++ to use reference counting and "copy on write" policies. While these techniques can speed up some scenarios, they impose a problem with respect to thread safety. bstrings and CBStrings can be properly protected with "per-object" mutexes, meaning that two bstrlib calls can be made and execute simultaneously, so long as the bstrings and CBstrings are distinct. With a reference count and alias before copy on write policy, global mutexes are required that prevent multiple calls to the strings library to execute simultaneously regardless of whether or not the strings represent the same string. One interesting trade off in CBString is that the default constructor is not trivial. I.e., it always prepares a ready to use memory buffer. The purpose is to ensure that there is a uniform internal composition for any functioning CBString that is compatible with bstrings. It also means that the other methods in the class are not forced to perform "late initialization" checks. In the end it means that construction of CBStrings are slower than other comparable C++ string classes. Initial testing, however, indicates that CBString outperforms std::string and MFC's CString, for example, in all other operations. So to work around this weakness it is recommended that CBString declarations be pushed outside of inner loops. Practical testing indicates that with the exception of the caveats given above (constructors and safe index character manipulations) the C++ API for Bstrlib generally outperforms popular standard C++ string classes. Amongst the standard libraries and compilers, the quality of concatenation operations varies wildly and very little care has gone into search functions. Bstrlib dominates those performance benchmarks. Memory management: .................. The bstring functions which write and modify bstrings will automatically reallocate the backing memory for the char buffer whenever it is required to grow. The algorithm for resizing chosen is to snap up to sizes that are a power of two which are sufficient to hold the intended new size. Memory reallocation is not performed when the required size of the buffer is decreased. This behavior can be relied on, and is necessary to make the behaviour of balloc deterministic. This trades off additional memory usage for decreasing the frequency for required reallocations: 1. For any bstring whose size never exceeds n, its buffer is not ever reallocated more than log_2(n) times for its lifetime. 2. For any bstring whose size never exceeds n, its buffer is never more than 2*(n+1) in length. (The extra characters beyond 2*n are to allow for the implicit '\0' which is always added by the bstring modifying functions.) Decreasing the buffer size when the string decreases in size would violate 1) above and in real world case lead to pathological heap thrashing. Similarly, allocating more tightly than "least power of 2 greater than necessary" would lead to a violation of 1) and have the same potential for heap thrashing. Property 2) needs emphasizing. Although the memory allocated is always a power of 2, for a bstring that grows linearly in size, its buffer memory also grows linearly, not exponentially. The reason is that the amount of extra space increases with each reallocation, which decreases the frequency of future reallocations. Obviously, given that bstring writing functions may reallocate the data buffer backing the target bstring, one should not attempt to cache the data buffer address and use it after such bstring functions have been called. This includes making reference struct tagbstrings which alias to a writable bstring. balloc or bfromcstralloc can be used to preallocate the minimum amount of space used for a given bstring. This will reduce even further the number of times the data portion is reallocated. If the length of the string is never more than one less than the memory length then there will be no further reallocations. Note that invoking the bwriteallow macro may increase the number of reallocs by one more than necessary for every call to bwriteallow interleaved with any bstring API which writes to this bstring. The library does not use any mechanism for automatic clean up for the C API. Thus explicit clean up via calls to bdestroy() are required to avoid memory leaks. Constant and static tagbstrings: ................................ A struct tagbstring can be write protected from any bstrlib function using the bwriteprotect macro. A write protected struct tagbstring can then be reset to being writable via the bwriteallow macro. There is, of course, no protection from attempts to directly access the bstring members. Modifying a bstring which is write protected by direct access has undefined behavior. static struct tagbstrings can be declared via the bsStatic macro. They are considered permanently unwritable. Such struct tagbstrings's are declared such that attempts to write to it are not well defined. Invoking either bwriteallow or bwriteprotect on static struct tagbstrings has no effect. struct tagbstring's initialized via btfromcstr or blk2tbstr are protected by default but can be made writeable via the bwriteallow macro. If bwriteallow is called on such struct tagbstring's, it is the programmer's responsibility to ensure that: 1) the buffer supplied was allocated from the heap. 2) bdestroy is not called on this tagbstring (unless the header itself has also been allocated from the heap.) 3) free is called on the buffer to reclaim its memory. bwriteallow and bwriteprotect can be invoked on ordinary bstrings (they have to be dereferenced with the (*) operator to get the levels of indirection correct) to give them write protection. Buffer declaration: ................... The memory buffer is actually declared "unsigned char *" instead of "char *". The reason for this is to trigger compiler warnings whenever uncasted char buffers are assigned to the data portion of a bstring. This will draw more diligent programmers into taking a second look at the code where they have carelessly left off the typically required cast. (Research from AT&T/Lucent indicates that additional programmer eyeballs is one of the most effective mechanisms at ferreting out bugs.) Function pointers: .................. The bgets, bread and bStream functions use function pointers to obtain strings from data streams. The function pointer declarations have been specifically chosen to be compatible with the fgetc and fread functions. While this may seem to be a convoluted way of implementing fgets and fread style functionality, it has been specifically designed this way to ensure that there is no dependency on a single narrowly defined set of device interfaces, such as just stream I/O. In the embedded world, its quite possible to have environments where such interfaces may not exist in the standard C library form. Furthermore, the generalization that this opens up allows for more sophisticated uses for these functions (performing an fgets like function on a socket, for example.) By using function pointers, it also allows such abstract stream interfaces to be created using the bstring library itself while not creating a circular dependency. Use of int's for sizes: ....................... This is just a recognition that 16bit platforms with requirements for strings that are larger than 64K and 32bit+ platforms with requirements for strings that are larger than 4GB are pretty marginal. The main focus is for 32bit platforms, and emerging 64bit platforms with reasonable < 4GB string requirements. Using ints allows for negative values which has meaning internally to bstrlib. Semantic consideration: ....................... Certain care needs to be taken when copying and aliasing bstrings. A bstring is essentially a pointer type which points to a multipart abstract data structure. Thus usage, and lifetime of bstrings have semantics that follow these considerations. For example: bstring a, b; struct tagbstring t; a = bfromcstr("Hello"); /* Create new bstring and copy "Hello" into it. */ b = a; /* Alias b to the contents of a. */ t = *a; /* Create a current instance pseudo-alias of a. */ bconcat (a, b); /* Double a and b, t is now undefined. */ bdestroy (a); /* Destroy the contents of both a and b. */ Variables of type bstring are really just references that point to real bstring objects. The equal operator (=) creates aliases, and the asterisk dereference operator (*) creates a kind of alias to the current instance (which is generally not useful for any purpose.) Using bstrcpy() is the correct way of creating duplicate instances. The ampersand operator (&) is useful for creating aliases to struct tagbstrings (remembering that constructed struct tagbstrings are not writable by default.) CBStrings use complete copy semantics for the equal operator (=), and thus do not have these sorts of issues. Debugging: .......... Bstrings have a simple, exposed definition and construction, and the library itself is open source. So most debugging is going to be fairly straight- forward. But the memory for bstrings come from the heap, which can often be corrupted indirectly, and it might not be obvious what has happened even from direct examination of the contents in a debugger or a core dump. There are some tools such as Purify, Insure++ and Electric Fence which can help solve such problems, however another common approach is to directly instrument the calls to malloc, realloc, calloc, free, memcpy, memmove and/or other calls by overriding them with macro definitions. Although the user could hack on the Bstrlib sources directly as necessary to perform such an instrumentation, Bstrlib comes with a built-in mechanism for doing this. By defining the macro BSTRLIB_MEMORY_DEBUG and providing an include file named memdbg.h this will force the core Bstrlib modules to attempt to include this file. In such a file, macros could be defined which overrides Bstrlib's useage of the C standard library. Rather than calling malloc, realloc, free, memcpy or memmove directly, Bstrlib emits the macros bstr__alloc, bstr__realloc, bstr__free, bstr__memcpy and bstr__memmove in their place respectively. By default these macros are simply assigned to be equivalent to their corresponding C standard library function call. However, if they are given earlier macro definitions (via the back door include file) they will not be given their default definition. In this way Bstrlib's interface to the standard library can be changed but without having to directly redefine or link standard library symbols (both of which are not strictly ANSI C compliant.) An example definition might include: #define bstr__alloc(sz) X_malloc ((sz), __LINE__, __FILE__) which might help contextualize heap entries in a debugging environment. The NULL parameter and sanity checking of bstrings is part of the Bstrlib API, and thus Bstrlib itself does not present any different modes which would correspond to "Debug" or "Release" modes. Bstrlib always contains mechanisms which one might think of as debugging features, but retains the performance and small memory footprint one would normally associate with release mode code. Integration Microsoft's Visual Studio debugger: ............................................... Microsoft's Visual Studio debugger has a capability of customizable mouse float over data type descriptions. This is accomplished by editting the AUTOEXP.DAT file to include the following: ; new for CBString tagbstring =slen= mlen= Bstrlib::CBStringList =count= In Visual C++ 6.0 this file is located in the directory: C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin and in Visual Studio .NET 2003 its located here: C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Packages\Debugger This will improve the ability of debugging with Bstrlib under Visual Studio. Security -------- Bstrlib does not come with explicit security features outside of its fairly comprehensive error detection, coupled with its strict semantic support. That is to say that certain common security problems, such as buffer overrun, constant overwrite, arbitrary truncation etc, are far less likely to happen inadvertently. Where it does help, Bstrlib maximizes its advantage by providing developers a simple adoption path that lets them leave less secure string mechanisms behind. The library will not leave developers wanting, so they will be less likely to add new code using a less secure string library to add functionality that might be missing from Bstrlib. That said there are a number of security ideas not addressed by Bstrlib: 1. Race condition exploitation (i.e., verifying a string's contents, then raising the privilege level and execute it as a shell command as two non-atomic steps) is well beyond the scope of what Bstrlib can provide. It should be noted that MFC's built-in string mutex actually does not solve this problem either -- it just removes immediate data corruption as a possible outcome of such exploit attempts (it can be argued that this is worse, since it will leave no trace of the exploitation). In general race conditions have to be dealt with by careful design and implementation; it cannot be assisted by a string library. 2. Any kind of access control or security attributes to prevent usage in dangerous interfaces such as system(). Perl includes a "trust" attribute which can be endowed upon strings that are intended to be passed to such dangerous interfaces. However, Perl's solution reflects its own limitations -- notably that it is not a strongly typed language. In the example code for Bstrlib, there is a module called taint.cpp. It demonstrates how to write a simple wrapper class for managing "untainted" or trusted strings using the type system to prevent questionable mixing of ordinary untrusted strings with untainted ones then passing them to dangerous interfaces. In this way the security correctness of the code reduces to auditing the direct usages of dangerous interfaces or promotions of tainted strings to untainted ones. 3. Encryption of string contents is way beyond the scope of Bstrlib. Maintaining encrypted string contents in the futile hopes of thwarting things like using system-level debuggers to examine sensitive string data is likely to be a wasted effort (imagine a debugger that runs at a higher level than a virtual processor where the application runs). For more standard encryption usages, since the bstring contents are simply binary blocks of data, this should pose no problem for usage with other standard encryption libraries. Compatibility ------------- The Better String Library is known to compile and function correctly with the following compilers: - Microsoft Visual C++ - Watcom C/C++ - Intel's C/C++ compiler (Windows) - The GNU C/C++ compiler (cygwin and Linux on PPC64) - Borland C - Turbo C Setting of configuration options should be unnecessary for these compilers (unless exceptions are being disabled or STLport has been added to WATCOM C/C++). Bstrlib has been developed with an emphasis on portability. As such porting it to other compilers should be straight forward. This package includes a porting guide (called porting.txt) which explains what issues may exist for porting Bstrlib to different compilers and environments. ANSI issues ----------- 1. The function pointer types bNgetc and bNread have prototypes which are very similar to, but not exactly the same as fgetc and fread respectively. Basically the FILE * parameter is replaced by void *. The purpose of this was to allow one to create other functions with fgetc and fread like semantics without being tied to ANSI C's file streaming mechanism. I.e., one could very easily adapt it to sockets, or simply reading a block of memory, or procedurally generated strings (for fractal generation, for example.) The problem is that invoking the functions (bNgetc)fgetc and (bNread)fread is not technically legal in ANSI C. The reason being that the compiler is only able to coerce the function pointers themselves into the target type, however are unable to perform any cast (implicit or otherwise) on the parameters passed once invoked. I.e., if internally void * and FILE * need some kind of mechanical coercion, the compiler will not properly perform this conversion and thus lead to undefined behavior. Apparently a platform from Data General called "Eclipse" and another from Tandem called "NonStop" have a different representation for pointers to bytes and pointers to words, for example, where coercion via casting is necessary. (Actual confirmation of the existence of such machines is hard to come by, so it is prudent to be skeptical about this information.) However, this is not an issue for any known contemporary platforms. One may conclude that such platforms are effectively apocryphal even if they do exist. To correctly work around this problem to the satisfaction of the ANSI limitations, one needs to create wrapper functions for fgets and/or fread with the prototypes of bNgetc and/or bNread respectively which performs no other action other than to explicitely cast the void * parameter to a FILE *, and simply pass the remaining parameters straight to the function pointer call. The wrappers themselves are trivial: size_t freadWrap (void * buff, size_t esz, size_t eqty, void * parm) { return fread (buff, esz, eqty, (FILE *) parm); } int fgetcWrap (void * parm) { return fgetc ((FILE *) parm); } These have not been supplied in bstrlib or bstraux to prevent unnecessary linking with file I/O functions. 2. vsnprintf is not available on all compilers. Because of this, the bformat and bformata functions (and format and formata methods) are not guaranteed to work properly. For those compilers that don't have vsnprintf, the BSTRLIB_NOVSNP macro should be set before compiling bstrlib, and the format functions/method will be disabled. The more recent ANSI C standards have specified the required inclusion of a vsnprintf function. 3. The bstrlib function names are not unique in the first 6 characters. This is only an issue for older C compiler environments which do not store more than 6 characters for function names. 4. The bsafe module defines macros and function names which are part of the C library. This simply overrides the definition as expected on all platforms tested, however it is not sanctioned by the ANSI standard. This module is clearly optional and should be omitted on platforms which disallow its undefined semantics. In practice the real issue is that some compilers in some modes of operation can/will inline these standard library functions on a module by module basis as they appear in each. The linker will thus have no opportunity to override the implementation of these functions for those cases. This can lead to inconsistent behaviour of the bsafe module on different platforms and compilers. =============================================================================== Comparison with Microsoft's CString class ----------------------------------------- Although developed independently, CBStrings have very similar functionality to Microsoft's CString class. However, the bstring library has significant advantages over CString: 1. Bstrlib is a C-library as well as a C++ library (using the C++ wrapper). - Thus it is compatible with more programming environments and available to a wider population of programmers. 2. The internal structure of a bstring is considered exposed. - A single contiguous block of data can be cut into read-only pieces by simply creating headers, without allocating additional memory to create reference copies of each of these sub-strings. - In this way, using bstrings in a totally abstracted way becomes a choice rather than an imposition. Further this choice can be made differently at different layers of applications that use it. 3. Static declaration support precludes the need for constructor invocation. - Allows for static declarations of constant strings that has no additional constructor overhead. 4. Bstrlib is not attached to another library. - Bstrlib is designed to be easily plugged into any other library collection, without dependencies on other libraries or paradigms (such as "MFC".) The bstring library also comes with a few additional functions that are not available in the CString class: - bsetstr - bsplit - bread - breplace (this is different from CString::Replace()) - Writable indexed characters (for example a[i]='x') Interestingly, although Microsoft did implement mid$(), left$() and right$() functional analogues (these are functions from GWBASIC) they seem to have forgotten that mid$() could be also used to write into the middle of a string. This functionality exists in Bstrlib with the bsetstr() and breplace() functions. Among the disadvantages of Bstrlib is that there is no special support for localization or wide characters. Such things are considered beyond the scope of what bstrings are trying to deliver. CString essentially supports the older UCS-2 version of Unicode via widechar_t as an application-wide compile time switch. CString's also use built-in mechanisms for ensuring thread safety under all situations. While this makes writing thread safe code that much easier, this built-in safety feature has a price -- the inner loops of each CString method runs in its own critical section (grabbing and releasing a light weight mutex on every operation.) The usual way to decrease the impact of a critical section performance penalty is to amortize more operations per critical section. But since the implementation of CStrings is fixed as a one critical section per-operation cost, there is no way to leverage this common performance enhancing idea. The search facilities in Bstrlib are comparable to those in MFC's CString class, though it is missing locale specific collation. But because Bstrlib is interoperable with C's char buffers, it will allow programmers to write their own string searching mechanism (such as Boyer-Moore), or be able to choose from a variety of available existing string searching libraries (such as those for regular expressions) without difficulty. Microsoft used a very non-ANSI conforming trick in its implementation to allow printf() to use the "%s" specifier to output a CString correctly. This can be convenient, but it is inherently not portable. CBString requires an explicit cast, while bstring requires the data member to be dereferenced. Microsoft's own documentation recommends casting, instead of relying on this feature. Comparison with C++'s std::string --------------------------------- This is the C++ language's standard STL based string class. 1. There is no C implementation. 2. The [] operator is not bounds checked. 3. Missing a lot of useful functions like printf-like formatting. 4. Some sub-standard std::string implementations (SGI) are necessarily unsafe to use with multithreading. 5. Limited by STL's std::iostream which in turn is limited by ifstream which can only take input from files. (Compare to CBStream's API which can take abstracted input.) 6. Extremely uneven performance across implementations. Comparison with ISO C TR 24731 proposal --------------------------------------- Following the ISO C99 standard, Microsoft has proposed a group of C library extensions which are supposedly "safer and more secure". This proposal is expected to be adopted by the ISO C standard which follows C99. The proposal reveals itself to be very similar to Microsoft's "StrSafe" library. The functions are basically the same as other standard C library string functions except that destination parameters are paired with an additional length parameter of type rsize_t. rsize_t is the same as size_t, however, the range is checked to make sure its between 1 and RSIZE_MAX. Like Bstrlib, the functions perform a "parameter check". Unlike Bstrlib, when a parameter check fails, rather than simply outputing accumulatable error statuses, they call a user settable global error function handler, and upon return of control performs no (additional) detrimental action. The proposal covers basic string functions as well as a few non-reenterable functions (asctime, ctime, and strtok). 1. Still based solely on char * buffers (and therefore strlen() and strcat() is still O(n), and there are no faster streq() comparison functions.) 2. No growable string semantics. 3. Requires manual buffer length synchronization in the source code. 4. No attempt to enhance functionality of the C library. 5. Introduces a new error scenario (strings exceeding RSIZE_MAX length). The hope is that by exposing the buffer length requirements there will be fewer buffer overrun errors. However, the error modes are really just transformed, rather than removed. The real problem of buffer overflows is that they all happen as a result of erroneous programming. So forcing programmers to manually deal with buffer limits, will make them more aware of the problem but doesn't remove the possibility of erroneous programming. So a programmer that erroneously mixes up the rsize_t parameters is no better off from a programmer that introduces potential buffer overflows through other more typical lapses. So at best this may reduce the rate of erroneous programming, rather than making any attempt at removing failure modes. The error handler can discriminate between types of failures, but does not take into account any callsite context. So the problem is that the error is going to be manifest in a piece of code, but there is no pointer to that code. It would seem that passing in the call site __FILE__, __LINE__ as parameters would be very useful, but the API clearly doesn't support such a thing (it would increase code bloat even more than the extra length parameter does, and would require macro tricks to implement). The Bstrlib C API takes the position that error handling needs to be done at the callsite, and just tries to make it as painless as possible. Furthermore, error modes are removed by supporting auto-growing strings and aliasing. For capturing errors in more central code fragments, Bstrlib's C++ API uses exception handling extensively, which is superior to the leaf-only error handler approach. Comparison with Managed String Library CERT proposal ---------------------------------------------------- The main webpage for the managed string library: http://www.cert.org/secure-coding/managedstring.html Robert Seacord at CERT has proposed a C string library that he calls the "Managed String Library" for C. Like Bstrlib, it introduces a new type which is called a managed string. The structure of a managed string (string_m) is like a struct tagbstring but missing the length field. This internal structure is considered opaque. The length is, like the C standard library, always computed on the fly by searching for a terminating NUL on every operation that requires it. So it suffers from every performance problem that the C standard library suffers from. Interoperating with C string APIs (like printf, fopen, or anything else that takes a string parameter) requires copying to additionally allocating buffers that have to be manually freed -- this makes this library probably slower and more cumbersome than any other string library in existence. The library gives a fully populated error status as the return value of every string function. The hope is to be able to diagnose all problems specifically from the return code alone. Comparing this to Bstrlib, which aways returns one consistent error message, might make it seem that Bstrlib would be harder to debug; but this is not true. With Bstrlib, if an error occurs there is always enough information from just knowing there was an error and examining the parameters to deduce exactly what kind of error has happened. The managed string library thus gives up nested function calls while achieving little benefit, while Bstrlib does not. One interesting feature that "managed strings" has is the idea of data sanitization via character set whitelisting. That is to say, a globally definable filter that makes any attempt to put invalid characters into strings lead to an error and not modify the string. The author gives the following example: // create valid char set if (retValue = strcreate_m(&str1, "abc") ) { fprintf( stderr, "Error %d from strcreate_m.\n", retValue ); } if (retValue = setcharset(str1)) { fprintf( stderr, "Error %d from setcharset().\n", retValue ); } if (retValue = strcreate_m(&str1, "aabbccabc")) { fprintf( stderr, "Error %d from strcreate_m.\n", retValue ); } // create string with invalid char set if (retValue = strcreate_m(&str1, "abbccdabc")) { fprintf( stderr, "Error %d from strcreate_m.\n", retValue ); } Which we can compare with a more Bstrlib way of doing things: bstring bCreateWithFilter (const char * cstr, const_bstring filter) { bstring b = bfromcstr (cstr); if (BSTR_ERR != bninchr (b, filter) && NULL != b) { fprintf (stderr, "Filter violation.\n"); bdestroy (b); b = NULL; } return b; } struct tagbstring charFilter = bsStatic ("abc"); bstring str1 = bCreateWithFilter ("aabbccabc", &charFilter); bstring str2 = bCreateWithFilter ("aabbccdabc", &charFilter); The first thing we should notice is that with the Bstrlib approach you can have different filters for different strings if necessary. Furthermore, selecting a charset filter in the Managed String Library is uni-contextual. That is to say, there can only be one such filter active for the entire program, which means its usage is not well defined for intermediate library usage (a library that uses it will interfere with user code that uses it, and vice versa.) It is also likely to be poorly defined in multi-threading environments. There is also a question as to whether the data sanitization filter is checked on every operation, or just on creation operations. Since the charset can be set arbitrarily at run time, it might be set *after* some managed strings have been created. This would seem to imply that all functions should run this additional check every time if there is an attempt to enforce this. This would make things tremendously slow. On the other hand, if it is assumed that only creates and other operations that take char *'s as input need be checked because the charset was only supposed to be called once at and before any other managed string was created, then one can see that its easy to cover Bstrlib with equivalent functionality via a few wrapper calls such as the example given above. And finally we have to question the value of sanitation in the first place. For example, for httpd servers, there is generally a requirement that the URLs parsed have some form that avoids undesirable translation to local file system filenames or resources. The problem is that the way URLs can be encoded, it must be completely parsed and translated to know if it is using certain invalid character combinations. That is to say, merely filtering each character one at a time is not necessarily the right way to ensure that a string has safe contents. In the article that describes this proposal, it is claimed that it fairly closely approximates the existing C API semantics. On this point we should compare this "closeness" with Bstrlib: Bstrlib Managed String Library ------- ---------------------- Pointer arithmetic Segment arithmetic N/A Use in C Std lib ->data, or bdata{e} getstr_m(x,*) ... free(x) String literals bsStatic, bsStaticBlk strcreate_m() Transparency Complete None Its pretty clear that the semantic mapping from C strings to Bstrlib is fairly straightforward, and that in general semantic capabilities are the same or superior in Bstrlib. On the other hand the Managed String Library is either missing semantics or changes things fairly significantly. Comparison with Annexia's c2lib library --------------------------------------- This library is available at: http://www.annexia.org/freeware/c2lib 1. Still based solely on char * buffers (and therefore strlen() and strcat() is still O(n), and there are no faster streq() comparison functions.) Their suggestion that alternatives which wrap the string data type (such as bstring does) imposes a difficulty in interoperating with the C langauge's ordinary C string library is not founded. 2. Introduction of memory (and vector?) abstractions imposes a learning curve, and some kind of memory usage policy that is outside of the strings themselves (and therefore must be maintained by the developer.) 3. The API is massive, and filled with all sorts of trivial (pjoin) and controvertial (pmatch -- regular expression are not sufficiently standardized, and there is a very large difference in performance between compiled and non-compiled, REs) functions. Bstrlib takes a decidely minimal approach -- none of the functionality in c2lib is difficult or challenging to implement on top of Bstrlib (except the regex stuff, which is going to be difficult, and controvertial no matter what.) 4. Understanding why c2lib is the way it is pretty much requires a working knowledge of Perl. bstrlib requires only knowledge of the C string library while providing just a very select few worthwhile extras. 5. It is attached to a lot of cruft like a matrix math library (that doesn't include any functions for getting the determinant, eigenvectors, eigenvalues, the matrix inverse, test for singularity, test for orthogonality, a grahm schmit orthogonlization, LU decomposition ... I mean why bother?) Convincing a development house to use c2lib is likely quite difficult. It introduces too much, while not being part of any kind of standards body. The code must therefore be trusted, or maintained by those that use it. While bstring offers nothing more on this front, since its so much smaller, covers far less in terms of scope, and will typically improve string performance, the barrier to usage should be much smaller. Comparison with stralloc/qmail ------------------------------ More information about this library can be found here: http://www.canonical.org/~kragen/stralloc.html or here: http://cr.yp.to/lib/stralloc.html 1. Library is very very minimal. A little too minimal. 2. Untargetted source parameters are not declared const. 3. Slightly different expected emphasis (like _cats function which takes an ordinary C string char buffer as a parameter.) Its clear that the remainder of the C string library is still required to perform more useful string operations. The struct declaration for their string header is essentially the same as that for bstring. But its clear that this was a quickly written hack whose goals are clearly a subset of what Bstrlib supplies. For anyone who is served by stralloc, Bstrlib is complete substitute that just adds more functionality. stralloc actually uses the interesting policy that a NULL data pointer indicates an empty string. In this way, non-static empty strings can be declared without construction. This advantage is minimal, since static empty bstrings can be declared inline without construction, and if the string needs to be written to it should be constructed from an empty string (or its first initializer) in any event. wxString class -------------- This is the string class used in the wxWindows project. A description of wxString can be found here: http://www.wxwindows.org/manuals/2.4.2/wx368.htm#wxstring This C++ library is similar to CBString. However, it is littered with trivial functions (IsAscii, UpperCase, RemoveLast etc.) 1. There is no C implementation. 2. The memory management strategy is to allocate a bounded fixed amount of additional space on each resize, meaning that it does not have the log_2(n) property that Bstrlib has (it will thrash very easily, cause massive fragmentation in common heap implementations, and can easily be a common source of performance problems). 3. The library uses a "copy on write" strategy, meaning that it has to deal with multithreading problems. Vstr ---- This is a highly orthogonal C string library with an emphasis on networking/realtime programming. It can be found here: http://www.and.org/vstr/ 1. The convoluted internal structure does not contain a '\0' char * compatible buffer, so interoperability with the C library a non-starter. 2. The API and implementation is very large (owing to its orthogonality) and can lead to difficulty in understanding its exact functionality. 3. An obvious dependency on gnu tools (confusing make configure step) 4. Uses a reference counting system, meaning that it is not likely to be thread safe. The implementation has an extreme emphasis on performance for nontrivial actions (adds, inserts and deletes are all constant or roughly O(#operations) time) following the "zero copy" principle. This trades off performance of trivial functions (character access, char buffer access/coersion, alias detection) which becomes significantly slower, as well as incremental accumulative costs for its searching/parsing functions. Whether or not Vstr wins any particular performance benchmark will depend a lot on the benchmark, but it should handily win on some, while losing dreadfully on others. The learning curve for Vstr is very steep, and it doesn't come with any obvious way to build for Windows or other platforms without gnu tools. At least one mechanism (the iterator) introduces a new undefined scenario (writing to a Vstr while iterating through it.) Vstr has a very large footprint, and is very ambitious in its total functionality. Vstr has no C++ API. Vstr usage requires context initialization via vstr_init() which must be run in a thread-local context. Given the totally reference based architecture this means that sharing Vstrings across threads is not well defined, or at least not safe from race conditions. This API is clearly geared to the older standard of fork() style multitasking in UNIX, and is not safely transportable to modern shared memory multithreading available in Linux and Windows. There is no portable external solution making the library thread safe (since it requires a mutex around each Vstr context -- not each string.) In the documentation for this library, a big deal is made of its self hosted s(n)printf-like function. This is an issue for older compilers that don't include vsnprintf(), but also an issue because Vstr has a slow conversion to '\0' terminated char * mechanism. That is to say, using "%s" to format data that originates from Vstr would be slow without some sort of native function to do so. Bstrlib sidesteps the issue by relying on what snprintf-like functionality does exist and having a high performance conversion to a char * compatible string so that "%s" can be used directly. Str Library ----------- This is a fairly extensive string library, that includes full unicode support and targetted at the goal of out performing MFC and STL. The architecture, similarly to MFC's CStrings, is a copy on write reference counting mechanism. http://www.utilitycode.com/str/default.aspx 1. Commercial. 2. C++ only. This library, like Vstr, uses a ref counting system. There is only so deeply I can analyze it, since I don't have a license for it. However, performance improvements over MFC's and STL, doesn't seem like a sufficient reason to move your source base to it. For example, in the future, Microsoft may improve the performance CString. It should be pointed out that performance testing of Bstrlib has indicated that its relative performance advantage versus MFC's CString and STL's std::string is at least as high as that for the Str library. libmib astrings --------------- A handful of functional extensions to the C library that add dynamic string functionality. http://www.mibsoftware.com/libmib/astring/ This package basically references strings through char ** pointers and assumes they are pointing to the top of an allocated heap entry (or NULL, in which case memory will be newly allocated from the heap.) So its still up to user to mix and match the older C string functions with these functions whenever pointer arithmetic is used (i.e., there is no leveraging of the type system to assert semantic differences between references and base strings as Bstrlib does since no new types are introduced.) Unlike Bstrlib, exact string length meta data is not stored, thus requiring a strlen() call on *every* string writing operation. The library is very small, covering only a handful of C's functions. While this is better than nothing, it is clearly slower than even the standard C library, less safe and less functional than Bstrlib. To explain the advantage of using libmib, their website shows an example of how dangerous C code: char buf[256]; char *pszExtraPath = ";/usr/local/bin"; strcpy(buf,getenv("PATH")); /* oops! could overrun! */ strcat(buf,pszExtraPath); /* Could overrun as well! */ printf("Checking...%s\n",buf); /* Some printfs overrun too! */ is avoided using libmib: char *pasz = 0; /* Must initialize to 0 */ char *paszOut = 0; char *pszExtraPath = ";/usr/local/bin"; if (!astrcpy(&pasz,getenv("PATH"))) /* malloc error */ exit(-1); if (!astrcat(&pasz,pszExtraPath)) /* malloc error */ exit(-1); /* Finally, a "limitless" printf! we can use */ asprintf(&paszOut,"Checking...%s\n",pasz);fputs(paszOut,stdout); astrfree(&pasz); /* Can use free(pasz) also. */ astrfree(&paszOut); However, compare this to Bstrlib: bstring b, out; bcatcstr (b = bfromcstr (getenv ("PATH")), ";/usr/local/bin"); out = bformat ("Checking...%s\n", bdatae (b, "")); /* if (out && b) */ fputs (bdatae (out, ""), stdout); bdestroy (b); bdestroy (out); Besides being shorter, we can see that error handling can be deferred right to the very end. Also, unlike the above two versions, if getenv() returns with NULL, the Bstrlib version will not exhibit undefined behavior. Initialization starts with the relevant content rather than an extra autoinitialization step. libclc ------ An attempt to add to the standard C library with a number of common useful functions, including additional string functions. http://libclc.sourceforge.net/ 1. Uses standard char * buffer, and adopts C 99's usage of "restrict" to pass the responsibility to guard against aliasing to the programmer. 2. Adds no safety or memory management whatsoever. 3. Most of the supplied string functions are completely trivial. The goals of libclc and Bstrlib are clearly quite different. fireString ---------- http://firestuff.org/ 1. Uses standard char * buffer, and adopts C 99's usage of "restrict" to pass the responsibility to guard against aliasing to the programmer. 2. Mixes char * and length wrapped buffers (estr) functions, doubling the API size, with safety limited to only half of the functions. Firestring was originally just a wrapper of char * functionality with extra length parameters. However, it has been augmented with the inclusion of the estr type which has similar functionality to stralloc. But firestring does not nearly cover the functional scope of Bstrlib. Safe C String Library --------------------- A library written for the purpose of increasing safety and power to C's string handling capabilities. http://www.zork.org/safestr/safestr.html 1. While the safestr_* functions are safe in of themselves, interoperating with char * string has dangerous unsafe modes of operation. 2. The architecture of safestr's causes the base pointer to change. Thus, its not practical/safe to store a safestr in multiple locations if any single instance can be manipulated. 3. Dependent on an additional error handling library. 4. Uses reference counting, meaning that it is either not thread safe or slow and not portable. I think the idea of reallocating (and hence potentially changing) the base pointer is a serious design flaw that is fatal to this architecture. True safety is obtained by having automatic handling of all common scenarios without creating implicit constraints on the user. Because of its automatic temporary clean up system, it cannot use "const" semantics on input arguments. Interesting anomolies such as: safestr_t s, t; s = safestr_replace (t = SAFESTR_TEMP ("This is a test"), SAFESTR_TEMP (" "), SAFESTR_TEMP (".")); /* t is now undefined. */ are possible. If one defines a function which takes a safestr_t as a parameter, then the function would not know whether or not the safestr_t is defined after it passes it to a safestr library function. The author recommended method for working around this problem is to examine the attributes of the safestr_t within the function which is to modify any of its parameters and play games with its reference count. I think, therefore, that the whole SAFESTR_TEMP idea is also fatally broken. The library implements immutability, optional non-resizability, and a "trust" flag. This trust flag is interesting, and suggests that applying any arbitrary sequence of safestr_* function calls on any set of trusted strings will result in a trusted string. It seems to me, however, that if one wanted to implement a trusted string semantic, one might do so by actually creating a different *type* and only implement the subset of string functions that are deemed safe (i.e., user input would be excluded, for example.) This, in essence, would allow the compiler to enforce trust propogation at compile time rather than run time. Non-resizability is also interesting, however, it seems marginal (i.e., to want a string that cannot be resized, yet can be modified and yet where a fixed sized buffer is undesirable.) =============================================================================== Examples -------- Dumping a line numbered file: FILE * fp; int i, ret; struct bstrList * lines; struct tagbstring prefix = bsStatic ("-> "); if (NULL != (fp = fopen ("bstrlib.txt", "rb"))) { bstring b = bread ((bNread) fread, fp); fclose (fp); if (NULL != (lines = bsplit (b, '\n'))) { for (i=0; i < lines->qty; i++) { binsert (lines->entry[i], 0, &prefix, '?'); printf ("%04d: %s\n", i, bdatae (lines->entry[i], "NULL")); } bstrListDestroy (lines); } bdestroy (b); } For numerous other examples, see bstraux.c, bstraux.h and the example archive. =============================================================================== License ------- The Better String Library is available under either the BSD license (see the accompanying license.txt) or the Gnu Public License version 2 (see the accompanying gpl.txt) at the option of the user. =============================================================================== Acknowledgements ---------------- The following individuals have made significant contributions to the design and testing of the Better String Library: Bjorn Augestad Clint Olsen Darryl Bleau Fabian Cenedese Graham Wideman Ignacio Burgueno International Business Machines Corporation Ira Mica John Kortink Manuel Woelker Marcel van Kervinck Michael Hsieh Richard A. Smith Simon Ekstrom Wayne Scott =============================================================================== allegro5-5.2.10.1/src/misc/list.c000066400000000000000000000357741473414355200163410ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Double linked list. * * By Michał Cichoń. * * See readme.txt for copyright information. * * * This is a simple general purpose double linked list. * * This module is NOT thread-safe. */ #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_list.h" ALLEGRO_DEBUG_CHANNEL("list") /* Definition of list, holds root and size. */ struct _AL_LIST { /* Root of the list. It is an element, but * not visible one. Using it end and the * beginning can be easily identified. */ _AL_LIST_ITEM* root; size_t size; size_t capacity; size_t item_size; size_t item_size_with_extra; _AL_LIST_ITEM* next_free; void* user_data; _AL_LIST_DTOR dtor; }; /* List item, holds user data and destructor. */ struct _AL_LIST_ITEM { _AL_LIST* list; _AL_LIST_ITEM* next; _AL_LIST_ITEM* prev; void* data; _AL_LIST_ITEM_DTOR dtor; }; /* List of the internal functions. */ static _AL_LIST* list_do_create(size_t capacity, size_t item_extra_size); static bool list_is_static(_AL_LIST* list); static _AL_LIST_ITEM* list_get_free_item(_AL_LIST* list); static _AL_LIST_ITEM* list_create_item(_AL_LIST* list); static void list_destroy_item(_AL_LIST* list, _AL_LIST_ITEM* item); /* * Create an instance of double linked list. * * Parameters: * capacity [in] * Maximum number of elements list can hold. If it is zero, list is * created as fully dynamic linked list with unlimited item count. * For any other positive number static linked list is created, * memory for all elements is allocated once and then used. * * extra_item_size [in] * Number of extra bytes which should be left after each list item. * It is currently not used, so default value is zero. * * Returns: * Pointer to new instance of double linked list. * * Remarks: * There are two kind of double linked list supported: dynamic and static. * For dynamic linked list each item is allocated while adding and freed * while removing. This kind of list does not have capacity limit but * suffer from memory allocation delay. * Static linked list use one memory allocation and are hold as solid * piece of memory. This kind of list have capacity, but adding and * removing elements is very cheap operation. */ static _AL_LIST* list_do_create(size_t capacity, size_t extra_item_size) { size_t i; size_t memory_size; uint8_t* memory_ptr; _AL_LIST* list = NULL; _AL_LIST_ITEM* item = NULL; _AL_LIST_ITEM* prev = NULL; /* Calculate amount of memory needed for the list. * Always at least one element is allocated together with list, * which is intended to be a root. */ memory_size = sizeof(_AL_LIST) + (capacity + 1) * (sizeof(_AL_LIST_ITEM) + extra_item_size); memory_ptr = (uint8_t*)al_malloc(memory_size); if (NULL == memory_ptr) { ALLEGRO_ERROR("Out of memory."); return NULL; } list = (_AL_LIST*)memory_ptr; memory_ptr += sizeof(_AL_LIST); list->size = 0; list->capacity = capacity; list->item_size = sizeof(_AL_LIST_ITEM); list->item_size_with_extra = sizeof(_AL_LIST_ITEM) + extra_item_size; list->next_free = (_AL_LIST_ITEM*)memory_ptr; list->user_data = NULL; list->dtor = NULL; /* Initialize free item list. */ prev = NULL; item = list->next_free; for (i = 0; i <= list->capacity; ++i) { memory_ptr += list->item_size_with_extra; item->list = list; item->next = (_AL_LIST_ITEM*)memory_ptr; prev = item; item = item->next; } /* Set proper free list tail value. */ prev->next = NULL; /* Initialize root. */ list->root = list_get_free_item(list); list->root->dtor = NULL; list->root->next = list->root; list->root->prev = list->root; return list; } /* * Returns true if 'list' point to static double linked list. */ static bool list_is_static(_AL_LIST* list) { return 0 != list->capacity; } /* * Returns free item from internal list. Call to this function * is valid only for static lists. */ static _AL_LIST_ITEM* list_get_free_item(_AL_LIST* list) { _AL_LIST_ITEM* item; //thedmd: disabled, root is always static-like element and this method // is called even for dynamic lists //ASSERT(list_is_static(list)); item = list->next_free; if (NULL != item) list->next_free = item->next; return item; } /* * Create an instance of new double linked list item. */ static _AL_LIST_ITEM* list_create_item(_AL_LIST* list) { _AL_LIST_ITEM* item = NULL; if (list_is_static(list)) { /* Items from internal list already are partially initialized. * So we do not have to setup list pointer. */ item = list_get_free_item(list); } else { item = (_AL_LIST_ITEM*)al_malloc(list->item_size_with_extra); item->list = list; } return item; } /* * Destroys double linked list item. Item destructor is called * when necessary. */ static void list_destroy_item(_AL_LIST* list, _AL_LIST_ITEM* item) { ASSERT(list == item->list); if (NULL != item->dtor) item->dtor(item->data, list->user_data); if (list_is_static(list)) { item->next = list->next_free; list->next_free = item; } else al_free(item); } /* * Create new instance of dynamic double linked list. * * See: * list_do_create */ _AL_LIST* _al_list_create(void) { return list_do_create(0, 0); } /* * Create new instance of list item. Maximum number of list items is * limited by capacity. * * See: * list_do_create */ _AL_LIST* _al_list_create_static(size_t capacity) { if (capacity < 1) { ALLEGRO_ERROR("Cannot create static list without any capacity."); return NULL; } return list_do_create(capacity, 0); } /* * Destroys instance of the list. All elements * that list contain are also destroyed. */ void _al_list_destroy(_AL_LIST* list) { if (NULL == list) return; if (list->dtor) list->dtor(list->user_data); _al_list_clear(list); al_free(list); } /* * Sets a destructor for the list. */ void _al_list_set_dtor(_AL_LIST* list, _AL_LIST_DTOR dtor) { list->dtor = dtor; } /* * Returns destructor of the list. */ _AL_LIST_DTOR _al_list_get_dtor(_AL_LIST* list) { return list->dtor; } /* * Create and push new item at the beginning of the list. * * Returns pointer to new item. */ _AL_LIST_ITEM* _al_list_push_front(_AL_LIST* list, void* data) { return _al_list_insert_after(list, list->root, data); } /* * Pretty the same as _al_list_push_front(), but also allow * to provide custom destructor for the item. */ _AL_LIST_ITEM* _al_list_push_front_ex(_AL_LIST* list, void* data, _AL_LIST_ITEM_DTOR dtor) { return _al_list_insert_after_ex(list, list->root, data, dtor); } /* * Create and push new item at the end of the list. * * Returns pointer to new item. */ _AL_LIST_ITEM* _al_list_push_back(_AL_LIST* list, void* data) { return _al_list_insert_before(list, list->root, data); } /* * Pretty the same as _al_list_push_back(), but also allow * to provide custom destructor for the item. */ _AL_LIST_ITEM* _al_list_push_back_ex(_AL_LIST* list, void* data, _AL_LIST_ITEM_DTOR dtor) { return _al_list_insert_before_ex(list, list->root, data, dtor); } /* * Remove first item in the list. */ void _al_list_pop_front(_AL_LIST* list) { if (list->size > 0) _al_list_erase(list, list->root->next); } /* * Remove last item in the list. */ void _al_list_pop_back(_AL_LIST* list) { if (list->size > 0) _al_list_erase(list, list->root->prev); } /* * Create and insert new item after one specified by 'where'. * * Returns pointer to new item. */ _AL_LIST_ITEM* _al_list_insert_after(_AL_LIST* list, _AL_LIST_ITEM* where, void* data) { return _al_list_insert_after_ex(list, where, data, NULL); } /* * Pretty the same as _al_list_insert_after(), but also allow * to provide custom destructor for the item. */ _AL_LIST_ITEM* _al_list_insert_after_ex(_AL_LIST* list, _AL_LIST_ITEM* where, void* data, _AL_LIST_ITEM_DTOR dtor) { _AL_LIST_ITEM* item; ASSERT(list == where->list); item = list_create_item(list); if (NULL == item) return NULL; item->data = data; item->dtor = dtor; item->prev = where; item->next = where->next; where->next->prev = item; where->next = item; list->size++; return item; } /* * Create and insert new item before one specified by 'where'. * * Returns pointer to new item. */ _AL_LIST_ITEM* _al_list_insert_before(_AL_LIST* list, _AL_LIST_ITEM* where, void* data) { return _al_list_insert_before_ex(list, where, data, NULL); } /* * Pretty the same as _al_list_insert_before(), but also allow * to provide custom destructor for the item. */ _AL_LIST_ITEM* _al_list_insert_before_ex(_AL_LIST* list, _AL_LIST_ITEM* where, void* data, _AL_LIST_ITEM_DTOR dtor) { _AL_LIST_ITEM* item; ASSERT(list == where->list); item = list_create_item(list); if (NULL == item) return NULL; item->data = data; item->dtor = dtor; item->next = where; item->prev = where->prev; where->prev->next = item; where->prev = item; list->size++; return item; } /* * Remove specified item from the list. */ void _al_list_erase(_AL_LIST* list, _AL_LIST_ITEM* item) { if (NULL == item) return; ASSERT(list == item->list); item->prev->next = item->next; item->next->prev = item->prev; list->size--; list_destroy_item(list, item); } /* * Remove all items from the list. */ void _al_list_clear(_AL_LIST* list) { _AL_LIST_ITEM* item; _AL_LIST_ITEM* next; item = _al_list_front(list); while (NULL != item) { next = _al_list_next(list, item); _al_list_erase(list, item); item = next; } } /* * Remove all occurrences of specified value in the list. */ void _al_list_remove(_AL_LIST* list, void* data) { _AL_LIST_ITEM* item = NULL; _AL_LIST_ITEM* next = NULL; item = _al_list_find_first(list, data); while (NULL != item) { next = _al_list_find_after(list, item, data); _al_list_erase(list, item); item = next; } } /* * Returns true if list is empty. */ bool _al_list_is_empty(_AL_LIST* list) { return 0 == list->size; } /* * Returns true if list contain specified value. */ bool _al_list_contains(_AL_LIST* list, void* data) { return NULL != _al_list_find_first(list, data); } /* * Returns first occurrence of specified value in the list. */ _AL_LIST_ITEM* _al_list_find_first(_AL_LIST* list, void* data) { return _al_list_find_after(list, list->root, data); } /* * Returns last occurrence of specified value in the list. */ _AL_LIST_ITEM* _al_list_find_last(_AL_LIST* list, void* data) { return _al_list_find_before(list, list->root, data); } /* * Return occurrence of specified value in the list after 'where' item. */ _AL_LIST_ITEM* _al_list_find_after(_AL_LIST* list, _AL_LIST_ITEM* where, void* data) { _AL_LIST_ITEM* item; ASSERT(list == where->list); for (item = where->next; item != list->root; item = item->next) if (item->data == data) return item; return NULL; } /* * Return occurrence of specified value in the list before 'where' item. */ _AL_LIST_ITEM* _al_list_find_before(_AL_LIST* list, _AL_LIST_ITEM* where, void* data) { _AL_LIST_ITEM* item; ASSERT(list == where->list); for (item = where->prev; item != list->root; item = item->prev) if (item->data == data) return item; return NULL; } /* * Returns current size of the list. */ size_t _al_list_size(_AL_LIST* list) { return list->size; } /* * Returns item located at specified index. */ _AL_LIST_ITEM* _al_list_at(_AL_LIST* list, size_t index) { if (index >= list->size) return NULL; if (index < list->size / 2) { _AL_LIST_ITEM* item = list->root->next; while (index--) item = item->next; return item; } else { _AL_LIST_ITEM* item = list->root->prev; index = list->size - index - 1; while (index--) item = item->prev; return item; } } /* * Returns first item in the list. */ _AL_LIST_ITEM* _al_list_front(_AL_LIST* list) { if (list->size > 0) return list->root->next; else return NULL; } /* * Returns last item in the list. */ _AL_LIST_ITEM* _al_list_back(_AL_LIST* list) { if (list->size > 0) return list->root->prev; else return NULL; } /* * Returns next element in the list. */ _AL_LIST_ITEM* _al_list_next(_AL_LIST* list, _AL_LIST_ITEM* item) { ASSERT(list == item->list); (void)list; if (item->next != item->list->root) return item->next; else return NULL; } /* * Returns previous element in the list. */ _AL_LIST_ITEM* _al_list_previous(_AL_LIST* list, _AL_LIST_ITEM* item) { ASSERT(list == item->list); (void)list; if (item->prev != item->list->root) return item->prev; else return NULL; } /* * Returns next element in the list. If end of the list is reached, * first element is returned instead of NULL. */ _AL_LIST_ITEM* _al_list_next_circular(_AL_LIST* list, _AL_LIST_ITEM* item) { ASSERT(list == item->list); if (item->next != item->list->root) return item->next; else return list->root->next; } /* * Returns previous element in the list. If beginning of the list is reached, * last element is returned instead of NULL. */ _AL_LIST_ITEM* _al_list_previous_circular(_AL_LIST* list, _AL_LIST_ITEM* item) { ASSERT(list == item->list); if (item->prev != item->list->root) return item->prev; else return list->root->prev; } /* * Returns value associated with specified item. */ void* _al_list_item_data(_AL_LIST_ITEM* item) { return item->data; } /* * Sets item destructor. */ void _al_list_item_set_dtor(_AL_LIST_ITEM* item, _AL_LIST_ITEM_DTOR dtor) { item->dtor = dtor; } /* * Returns item destructor. */ _AL_LIST_ITEM_DTOR _al_list_item_get_dtor(_AL_LIST_ITEM* item) { return item->dtor; } /* * Sets user data for list. This pointer is passed to list destructor. */ void _al_list_set_user_data(_AL_LIST* list, void* user_data) { list->user_data = user_data; } /* * Returns user data for list. */ void* _al_list_get_user_data(_AL_LIST* list) { return list->user_data; } allegro5-5.2.10.1/src/misc/vector.c000066400000000000000000000212361473414355200166540ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Vectors, aka growing arrays. * * By Peter Wang. * * See readme.txt for copyright information. * * * This is a simple growing array to hold objects of various sizes, * growing by powers of two as needed. At the moment the vector never * shrinks, except when it is freed. Usually the vector would hold * pointers to objects, not the objects themselves, as the vector is * allowed to move the objects around. * * This module is NOT thread-safe. */ /* Internal Title: Vectors */ #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_vector.h" /* return the given item's starting address in the vector */ #define ITEM_START(vec, idx) (vec->_items + ((idx) * vec->_itemsize)) /* Internal function: _al_vector_init * * Initialise a vector. ITEMSIZE is the number of bytes to allocate for * each item in the vector. * * Alternatively, you can statically initialise a vector using * _AL_VECTOR vec = _AL_VECTOR_INITIALIZER(itemtype); */ void _al_vector_init(_AL_VECTOR *vec, size_t itemsize) { ASSERT(vec); ASSERT(itemsize > 0); vec->_itemsize = itemsize; vec->_items = NULL; vec->_size = 0; vec->_unused = 0; } /* * Simple inline functions: * * size_t _al_vector_size(const _AL_VECTOR *vec); * bool _al_vector_is_empty(const _AL_VECTOR*); */ /* Internal function: _al_vector_ref * * Return a pointer to the SLOT in the vector given by INDEX. The returned * address should only be used while the vector is not modified; after that * it is invalid. * * Tip: If you are storing pointers in the vector, you need to dereference * the returned value! */ void *_al_vector_ref(const _AL_VECTOR *vec, unsigned int idx) { ASSERT(vec); ASSERT(idx < vec->_size); return ITEM_START(vec, idx); } /* Internal function: _al_vector_ref_front * Convenience function. */ void* _al_vector_ref_front(const _AL_VECTOR *vec) { return _al_vector_ref(vec, 0); } /* Internal function: _al_vector_ref_back * Convenience function. */ void* _al_vector_ref_back(const _AL_VECTOR *vec) { ASSERT(vec); return _al_vector_ref(vec, vec->_size-1); } /* Internal function: _al_vector_append_array * Append `num` elements from `arr` array to _AL_VECTOR `vec` */ bool _al_vector_append_array(_AL_VECTOR *vec, unsigned int num, const void *arr) { ASSERT(vec); ASSERT(arr); ASSERT(num); if (vec->_items == NULL) { ASSERT(vec->_size == 0); ASSERT(vec->_unused == 0); vec->_items = al_malloc(vec->_itemsize * num); ASSERT(vec->_items); if (!vec->_items) return false; vec->_unused = num; } else if (vec->_unused < num) { char *new_items; new_items = al_realloc(vec->_items, (vec->_size + num) * vec->_itemsize); ASSERT(new_items); if (!new_items) return false; vec->_items = new_items; vec->_unused = num; } memcpy(vec->_items + (vec->_size * vec->_itemsize), arr, vec->_itemsize * num); vec->_size += num; vec->_unused -= num; return true; } /* Internal function: _al_vector_alloc_back * * Allocate a block of memory at the back of the vector of the vector's item * size (see _AL_VECTOR_INITIALIZER and _al_vector_init). Returns a pointer * to the start of this block. This address should only be used while the * vector is not modified; after that it is invalid. You may fill the block * with whatever you want. * * Example: * _AL_VECTOR vec = _AL_VECTOR_INITIALIZER(struct boo); * struct boo *thing = _al_vector_alloc_back(&vec); * thing->aaa = 100; * thing->bbb = "a string"; */ void* _al_vector_alloc_back(_AL_VECTOR *vec) { ASSERT(vec); ASSERT(vec->_itemsize > 0); { if (vec->_items == NULL) { ASSERT(vec->_size == 0); ASSERT(vec->_unused == 0); vec->_items = al_malloc(vec->_itemsize); ASSERT(vec->_items); if (!vec->_items) return NULL; vec->_unused = 1; } else if (vec->_unused == 0) { char *new_items = al_realloc(vec->_items, 2 * vec->_size * vec->_itemsize); ASSERT(new_items); if (!new_items) return NULL; vec->_items = new_items; vec->_unused = vec->_size; } vec->_size++; vec->_unused--; return ITEM_START(vec, vec->_size-1); } } /* Internal function: _al_vector_alloc_mid * * Allocate a block of memory in the middle of the vector of the vector's * item * size (see _AL_VECTOR_INITIALIZER and _al_vector_init). Returns a pointer * to the start of this block. This address should only be used while the * vector is not modified; after that it is invalid. You may fill the block * with whatever you want. */ void* _al_vector_alloc_mid(_AL_VECTOR *vec, unsigned int index) { ASSERT(vec); ASSERT(vec->_itemsize > 0); { if (vec->_items == NULL) { ASSERT(index == 0); return _al_vector_alloc_back(vec); } if (vec->_unused == 0) { char *new_items = al_realloc(vec->_items, 2 * vec->_size * vec->_itemsize); ASSERT(new_items); if (!new_items) return NULL; vec->_items = new_items; vec->_unused = vec->_size; } memmove(ITEM_START(vec, index + 1), ITEM_START(vec, index), vec->_itemsize * (vec->_size - index)); vec->_size++; vec->_unused--; return ITEM_START(vec, index); } } /* Internal function: _al_vector_find * * Find the slot in the vector where the contents of the slot * match whatever PTR_ITEM points to, bit-for-bit. If no such * slot is found, a negative number is returned (currently -1). */ int _al_vector_find(const _AL_VECTOR *vec, const void *ptr_item) { ASSERT(vec); ASSERT(ptr_item); if (vec->_itemsize == sizeof(void *)) { /* fast path for pointers */ void **items = (void **)vec->_items; unsigned int i; for (i = 0; i < vec->_size; i++) if (items[i] == *(void **)ptr_item) return i; } else { /* slow path */ unsigned int i; for (i = 0; i < vec->_size; i++) if (memcmp(ITEM_START(vec, i), ptr_item, vec->_itemsize) == 0) return i; } return -1; } /* Internal function: _al_vector_contains * A simple wrapper over _al_vector_find. */ bool _al_vector_contains(const _AL_VECTOR *vec, const void *ptr_item) { return _al_vector_find(vec, ptr_item) >= 0; } /* Internal function: _al_vector_delete_at * * Delete the slot given by index. Deleting from the start or middle of the * vector requires moving the rest of the vector towards the front, so it is * better to delete from the tail of the vector. * * Example: * while (!_al_vector_is_empty(&v)) * _al_vector_delete_at(&v, _al_vector_size(&v)-1); */ void _al_vector_delete_at(_AL_VECTOR *vec, unsigned int idx) { ASSERT(vec); ASSERT(idx < vec->_size); { int to_move = vec->_size - idx - 1; if (to_move > 0) memmove(ITEM_START(vec, idx), ITEM_START(vec, idx+1), to_move * vec->_itemsize); vec->_size--; vec->_unused++; memset(ITEM_START(vec, vec->_size), 0, vec->_itemsize); } } /* Internal function: _al_vector_find_and_delete * * Similar to _al_vector_delete_at(_al_vector_find(vec, ptr_item)) but is * lenient if the item is not found. Returns true if the item was found and * deleted. */ bool _al_vector_find_and_delete(_AL_VECTOR *vec, const void *ptr_item) { int idx = _al_vector_find(vec, ptr_item); if (idx >= 0) { _al_vector_delete_at(vec, idx); return true; } else return false; } /* Internal function: _al_vector_free * * Free the space used by the vector. You really must do this at some * stage. It is not enough to delete all the items in the vector (which you * should usually do also). */ void _al_vector_free(_AL_VECTOR *vec) { ASSERT(vec); if (vec->_items != NULL) { al_free(vec->_items); vec->_items = NULL; } vec->_size = 0; vec->_unused = 0; } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ allegro5-5.2.10.1/src/monitor.c000066400000000000000000000040231473414355200161010ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Monitor queries. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_system.h" /* Function: al_get_num_video_adapters */ int al_get_num_video_adapters(void) { ALLEGRO_SYSTEM *system = al_get_system_driver(); if (system && system->vt && system->vt->get_num_video_adapters) { return system->vt->get_num_video_adapters(); } return 0; } /* Function: al_get_monitor_refresh_rate */ int al_get_monitor_refresh_rate(int adapter) { ALLEGRO_SYSTEM *system = al_get_system_driver(); if (adapter < al_get_num_video_adapters()) { if (system && system->vt && system->vt->get_monitor_refresh_rate) { return system->vt->get_monitor_refresh_rate(adapter); } } return 0; } /* Function: al_get_monitor_info */ bool al_get_monitor_info(int adapter, ALLEGRO_MONITOR_INFO *info) { ALLEGRO_SYSTEM *system = al_get_system_driver(); if (adapter < al_get_num_video_adapters()) { if (system && system->vt && system->vt->get_monitor_info) { return system->vt->get_monitor_info(adapter, info); } } info->x1 = info->y1 = info->x2 = info->y2 = INT_MAX; return false; } /* Function: al_get_monitor_dpi */ int al_get_monitor_dpi(int adapter) { ALLEGRO_SYSTEM *system = al_get_system_driver(); if (adapter < al_get_num_video_adapters()) { if (system && system->vt && system->vt->get_monitor_dpi) { return system->vt->get_monitor_dpi(adapter); } } return 0; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/mouse_cursor.c000066400000000000000000000053751473414355200171520ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Mouse cursors. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_system.h" /* Function: al_create_mouse_cursor */ ALLEGRO_MOUSE_CURSOR *al_create_mouse_cursor(ALLEGRO_BITMAP *bmp, int x_focus, int y_focus) { ALLEGRO_SYSTEM *sysdrv = al_get_system_driver(); ASSERT(bmp); ASSERT(sysdrv->vt->create_mouse_cursor); return sysdrv->vt->create_mouse_cursor(bmp, x_focus, y_focus); } /* Function: al_destroy_mouse_cursor */ void al_destroy_mouse_cursor(ALLEGRO_MOUSE_CURSOR *cursor) { ALLEGRO_SYSTEM *sysdrv; if (!cursor) { return; } sysdrv = al_get_system_driver(); ASSERT(sysdrv->vt->destroy_mouse_cursor); sysdrv->vt->destroy_mouse_cursor(cursor); } /* Function: al_set_mouse_cursor */ bool al_set_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_MOUSE_CURSOR *cursor) { if (!cursor) { return false; } if (display) { ASSERT(display->vt->set_mouse_cursor); return display->vt->set_mouse_cursor(display, cursor); } return false; } /* Function: al_set_system_mouse_cursor */ bool al_set_system_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id) { /* XXX should you be able to set ALLEGRO_SYSTEM_MOUSE_CURSOR_NONE? */ ASSERT(cursor_id > ALLEGRO_SYSTEM_MOUSE_CURSOR_NONE); ASSERT(cursor_id < ALLEGRO_NUM_SYSTEM_MOUSE_CURSORS); ASSERT(display); if (cursor_id <= ALLEGRO_SYSTEM_MOUSE_CURSOR_NONE) { return false; } if (cursor_id > ALLEGRO_NUM_SYSTEM_MOUSE_CURSORS) { return false; } if (!display) { return false; } ASSERT(display->vt->set_system_mouse_cursor); return display->vt->set_system_mouse_cursor(display, cursor_id); } /* Function: al_show_mouse_cursor */ bool al_show_mouse_cursor(ALLEGRO_DISPLAY *display) { if (display) { ASSERT(display->vt->show_mouse_cursor); return display->vt->show_mouse_cursor(display); } return false; } /* Function: al_hide_mouse_cursor */ bool al_hide_mouse_cursor(ALLEGRO_DISPLAY *display) { if (display) { ASSERT(display->vt->hide_mouse_cursor); return display->vt->hide_mouse_cursor(display); } return false; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/mousenu.c000066400000000000000000000151361473414355200161140ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * New mouse API. * * By Peter Wang. * * See readme.txt for copyright information. */ /* Title: Mouse routines */ #define ALLEGRO_NO_COMPATIBILITY #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_mouse.h" #include "allegro5/internal/aintern_system.h" /* the active keyboard driver */ static ALLEGRO_MOUSE_DRIVER *new_mouse_driver = NULL; /* Function: al_is_mouse_installed */ bool al_is_mouse_installed(void) { return (new_mouse_driver ? true : false); } /* Function: al_install_mouse */ bool al_install_mouse(void) { if (new_mouse_driver) return true; //FIXME: seems A4/A5 driver list stuff doesn't quite agree right now if (al_get_system_driver()->vt->get_mouse_driver) { new_mouse_driver = al_get_system_driver()->vt->get_mouse_driver(); if (!new_mouse_driver->init_mouse()) { new_mouse_driver = NULL; return false; } _al_add_exit_func(al_uninstall_mouse, "al_uninstall_mouse"); return true; } return false; #if 0 if (system_driver && system_driver->mouse_drivers) driver_list = system_driver->mouse_drivers(); else driver_list = _al_mouse_driver_list; ASSERT(driver_list); for (i=0; driver_list[i].driver; i++) { new_mouse_driver = driver_list[i].driver; //name = get_config_text(new_mouse_driver->msedrv_ascii_name); name = new_mouse_driver->msedrv_ascii_name; new_mouse_driver->msedrv_name = name; new_mouse_driver->msedrv_desc = name; if (new_mouse_driver->init_mouse()) { break; } } if (!driver_list[i].driver) { new_mouse_driver = NULL; return false; } _al_add_exit_func(al_uninstall_mouse, "al_uninstall_mouse"); return true; #endif } /* Function: al_uninstall_mouse */ void al_uninstall_mouse(void) { if (!new_mouse_driver) return; new_mouse_driver->exit_mouse(); new_mouse_driver = NULL; } /* This was in the public API but its only purpose is now served by * al_get_mouse_event_source(). */ static ALLEGRO_MOUSE *al_get_mouse(void) { ALLEGRO_MOUSE *mse; ASSERT(new_mouse_driver); mse = new_mouse_driver->get_mouse(); ASSERT(mse); return mse; } /* Function: al_get_mouse_num_buttons */ unsigned int al_get_mouse_num_buttons(void) { ASSERT(new_mouse_driver); return new_mouse_driver->get_mouse_num_buttons(); } /* Function: al_get_mouse_num_axes */ unsigned int al_get_mouse_num_axes(void) { ASSERT(new_mouse_driver); return new_mouse_driver->get_mouse_num_axes(); } /* Function: al_set_mouse_xy */ bool al_set_mouse_xy(ALLEGRO_DISPLAY *display, int x, int y) { ASSERT(new_mouse_driver); ASSERT(new_mouse_driver->set_mouse_xy); return new_mouse_driver->set_mouse_xy(display, x, y); } /* Function: al_set_mouse_z */ bool al_set_mouse_z(int z) { ASSERT(new_mouse_driver); ASSERT(new_mouse_driver->set_mouse_axis); return new_mouse_driver->set_mouse_axis(2, z); } /* Function: al_set_mouse_w */ bool al_set_mouse_w(int w) { ASSERT(new_mouse_driver); ASSERT(new_mouse_driver->set_mouse_axis); return new_mouse_driver->set_mouse_axis(3, w); } /* Function: al_set_mouse_axis */ bool al_set_mouse_axis(int which, int value) { ASSERT(new_mouse_driver); ASSERT(new_mouse_driver->set_mouse_axis); ASSERT(which >= 2); ASSERT(which < 4 + ALLEGRO_MOUSE_MAX_EXTRA_AXES); if (which >= 2 && which < 4 + ALLEGRO_MOUSE_MAX_EXTRA_AXES) return new_mouse_driver->set_mouse_axis(which, value); else return false; } /* Function: al_get_mouse_state */ void al_get_mouse_state(ALLEGRO_MOUSE_STATE *ret_state) { ASSERT(new_mouse_driver); ASSERT(ret_state); new_mouse_driver->get_mouse_state(ret_state); } /* Function: al_get_mouse_state_axis */ int al_get_mouse_state_axis(const ALLEGRO_MOUSE_STATE *state, int axis) { ASSERT(state); ASSERT(axis >= 0); ASSERT(axis < (4 + ALLEGRO_MOUSE_MAX_EXTRA_AXES)); switch (axis) { case 0: return state->x; case 1: return state->y; case 2: return state->z; case 3: return state->w; default: return state->more_axes[axis - 4]; } } /* Function: al_mouse_button_down */ bool al_mouse_button_down(const ALLEGRO_MOUSE_STATE *state, int button) { ASSERT(state); ASSERT(button > 0); return (state->buttons & (1 << (button-1))); } /* Function: al_can_get_mouse_cursor_position */ bool al_can_get_mouse_cursor_position(void) { ALLEGRO_SYSTEM *alsys = al_get_system_driver(); return alsys->vt->get_cursor_position; } /* Function: al_get_mouse_cursor_position */ bool al_get_mouse_cursor_position(int *ret_x, int *ret_y) { ALLEGRO_SYSTEM *alsys = al_get_system_driver(); ASSERT(ret_x); ASSERT(ret_y); if (alsys->vt->get_cursor_position) { return alsys->vt->get_cursor_position(ret_x, ret_y); } else { *ret_x = 0; *ret_y = 0; return false; } } /* Function: al_grab_mouse */ bool al_grab_mouse(ALLEGRO_DISPLAY *display) { ALLEGRO_SYSTEM *alsys = al_get_system_driver(); if (alsys->vt->grab_mouse) return alsys->vt->grab_mouse(display); return false; } /* Function: al_ungrab_mouse */ bool al_ungrab_mouse(void) { ALLEGRO_SYSTEM *alsys = al_get_system_driver(); if (alsys->vt->ungrab_mouse) return alsys->vt->ungrab_mouse(); return false; } /* Function: al_get_mouse_event_source */ ALLEGRO_EVENT_SOURCE *al_get_mouse_event_source(void) { ALLEGRO_MOUSE *mouse = al_get_mouse(); return (mouse) ? &mouse->es : NULL; } /* Function: al_set_mouse_wheel_precision */ void al_set_mouse_wheel_precision(int precision) { ALLEGRO_SYSTEM *alsys = al_get_system_driver(); ASSERT(alsys); if (precision < 1) precision = 1; alsys->mouse_wheel_precision = precision; } /* Function: al_get_mouse_wheel_precision */ int al_get_mouse_wheel_precision(void) { ALLEGRO_SYSTEM *alsys = al_get_system_driver(); ASSERT(alsys); return alsys->mouse_wheel_precision; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/opengl/000077500000000000000000000000001473414355200155335ustar00rootroot00000000000000allegro5-5.2.10.1/src/opengl/extensions.c000066400000000000000000000627411473414355200201100ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * OpenGL extensions management subsystem * * By Elias Pschernig and Milan Mimica. * * Based on AllegroGL extensions management. */ #include #include #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/opengl/gl_ext.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_system.h" /* We need some driver specific details not worth of a vtable entry. */ #if defined ALLEGRO_WINDOWS #include "../win/wgl.h" #elif defined ALLEGRO_UNIX && !defined ALLEGRO_EXCLUDE_GLX #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xsystem.h" #endif #if defined __APPLE__ && !defined ALLEGRO_IPHONE #include #elif !defined ALLEGRO_CFG_OPENGLES #include #endif ALLEGRO_DEBUG_CHANNEL("opengl") #ifdef ALLEGRO_HAVE_DYNAMIC_LINK #include /* Handle for dynamic library libGL.so */ static void *__libgl_handle = NULL; /* Pointer to glXGetProcAddressARB */ typedef void *(*GLXGETPROCADDRESSARBPROC) (const GLubyte *); static GLXGETPROCADDRESSARBPROC alXGetProcAddress; #else /* #ifdef ALLEGRO_HAVE_DYNAMIC_LINK */ /* Tries static linking */ /* FIXME: set ALLEGRO_GLXGETPROCADDRESSARB on configure time, if * glXGetProcAddressARB must be used! */ #if defined ALLEGRO_GLXGETPROCADDRESSARB #define alXGetProcAddress glXGetProcAddressARB #elif defined ALLEGRO_RASPBERRYPI #define alXGetProcAddress eglGetProcAddress #else #define alXGetProcAddress glXGetProcAddress #endif #endif /* #ifdef ALLEGRO_HAVE_DYNAMIC_LINK */ #ifdef ALLEGRO_MACOSX #include static CFBundleRef opengl_bundle_ref; #endif /* Define the GL API pointers. * Example: * _ALLEGRO_glBlendEquation_t _al_glBlendEquation = NULL; */ #define AGL_API(type, name, args) _ALLEGRO_gl##name##_t _al_gl##name = NULL; # include "allegro5/opengl/GLext/gl_ext_api.h" #undef AGL_API #ifdef ALLEGRO_WINDOWS #define AGL_API(type, name, args) _ALLEGRO_wgl##name##_t _al_wgl##name = NULL; # include "allegro5/opengl/GLext/wgl_ext_api.h" #undef AGL_API #elif defined ALLEGRO_UNIX #define AGL_API(type, name, args) _ALLEGRO_glX##name##_t _al_glX##name = NULL; # include "allegro5/opengl/GLext/glx_ext_api.h" #undef AGL_API #endif static uint32_t parse_opengl_version(const char *s) { char *p = (char *) s; int v[4] = {0, 0, 0, 0}; int n; uint32_t ver; /* For OpenGL ES version strings have the form: * "OpenGL ES- ." * So for example: "OpenGL ES-CM 2.0". We simply skip any non-digit * characters and then parse it like for normal OpenGL. */ while (*p && !isdigit(*p)) { p++; } /* e.g. "4.0.0 Vendor blah blah" */ for (n = 0; n < 4; n++) { char *end; long l; errno = 0; l = strtol(p, &end, 10); if (errno) break; v[n] = _ALLEGRO_CLAMP(0, l, 255); if (*end != '.') break; p = end + 1; /* skip dot */ } ver = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3]; ALLEGRO_DEBUG("Parsed '%s' as 0x%08x\n", s, ver); return ver; } /* Reads version info out of glGetString(GL_VERSION) */ static uint32_t _al_ogl_version(void) { char const *value = al_get_config_value(al_get_system_config(), "opengl", "force_opengl_version"); if (value) { uint32_t v = parse_opengl_version(value); ALLEGRO_INFO("OpenGL version forced to %d.%d.%d.%d.\n", (v >> 24) & 0xff, (v >> 16) & 0xff, (v >> 8) & 0xff, (v & 0xff)); return v; } const char *str; str = (const char *)glGetString(GL_VERSION); if (str) { #ifdef ALLEGRO_CFG_OPENGLES char *str2 = strstr(str, "ES "); if (str2) str = str2 + 3; #endif return parse_opengl_version(str); } else { /* The OpenGL driver does not return a version * number. However it probably supports at least OpenGL 1.0 */ return _ALLEGRO_OPENGL_VERSION_1_0; } } /* print_extensions: * Given a string containing extensions (i.e. a NULL terminated string where * each extension are separated by a space and which names do not contain any * space) */ static void print_extensions(char const *extension) { char buf[80]; char *start; ASSERT(extension); while (*extension != '\0') { start = buf; _al_sane_strncpy(buf, extension, 80); while ((*start != ' ') && (*start != '\0')) { extension++; start++; } *start = '\0'; if (*extension != '\0') extension++; ALLEGRO_DEBUG("%s\n", buf); } } #if !defined ALLEGRO_CFG_OPENGLES /* Print all extensions the OpenGL 3.0 way. */ static void print_extensions_3_0(void) { int i; GLint n; GLubyte const *name; glGetIntegerv(GL_NUM_EXTENSIONS, &n); for (i = 0; i < n; i++) { name = glGetStringi(GL_EXTENSIONS, i); ALLEGRO_DEBUG("%s\n", name); } } #endif /* Function: al_get_opengl_version */ uint32_t al_get_opengl_version(void) { ALLEGRO_DISPLAY *ogl_disp; ogl_disp = al_get_current_display(); if (!ogl_disp || !ogl_disp->ogl_extras) return 0x0; return ogl_disp->ogl_extras->ogl_info.version; } /* NOTE: al_get_opengl_variant is pretty simple right now but may * eventually need driver support. */ /* Function: al_get_opengl_variant */ int al_get_opengl_variant(void) { #if defined ALLEGRO_CFG_OPENGLES return ALLEGRO_OPENGL_ES; #else return ALLEGRO_DESKTOP_OPENGL; #endif } /* Create the extension list */ static ALLEGRO_OGL_EXT_LIST *create_extension_list(void) { ALLEGRO_OGL_EXT_LIST *ret = al_calloc(1, sizeof(ALLEGRO_OGL_EXT_LIST)); if (!ret) { return NULL; } return ret; } /* Create the extension API table */ static ALLEGRO_OGL_EXT_API *create_extension_api_table(void) { ALLEGRO_OGL_EXT_API *ret = al_calloc(1, sizeof(ALLEGRO_OGL_EXT_API)); if (!ret) { return NULL; } return ret; } typedef void (*VOID_FPTR)(void); /* GCC 4.8.2 and possibly others are really slow at optimizing the 100's of the * if statements in the load_extensions function below, so we extract them to * this function. */ static VOID_FPTR load_extension(const char* name) { VOID_FPTR fptr = NULL; #ifdef ALLEGRO_WINDOWS fptr = (VOID_FPTR)wglGetProcAddress(name); #elif defined ALLEGRO_UNIX fptr = (VOID_FPTR)alXGetProcAddress((const GLubyte*)name); #elif defined ALLEGRO_MACOSX CFStringRef cfstr = CFStringCreateWithCStringNoCopy(NULL, name, kCFStringEncodingUTF8, kCFAllocatorNull); if (cfstr) { fptr = (VOID_FPTR)CFBundleGetFunctionPointerForName(opengl_bundle_ref, cfstr); CFRelease(cfstr); } #elif defined ALLEGRO_SDL fptr = SDL_GL_GetProcAddress(name); #endif if (fptr) { ALLEGRO_DEBUG("%s successfully loaded (%p)\n", name, fptr); } return fptr; } /* Load the extension API addresses into the table. * Should only be done on context creation. */ static void load_extensions(ALLEGRO_OGL_EXT_API *ext) { if (!ext) { return; } #ifdef ALLEGRO_UNIX #ifdef ALLEGRO_HAVE_DYNAMIC_LINK if (!alXGetProcAddress) { return; } #endif #endif #ifdef ALLEGRO_WINDOWS #define AGL_API(type, name, args) \ ext->name = (_ALLEGRO_gl##name##_t)load_extension("gl" #name); #include "allegro5/opengl/GLext/gl_ext_api.h" #undef AGL_API #define AGL_API(type, name, args) \ ext->name = (_ALLEGRO_wgl##name##_t)load_extension("wgl" #name); #include "allegro5/opengl/GLext/wgl_ext_api.h" #undef AGL_API #elif defined ALLEGRO_UNIX #define AGL_API(type, name, args) \ ext->name = (_ALLEGRO_gl##name##_t)load_extension("gl" #name); #include "allegro5/opengl/GLext/gl_ext_api.h" #undef AGL_API #define AGL_API(type, name, args) \ ext->name = (_ALLEGRO_glX##name##_t)load_extension("glX" #name); #include "allegro5/opengl/GLext/glx_ext_api.h" #undef AGL_API #elif defined ALLEGRO_MACOSX #define AGL_API(type, name, args) \ ext->name = (_ALLEGRO_gl##name##_t)load_extension("gl" # name); #include "allegro5/opengl/GLext/gl_ext_api.h" #undef AGL_API #elif defined ALLEGRO_SDL #define AGL_API(type, name, args) \ ext->name = (_ALLEGRO_gl##name##_t)load_extension("gl" # name); #include "allegro5/opengl/GLext/gl_ext_api.h" #undef AGL_API #endif } /* Set the GL API pointers to the current table * Should only be called on context switches. */ void _al_ogl_set_extensions(ALLEGRO_OGL_EXT_API *ext) { if (!ext) { return; } #define AGL_API(type, name, args) _al_gl##name = ext->name; # include "allegro5/opengl/GLext/gl_ext_api.h" #undef AGL_API #ifdef ALLEGRO_WINDOWS #define AGL_API(type, name, args) _al_wgl##name = ext->name; # include "allegro5/opengl/GLext/wgl_ext_api.h" #undef AGL_API #elif defined ALLEGRO_UNIX #define AGL_API(type, name, args) _al_glX##name = ext->name; # include "allegro5/opengl/GLext/glx_ext_api.h" #undef AGL_API #endif } /* Destroys the extension API table */ static void destroy_extension_api_table(ALLEGRO_OGL_EXT_API *ext) { if (ext) { al_free(ext); } } /* Destroys the extension list */ static void destroy_extension_list(ALLEGRO_OGL_EXT_LIST *list) { if (list) { al_free(list); } } /* _al_ogl_look_for_an_extension: * This function has been written by Mark J. Kilgard in one of his * tutorials about OpenGL extensions */ int _al_ogl_look_for_an_extension(const char *name, const GLubyte *extensions) { const GLubyte *start; GLubyte *where, *terminator; ASSERT(extensions); /* Extension names should not have spaces. */ where = (GLubyte *) strchr(name, ' '); if (where || *name == '\0') return false; /* 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; for (;;) { where = (GLubyte *) strstr((const char *)start, name); if (!where) break; terminator = where + strlen(name); if (where == start || *(where - 1) == ' ') if (*terminator == ' ' || *terminator == '\0') return true; start = terminator; } return false; } static bool _ogl_is_extension_supported(const char *extension, ALLEGRO_DISPLAY *disp) { int ret = 0; GLubyte const *ext_str; #if !defined ALLEGRO_CFG_OPENGLES int v = al_get_opengl_version(); #endif (void)disp; #if !defined ALLEGRO_CFG_OPENGLES if (disp->flags & ALLEGRO_OPENGL_3_0 || v >= _ALLEGRO_OPENGL_VERSION_3_0) { int i; GLint ext_cnt; glGetIntegerv(GL_NUM_EXTENSIONS, &ext_cnt); for (i = 0; i < ext_cnt; i++) { ext_str = glGetStringi(GL_EXTENSIONS, i); if (ext_str && !strcmp(extension, (char*)ext_str)) { ret = 1; break; } } } else #endif { ext_str = glGetString(GL_EXTENSIONS); if (!ext_str) return false; ret = _al_ogl_look_for_an_extension(extension, ext_str); } #ifdef ALLEGRO_WINDOWS if (!ret && strncmp(extension, "WGL", 3) == 0) { ALLEGRO_DISPLAY_WGL *wgl_disp = (void*)disp; _ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB; if (!wgl_disp->dc) return false; _wglGetExtensionsStringARB = (void *) wglGetProcAddress("wglGetExtensionsStringARB"); if (_wglGetExtensionsStringARB) { ret = _al_ogl_look_for_an_extension(extension, (const GLubyte *) _wglGetExtensionsStringARB(wgl_disp->dc)); } } #elif defined ALLEGRO_UNIX && !defined ALLEGRO_EXCLUDE_GLX if (!ret && strncmp(extension, "GLX", 3) == 0) { ALLEGRO_SYSTEM_XGLX *sys = (void*)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx_disp = (void*)disp; char const *ext; if (!sys->gfxdisplay) return false; ext = glXQueryExtensionsString(sys->gfxdisplay, glx_disp->xscreen); if (!ext) { /* work around driver bugs? */ ext = ""; } ret = _al_ogl_look_for_an_extension(extension, (const GLubyte *)ext); } #endif return ret; } static bool _ogl_is_extension_with_version_supported( const char *extension, ALLEGRO_DISPLAY *disp, uint32_t ver) { char const *value; /* For testing purposes, any OpenGL extension can be disable in * the config by using something like: * * [opengl_disabled_extensions] * GL_ARB_texture_non_power_of_two=0 * GL_EXT_framebuffer_object=0 * */ value = al_get_config_value(al_get_system_config(), "opengl_disabled_extensions", extension); if (value) { ALLEGRO_WARN("%s found in [opengl_disabled_extensions].\n", extension); return false; } /* If the extension is included in the OpenGL version, there is no * need to check the extensions list. */ if (ver > 0 && disp->ogl_extras->ogl_info.version >= ver) { return true; } return _ogl_is_extension_supported(extension, disp); } /* Function: al_have_opengl_extension */ bool al_have_opengl_extension(const char *extension) { ALLEGRO_DISPLAY *disp; disp = al_get_current_display(); if (!disp) return false; if (!(disp->flags & ALLEGRO_OPENGL)) return false; return _ogl_is_extension_supported(extension, disp); } /* Function: al_get_opengl_proc_address */ void *al_get_opengl_proc_address(const char *name) { void *symbol = NULL; #ifdef ALLEGRO_MACOSX CFStringRef function; #endif ALLEGRO_DISPLAY *disp; disp = al_get_current_display(); if (!disp) return NULL; if (!(disp->flags & ALLEGRO_OPENGL)) return NULL; #if defined ALLEGRO_WINDOWS /* For once Windows is the easiest platform to use :) * It provides a standardized way to get a function address * But of course there is a drawback : the symbol is only valid * under the current context :P */ { ALLEGRO_DISPLAY_WGL *wgl_disp = (void*)disp; if (!wgl_disp->dc) return NULL; symbol = wglGetProcAddress(name); } #elif defined ALLEGRO_UNIX #if defined ALLEGRO_HAVE_DYNAMIC_LINK if (alXGetProcAddress) #endif { /* This is definitely the *good* way on Unix to get a GL proc * address. Unfortunately glXGetProcAddress is an extension * and may not be available on all platforms */ #if defined ALLEGRO_RASPBERRYPI symbol = alXGetProcAddress(name); #else symbol = alXGetProcAddress((const GLubyte *)name); #endif } #elif defined ALLEGRO_HAVE_DYNAMIC_LINK else { /* Hack if glXGetProcAddress is not available : * we try to find the symbol into libGL.so */ if (__al_handle) { symbol = dlsym(__al_handle, name); } } #elif defined ALLEGRO_MACOSX function = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); if (function) { symbol = CFBundleGetFunctionPointerForName(opengl_bundle_ref, function); CFRelease(function); } #endif if (!symbol) { #if defined ALLEGRO_HAVE_DYNAMIC_LINK if (!alXGetProcAddress) { ALLEGRO_WARN("get_proc_address: libdl::dlsym: %s\n", dlerror()); } #endif ALLEGRO_WARN("get_proc_address : Unable to load symbol %s\n", name); } else { ALLEGRO_DEBUG("get_proc_address : Symbol %s successfully loaded\n", name); } return symbol; } /* fill_in_info_struct: * Fills in the OPENGL_INFO info struct for blacklisting video cards. */ static void fill_in_info_struct(const GLubyte *rendereru, OPENGL_INFO *info) { const char *renderer = (const char *)rendereru; ASSERT(renderer); /* Some cards are "special"... */ if (strstr(renderer, "3Dfx/Voodoo")) { info->is_voodoo = 1; } else if (strstr(renderer, "Matrox G200")) { info->is_matrox_g200 = 1; } else if (strstr(renderer, "RagePRO")) { info->is_ati_rage_pro = 1; } else if (strstr(renderer, "RADEON 7000")) { info->is_ati_radeon_7000 = 1; } else if (strstr(renderer, "Mesa DRI R200")) { info->is_ati_r200_chip = 1; } else if (strstr(renderer, "Intel HD Graphics 3000 OpenGL Engine")) { info->is_intel_hd_graphics_3000 = 1; } if ((strncmp(renderer, "3Dfx/Voodoo3 ", 13) == 0) || (strncmp(renderer, "3Dfx/Voodoo2 ", 13) == 0) || (strncmp(renderer, "3Dfx/Voodoo ", 12) == 0)) { info->is_voodoo3_and_under = 1; } /* Read OpenGL properties */ info->version = _al_ogl_version(); ALLEGRO_INFO("Assumed OpenGL version: %d.%d.%d.%d\n", (info->version >> 24) & 0xff, (info->version >> 16) & 0xff, (info->version >> 8) & 0xff, (info->version ) & 0xff); return; } /* _al_ogl_manage_extensions: * This functions fills the extensions API table and extension list * structures and displays on the log file which extensions are available. */ void _al_ogl_manage_extensions(ALLEGRO_DISPLAY *gl_disp) { //const GLubyte *buf; #if defined ALLEGRO_MACOSX CFURLRef bundle_url; #endif ALLEGRO_OGL_EXT_API *ext_api; ALLEGRO_OGL_EXT_LIST *ext_list; /* Some functions depend on knowing the version of opengl in use */ fill_in_info_struct(glGetString(GL_RENDERER), &(gl_disp->ogl_extras->ogl_info)); /* Print out OpenGL extensions * We should use glGetStringi(GL_EXTENSIONS, i) for OpenGL 3.0+ * but it doesn't seem to work until later. */ if (gl_disp->ogl_extras->ogl_info.version < _ALLEGRO_OPENGL_VERSION_3_0) { ALLEGRO_DEBUG("OpenGL Extensions:\n"); print_extensions((char const *)glGetString(GL_EXTENSIONS)); } /* Print out GLU version */ //buf = gluGetString(GLU_VERSION); //ALLEGRO_INFO("GLU Version : %s\n", buf); #ifdef ALLEGRO_HAVE_DYNAMIC_LINK /* Get glXGetProcAddress entry */ __libgl_handle = dlopen("libGL.so", RTLD_LAZY); if (__libgl_handle) { alXGetProcAddress = (GLXGETPROCADDRESSARBPROC) dlsym(__libgl_handle, "glXGetProcAddressARB"); if (!alXGetProcAddress) { alXGetProcAddress = (GLXGETPROCADDRESSARBPROC) dlsym(__libgl_handle, "glXGetProcAddress"); if (!alXGetProcAddress) { alXGetProcAddress = (GLXGETPROCADDRESSARBPROC) dlsym(__libgl_handle, "eglGetProcAddress"); } } } else { ALLEGRO_WARN("Failed to dlopen libGL.so : %s\n", dlerror()); } ALLEGRO_INFO("glXGetProcAddress Extension: %s\n", alXGetProcAddress ? "Supported" : "Unsupported"); #elif defined ALLEGRO_UNIX #ifdef ALLEGROGL_GLXGETPROCADDRESSARB ALLEGRO_INFO("glXGetProcAddressARB Extension: supported\n"); #else ALLEGRO_INFO("glXGetProcAddress Extension: supported\n"); #endif #endif #ifdef ALLEGRO_MACOSX bundle_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR ("/System/Library/Frameworks/OpenGL.framework"), kCFURLPOSIXPathStyle, true); opengl_bundle_ref = CFBundleCreate(kCFAllocatorDefault, bundle_url); CFRelease(bundle_url); #endif #if defined ALLEGRO_UNIX && !defined ALLEGRO_EXCLUDE_GLX ALLEGRO_DEBUG("GLX Extensions:\n"); ALLEGRO_SYSTEM_XGLX *glx_sys = (void*)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx_disp = (void *)gl_disp; char const *ext = glXQueryExtensionsString( glx_sys->gfxdisplay, glx_disp->xscreen); if (!ext) { /* work around driver bugs? */ ext = ""; } print_extensions(ext); #endif /* Create & load extension API table */ ext_api = create_extension_api_table(); load_extensions(ext_api); gl_disp->ogl_extras->extension_api = ext_api; #if !defined ALLEGRO_CFG_OPENGLES /* Need that symbol already so can't wait until it is assigned later. */ glGetStringi = ext_api->GetStringi; if (gl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_3_0) { ALLEGRO_DEBUG("OpenGL Extensions:\n"); print_extensions_3_0(); } #endif /* Create the list of supported extensions. */ ext_list = create_extension_list(); gl_disp->ogl_extras->extension_list = ext_list; /* Fill the list. */ #define AGL_EXT(name, ver) { \ ext_list->ALLEGRO_GL_##name = \ _ogl_is_extension_with_version_supported("GL_" #name, gl_disp, \ _ALLEGRO_OPENGL_VERSION_##ver); \ } #include "allegro5/opengl/GLext/gl_ext_list.h" #undef AGL_EXT #ifdef ALLEGRO_UNIX #define AGL_EXT(name, ver) { \ ext_list->ALLEGRO_GLX_##name = \ _ogl_is_extension_with_version_supported("GLX_" #name, gl_disp, \ _ALLEGRO_OPENGL_VERSION_##ver); \ } #include "allegro5/opengl/GLext/glx_ext_list.h" #undef AGL_EXT #elif defined ALLEGRO_WINDOWS #define AGL_EXT(name, ver) { \ ext_list->ALLEGRO_WGL_##name = \ _ogl_is_extension_with_version_supported("WGL_" #name, gl_disp, \ _ALLEGRO_OPENGL_VERSION_##ver); \ } #include "allegro5/opengl/GLext/wgl_ext_list.h" #undef AGL_EXT #endif /* Get max texture size */ glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *) & gl_disp->ogl_extras->ogl_info.max_texture_size); /* Note: Voodoo (even V5) don't seem to correctly support * packed pixel formats. Disabling them for those cards. */ ext_list->ALLEGRO_GL_EXT_packed_pixels &= !gl_disp->ogl_extras->ogl_info.is_voodoo; if (ext_list->ALLEGRO_GL_EXT_packed_pixels) { ALLEGRO_INFO("Packed Pixels formats available\n"); /* XXX On NV cards, we want to use BGRA instead of RGBA for speed */ /* Fills the __allegro_gl_texture_format array */ /* TODO: use these somewhere */ #if 0 __allegro_gl_texture_read_format[0] = GL_UNSIGNED_BYTE_3_3_2; __allegro_gl_texture_read_format[1] = GL_UNSIGNED_SHORT_5_5_5_1; __allegro_gl_texture_read_format[2] = GL_UNSIGNED_SHORT_5_6_5; #endif /* #if 0 */ } /* NVidia and ATI cards expose OpenGL 2.0 but often don't accelerate * non-power-of-2 textures. This check is how you verify that NP2 * textures are hardware accelerated or not. * We should clobber the NPOT support if it's not accelerated. */ { const char *vendor = (const char *)glGetString(GL_VENDOR); if (strstr(vendor, "NVIDIA Corporation")) { if (!ext_list->ALLEGRO_GL_NV_fragment_program2 || !ext_list->ALLEGRO_GL_NV_vertex_program3) { ext_list->ALLEGRO_GL_ARB_texture_non_power_of_two = 0; } } else if (strstr(vendor, "ATI Technologies")) { if (gl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_3_0) { /* Assume okay. */ } else if (!strstr((const char *)glGetString(GL_EXTENSIONS), "GL_ARB_texture_non_power_of_two") && gl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_2_0) { ext_list->ALLEGRO_GL_ARB_texture_non_power_of_two = 0; } } } { int *s = gl_disp->extra_settings.settings; glGetIntegerv(GL_MAX_TEXTURE_SIZE, s + ALLEGRO_MAX_BITMAP_SIZE); if (gl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_2_0) s[ALLEGRO_SUPPORT_SEPARATE_ALPHA] = 1; s[ALLEGRO_SUPPORT_NPOT_BITMAP] = ext_list->ALLEGRO_GL_ARB_texture_non_power_of_two || ext_list->ALLEGRO_GL_OES_texture_npot; ALLEGRO_INFO("Use of non-power-of-two textures %s.\n", s[ALLEGRO_SUPPORT_NPOT_BITMAP] ? "enabled" : "disabled"); #if defined ALLEGRO_CFG_OPENGLES if (gl_disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { s[ALLEGRO_CAN_DRAW_INTO_BITMAP] = true; } else { s[ALLEGRO_CAN_DRAW_INTO_BITMAP] = ext_list->ALLEGRO_GL_OES_framebuffer_object; } ALLEGRO_INFO("Use of FBO to draw to textures %s.\n", s[ALLEGRO_CAN_DRAW_INTO_BITMAP] ? "enabled" : "disabled"); #else s[ALLEGRO_CAN_DRAW_INTO_BITMAP] = ext_list->ALLEGRO_GL_EXT_framebuffer_object; ALLEGRO_INFO("Use of FBO to draw to textures %s.\n", s[ALLEGRO_CAN_DRAW_INTO_BITMAP] ? "enabled" : "disabled"); #endif } } /* Function: al_get_opengl_extension_list */ ALLEGRO_OGL_EXT_LIST *al_get_opengl_extension_list(void) { ALLEGRO_DISPLAY *disp; disp = al_get_current_display(); ASSERT(disp); if (!(disp->flags & ALLEGRO_OPENGL)) return NULL; ASSERT(disp->ogl_extras); return disp->ogl_extras->extension_list; } void _al_ogl_unmanage_extensions(ALLEGRO_DISPLAY *gl_disp) { destroy_extension_api_table(gl_disp->ogl_extras->extension_api); destroy_extension_list(gl_disp->ogl_extras->extension_list); gl_disp->ogl_extras->extension_api = NULL; gl_disp->ogl_extras->extension_list = NULL; #ifdef ALLEGRO_MACOSX CFRelease(opengl_bundle_ref); #endif #ifdef ALLEGRO_HAVE_DYNAMIC_LINK if (__libgl_handle) { dlclose(__libgl_handle); __libgl_handle = NULL; } #endif } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/opengl/ogl_bitmap.c000066400000000000000000001136511473414355200200230ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * OpenGL bitmap vtable * * By Elias Pschernig. * OpenGL ES 1.1 support by Trent Gamblin. * */ #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_memblit.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_pixels.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_transform.h" #if defined ALLEGRO_ANDROID #include "allegro5/internal/aintern_android.h" #endif #include "ogl_helpers.h" ALLEGRO_DEBUG_CHANNEL("opengl") /* OpenGL does not support "locking", i.e. direct access to a memory * buffer with pixel data. Instead, the data can be copied from/to * client memory. Because OpenGL stores pixel data starting with the * pixel in the lower left corner, that's also how we return locked * data. Otherwise (and as was done in earlier versions of this code) * we would have to flip all locked memory after receiving and before * sending it to OpenGL. * * Also, we do support old OpenGL drivers where textures must have * power-of-two dimensions. If a non-power-of-two bitmap is created in * such a case, we use a texture with the next larger POT dimensions, * and just keep some unused padding space to the right/bottom of the * pixel data. * * Putting it all together, if we have an Allegro bitmap like this, * with Allegro's y-coordinates: * 0 ########### * 1 #111 # * 2 #222 # * 3 #333 # * 4 ########### * * Then the corresponding texture looks like this with OpenGL * y-coordinates (assuming we use an old driver which needs padding to * POT): * 7 ................ * 6 ................ * 5 ................ * 4 ###########..... * 3 #333 #..... * 2 #222 #..... * 1 #111 #..... * 0 ###########..... */ /* Conversion table from Allegro's pixel formats to corresponding OpenGL * formats. The three entries are: * - GL internal format: the number of color components in the texture * - GL pixel type: Specifies the data type of the pixel data. * - GL format: Specifies the format of the pixel data. * * GL does not support RGB_555 and BGR_555 directly so we use * GL_UNSIGNED_SHORT_1_5_5_5_REV when transferring pixel data, and ensure that * the alpha bit (the "1" component) is present by setting GL_ALPHA_BIAS. * * Desktop OpenGL 3.0+ has no GL_LUMINANCE, so we have to adjust depending on * the runtime version. */ #define get_glformat(f, c) _al_ogl_get_glformat((f), (c)) int _al_ogl_get_glformat(int format, int component) { #if !defined ALLEGRO_CFG_OPENGLES static int glformats[ALLEGRO_NUM_PIXEL_FORMATS][3] = { /* Skip pseudo formats */ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* Actual formats */ {GL_RGBA8, GL_UNSIGNED_INT_8_8_8_8_REV, GL_BGRA}, /* ARGB_8888 */ {GL_RGBA8, GL_UNSIGNED_INT_8_8_8_8, GL_RGBA}, /* RGBA_8888 */ {GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4_REV, GL_BGRA}, /* ARGB_4444 */ {GL_RGB8, GL_UNSIGNED_BYTE, GL_BGR}, /* RGB_888 */ {GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB}, /* RGB_565 */ {GL_RGB5, GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_BGRA}, /* RGB_555 - see above */ {GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1, GL_RGBA}, /* RGBA_5551 */ {GL_RGB5_A1, GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_BGRA}, /* ARGB_1555 */ {GL_RGBA8, GL_UNSIGNED_INT_8_8_8_8_REV, GL_RGBA}, /* ABGR_8888 */ {GL_RGBA8, GL_UNSIGNED_INT_8_8_8_8_REV, GL_RGBA}, /* XBGR_8888 */ {GL_RGB8, GL_UNSIGNED_BYTE, GL_RGB}, /* BGR_888 */ {GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, GL_RGB}, /* BGR_565 */ {GL_RGB5, GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_RGBA}, /* BGR_555 - see above */ {GL_RGBA8, GL_UNSIGNED_INT_8_8_8_8, GL_RGBA}, /* RGBX_8888 */ {GL_RGBA8, GL_UNSIGNED_INT_8_8_8_8_REV, GL_BGRA}, /* XRGB_8888 */ {GL_RGBA32F_ARB, GL_FLOAT, GL_RGBA}, /* ABGR_F32 */ {GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA}, /* ABGR_8888_LE */ {GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA}, /* RGBA_4444 */ {GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE}, /* SINGLE_CHANNEL_8 */ {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_INT_8_8_8_8, GL_RGBA}, /* RGBA_DXT1 */ {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_INT_8_8_8_8, GL_RGBA}, /* RGBA_DXT3 */ {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_INT_8_8_8_8, GL_RGBA}, /* RGBA_DXT5 */ }; if (al_get_opengl_version() >= _ALLEGRO_OPENGL_VERSION_3_0) { glformats[ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8][0] = GL_RED; glformats[ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8][2] = GL_RED; } #else // TODO: Check supported formats by various GLES versions static const int glformats[ALLEGRO_NUM_PIXEL_FORMATS][3] = { /* Skip pseudo formats */ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* Actual formats */ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB}, /* RGB_565 */ {0, 0, 0}, {GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_RGBA}, /* RGBA_5551 */ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA}, /* ABGR_8888_LE */ {GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA}, /* RGBA_4444 */ {GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE}, /* SINGLE_CHANNEL_8 */ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, }; #endif return glformats[format][component]; } static ALLEGRO_BITMAP_INTERFACE glbmp_vt; #define SWAP(type, x, y) {type temp = x; x = y; y = temp;} #define ERR(e) case e: return #e; char const *_al_gl_error_string(GLenum e) { switch (e) { ERR(GL_NO_ERROR) ERR(GL_INVALID_ENUM) ERR(GL_INVALID_VALUE) ERR(GL_INVALID_OPERATION) #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION ERR(GL_STACK_OVERFLOW) ERR(GL_STACK_UNDERFLOW) #endif ERR(GL_OUT_OF_MEMORY) #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE ERR(GL_INVALID_FRAMEBUFFER_OPERATION) #endif } return "UNKNOWN"; } #undef ERR static INLINE void transform_vertex(float* x, float* y, float* z) { al_transform_coordinates_3d(al_get_current_transform(), x, y, z); } static void draw_quad(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, int flags) { float tex_l, tex_t, tex_r, tex_b, w, h, true_w, true_h; float dw = sw, dh = sh; ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra; ALLEGRO_OGL_BITMAP_VERTEX *verts; ALLEGRO_DISPLAY *disp = al_get_current_display(); (void)flags; if (disp->num_cache_vertices != 0 && ogl_bitmap->texture != disp->cache_texture) { disp->vt->flush_vertex_cache(disp); } disp->cache_texture = ogl_bitmap->texture; verts = disp->vt->prepare_vertex_cache(disp, 6); tex_l = ogl_bitmap->left; tex_r = ogl_bitmap->right; tex_t = ogl_bitmap->top; tex_b = ogl_bitmap->bottom; w = bitmap->w; h = bitmap->h; true_w = ogl_bitmap->true_w; true_h = ogl_bitmap->true_h; tex_l += sx / true_w; tex_t -= sy / true_h; tex_r -= (w - sx - sw) / true_w; tex_b += (h - sy - sh) / true_h; verts[0].x = 0; verts[0].y = dh; verts[0].z = 0; verts[0].tx = tex_l; verts[0].ty = tex_b; verts[0].r = tint.r; verts[0].g = tint.g; verts[0].b = tint.b; verts[0].a = tint.a; verts[1].x = 0; verts[1].y = 0; verts[1].z = 0; verts[1].tx = tex_l; verts[1].ty = tex_t; verts[1].r = tint.r; verts[1].g = tint.g; verts[1].b = tint.b; verts[1].a = tint.a; verts[2].x = dw; verts[2].y = dh; verts[2].z = 0; verts[2].tx = tex_r; verts[2].ty = tex_b; verts[2].r = tint.r; verts[2].g = tint.g; verts[2].b = tint.b; verts[2].a = tint.a; verts[4].x = dw; verts[4].y = 0; verts[4].z = 0; verts[4].tx = tex_r; verts[4].ty = tex_t; verts[4].r = tint.r; verts[4].g = tint.g; verts[4].b = tint.b; verts[4].a = tint.a; if (disp->cache_enabled) { /* If drawing is batched, we apply transformations manually. */ transform_vertex(&verts[0].x, &verts[0].y, &verts[0].z); transform_vertex(&verts[1].x, &verts[1].y, &verts[1].z); transform_vertex(&verts[2].x, &verts[2].y, &verts[2].z); transform_vertex(&verts[4].x, &verts[4].y, &verts[4].z); } verts[3] = verts[1]; verts[5] = verts[2]; if (!disp->cache_enabled) disp->vt->flush_vertex_cache(disp); } #undef SWAP static void ogl_draw_bitmap_region(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, int flags) { // FIXME: hack // FIXME: need format conversion if they don't match ALLEGRO_BITMAP *target = al_get_target_bitmap(); ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_target; ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target); /* For sub-bitmaps */ if (target->parent) { target = target->parent; } ogl_target = target->extra; if (!(al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP) && !bitmap->locked && !target->locked) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_source = bitmap->extra; if (ogl_source->is_backbuffer) { /* Our source bitmap is the OpenGL backbuffer, the target * is an OpenGL texture. */ float xtrans, ytrans; /* Source and target cannot both be the back-buffer. */ ASSERT(!ogl_target->is_backbuffer); /* If we only translate, we can do this fast. */ if (_al_transform_is_translation(al_get_current_transform(), &xtrans, &ytrans)) { /* In general, we can't modify the texture while it's * FBO bound - so we temporarily disable the FBO. */ if (ogl_target->fbo_info) _al_ogl_set_target_bitmap(disp, bitmap); /* We need to do clipping because glCopyTexSubImage2D * fails otherwise. */ if (xtrans < target->cl) { sx -= xtrans - target->cl; sw += xtrans - target->cl; xtrans = target->cl; } if (ytrans < target->ct) { sy -= ytrans - target->ct; sh += ytrans - target->ct; ytrans = target->ct; } if (xtrans + sw > target->cr_excl) { sw = target->cr_excl - xtrans; } if (ytrans + sh > target->cb_excl) { sh = target->cb_excl - ytrans; } /* Note: Allegro 5.0.0 does not support blending or * tinting if the source bitmap is the screen. So it is * correct to ignore them here. */ glBindTexture(GL_TEXTURE_2D, ogl_target->texture); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xtrans, target->h - ytrans - sh, sx, bitmap->h - sy - sh, sw, sh); /* Fix up FBO again after the copy. */ if (ogl_target->fbo_info) _al_ogl_set_target_bitmap(disp, target); return; } /* Drawing a deformed backbuffer is not supported. */ ASSERT(0); } } if (disp->ogl_extras->opengl_target == target) { draw_quad(bitmap, tint, sx, sy, sw, sh, flags); return; } /* If all else fails, fall back to software implementation. */ _al_draw_bitmap_region_memory(bitmap, tint, sx, sy, sw, sh, 0, 0, flags); } /* Helper to get smallest fitting power of two. */ static int pot(int x) { int y = 1; while (y < x) y *= 2; return y; } static GLint ogl_bitmap_wrap(ALLEGRO_BITMAP_WRAP wrap) { switch (wrap) { default: case ALLEGRO_BITMAP_WRAP_DEFAULT: return GL_CLAMP_TO_EDGE; case ALLEGRO_BITMAP_WRAP_REPEAT: return GL_REPEAT; case ALLEGRO_BITMAP_WRAP_CLAMP: return GL_CLAMP_TO_EDGE; case ALLEGRO_BITMAP_WRAP_MIRROR: return GL_MIRRORED_REPEAT; } } // FIXME: need to do all the logic AllegroGL does, checking extensions, // proxy textures, formats, limits ... static bool ogl_upload_bitmap(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra; int w = bitmap->w; int h = bitmap->h; int bitmap_format = al_get_bitmap_format(bitmap); int bitmap_flags = al_get_bitmap_flags(bitmap); bool post_generate_mipmap = false; GLenum e; int filter; int gl_filters[] = { GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR }; if (ogl_bitmap->texture == 0) { glGenTextures(1, &ogl_bitmap->texture); e = glGetError(); if (e) { ALLEGRO_ERROR("glGenTextures failed: %s\n", _al_gl_error_string(e)); } else { ALLEGRO_DEBUG("Created new OpenGL texture %d (%dx%d, format %s)\n", ogl_bitmap->texture, ogl_bitmap->true_w, ogl_bitmap->true_h, _al_pixel_format_name(bitmap_format)); } } glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture); e = glGetError(); if (e) { ALLEGRO_ERROR("glBindTexture for texture %d failed (%s).\n", ogl_bitmap->texture, _al_gl_error_string(e)); } /* Wrap, Min/Mag should always come before glTexImage2D so the texture is "complete" */ // NOTE: on OGLES CLAMP_TO_EDGE is only one supported with NPOT textures ALLEGRO_BITMAP_WRAP wrap_u, wrap_v; _al_get_bitmap_wrap(bitmap, &wrap_u, &wrap_v); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ogl_bitmap_wrap(wrap_u)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ogl_bitmap_wrap(wrap_v)); filter = (bitmap_flags & ALLEGRO_MIPMAP) ? 2 : 0; if (bitmap_flags & ALLEGRO_MIN_LINEAR) { filter++; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filters[filter]); filter = 0; if (bitmap_flags & ALLEGRO_MAG_LINEAR) { filter++; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filters[filter]); // TODO: To support anisotropy, we would need an API for it. Something // like: // al_set_new_bitmap_option(ALLEGRO_ANISOTROPY, 16.0); #if 0 if (al_get_opengl_extension_list()->ALLEGRO_GL_EXT_texture_filter_anisotropic) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); } #endif if (bitmap_flags & ALLEGRO_MIPMAP) { /* If using FBOs, use glGenerateMipmapEXT instead of the GL_GENERATE_MIPMAP * texture parameter. GL_GENERATE_MIPMAP is deprecated in GL 3.0 so we * may want to use the new method in other cases as well. */ if (al_get_opengl_extension_list()->ALLEGRO_GL_EXT_framebuffer_object || al_get_opengl_extension_list()->ALLEGRO_GL_OES_framebuffer_object || IS_OPENGLES /* FIXME */) { post_generate_mipmap = true; } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); e = glGetError(); if (e) { ALLEGRO_ERROR("glTexParameteri for texture %d failed (%s).\n", ogl_bitmap->texture, _al_gl_error_string(e)); } #endif } } /* If there's unused space around the bitmap, we need to clear it * else linear filtering will cause artifacts from the random * data there. We also clear for floating point formats because * NaN values in the texture cause some blending modes to fail on * those pixels */ if (!IS_OPENGLES) { if (ogl_bitmap->true_w != bitmap->w || ogl_bitmap->true_h != bitmap->h || bitmap_format == ALLEGRO_PIXEL_FORMAT_ABGR_F32) { unsigned char *buf; buf = al_calloc(ogl_bitmap->true_h, ogl_bitmap->true_w); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, get_glformat(bitmap_format, 0), ogl_bitmap->true_w, ogl_bitmap->true_h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buf); e = glGetError(); al_free(buf); } else { glTexImage2D(GL_TEXTURE_2D, 0, get_glformat(bitmap_format, 0), ogl_bitmap->true_w, ogl_bitmap->true_h, 0, get_glformat(bitmap_format, 2), get_glformat(bitmap_format, 1), NULL); e = glGetError(); } } else { unsigned char *buf; int pix_size = al_get_pixel_size(bitmap_format); buf = al_calloc(pix_size, ogl_bitmap->true_h * ogl_bitmap->true_w); glPixelStorei(GL_UNPACK_ALIGNMENT, pix_size); glTexImage2D(GL_TEXTURE_2D, 0, get_glformat(bitmap_format, 0), ogl_bitmap->true_w, ogl_bitmap->true_h, 0, get_glformat(bitmap_format, 2), get_glformat(bitmap_format, 1), buf); e = glGetError(); al_free(buf); } if (e) { ALLEGRO_ERROR("glTexImage2D for format %s, size %dx%d failed (%s)\n", _al_pixel_format_name(bitmap_format), ogl_bitmap->true_w, ogl_bitmap->true_h, _al_gl_error_string(e)); glDeleteTextures(1, &ogl_bitmap->texture); ogl_bitmap->texture = 0; // FIXME: Should we convert it into a memory bitmap? Or if the size is // the problem try to use multiple textures? return false; } if (post_generate_mipmap) { glGenerateMipmapEXT(GL_TEXTURE_2D); e = glGetError(); if (e) { ALLEGRO_ERROR("glGenerateMipmapEXT for texture %d failed (%s).\n", ogl_bitmap->texture, _al_gl_error_string(e)); } } ogl_bitmap->left = 0; ogl_bitmap->right = (float) w / ogl_bitmap->true_w; ogl_bitmap->top = (float) h / ogl_bitmap->true_h; ogl_bitmap->bottom = 0; return true; } static void ogl_update_clipping_rectangle(ALLEGRO_BITMAP *bitmap) { ALLEGRO_DISPLAY *ogl_disp = al_get_current_display(); ALLEGRO_BITMAP *target_bitmap = bitmap; if (bitmap->parent) { target_bitmap = bitmap->parent; } if (ogl_disp->ogl_extras->opengl_target == target_bitmap) { _al_ogl_setup_bitmap_clipping(bitmap); } } static void ogl_destroy_bitmap(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra; ALLEGRO_DISPLAY *disp; ALLEGRO_DISPLAY *bmp_disp; ALLEGRO_DISPLAY *old_disp = NULL; ASSERT(!al_is_sub_bitmap(bitmap)); bmp_disp = _al_get_bitmap_display(bitmap); disp = al_get_current_display(); if (bmp_disp->ogl_extras->is_shared == false && bmp_disp != disp) { old_disp = disp; _al_set_current_display_only(bmp_disp); } if (bmp_disp->ogl_extras->opengl_target == bitmap) { bmp_disp->ogl_extras->opengl_target = NULL; } al_remove_opengl_fbo(bitmap); if (ogl_bitmap->texture) { glDeleteTextures(1, &ogl_bitmap->texture); ogl_bitmap->texture = 0; } if (old_disp) { _al_set_current_display_only(old_disp); } al_free(ogl_bitmap); } static void ogl_bitmap_pointer_changed(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP *old) { ALLEGRO_BITMAP_EXTRA_OPENGL *extra = bitmap->extra; if (extra && extra->fbo_info) { ASSERT(extra->fbo_info->owner == old); extra->fbo_info->owner = bitmap; } } static bool can_flip_blocks(ALLEGRO_PIXEL_FORMAT format) { switch (format) { case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1: case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3: case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5: return true; default: return false; } } static void ogl_flip_blocks(ALLEGRO_LOCKED_REGION *lr, int wc, int hc) { #define SWAP(x, y) do { unsigned char t = x; x = y; y = t; } while (0) int x, y; unsigned char* data = lr->data; ASSERT(can_flip_blocks(lr->format)); switch (lr->format) { case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1: { for (y = 0; y < hc; y++) { unsigned char* row = data; for (x = 0; x < wc; x++) { /* Skip color table */ row += 4; /* Swap colors */ SWAP(row[0], row[3]); SWAP(row[2], row[1]); /* Skip bit-map */ row += 4; } data += lr->pitch; } break; } case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3: { for (y = 0; y < hc; y++) { unsigned char* row = data; for (x = 0; x < wc; x++) { /* Swap alpha */ SWAP(row[0], row[6]); SWAP(row[1], row[7]); SWAP(row[2], row[4]); SWAP(row[3], row[5]); /* Skip alpha bit-map */ row += 8; /* Skip color table */ row += 4; /* Swap colors */ SWAP(row[0], row[3]); SWAP(row[2], row[1]); /* Skip bit-map */ row += 4; } data += lr->pitch; } break; } case ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5: { for (y = 0; y < hc; y++) { unsigned char* row = data; for (x = 0; x < wc; x++) { uint16_t bit_row0, bit_row1, bit_row2, bit_row3; /* Skip the alpha table */ row += 2; bit_row0 = (((uint16_t)row[0]) | (uint16_t)row[1] << 8) << 4; bit_row1 = (((uint16_t)row[1]) | (uint16_t)row[2] << 8) >> 4; bit_row2 = (((uint16_t)row[3]) | (uint16_t)row[4] << 8) << 4; bit_row3 = (((uint16_t)row[4]) | (uint16_t)row[5] << 8) >> 4; row[0] = (unsigned char)(bit_row3 & 0x00ff); row[1] = (unsigned char)((bit_row2 & 0x00ff) | ((bit_row3 & 0xff00) >> 8)); row[2] = (unsigned char)((bit_row2 & 0xff00) >> 8); row[3] = (unsigned char)(bit_row1 & 0x00ff); row[4] = (unsigned char)((bit_row0 & 0x00ff) | ((bit_row1 & 0xff00) >> 8)); row[5] = (unsigned char)((bit_row0 & 0xff00) >> 8); /* Skip the alpha bit-map */ row += 6; /* Skip color table */ row += 4; /* Swap colors */ SWAP(row[0], row[3]); SWAP(row[2], row[1]); /* Skip bit-map */ row += 4; } data += lr->pitch; } break; } default: (void)x; (void)y; (void)data; (void)wc; (void)hc; } #undef SWAP } static ALLEGRO_LOCKED_REGION *ogl_lock_compressed_region(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int flags) { #if !defined ALLEGRO_CFG_OPENGLES ALLEGRO_BITMAP_EXTRA_OPENGL *const ogl_bitmap = bitmap->extra; ALLEGRO_DISPLAY *disp; ALLEGRO_DISPLAY *old_disp = NULL; GLenum e; bool ok = true; int bitmap_format = al_get_bitmap_format(bitmap); int block_width = al_get_pixel_block_width(bitmap_format); int block_height = al_get_pixel_block_height(bitmap_format); int block_size = al_get_pixel_block_size(bitmap_format); int xc = x / block_width; int yc = y / block_width; int wc = w / block_width; int hc = h / block_width; int true_wc = ogl_bitmap->true_w / block_width; int true_hc = ogl_bitmap->true_h / block_height; int gl_yc = _al_get_least_multiple(bitmap->h, block_height) / block_height - yc - hc; if (!can_flip_blocks(bitmap_format)) { return NULL; } if (flags & ALLEGRO_LOCK_WRITEONLY) { int pitch = wc * block_size; ogl_bitmap->lock_buffer = al_malloc(pitch * hc); if (ogl_bitmap->lock_buffer == NULL) { return NULL; } bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (hc - 1); bitmap->locked_region.format = bitmap_format; bitmap->locked_region.pitch = -pitch; bitmap->locked_region.pixel_size = block_size; return &bitmap->locked_region; } disp = al_get_current_display(); /* Change OpenGL context if necessary. */ if (!disp || (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false && _al_get_bitmap_display(bitmap) != disp)) { old_disp = disp; _al_set_current_display_only(_al_get_bitmap_display(bitmap)); } /* Set up the pixel store state. We will need to match it when unlocking. * There may be other pixel store state we should be setting. * See also pitfalls 7 & 8 from: * http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/ */ int previous_alignment; glGetIntegerv(GL_PACK_ALIGNMENT, &previous_alignment); if (previous_alignment != 1) { glPixelStorei(GL_PACK_ALIGNMENT, 1); e = glGetError(); if (e) { ALLEGRO_ERROR("glPixelStorei(GL_PACK_ALIGNMENT, %d) failed (%s).\n", 1, _al_gl_error_string(e)); ok = false; } } if (ok) { ogl_bitmap->lock_buffer = al_malloc(true_wc * true_hc * block_size); if (ogl_bitmap->lock_buffer != NULL) { glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture); glGetCompressedTexImage(GL_TEXTURE_2D, 0, ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glGetCompressedTexImage for format %s failed (%s).\n", _al_pixel_format_name(bitmap_format), _al_gl_error_string(e)); al_free(ogl_bitmap->lock_buffer); ogl_bitmap->lock_buffer = NULL; ok = false; } else { if (flags == ALLEGRO_LOCK_READWRITE) { /* Need to make the locked memory contiguous, as * glCompressedTexSubImage2D cannot read strided * memory. */ int y; int src_pitch = true_wc * block_size; int dest_pitch = wc * block_size; char* dest_ptr = (char*)ogl_bitmap->lock_buffer; char* src_ptr = (char*)ogl_bitmap->lock_buffer + src_pitch * gl_yc + block_size * xc; for (y = 0; y < hc; y++) { memmove(dest_ptr, src_ptr, dest_pitch); src_ptr += src_pitch; dest_ptr += dest_pitch; } bitmap->locked_region.data = ogl_bitmap->lock_buffer + dest_pitch * (hc - 1); bitmap->locked_region.pitch = -dest_pitch; } else { int pitch = true_wc * block_size; bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (gl_yc + hc - 1) + block_size * xc; bitmap->locked_region.pitch = -pitch; } bitmap->locked_region.format = bitmap_format; bitmap->locked_region.pixel_size = block_size; } } else { ok = false; } } if (previous_alignment != 1) { glPixelStorei(GL_PACK_ALIGNMENT, previous_alignment); } if (old_disp != NULL) { _al_set_current_display_only(old_disp); } if (ok) { ogl_flip_blocks(&bitmap->locked_region, wc, hc); return &bitmap->locked_region; } ALLEGRO_ERROR("Failed to lock region\n"); ASSERT(ogl_bitmap->lock_buffer == NULL); return NULL; #else (void)bitmap; (void)x; (void)y; (void)w; (void)h; (void)flags; return NULL; #endif } static void ogl_unlock_compressed_region(ALLEGRO_BITMAP *bitmap) { #if !defined ALLEGRO_CFG_OPENGLES ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra; int lock_format = bitmap->locked_region.format; ALLEGRO_DISPLAY *old_disp = NULL; ALLEGRO_DISPLAY *disp; GLenum e; int block_size = al_get_pixel_block_size(lock_format); int block_width = al_get_pixel_block_width(lock_format); int block_height = al_get_pixel_block_height(lock_format); int data_size = bitmap->lock_h * bitmap->lock_w / (block_width * block_height) * block_size; int gl_y = _al_get_least_multiple(bitmap->h, block_height) - bitmap->lock_y - bitmap->lock_h; /* It shouldn't be possible for this to fail, as we wouldn't have been able * to lock earlier */ ASSERT(can_flip_blocks(bitmap->locked_region.format)); if ((bitmap->lock_flags & ALLEGRO_LOCK_READONLY)) { goto EXIT; } ogl_flip_blocks(&bitmap->locked_region, bitmap->lock_w / block_width, bitmap->lock_h / block_height); disp = al_get_current_display(); /* Change OpenGL context if necessary. */ if (!disp || (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false && _al_get_bitmap_display(bitmap) != disp)) { old_disp = disp; _al_set_current_display_only(_al_get_bitmap_display(bitmap)); } /* Keep this in sync with ogl_lock_compressed_region. */ int previous_alignment; glGetIntegerv(GL_UNPACK_ALIGNMENT, &previous_alignment); if (previous_alignment != 1) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); e = glGetError(); if (e) { ALLEGRO_ERROR("glPixelStorei(GL_UNPACK_ALIGNMENT, %d) failed (%s).\n", 1, _al_gl_error_string(e)); } } glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture); glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, bitmap->lock_x, gl_y, bitmap->lock_w, bitmap->lock_h, get_glformat(lock_format, 0), data_size, ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glCompressedTexSubImage2D for format %s failed (%s).\n", _al_pixel_format_name(lock_format), _al_gl_error_string(e)); } if (previous_alignment != 1) { glPixelStorei(GL_UNPACK_ALIGNMENT, previous_alignment); } if (old_disp) { _al_set_current_display_only(old_disp); } EXIT: al_free(ogl_bitmap->lock_buffer); ogl_bitmap->lock_buffer = NULL; #else (void)bitmap; #endif } static void ogl_backup_dirty_bitmap(ALLEGRO_BITMAP *b) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = b->extra; ALLEGRO_LOCKED_REGION *lr; int bitmap_flags = al_get_bitmap_flags(b); if (b->parent) return; if ((bitmap_flags & ALLEGRO_MEMORY_BITMAP) || (bitmap_flags & ALLEGRO_NO_PRESERVE_TEXTURE) || !b->dirty || ogl_bitmap->is_backbuffer) return; ALLEGRO_DEBUG("Backing up dirty bitmap %p\n", b); lr = al_lock_bitmap( b, _al_get_bitmap_memory_format(b), ALLEGRO_LOCK_READONLY ); if (lr) { int line_size = al_get_pixel_size(lr->format) * b->w; int y; for (y = 0; y < b->h; y++) { unsigned char *p = ((unsigned char *)lr->data) + lr->pitch * y; unsigned char *p2; p2 = ((unsigned char *)b->memory) + line_size * (b->h-1-y); memcpy(p2, p, line_size); } al_unlock_bitmap(b); b->dirty = false; } else { ALLEGRO_WARN("Failed to lock dirty bitmap %p\n", b); } } /* Obtain a reference to this driver. */ static ALLEGRO_BITMAP_INTERFACE *ogl_bitmap_driver(void) { if (glbmp_vt.draw_bitmap_region) { return &glbmp_vt; } glbmp_vt.draw_bitmap_region = ogl_draw_bitmap_region; glbmp_vt.upload_bitmap = ogl_upload_bitmap; glbmp_vt.update_clipping_rectangle = ogl_update_clipping_rectangle; glbmp_vt.destroy_bitmap = ogl_destroy_bitmap; glbmp_vt.bitmap_pointer_changed = ogl_bitmap_pointer_changed; #if defined(ALLEGRO_CFG_OPENGLES) glbmp_vt.lock_region = _al_ogl_lock_region_gles; glbmp_vt.unlock_region = _al_ogl_unlock_region_gles; #else glbmp_vt.lock_region = _al_ogl_lock_region_new; glbmp_vt.unlock_region = _al_ogl_unlock_region_new; #endif glbmp_vt.lock_compressed_region = ogl_lock_compressed_region; glbmp_vt.unlock_compressed_region = ogl_unlock_compressed_region; glbmp_vt.backup_dirty_bitmap = ogl_backup_dirty_bitmap; return &glbmp_vt; } ALLEGRO_BITMAP *_al_ogl_create_bitmap(ALLEGRO_DISPLAY *d, int w, int h, int format, int flags) { ALLEGRO_BITMAP *bitmap; ALLEGRO_BITMAP_EXTRA_OPENGL *extra; int true_w; int true_h; int block_width; int block_height; ALLEGRO_SYSTEM *system = al_get_system_driver(); (void)d; format = _al_get_real_pixel_format(d, format); ASSERT(_al_pixel_format_is_real(format)); block_width = al_get_pixel_block_width(format); block_height = al_get_pixel_block_width(format); true_w = _al_get_least_multiple(w, block_width); true_h = _al_get_least_multiple(h, block_height); if (_al_pixel_format_is_compressed(format)) { if (!al_get_opengl_extension_list()->ALLEGRO_GL_EXT_texture_compression_s3tc) { ALLEGRO_DEBUG("Device does not support S3TC compressed textures.\n"); return NULL; } } if (!d->extra_settings.settings[ALLEGRO_SUPPORT_NPOT_BITMAP]) { true_w = pot(true_w); true_h = pot(true_h); } /* This used to be an iOS/Android only workaround - but * Intel is making GPUs with the same chips now. Very * small textures can have garbage pixels and FBOs don't * work with them on some of these chips. This is a * workaround. */ if (true_w < system->min_bitmap_size) true_w = system->min_bitmap_size; if (true_h < system->min_bitmap_size) true_h = system->min_bitmap_size; /* glReadPixels requires 32 byte aligned rows */ if (IS_ANDROID) { int mod = true_w % 32; if (mod != 0) { true_w += 32 - mod; } } ASSERT(true_w % block_width == 0); ASSERT(true_h % block_height == 0); bitmap = al_calloc(1, sizeof *bitmap); ASSERT(bitmap); bitmap->extra = al_calloc(1, sizeof(ALLEGRO_BITMAP_EXTRA_OPENGL)); ASSERT(bitmap->extra); extra = bitmap->extra; bitmap->vt = ogl_bitmap_driver(); bitmap->_memory_format = _al_pixel_format_is_compressed(format) ? ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE : format; bitmap->pitch = true_w * al_get_pixel_size(bitmap->_memory_format); bitmap->_format = format; bitmap->_flags = flags | _ALLEGRO_INTERNAL_OPENGL; extra->true_w = true_w; extra->true_h = true_h; if (!(flags & ALLEGRO_NO_PRESERVE_TEXTURE)) { bitmap->memory = al_calloc(1, al_get_pixel_size(bitmap->_memory_format)*w*h); } return bitmap; } /* lets you setup the memory pointer to skip a lock/unlock copy * if it's unnecessary * 'ptr' should be tightly packed or NULL if no texture data * upload is desired. */ void _al_ogl_upload_bitmap_memory(ALLEGRO_BITMAP *bitmap, int format, void *ptr) { int w = bitmap->w; int h = bitmap->h; int pixsize = al_get_pixel_size(format); int y; ALLEGRO_BITMAP *tmp; ALLEGRO_LOCKED_REGION *lr; uint8_t *dst; uint8_t *src; ASSERT(al_get_current_display() == _al_get_bitmap_display(bitmap)); tmp = _al_create_bitmap_params(_al_get_bitmap_display(bitmap), w, h, format, al_get_bitmap_flags(bitmap), 0, 0); ASSERT(tmp); if (ptr != NULL) { lr = al_lock_bitmap(tmp, format, ALLEGRO_LOCK_WRITEONLY); ASSERT(lr); dst = (uint8_t *)lr->data; // we need to flip it src = ((uint8_t *)ptr) + (pixsize * w * (h-1)); for (y = 0; y < h; y++) { memcpy(dst, src, pixsize * w); dst += lr->pitch; src -= pixsize * w; // minus because it's flipped } al_unlock_bitmap(tmp); } ((ALLEGRO_BITMAP_EXTRA_OPENGL *)bitmap->extra)->texture = ((ALLEGRO_BITMAP_EXTRA_OPENGL *)tmp->extra)->texture; ((ALLEGRO_BITMAP_EXTRA_OPENGL *)tmp->extra)->texture = 0; al_destroy_bitmap(tmp); } /* Function: al_get_opengl_texture */ GLuint al_get_opengl_texture(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_OPENGL *extra; if (bitmap->parent) bitmap = bitmap->parent; if (!(al_get_bitmap_flags(bitmap) & _ALLEGRO_INTERNAL_OPENGL)) return 0; extra = bitmap->extra; return extra->texture; } /* Function: al_remove_opengl_fbo */ void al_remove_opengl_fbo(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap; if (bitmap->parent) bitmap = bitmap->parent; if (!(al_get_bitmap_flags(bitmap) & _ALLEGRO_INTERNAL_OPENGL)) return; ogl_bitmap = bitmap->extra; if (!ogl_bitmap->fbo_info) return; ASSERT(ogl_bitmap->fbo_info->fbo_state > FBO_INFO_UNUSED); ASSERT(ogl_bitmap->fbo_info->fbo != 0); ALLEGRO_FBO_INFO *info = ogl_bitmap->fbo_info; _al_ogl_del_fbo(info); if (info->fbo_state == FBO_INFO_PERSISTENT) { al_free(info); } else { _al_ogl_reset_fbo_info(info); } } /* Function: al_get_opengl_fbo */ GLuint al_get_opengl_fbo(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap; if (bitmap->parent) bitmap = bitmap->parent; if (!(al_get_bitmap_flags(bitmap) & _ALLEGRO_INTERNAL_OPENGL)) return 0; ogl_bitmap = bitmap->extra; if (!ogl_bitmap->fbo_info) { if (!_al_ogl_create_persistent_fbo(bitmap)) { return 0; } } if (ogl_bitmap->fbo_info->fbo_state == FBO_INFO_TRANSIENT) { ogl_bitmap->fbo_info = _al_ogl_persist_fbo(_al_get_bitmap_display(bitmap), ogl_bitmap->fbo_info); } return ogl_bitmap->fbo_info->fbo; } /* Function: al_get_opengl_texture_size */ bool al_get_opengl_texture_size(ALLEGRO_BITMAP *bitmap, int *w, int *h) { /* The designers of OpenGL ES 1.0 forgot to add a function to query * texture sizes, so this will be the only way there to get the texture * size. On normal OpenGL also glGetTexLevelParameter could be used. */ ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap; if (bitmap->parent) bitmap = bitmap->parent; if (!(al_get_bitmap_flags(bitmap) & _ALLEGRO_INTERNAL_OPENGL)) { *w = 0; *h = 0; return false; } ogl_bitmap = bitmap->extra; *w = ogl_bitmap->true_w; *h = ogl_bitmap->true_h; return true; } /* Function: al_get_opengl_texture_position */ void al_get_opengl_texture_position(ALLEGRO_BITMAP *bitmap, int *u, int *v) { ASSERT(bitmap); ASSERT(u); ASSERT(v); *u = bitmap->xofs; *v = bitmap->yofs; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/opengl/ogl_display.c000066400000000000000000000164551473414355200202200ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * OpenGL routines common to all OpenGL drivers. * * By Elias Pschernig and Milan Mimica. * */ #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_pixels.h" #include "allegro5/transformations.h" #ifdef ALLEGRO_IPHONE #include "allegro5/internal/aintern_iphone.h" #endif #ifdef ALLEGRO_ANDROID #include "allegro5/internal/aintern_android.h" #endif #include "ogl_helpers.h" ALLEGRO_DEBUG_CHANNEL("opengl") /* Helper to set up GL state as we want it. */ void _al_ogl_setup_gl(ALLEGRO_DISPLAY *d) { ALLEGRO_OGL_EXTRAS *ogl = d->ogl_extras; if (ogl->backbuffer) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); _al_ogl_resize_backbuffer(ogl->backbuffer, d->w, d->h); /* If we are currently targetting the backbuffer, we need to update the * transformations. */ if (target && (target == ogl->backbuffer || target->parent == ogl->backbuffer)) { /* vt should be set at this point, but doesn't hurt to check */ ASSERT(d->vt); d->vt->update_transformation(d, target); } } else { ogl->backbuffer = _al_ogl_create_backbuffer(d); } } void _al_ogl_set_target_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP *target = bitmap; if (bitmap->parent) target = bitmap->parent; /* if either this bitmap or its parent (in the case of subbitmaps) * is locked then don't do anything */ if (bitmap->locked) return; if (bitmap->parent && bitmap->parent->locked) return; _al_ogl_setup_fbo(display, bitmap); if (display->ogl_extras->opengl_target == target) { _al_ogl_setup_bitmap_clipping(bitmap); } } void _al_ogl_unset_target_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *target) { if (!target) return; _al_ogl_finalize_fbo(display, target); } /* Function: al_set_current_opengl_context */ void al_set_current_opengl_context(ALLEGRO_DISPLAY *display) { ASSERT(display); if (!(display->flags & ALLEGRO_OPENGL)) return; if (display) { ALLEGRO_BITMAP *bmp = al_get_target_bitmap(); if (bmp && _al_get_bitmap_display(bmp) && _al_get_bitmap_display(bmp) != display) { al_set_target_bitmap(NULL); } } _al_set_current_display_only(display); } void _al_ogl_setup_bitmap_clipping(const ALLEGRO_BITMAP *bitmap) { int x_1, y_1, x_2, y_2, h; bool use_scissor = true; x_1 = bitmap->cl; y_1 = bitmap->ct; x_2 = bitmap->cr_excl; y_2 = bitmap->cb_excl; h = bitmap->h; /* Drawing onto the sub bitmap is handled by clipping the parent. */ if (bitmap->parent) { x_1 += bitmap->xofs; y_1 += bitmap->yofs; x_2 += bitmap->xofs; y_2 += bitmap->yofs; h = bitmap->parent->h; } if (x_1 == 0 && y_1 == 0 && x_2 == bitmap->w && y_2 == bitmap->h) { if (bitmap->parent) { /* Can only disable scissor if the sub-bitmap covers the * complete parent. */ if (bitmap->xofs == 0 && bitmap->yofs == 0 && bitmap->w == bitmap->parent->w && bitmap->h == bitmap->parent->h) { use_scissor = false; } } else { use_scissor = false; } } if (!use_scissor) { glDisable(GL_SCISSOR_TEST); } else { glEnable(GL_SCISSOR_TEST); #ifdef ALLEGRO_IPHONE _al_iphone_clip(bitmap, x_1, y_1, x_2, y_2); #else /* OpenGL is upside down, so must adjust y_2 to the height. */ glScissor(x_1, h - y_2, x_2 - x_1, y_2 - y_1); #endif } } ALLEGRO_BITMAP *_al_ogl_get_backbuffer(ALLEGRO_DISPLAY *d) { return (ALLEGRO_BITMAP *)d->ogl_extras->backbuffer; } bool _al_ogl_resize_backbuffer(ALLEGRO_BITMAP *b, int w, int h) { int pitch; ALLEGRO_BITMAP_EXTRA_OPENGL *extra = b->extra; pitch = w * al_get_pixel_size(al_get_bitmap_format(b)); b->w = w; b->h = h; b->pitch = pitch; b->cl = 0; b->ct = 0; b->cr_excl = w; b->cb_excl = h; al_identity_transform(&b->proj_transform); al_orthographic_transform(&b->proj_transform, 0, 0, -1.0, w, h, 1.0); /* There is no texture associated with the backbuffer so no need to care * about texture size limitations. */ extra->true_w = w; extra->true_h = h; b->memory = NULL; return true; } ALLEGRO_BITMAP* _al_ogl_create_backbuffer(ALLEGRO_DISPLAY *disp) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_backbuffer; ALLEGRO_BITMAP *backbuffer; int format; ALLEGRO_DEBUG("Creating backbuffer\n"); // FIXME: _al_deduce_color_format would work fine if the display paramerers // are filled in, for OpenGL ES if (IS_OPENGLES) { if (disp->extra_settings.settings[ALLEGRO_COLOR_SIZE] == 16) { format = ALLEGRO_PIXEL_FORMAT_RGB_565; } else { format = ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE; } } else { format = _al_deduce_color_format(&disp->extra_settings); /* Eww. No OpenGL hardware in the world does that - let's just * switch to some default. */ if (al_get_pixel_size(format) == 3) { /* Or should we use RGBA? Maybe only if not Nvidia cards? */ format = ALLEGRO_PIXEL_FORMAT_ABGR_8888; } } ALLEGRO_TRACE_CHANNEL_LEVEL("display", 1)("Deduced format %s for backbuffer.\n", _al_pixel_format_name(format)); /* Now that the display backbuffer has a format, update extra_settings so * the user can query it back. */ _al_set_color_components(format, &disp->extra_settings, ALLEGRO_REQUIRE); disp->backbuffer_format = format; ALLEGRO_DEBUG("Creating backbuffer bitmap\n"); /* Using ALLEGRO_NO_PRESERVE_TEXTURE prevents extra memory being allocated */ backbuffer = _al_ogl_create_bitmap(disp, disp->w, disp->h, format, ALLEGRO_VIDEO_BITMAP | ALLEGRO_NO_PRESERVE_TEXTURE); if (!backbuffer) { ALLEGRO_DEBUG("Backbuffer bitmap creation failed.\n"); return NULL; } backbuffer->w = disp->w; backbuffer->h = disp->h; backbuffer->cl = 0; backbuffer->ct = 0; backbuffer->cr_excl = disp->w; backbuffer->cb_excl = disp->h; al_identity_transform(&backbuffer->transform); al_identity_transform(&backbuffer->proj_transform); al_orthographic_transform(&backbuffer->proj_transform, 0, 0, -1.0, disp->w, disp->h, 1.0); ALLEGRO_TRACE_CHANNEL_LEVEL("display", 1)( "Created backbuffer bitmap (actual format: %s)\n", _al_pixel_format_name(al_get_bitmap_format(backbuffer))); ogl_backbuffer = backbuffer->extra; ogl_backbuffer->true_w = disp->w; ogl_backbuffer->true_h = disp->h; ogl_backbuffer->is_backbuffer = 1; backbuffer->_display = disp; return backbuffer; } void _al_ogl_destroy_backbuffer(ALLEGRO_BITMAP *b) { al_destroy_bitmap(b); } /* vi: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/opengl/ogl_draw.c000066400000000000000000000375541473414355200175130ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * OpenGL drawing routines * * By Elias Pschernig. */ #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_memdraw.h" #include "allegro5/internal/aintern_opengl.h" #ifdef ALLEGRO_ANDROID #include "allegro5/internal/aintern_android.h" #endif #include "ogl_helpers.h" ALLEGRO_DEBUG_CHANNEL("opengl") /* FIXME: For some reason x86_64 Android crashes for me when calling * glBlendColor - so adding this hack to disable it. */ #ifdef ALLEGRO_ANDROID #if defined(__x86_64__) || defined(__i686__) #define ALLEGRO_ANDROID_HACK_X86_64 #endif #endif static void try_const_color(ALLEGRO_DISPLAY *ogl_disp, ALLEGRO_COLOR *c) { #ifdef ALLEGRO_CFG_OPENGLES #ifndef ALLEGRO_CFG_OPENGLES2 return; #endif // Only OpenGL ES 2.0 has glBlendColor if (ogl_disp->ogl_extras->ogl_info.version < _ALLEGRO_OPENGL_VERSION_2_0) { return; } #else (void)ogl_disp; #endif glBlendColor(c->r, c->g, c->b, c->a); } bool _al_opengl_set_blender(ALLEGRO_DISPLAY *ogl_disp) { int op, src_color, dst_color, op_alpha, src_alpha, dst_alpha; ALLEGRO_COLOR const_color; const int blend_modes[10] = { GL_ZERO, GL_ONE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ONE_MINUS_DST_COLOR, #if defined(ALLEGRO_CFG_OPENGLES2) || !defined(ALLEGRO_CFG_OPENGLES) GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR #else GL_ONE, GL_ONE #endif }; const int blend_equations[3] = { GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT }; (void)ogl_disp; al_get_separate_bitmap_blender(&op, &src_color, &dst_color, &op_alpha, &src_alpha, &dst_alpha); const_color = al_get_bitmap_blend_color(); /* glBlendFuncSeparate was only included with OpenGL 1.4 */ #if !defined ALLEGRO_CFG_OPENGLES if (ogl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_1_4) { #else /* FIXME: At this time (09/2014) there are a lot of Android phones that * don't support glBlendFuncSeparate even though they claim OpenGL ES 2.0 * support. Rather than not work on 20-25% of phones, we just don't support * separate blending on Android for now. */ #if defined ALLEGRO_ANDROID && !defined ALLEGRO_CFG_OPENGLES3 if (false) { #else if (ogl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_2_0) { #endif #endif glEnable(GL_BLEND); try_const_color(ogl_disp, &const_color); glBlendFuncSeparate(blend_modes[src_color], blend_modes[dst_color], blend_modes[src_alpha], blend_modes[dst_alpha]); if (ogl_disp->ogl_extras->ogl_info.version >= _ALLEGRO_OPENGL_VERSION_2_0) { glBlendEquationSeparate( blend_equations[op], blend_equations[op_alpha]); } else { glBlendEquation(blend_equations[op]); } } else { if (src_color == src_alpha && dst_color == dst_alpha) { glEnable(GL_BLEND); try_const_color(ogl_disp, &const_color); glBlendFunc(blend_modes[src_color], blend_modes[dst_color]); } else { ALLEGRO_ERROR("Blender unsupported with this OpenGL version (%d %d %d %d %d %d)\n", op, src_color, dst_color, op_alpha, src_alpha, dst_alpha); return false; } } return true; } /* These functions make drawing calls use shaders or the fixed pipeline * based on what the user has set up. FIXME: OpenGL only right now. */ static void vert_ptr_on(ALLEGRO_DISPLAY *display, int n, GLint t, int stride, void *v) { /* Only use this shader stuff with GLES2+ or equivalent */ if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.pos_loc >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.pos_loc, n, t, false, stride, v); glEnableVertexAttribArray(display->ogl_extras->varlocs.pos_loc); } #endif } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(n, t, stride, v); #endif } } static void vert_ptr_off(ALLEGRO_DISPLAY *display) { if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.pos_loc >= 0) { glDisableVertexAttribArray(display->ogl_extras->varlocs.pos_loc); } #endif } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION glDisableClientState(GL_VERTEX_ARRAY); #endif } } static void color_ptr_on(ALLEGRO_DISPLAY *display, int n, GLint t, int stride, void *v) { if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.color_loc >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.color_loc, n, t, false, stride, v); glEnableVertexAttribArray(display->ogl_extras->varlocs.color_loc); } #endif } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION glEnableClientState(GL_COLOR_ARRAY); glColorPointer(n, t, stride, v); #endif } } static void color_ptr_off(ALLEGRO_DISPLAY *display) { if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.color_loc >= 0) { glDisableVertexAttribArray(display->ogl_extras->varlocs.color_loc); } #endif } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION glDisableClientState(GL_COLOR_ARRAY); #endif } } static void tex_ptr_on(ALLEGRO_DISPLAY *display, int n, GLint t, int stride, void *v) { if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.texcoord_loc >= 0) { glVertexAttribPointer(display->ogl_extras->varlocs.texcoord_loc, n, t, false, stride, v); glEnableVertexAttribArray(display->ogl_extras->varlocs.texcoord_loc); } #endif } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(n, t, stride, v); #endif } } static void tex_ptr_off(ALLEGRO_DISPLAY *display) { if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (display->ogl_extras->varlocs.texcoord_loc >= 0) { glDisableVertexAttribArray(display->ogl_extras->varlocs.texcoord_loc); } #endif } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION glDisableClientState(GL_TEXTURE_COORD_ARRAY); #endif } } static void ogl_clear(ALLEGRO_DISPLAY *d, ALLEGRO_COLOR *color) { ALLEGRO_DISPLAY *ogl_disp = (void *)d; ALLEGRO_BITMAP *target = al_get_target_bitmap(); ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_target; float r, g, b, a; if (target->parent) target = target->parent; ogl_target = target->extra; if ((!ogl_target->is_backbuffer && ogl_disp->ogl_extras->opengl_target != target) || target->locked) { _al_clear_bitmap_by_locking(target, color); return; } al_unmap_rgba_f(*color, &r, &g, &b, &a); glClearColor(r, g, b, a); glClear(GL_COLOR_BUFFER_BIT); } static void ogl_draw_pixel(ALLEGRO_DISPLAY *d, float x, float y, ALLEGRO_COLOR *color) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_target; GLfloat vert[2]; GLfloat color_array[4]; /* For sub-bitmaps */ if (target->parent) { target = target->parent; } ogl_target = target->extra; if ((!ogl_target->is_backbuffer && d->ogl_extras->opengl_target != target) || target->locked || !_al_opengl_set_blender(d)) { _al_draw_pixel_memory(target, x, y, color); return; } vert[0] = x; vert[1] = y; color_array[0] = color->r; color_array[1] = color->g; color_array[2] = color->b; color_array[3] = color->a; vert_ptr_on(d, 2, GL_FLOAT, 2*sizeof(float), vert); color_ptr_on(d, 4, GL_FLOAT, 4*sizeof(float), color_array); // Should this be here if it's in the if above? if (!_al_opengl_set_blender(d)) { return; } glDrawArrays(GL_POINTS, 0, 1); vert_ptr_off(d); color_ptr_off(d); } static void* ogl_prepare_vertex_cache(ALLEGRO_DISPLAY* disp, int num_new_vertices) { disp->num_cache_vertices += num_new_vertices; if (!disp->vertex_cache) { disp->vertex_cache = al_malloc(num_new_vertices * sizeof(ALLEGRO_OGL_BITMAP_VERTEX)); disp->vertex_cache_size = num_new_vertices; } else if (disp->num_cache_vertices > disp->vertex_cache_size) { disp->vertex_cache = al_realloc(disp->vertex_cache, 2 * disp->num_cache_vertices * sizeof(ALLEGRO_OGL_BITMAP_VERTEX)); disp->vertex_cache_size = 2 * disp->num_cache_vertices; } return (ALLEGRO_OGL_BITMAP_VERTEX*)disp->vertex_cache + (disp->num_cache_vertices - num_new_vertices); } static void ogl_flush_vertex_cache(ALLEGRO_DISPLAY *disp) { GLuint current_texture; ALLEGRO_OGL_EXTRAS *o = disp->ogl_extras; (void)o; /* not used in all ports */ if (!disp->vertex_cache) return; if (disp->num_cache_vertices == 0) return; if (!_al_opengl_set_blender(disp)) { disp->num_cache_vertices = 0; return; } if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (disp->ogl_extras->varlocs.use_tex_loc >= 0) { glUniform1i(disp->ogl_extras->varlocs.use_tex_loc, 1); } if (disp->ogl_extras->varlocs.use_tex_matrix_loc >= 0) { glUniform1i(disp->ogl_extras->varlocs.use_tex_matrix_loc, 0); } #endif } else { glEnable(GL_TEXTURE_2D); } glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)¤t_texture); if (current_texture != disp->cache_texture) { if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE /* Use texture unit 0 */ glActiveTexture(GL_TEXTURE0); if (disp->ogl_extras->varlocs.tex_loc >= 0) glUniform1i(disp->ogl_extras->varlocs.tex_loc, 0); #endif } glBindTexture(GL_TEXTURE_2D, disp->cache_texture); } #if !defined(ALLEGRO_CFG_OPENGLES) && !defined(ALLEGRO_MACOSX) if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { int stride = sizeof(ALLEGRO_OGL_BITMAP_VERTEX); int bytes = disp->num_cache_vertices * stride; /* We create the VAO and VBO on first use. */ if (o->vao == 0) { glGenVertexArrays(1, &o->vao); ALLEGRO_DEBUG("new VAO: %u\n", o->vao); } glBindVertexArray(o->vao); if (o->vbo == 0) { glGenBuffers(1, &o->vbo); ALLEGRO_DEBUG("new VBO: %u\n", o->vbo); } glBindBuffer(GL_ARRAY_BUFFER, o->vbo); /* Then we upload data into it. */ glBufferData(GL_ARRAY_BUFFER, bytes, disp->vertex_cache, GL_STREAM_DRAW); /* Finally set the "pos", "texccord" and "color" attributes used by our * shader and enable them. */ if (o->varlocs.pos_loc >= 0) { glVertexAttribPointer(o->varlocs.pos_loc, 3, GL_FLOAT, false, stride, (void *)offsetof(ALLEGRO_OGL_BITMAP_VERTEX, x)); glEnableVertexAttribArray(o->varlocs.pos_loc); } if (o->varlocs.texcoord_loc >= 0) { glVertexAttribPointer(o->varlocs.texcoord_loc, 2, GL_FLOAT, false, stride, (void *)offsetof(ALLEGRO_OGL_BITMAP_VERTEX, tx)); glEnableVertexAttribArray(o->varlocs.texcoord_loc); } if (o->varlocs.color_loc >= 0) { glVertexAttribPointer(o->varlocs.color_loc, 4, GL_FLOAT, false, stride, (void *)offsetof(ALLEGRO_OGL_BITMAP_VERTEX, r)); glEnableVertexAttribArray(o->varlocs.color_loc); } } else #endif { vert_ptr_on(disp, 3, GL_FLOAT, sizeof(ALLEGRO_OGL_BITMAP_VERTEX), (char *)(disp->vertex_cache) + offsetof(ALLEGRO_OGL_BITMAP_VERTEX, x)); tex_ptr_on(disp, 2, GL_FLOAT, sizeof(ALLEGRO_OGL_BITMAP_VERTEX), (char*)(disp->vertex_cache) + offsetof(ALLEGRO_OGL_BITMAP_VERTEX, tx)); color_ptr_on(disp, 4, GL_FLOAT, sizeof(ALLEGRO_OGL_BITMAP_VERTEX), (char*)(disp->vertex_cache) + offsetof(ALLEGRO_OGL_BITMAP_VERTEX, r)); #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION if (!(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) glDisableClientState(GL_NORMAL_ARRAY); #endif } glGetError(); /* clear error */ glDrawArrays(GL_TRIANGLES, 0, disp->num_cache_vertices); #ifdef DEBUGMODE { int e = glGetError(); if (e) { ALLEGRO_WARN("glDrawArrays failed: %s\n", _al_gl_error_string(e)); } } #endif #if !defined ALLEGRO_CFG_OPENGLES && !defined ALLEGRO_MACOSX if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { if (o->varlocs.pos_loc >= 0) glDisableVertexAttribArray(o->varlocs.pos_loc); if (o->varlocs.texcoord_loc >= 0) glDisableVertexAttribArray(o->varlocs.texcoord_loc); if (o->varlocs.color_loc >= 0) glDisableVertexAttribArray(o->varlocs.color_loc); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } else #endif { vert_ptr_off(disp); tex_ptr_off(disp); color_ptr_off(disp); } disp->num_cache_vertices = 0; if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE if (disp->ogl_extras->varlocs.use_tex_loc >= 0) glUniform1i(disp->ogl_extras->varlocs.use_tex_loc, 0); #endif } else { glDisable(GL_TEXTURE_2D); } } static void ogl_update_transformation(ALLEGRO_DISPLAY* disp, ALLEGRO_BITMAP *target) { if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_SHADER_GLSL GLint loc = disp->ogl_extras->varlocs.projview_matrix_loc; ALLEGRO_TRANSFORM projview; al_copy_transform(&projview, &target->transform); al_compose_transform(&projview, &target->proj_transform); al_copy_transform(&disp->projview_transform, &projview); if (disp->ogl_extras->program_object > 0 && loc >= 0) { _al_glsl_set_projview_matrix(loc, &disp->projview_transform); } #endif } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION glMatrixMode(GL_PROJECTION); glLoadMatrixf((float *)target->proj_transform.m); glMatrixMode(GL_MODELVIEW); glLoadMatrixf((float *)target->transform.m); #endif } if (target->parent) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_extra = target->parent->extra; /* glViewport requires the bottom-left coordinate of the corner. */ glViewport(target->xofs, ogl_extra->true_h - (target->yofs + target->h), target->w, target->h); } else { glViewport(0, 0, target->w, target->h); } } static void ogl_clear_depth_buffer(ALLEGRO_DISPLAY *display, float x) { (void)display; #if defined(ALLEGRO_CFG_OPENGLES) glClearDepthf(x); #else glClearDepth(x); #endif /* We may want to defer this to the next glClear call as a combined * color/depth clear may be faster. */ glClear(GL_DEPTH_BUFFER_BIT); } /* Add drawing commands to the vtable. */ void _al_ogl_add_drawing_functions(ALLEGRO_DISPLAY_INTERFACE *vt) { vt->clear = ogl_clear; vt->draw_pixel = ogl_draw_pixel; vt->clear_depth_buffer = ogl_clear_depth_buffer; vt->flush_vertex_cache = ogl_flush_vertex_cache; vt->prepare_vertex_cache = ogl_prepare_vertex_cache; vt->update_transformation = ogl_update_transformation; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/opengl/ogl_fbo.c000066400000000000000000000454711473414355200173210ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * OpenGL framebuffer objects. * * See LICENSE.txt for copyright information. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_pixels.h" #ifdef ALLEGRO_ANDROID #include #include "allegro5/internal/aintern_android.h" #elif defined ALLEGRO_IPHONE #include "allegro5/internal/aintern_iphone.h" #endif #include "ogl_helpers.h" ALLEGRO_DEBUG_CHANNEL("opengl") /* forward declarations */ static void setup_fbo_backbuffer(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap); static void use_fbo_for_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap, ALLEGRO_FBO_INFO *info); /* glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT..) not supported on some Androids. * We keep track of it manually. */ #ifdef ALLEGRO_ANDROID static GLint _al_gl_curr_fbo = 0; GLint _al_android_get_curr_fbo(void) { return _al_gl_curr_fbo; } void _al_android_set_curr_fbo(GLint fbo) { _al_gl_curr_fbo = fbo; } GLint _al_ogl_bind_framebuffer(GLint fbo) { GLint old_fbo = _al_android_get_curr_fbo(); GLint e; if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) { glBindFramebuffer(GL_FRAMEBUFFER, fbo); } else { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); } e = glGetError(); if (e) { ALLEGRO_DEBUG("glBindFramebufferEXT failed (%s)", _al_gl_error_string(e)); } _al_android_set_curr_fbo(fbo); return old_fbo; } #else /* !ALLEGRO_ANDROID */ GLint _al_ogl_bind_framebuffer(GLint fbo) { GLint old_fbo; glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); return old_fbo; } #endif /* !ALLEGRO_ANDROID */ void _al_ogl_reset_fbo_info(ALLEGRO_FBO_INFO *info) { info->fbo_state = FBO_INFO_UNUSED; info->fbo = 0; info->buffers.depth_buffer = 0; info->buffers.multisample_buffer = 0; info->buffers.dw = 0; info->buffers.dh = 0; info->buffers.mw = 0; info->buffers.mh = 0; info->owner = NULL; info->last_use_time = 0.0; } #if (!defined ALLEGRO_CFG_OPENGLES) || defined ALLEGRO_CFG_OPENGLES3 static void check_gl_error(void) { GLint e = glGetError(); if (e) { ALLEGRO_ERROR("OpenGL call failed! (%s)\n", _al_gl_error_string(e)); } } #endif static void detach_depth_buffer(ALLEGRO_FBO_INFO *info) { #ifndef ALLEGRO_RASPBERRYPI if (info->buffers.depth_buffer == 0) return; ALLEGRO_DEBUG("Deleting depth render buffer: %u\n", info->buffers.depth_buffer); glDeleteRenderbuffersEXT(1, &info->buffers.depth_buffer); info->buffers.depth_buffer = 0; info->buffers.dw = 0; info->buffers.dh = 0; info->buffers.depth = 0; #endif } static void detach_multisample_buffer(ALLEGRO_FBO_INFO *info) { #ifndef ALLEGRO_RASPBERRYPI if (info->buffers.multisample_buffer == 0) return; ALLEGRO_DEBUG("Deleting multisample render buffer: %u\n", info->buffers.depth_buffer); glDeleteRenderbuffersEXT(1, &info->buffers.multisample_buffer); info->buffers.multisample_buffer = 0; info->buffers.mw = 0; info->buffers.mh = 0; info->buffers.samples = 0; #endif } static void attach_depth_buffer(ALLEGRO_FBO_INFO *info) { #if !defined ALLEGRO_RASPBERRYPI GLuint rb; GLenum gldepth = GL_DEPTH_COMPONENT16; ALLEGRO_BITMAP *b = info->owner; int bits = al_get_bitmap_depth(b); if (info->buffers.depth_buffer != 0) { if (info->buffers.depth != bits || info->buffers.dw != al_get_bitmap_width(b) || info->buffers.dh != al_get_bitmap_height(b)) { detach_depth_buffer(info); } } if (!bits) return; if (info->buffers.depth_buffer == 0) { ALLEGRO_DISPLAY *display = _al_get_bitmap_display(info->owner); int w = al_get_bitmap_width(info->owner); int h = al_get_bitmap_height(info->owner); #if !defined ALLEGRO_CFG_OPENGLES || defined ALLEGRO_CFG_OPENGLES3 if (bits == 24) gldepth = GL_DEPTH_COMPONENT24; #endif glGenRenderbuffersEXT(1, &rb); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rb); int samples = al_get_bitmap_samples(info->owner); bool extension_supported; #ifdef ALLEGRO_CFG_OPENGLES (void)display; extension_supported = al_have_opengl_extension("EXT_multisampled_render_to_texture"); #else extension_supported = display->ogl_extras->extension_list->ALLEGRO_GL_EXT_framebuffer_multisample; #endif if (samples == 0 || !extension_supported) glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, gldepth, w, h); #if !defined ALLEGRO_CFG_OPENGLES || defined ALLEGRO_CFG_OPENGLES3 else glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, gldepth, w, h); #else else { return; } #endif info->buffers.depth_buffer = rb; info->buffers.dw = w; info->buffers.dh = h; info->buffers.depth = bits; GLint e = glGetError(); if (e) { ALLEGRO_ERROR("glRenderbufferStorage failed! bits=%d w=%d h=%d (%s)\n", bits, w, h, _al_gl_error_string(e)); } else { ALLEGRO_DEBUG("Depth render buffer created: %u\n", info->buffers.depth_buffer); } glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rb); if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { ALLEGRO_ERROR("attaching depth renderbuffer failed\n"); } glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); } #endif } static void attach_multisample_buffer(ALLEGRO_FBO_INFO *info) { #if !defined ALLEGRO_CFG_OPENGLES || defined ALLEGRO_CFG_OPENGLES3 ALLEGRO_BITMAP *b = info->owner; int samples = al_get_bitmap_samples(b); if (info->buffers.multisample_buffer != 0) { if (info->buffers.samples != samples || info->buffers.mw != al_get_bitmap_width(b) || info->buffers.mh != al_get_bitmap_height(b)) { detach_multisample_buffer(info); } } if (!samples) return; ALLEGRO_DISPLAY *display = _al_get_bitmap_display(info->owner); if (!display->ogl_extras->extension_list->ALLEGRO_GL_EXT_framebuffer_multisample) return; #ifdef ALLEGRO_CFG_OPENGLES (void)display; #else if (info->buffers.multisample_buffer == 0) { GLuint rb; GLint e; int w = al_get_bitmap_width(info->owner); int h = al_get_bitmap_height(info->owner); glGenRenderbuffersEXT(1, &rb); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rb); check_gl_error(); glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, _al_ogl_get_glformat( al_get_bitmap_format(info->owner), 0), w, h); info->buffers.multisample_buffer = rb; info->buffers.mw = w; info->buffers.mh = h; info->buffers.samples = samples; e = glGetError(); if (e) { ALLEGRO_ERROR("glRenderbufferStorage failed! samples=%d w=%d h=%d (%s)\n", samples, w, h, _al_gl_error_string(e)); } else { ALLEGRO_DEBUG("Multisample render buffer created: %u\n", info->buffers.multisample_buffer); } glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, rb); if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { ALLEGRO_ERROR("attaching multisample renderbuffer failed\n"); } glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); } #endif #else (void)info; #endif } bool _al_ogl_create_persistent_fbo(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap; ALLEGRO_FBO_INFO *info; GLint old_fbo, e; if (bitmap->parent) bitmap = bitmap->parent; ogl_bitmap = bitmap->extra; /* Don't continue if the bitmap does not belong to the current display. */ if (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false && _al_get_bitmap_display(bitmap) != al_get_current_display()) { return false; } if (ogl_bitmap->is_backbuffer) { return false; } ASSERT(!ogl_bitmap->fbo_info); info = al_malloc(sizeof(ALLEGRO_FBO_INFO)); info->owner = bitmap; if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) { glGenFramebuffers(1, &info->fbo); } else { glGenFramebuffersEXT(1, &info->fbo); } if (info->fbo == 0) { al_free(info); return false; } old_fbo = _al_ogl_bind_framebuffer(info->fbo); if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ogl_bitmap->texture, 0); } else { glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, ogl_bitmap->texture, 0); } e = glGetError(); if (e) { ALLEGRO_DEBUG("glFrameBufferTexture2DEXT failed! fbo=%d texture=%d (%s)\n", info->fbo, ogl_bitmap->texture, _al_gl_error_string(e)); } attach_depth_buffer(info); /* You'll see this a couple times in this file: some ES 1.1 functions aren't * implemented on Android. This is an ugly workaround. */ if (UNLESS_ANDROID_OR_RPI( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)) { ALLEGRO_ERROR("FBO incomplete.\n"); _al_ogl_bind_framebuffer(old_fbo); glDeleteFramebuffersEXT(1, &info->fbo); al_free(info); return false; } _al_ogl_bind_framebuffer(old_fbo); info->fbo_state = FBO_INFO_PERSISTENT; info->last_use_time = al_get_time(); ogl_bitmap->fbo_info = info; ALLEGRO_DEBUG("Persistent FBO: %u\n", info->fbo); return true; } ALLEGRO_FBO_INFO *_al_ogl_persist_fbo(ALLEGRO_DISPLAY *display, ALLEGRO_FBO_INFO *transient_fbo_info) { ALLEGRO_OGL_EXTRAS *extras = display->ogl_extras; int i; ASSERT(transient_fbo_info->fbo_state == FBO_INFO_TRANSIENT); for (i = 0; i < ALLEGRO_MAX_OPENGL_FBOS; i++) { if (transient_fbo_info == &extras->fbos[i]) { ALLEGRO_FBO_INFO *new_info = al_malloc(sizeof(ALLEGRO_FBO_INFO)); *new_info = *transient_fbo_info; new_info->fbo_state = FBO_INFO_PERSISTENT; _al_ogl_reset_fbo_info(transient_fbo_info); ALLEGRO_DEBUG("Persistent FBO: %u\n", new_info->fbo); return new_info; } } ALLEGRO_ERROR("Could not find FBO %u in pool\n", transient_fbo_info->fbo); return transient_fbo_info; } static ALLEGRO_FBO_INFO *ogl_find_unused_fbo(ALLEGRO_DISPLAY *display) { ALLEGRO_OGL_EXTRAS *extras = display->ogl_extras; double min_time = DBL_MAX; int min_time_index = -1; int i; for (i = 0; i < ALLEGRO_MAX_OPENGL_FBOS; i++) { if (extras->fbos[i].fbo_state == FBO_INFO_UNUSED) return &extras->fbos[i]; if (extras->fbos[i].last_use_time < min_time) { min_time = extras->fbos[i].last_use_time; min_time_index = i; } } return &extras->fbos[min_time_index]; } void _al_ogl_del_fbo(ALLEGRO_FBO_INFO *info) { ALLEGRO_BITMAP_EXTRA_OPENGL *extra = info->owner->extra; extra->fbo_info = NULL; ALLEGRO_DEBUG("Deleting FBO: %u\n", info->fbo); if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) { glDeleteFramebuffers(1, &info->fbo); } else { glDeleteFramebuffersEXT(1, &info->fbo); } detach_depth_buffer(info); detach_multisample_buffer(info); info->fbo = 0; } static ALLEGRO_FBO_INFO *ogl_new_fbo(ALLEGRO_DISPLAY *display) { ALLEGRO_FBO_INFO *info; GLint e; info = ogl_find_unused_fbo(display); ASSERT(info->fbo_state != FBO_INFO_PERSISTENT); if (info->fbo_state == FBO_INFO_TRANSIENT) { _al_ogl_del_fbo(info); _al_ogl_reset_fbo_info(info); } else { /* FBO_INFO_UNUSED */ } if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) { glGenFramebuffers(1, &info->fbo); } else { glGenFramebuffersEXT(1, &info->fbo); } e = glGetError(); if (e) { ALLEGRO_ERROR("glGenFramebuffersEXT failed\n"); _al_ogl_reset_fbo_info(info); return NULL; } ALLEGRO_DEBUG("Created FBO: %u\n", info->fbo); return info; } void _al_ogl_setup_fbo(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap; if (bitmap->parent) bitmap = bitmap->parent; ogl_bitmap = bitmap->extra; /* We can't return here. Target's FBO can be taken away by locking * a lot of bitmaps consecutively. * Also affects ex_multiwin; resizing one window affects the other. */ if (false && display->ogl_extras->opengl_target == bitmap) return; _al_ogl_unset_target_bitmap(display, display->ogl_extras->opengl_target); if (ogl_bitmap->is_backbuffer) setup_fbo_backbuffer(display, bitmap); else _al_ogl_setup_fbo_non_backbuffer(display, bitmap); } /* With the framebuffer_multisample extension, the absolutely one and * only way to ever access the multisample buffer is with the * framebuffer_blit extension. [1] * * This is what we do in this function - if there is a multisample * buffer, downsample it back into the texture. * * [1] https://www.opengl.org/registry/specs/EXT/framebuffer_multisample.txt */ void _al_ogl_finalize_fbo(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_OPENGL *extra = bitmap->extra; if (!extra) return; ALLEGRO_FBO_INFO *info = extra->fbo_info; (void)display; if (!info) return; if (!info->buffers.multisample_buffer) return; #ifndef ALLEGRO_CFG_OPENGLES int w = al_get_bitmap_width(bitmap); int h = al_get_bitmap_height(bitmap); GLuint blit_fbo; glGenFramebuffersEXT(1, &blit_fbo); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blit_fbo); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, extra->texture, 0); glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, info->fbo); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, blit_fbo); glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); check_gl_error(); glDeleteFramebuffersEXT(1, &blit_fbo); #else (void)bitmap; #endif } static void setup_fbo_backbuffer(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { display->ogl_extras->opengl_target = bitmap; // The IS_OPENGLES part is a hack. if (IS_OPENGLES || display->ogl_extras->extension_list->ALLEGRO_GL_EXT_framebuffer_object || display->ogl_extras->extension_list->ALLEGRO_GL_OES_framebuffer_object) { _al_ogl_bind_framebuffer(0); } #ifdef ALLEGRO_IPHONE _al_iphone_setup_opengl_view(display, false); #endif } bool _al_ogl_setup_fbo_non_backbuffer(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra; ALLEGRO_FBO_INFO *info; ASSERT(bitmap->parent == NULL); /* When a bitmap is set as target bitmap, we try to create an FBO for it. */ info = ogl_bitmap->fbo_info; if (!info) { /* FIXME The IS_OPENGLES part is quite a hack but I don't know how the * Allegro extension manager works to fix this properly (getting * extensions properly reported on iphone). All iOS devices support * FBOs though (currently.) */ if (IS_OPENGLES || al_get_opengl_extension_list()->ALLEGRO_GL_EXT_framebuffer_object || al_get_opengl_extension_list()->ALLEGRO_GL_OES_framebuffer_object) { info = ogl_new_fbo(display); } } if (!info || info->fbo == 0) { return false; } use_fbo_for_bitmap(display, bitmap, info); return true; /* state changed */ } static void use_fbo_for_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap, ALLEGRO_FBO_INFO *info) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra; GLint e; if (info->fbo_state == FBO_INFO_UNUSED) info->fbo_state = FBO_INFO_TRANSIENT; info->owner = bitmap; info->last_use_time = al_get_time(); ogl_bitmap->fbo_info = info; /* Bind to the FBO. */ _al_ogl_bind_framebuffer(info->fbo); attach_multisample_buffer(info); attach_depth_buffer(info); /* If we have a multisample renderbuffer, we can only syncronize * it back to the texture once we stop drawing into it - i.e. * when the target bitmap is changed to something else. */ if (!info->buffers.multisample_buffer) { /* Attach the texture. */ #ifdef ALLEGRO_CFG_OPENGLES if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) { if (al_get_bitmap_samples(bitmap) == 0 || !al_have_opengl_extension("EXT_multisampled_render_to_texture")) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ogl_bitmap->texture, 0); } #if ((!defined ALLEGRO_CFG_OPENGLES || defined ALLEGRO_CFG_OPENGLES3) && !defined ALLEGRO_IPHONE) #if (!defined ALLEGRO_ANDROID) || (__ANDROID_API__ >= 28) /* Android: glFramebufferTexture2DMultisampleEXT exists in newer libGLESv[23].so */ else { glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ogl_bitmap->texture, 0, al_get_bitmap_samples(bitmap)); } #endif #endif } else #endif { glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, ogl_bitmap->texture, 0); } e = glGetError(); if (e) { ALLEGRO_DEBUG("glFrameBufferTexture2DEXT failed! fbo=%d texture=%d (%s)\n", info->fbo, ogl_bitmap->texture, _al_gl_error_string(e)); } } /* See comment about unimplemented functions on Android above */ if (UNLESS_ANDROID_OR_RPI( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)) { /* For some reason, we cannot use the FBO with this * texture. So no reason to keep re-trying, output a log * message and switch to (extremely slow) software mode. */ ALLEGRO_ERROR("Could not use FBO for bitmap with format %s.\n", _al_pixel_format_name(al_get_bitmap_format(bitmap))); ALLEGRO_ERROR("*** SWITCHING TO SOFTWARE MODE ***\n"); _al_ogl_bind_framebuffer(0); glDeleteFramebuffersEXT(1, &info->fbo); _al_ogl_reset_fbo_info(info); ogl_bitmap->fbo_info = NULL; } else { display->ogl_extras->opengl_target = bitmap; } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/opengl/ogl_helpers.h000066400000000000000000000073351473414355200202170ustar00rootroot00000000000000#ifndef __al_included_ogl_helpers_h #define __al_included_ogl_helpers_h #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" /* Some definitions to smooth out the code in the opengl directory. */ #ifdef ALLEGRO_CFG_OPENGLES #define IS_OPENGLES (true) #else #define IS_OPENGLES (false) #endif #ifdef ALLEGRO_IPHONE #define IS_IPHONE (true) #else #define IS_IPHONE (false) #endif #ifdef ALLEGRO_ANDROID #define IS_ANDROID (true) #define IS_ANDROID_AND(x) (x) #else #define IS_ANDROID (false) #define IS_ANDROID_AND(x) (false) #endif #ifdef ALLEGRO_RASPBERRYPI #define IS_RASPBERRYPI (true) #else #define IS_RASPBERRYPI (false) #endif #if defined(ALLEGRO_ANDROID) || defined(ALLEGRO_RASPBERRYPI) #define UNLESS_ANDROID_OR_RPI(x) (0) #else #define UNLESS_ANDROID_OR_RPI(x) (x) #endif /* Android uses different functions/symbol names depending on ES version */ #define ANDROID_PROGRAMMABLE_PIPELINE(dpy) \ IS_ANDROID_AND(al_get_display_flags(dpy) & ALLEGRO_PROGRAMMABLE_PIPELINE) #if defined ALLEGRO_CFG_OPENGLES2 #ifndef GL_EXT_draw_buffers #define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0 #endif #define GL_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING #define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE #define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER #define GL_RENDERBUFFER_EXT GL_RENDERBUFFER #define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT #define glBindFramebufferEXT glBindFramebuffer #define glCheckFramebufferStatusEXT glCheckFramebufferStatus #define glDeleteFramebuffersEXT glDeleteFramebuffers #define glFramebufferTexture2DEXT glFramebufferTexture2D #define glGenFramebuffersEXT glGenFramebuffers #define glGenerateMipmapEXT glGenerateMipmap #define glOrtho glOrthof #define glGenRenderbuffersEXT glGenRenderbuffers #define glBindRenderbufferEXT glBindRenderbuffer #define glRenderbufferStorageEXT glRenderbufferStorage #define glFramebufferRenderbufferEXT glFramebufferRenderbuffer #define glDeleteRenderbuffersEXT glDeleteRenderbuffers #define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT #elif defined ALLEGRO_CFG_OPENGLES /* Note: This works because all the constants are the same, e.g. * GL_FRAMEBUFFER_OES == GL_FRAMEBUFFER_EXT == 0x8D40 * And so we can use the OpenGL framebuffer extension in the same was * as the OpenGL ES framebuffer extension. */ #ifndef GL_EXT_draw_buffers #define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0_OES #endif #define GL_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_OES #define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE_OES #define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER_OES #define GL_RENDERBUFFER_EXT GL_RENDERBUFFER_OES #define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT_OES #define glBindFramebufferEXT glBindFramebufferOES #define glCheckFramebufferStatusEXT glCheckFramebufferStatusOES #define glDeleteFramebuffersEXT glDeleteFramebuffersOES #define glFramebufferTexture2DEXT glFramebufferTexture2DOES #define glGenFramebuffersEXT glGenFramebuffersOES #define glGenerateMipmapEXT glGenerateMipmapOES #define glGenRenderbuffersEXT glGenRenderbuffersOES #define glBindRenderbufferEXT glBindRenderbufferOES #define glRenderbufferStorageEXT glRenderbufferStorageOES #define glFramebufferRenderbufferEXT glFramebufferRenderbufferOES #define glOrtho glOrthof #define glDeleteRenderbuffersEXT glDeleteRenderbuffersOES #endif #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/opengl/ogl_lock.c000066400000000000000000000525571473414355200175060ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * OpenGL bitmap locking. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_pixels.h" /* * This is an attempt to refactor ogl_lock_region and ogl_unlock_region. * To begin with it only supports desktop OpenGL. Support for mobile platforms * should be migrated here gradually, but PLEASE try not to do it by inserting * #ifdefs everywhere. Combined with huge functions, that made the previous * version very hard to follow and prone to break. */ #if !defined(ALLEGRO_CFG_OPENGLES) ALLEGRO_DEBUG_CHANNEL("opengl") #define get_glformat(f, c) _al_ogl_get_glformat((f), (c)) /* * Helpers - duplicates code in ogl_bitmap.c for now */ static int ogl_pixel_alignment(int pixel_size) { /* Valid alignments are: 1, 2, 4, 8 bytes. */ switch (pixel_size) { case 1: case 2: case 4: case 8: return pixel_size; case 3: return 1; case 16: /* float32 */ return 4; default: ASSERT(false); return 4; } } static int ogl_pitch(int w, int pixel_size) { int pitch = w * pixel_size; return pitch; } static bool exactly_15bpp(int pixel_format) { return pixel_format == ALLEGRO_PIXEL_FORMAT_RGB_555 || pixel_format == ALLEGRO_PIXEL_FORMAT_BGR_555; } /* * Locking */ static bool ogl_lock_region_backbuffer( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format, int flags); static bool ogl_lock_region_nonbb_writeonly( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format); static bool ogl_lock_region_nonbb_readwrite( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format, bool* restore_fbo); static bool ogl_lock_region_nonbb_readwrite_fbo( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format); static bool ogl_lock_region_nonbb_readwrite_nonfbo( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format); ALLEGRO_LOCKED_REGION *_al_ogl_lock_region_new(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int format, int flags) { ALLEGRO_BITMAP_EXTRA_OPENGL * const ogl_bitmap = bitmap->extra; const GLint gl_y = bitmap->h - y - h; ALLEGRO_DISPLAY *disp; ALLEGRO_DISPLAY *old_disp = NULL; ALLEGRO_BITMAP *old_target = al_get_target_bitmap(); GLenum e; bool ok; bool restore_fbo = false; bool reset_alignment = false; if (format == ALLEGRO_PIXEL_FORMAT_ANY) { /* Never pick compressed formats with ANY, as it interacts weirdly with * existing code (e.g. al_get_pixel_size() etc) */ int bitmap_format = al_get_bitmap_format(bitmap); if (_al_pixel_format_is_compressed(bitmap_format)) { // XXX Get a good format from the driver? format = ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE; } else { format = bitmap_format; } } disp = al_get_current_display(); format = _al_get_real_pixel_format(disp, format); /* Change OpenGL context if necessary. */ if (!disp || (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false && _al_get_bitmap_display(bitmap) != disp)) { old_disp = disp; _al_set_current_display_only(_al_get_bitmap_display(bitmap)); } ok = true; /* Set up the pixel store state. We will need to match it when unlocking. * There may be other pixel store state we should be setting. * See also pitfalls 7 & 8 from: * http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/ */ int previous_alignment; glGetIntegerv(GL_PACK_ALIGNMENT, &previous_alignment); { const int pixel_size = al_get_pixel_size(format); const int pixel_alignment = ogl_pixel_alignment(pixel_size); if (previous_alignment != pixel_alignment) { reset_alignment = true; glPixelStorei(GL_PACK_ALIGNMENT, pixel_alignment); e = glGetError(); if (e) { ALLEGRO_ERROR("glPixelStorei(GL_PACK_ALIGNMENT, %d) failed (%s).\n", pixel_alignment, _al_gl_error_string(e)); ok = false; } } } if (ok) { if (ogl_bitmap->is_backbuffer) { ALLEGRO_DEBUG("Locking backbuffer\n"); ok = ogl_lock_region_backbuffer(bitmap, ogl_bitmap, x, gl_y, w, h, format, flags); } else if (flags & ALLEGRO_LOCK_WRITEONLY) { ALLEGRO_DEBUG("Locking non-backbuffer WRITEONLY\n"); ok = ogl_lock_region_nonbb_writeonly(bitmap, ogl_bitmap, x, gl_y, w, h, format); } else { ALLEGRO_DEBUG("Locking non-backbuffer READWRITE\n"); ok = ogl_lock_region_nonbb_readwrite(bitmap, ogl_bitmap, x, gl_y, w, h, format, &restore_fbo); } } if (reset_alignment) { glPixelStorei(GL_PACK_ALIGNMENT, previous_alignment); } /* Restore state after switching FBO. */ if (restore_fbo) { if (!old_target) { /* Old target was NULL; release the context. */ _al_set_current_display_only(NULL); } else if (!_al_get_bitmap_display(old_target)) { /* Old target was memory bitmap; leave the current display alone. */ } else if (old_target != bitmap) { /* Old target was another OpenGL bitmap. */ _al_ogl_setup_fbo(_al_get_bitmap_display(old_target), old_target); } } ASSERT(al_get_target_bitmap() == old_target); if (old_disp != NULL) { _al_set_current_display_only(old_disp); } if (ok) { return &bitmap->locked_region; } ALLEGRO_ERROR("Failed to lock region\n"); ASSERT(ogl_bitmap->lock_buffer == NULL); return NULL; } static bool ogl_lock_region_backbuffer( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format, int flags) { const int pixel_size = al_get_pixel_size(format); const int pitch = ogl_pitch(w, pixel_size); GLenum e; ogl_bitmap->lock_buffer = al_malloc(pitch * h); if (ogl_bitmap->lock_buffer == NULL) { return false; } if (!(flags & ALLEGRO_LOCK_WRITEONLY)) { glReadPixels(x, gl_y, w, h, get_glformat(format, 2), get_glformat(format, 1), ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glReadPixels for format %s failed (%s).\n", _al_pixel_format_name(format), _al_gl_error_string(e)); al_free(ogl_bitmap->lock_buffer); ogl_bitmap->lock_buffer = NULL; return false; } } bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (h - 1); bitmap->locked_region.format = format; bitmap->locked_region.pitch = -pitch; bitmap->locked_region.pixel_size = pixel_size; return true; } static bool ogl_lock_region_nonbb_writeonly( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format) { const int pixel_size = al_get_pixel_size(format); const int pitch = ogl_pitch(w, pixel_size); (void) x; (void) gl_y; ogl_bitmap->lock_buffer = al_malloc(pitch * h); if (ogl_bitmap->lock_buffer == NULL) { return false; } bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (h - 1); bitmap->locked_region.format = format; bitmap->locked_region.pitch = -pitch; bitmap->locked_region.pixel_size = pixel_size; return true; } static bool ogl_lock_region_nonbb_readwrite( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format, bool* restore_fbo) { bool ok; ASSERT(bitmap->parent == NULL); ASSERT(bitmap->locked == false); ASSERT(_al_get_bitmap_display(bitmap) == al_get_current_display()); /* Try to create an FBO if there isn't one. */ *restore_fbo = _al_ogl_setup_fbo_non_backbuffer(_al_get_bitmap_display(bitmap), bitmap); if (ogl_bitmap->fbo_info) { ALLEGRO_DEBUG("Locking non-backbuffer READWRITE with fbo\n"); ok = ogl_lock_region_nonbb_readwrite_fbo(bitmap, ogl_bitmap, x, gl_y, w, h, format); } else { ALLEGRO_DEBUG("Locking non-backbuffer READWRITE no fbo\n"); ok = ogl_lock_region_nonbb_readwrite_nonfbo(bitmap, ogl_bitmap, x, gl_y, w, h, format); } return ok; } static bool ogl_lock_region_nonbb_readwrite_fbo( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format) { const int pixel_size = al_get_pixel_size(format); const int pitch = ogl_pitch(w, pixel_size); GLint old_fbo; GLenum e; bool ok; glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo); e = glGetError(); if (e) { ALLEGRO_ERROR("glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT) failed (%s).\n", _al_gl_error_string(e)); return false; } ok = true; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ogl_bitmap->fbo_info->fbo); e = glGetError(); if (e) { ALLEGRO_ERROR("glBindFramebufferEXT failed (%s).\n", _al_gl_error_string(e)); ok = false; } if (ok) { ogl_bitmap->lock_buffer = al_malloc(pitch * h); if (ogl_bitmap->lock_buffer == NULL) { ok = false; } } if (ok) { glReadPixels(x, gl_y, w, h, get_glformat(format, 2), get_glformat(format, 1), ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glReadPixels for format %s failed (%s).\n", _al_pixel_format_name(format), _al_gl_error_string(e)); } } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fbo); if (ok) { bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (h - 1); bitmap->locked_region.format = format; bitmap->locked_region.pitch = -pitch; bitmap->locked_region.pixel_size = pixel_size; return true; } al_free(ogl_bitmap->lock_buffer); ogl_bitmap->lock_buffer = NULL; return ok; } static bool ogl_lock_region_nonbb_readwrite_nonfbo( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format) { /* No FBO - fallback to reading the entire texture */ const int pixel_size = al_get_pixel_size(format); const int pitch = ogl_pitch(ogl_bitmap->true_w, pixel_size); GLenum e; bool ok; (void) w; ogl_bitmap->lock_buffer = al_malloc(pitch * ogl_bitmap->true_h); if (ogl_bitmap->lock_buffer == NULL) { return false; } ok = true; glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture); glGetTexImage(GL_TEXTURE_2D, 0, get_glformat(format, 2), get_glformat(format, 1), ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glGetTexImage for format %s failed (%s).\n", _al_pixel_format_name(format), _al_gl_error_string(e)); al_free(ogl_bitmap->lock_buffer); ogl_bitmap->lock_buffer = NULL; ok = false; } if (ok) { bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (gl_y + h - 1) + pixel_size * x; bitmap->locked_region.format = format; bitmap->locked_region.pitch = -pitch; bitmap->locked_region.pixel_size = pixel_size; } return ok; } /* * Unlocking */ static void ogl_unlock_region_non_readonly(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap); static void ogl_unlock_region_backbuffer(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y); static void ogl_unlock_region_nonbb_fbo(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format); static void ogl_unlock_region_nonbb_fbo_writeonly(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format); static void ogl_unlock_region_nonbb_fbo_readwrite(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y); static void ogl_unlock_region_nonbb_nonfbo(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y); void _al_ogl_unlock_region_new(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra; if (bitmap->lock_flags & ALLEGRO_LOCK_READONLY) { ALLEGRO_DEBUG("Unlocking non-backbuffer READONLY\n"); } else { ogl_unlock_region_non_readonly(bitmap, ogl_bitmap); } al_free(ogl_bitmap->lock_buffer); ogl_bitmap->lock_buffer = NULL; } static void ogl_unlock_region_non_readonly(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap) { const int lock_format = bitmap->locked_region.format; const int gl_y = bitmap->h - bitmap->lock_y - bitmap->lock_h; ALLEGRO_DISPLAY *old_disp = NULL; ALLEGRO_DISPLAY *disp; int orig_format; bool biased_alpha = false; bool reset_alignment = false; GLenum e; disp = al_get_current_display(); orig_format = _al_get_real_pixel_format(disp, _al_get_bitmap_memory_format(bitmap)); /* Change OpenGL context if necessary. */ if (!disp || (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false && _al_get_bitmap_display(bitmap) != disp)) { old_disp = disp; _al_set_current_display_only(_al_get_bitmap_display(bitmap)); } /* Keep this in sync with ogl_lock_region. */ int previous_alignment; glGetIntegerv(GL_UNPACK_ALIGNMENT, &previous_alignment); { const int lock_pixel_size = al_get_pixel_size(lock_format); const int pixel_alignment = ogl_pixel_alignment(lock_pixel_size); if (pixel_alignment != previous_alignment) { reset_alignment = true; glPixelStorei(GL_UNPACK_ALIGNMENT, pixel_alignment); e = glGetError(); if (e) { ALLEGRO_ERROR("glPixelStorei(GL_UNPACK_ALIGNMENT, %d) failed (%s).\n", pixel_alignment, _al_gl_error_string(e)); } } } if (exactly_15bpp(lock_format)) { /* OpenGL does not support 15-bpp internal format without an alpha, * so when storing such data we must ensure the alpha bit is set. */ glPixelTransferi(GL_ALPHA_BIAS, 1); biased_alpha = true; } if (ogl_bitmap->is_backbuffer) { ALLEGRO_DEBUG("Unlocking backbuffer\n"); ogl_unlock_region_backbuffer(bitmap, ogl_bitmap, gl_y); } else { glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture); if (ogl_bitmap->fbo_info) { ALLEGRO_DEBUG("Unlocking non-backbuffer (FBO)\n"); ogl_unlock_region_nonbb_fbo(bitmap, ogl_bitmap, gl_y, orig_format); } else { ALLEGRO_DEBUG("Unlocking non-backbuffer (non-FBO)\n"); ogl_unlock_region_nonbb_nonfbo(bitmap, ogl_bitmap, gl_y); } /* If using FBOs, we need to regenerate mipmaps explicitly now. */ /* XXX why don't we check ogl_bitmap->fbo_info? */ if ((al_get_bitmap_flags(bitmap) & ALLEGRO_MIPMAP) && al_get_opengl_extension_list()->ALLEGRO_GL_EXT_framebuffer_object) { glGenerateMipmapEXT(GL_TEXTURE_2D); e = glGetError(); if (e) { ALLEGRO_ERROR("glGenerateMipmapEXT for texture %d failed (%s).\n", ogl_bitmap->texture, _al_gl_error_string(e)); } } } if (biased_alpha) { glPixelTransferi(GL_ALPHA_BIAS, 0); } if (reset_alignment) { glPixelStorei(GL_UNPACK_ALIGNMENT, previous_alignment); } if (old_disp) { _al_set_current_display_only(old_disp); } } static void ogl_unlock_region_backbuffer(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y) { const int lock_format = bitmap->locked_region.format; bool popmatrix = false; GLenum e; GLint program = 0; ALLEGRO_DISPLAY *display = al_get_current_display(); if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { // FIXME: This is a hack where we temporarily disable the active shader. // It will only work on Desktop OpenGL in non-strict mode where we even // can switch back to the fixed pipeline. The correct way would be to not // use any OpenGL 2 functions (like glDrawPixels). Probably we will want // separate OpenGL <= 2 (including OpenGL ES 1) and OpenGL >= 3 (including // OpenGL ES >= 2) drivers at some point. glGetIntegerv(GL_CURRENT_PROGRAM, &program); glUseProgram(0); } /* glWindowPos2i may not be available. */ if (al_get_opengl_version() >= _ALLEGRO_OPENGL_VERSION_1_4) { glWindowPos2i(bitmap->lock_x, gl_y); } else { /* glRasterPos is affected by the current modelview and projection * matrices (so maybe we actually need to reset both of them?). * The coordinate is also clipped; the small offset was required to * prevent it being culled on one of my machines. --pw * * Consider using glWindowPos2fMESAemulate from: * http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/ */ glPushMatrix(); glLoadIdentity(); glRasterPos2f(bitmap->lock_x, bitmap->lock_y + bitmap->lock_h - 1e-4f); popmatrix = true; } glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glDrawPixels(bitmap->lock_w, bitmap->lock_h, get_glformat(lock_format, 2), get_glformat(lock_format, 1), ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glDrawPixels for format %s failed (%s).\n", _al_pixel_format_name(lock_format), _al_gl_error_string(e)); } if (popmatrix) { glPopMatrix(); } if (program != 0) { glUseProgram(program); } } static void ogl_unlock_region_nonbb_fbo(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format) { if (bitmap->lock_flags & ALLEGRO_LOCK_WRITEONLY) { ALLEGRO_DEBUG("Unlocking non-backbuffer FBO WRITEONLY\n"); ogl_unlock_region_nonbb_fbo_writeonly(bitmap, ogl_bitmap, gl_y, orig_format); } else { ALLEGRO_DEBUG("Unlocking non-backbuffer FBO READWRITE\n"); ogl_unlock_region_nonbb_fbo_readwrite(bitmap, ogl_bitmap, gl_y); } } static void ogl_unlock_region_nonbb_fbo_writeonly(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format) { const int lock_format = bitmap->locked_region.format; const int orig_pixel_size = al_get_pixel_size(orig_format); const int dst_pitch = bitmap->lock_w * orig_pixel_size; unsigned char * const tmpbuf = al_malloc(dst_pitch * bitmap->lock_h); GLenum e; _al_convert_bitmap_data( ogl_bitmap->lock_buffer, bitmap->locked_region.format, -bitmap->locked_region.pitch, tmpbuf, orig_format, dst_pitch, 0, 0, 0, 0, bitmap->lock_w, bitmap->lock_h); glTexSubImage2D(GL_TEXTURE_2D, 0, bitmap->lock_x, gl_y, bitmap->lock_w, bitmap->lock_h, get_glformat(orig_format, 2), get_glformat(orig_format, 1), tmpbuf); e = glGetError(); if (e) { ALLEGRO_ERROR("glTexSubImage2D for format %d failed (%s).\n", lock_format, _al_gl_error_string(e)); } al_free(tmpbuf); } static void ogl_unlock_region_nonbb_fbo_readwrite(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y) { const int lock_format = bitmap->locked_region.format; GLenum e; GLint tex_internalformat; glTexSubImage2D(GL_TEXTURE_2D, 0, bitmap->lock_x, gl_y, bitmap->lock_w, bitmap->lock_h, get_glformat(lock_format, 2), get_glformat(lock_format, 1), ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glTexSubImage2D for format %s failed (%s).\n", _al_pixel_format_name(lock_format), _al_gl_error_string(e)); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &tex_internalformat); ALLEGRO_DEBUG("x/y/w/h: %d/%d/%d/%d, internal format: %d\n", bitmap->lock_x, gl_y, bitmap->lock_w, bitmap->lock_h, tex_internalformat); } } static void ogl_unlock_region_nonbb_nonfbo(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y) { const int lock_format = bitmap->locked_region.format; unsigned char *start_ptr; GLenum e; if (bitmap->lock_flags & ALLEGRO_LOCK_WRITEONLY) { ALLEGRO_DEBUG("Unlocking non-backbuffer non-FBO WRITEONLY\n"); start_ptr = ogl_bitmap->lock_buffer; } else { ALLEGRO_DEBUG("Unlocking non-backbuffer non-FBO READWRITE\n"); glPixelStorei(GL_UNPACK_ROW_LENGTH, ogl_bitmap->true_w); start_ptr = (unsigned char *)bitmap->lock_data + (bitmap->lock_h - 1) * bitmap->locked_region.pitch; } glTexSubImage2D(GL_TEXTURE_2D, 0, bitmap->lock_x, gl_y, bitmap->lock_w, bitmap->lock_h, get_glformat(lock_format, 2), get_glformat(lock_format, 1), start_ptr); e = glGetError(); if (e) { ALLEGRO_ERROR("glTexSubImage2D for format %s failed (%s).\n", _al_pixel_format_name(lock_format), _al_gl_error_string(e)); } } #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/opengl/ogl_lock_es.c000066400000000000000000000524061473414355200201660ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * OpenGL bitmap locking (GLES). * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_pixels.h" #if defined ALLEGRO_ANDROID #include "allegro5/internal/aintern_android.h" #endif #include "ogl_helpers.h" /* * This is the GLES implementation of ogl_lock_region and ogl_unlock_region. * The version for desktop GL is in ogl_lock.c. They are pretty similar again * so probably could consider unifying them again. */ #if defined(ALLEGRO_CFG_OPENGLES) ALLEGRO_DEBUG_CHANNEL("opengl") #define get_glformat(f, c) _al_ogl_get_glformat((f), (c)) /* * Helpers - duplicates code in ogl_bitmap.c for now */ static int ogl_pixel_alignment(int pixel_size) { /* Valid alignments are: 1, 2, 4, 8 bytes. */ switch (pixel_size) { case 1: case 2: case 4: case 8: return pixel_size; case 3: return 1; case 16: /* float32 */ return 4; default: ASSERT(false); return 4; } } static int ogl_pitch(int w, int pixel_size) { int pitch = w * pixel_size; return pitch; } /* * Locking */ static ALLEGRO_LOCKED_REGION *ogl_lock_region_bb_readonly( ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int real_format); static ALLEGRO_LOCKED_REGION *ogl_lock_region_bb_proxy(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int real_format, int flags); static ALLEGRO_LOCKED_REGION *ogl_lock_region_nonbb(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int real_format, int flags); static bool ogl_lock_region_nonbb_writeonly( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int real_format); static bool ogl_lock_region_nonbb_readwrite( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int real_format, bool* restore_fbo); static bool ogl_lock_region_nonbb_readwrite_fbo( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int real_format); ALLEGRO_LOCKED_REGION *_al_ogl_lock_region_gles(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int format, int flags) { ALLEGRO_BITMAP_EXTRA_OPENGL * const ogl_bitmap = bitmap->extra; ALLEGRO_DISPLAY *disp; int real_format; if (format == ALLEGRO_PIXEL_FORMAT_ANY) { /* Never pick compressed formats with ANY, as it interacts weirdly with * existing code (e.g. al_get_pixel_size() etc) */ int bitmap_format = al_get_bitmap_format(bitmap); if (_al_pixel_format_is_compressed(bitmap_format)) { // XXX Get a good format from the driver? format = ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE; } else { format = bitmap_format; } } disp = al_get_current_display(); real_format = _al_get_real_pixel_format(disp, format); if (ogl_bitmap->is_backbuffer) { if (flags & ALLEGRO_LOCK_READONLY) { return ogl_lock_region_bb_readonly(bitmap, x, y, w, h, real_format); } else { return ogl_lock_region_bb_proxy(bitmap, x, y, w, h, real_format, flags); } } else { return ogl_lock_region_nonbb(bitmap, x, y, w, h, real_format, flags); } } static ALLEGRO_LOCKED_REGION *ogl_lock_region_bb_readonly( ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int real_format) { ALLEGRO_BITMAP_EXTRA_OPENGL * const ogl_bitmap = bitmap->extra; const int pixel_size = al_get_pixel_size(real_format); const int pitch = ogl_pitch(w, pixel_size); const int gl_y = bitmap->h - y - h; GLenum e; ogl_bitmap->lock_buffer = al_malloc(pitch * h); if (ogl_bitmap->lock_buffer == NULL) { ALLEGRO_ERROR("Out of memory\n"); return false; } /* NOTE: GLES can only read 4 byte pixels (or one other implementation * defined format), we have to convert */ glReadPixels(x, gl_y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glReadPixels for format %s failed (%s).\n", _al_pixel_format_name(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE), _al_gl_error_string(e)); al_free(ogl_bitmap->lock_buffer); ogl_bitmap->lock_buffer = NULL; return false; } ALLEGRO_DEBUG("Converting from format %d -> %d\n", ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, real_format); /* That's right, we convert in-place. * (safe as long as dst size <= src size, which it always is) */ _al_convert_bitmap_data(ogl_bitmap->lock_buffer, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ogl_pitch(w, 4), ogl_bitmap->lock_buffer, real_format, pitch, 0, 0, 0, 0, w, h); bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (h - 1); bitmap->locked_region.format = real_format; bitmap->locked_region.pitch = -pitch; bitmap->locked_region.pixel_size = pixel_size; return &bitmap->locked_region; } static ALLEGRO_LOCKED_REGION *ogl_lock_region_bb_proxy(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int real_format, int flags) { ALLEGRO_BITMAP_EXTRA_OPENGL * const ogl_bitmap = bitmap->extra; ALLEGRO_BITMAP *proxy; ALLEGRO_LOCKED_REGION *lr; const int pixel_size = al_get_pixel_size(real_format); const int pitch = ogl_pitch(w, pixel_size); ALLEGRO_DEBUG("Creating backbuffer proxy bitmap\n"); proxy = _al_create_bitmap_params(al_get_current_display(), w, h, real_format, ALLEGRO_VIDEO_BITMAP|ALLEGRO_NO_PRESERVE_TEXTURE, 0, 0); if (!proxy) { return NULL; } ALLEGRO_DEBUG("Locking backbuffer proxy bitmap\n"); proxy->lock_x = 0; proxy->lock_y = 0; proxy->lock_w = w; proxy->lock_h = h; proxy->lock_flags = flags; lr = ogl_lock_region_nonbb(proxy, 0, 0, w, h, real_format, flags); if (!lr) { al_destroy_bitmap(proxy); return NULL; } if (!(flags & ALLEGRO_LOCK_WRITEONLY)) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_proxy = proxy->extra; const int gl_y = bitmap->h - y - h; GLenum e; /* NOTE: GLES can only read 4 byte pixels (or one other implementation * defined format), we have to convert */ glReadPixels(x, gl_y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ogl_proxy->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glReadPixels for format %s failed (%s).\n", _al_pixel_format_name(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE), _al_gl_error_string(e)); al_destroy_bitmap(proxy); return NULL; } ALLEGRO_DEBUG("Converting from format %d -> %d\n", ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, real_format); /* That's right, we convert in-place. * (safe as long as dst size <= src size, which it always is) */ _al_convert_bitmap_data(ogl_proxy->lock_buffer, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ogl_pitch(w, 4), ogl_proxy->lock_buffer, real_format, pitch, 0, 0, 0, 0, w, h); } proxy->locked = true; bitmap->locked_region = proxy->locked_region; ogl_bitmap->lock_proxy = proxy; return lr; } static ALLEGRO_LOCKED_REGION *ogl_lock_region_nonbb(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int real_format, int flags) { ALLEGRO_BITMAP_EXTRA_OPENGL * const ogl_bitmap = bitmap->extra; const int gl_y = bitmap->h - y - h; ALLEGRO_DISPLAY *disp; ALLEGRO_DISPLAY *old_disp = NULL; ALLEGRO_BITMAP *old_target = al_get_target_bitmap(); bool ok; bool restore_fbo = false; disp = al_get_current_display(); /* Change OpenGL context if necessary. */ if (!disp || (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false && _al_get_bitmap_display(bitmap) != disp)) { old_disp = disp; _al_set_current_display_only(_al_get_bitmap_display(bitmap)); } ok = true; /* Set up the pixel store state. We will need to match it when unlocking. * There may be other pixel store state we should be setting. * See also pitfalls 7 & 8 from: * http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/ */ { const int pixel_size = al_get_pixel_size(real_format); const int pixel_alignment = ogl_pixel_alignment(pixel_size); GLenum e; glPixelStorei(GL_PACK_ALIGNMENT, pixel_alignment); e = glGetError(); if (e) { ALLEGRO_ERROR("glPixelStorei(GL_PACK_ALIGNMENT, %d) failed (%s).\n", pixel_alignment, _al_gl_error_string(e)); ok = false; } } if (ok) { if (flags & ALLEGRO_LOCK_WRITEONLY) { ALLEGRO_DEBUG("Locking non-backbuffer WRITEONLY\n"); ok = ogl_lock_region_nonbb_writeonly(bitmap, ogl_bitmap, x, gl_y, w, h, real_format); } else { ALLEGRO_DEBUG("Locking non-backbuffer %s\n", (flags & ALLEGRO_LOCK_READONLY) ? "READONLY" : "READWRITE"); ok = ogl_lock_region_nonbb_readwrite(bitmap, ogl_bitmap, x, gl_y, w, h, real_format, &restore_fbo); } } /* Restore state after switching FBO. */ if (restore_fbo) { if (!old_target) { /* Old target was NULL; release the context. */ _al_set_current_display_only(NULL); } else if (!_al_get_bitmap_display(old_target)) { /* Old target was memory bitmap; leave the current display alone. */ } else if (old_target != bitmap) { /* Old target was another OpenGL bitmap. */ _al_ogl_setup_fbo(_al_get_bitmap_display(old_target), old_target); } } ASSERT(al_get_target_bitmap() == old_target); if (old_disp != NULL) { _al_set_current_display_only(old_disp); } if (ok) { return &bitmap->locked_region; } ALLEGRO_ERROR("Failed to lock region\n"); ASSERT(ogl_bitmap->lock_buffer == NULL); return NULL; } static bool ogl_lock_region_nonbb_writeonly( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int real_format) { const int pixel_size = al_get_pixel_size(real_format); const int pitch = ogl_pitch(w, pixel_size); (void) x; (void) gl_y; ogl_bitmap->lock_buffer = al_malloc(pitch * h); if (ogl_bitmap->lock_buffer == NULL) { return false; } bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (h - 1); bitmap->locked_region.format = real_format; bitmap->locked_region.pitch = -pitch; bitmap->locked_region.pixel_size = pixel_size; // Not sure why this is needed on Pi if (IS_RASPBERRYPI) { glFlush(); } return true; } static bool ogl_lock_region_nonbb_readwrite( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int real_format, bool* restore_fbo) { bool ok; ASSERT(bitmap->parent == NULL); ASSERT(bitmap->locked == false); ASSERT(_al_get_bitmap_display(bitmap) == al_get_current_display()); /* Try to create an FBO if there isn't one. */ *restore_fbo = _al_ogl_setup_fbo_non_backbuffer(_al_get_bitmap_display(bitmap), bitmap); /* Unlike in desktop GL, there seems to be nothing we can do without an FBO. */ if (*restore_fbo && ogl_bitmap->fbo_info) { ok = ogl_lock_region_nonbb_readwrite_fbo(bitmap, ogl_bitmap, x, gl_y, w, h, real_format); } else { ALLEGRO_ERROR("no fbo\n"); ok = false; } return ok; } static bool ogl_lock_region_nonbb_readwrite_fbo( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int real_format) { const int pixel_size = al_get_pixel_size(real_format); const int pitch = ogl_pitch(w, pixel_size); const int start_h = h; GLint old_fbo; GLenum e; bool ok; ASSERT(ogl_bitmap->fbo_info); old_fbo = _al_ogl_bind_framebuffer(ogl_bitmap->fbo_info->fbo); e = glGetError(); if (e) { ALLEGRO_ERROR("glBindFramebufferEXT failed (%s).\n", _al_gl_error_string(e)); return false; } ok = true; /* Allocate a buffer big enough for both purposes. This requires more * memory to be held for the period of the lock, but overall less * memory is needed to complete the lock. */ if (ok) { size_t size = _ALLEGRO_MAX(pitch * h, ogl_pitch(w, 4) * h); ogl_bitmap->lock_buffer = al_malloc(size); if (ogl_bitmap->lock_buffer == NULL) { ok = false; } } if (ok) { /* NOTE: GLES can only read 4 byte pixels (or one other implementation * defined format), we have to convert */ glReadPixels(x, gl_y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glReadPixels for format %s failed (%s).\n", _al_pixel_format_name(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE), _al_gl_error_string(e)); al_free(ogl_bitmap->lock_buffer); ogl_bitmap->lock_buffer = NULL; ok = false; } } if (ok) { ALLEGRO_DEBUG("Converting from format %d -> %d\n", ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, real_format); /* That's right, we convert in-place. * (safe as long as dst size <= src size, which it always is) */ _al_convert_bitmap_data(ogl_bitmap->lock_buffer, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ogl_pitch(w, 4), ogl_bitmap->lock_buffer, real_format, pitch, 0, 0, 0, 0, w, h); bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (start_h - 1); bitmap->locked_region.format = real_format; bitmap->locked_region.pitch = -pitch; bitmap->locked_region.pixel_size = pixel_size; ok = true; } _al_ogl_bind_framebuffer(old_fbo); return ok; } /* * Unlocking */ static void ogl_unlock_region_bb_proxy(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap); static void ogl_unlock_region_nonbb(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap); static void ogl_unlock_region_nonbb_2(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format); static void ogl_unlock_region_nonbb_nonfbo_conv(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format); static void ogl_unlock_region_nonbb_nonfbo_noconv(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format); void _al_ogl_unlock_region_gles(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra; if (bitmap->lock_flags & ALLEGRO_LOCK_READONLY) { ALLEGRO_DEBUG("Unlocking READONLY\n"); ASSERT(ogl_bitmap->lock_proxy == NULL); } else if (ogl_bitmap->lock_proxy != NULL) { ogl_unlock_region_bb_proxy(bitmap, ogl_bitmap); } else { ogl_unlock_region_nonbb(bitmap, ogl_bitmap); } al_free(ogl_bitmap->lock_buffer); ogl_bitmap->lock_buffer = NULL; } static void ogl_unlock_region_bb_proxy(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap) { ALLEGRO_BITMAP *proxy = ogl_bitmap->lock_proxy; ASSERT(proxy); ASSERT(ogl_bitmap->lock_buffer == NULL); ALLEGRO_DEBUG("Unlocking backbuffer proxy bitmap\n"); _al_ogl_unlock_region_gles(proxy); proxy->locked = false; ALLEGRO_DEBUG("Drawing proxy to backbuffer\n"); { ALLEGRO_DISPLAY *disp; ALLEGRO_STATE state0; ALLEGRO_TRANSFORM t; bool held; disp = al_get_current_display(); held = al_is_bitmap_drawing_held(); if (held) { al_hold_bitmap_drawing(false); } al_store_state(&state0, ALLEGRO_STATE_TARGET_BITMAP | ALLEGRO_STATE_TRANSFORM | ALLEGRO_STATE_BLENDER | ALLEGRO_STATE_PROJECTION_TRANSFORM); { al_set_target_bitmap(bitmap); al_identity_transform(&t); al_use_transform(&t); al_orthographic_transform(&t, 0, 0, -1, disp->w, disp->h, 1); al_use_projection_transform(&t); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_draw_bitmap(proxy, bitmap->lock_x, bitmap->lock_y, 0); } al_restore_state(&state0); al_hold_bitmap_drawing(held); } ALLEGRO_DEBUG("Destroying backbuffer proxy bitmap\n"); al_destroy_bitmap(proxy); ogl_bitmap->lock_proxy = NULL; } static void ogl_unlock_region_nonbb(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap) { const int gl_y = bitmap->h - bitmap->lock_y - bitmap->lock_h; ALLEGRO_DISPLAY *old_disp = NULL; ALLEGRO_DISPLAY *disp; int orig_format; GLenum e; disp = al_get_current_display(); orig_format = _al_get_real_pixel_format(disp, al_get_bitmap_format(bitmap)); /* Change OpenGL context if necessary. */ if (!disp || (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false && _al_get_bitmap_display(bitmap) != disp)) { old_disp = disp; _al_set_current_display_only(_al_get_bitmap_display(bitmap)); } /* Desktop code sets GL_UNPACK_ALIGNMENT here instead of later. */ ogl_unlock_region_nonbb_2(bitmap, ogl_bitmap, gl_y, orig_format); /* If using FBOs, we need to regenerate mipmaps explicitly now. */ /* XXX why don't we check ogl_bitmap->fbo_info? */ if ((al_get_bitmap_flags(bitmap) & ALLEGRO_MIPMAP) && (al_get_opengl_extension_list()->ALLEGRO_GL_OES_framebuffer_object || IS_OPENGLES) /* FIXME */) { glGenerateMipmapEXT(GL_TEXTURE_2D); e = glGetError(); if (e) { ALLEGRO_ERROR("glGenerateMipmapEXT for texture %d failed (%s).\n", ogl_bitmap->texture, _al_gl_error_string(e)); } } if (old_disp) { _al_set_current_display_only(old_disp); } } static void ogl_unlock_region_nonbb_2(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format) { GLint fbo; GLenum e; #ifdef ALLEGRO_ANDROID fbo = _al_android_get_curr_fbo(); #else glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fbo); #endif glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); #ifdef ALLEGRO_ANDROID _al_android_set_curr_fbo(0); #endif glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture); e = glGetError(); if (e) { ALLEGRO_ERROR("glBindTexture failed (%s).\n", _al_gl_error_string(e)); } /* Differs from desktop code. */ ALLEGRO_DEBUG("Unlocking non-backbuffer (non-FBO)\n"); if (bitmap->locked_region.format != orig_format) { ALLEGRO_DEBUG( "Unlocking non-backbuffer non-FBO with conversion (%d -> %d)\n", bitmap->locked_region.format, orig_format); ogl_unlock_region_nonbb_nonfbo_conv(bitmap, ogl_bitmap, gl_y, orig_format); } else { ALLEGRO_DEBUG("Unlocking non-backbuffer non-FBO without conversion\n"); ogl_unlock_region_nonbb_nonfbo_noconv(bitmap, ogl_bitmap, gl_y, orig_format); } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); #ifdef ALLEGRO_ANDROID _al_android_set_curr_fbo(fbo); #endif } static void ogl_unlock_region_nonbb_nonfbo_conv(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format) { const int lock_format = bitmap->locked_region.format; const int orig_pixel_size = al_get_pixel_size(orig_format); const int dst_pitch = bitmap->lock_w * orig_pixel_size; unsigned char * const tmpbuf = al_malloc(dst_pitch * bitmap->lock_h); GLenum e; _al_convert_bitmap_data( ogl_bitmap->lock_buffer, bitmap->locked_region.format, -bitmap->locked_region.pitch, tmpbuf, orig_format, dst_pitch, 0, 0, 0, 0, bitmap->lock_w, bitmap->lock_h); glPixelStorei(GL_UNPACK_ALIGNMENT, ogl_pixel_alignment(orig_pixel_size)); glTexSubImage2D(GL_TEXTURE_2D, 0, bitmap->lock_x, gl_y, bitmap->lock_w, bitmap->lock_h, get_glformat(orig_format, 2), get_glformat(orig_format, 1), tmpbuf); e = glGetError(); if (e) { ALLEGRO_ERROR("glTexSubImage2D for format %d failed (%s).\n", lock_format, _al_gl_error_string(e)); } al_free(tmpbuf); } static void ogl_unlock_region_nonbb_nonfbo_noconv(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format) { const int lock_format = bitmap->locked_region.format; const int orig_pixel_size = al_get_pixel_size(orig_format); GLenum e; glPixelStorei(GL_UNPACK_ALIGNMENT, ogl_pixel_alignment(orig_pixel_size)); e = glGetError(); if (e) { ALLEGRO_ERROR("glPixelStorei for format %s failed (%s).\n", _al_pixel_format_name(lock_format), _al_gl_error_string(e)); } glTexSubImage2D(GL_TEXTURE_2D, 0, bitmap->lock_x, gl_y, bitmap->lock_w, bitmap->lock_h, get_glformat(lock_format, 2), get_glformat(lock_format, 1), ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glTexSubImage2D for format %s failed (%s).\n", _al_pixel_format_name(lock_format), _al_gl_error_string(e)); } } #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/opengl/ogl_render_state.c000066400000000000000000000036341473414355200212250ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_opengl.h" ALLEGRO_DEBUG_CHANNEL("opengl") /* Note: synched to ALLEGRO_RENDER_FUNCTION values as array indices */ static int _gl_funcs[] = { GL_NEVER, GL_ALWAYS, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL }; void _al_ogl_update_render_state(ALLEGRO_DISPLAY *display) { _ALLEGRO_RENDER_STATE *r = &display->render_state; /* TODO: We could store the previous state and/or mark updated states to * avoid so many redundant OpenGL calls. */ if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_SHADER_GLSL GLint atloc = display->ogl_extras->varlocs.alpha_test_loc; GLint floc = display->ogl_extras->varlocs.alpha_func_loc; GLint tvloc = display->ogl_extras->varlocs.alpha_test_val_loc; if (display->ogl_extras->program_object > 0 && floc >= 0 && tvloc >= 0) { glUniform1i(atloc, r->alpha_test); glUniform1i(floc, r->alpha_function); glUniform1f(tvloc, (float)r->alpha_test_value / 255.0); } #endif } else { #ifdef ALLEGRO_CFG_OPENGL_FIXED_FUNCTION if (r->alpha_test == 0) glDisable(GL_ALPHA_TEST); else glEnable(GL_ALPHA_TEST); glAlphaFunc(_gl_funcs[r->alpha_function], (float)r->alpha_test_value / 255.0); #endif } if (r->depth_test == 0) glDisable(GL_DEPTH_TEST); else glEnable(GL_DEPTH_TEST); glDepthFunc(_gl_funcs[r->depth_function]); glDepthMask((r->write_mask & ALLEGRO_MASK_DEPTH) ? GL_TRUE : GL_FALSE); glColorMask( (r->write_mask & ALLEGRO_MASK_RED) ? GL_TRUE : GL_FALSE, (r->write_mask & ALLEGRO_MASK_GREEN) ? GL_TRUE : GL_FALSE, (r->write_mask & ALLEGRO_MASK_BLUE) ? GL_TRUE : GL_FALSE, (r->write_mask & ALLEGRO_MASK_ALPHA) ? GL_TRUE : GL_FALSE); } allegro5-5.2.10.1/src/opengl/ogl_shader.c000066400000000000000000000346311473414355200200150ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * OpenGL shader support. * * See LICENSE.txt for copyright information. */ #include #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_shader.h" #ifdef ALLEGRO_MSVC #define snprintf _snprintf #endif #ifdef ALLEGRO_CFG_SHADER_GLSL ALLEGRO_DEBUG_CHANNEL("shader") static _AL_VECTOR shaders; static ALLEGRO_MUTEX *shaders_mutex; typedef struct ALLEGRO_SHADER_GLSL_S ALLEGRO_SHADER_GLSL_S; struct ALLEGRO_SHADER_GLSL_S { ALLEGRO_SHADER shader; GLuint vertex_shader; GLuint pixel_shader; GLuint program_object; ALLEGRO_OGL_VARLOCS varlocs; }; /* forward declarations */ static struct ALLEGRO_SHADER_INTERFACE shader_glsl_vt; static void lookup_varlocs(ALLEGRO_OGL_VARLOCS *varlocs, GLuint program); static bool check_gl_error(const char* name) { GLenum err = glGetError(); if (err != 0) { ALLEGRO_WARN("%s (%s)\n", name, _al_gl_error_string(err)); return false; } return true; } ALLEGRO_SHADER *_al_create_shader_glsl(ALLEGRO_SHADER_PLATFORM platform) { ALLEGRO_SHADER_GLSL_S *shader = al_calloc(1, sizeof(ALLEGRO_SHADER_GLSL_S)); if (!shader) return NULL; shader->shader.platform = platform; shader->shader.vt = &shader_glsl_vt; _al_vector_init(&shader->shader.bitmaps, sizeof(ALLEGRO_BITMAP *)); al_lock_mutex(shaders_mutex); { ALLEGRO_SHADER **back = (ALLEGRO_SHADER **)_al_vector_alloc_back(&shaders); *back = (ALLEGRO_SHADER *)shader; } al_unlock_mutex(shaders_mutex); return (ALLEGRO_SHADER *)shader; } static bool glsl_attach_shader_source(ALLEGRO_SHADER *shader, ALLEGRO_SHADER_TYPE type, const char *source) { GLint status; GLchar error_buf[4096]; ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader; ALLEGRO_DISPLAY *display = al_get_current_display(); ASSERT(display); ASSERT(display->flags & ALLEGRO_OPENGL); if (source == NULL) { if (type == ALLEGRO_VERTEX_SHADER) { if (gl_shader->vertex_shader) { glDetachShader(gl_shader->program_object, gl_shader->vertex_shader); glDeleteShader(gl_shader->vertex_shader); gl_shader->vertex_shader = 0; } } else { if (gl_shader->pixel_shader) { glDetachShader(gl_shader->program_object, gl_shader->pixel_shader); glDeleteShader(gl_shader->pixel_shader); gl_shader->pixel_shader = 0; } } return true; } else { GLuint *handle; GLenum gl_type; if (type == ALLEGRO_VERTEX_SHADER) { handle = &(gl_shader->vertex_shader); gl_type = GL_VERTEX_SHADER; } else { handle = &(gl_shader->pixel_shader); gl_type = GL_FRAGMENT_SHADER; } *handle = glCreateShader(gl_type); if ((*handle) == 0) { return false; } glShaderSource(*handle, 1, &source, NULL); glCompileShader(*handle); glGetShaderiv(*handle, GL_COMPILE_STATUS, &status); if (status == 0) { glGetShaderInfoLog(*handle, sizeof(error_buf), NULL, error_buf); if (shader->log) { al_ustr_truncate(shader->log, 0); al_ustr_append_cstr(shader->log, error_buf); } else { shader->log = al_ustr_new(error_buf); } ALLEGRO_ERROR("Compile error: %s\n", error_buf); glDeleteShader(*handle); return false; } } return true; } static bool glsl_build_shader(ALLEGRO_SHADER *shader) { GLint status; ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader; GLchar error_buf[4096]; if (gl_shader->vertex_shader == 0 && gl_shader->pixel_shader == 0) return false; if (gl_shader->program_object != 0) { glDeleteProgram(gl_shader->program_object); } gl_shader->program_object = glCreateProgram(); if (gl_shader->program_object == 0) return false; if (gl_shader->vertex_shader) glAttachShader(gl_shader->program_object, gl_shader->vertex_shader); if (gl_shader->pixel_shader) glAttachShader(gl_shader->program_object, gl_shader->pixel_shader); glLinkProgram(gl_shader->program_object); glGetProgramiv(gl_shader->program_object, GL_LINK_STATUS, &status); if (status == 0) { glGetProgramInfoLog(gl_shader->program_object, sizeof(error_buf), NULL, error_buf); if (shader->log) { al_ustr_truncate(shader->log, 0); al_ustr_append_cstr(shader->log, error_buf); } else { shader->log = al_ustr_new(error_buf); } ALLEGRO_ERROR("Link error: %s\n", error_buf); glDeleteProgram(gl_shader->program_object); return false; } /* Look up variable locations. */ lookup_varlocs(&gl_shader->varlocs, gl_shader->program_object); return true; } static bool glsl_use_shader(ALLEGRO_SHADER *shader, ALLEGRO_DISPLAY *display, bool set_projview_matrix_from_display) { ALLEGRO_SHADER_GLSL_S *gl_shader; GLuint program_object; GLenum err; if (!(display->flags & ALLEGRO_OPENGL)) { return false; } gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader; program_object = gl_shader->program_object; glGetError(); /* clear error */ glUseProgram(program_object); err = glGetError(); if (err != GL_NO_ERROR) { ALLEGRO_WARN("glUseProgram(%u) failed: %s\n", program_object, _al_gl_error_string(err)); display->ogl_extras->program_object = 0; return false; } display->ogl_extras->program_object = program_object; /* Copy variable locations. */ display->ogl_extras->varlocs = gl_shader->varlocs; /* Optionally set projview matrix. We skip this when it is known that the * matrices in the display are out of date and are about to be clobbered * itself. */ if (set_projview_matrix_from_display) { _al_glsl_set_projview_matrix( display->ogl_extras->varlocs.projview_matrix_loc, &display->projview_transform); } /* Alpha testing may be done in the shader and so when a shader is * set the uniforms need to be synchronized. */ _al_ogl_update_render_state(display); return true; } static void glsl_unuse_shader(ALLEGRO_SHADER *shader, ALLEGRO_DISPLAY *display) { (void)shader; (void)display; glUseProgram(0); } static void glsl_destroy_shader(ALLEGRO_SHADER *shader) { ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader; al_lock_mutex(shaders_mutex); _al_vector_find_and_delete(&shaders, &shader); al_unlock_mutex(shaders_mutex); glDeleteShader(gl_shader->vertex_shader); glDeleteShader(gl_shader->pixel_shader); glDeleteProgram(gl_shader->program_object); al_free(shader); } static bool glsl_set_shader_sampler(ALLEGRO_SHADER *shader, const char *name, ALLEGRO_BITMAP *bitmap, int unit) { ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader; GLint handle; GLuint texture; if (bitmap && al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP) { ALLEGRO_WARN("Cannot use memory bitmap for sampler\n"); return false; } handle = glGetUniformLocation(gl_shader->program_object, name); if (handle < 0) { ALLEGRO_WARN("No uniform variable '%s' in shader program\n", name); return false; } glActiveTexture(GL_TEXTURE0 + unit); texture = bitmap ? al_get_opengl_texture(bitmap) : 0; glBindTexture(GL_TEXTURE_2D, texture); glUniform1i(handle, unit); return check_gl_error(name); } static bool glsl_set_shader_matrix(ALLEGRO_SHADER *shader, const char *name, const ALLEGRO_TRANSFORM *matrix) { ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader; GLint handle; handle = glGetUniformLocation(gl_shader->program_object, name); if (handle < 0) { ALLEGRO_WARN("No uniform variable '%s' in shader program\n", name); return false; } glUniformMatrix4fv(handle, 1, false, (const float *)matrix->m); return check_gl_error(name); } static bool glsl_set_shader_int(ALLEGRO_SHADER *shader, const char *name, int i) { ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader; GLint handle; handle = glGetUniformLocation(gl_shader->program_object, name); if (handle < 0) { ALLEGRO_WARN("No uniform variable '%s' in shader program\n", name); return false; } glUniform1i(handle, i); return check_gl_error(name); } static bool glsl_set_shader_float(ALLEGRO_SHADER *shader, const char *name, float f) { ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader; GLint handle; handle = glGetUniformLocation(gl_shader->program_object, name); if (handle < 0) { ALLEGRO_WARN("No uniform variable '%s' in shader program\n", name); return false; } glUniform1f(handle, f); return check_gl_error(name); } static bool glsl_set_shader_int_vector(ALLEGRO_SHADER *shader, const char *name, int num_components, const int *i, int num_elems) { ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader; GLint handle; handle = glGetUniformLocation(gl_shader->program_object, name); if (handle < 0) { ALLEGRO_WARN("No uniform variable '%s' in shader program\n", name); return false; } switch (num_components) { case 1: glUniform1iv(handle, num_elems, i); break; case 2: glUniform2iv(handle, num_elems, i); break; case 3: glUniform3iv(handle, num_elems, i); break; case 4: glUniform4iv(handle, num_elems, i); break; default: ASSERT(false); break; } return check_gl_error(name); } static bool glsl_set_shader_float_vector(ALLEGRO_SHADER *shader, const char *name, int num_components, const float *f, int num_elems) { ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader; GLint handle; handle = glGetUniformLocation(gl_shader->program_object, name); if (handle < 0) { ALLEGRO_WARN("No uniform variable '%s' in shader program\n", name); return false; } switch (num_components) { case 1: glUniform1fv(handle, num_elems, f); break; case 2: glUniform2fv(handle, num_elems, f); break; case 3: glUniform3fv(handle, num_elems, f); break; case 4: glUniform4fv(handle, num_elems, f); break; default: ASSERT(false); break; } return check_gl_error(name); } static bool glsl_set_shader_bool(ALLEGRO_SHADER *shader, const char *name, bool b) { return glsl_set_shader_int(shader, name, b); } static struct ALLEGRO_SHADER_INTERFACE shader_glsl_vt = { glsl_attach_shader_source, glsl_build_shader, glsl_use_shader, glsl_unuse_shader, glsl_destroy_shader, NULL, /* on_lost_device */ NULL, /* on_reset_device */ glsl_set_shader_sampler, glsl_set_shader_matrix, glsl_set_shader_int, glsl_set_shader_float, glsl_set_shader_int_vector, glsl_set_shader_float_vector, glsl_set_shader_bool }; static void lookup_varlocs(ALLEGRO_OGL_VARLOCS *varlocs, GLuint program) { unsigned i; varlocs->pos_loc = glGetAttribLocation(program, ALLEGRO_SHADER_VAR_POS); varlocs->color_loc = glGetAttribLocation(program, ALLEGRO_SHADER_VAR_COLOR); varlocs->projview_matrix_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_PROJVIEW_MATRIX); varlocs->texcoord_loc = glGetAttribLocation(program, ALLEGRO_SHADER_VAR_TEXCOORD); varlocs->use_tex_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_USE_TEX); varlocs->tex_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_TEX); varlocs->use_tex_matrix_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_USE_TEX_MATRIX); varlocs->tex_matrix_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_TEX_MATRIX); varlocs->alpha_test_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_ALPHA_TEST); varlocs->alpha_func_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_ALPHA_FUNCTION); varlocs->alpha_test_val_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_ALPHA_TEST_VALUE); for (i = 0; i < _ALLEGRO_PRIM_MAX_USER_ATTR; i++) { /* al_user_attr_##0 */ char user_attr_name[sizeof(ALLEGRO_SHADER_VAR_USER_ATTR "999")]; snprintf(user_attr_name, sizeof(user_attr_name), ALLEGRO_SHADER_VAR_USER_ATTR "%d", i); varlocs->user_attr_loc[i] = glGetAttribLocation(program, user_attr_name); } check_gl_error("glGetAttribLocation, glGetUniformLocation"); } bool _al_glsl_set_projview_matrix(GLint projview_matrix_loc, const ALLEGRO_TRANSFORM *t) { if (projview_matrix_loc >= 0) { glUniformMatrix4fv(projview_matrix_loc, 1, false, (float *)t->m); return true; } return false; } void _al_glsl_init_shaders(void) { _al_vector_init(&shaders, sizeof(ALLEGRO_SHADER *)); shaders_mutex = al_create_mutex(); } void _al_glsl_shutdown_shaders(void) { _al_vector_free(&shaders); al_destroy_mutex(shaders_mutex); shaders_mutex = NULL; } /* Look through all the bitmaps associated with all the shaders and c;ear their * shader field */ void _al_glsl_unuse_shaders(void) { unsigned i; al_lock_mutex(shaders_mutex); for (i = 0; i < _al_vector_size(&shaders); i++) { unsigned j; ALLEGRO_SHADER *shader = *((ALLEGRO_SHADER **)_al_vector_ref(&shaders, i)); for (j = 0; j < _al_vector_size(&shader->bitmaps); j++) { ALLEGRO_BITMAP *bitmap = *((ALLEGRO_BITMAP **)_al_vector_ref(&shader->bitmaps, j)); _al_set_bitmap_shader_field(bitmap, NULL); } } al_unlock_mutex(shaders_mutex); } #endif /* Function: al_get_opengl_program_object */ GLuint al_get_opengl_program_object(ALLEGRO_SHADER *shader) { ASSERT(shader); #ifdef ALLEGRO_CFG_SHADER_GLSL if (shader->platform != ALLEGRO_SHADER_GLSL) return 0; return ((ALLEGRO_SHADER_GLSL_S *)shader)->program_object; #else return 0; #endif } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/path.c000066400000000000000000000316101473414355200153500ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Filesystem path routines. * * By Thomas Fjellstrom. * * See LICENSE.txt for copyright information. */ /* Title: Filesystem path routines */ #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_vector.h" #include "allegro5/internal/aintern_path.h" /* get_segment: * Return the i'th directory component of a path. */ static ALLEGRO_USTR *get_segment(const ALLEGRO_PATH *path, unsigned i) { ALLEGRO_USTR **seg = _al_vector_ref(&path->segments, i); return *seg; } /* get_segment_cstr: * Return the i'th directory component of a path as a C string. */ static const char *get_segment_cstr(const ALLEGRO_PATH *path, unsigned i) { return al_cstr(get_segment(path, i)); } /* replace_backslashes: * Replace backslashes by slashes. */ static void replace_backslashes(ALLEGRO_USTR *path) { al_ustr_find_replace_cstr(path, 0, "\\", "/"); } /* parse_path_string: * * Parse a path string according to the following grammar. The last * component, if it is not followed by a directory separator, is interpreted * as the filename component, unless it is "." or "..". * * GRAMMAR * * path ::= "//" c+ "/" nonlast [Windows only] * | c ":" nonlast [Windows only] * | nonlast * * nonlast ::= c* "/" nonlast * | last * * last ::= "." * | ".." * | filename * * filename ::= c* [but not "." and ".."] * * c ::= any character but '/' */ static bool parse_path_string(const ALLEGRO_USTR *str, ALLEGRO_PATH *path) { ALLEGRO_USTR_INFO dot_info; ALLEGRO_USTR_INFO dotdot_info; const ALLEGRO_USTR * dot = al_ref_cstr(&dot_info, "."); const ALLEGRO_USTR * dotdot = al_ref_cstr(&dotdot_info, ".."); ALLEGRO_USTR *piece = al_ustr_new(""); int pos = 0; bool on_windows; /* We compile the drive handling code on non-Windows platforms to prevent * it becoming broken. */ #ifdef ALLEGRO_WINDOWS on_windows = true; #else on_windows = false; #endif if (on_windows) { /* UNC \\server\share name */ if (al_ustr_has_prefix_cstr(str, "//")) { int slash = al_ustr_find_chr(str, 2, '/'); if (slash == -1 || slash == 2) { /* Missing slash or server component is empty. */ goto Error; } al_ustr_assign_substr(path->drive, str, pos, slash); // Note: The slash will be parsed again, so we end up with // "//server/share" and not "//servershare"! pos = slash; } else { /* Drive letter. */ int colon = al_ustr_offset(str, 1); if (colon > -1 && al_ustr_get(str, colon) == ':') { /* Include the colon in the drive string. */ al_ustr_assign_substr(path->drive, str, 0, colon + 1); pos = colon + 1; } } } for (;;) { int slash = al_ustr_find_chr(str, pos, '/'); if (slash == -1) { /* Last component. */ al_ustr_assign_substr(piece, str, pos, al_ustr_size(str)); if (al_ustr_equal(piece, dot) || al_ustr_equal(piece, dotdot)) { al_append_path_component(path, al_cstr(piece)); } else { /* This might be an empty string, but that's okay. */ al_ustr_assign(path->filename, piece); } break; } /* Non-last component. */ al_ustr_assign_substr(piece, str, pos, slash); al_append_path_component(path, al_cstr(piece)); pos = slash + 1; } al_ustr_free(piece); return true; Error: al_ustr_free(piece); return false; } /* Function: al_create_path */ ALLEGRO_PATH *al_create_path(const char *str) { ALLEGRO_PATH *path; path = al_malloc(sizeof(ALLEGRO_PATH)); if (!path) return NULL; path->drive = al_ustr_new(""); path->filename = al_ustr_new(""); _al_vector_init(&path->segments, sizeof(ALLEGRO_USTR *)); path->basename = al_ustr_new(""); path->full_string = al_ustr_new(""); if (str != NULL) { ALLEGRO_USTR *copy = al_ustr_new(str); replace_backslashes(copy); if (!parse_path_string(copy, path)) { al_destroy_path(path); path = NULL; } al_ustr_free(copy); } return path; } /* Function: al_create_path_for_directory */ ALLEGRO_PATH *al_create_path_for_directory(const char *str) { ALLEGRO_PATH *path = al_create_path(str); if (al_ustr_length(path->filename)) { ALLEGRO_USTR *last = path->filename; path->filename = al_ustr_new(""); al_append_path_component(path, al_cstr(last)); al_ustr_free(last); } return path; } /* Function: al_clone_path */ ALLEGRO_PATH *al_clone_path(const ALLEGRO_PATH *path) { ALLEGRO_PATH *clone; unsigned int i; ASSERT(path); clone = al_create_path(NULL); if (!clone) { return NULL; } al_ustr_assign(clone->drive, path->drive); al_ustr_assign(clone->filename, path->filename); for (i = 0; i < _al_vector_size(&path->segments); i++) { ALLEGRO_USTR **slot = _al_vector_alloc_back(&clone->segments); (*slot) = al_ustr_dup(get_segment(path, i)); } return clone; } /* Function: al_get_path_num_components */ int al_get_path_num_components(const ALLEGRO_PATH *path) { ASSERT(path); return _al_vector_size(&path->segments); } /* Function: al_get_path_component */ const char *al_get_path_component(const ALLEGRO_PATH *path, int i) { ASSERT(path); ASSERT(i < (int)_al_vector_size(&path->segments)); if (i < 0) i = _al_vector_size(&path->segments) + i; ASSERT(i >= 0); return get_segment_cstr(path, i); } /* Function: al_replace_path_component */ void al_replace_path_component(ALLEGRO_PATH *path, int i, const char *s) { ASSERT(path); ASSERT(s); ASSERT(i < (int)_al_vector_size(&path->segments)); if (i < 0) i = _al_vector_size(&path->segments) + i; ASSERT(i >= 0); al_ustr_assign_cstr(get_segment(path, i), s); } /* Function: al_remove_path_component */ void al_remove_path_component(ALLEGRO_PATH *path, int i) { ASSERT(path); ASSERT(i < (int)_al_vector_size(&path->segments)); if (i < 0) i = _al_vector_size(&path->segments) + i; ASSERT(i >= 0); al_ustr_free(get_segment(path, i)); _al_vector_delete_at(&path->segments, i); } /* Function: al_insert_path_component */ void al_insert_path_component(ALLEGRO_PATH *path, int i, const char *s) { ALLEGRO_USTR **slot; ASSERT(path); ASSERT(i <= (int)_al_vector_size(&path->segments)); if (i < 0) i = _al_vector_size(&path->segments) + i; ASSERT(i >= 0); slot = _al_vector_alloc_mid(&path->segments, i); (*slot) = al_ustr_new(s); } /* Function: al_get_path_tail */ const char *al_get_path_tail(const ALLEGRO_PATH *path) { ASSERT(path); if (al_get_path_num_components(path) == 0) return NULL; return al_get_path_component(path, -1); } /* Function: al_drop_path_tail */ void al_drop_path_tail(ALLEGRO_PATH *path) { if (al_get_path_num_components(path) > 0) { al_remove_path_component(path, -1); } } /* Function: al_append_path_component */ void al_append_path_component(ALLEGRO_PATH *path, const char *s) { ALLEGRO_USTR **slot = _al_vector_alloc_back(&path->segments); (*slot) = al_ustr_new(s); } static bool path_is_absolute(const ALLEGRO_PATH *path) { /* If the first segment is empty, we have an absolute path. */ return (_al_vector_size(&path->segments) > 0) && (al_ustr_size(get_segment(path, 0)) == 0); } /* Function: al_join_paths */ bool al_join_paths(ALLEGRO_PATH *path, const ALLEGRO_PATH *tail) { unsigned i; ASSERT(path); ASSERT(tail); /* Don't bother concating if the tail is an absolute path. */ if (path_is_absolute(tail)) { return false; } /* We ignore tail->drive. The other option is to do nothing if tail * contains a drive letter. */ al_ustr_assign(path->filename, tail->filename); for (i = 0; i < _al_vector_size(&tail->segments); i++) { al_append_path_component(path, get_segment_cstr(tail, i)); } return true; } /* Function: al_rebase_path */ bool al_rebase_path(const ALLEGRO_PATH *head, ALLEGRO_PATH *tail) { unsigned i; ASSERT(head); ASSERT(tail); /* Don't bother concating if the tail is an absolute path. */ if (path_is_absolute(tail)) { return false; } al_set_path_drive(tail, al_get_path_drive(head)); for (i = 0; i < _al_vector_size(&head->segments); i++) { al_insert_path_component(tail, i, get_segment_cstr(head, i)); } return true; } static void path_to_ustr(const ALLEGRO_PATH *path, int32_t delim, ALLEGRO_USTR *str) { unsigned i; al_ustr_assign(str, path->drive); for (i = 0; i < _al_vector_size(&path->segments); i++) { al_ustr_append(str, get_segment(path, i)); al_ustr_append_chr(str, delim); } al_ustr_append(str, path->filename); } /* Function: al_path_cstr */ const char *al_path_cstr(const ALLEGRO_PATH *path, char delim) { return al_cstr(al_path_ustr(path, delim)); } /* Function: al_path_ustr */ const ALLEGRO_USTR *al_path_ustr(const ALLEGRO_PATH *path, char delim) { path_to_ustr(path, delim, path->full_string); return path->full_string; } /* Function: al_destroy_path */ void al_destroy_path(ALLEGRO_PATH *path) { unsigned i; if (!path) { return; } if (path->drive) { al_ustr_free(path->drive); path->drive = NULL; } if (path->filename) { al_ustr_free(path->filename); path->filename = NULL; } for (i = 0; i < _al_vector_size(&path->segments); i++) { al_ustr_free(get_segment(path, i)); } _al_vector_free(&path->segments); if (path->basename) { al_ustr_free(path->basename); path->basename = NULL; } if (path->full_string) { al_ustr_free(path->full_string); path->full_string = NULL; } al_free(path); } /* Function: al_set_path_drive */ void al_set_path_drive(ALLEGRO_PATH *path, const char *drive) { ASSERT(path); if (drive) al_ustr_assign_cstr(path->drive, drive); else al_ustr_truncate(path->drive, 0); } /* Function: al_get_path_drive */ const char *al_get_path_drive(const ALLEGRO_PATH *path) { ASSERT(path); return al_cstr(path->drive); } /* Function: al_set_path_filename */ void al_set_path_filename(ALLEGRO_PATH *path, const char *filename) { ASSERT(path); if (filename) al_ustr_assign_cstr(path->filename, filename); else al_ustr_truncate(path->filename, 0); } /* Function: al_get_path_filename */ const char *al_get_path_filename(const ALLEGRO_PATH *path) { ASSERT(path); return al_cstr(path->filename); } /* Function: al_get_path_extension */ const char *al_get_path_extension(const ALLEGRO_PATH *path) { int pos; ASSERT(path); pos = al_ustr_rfind_chr(path->filename, al_ustr_size(path->filename), '.'); if (pos == -1) pos = al_ustr_size(path->filename); return al_cstr(path->filename) + pos; /* include dot */ } /* Function: al_set_path_extension */ bool al_set_path_extension(ALLEGRO_PATH *path, char const *extension) { int dot; ASSERT(path); if (al_ustr_size(path->filename) == 0) { return false; } dot = al_ustr_rfind_chr(path->filename, al_ustr_size(path->filename), '.'); if (dot >= 0) { al_ustr_truncate(path->filename, dot); } al_ustr_append_cstr(path->filename, extension); return true; } /* Function: al_get_path_basename */ const char *al_get_path_basename(const ALLEGRO_PATH *path) { int dot; ASSERT(path); dot = al_ustr_rfind_chr(path->filename, al_ustr_size(path->filename), '.'); if (dot >= 0) { al_ustr_assign_substr(path->basename, path->filename, 0, dot); return al_cstr(path->basename); } return al_cstr(path->filename); } /* Function: al_make_path_canonical */ bool al_make_path_canonical(ALLEGRO_PATH *path) { unsigned i; ASSERT(path); for (i = 0; i < _al_vector_size(&path->segments); ) { if (strcmp(get_segment_cstr(path, i), ".") == 0) al_remove_path_component(path, i); else i++; } /* Remove leading '..'s on absolute paths. */ if (_al_vector_size(&path->segments) >= 1 && al_ustr_size(get_segment(path, 0)) == 0) { while (_al_vector_size(&path->segments) >= 2 && strcmp(get_segment_cstr(path, 1), "..") == 0) { al_remove_path_component(path, 1); } } return true; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/pixel_tables.inc000066400000000000000000000163751473414355200174310ustar00rootroot00000000000000// Warning: This file was created by make_pixel_tables.py - do not edit. float _al_u8_to_float[] = { 0.0, 0.00392156862745098, 0.00784313725490196, 0.011764705882352941, 0.01568627450980392, 0.0196078431372549, 0.023529411764705882, 0.027450980392156862, 0.03137254901960784, 0.03529411764705882, 0.0392156862745098, 0.043137254901960784, 0.047058823529411764, 0.050980392156862744, 0.054901960784313725, 0.058823529411764705, 0.06274509803921569, 0.06666666666666667, 0.07058823529411765, 0.07450980392156863, 0.0784313725490196, 0.08235294117647059, 0.08627450980392157, 0.09019607843137255, 0.09411764705882353, 0.09803921568627451, 0.10196078431372549, 0.10588235294117647, 0.10980392156862745, 0.11372549019607843, 0.11764705882352941, 0.12156862745098039, 0.12549019607843137, 0.12941176470588237, 0.13333333333333333, 0.13725490196078433, 0.1411764705882353, 0.1450980392156863, 0.14901960784313725, 0.15294117647058825, 0.1568627450980392, 0.1607843137254902, 0.16470588235294117, 0.16862745098039217, 0.17254901960784313, 0.17647058823529413, 0.1803921568627451, 0.1843137254901961, 0.18823529411764706, 0.19215686274509805, 0.19607843137254902, 0.2, 0.20392156862745098, 0.20784313725490197, 0.21176470588235294, 0.21568627450980393, 0.2196078431372549, 0.2235294117647059, 0.22745098039215686, 0.23137254901960785, 0.23529411764705882, 0.23921568627450981, 0.24313725490196078, 0.24705882352941178, 0.25098039215686274, 0.2549019607843137, 0.25882352941176473, 0.2627450980392157, 0.26666666666666666, 0.27058823529411763, 0.27450980392156865, 0.2784313725490196, 0.2823529411764706, 0.28627450980392155, 0.2901960784313726, 0.29411764705882354, 0.2980392156862745, 0.30196078431372547, 0.3058823529411765, 0.30980392156862746, 0.3137254901960784, 0.3176470588235294, 0.3215686274509804, 0.3254901960784314, 0.32941176470588235, 0.3333333333333333, 0.33725490196078434, 0.3411764705882353, 0.34509803921568627, 0.34901960784313724, 0.35294117647058826, 0.3568627450980392, 0.3607843137254902, 0.36470588235294116, 0.3686274509803922, 0.37254901960784315, 0.3764705882352941, 0.3803921568627451, 0.3843137254901961, 0.38823529411764707, 0.39215686274509803, 0.396078431372549, 0.4, 0.403921568627451, 0.40784313725490196, 0.4117647058823529, 0.41568627450980394, 0.4196078431372549, 0.4235294117647059, 0.42745098039215684, 0.43137254901960786, 0.43529411764705883, 0.4392156862745098, 0.44313725490196076, 0.4470588235294118, 0.45098039215686275, 0.4549019607843137, 0.4588235294117647, 0.4627450980392157, 0.4666666666666667, 0.47058823529411764, 0.4745098039215686, 0.47843137254901963, 0.4823529411764706, 0.48627450980392156, 0.49019607843137253, 0.49411764705882355, 0.4980392156862745, 0.5019607843137255, 0.5058823529411764, 0.5098039215686274, 0.5137254901960784, 0.5176470588235295, 0.5215686274509804, 0.5254901960784314, 0.5294117647058824, 0.5333333333333333, 0.5372549019607843, 0.5411764705882353, 0.5450980392156862, 0.5490196078431373, 0.5529411764705883, 0.5568627450980392, 0.5607843137254902, 0.5647058823529412, 0.5686274509803921, 0.5725490196078431, 0.5764705882352941, 0.5803921568627451, 0.5843137254901961, 0.5882352941176471, 0.592156862745098, 0.596078431372549, 0.6, 0.6039215686274509, 0.6078431372549019, 0.611764705882353, 0.615686274509804, 0.6196078431372549, 0.6235294117647059, 0.6274509803921569, 0.6313725490196078, 0.6352941176470588, 0.6392156862745098, 0.6431372549019608, 0.6470588235294118, 0.6509803921568628, 0.6549019607843137, 0.6588235294117647, 0.6627450980392157, 0.6666666666666666, 0.6705882352941176, 0.6745098039215687, 0.6784313725490196, 0.6823529411764706, 0.6862745098039216, 0.6901960784313725, 0.6941176470588235, 0.6980392156862745, 0.7019607843137254, 0.7058823529411765, 0.7098039215686275, 0.7137254901960784, 0.7176470588235294, 0.7215686274509804, 0.7254901960784313, 0.7294117647058823, 0.7333333333333333, 0.7372549019607844, 0.7411764705882353, 0.7450980392156863, 0.7490196078431373, 0.7529411764705882, 0.7568627450980392, 0.7607843137254902, 0.7647058823529411, 0.7686274509803922, 0.7725490196078432, 0.7764705882352941, 0.7803921568627451, 0.7843137254901961, 0.788235294117647, 0.792156862745098, 0.796078431372549, 0.8, 0.803921568627451, 0.807843137254902, 0.8117647058823529, 0.8156862745098039, 0.8196078431372549, 0.8235294117647058, 0.8274509803921568, 0.8313725490196079, 0.8352941176470589, 0.8392156862745098, 0.8431372549019608, 0.8470588235294118, 0.8509803921568627, 0.8549019607843137, 0.8588235294117647, 0.8627450980392157, 0.8666666666666667, 0.8705882352941177, 0.8745098039215686, 0.8784313725490196, 0.8823529411764706, 0.8862745098039215, 0.8901960784313725, 0.8941176470588236, 0.8980392156862745, 0.9019607843137255, 0.9058823529411765, 0.9098039215686274, 0.9137254901960784, 0.9176470588235294, 0.9215686274509803, 0.9254901960784314, 0.9294117647058824, 0.9333333333333333, 0.9372549019607843, 0.9411764705882353, 0.9450980392156862, 0.9490196078431372, 0.9529411764705882, 0.9568627450980393, 0.9607843137254902, 0.9647058823529412, 0.9686274509803922, 0.9725490196078431, 0.9764705882352941, 0.9803921568627451, 0.984313725490196, 0.9882352941176471, 0.9921568627450981, 0.996078431372549, 1.0, }; int _al_rgb_scale_1[] = { 0, 255, }; int _al_rgb_scale_4[] = { 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255, }; int _al_rgb_scale_5[] = { 0, 8, 16, 24, 32, 41, 49, 57, 65, 74, 82, 90, 98, 106, 115, 123, 131, 139, 148, 156, 164, 172, 180, 189, 197, 205, 213, 222, 230, 238, 246, 255, }; int _al_rgb_scale_6[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 214, 218, 222, 226, 230, 234, 238, 242, 246, 250, 255, }; // Warning: This file was created by make_pixel_tables.py - do not edit. allegro5-5.2.10.1/src/pixels.c000066400000000000000000000304121473414355200157170ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Pixel formats. * * By Trent Gamblin. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_pixels.h" ALLEGRO_DEBUG_CHANNEL("pixels") /* lookup table for scaling 8 bit integers up to floats [0.0, 1.0] */ #include "pixel_tables.inc" static int pixel_sizes[] = { 0, /* ALLEGRO_PIXEL_FORMAT_ANY */ 0, 0, 2, 2, 2, 3, 4, 4, 4, /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */ 4, 2, 3, 2, 2, 2, 2, 4, 4, 3, 2, 2, 4, 4, 16, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */ 4, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */ 2, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */ 1, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */ 0, 0, 0, }; static int pixel_bits[] = { 0, /* ALLEGRO_PIXEL_FORMAT_ANY */ 0, 0, 15, 16, 16, 24, 32, 32, 32, /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */ 32, 16, 24, 16, 15, 16, 16, 32, 32, 24, 16, 15, 32, 32, 128, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */ 32, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */ 16, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */ 8, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */ 0, 0, 0, }; static int pixel_block_widths[] = { 0, /* ALLEGRO_PIXEL_FORMAT_ANY */ 0, 0, 1, 1, 1, 1, 1, 1, 1, /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */ 1, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */ 1, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */ 1, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */ 4, 4, 4, }; static int pixel_block_heights[] = { 0, /* ALLEGRO_PIXEL_FORMAT_ANY */ 0, 0, 1, 1, 1, 1, 1, 1, 1, /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */ 1, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */ 1, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */ 1, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */ 4, 4, 4, }; static int pixel_block_sizes[] = { 0, /* ALLEGRO_PIXEL_FORMAT_ANY */ 0, 0, 2, 2, 2, 3, 4, 4, 4, /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */ 4, 2, 3, 2, 2, 2, 2, 4, 4, 3, 2, 2, 4, 4, 16, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */ 4, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */ 2, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */ 1, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */ 8, 16, 16, }; static bool format_alpha_table[ALLEGRO_NUM_PIXEL_FORMATS] = { false, /* neutral (ALLEGRO_PIXEL_FORMAT_ANY) */ false, true, false, false, true, false, false, true, true, /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */ true, true, false, false, false, true, true, true, false, false, false, false, false, false, true, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */ true, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */ true, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */ false, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */ true, true, true, }; static char const *pixel_format_names[ALLEGRO_NUM_PIXEL_FORMATS + 1] = { "ANY", "ANY_NO_ALPHA", "ANY_WITH_ALPHA", "ANY_15_NO_ALPHA", "ANY_16_NO_ALPHA", "ANY_16_WITH_ALPHA", "ANY_24_NO_ALPHA", "ANY_32_NO_ALPHA", "ANY_32_WITH_ALPHA", "ARGB_8888", "RGBA_8888", "ARGB_4444", "RGB_888", "RGB_565", "RGB_555", "RGBA_5551", "ARGB_1555", "ABGR_8888", "XBGR_8888", "BGR_888", "BGR_565", "BGR_555", "RGBX_8888", "XRGB_8888", "ABGR_F32", "ABGR_8888_LE", "RGBA_4444", "SINGLE_CHANNEL_8", "RGBA_DXT1", "RGBA_DXT3", "RGBA_DXT5", "INVALID" }; static bool format_is_real[ALLEGRO_NUM_PIXEL_FORMATS] = { false, /* ALLEGRO_PIXEL_FORMAT_ANY */ false, false, false, false, false, false, false, false, true, /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */ true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */ true, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */ true, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */ true, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */ true, true, true, }; static bool format_is_video_only[ALLEGRO_NUM_PIXEL_FORMATS] = { false, /* ALLEGRO_PIXEL_FORMAT_ANY */ false, false, false, false, false, false, false, false, false, /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */ false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */ false, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */ false, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */ false, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */ true, true, true, }; static bool format_is_compressed[ALLEGRO_NUM_PIXEL_FORMATS] = { false, /* ALLEGRO_PIXEL_FORMAT_ANY */ false, false, false, false, false, false, false, false, false, /* ALLEGRO_PIXEL_FORMAT_ARGB_8888 */ false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, /* ALLEGRO_PIXEL_FORMAT_ABGR_F32 */ false, /* ALLEGRO_PIXEL_FORMAT_ABGR_LE */ false, /* ALLEGRO_PIXEL_FORMAT_RGBA_4444 */ false, /* ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8 */ true, true, true, }; /* Function: al_get_pixel_block_size */ int al_get_pixel_block_size(int format) { return pixel_block_sizes[format]; } /* Function: al_get_pixel_block_width */ int al_get_pixel_block_width(int format) { return pixel_block_widths[format]; } /* Function: al_get_pixel_block_height */ int al_get_pixel_block_height(int format) { return pixel_block_heights[format]; } /* Function: al_get_pixel_size */ int al_get_pixel_size(int format) { return pixel_sizes[format]; } /* Function: al_get_pixel_format_bits */ int al_get_pixel_format_bits(int format) { return pixel_bits[format]; } bool _al_pixel_format_has_alpha(int format) { return format_alpha_table[format]; } bool _al_pixel_format_is_real(int format) { ASSERT(format >= 0); ASSERT(format < ALLEGRO_NUM_PIXEL_FORMATS); return format_is_real[format]; } bool _al_pixel_format_is_video_only(int format) { ASSERT(format >= 0); ASSERT(format < ALLEGRO_NUM_PIXEL_FORMATS); return format_is_video_only[format]; } bool _al_pixel_format_is_compressed(int format) { ASSERT(format >= 0); ASSERT(format < ALLEGRO_NUM_PIXEL_FORMATS); return format_is_compressed[format]; } /* We use al_get_display_format() as a hint for the preferred RGB ordering when * nothing else is specified. */ static bool try_display_format(ALLEGRO_DISPLAY *display, int *format) { int best_format; int bytes; if (!display) { return false; } best_format = al_get_display_format(display); if (!_al_pixel_format_is_real(best_format)) return false; bytes = al_get_pixel_size(*format); if (bytes && bytes != al_get_pixel_size(best_format)) return false; if (_al_pixel_format_has_alpha(*format) && !_al_pixel_format_has_alpha(best_format)) { switch (best_format) { case ALLEGRO_PIXEL_FORMAT_RGBX_8888: *format = ALLEGRO_PIXEL_FORMAT_RGBA_8888; return true; case ALLEGRO_PIXEL_FORMAT_XRGB_8888: *format = ALLEGRO_PIXEL_FORMAT_ARGB_8888; return true; case ALLEGRO_PIXEL_FORMAT_XBGR_8888: *format = ALLEGRO_PIXEL_FORMAT_ABGR_8888; return true; default: return false; } } if (!_al_pixel_format_has_alpha(*format) && _al_pixel_format_has_alpha(best_format)) { switch (best_format) { case ALLEGRO_PIXEL_FORMAT_RGBA_8888: *format = ALLEGRO_PIXEL_FORMAT_RGBX_8888; return true; case ALLEGRO_PIXEL_FORMAT_ARGB_8888: *format = ALLEGRO_PIXEL_FORMAT_XRGB_8888; return true; case ALLEGRO_PIXEL_FORMAT_ABGR_8888: *format = ALLEGRO_PIXEL_FORMAT_XBGR_8888; return true; default: return false; } } *format = best_format; return true; } int _al_get_real_pixel_format(ALLEGRO_DISPLAY *display, int format) { /* Pick an appropriate format if the user is vague */ switch (format) { case ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA: case ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA: if (!try_display_format(display, &format)) format = ALLEGRO_PIXEL_FORMAT_XRGB_8888; break; case ALLEGRO_PIXEL_FORMAT_ANY: case ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA: case ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA: if (!try_display_format(display, &format)) #if defined ALLEGRO_CFG_OPENGLES // OPENGLES doesn't have ARGB_8888 format = ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE; #else format = ALLEGRO_PIXEL_FORMAT_ARGB_8888; #endif break; case ALLEGRO_PIXEL_FORMAT_ANY_15_NO_ALPHA: format = ALLEGRO_PIXEL_FORMAT_RGB_555; break; case ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA: if (!try_display_format(display, &format)) format = ALLEGRO_PIXEL_FORMAT_RGB_565; break; case ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA: format = ALLEGRO_PIXEL_FORMAT_RGBA_4444; break; case ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA: format = ALLEGRO_PIXEL_FORMAT_RGB_888; break; default: /* Already a real format - don't change it. */ break; } ASSERT(_al_pixel_format_is_real(format)); return format; } char const *_al_pixel_format_name(ALLEGRO_PIXEL_FORMAT format) { if (format >= ALLEGRO_NUM_PIXEL_FORMATS) format = ALLEGRO_NUM_PIXEL_FORMATS; return pixel_format_names[format]; } /* Color mapping functions */ /* Function: al_map_rgba */ ALLEGRO_COLOR al_map_rgba( unsigned char r, unsigned char g, unsigned char b, unsigned char a) { ALLEGRO_COLOR color; _AL_MAP_RGBA(color, r, g, b, a); return color; } /* Function: al_premul_rgba */ ALLEGRO_COLOR al_premul_rgba( unsigned char r, unsigned char g, unsigned char b, unsigned char a) { ALLEGRO_COLOR color; _AL_MAP_RGBA(color, r * a / 255, g * a / 255, b * a / 255, a); return color; } /* Function: al_map_rgb */ ALLEGRO_COLOR al_map_rgb( unsigned char r, unsigned char g, unsigned char b) { return al_map_rgba(r, g, b, 255); } /* Function: al_map_rgba_f */ ALLEGRO_COLOR al_map_rgba_f(float r, float g, float b, float a) { ALLEGRO_COLOR color; color.r = r; color.g = g; color.b = b; color.a = a; return color; } /* Function: al_premul_rgba_f */ ALLEGRO_COLOR al_premul_rgba_f(float r, float g, float b, float a) { ALLEGRO_COLOR color; color.r = r * a; color.g = g * a; color.b = b * a; color.a = a; return color; } /* Function: al_map_rgb_f */ ALLEGRO_COLOR al_map_rgb_f(float r, float g, float b) { return al_map_rgba_f(r, g, b, 1.0f); } /* unmapping functions */ /* Function: al_unmap_rgba */ void al_unmap_rgba(ALLEGRO_COLOR color, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) { *r = color.r * 255.0f; *g = color.g * 255.0f; *b = color.b * 255.0f; *a = color.a * 255.0f; } /* Function: al_unmap_rgb */ void al_unmap_rgb(ALLEGRO_COLOR color, unsigned char *r, unsigned char *g, unsigned char *b) { unsigned char tmp; al_unmap_rgba(color, r, g, b, &tmp); } /* Function: al_unmap_rgba_f */ void al_unmap_rgba_f(ALLEGRO_COLOR color, float *r, float *g, float *b, float *a) { *r = color.r; *g = color.g; *b = color.b; *a = color.a; } /* Function: al_unmap_rgb_f */ void al_unmap_rgb_f(ALLEGRO_COLOR color, float *r, float *g, float *b) { float tmp; al_unmap_rgba_f(color, r, g, b, &tmp); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/raspberrypi/000077500000000000000000000000001473414355200166115ustar00rootroot00000000000000allegro5-5.2.10.1/src/raspberrypi/picursor.h000066400000000000000000000123231473414355200206310ustar00rootroot00000000000000static uint32_t default_cursor[] = { 0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0xff000000,0xff000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0xff000000,0xff000000,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0xff000000,0xff000000,0xffffffff,0xffffffff,0xffffffff,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000, 0xff000000,0xff000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xff000000,0xffffffff,0xffffffff,0xffffffff,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xff000000,0xff000000,0xffffffff,0xffffffff,0xffffffff,0xff000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xff000000,0xff000000,0xffffffff,0xffffffff,0xff000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xff000000,0xff000000,0xff000000,0xff000000,0x00000000,0x00000000,0x00000000 }; allegro5-5.2.10.1/src/raspberrypi/pidisplay.c000066400000000000000000000517361473414355200207670ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_vector.h" #include "allegro5/internal/aintern_raspberrypi.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xwindow.h" #include #include #include #include #include "picursor.h" #define DEFAULT_CURSOR_WIDTH 17 #define DEFAULT_CURSOR_HEIGHT 28 static ALLEGRO_DISPLAY_INTERFACE *vt; static EGLDisplay egl_display; static EGLSurface egl_window; static EGLContext egl_context; static DISPMANX_UPDATE_HANDLE_T dispman_update; static DISPMANX_RESOURCE_HANDLE_T cursor_resource; static DISPMANX_DISPLAY_HANDLE_T dispman_display; static DISPMANX_ELEMENT_HANDLE_T cursor_element; static VC_RECT_T dst_rect; static VC_RECT_T src_rect; static bool cursor_added = false; static float mouse_scale_ratio_x = 1.0f, mouse_scale_ratio_y = 1.0f; struct ALLEGRO_DISPLAY_RASPBERRYPI_EXTRA { }; static int pot(int n) { int i = 1; while (i < n) { i = i * 2; } return i; } static void set_cursor_data(ALLEGRO_DISPLAY_RASPBERRYPI *d, uint32_t *data, int width, int height) { al_free(d->cursor_data); int spitch = sizeof(uint32_t) * width; int dpitch = pot(spitch); d->cursor_data = al_malloc(dpitch * height); int y; for (y = 0; y < height; y++) { uint8_t *p1 = (uint8_t *)d->cursor_data + y * dpitch; uint8_t *p2 = (uint8_t *)data + y * spitch; memcpy(p1, p2, spitch); } d->cursor_width = width; d->cursor_height = height; } static void delete_cursor_data(ALLEGRO_DISPLAY_RASPBERRYPI *d) { al_free(d->cursor_data); d->cursor_data = NULL; } static void show_cursor(ALLEGRO_DISPLAY_RASPBERRYPI *d) { if (d->cursor_data == NULL) { return; } int width = d->cursor_width; int height = d->cursor_height; if (cursor_added == false) { uint32_t unused; cursor_resource = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, width, height, &unused); VC_RECT_T r; r.x = 0; r.y = 0; r.width = width; r.height = height; int dpitch = pot(sizeof(uint32_t) * width); dispman_update = vc_dispmanx_update_start(0); vc_dispmanx_resource_write_data(cursor_resource, VC_IMAGE_ARGB8888, dpitch, d->cursor_data, &r); vc_dispmanx_update_submit_sync(dispman_update); ALLEGRO_MOUSE_STATE state; al_get_mouse_state(&state); dst_rect.x = state.x+d->cursor_offset_x; dst_rect.y = state.y+d->cursor_offset_y; dst_rect.width = width; dst_rect.height = height; src_rect.x = 0; src_rect.y = 0; src_rect.width = width << 16; src_rect.height = height << 16; dispman_update = vc_dispmanx_update_start(0); cursor_element = vc_dispmanx_element_add( dispman_update, dispman_display, 0/*layer*/, &dst_rect, cursor_resource, &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, 0/*transform*/ ); vc_dispmanx_update_submit_sync(dispman_update); cursor_added = true; } else { ALLEGRO_DISPLAY *disp = (ALLEGRO_DISPLAY *)d; VC_RECT_T src, dst; src.x = 0; src.y = 0; src.width = d->cursor_width << 16; src.height = d->cursor_height << 16; ALLEGRO_MOUSE_STATE st; al_get_mouse_state(&st); st.x = (st.x+0.5) * d->screen_width / disp->w; st.y = (st.y+0.5) * d->screen_height / disp->h; dst.x = st.x+d->cursor_offset_x; dst.y = st.y+d->cursor_offset_y; dst.width = d->cursor_width; dst.height = d->cursor_height; dispman_update = vc_dispmanx_update_start(0); vc_dispmanx_element_change_attributes( dispman_update, cursor_element, 0, 0, 0, &dst, &src, 0, 0 ); vc_dispmanx_update_submit_sync(dispman_update); } } static void hide_cursor(ALLEGRO_DISPLAY_RASPBERRYPI *d) { (void)d; if (!cursor_added) { return; } dispman_update = vc_dispmanx_update_start(0); vc_dispmanx_element_remove(dispman_update, cursor_element); vc_dispmanx_update_submit_sync(dispman_update); vc_dispmanx_resource_delete(cursor_resource); cursor_added = false; } /* Helper to set up GL state as we want it. */ static void setup_gl(ALLEGRO_DISPLAY *d) { ALLEGRO_OGL_EXTRAS *ogl = d->ogl_extras; if (ogl->backbuffer) _al_ogl_resize_backbuffer(ogl->backbuffer, d->w, d->h); else ogl->backbuffer = _al_ogl_create_backbuffer(d); } void _al_raspberrypi_get_screen_info(int *dx, int *dy, int *screen_width, int *screen_height) { graphics_get_display_size(0 /* LCD */, (uint32_t *)screen_width, (uint32_t *)screen_height); /* On TV-out the visible area (area used by X and console) * is different from that reported by the bcm functions. We * have to 1) read fbwidth and fbheight from /proc/cmdline * and also overscan parameters from /boot/config.txt so our * displays are the same size and overlap perfectly. */ *dx = 0; *dy = 0; FILE *cmdline = fopen("/proc/cmdline", "r"); if (cmdline) { char line[1000]; int i; for (i = 0; i < 999; i++) { int c = fgetc(cmdline); if (c == EOF) break; line[i] = c; } line[i] = 0; const char *p = strstr(line, "fbwidth="); if (p) { const char *p2 = strstr(line, "fbheight="); if (p2) { p += strlen("fbwidth="); p2 += strlen("fbheight="); int w = atoi(p); int h = atoi(p2); const ALLEGRO_FILE_INTERFACE *file_interface = al_get_new_file_interface(); al_set_standard_file_interface(); ALLEGRO_CONFIG *cfg = al_load_config_file("/boot/config.txt"); if (cfg) { const char *disable_overscan = al_get_config_value( cfg, "", "disable_overscan" ); // If overscan parameters are disabled don't process if (!disable_overscan || (disable_overscan && (!strcasecmp(disable_overscan, "false") || atoi(disable_overscan) == 0))) { const char *left = al_get_config_value( cfg, "", "overscan_left"); const char *right = al_get_config_value( cfg, "", "overscan_right"); const char *top = al_get_config_value( cfg, "", "overscan_top"); const char *bottom = al_get_config_value( cfg, "", "overscan_bottom"); int xx = left ? atoi(left) : 0; xx -= right ? atoi(right) : 0; int yy = top ? atoi(top) : 0; yy -= bottom ? atoi(bottom) : 0; *dx = (*screen_width - w + xx) / 2; *dy = (*screen_height - h + yy) / 2; *screen_width = w; *screen_height = h; } else { *dx = (*screen_width - w) / 2; *dy = (*screen_height - h) / 2; *screen_width = w; *screen_height = h; } al_destroy_config(cfg); } else { printf("Couldn't open /boot/config.txt\n"); } al_set_new_file_interface(file_interface); } } fclose(cmdline); } } void _al_raspberrypi_get_mouse_scale_ratios(float *x, float *y) { *x = mouse_scale_ratio_x; *y = mouse_scale_ratio_y; } static bool pi_create_display(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_RASPBERRYPI *d = (void *)display; ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = _al_get_new_display_settings(); egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (egl_display == EGL_NO_DISPLAY) { return false; } int major, minor; if (!eglInitialize(egl_display, &major, &minor)) { return false; } static EGLint attrib_list[] = { EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; attrib_list[1] = eds->settings[ALLEGRO_DEPTH_SIZE]; attrib_list[3] = eds->settings[ALLEGRO_STENCIL_SIZE]; if (eds->settings[ALLEGRO_RED_SIZE] || eds->settings[ALLEGRO_GREEN_SIZE] || eds->settings[ALLEGRO_BLUE_SIZE] || eds->settings[ALLEGRO_ALPHA_SIZE]) { attrib_list[5] = eds->settings[ALLEGRO_RED_SIZE]; attrib_list[7] = eds->settings[ALLEGRO_GREEN_SIZE]; attrib_list[9] = eds->settings[ALLEGRO_BLUE_SIZE]; attrib_list[11] = eds->settings[ALLEGRO_ALPHA_SIZE]; } else if (eds->settings[ALLEGRO_COLOR_SIZE] == 16) { attrib_list[5] = 5; attrib_list[7] = 6; attrib_list[9] = 5; attrib_list[11] = 0; } EGLConfig config; int num_configs; if (!eglChooseConfig(egl_display, attrib_list, &config, 1, &num_configs)) { return false; } eglBindAPI(EGL_OPENGL_ES_API); int es_ver = (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) ? 2 : 1; static EGLint ctxattr[3] = { EGL_CONTEXT_CLIENT_VERSION, 0xDEADBEEF, EGL_NONE }; ctxattr[1] = es_ver; egl_context = eglCreateContext(egl_display, config, EGL_NO_CONTEXT, ctxattr); if (egl_context == EGL_NO_CONTEXT) { return false; } static EGL_DISPMANX_WINDOW_T nativewindow; DISPMANX_ELEMENT_HANDLE_T dispman_element; int dx, dy, screen_width, screen_height; _al_raspberrypi_get_screen_info(&dx, &dy, &screen_width, &screen_height); mouse_scale_ratio_x = (float)display->w / screen_width; mouse_scale_ratio_y = (float)display->h / screen_height; d->cursor_offset_x = dx; d->cursor_offset_y = dy; dst_rect.x = dx; dst_rect.y = dy; dst_rect.width = screen_width; dst_rect.height = screen_height; d->screen_width = screen_width; d->screen_height = screen_height; src_rect.x = 0; src_rect.y = 0; src_rect.width = display->w << 16; src_rect.height = display->h << 16; dispman_display = vc_dispmanx_display_open(0 /* LCD */); dispman_update = vc_dispmanx_update_start(0); dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display, 0/*layer*/, &dst_rect, 0/*src*/, &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, DISPMANX_NO_ROTATE/*transform*/ ); nativewindow.element = dispman_element; nativewindow.width = display->w; nativewindow.height = display->h; vc_dispmanx_update_submit_sync(dispman_update); egl_window = eglCreateWindowSurface( egl_display, config, &nativewindow, NULL); if (egl_window == EGL_NO_SURFACE) { return false; } if (!eglMakeCurrent(egl_display, egl_window, egl_window, egl_context)) { return false; } if (!getenv("DISPLAY")) { _al_evdev_set_mouse_range(0, 0, display->w-1, display->h-1); } return true; } static ALLEGRO_DISPLAY *raspberrypi_create_display(int w, int h) { ALLEGRO_DISPLAY_RASPBERRYPI *d = al_calloc(1, sizeof *d); ALLEGRO_DISPLAY *display = (void*)d; ALLEGRO_OGL_EXTRAS *ogl = al_calloc(1, sizeof *ogl); display->ogl_extras = ogl; display->vt = _al_get_raspberrypi_display_interface(); display->flags = al_get_new_display_flags(); ALLEGRO_SYSTEM_RASPBERRYPI *system = (void *)al_get_system_driver(); /* Add ourself to the list of displays. */ ALLEGRO_DISPLAY_RASPBERRYPI **add; add = _al_vector_alloc_back(&system->system.displays); *add = d; /* Each display is an event source. */ _al_event_source_init(&display->es); display->extra_settings.settings[ALLEGRO_COMPATIBLE_DISPLAY] = 1; display->w = w; display->h = h; display->flags |= ALLEGRO_OPENGL; #ifdef ALLEGRO_CFG_OPENGLES2 display->flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; #endif #ifdef ALLEGRO_CFG_OPENGLES display->flags |= ALLEGRO_OPENGL_ES_PROFILE; #endif if (!pi_create_display(display)) { // FIXME: cleanup return NULL; } if (getenv("DISPLAY")) { _al_mutex_lock(&system->lock); Window root = RootWindow( system->x11display, DefaultScreen(system->x11display)); XWindowAttributes attr; XGetWindowAttributes(system->x11display, root, &attr); d->window = XCreateWindow( system->x11display, root, 0, 0, attr.width, attr.height, 0, 0, InputOnly, DefaultVisual(system->x11display, 0), 0, NULL ); XGetWindowAttributes(system->x11display, d->window, &attr); XSelectInput( system->x11display, d->window, PointerMotionMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask ); XMapWindow(system->x11display, d->window); _al_xwin_reset_size_hints(display); _al_xwin_set_fullscreen_window(display, 2); _al_xwin_set_size_hints(display, INT_MAX, INT_MAX); d->wm_delete_window_atom = XInternAtom(system->x11display, "WM_DELETE_WINDOW", False); XSetWMProtocols(system->x11display, d->window, &d->wm_delete_window_atom, 1); _al_mutex_unlock(&system->lock); } al_grab_mouse(display); _al_ogl_manage_extensions(display); _al_ogl_set_extensions(ogl->extension_api); setup_gl(display); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); if (al_is_mouse_installed() && !getenv("DISPLAY")) { _al_evdev_set_mouse_range(0, 0, display->w-1, display->h-1); } set_cursor_data(d, default_cursor, DEFAULT_CURSOR_WIDTH, DEFAULT_CURSOR_HEIGHT); /* Fill in opengl version */ const int v = display->ogl_extras->ogl_info.version; display->extra_settings.settings[ALLEGRO_OPENGL_MAJOR_VERSION] = (v >> 24) & 0xFF; display->extra_settings.settings[ALLEGRO_OPENGL_MINOR_VERSION] = (v >> 16) & 0xFF; return display; } static void raspberrypi_destroy_display(ALLEGRO_DISPLAY *d) { ALLEGRO_DISPLAY_RASPBERRYPI *pidisplay = (ALLEGRO_DISPLAY_RASPBERRYPI *)d; hide_cursor(pidisplay); delete_cursor_data(pidisplay); _al_set_current_display_only(d); while (d->bitmaps._size > 0) { ALLEGRO_BITMAP **bptr = (ALLEGRO_BITMAP **)_al_vector_ref_back(&d->bitmaps); ALLEGRO_BITMAP *b = *bptr; _al_convert_to_memory_bitmap(b); } _al_event_source_free(&d->es); ALLEGRO_SYSTEM_RASPBERRYPI *system = (void *)al_get_system_driver(); _al_vector_find_and_delete(&system->system.displays, &d); eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(egl_display, egl_window); eglDestroyContext(egl_display, egl_context); eglTerminate(egl_display); if (getenv("DISPLAY")) { _al_mutex_lock(&system->lock); XUnmapWindow(system->x11display, pidisplay->window); XDestroyWindow(system->x11display, pidisplay->window); _al_mutex_unlock(&system->lock); } if (system->mouse_grab_display == d) { system->mouse_grab_display = NULL; } } static bool raspberrypi_set_current_display(ALLEGRO_DISPLAY *d) { (void)d; // FIXME _al_ogl_update_render_state(d); return true; } static int raspberrypi_get_orientation(ALLEGRO_DISPLAY *d) { (void)d; return ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES; } /* There can be only one window and only one OpenGL context, so all bitmaps * are compatible. */ static bool raspberrypi_is_compatible_bitmap( ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap ) { (void)display; (void)bitmap; return true; } /* Resizing is not possible. */ static bool raspberrypi_resize_display(ALLEGRO_DISPLAY *d, int w, int h) { (void)d; (void)w; (void)h; return false; } /* The icon must be provided in the Info.plist file, it cannot be changed * at runtime. */ static void raspberrypi_set_icons(ALLEGRO_DISPLAY *d, int num_icons, ALLEGRO_BITMAP *bitmaps[]) { (void)d; (void)num_icons; (void)bitmaps; } /* There is no way to leave fullscreen so no window title is visible. */ static void raspberrypi_set_window_title(ALLEGRO_DISPLAY *display, char const *title) { (void)display; (void)title; } /* The window always spans the entire screen right now. */ static void raspberrypi_set_window_position(ALLEGRO_DISPLAY *display, int x, int y) { (void)display; (void)x; (void)y; } /* The window cannot be constrained. */ static bool raspberrypi_set_window_constraints(ALLEGRO_DISPLAY *display, int min_w, int min_h, int max_w, int max_h) { (void)display; (void)min_w; (void)min_h; (void)max_w; (void)max_h; return false; } /* Always fullscreen. */ static bool raspberrypi_set_display_flag(ALLEGRO_DISPLAY *display, int flag, bool onoff) { (void)display; (void)flag; (void)onoff; return false; } static void raspberrypi_get_window_position(ALLEGRO_DISPLAY *display, int *x, int *y) { (void)display; *x = 0; *y = 0; } /* The window cannot be constrained. */ static bool raspberrypi_get_window_constraints(ALLEGRO_DISPLAY *display, int *min_w, int *min_h, int *max_w, int *max_h) { (void)display; (void)min_w; (void)min_h; (void)max_w; (void)max_h; return false; } static bool raspberrypi_wait_for_vsync(ALLEGRO_DISPLAY *display) { (void)display; return false; } static void raspberrypi_flip_display(ALLEGRO_DISPLAY *disp) { eglSwapBuffers(egl_display, egl_window); if (cursor_added) { show_cursor((ALLEGRO_DISPLAY_RASPBERRYPI *)disp); } } static void raspberrypi_update_display_region(ALLEGRO_DISPLAY *d, int x, int y, int w, int h) { (void)x; (void)y; (void)w; (void)h; raspberrypi_flip_display(d); } static bool raspberrypi_acknowledge_resize(ALLEGRO_DISPLAY *d) { setup_gl(d); return true; } static bool raspberrypi_show_mouse_cursor(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_RASPBERRYPI *d = (void *)display; hide_cursor(d); show_cursor(d); return true; } static bool raspberrypi_hide_mouse_cursor(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_RASPBERRYPI *d = (void *)display; hide_cursor(d); return true; } static bool raspberrypi_set_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_MOUSE_CURSOR *cursor) { ALLEGRO_DISPLAY_RASPBERRYPI *d = (void *)display; ALLEGRO_MOUSE_CURSOR_RASPBERRYPI *pi_cursor = (void *)cursor; int w = al_get_bitmap_width(pi_cursor->bitmap); int h = al_get_bitmap_height(pi_cursor->bitmap); int pitch = w * sizeof(uint32_t); uint32_t *data = al_malloc(pitch * h); ALLEGRO_LOCKED_REGION *lr = al_lock_bitmap(pi_cursor->bitmap, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_READONLY); int y; for (y = 0; y < h; y++) { uint8_t *p = (uint8_t *)lr->data + lr->pitch * y; uint8_t *p2 = (uint8_t *)data + pitch * y; memcpy(p2, p, pitch); } al_unlock_bitmap(pi_cursor->bitmap); delete_cursor_data(d); set_cursor_data(d, data, w, h); al_free(data); if (cursor_added) { hide_cursor(d); show_cursor(d); } return true; } static bool raspberrypi_set_system_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id) { (void)cursor_id; ALLEGRO_DISPLAY_RASPBERRYPI *d = (void *)display; delete_cursor_data(d); set_cursor_data(d, default_cursor, DEFAULT_CURSOR_WIDTH, DEFAULT_CURSOR_HEIGHT); return true; } /* Obtain a reference to this driver. */ ALLEGRO_DISPLAY_INTERFACE *_al_get_raspberrypi_display_interface(void) { if (vt) return vt; vt = al_calloc(1, sizeof *vt); vt->create_display = raspberrypi_create_display; vt->destroy_display = raspberrypi_destroy_display; vt->set_current_display = raspberrypi_set_current_display; vt->flip_display = raspberrypi_flip_display; vt->update_display_region = raspberrypi_update_display_region; vt->acknowledge_resize = raspberrypi_acknowledge_resize; vt->create_bitmap = _al_ogl_create_bitmap; vt->get_backbuffer = _al_ogl_get_backbuffer; vt->set_target_bitmap = _al_ogl_set_target_bitmap; vt->get_orientation = raspberrypi_get_orientation; vt->is_compatible_bitmap = raspberrypi_is_compatible_bitmap; vt->resize_display = raspberrypi_resize_display; vt->set_icons = raspberrypi_set_icons; vt->set_window_title = raspberrypi_set_window_title; vt->set_window_position = raspberrypi_set_window_position; vt->get_window_position = raspberrypi_get_window_position; vt->set_window_constraints = raspberrypi_set_window_constraints; vt->get_window_constraints = raspberrypi_get_window_constraints; vt->set_display_flag = raspberrypi_set_display_flag; vt->wait_for_vsync = raspberrypi_wait_for_vsync; vt->update_render_state = _al_ogl_update_render_state; _al_ogl_add_drawing_functions(vt); vt->set_mouse_cursor = raspberrypi_set_mouse_cursor; vt->set_system_mouse_cursor = raspberrypi_set_system_mouse_cursor; vt->show_mouse_cursor = raspberrypi_show_mouse_cursor; vt->hide_mouse_cursor = raspberrypi_hide_mouse_cursor; return vt; } allegro5-5.2.10.1/src/raspberrypi/pisystem.c000066400000000000000000000125041473414355200206340ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "allegro5/platform/aintraspberrypi.h" #include "allegro5/internal/aintern_raspberrypi.h" #include "allegro5/platform/aintunix.h" #include "allegro5/platform/aintlnx.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xevents.h" #include "allegro5/internal/aintern_xmouse.h" #include #include ALLEGRO_DEBUG_CHANNEL("system") static ALLEGRO_SYSTEM_INTERFACE *pi_vt; static ALLEGRO_SYSTEM *pi_initialize(int flags) { (void)flags; ALLEGRO_SYSTEM_RASPBERRYPI *s; bcm_host_init(); s = al_calloc(1, sizeof *s); _al_vector_init(&s->system.displays, sizeof (ALLEGRO_DISPLAY_RASPBERRYPI *)); _al_unix_init_time(); if (getenv("DISPLAY")) { _al_mutex_init_recursive(&s->lock); s->x11display = XOpenDisplay(0); _al_thread_create(&s->thread, _al_xwin_background_thread, s); ALLEGRO_INFO("events thread spawned.\n"); /* We need to put *some* atom into the ClientMessage we send for * faking mouse movements with al_set_mouse_xy - so let's ask X11 * for one here. */ s->AllegroAtom = XInternAtom(s->x11display, "AllegroAtom", False); } s->inhibit_screensaver = false; s->system.vt = pi_vt; return &s->system; } static void pi_shutdown_system(void) { ALLEGRO_SYSTEM *s = al_get_system_driver(); ALLEGRO_SYSTEM_RASPBERRYPI *spi = (void *)s; ALLEGRO_INFO("shutting down.\n"); /* Close all open displays. */ while (_al_vector_size(&s->displays) > 0) { ALLEGRO_DISPLAY **dptr = _al_vector_ref(&s->displays, 0); ALLEGRO_DISPLAY *d = *dptr; al_destroy_display(d); } _al_vector_free(&s->displays); if (getenv("DISPLAY")) { _al_thread_join(&spi->thread); XCloseDisplay(spi->x11display); } bcm_host_deinit(); raise(SIGINT); al_free(spi); } static ALLEGRO_KEYBOARD_DRIVER *pi_get_keyboard_driver(void) { if (getenv("DISPLAY")) { return _al_xwin_keyboard_driver(); } return _al_linux_keyboard_driver_list[0].driver; } static ALLEGRO_MOUSE_DRIVER *pi_get_mouse_driver(void) { if (getenv("DISPLAY")) { return _al_xwin_mouse_driver(); } return _al_linux_mouse_driver_list[0].driver; } static ALLEGRO_JOYSTICK_DRIVER *pi_get_joystick_driver(void) { return _al_joystick_driver_list[0].driver; } static int pi_get_num_video_adapters(void) { return 1; } static bool pi_get_monitor_info(int adapter, ALLEGRO_MONITOR_INFO *info) { (void)adapter; int dx, dy, w, h; _al_raspberrypi_get_screen_info(&dx, &dy, &w, &h); info->x1 = 0; info->y1 = 0; info->x2 = w; info->y2 = h; return true; } static bool pi_get_cursor_position(int *ret_x, int *ret_y) { // FIXME: (void)ret_x; (void)ret_y; return false; } static bool pi_inhibit_screensaver(bool inhibit) { ALLEGRO_SYSTEM_RASPBERRYPI *system = (void *)al_get_system_driver(); system->inhibit_screensaver = inhibit; return true; } static int pi_get_num_display_modes(void) { return 1; } static ALLEGRO_DISPLAY_MODE *pi_get_display_mode(int mode, ALLEGRO_DISPLAY_MODE *dm) { (void)mode; int dx, dy, w, h; _al_raspberrypi_get_screen_info(&dx, &dy, &w, &h); dm->width = w; dm->height = h; dm->format = 0; // FIXME dm->refresh_rate = 60; return dm; } static ALLEGRO_MOUSE_CURSOR *pi_create_mouse_cursor(ALLEGRO_BITMAP *bmp, int focus_x_ignored, int focus_y_ignored) { (void)focus_x_ignored; (void)focus_y_ignored; ALLEGRO_STATE state; al_store_state(&state, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS | ALLEGRO_STATE_TARGET_BITMAP); al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ARGB_8888); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); ALLEGRO_BITMAP *cursor_bmp = al_clone_bitmap(bmp); ALLEGRO_MOUSE_CURSOR_RASPBERRYPI *cursor = al_malloc(sizeof(ALLEGRO_MOUSE_CURSOR_RASPBERRYPI)); cursor->bitmap = cursor_bmp; al_restore_state(&state); return (ALLEGRO_MOUSE_CURSOR *)cursor; } static void pi_destroy_mouse_cursor(ALLEGRO_MOUSE_CURSOR *cursor) { ALLEGRO_MOUSE_CURSOR_RASPBERRYPI *pi_cursor = (void *)cursor; al_destroy_bitmap(pi_cursor->bitmap); al_free(pi_cursor); } /* Internal function to get a reference to this driver. */ ALLEGRO_SYSTEM_INTERFACE *_al_system_raspberrypi_driver(void) { if (pi_vt) return pi_vt; pi_vt = al_calloc(1, sizeof *pi_vt); pi_vt->id = ALLEGRO_SYSTEM_ID_RASPBERRYPI; pi_vt->initialize = pi_initialize; pi_vt->get_display_driver = _al_get_raspberrypi_display_interface; pi_vt->get_keyboard_driver = pi_get_keyboard_driver; pi_vt->get_mouse_driver = pi_get_mouse_driver; pi_vt->get_joystick_driver = pi_get_joystick_driver; pi_vt->get_num_display_modes = pi_get_num_display_modes; pi_vt->get_display_mode = pi_get_display_mode; pi_vt->shutdown_system = pi_shutdown_system; pi_vt->get_num_video_adapters = pi_get_num_video_adapters; pi_vt->get_monitor_info = pi_get_monitor_info; pi_vt->create_mouse_cursor = pi_create_mouse_cursor; pi_vt->destroy_mouse_cursor = pi_destroy_mouse_cursor; pi_vt->get_cursor_position = pi_get_cursor_position; pi_vt->get_path = _al_unix_get_path; pi_vt->inhibit_screensaver = pi_inhibit_screensaver; pi_vt->get_time = _al_unix_get_time; pi_vt->rest = _al_unix_rest; pi_vt->init_timeout = _al_unix_init_timeout; return pi_vt; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/sdl/000077500000000000000000000000001473414355200150315ustar00rootroot00000000000000allegro5-5.2.10.1/src/sdl/sdl_display.c000066400000000000000000000426561473414355200175210ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * SDL display implementation. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/system.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_vector.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_pixels.h" #include "allegro5/internal/aintern_shader.h" #include "allegro5/platform/allegro_internal_sdl.h" ALLEGRO_DEBUG_CHANNEL("display") int _al_win_determine_adapter(void); static ALLEGRO_DISPLAY_INTERFACE *vt; float _al_sdl_get_display_pixel_ratio(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_SDL *sdl = (void *)display; int window_width, drawable_width, h; SDL_GetWindowSize(sdl->window, &window_width, &h); SDL_GL_GetDrawableSize(sdl->window, &drawable_width, &h); return drawable_width / (float)window_width; } ALLEGRO_DISPLAY *_al_sdl_find_display(uint32_t window_id) { unsigned int i; ALLEGRO_SYSTEM *s = al_get_system_driver(); for (i = 0; i < _al_vector_size(&s->displays); i++) { void **v = (void **)_al_vector_ref(&s->displays, i); ALLEGRO_DISPLAY_SDL *d = *v; if (SDL_GetWindowID(d->window) == window_id) { return &d->display; break; } } return NULL; } void _al_sdl_display_event(SDL_Event *e) { ALLEGRO_EVENT event; event.display.timestamp = al_get_time(); ALLEGRO_DISPLAY *d = NULL; if (e->type == SDL_WINDOWEVENT) { d = _al_sdl_find_display(e->window.windowID); if (e->window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_IN; } if (e->window.event == SDL_WINDOWEVENT_FOCUS_LOST) { event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_OUT; } if (e->window.event == SDL_WINDOWEVENT_CLOSE) { event.display.type = ALLEGRO_EVENT_DISPLAY_CLOSE; } if (e->window.event == SDL_WINDOWEVENT_RESIZED) { float ratio = _al_sdl_get_display_pixel_ratio(d); event.display.type = ALLEGRO_EVENT_DISPLAY_RESIZE; event.display.width = e->window.data1 * ratio; event.display.height = e->window.data2 * ratio; } } if (e->type == SDL_QUIT) { event.display.type = ALLEGRO_EVENT_DISPLAY_CLOSE; /* Use the first display as event source if we have any displays. */ ALLEGRO_SYSTEM *s = al_get_system_driver(); if (_al_vector_size(&s->displays) > 0) { void **v = (void **)_al_vector_ref(&s->displays, 0); d = *v; } } if (!d) return; ALLEGRO_EVENT_SOURCE *es = &d->es; _al_event_source_lock(es); _al_event_source_emit_event(es, &event); _al_event_source_unlock(es); } static void GLoption(int allegro, int sdl) { int i; int x = al_get_new_display_option(allegro, &i); if (i == ALLEGRO_DONTCARE) return; SDL_GL_SetAttribute(sdl, x); } static ALLEGRO_DISPLAY *sdl_create_display_locked(int w, int h) { ALLEGRO_DISPLAY_SDL *sdl = al_calloc(1, sizeof *sdl); ALLEGRO_DISPLAY *d = (void *)sdl; d->w = w; d->h = h; d->flags = al_get_new_display_flags(); d->flags |= ALLEGRO_OPENGL; #ifdef ALLEGRO_CFG_OPENGLES2 d->flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; #endif #ifdef ALLEGRO_CFG_OPENGLES d->flags |= ALLEGRO_OPENGL_ES_PROFILE; #endif int flags = SDL_WINDOW_OPENGL; if (d->flags & ALLEGRO_FULLSCREEN) flags |= SDL_WINDOW_FULLSCREEN; if (d->flags & ALLEGRO_FULLSCREEN_WINDOW) flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; if (d->flags & ALLEGRO_FRAMELESS) flags |= SDL_WINDOW_BORDERLESS; if (d->flags & ALLEGRO_RESIZABLE) flags |= SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI; if (d->flags & ALLEGRO_OPENGL_ES_PROFILE) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); #ifdef ALLEGRO_CFG_OPENGLES1 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); #else SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); #endif SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); } GLoption(ALLEGRO_COLOR_SIZE, SDL_GL_BUFFER_SIZE); GLoption(ALLEGRO_RED_SIZE, SDL_GL_RED_SIZE); GLoption(ALLEGRO_GREEN_SIZE, SDL_GL_GREEN_SIZE); GLoption(ALLEGRO_BLUE_SIZE, SDL_GL_BLUE_SIZE); GLoption(ALLEGRO_ALPHA_SIZE, SDL_GL_ALPHA_SIZE); GLoption(ALLEGRO_ACC_RED_SIZE, SDL_GL_ACCUM_RED_SIZE); GLoption(ALLEGRO_ACC_GREEN_SIZE, SDL_GL_ACCUM_GREEN_SIZE); GLoption(ALLEGRO_ACC_BLUE_SIZE, SDL_GL_ACCUM_BLUE_SIZE); GLoption(ALLEGRO_ACC_ALPHA_SIZE, SDL_GL_ACCUM_ALPHA_SIZE); GLoption(ALLEGRO_STEREO, SDL_GL_STEREO); GLoption(ALLEGRO_DEPTH_SIZE, SDL_GL_DEPTH_SIZE); GLoption(ALLEGRO_STENCIL_SIZE, SDL_GL_STENCIL_SIZE); GLoption(ALLEGRO_SAMPLE_BUFFERS, SDL_GL_MULTISAMPLEBUFFERS); GLoption(ALLEGRO_SAMPLES, SDL_GL_MULTISAMPLESAMPLES); GLoption(ALLEGRO_OPENGL_MAJOR_VERSION, SDL_GL_CONTEXT_MAJOR_VERSION); GLoption(ALLEGRO_OPENGL_MINOR_VERSION, SDL_GL_CONTEXT_MINOR_VERSION); SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); sdl->window = SDL_CreateWindow(al_get_new_window_title(), sdl->x, sdl->y, d->w, d->h, flags); if (!sdl->window) { ALLEGRO_ERROR("SDL_CreateWindow failed: %s", SDL_GetError()); return NULL; } sdl->context = SDL_GL_CreateContext(sdl->window); SDL_GL_GetDrawableSize(sdl->window, &d->w, &d->h); // there's no way to query pixel ratio before creating the window, so we // have to compensate afterwards if (d->flags & ALLEGRO_RESIZABLE && !(d->flags & ALLEGRO_FULLSCREEN || d->flags & ALLEGRO_FULLSCREEN_WINDOW)) { int window_width, window_height; SDL_GetWindowSize(sdl->window, &window_width, &window_height); float ratio = _al_sdl_get_display_pixel_ratio(d); ALLEGRO_DEBUG("resizing the display to %dx%d to match the scaling factor %f\n", (int)(window_width / ratio), (int)(window_height / ratio), ratio); SDL_SetWindowSize(sdl->window, window_width / ratio, window_height / ratio); SDL_GL_GetDrawableSize(sdl->window, &d->w, &d->h); } ALLEGRO_DISPLAY **add; ALLEGRO_SYSTEM *system = al_get_system_driver(); add = _al_vector_alloc_back(&system->displays); *add = d; _al_event_source_init(&d->es); d->vt = vt; d->extra_settings.settings[ALLEGRO_COMPATIBLE_DISPLAY] = true; d->ogl_extras = al_calloc(1, sizeof *d->ogl_extras); _al_ogl_manage_extensions(d); _al_ogl_set_extensions(d->ogl_extras->extension_api); _al_ogl_setup_gl(d); /* Fill in opengl version */ const int v = d->ogl_extras->ogl_info.version; d->extra_settings.settings[ALLEGRO_OPENGL_MAJOR_VERSION] = (v >> 24) & 0xFF; d->extra_settings.settings[ALLEGRO_OPENGL_MINOR_VERSION] = (v >> 16) & 0xFF; return d; } static ALLEGRO_DISPLAY *sdl_create_display(int w, int h) { ALLEGRO_SYSTEM_SDL *s = (void *)al_get_system_driver(); al_lock_mutex(s->mutex); ALLEGRO_DISPLAY *d = sdl_create_display_locked(w, h); al_unlock_mutex(s->mutex); return d; } static void convert_display_bitmaps_to_memory_bitmap(ALLEGRO_DISPLAY *d) { ALLEGRO_DEBUG("converting display bitmaps to memory bitmaps.\n"); while (d->bitmaps._size > 0) { ALLEGRO_BITMAP **bptr = _al_vector_ref_back(&d->bitmaps); ALLEGRO_BITMAP *b = *bptr; _al_convert_to_memory_bitmap(b); } } static void transfer_display_bitmaps_to_any_other_display( ALLEGRO_SYSTEM *s, ALLEGRO_DISPLAY *d) { size_t i; ALLEGRO_DISPLAY *living = NULL; ASSERT(s->displays._size > 1); for (i = 0; i < s->displays._size; i++) { ALLEGRO_DISPLAY **slot = _al_vector_ref(&s->displays, i); living = *slot; if (living != d) break; } ALLEGRO_DEBUG("transferring display bitmaps to other display.\n"); for (i = 0; i < d->bitmaps._size; i++) { ALLEGRO_BITMAP **add = _al_vector_alloc_back(&(living->bitmaps)); ALLEGRO_BITMAP **ref = _al_vector_ref(&d->bitmaps, i); *add = *ref; (*add)->_display = living; } } static void sdl_destroy_display_locked(ALLEGRO_DISPLAY *d) { ALLEGRO_DISPLAY_SDL *sdl = (void *)d; ALLEGRO_SYSTEM *system = al_get_system_driver(); ALLEGRO_OGL_EXTRAS *ogl = d->ogl_extras; bool is_last; ALLEGRO_DEBUG("destroying display.\n"); /* If we're the last display, convert all bitmaps to display independent * (memory) bitmaps. Otherwise, pass all bitmaps to any other living * display. We assume all displays are compatible.) */ is_last = (system->displays._size == 1); if (is_last) convert_display_bitmaps_to_memory_bitmap(d); else transfer_display_bitmaps_to_any_other_display(system, d); _al_ogl_unmanage_extensions(d); ALLEGRO_DEBUG("unmanaged extensions.\n"); if (ogl->backbuffer) { _al_ogl_destroy_backbuffer(ogl->backbuffer); ogl->backbuffer = NULL; ALLEGRO_DEBUG("destroy backbuffer.\n"); } _al_vector_free(&d->bitmaps); _al_event_source_free(&d->es); al_free(d->ogl_extras); al_free(d->vertex_cache); _al_event_source_free(&d->es); _al_vector_find_and_delete(&system->displays, &d); SDL_GL_DeleteContext(sdl->context); SDL_DestroyWindow(sdl->window); al_free(sdl); } static void sdl_destroy_display(ALLEGRO_DISPLAY *d) { ALLEGRO_SYSTEM_SDL *s = (void *)al_get_system_driver(); al_lock_mutex(s->mutex); sdl_destroy_display_locked(d); al_unlock_mutex(s->mutex); } static bool sdl_set_current_display(ALLEGRO_DISPLAY *d) { ALLEGRO_DISPLAY_SDL *sdl = (void *)d; SDL_GL_MakeCurrent(sdl->window, sdl->context); return true; } static void sdl_unset_current_display(ALLEGRO_DISPLAY *d) { (void)d; } static void sdl_flip_display(ALLEGRO_DISPLAY *d) { ALLEGRO_DISPLAY_SDL *sdl = (void *)d; SDL_GL_SwapWindow(sdl->window); // SDL loses texture contents, for example on resize. al_backup_dirty_bitmaps(d); } static void sdl_update_display_region(ALLEGRO_DISPLAY *d, int x, int y, int width, int height) { ALLEGRO_DISPLAY_SDL *sdl = (void *)d; (void)x; (void)y; (void)width; (void)height; SDL_GL_SwapWindow(sdl->window); } static bool sdl_is_compatible_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { (void)display; (void)bitmap; return true; } static bool sdl_set_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_MOUSE_CURSOR *cursor) { ALLEGRO_MOUSE_CURSOR_SDL *sdl_cursor = (ALLEGRO_MOUSE_CURSOR_SDL *) cursor; (void)display; SDL_SetCursor(sdl_cursor->cursor); return true; } static bool sdl_set_system_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id) { (void)display; (void)cursor_id; return false; } static bool sdl_show_mouse_cursor(ALLEGRO_DISPLAY *display) { (void)display; return SDL_ShowCursor(SDL_ENABLE) == SDL_ENABLE; } static bool sdl_hide_mouse_cursor(ALLEGRO_DISPLAY *display) { (void)display; return SDL_ShowCursor(SDL_DISABLE) == SDL_DISABLE; } static void sdl_set_window_position(ALLEGRO_DISPLAY *display, int x, int y) { ALLEGRO_DISPLAY_SDL *sdl = (void *)display; SDL_SetWindowPosition(sdl->window, x, y); } static void sdl_get_window_position(ALLEGRO_DISPLAY *display, int *x, int *y) { ALLEGRO_DISPLAY_SDL *sdl = (void *)display; SDL_GetWindowPosition(sdl->window, x, y); } static void recreate_textures(ALLEGRO_DISPLAY *display) { unsigned int i; for (i = 0; i < _al_vector_size(&display->bitmaps); i++) { ALLEGRO_BITMAP **bptr = _al_vector_ref(&display->bitmaps, i); ALLEGRO_BITMAP *bitmap = *bptr; int bitmap_flags = al_get_bitmap_flags(bitmap); if (bitmap->parent) continue; if (bitmap_flags & ALLEGRO_MEMORY_BITMAP) continue; if (bitmap_flags & ALLEGRO_NO_PRESERVE_TEXTURE) continue; _al_ogl_upload_bitmap_memory(bitmap, _al_get_bitmap_memory_format( bitmap), bitmap->memory); } } static bool sdl_acknowledge_resize(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_SDL *sdl = (void *)display; SDL_GL_GetDrawableSize(sdl->window, &display->w, &display->h); _al_ogl_setup_gl(display); if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { display->default_shader = _al_create_default_shader(display); al_use_shader(display->default_shader); } recreate_textures(display); _al_glsl_unuse_shaders(); return true; } static void sdl_set_window_title(ALLEGRO_DISPLAY *display, char const *title) { ALLEGRO_DISPLAY_SDL *sdl = (void *)display; SDL_SetWindowTitle(sdl->window, title); } static bool sdl_resize_display(ALLEGRO_DISPLAY *display, int width, int height) { ALLEGRO_DISPLAY_SDL *sdl = (void *)display; // Allegro uses pixels everywhere, while SDL uses screen space for window size int window_width, drawable_width, h; SDL_GetWindowSize(sdl->window, &window_width, &h); SDL_GL_GetDrawableSize(sdl->window, &drawable_width, &h); float ratio = drawable_width / (float)window_width; SDL_SetWindowSize(sdl->window, width / ratio, height / ratio); sdl_acknowledge_resize(display); return true; } static bool sdl_set_display_flag(ALLEGRO_DISPLAY *display, int flag, bool flag_onoff) { ALLEGRO_DISPLAY_SDL *sdl = (void *)display; switch (flag) { case ALLEGRO_FRAMELESS: /* The ALLEGRO_FRAMELESS flag is backwards. */ SDL_SetWindowBordered(sdl->window, !flag_onoff); return true; case ALLEGRO_FULLSCREEN_WINDOW: SDL_SetWindowFullscreen(sdl->window, flag_onoff ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); return true; case ALLEGRO_MAXIMIZED: if (flag_onoff) { SDL_MaximizeWindow(sdl->window); } else { SDL_RestoreWindow(sdl->window); } return true; } return false; } static void sdl_set_icons(ALLEGRO_DISPLAY *display, int num_icons, ALLEGRO_BITMAP *bitmaps[]) { ALLEGRO_DISPLAY_SDL *sdl = (void *)display; int w = al_get_bitmap_width(bitmaps[0]); int h = al_get_bitmap_height(bitmaps[0]); int data_size = w * h * 4; (void)num_icons; unsigned char* data = al_malloc(data_size * sizeof(data[0])); Uint32 rmask, gmask, bmask, amask; #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; #else // little endian, like x86 rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; #endif ALLEGRO_LOCKED_REGION *lock = al_lock_bitmap(bitmaps[0], ALLEGRO_PIXEL_FORMAT_ABGR_8888, ALLEGRO_LOCK_READONLY); if (lock) { int i = 0, y = 0; for (y = 0; y < h; y++) { int x = 0; for (x = 0; x < w; x++) { ALLEGRO_COLOR c = al_get_pixel(bitmaps[0], x, y); al_unmap_rgba(c, data+i, data+i+1, data+i+2, data+i+3); i += 4; } } al_unlock_bitmap(bitmaps[0]); SDL_Surface *icon = SDL_CreateRGBSurfaceFrom(data, w, h, 4 * 8, w * 4, rmask, gmask, bmask, amask); SDL_SetWindowIcon(sdl->window, icon); SDL_FreeSurface(icon); } al_free(data); } ALLEGRO_DISPLAY_INTERFACE *_al_sdl_display_driver(void) { if (vt) return vt; vt = al_calloc(1, sizeof *vt); vt->id = AL_ID('S', 'D', 'L', '2'); vt->create_display = sdl_create_display; vt->destroy_display = sdl_destroy_display; vt->set_current_display = sdl_set_current_display; vt->unset_current_display = sdl_unset_current_display; //vt->clear = GL //vt->draw_pixel = GL vt->flip_display = sdl_flip_display; vt->update_display_region = sdl_update_display_region; vt->acknowledge_resize = sdl_acknowledge_resize; vt->resize_display = sdl_resize_display; /*vt->quick_size = sdl_quick_size; vt->get_orientation = sdl_get_orientation;*/ vt->create_bitmap = _al_ogl_create_bitmap; vt->set_target_bitmap = _al_ogl_set_target_bitmap; vt->get_backbuffer = _al_ogl_get_backbuffer; vt->is_compatible_bitmap = sdl_is_compatible_bitmap; /*vt->switch_out = sdl_switch_out; vt->switch_in = sdl_switch_in; vt->draw_memory_bitmap_region = sdl_draw_memory_bitmap_region; vt->wait_for_vsync = sdl_wait_for_vsync;*/ vt->set_mouse_cursor = sdl_set_mouse_cursor; vt->set_system_mouse_cursor = sdl_set_system_mouse_cursor; vt->show_mouse_cursor = sdl_show_mouse_cursor; vt->hide_mouse_cursor = sdl_hide_mouse_cursor; vt->set_icons = sdl_set_icons; vt->set_window_position = sdl_set_window_position; vt->get_window_position = sdl_get_window_position; /*vt->set_window_constraints = sdl_set_window_constraints; vt->get_window_constraints = sdl_get_window_constraints;*/ vt->set_display_flag = sdl_set_display_flag; vt->set_window_title = sdl_set_window_title; //vt->flush_vertex_cache = GL //vt->prepare_vertex_cache = GL //vt->update_transformation = GL //vt->set_projection = GL /*vt->shutdown = sdl_shutdown; vt->acknowledge_drawing_halt = sdl_acknowledge_drawing_halt; vt->acknowledge_drawing_resume = sdl_acknowledge_drawing_resume; vt->set_display_option = sdl_set_display_option;*/ //vt->clear_depth_buffer = GL vt->update_render_state = _al_ogl_update_render_state; _al_ogl_add_drawing_functions(vt); return vt; } allegro5-5.2.10.1/src/sdl/sdl_event_hack.c000066400000000000000000000041701473414355200201500ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * SDL event hack (see below). * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_timer.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/platform/allegro_internal_sdl.h" /* This is a thread which wakes up event queues from time to time (with fake * timer events) to prevent a deadlock in an unbound al_wait_for_event. */ static ALLEGRO_THREAD *thread; static void wakeup_with_fake_timer_event(void) { ALLEGRO_EVENT_SOURCE *es = al_get_keyboard_event_source(); _al_event_source_lock(es); ALLEGRO_EVENT event; event.timer.type = ALLEGRO_EVENT_TIMER; event.timer.timestamp = al_get_time(); event.timer.count = 0; event.timer.error = 0; _al_event_source_emit_event(es, &event); _al_event_source_unlock(es); } static void *wakeup_thread(ALLEGRO_THREAD *thread, void *user) { al_rest(1); while (!al_get_thread_should_stop(thread)) { /* If the program uses timers, this hack is not required usually. */ if (_al_get_active_timers_count()) break; if (!al_is_keyboard_installed()) break; wakeup_with_fake_timer_event(); al_rest(0.01); } return user; } static void _uninstall_sdl_event_hack(void) { if (thread) { al_set_thread_should_stop(thread); al_join_thread(thread, NULL); al_destroy_thread(thread); } } void _al_sdl_event_hack(void) { if (thread) return; _al_add_exit_func(_uninstall_sdl_event_hack, "uninstall_sdl_event_hack"); thread = al_create_thread(wakeup_thread, NULL); al_start_thread(thread); } allegro5-5.2.10.1/src/sdl/sdl_joystick.c000066400000000000000000000131011473414355200176720ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * SDL joystick driver. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/platform/allegro_internal_sdl.h" ALLEGRO_DEBUG_CHANNEL("SDL") typedef struct ALLEGRO_JOYSTICK_SDL { int id; ALLEGRO_JOYSTICK allegro; SDL_Joystick *sdl; } ALLEGRO_JOYSTICK_SDL; static ALLEGRO_JOYSTICK_DRIVER *vt; static int count; static ALLEGRO_JOYSTICK_SDL *joysticks; static int get_id(ALLEGRO_JOYSTICK *allegro) { int i; for (i = 0; i < count; i++) { if (&joysticks[i].allegro == allegro) return i; } return -1; } static SDL_Joystick *get_sdl(ALLEGRO_JOYSTICK *allegro) { int id = get_id(allegro); if (id < 0) return NULL; return joysticks[id].sdl; } void _al_sdl_joystick_event(SDL_Event *e) { ALLEGRO_EVENT event; memset(&event, 0, sizeof event); event.joystick.timestamp = al_get_time(); if (e->type == SDL_JOYAXISMOTION) { event.joystick.type = ALLEGRO_EVENT_JOYSTICK_AXIS; event.joystick.id = &joysticks[e->jaxis.which].allegro; event.joystick.stick = e->jaxis.axis / 2; event.joystick.axis = e->jaxis.axis % 2; event.joystick.pos = e->jaxis.value / 32768.0; event.joystick.button = 0; } else if (e->type == SDL_JOYBUTTONDOWN) { event.joystick.type = ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN; event.joystick.id = &joysticks[e->jbutton.which].allegro; event.joystick.stick = 0; event.joystick.axis = 0; event.joystick.pos = 0; event.joystick.button = e->jbutton.button; } else if (e->type == SDL_JOYBUTTONUP) { event.joystick.type = ALLEGRO_EVENT_JOYSTICK_BUTTON_UP; event.joystick.id = &joysticks[e->jbutton.which].allegro; event.joystick.stick = 0; event.joystick.axis = 0; event.joystick.pos = 0; event.joystick.button = e->jbutton.button; } else if (e->type == SDL_JOYDEVICEADDED || e->type == SDL_JOYDEVICEREMOVED) { event.joystick.type = ALLEGRO_EVENT_JOYSTICK_CONFIGURATION; } else { return; } ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); _al_event_source_lock(es); _al_event_source_emit_event(es, &event); _al_event_source_unlock(es); } static bool sdl_init_joystick(void) { count = SDL_NumJoysticks(); joysticks = count > 0 ? calloc(count, sizeof * joysticks) : NULL; int i; for (i = 0; i < count; i++) { joysticks[i].sdl = SDL_JoystickOpen(i); _AL_JOYSTICK_INFO *info = &joysticks[i].allegro.info; int an = SDL_JoystickNumAxes(joysticks[i].sdl); int a; info->num_sticks = an / 2; for (a = 0; a < an; a++) { info->stick[a / 2].num_axes = 2; info->stick[a / 2].name = "stick"; info->stick[a / 2].axis[0].name = "X"; info->stick[a / 2].axis[1].name = "Y"; } int bn = SDL_JoystickNumButtons(joysticks[i].sdl); info->num_buttons = bn; int b; for (b = 0; b < bn; b++) { info->button[b].name = SDL_IsGameController(i) ? SDL_GameControllerGetStringForButton(b) : "button"; } } SDL_JoystickEventState(SDL_ENABLE); return true; } static void sdl_exit_joystick(void) { int i; for (i = 0; i < count; i++) { SDL_JoystickClose(joysticks[i].sdl); } count = 0; free(joysticks); joysticks = NULL; } static bool sdl_reconfigure_joysticks(void) { sdl_exit_joystick(); return sdl_init_joystick(); } static int sdl_num_joysticks(void) { return count; } static ALLEGRO_JOYSTICK *sdl_get_joystick(int joyn) { return &joysticks[joyn].allegro; } static void sdl_release_joystick(ALLEGRO_JOYSTICK *joy) { ASSERT(joy); } static void sdl_get_joystick_state(ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state) { ALLEGRO_SYSTEM_INTERFACE *s = _al_sdl_system_driver(); s->heartbeat(); SDL_Joystick *sdl = get_sdl(joy); int an = SDL_JoystickNumAxes(sdl); int i; for (i = 0; i < an; i++) { ret_state->stick[i / 2].axis[i % 2] = SDL_JoystickGetAxis(sdl, i) / 32768.0; } int bn = SDL_JoystickNumButtons(sdl); for (i = 0; i < bn; i++) { ret_state->button[i] = SDL_JoystickGetButton(sdl, i) * 32767; } } static const char *sdl_get_name(ALLEGRO_JOYSTICK *joy) { SDL_Joystick *sdl = get_sdl(joy); return SDL_JoystickName(sdl); } static bool sdl_get_active(ALLEGRO_JOYSTICK *joy) { SDL_Joystick *sdl = get_sdl(joy); return SDL_JoystickGetAttached(sdl); } ALLEGRO_JOYSTICK_DRIVER *_al_sdl_joystick_driver(void) { if (vt) return vt; vt = al_calloc(1, sizeof *vt); vt->joydrv_id = AL_ID('S','D','L','2'); vt->joydrv_name = "SDL2 Joystick"; vt->joydrv_desc = "SDL2 Joystick"; vt->joydrv_ascii_name = "SDL2 Joystick"; vt->init_joystick = sdl_init_joystick; vt->exit_joystick = sdl_exit_joystick; vt->reconfigure_joysticks = sdl_reconfigure_joysticks; vt->num_joysticks = sdl_num_joysticks; vt->get_joystick = sdl_get_joystick; vt->release_joystick = sdl_release_joystick; vt->get_joystick_state = sdl_get_joystick_state;; vt->get_name = sdl_get_name; vt->get_active = sdl_get_active; return vt; } allegro5-5.2.10.1/src/sdl/sdl_keyboard.c000066400000000000000000000345361473414355200176520ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * SDL keyboard driver. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/platform/allegro_internal_sdl.h" ALLEGRO_DEBUG_CHANNEL("SDL") typedef struct ALLEGRO_KEYBOARD_SDL { ALLEGRO_KEYBOARD keyboard; int table[1024]; int inverse[1024]; int unicode[1024]; int inverse_unicode[1024]; bool create_extra_char[1024]; ALLEGRO_DISPLAY *display; } ALLEGRO_KEYBOARD_SDL; static ALLEGRO_KEYBOARD_DRIVER *vt; static ALLEGRO_KEYBOARD_SDL *keyboard; static unsigned int get_modifiers(int modifiers) { int result = 0; if (modifiers & KMOD_LSHIFT) result |= ALLEGRO_KEYMOD_SHIFT; if (modifiers & KMOD_RSHIFT) result |= ALLEGRO_KEYMOD_SHIFT; if (modifiers & KMOD_LCTRL) result |= ALLEGRO_KEYMOD_CTRL; if (modifiers & KMOD_RCTRL) result |= ALLEGRO_KEYMOD_CTRL; if (modifiers & KMOD_LALT) result |= ALLEGRO_KEYMOD_ALT; if (modifiers & KMOD_RALT) result |= ALLEGRO_KEYMOD_ALT; if (modifiers & KMOD_LGUI) result |= ALLEGRO_KEYMOD_LWIN; if (modifiers & KMOD_RGUI) result |= ALLEGRO_KEYMOD_RWIN; if (modifiers & KMOD_NUM) result |= ALLEGRO_KEYMOD_NUMLOCK; if (modifiers & KMOD_CAPS) result |= ALLEGRO_KEYMOD_CAPSLOCK; if (modifiers & KMOD_MODE) result |= ALLEGRO_KEYMOD_ALTGR; return result; } void _al_sdl_keyboard_event(SDL_Event *e) { if (!keyboard) return; if (e->type == SDL_WINDOWEVENT) { if (e->window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { keyboard->display = _al_sdl_find_display(e->window.windowID); } else { keyboard->display = NULL; } return; } ALLEGRO_EVENT event; ALLEGRO_EVENT_SOURCE *es = &keyboard->keyboard.es; _al_event_source_lock(es); event.keyboard.timestamp = al_get_time(); event.keyboard.display = NULL; event.keyboard.modifiers = get_modifiers(e->key.keysym.mod); event.keyboard.repeat = false; if (e->type == SDL_TEXTINPUT) { ALLEGRO_USTR_INFO info; ALLEGRO_USTR const *u = al_ref_cstr(&info, e->text.text); int pos = 0; while (true) { int32_t c = al_ustr_get_next(u, &pos); if (c <= 0) break; event.keyboard.type = ALLEGRO_EVENT_KEY_CHAR; event.keyboard.keycode = c < 1024 ? keyboard->inverse_unicode[c] : 0; event.keyboard.unichar = c; event.keyboard.display = _al_sdl_find_display(e->text.windowID); _al_event_source_emit_event(es, &event); } } else if (e->type == SDL_KEYDOWN) { event.keyboard.type = ALLEGRO_EVENT_KEY_DOWN; event.keyboard.keycode = keyboard->table[e->key.keysym.scancode]; event.keyboard.unichar = keyboard->unicode[e->key.keysym.scancode]; event.keyboard.display = _al_sdl_find_display(e->key.windowID); if (!e->key.repeat) { _al_event_source_emit_event(es, &event); } if (keyboard->create_extra_char[e->key.keysym.scancode]) { event.keyboard.type = ALLEGRO_EVENT_KEY_CHAR; _al_event_source_emit_event(es, &event); } } else if (e->type == SDL_KEYUP) { event.keyboard.type = ALLEGRO_EVENT_KEY_UP; event.keyboard.keycode = keyboard->table[e->key.keysym.scancode]; event.keyboard.unichar = keyboard->unicode[e->key.keysym.scancode]; event.keyboard.display = _al_sdl_find_display(e->key.windowID); _al_event_source_emit_event(es, &event); } keyboard->display = event.keyboard.display; _al_event_source_unlock(es); } static void adde(int sdl_scancode, int allegro_keycode, int unicode, bool extra) { if (sdl_scancode >= 1024) { ALLEGRO_WARN("Cannot map SDL scancode %d.\n", sdl_scancode); return; } keyboard->table[sdl_scancode] = allegro_keycode; keyboard->inverse[allegro_keycode] = sdl_scancode; keyboard->unicode[sdl_scancode] = unicode; keyboard->inverse_unicode[unicode] = allegro_keycode; keyboard->create_extra_char[sdl_scancode] = extra; } static void add(int sdl_scancode, int allegro_keycode, int unicode) { adde(sdl_scancode, allegro_keycode, unicode, false); } #define ADD_SAME(X, c) add(SDL_SCANCODE_##X, ALLEGRO_KEY_##X, c) #define ADD_SAMEC(X) add(SDL_SCANCODE_##X, ALLEGRO_KEY_##X, tolower(#X[0])) #define ADD_SAMEE(X, c) adde(SDL_SCANCODE_##X, ALLEGRO_KEY_##X, c, true) static bool sdl_init_keyboard(void) { keyboard = al_calloc(1, sizeof *keyboard); _al_event_source_init(&keyboard->keyboard.es); add(SDL_SCANCODE_UNKNOWN, 0, 0); ADD_SAMEC(A); ADD_SAMEC(B); ADD_SAMEC(C); ADD_SAMEC(D); ADD_SAMEC(E); ADD_SAMEC(F); ADD_SAMEC(G); ADD_SAMEC(H); ADD_SAMEC(I); ADD_SAMEC(J); ADD_SAMEC(K); ADD_SAMEC(L); ADD_SAMEC(M); ADD_SAMEC(N); ADD_SAMEC(O); ADD_SAMEC(P); ADD_SAMEC(Q); ADD_SAMEC(R); ADD_SAMEC(S); ADD_SAMEC(T); ADD_SAMEC(U); ADD_SAMEC(V); ADD_SAMEC(W); ADD_SAMEC(X); ADD_SAMEC(Y); ADD_SAMEC(Z); ADD_SAMEC(1); ADD_SAMEC(2); ADD_SAMEC(3); ADD_SAMEC(4); ADD_SAMEC(5); ADD_SAMEC(6); ADD_SAMEC(7); ADD_SAMEC(8); ADD_SAMEC(9); ADD_SAMEC(0); adde(SDL_SCANCODE_RETURN, ALLEGRO_KEY_ENTER, 13, true); ADD_SAMEE(ESCAPE, 27); ADD_SAMEE(BACKSPACE, 8); ADD_SAMEE(TAB, 9); ADD_SAME(SPACE, ' '); ADD_SAME(MINUS, '-'); ADD_SAME(EQUALS, '='); add(SDL_SCANCODE_LEFTBRACKET, ALLEGRO_KEY_OPENBRACE, '['); add(SDL_SCANCODE_RIGHTBRACKET, ALLEGRO_KEY_CLOSEBRACE, ']'); ADD_SAME(BACKSLASH, '\\'); add(SDL_SCANCODE_NONUSHASH, 0, '#'); ADD_SAME(SEMICOLON, ';'); add(SDL_SCANCODE_APOSTROPHE, ALLEGRO_KEY_QUOTE, '\''); add(SDL_SCANCODE_GRAVE, ALLEGRO_KEY_TILDE, '~'); ADD_SAME(COMMA, ','); add(SDL_SCANCODE_PERIOD, ALLEGRO_KEY_FULLSTOP, '.'); ADD_SAME(SLASH, '/'); ADD_SAME(CAPSLOCK, 0); ADD_SAMEE(F1, 0); ADD_SAMEE(F2, 0); ADD_SAMEE(F3, 0); ADD_SAMEE(F4, 0); ADD_SAMEE(F5, 0); ADD_SAMEE(F6, 0); ADD_SAMEE(F7, 0); ADD_SAMEE(F8, 0); ADD_SAMEE(F9, 0); ADD_SAMEE(F10, 0); ADD_SAMEE(F11, 0); ADD_SAMEE(F12, 0); ADD_SAME(PRINTSCREEN, 0); ADD_SAME(SCROLLLOCK, 0); ADD_SAME(PAUSE, 0); ADD_SAMEE(INSERT, 0); ADD_SAMEE(HOME, 0); add(SDL_SCANCODE_PAGEUP, ALLEGRO_KEY_PGUP, 0); ADD_SAMEE(DELETE, 0); ADD_SAMEE(END, 0); add(SDL_SCANCODE_PAGEDOWN, ALLEGRO_KEY_PGDN, 0); ADD_SAMEE(RIGHT, 0); ADD_SAMEE(LEFT, 0); ADD_SAMEE(DOWN, 0); ADD_SAMEE(UP, 0); add(SDL_SCANCODE_NUMLOCKCLEAR, ALLEGRO_KEY_NUMLOCK, 0); add(SDL_SCANCODE_KP_DIVIDE, ALLEGRO_KEY_PAD_SLASH, '/'); add(SDL_SCANCODE_KP_MULTIPLY, ALLEGRO_KEY_PAD_ASTERISK, '*'); add(SDL_SCANCODE_KP_MINUS, ALLEGRO_KEY_PAD_MINUS, '-'); add(SDL_SCANCODE_KP_PLUS, ALLEGRO_KEY_PAD_PLUS, '+'); add(SDL_SCANCODE_KP_ENTER, ALLEGRO_KEY_PAD_ENTER, 13); add(SDL_SCANCODE_KP_1, ALLEGRO_KEY_PAD_1, '1'); add(SDL_SCANCODE_KP_2, ALLEGRO_KEY_PAD_2, '2'); add(SDL_SCANCODE_KP_3, ALLEGRO_KEY_PAD_3, '3'); add(SDL_SCANCODE_KP_4, ALLEGRO_KEY_PAD_4, '4'); add(SDL_SCANCODE_KP_5, ALLEGRO_KEY_PAD_5, '5'); add(SDL_SCANCODE_KP_6, ALLEGRO_KEY_PAD_6, '6'); add(SDL_SCANCODE_KP_7, ALLEGRO_KEY_PAD_7, '7'); add(SDL_SCANCODE_KP_8, ALLEGRO_KEY_PAD_8, '8'); add(SDL_SCANCODE_KP_9, ALLEGRO_KEY_PAD_9, '9'); add(SDL_SCANCODE_KP_0, ALLEGRO_KEY_PAD_0, '0'); add(SDL_SCANCODE_KP_PERIOD, ALLEGRO_KEY_PAD_DELETE, 0); add(SDL_SCANCODE_NONUSBACKSLASH, 0, '\\'); add(SDL_SCANCODE_APPLICATION, 0, 0); add(SDL_SCANCODE_POWER, 0, 0); add(SDL_SCANCODE_KP_EQUALS, ALLEGRO_KEY_PAD_EQUALS, '='); add(SDL_SCANCODE_F13, 0, 0); add(SDL_SCANCODE_F14, 0, 0); add(SDL_SCANCODE_F15, 0, 0); add(SDL_SCANCODE_F16, 0, 0); add(SDL_SCANCODE_F17, 0, 0); add(SDL_SCANCODE_F18, 0, 0); add(SDL_SCANCODE_F19, 0, 0); add(SDL_SCANCODE_F20, 0, 0); add(SDL_SCANCODE_F21, 0, 0); add(SDL_SCANCODE_F22, 0, 0); add(SDL_SCANCODE_F23, 0, 0); add(SDL_SCANCODE_F24, 0, 0); add(SDL_SCANCODE_EXECUTE, 0, 0); add(SDL_SCANCODE_HELP, 0, 0); ADD_SAME(MENU, 0); add(SDL_SCANCODE_SELECT, 0, 0); add(SDL_SCANCODE_STOP, 0, 0); add(SDL_SCANCODE_AGAIN, 0, 0); add(SDL_SCANCODE_UNDO, 0, 0); add(SDL_SCANCODE_CUT, 0, 0); add(SDL_SCANCODE_COPY, 0, 0); add(SDL_SCANCODE_PASTE, 0, 0); add(SDL_SCANCODE_FIND, 0, 0); add(SDL_SCANCODE_MUTE, 0, 0); add(SDL_SCANCODE_VOLUMEUP, 0, 0); add(SDL_SCANCODE_VOLUMEDOWN, 0, 0); add(SDL_SCANCODE_KP_COMMA, 0, ','); add(SDL_SCANCODE_KP_EQUALSAS400, 0, 0); add(SDL_SCANCODE_INTERNATIONAL1, 0, 0); add(SDL_SCANCODE_INTERNATIONAL2, 0, 0); add(SDL_SCANCODE_INTERNATIONAL3, 0, 0); add(SDL_SCANCODE_INTERNATIONAL4, 0, 0); add(SDL_SCANCODE_INTERNATIONAL5, 0, 0); add(SDL_SCANCODE_INTERNATIONAL6, 0, 0); add(SDL_SCANCODE_INTERNATIONAL7, 0, 0); add(SDL_SCANCODE_INTERNATIONAL8, 0, 0); add(SDL_SCANCODE_INTERNATIONAL9, 0, 0); add(SDL_SCANCODE_LANG1, 0, 0); add(SDL_SCANCODE_LANG2, 0, 0); add(SDL_SCANCODE_LANG3, 0, 0); add(SDL_SCANCODE_LANG4, 0, 0); add(SDL_SCANCODE_LANG5, 0, 0); add(SDL_SCANCODE_LANG6, 0, 0); add(SDL_SCANCODE_LANG7, 0, 0); add(SDL_SCANCODE_LANG8, 0, 0); add(SDL_SCANCODE_LANG9, 0, 0); add(SDL_SCANCODE_ALTERASE, 0, 0); add(SDL_SCANCODE_SYSREQ, 0, 0); add(SDL_SCANCODE_CANCEL, 0, 0); add(SDL_SCANCODE_CLEAR, 0, 0); add(SDL_SCANCODE_PRIOR, 0, 0); add(SDL_SCANCODE_RETURN2, 0, 0); add(SDL_SCANCODE_SEPARATOR, 0, 0); add(SDL_SCANCODE_OUT, 0, 0); add(SDL_SCANCODE_OPER, 0, 0); add(SDL_SCANCODE_CLEARAGAIN, 0, 0); add(SDL_SCANCODE_CRSEL, 0, 0); add(SDL_SCANCODE_EXSEL, 0, 0); add(SDL_SCANCODE_KP_00, 0, 0); add(SDL_SCANCODE_KP_000, 0, 0); add(SDL_SCANCODE_THOUSANDSSEPARATOR, 0, 0); add(SDL_SCANCODE_DECIMALSEPARATOR, 0, 0); add(SDL_SCANCODE_CURRENCYUNIT, 0, 0); add(SDL_SCANCODE_CURRENCYSUBUNIT, 0, 0); add(SDL_SCANCODE_KP_LEFTPAREN, 0, 0); add(SDL_SCANCODE_KP_RIGHTPAREN, 0, 0); add(SDL_SCANCODE_KP_LEFTBRACE, 0, '{'); add(SDL_SCANCODE_KP_RIGHTBRACE, 0, '}'); add(SDL_SCANCODE_KP_TAB, 0, 9); add(SDL_SCANCODE_KP_BACKSPACE, 0, 8); add(SDL_SCANCODE_KP_A, 0, 0); add(SDL_SCANCODE_KP_B, 0, 0); add(SDL_SCANCODE_KP_C, 0, 0); add(SDL_SCANCODE_KP_D, 0, 0); add(SDL_SCANCODE_KP_E, 0, 0); add(SDL_SCANCODE_KP_F, 0, 0); add(SDL_SCANCODE_KP_XOR, 0, 0); add(SDL_SCANCODE_KP_POWER, 0, 0); add(SDL_SCANCODE_KP_PERCENT, 0, 0); add(SDL_SCANCODE_KP_LESS, 0, '<'); add(SDL_SCANCODE_KP_GREATER, 0, '>'); add(SDL_SCANCODE_KP_AMPERSAND, 0, '&'); add(SDL_SCANCODE_KP_DBLAMPERSAND, 0, 0); add(SDL_SCANCODE_KP_VERTICALBAR, 0, '|'); add(SDL_SCANCODE_KP_DBLVERTICALBAR, 0, 0); add(SDL_SCANCODE_KP_COLON, 0, ':'); add(SDL_SCANCODE_KP_HASH, 0, '#'); add(SDL_SCANCODE_KP_SPACE, 0, 0); add(SDL_SCANCODE_KP_AT, 0, '@'); add(SDL_SCANCODE_KP_EXCLAM, 0, '!'); add(SDL_SCANCODE_KP_MEMSTORE, 0, 0); add(SDL_SCANCODE_KP_MEMRECALL, 0, 0); add(SDL_SCANCODE_KP_MEMCLEAR, 0, 0); add(SDL_SCANCODE_KP_MEMADD, 0, 0); add(SDL_SCANCODE_KP_MEMSUBTRACT, 0, 0); add(SDL_SCANCODE_KP_MEMMULTIPLY, 0, 0); add(SDL_SCANCODE_KP_MEMDIVIDE, 0, 0); add(SDL_SCANCODE_KP_PLUSMINUS, 0, 0); add(SDL_SCANCODE_KP_CLEAR, 0, 0); add(SDL_SCANCODE_KP_CLEARENTRY, 0, 0); add(SDL_SCANCODE_KP_BINARY, 0, 0); add(SDL_SCANCODE_KP_OCTAL, 0, 0); add(SDL_SCANCODE_KP_DECIMAL, 0, 0); add(SDL_SCANCODE_KP_HEXADECIMAL, 0, 0); ADD_SAME(LCTRL, 0); ADD_SAME(LSHIFT, 0); add(SDL_SCANCODE_LALT, ALLEGRO_KEY_ALT, 0); add(SDL_SCANCODE_LGUI, ALLEGRO_KEY_LWIN, 0); ADD_SAME(RCTRL, 0); ADD_SAME(RSHIFT, 0); add(SDL_SCANCODE_RALT, ALLEGRO_KEY_ALTGR, 0); add(SDL_SCANCODE_RGUI, ALLEGRO_KEY_RWIN, 0); add(SDL_SCANCODE_MODE, 0, 0); add(SDL_SCANCODE_AUDIONEXT, 0, 0); add(SDL_SCANCODE_AUDIOPREV, 0, 0); add(SDL_SCANCODE_AUDIOSTOP, 0, 0); add(SDL_SCANCODE_AUDIOPLAY, 0, 0); add(SDL_SCANCODE_AUDIOMUTE, 0, 0); add(SDL_SCANCODE_MEDIASELECT, 0, 0); add(SDL_SCANCODE_WWW, 0, 0); add(SDL_SCANCODE_MAIL, 0, 0); add(SDL_SCANCODE_CALCULATOR, 0, 0); add(SDL_SCANCODE_COMPUTER, 0, 0); add(SDL_SCANCODE_AC_SEARCH, 0, 0); add(SDL_SCANCODE_AC_HOME, 0, 0); add(SDL_SCANCODE_AC_BACK, 0, 0); add(SDL_SCANCODE_AC_FORWARD, 0, 0); add(SDL_SCANCODE_AC_STOP, 0, 0); add(SDL_SCANCODE_AC_REFRESH, 0, 0); add(SDL_SCANCODE_AC_BOOKMARKS, 0, 0); add(SDL_SCANCODE_BRIGHTNESSDOWN, 0, 0); add(SDL_SCANCODE_BRIGHTNESSUP, 0, 0); add(SDL_SCANCODE_DISPLAYSWITCH, 0, 0); add(SDL_SCANCODE_KBDILLUMTOGGLE, 0, 0); add(SDL_SCANCODE_KBDILLUMDOWN, 0, 0); add(SDL_SCANCODE_KBDILLUMUP, 0, 0); add(SDL_SCANCODE_EJECT, 0, 0); add(SDL_SCANCODE_SLEEP, 0, 0); _al_sdl_event_hack(); return true; } static void sdl_exit_keyboard(void) { } static ALLEGRO_KEYBOARD *sdl_get_keyboard(void) { return &keyboard->keyboard; } static bool sdl_set_keyboard_leds(int leds) { (void)leds; return false; } static char const *sdl_keycode_to_name(int keycode) { return SDL_GetScancodeName(keyboard->inverse[keycode]); } static void sdl_get_keyboard_state(ALLEGRO_KEYBOARD_STATE *ret_state) { int i, n; ALLEGRO_SYSTEM_INTERFACE *sdl = _al_sdl_system_driver(); sdl->heartbeat(); const Uint8 *s = SDL_GetKeyboardState(&n); for (i = 0; i < n; i++) { if (s[i]) _AL_KEYBOARD_STATE_SET_KEY_DOWN(*ret_state, keyboard->table[i]); else _AL_KEYBOARD_STATE_CLEAR_KEY_DOWN(*ret_state, keyboard->table[i]); } ret_state->display = keyboard->display; } static void sdl_clear_keyboard_state(void) { return; } ALLEGRO_KEYBOARD_DRIVER *_al_sdl_keyboard_driver(void) { if (vt) return vt; vt = al_calloc(1, sizeof *vt); vt->keydrv_id = AL_ID('S','D','L','2'); vt->keydrv_name = "SDL2 Keyboard"; vt->keydrv_desc = "SDL2 Keyboard"; vt->keydrv_ascii_name = "SDL2 Keyboard"; vt->init_keyboard = sdl_init_keyboard; vt->exit_keyboard = sdl_exit_keyboard; vt->get_keyboard = sdl_get_keyboard; vt->set_keyboard_leds = sdl_set_keyboard_leds; vt->keycode_to_name = sdl_keycode_to_name; vt->get_keyboard_state = sdl_get_keyboard_state; vt->clear_keyboard_state = sdl_clear_keyboard_state; return vt; } allegro5-5.2.10.1/src/sdl/sdl_mouse.c000066400000000000000000000161131473414355200171710ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * SDL mouse driver. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/platform/allegro_internal_sdl.h" ALLEGRO_DEBUG_CHANNEL("SDL") typedef struct ALLEGRO_MOUSE_SDL { ALLEGRO_MOUSE mouse; ALLEGRO_MOUSE_STATE state; ALLEGRO_DISPLAY *display; float ratio; } ALLEGRO_MOUSE_SDL; static ALLEGRO_MOUSE_DRIVER *vt; static ALLEGRO_MOUSE_SDL *mouse; static ALLEGRO_DISPLAY *find_display(uint32_t window_id) { ALLEGRO_DISPLAY *d = _al_sdl_find_display(window_id); if (d) { return d; } else { // if there's only one display, we can assume that all // events refer to its coordinate system ALLEGRO_SYSTEM *s = al_get_system_driver(); if (_al_vector_size(&s->displays) == 1) { void **v = (void **)_al_vector_ref(&s->displays, 0); ALLEGRO_DISPLAY_SDL *d = *v; return &d->display; } } return NULL; } void _al_sdl_mouse_event(SDL_Event *e) { if (!mouse) return; ALLEGRO_EVENT_SOURCE *es = &mouse->mouse.es; _al_event_source_lock(es); ALLEGRO_EVENT event; memset(&event, 0, sizeof event); event.mouse.timestamp = al_get_time(); ALLEGRO_DISPLAY *d = NULL; if (e->type == SDL_WINDOWEVENT) { d = find_display(e->window.windowID); mouse->ratio = _al_sdl_get_display_pixel_ratio(d); if (e->window.event == SDL_WINDOWEVENT_ENTER) { event.mouse.type = ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY; SDL_GetMouseState(&event.mouse.x, &event.mouse.y); event.mouse.x *= mouse->ratio; event.mouse.y *= mouse->ratio; } else { event.mouse.type = ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY; event.mouse.x = mouse->state.x; event.mouse.y = mouse->state.y; event.mouse.z = mouse->state.z; event.mouse.w = mouse->state.w; } mouse->display = e->window.event == SDL_WINDOWEVENT_ENTER ? d : NULL; } else if (e->type == SDL_MOUSEMOTION) { if (e->motion.which == SDL_TOUCH_MOUSEID) { _al_event_source_unlock(es); return; } d = find_display(e->motion.windowID); float ratio = d ? _al_sdl_get_display_pixel_ratio(d) : 1.0; event.mouse.type = ALLEGRO_EVENT_MOUSE_AXES; event.mouse.x = e->motion.x * ratio; event.mouse.y = e->motion.y * ratio; event.mouse.z = mouse->state.z; event.mouse.w = mouse->state.w; event.mouse.dx = e->motion.xrel * ratio; event.mouse.dy = e->motion.yrel * ratio; event.mouse.dz = 0; event.mouse.dw = 0; mouse->state.x = e->motion.x * ratio; mouse->state.y = e->motion.y * ratio; } else if (e->type == SDL_MOUSEWHEEL) { if (e->wheel.which == SDL_TOUCH_MOUSEID) { _al_event_source_unlock(es); return; } d = find_display(e->wheel.windowID); event.mouse.type = ALLEGRO_EVENT_MOUSE_AXES; mouse->state.z += al_get_mouse_wheel_precision() * e->wheel.y; mouse->state.w += al_get_mouse_wheel_precision() * e->wheel.x; event.mouse.x = mouse->state.x; event.mouse.y = mouse->state.y; event.mouse.z = mouse->state.z; event.mouse.w = mouse->state.w; event.mouse.dx = 0; event.mouse.dy = 0; event.mouse.dz = al_get_mouse_wheel_precision() * e->wheel.y; event.mouse.dw = al_get_mouse_wheel_precision() * e->wheel.x; } else { if (e->button.which == SDL_TOUCH_MOUSEID) { _al_event_source_unlock(es); return; } d = find_display(e->button.windowID); float ratio = d ? _al_sdl_get_display_pixel_ratio(d) : 1.0; switch (e->button.button) { case SDL_BUTTON_LEFT: event.mouse.button = 1; break; case SDL_BUTTON_RIGHT: event.mouse.button = 2; break; case SDL_BUTTON_MIDDLE: event.mouse.button = 3; break; case SDL_BUTTON_X1: event.mouse.button = 4; break; case SDL_BUTTON_X2: event.mouse.button = 5; break; } event.mouse.x = e->button.x * ratio; event.mouse.y = e->button.y * ratio; event.mouse.z = mouse->state.z; event.mouse.w = mouse->state.w; if (e->type == SDL_MOUSEBUTTONDOWN) { event.mouse.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN; mouse->state.buttons |= 1 << (event.mouse.button - 1); } if (e->type == SDL_MOUSEBUTTONUP) { event.mouse.type = ALLEGRO_EVENT_MOUSE_BUTTON_UP; mouse->state.buttons &= ~(1 << (event.mouse.button - 1)); } } event.mouse.pressure = mouse->state.buttons ? 1.0 : 0.0; /* TODO */ event.mouse.display = d; _al_event_source_emit_event(es, &event); _al_event_source_unlock(es); } static bool sdl_init_mouse(void) { mouse = al_calloc(1, sizeof *mouse); _al_event_source_init(&mouse->mouse.es); mouse->ratio = 1.0f; return true; } static void sdl_exit_mouse(void) { } static ALLEGRO_MOUSE *sdl_get_mouse(void) { return &mouse->mouse; } static unsigned int sdl_get_mouse_num_buttons(void) { return 5; } static unsigned int sdl_get_mouse_num_axes(void) { return 4; } static bool sdl_set_mouse_xy(ALLEGRO_DISPLAY *display, int x, int y) { ALLEGRO_DISPLAY_SDL *sdl = (void *)display; float ratio = _al_sdl_get_display_pixel_ratio(display); SDL_WarpMouseInWindow(sdl->window, x / ratio, y / ratio); return true; } static bool sdl_set_mouse_axis(int which, int value) { if (which == 2) mouse->state.z = value; else if (which == 3) mouse->state.w = value; return false; } static void sdl_get_mouse_state(ALLEGRO_MOUSE_STATE *ret_state) { int x, y, i; ALLEGRO_SYSTEM_INTERFACE *sdl = _al_sdl_system_driver(); sdl->heartbeat(); SDL_GetMouseState(&x, &y); ret_state->x = x * mouse->ratio; ret_state->y = y * mouse->ratio; ret_state->z = 0; ret_state->w = 0; for (i = 0; i < ALLEGRO_MOUSE_MAX_EXTRA_AXES; i++) ret_state->more_axes[i] = 0; ret_state->buttons = mouse->state.buttons; ret_state->pressure = mouse->state.buttons ? 1.0 : 0.0; /* TODO */ ret_state->display = mouse->display; } ALLEGRO_MOUSE_DRIVER *_al_sdl_mouse_driver(void) { if (vt) return vt; vt = al_calloc(1, sizeof *vt); vt->msedrv_id = AL_ID('S','D','L','2'); vt->msedrv_name = "SDL2 Mouse"; vt->msedrv_desc = "SDL2 Mouse"; vt->msedrv_ascii_name = "SDL2 Mouse"; vt->init_mouse = sdl_init_mouse; vt->exit_mouse = sdl_exit_mouse; vt->get_mouse = sdl_get_mouse; vt->get_mouse_num_buttons = sdl_get_mouse_num_buttons; vt->get_mouse_num_axes = sdl_get_mouse_num_axes; vt->set_mouse_xy = sdl_set_mouse_xy; vt->set_mouse_axis = sdl_set_mouse_axis; vt->get_mouse_state = sdl_get_mouse_state; return vt; } allegro5-5.2.10.1/src/sdl/sdl_system.c000066400000000000000000000311651473414355200173710ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * SDL system interface. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/platform/allegro_internal_sdl.h" #include "allegro5/internal/aintern_timer.h" ALLEGRO_DEBUG_CHANNEL("SDL") static ALLEGRO_SYSTEM_INTERFACE *vt; #define ALLEGRO_SDL_EVENT_QUEUE_SIZE 8 #ifdef DEBUGMODE #define _E(x) if (type == x) return #x; static char const *event_name(int type) { _E(SDL_FIRSTEVENT) _E(SDL_QUIT) _E(SDL_APP_TERMINATING) _E(SDL_APP_LOWMEMORY) _E(SDL_APP_WILLENTERBACKGROUND) _E(SDL_APP_DIDENTERBACKGROUND) _E(SDL_APP_WILLENTERFOREGROUND) _E(SDL_APP_DIDENTERFOREGROUND) _E(SDL_WINDOWEVENT) _E(SDL_SYSWMEVENT) _E(SDL_KEYDOWN) _E(SDL_KEYUP) _E(SDL_TEXTEDITING) _E(SDL_TEXTINPUT) _E(SDL_MOUSEMOTION) _E(SDL_MOUSEBUTTONDOWN) _E(SDL_MOUSEBUTTONUP) _E(SDL_MOUSEWHEEL) _E(SDL_JOYAXISMOTION) _E(SDL_JOYBALLMOTION) _E(SDL_JOYHATMOTION) _E(SDL_JOYBUTTONDOWN) _E(SDL_JOYBUTTONUP) _E(SDL_JOYDEVICEADDED) _E(SDL_JOYDEVICEREMOVED) _E(SDL_CONTROLLERAXISMOTION) _E(SDL_CONTROLLERBUTTONDOWN) _E(SDL_CONTROLLERBUTTONUP) _E(SDL_CONTROLLERDEVICEADDED) _E(SDL_CONTROLLERDEVICEREMOVED) _E(SDL_CONTROLLERDEVICEREMAPPED) _E(SDL_FINGERDOWN) _E(SDL_FINGERUP) _E(SDL_FINGERMOTION) _E(SDL_DOLLARGESTURE) _E(SDL_DOLLARRECORD) _E(SDL_MULTIGESTURE) _E(SDL_CLIPBOARDUPDATE) _E(SDL_DROPFILE) _E(SDL_RENDER_TARGETS_RESET) _E(SDL_USEREVENT) return "(unknown)"; } #undef _E #endif static void sdl_heartbeat(void) { SDL_Event events[ALLEGRO_SDL_EVENT_QUEUE_SIZE]; ALLEGRO_SYSTEM_SDL *s = (void *)al_get_system_driver(); al_lock_mutex(s->mutex); SDL_PumpEvents(); int n, i; while ((n = SDL_PeepEvents(events, ALLEGRO_SDL_EVENT_QUEUE_SIZE, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) > 0) { for (i = 0; i < n; i++) { //printf("event %s\n", event_name(events[i].type)); switch (events[i].type) { case SDL_KEYDOWN: case SDL_KEYUP: case SDL_TEXTINPUT: _al_sdl_keyboard_event(&events[i]); break; case SDL_MOUSEMOTION: case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: case SDL_MOUSEWHEEL: _al_sdl_mouse_event(&events[i]); break; case SDL_FINGERDOWN: case SDL_FINGERMOTION: case SDL_FINGERUP: _al_sdl_touch_input_event(&events[i]); break; case SDL_JOYAXISMOTION: case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: case SDL_JOYDEVICEADDED: case SDL_JOYDEVICEREMOVED: _al_sdl_joystick_event(&events[i]); break; case SDL_QUIT: _al_sdl_display_event(&events[i]); break; case SDL_WINDOWEVENT: switch (events[i].window.event) { case SDL_WINDOWEVENT_ENTER: case SDL_WINDOWEVENT_LEAVE: _al_sdl_mouse_event(&events[i]); break; case SDL_WINDOWEVENT_FOCUS_GAINED: case SDL_WINDOWEVENT_FOCUS_LOST: _al_sdl_display_event(&events[i]); _al_sdl_keyboard_event(&events[i]); break; case SDL_WINDOWEVENT_CLOSE: case SDL_WINDOWEVENT_RESIZED: _al_sdl_display_event(&events[i]); break; } } } } #ifdef __EMSCRIPTEN__ double t = al_get_time(); double interval = t - s->timer_time; _al_timer_thread_handle_tick(interval); s->timer_time = t; #endif al_unlock_mutex(s->mutex); } static ALLEGRO_SYSTEM *sdl_initialize(int flags) { (void)flags; ALLEGRO_SYSTEM_SDL *s = al_calloc(1, sizeof *s); s->system.vt = vt; // TODO: map allegro flags to sdl flags. unsigned int sdl_flags = SDL_INIT_EVERYTHING; #ifdef __EMSCRIPTEN__ // SDL currently does not support haptic feedback for emscripten. sdl_flags &= ~SDL_INIT_HAPTIC; #endif if (SDL_Init(sdl_flags) < 0) { ALLEGRO_ERROR("SDL_Init failed: %s", SDL_GetError()); return NULL; } _al_vector_init(&s->system.displays, sizeof (ALLEGRO_DISPLAY_SDL *)); return &s->system; } static void sdl_heartbeat_init(void) { ALLEGRO_SYSTEM_SDL *s = (void *)al_get_system_driver(); /* This cannot be done in sdl_initialize because the threading system * requires a completed ALLEGRO_SYSTEM which only exists after the * function returns. This function on the other hand will get called * once the system was created. */ s->mutex = al_create_mutex(); #ifdef __EMSCRIPTEN__ s->timer_time = al_get_time(); #endif } static void sdl_shutdown_system(void) { ALLEGRO_SYSTEM_SDL *s = (void *)al_get_system_driver(); /* Close all open displays. */ while (_al_vector_size(&s->system.displays) > 0) { ALLEGRO_DISPLAY **dptr = _al_vector_ref(&s->system.displays, 0); ALLEGRO_DISPLAY *d = *dptr; al_destroy_display(d); } _al_vector_free(&s->system.displays); al_destroy_mutex(s->mutex); al_free(s); SDL_Quit(); } static ALLEGRO_PATH *sdl_get_path(int id) { ALLEGRO_PATH *p = NULL; char* dir; switch (id) { case ALLEGRO_TEMP_PATH: case ALLEGRO_USER_DOCUMENTS_PATH: case ALLEGRO_USER_DATA_PATH: case ALLEGRO_USER_SETTINGS_PATH: dir = SDL_GetPrefPath(al_get_org_name(), al_get_app_name()); p = al_create_path_for_directory(dir); if (id == ALLEGRO_TEMP_PATH) { al_append_path_component(p, "tmp"); } SDL_free(dir); break; case ALLEGRO_RESOURCES_PATH: case ALLEGRO_EXENAME_PATH: case ALLEGRO_USER_HOME_PATH: dir = SDL_GetBasePath(); p = al_create_path_for_directory(dir); if (id == ALLEGRO_EXENAME_PATH) { al_set_path_filename(p, al_get_app_name()); } SDL_free(dir); break; } return p; } static ALLEGRO_DISPLAY_INTERFACE *sdl_get_display_driver(void) { return _al_sdl_display_driver(); } static ALLEGRO_KEYBOARD_DRIVER *sdl_get_keyboard_driver(void) { return _al_sdl_keyboard_driver(); } static ALLEGRO_MOUSE_DRIVER *sdl_get_mouse_driver(void) { return _al_sdl_mouse_driver(); } static ALLEGRO_TOUCH_INPUT_DRIVER *sdl_get_touch_input_driver(void) { return _al_sdl_touch_input_driver(); } static ALLEGRO_JOYSTICK_DRIVER *sdl_get_joystick_driver(void) { return _al_sdl_joystick_driver(); } #define ADD(allegro, sdl) if (sdl_format == \ SDL_PIXELFORMAT_##sdl) return ALLEGRO_PIXEL_FORMAT_##allegro; int _al_sdl_get_allegro_pixel_format(int sdl_format) { ADD(ARGB_8888, ARGB8888) ADD(RGBA_8888, RGBA8888) ADD(ABGR_8888, ABGR8888) return 0; } #undef ADD #define ADD(allegro, sdl) if (allegro_format == \ ALLEGRO_PIXEL_FORMAT_##allegro) return SDL_PIXELFORMAT_##sdl; int _al_sdl_get_sdl_pixel_format(int allegro_format) { ADD(ANY, ABGR8888) ADD(ANY_NO_ALPHA, ABGR8888) ADD(ANY_WITH_ALPHA, ABGR8888) ADD(ANY_32_NO_ALPHA, ABGR8888) ADD(ANY_32_WITH_ALPHA, ABGR8888) ADD(ARGB_8888, ARGB8888) ADD(RGBA_8888, RGBA8888) ADD(ABGR_8888, ABGR8888) ADD(ABGR_8888_LE, ABGR8888) return 0; } #undef ADD static int sdl_get_num_video_adapters(void) { return SDL_GetNumVideoDisplays(); } static bool sdl_get_monitor_info(int adapter, ALLEGRO_MONITOR_INFO *info) { SDL_Rect rect; if (SDL_GetDisplayBounds(adapter, &rect) < 0) return false; info->x1 = rect.x; info->y1 = rect.y; info->x2 = rect.x + rect.w; info->y2 = rect.y + rect.h; return true; } static ALLEGRO_MOUSE_CURSOR* sdl_create_mouse_cursor(ALLEGRO_BITMAP *sprite, int xfocus, int yfocus) { SDL_Cursor *cursor; ALLEGRO_MOUSE_CURSOR_SDL *sdl_cursor; int w = al_get_bitmap_width(sprite); int h = al_get_bitmap_height(sprite); int data_size = w * h * 4; unsigned char* data = al_malloc(data_size * sizeof(data[0])); Uint32 rmask, gmask, bmask, amask; #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; #else // little endian, like x86 rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; #endif ALLEGRO_LOCKED_REGION *lock = al_lock_bitmap(sprite, ALLEGRO_PIXEL_FORMAT_ABGR_8888, ALLEGRO_LOCK_READONLY); if (lock) { int i = 0, y = 0; for (y = 0; y < h; y++) { int x = 0; for (x = 0; x < w; x++) { ALLEGRO_COLOR c = al_get_pixel(sprite, x, y); al_unmap_rgba(c, data+i, data+i+1, data+i+2, data+i+3); i += 4; } } al_unlock_bitmap(sprite); SDL_Surface *icon = SDL_CreateRGBSurfaceFrom(data, w, h, 4 * 8, w * 4, rmask, gmask, bmask, amask); cursor = SDL_CreateColorCursor(icon, xfocus, yfocus); SDL_FreeSurface(icon); } al_free(data); if (!cursor) { return NULL; } sdl_cursor = al_malloc(sizeof *sdl_cursor); if (!sdl_cursor) { SDL_FreeCursor(cursor); return NULL; } sdl_cursor->cursor = cursor; return (ALLEGRO_MOUSE_CURSOR *)sdl_cursor; } static void sdl_destroy_mouse_cursor(ALLEGRO_MOUSE_CURSOR *cursor) { ALLEGRO_MOUSE_CURSOR_SDL *sdl_cursor = (ALLEGRO_MOUSE_CURSOR_SDL *) cursor; ASSERT(sdl_cursor); SDL_FreeCursor(sdl_cursor->cursor); al_free(sdl_cursor); } static int sdl_get_monitor_dpi(int adapter) { float ddpi, hdpi, vdpi; if (SDL_GetDisplayDPI(adapter, &ddpi, &hdpi, &vdpi) < 0) return 72; // we can't indicate "unknown" so return something reasonable return hdpi; } static int sdl_get_num_display_modes(void) { int i = al_get_new_display_adapter(); if (i < 0) i = 0; return SDL_GetNumDisplayModes(i); } static ALLEGRO_DISPLAY_MODE *sdl_get_display_mode(int index, ALLEGRO_DISPLAY_MODE *mode) { SDL_DisplayMode sdl_mode; int i = al_get_new_display_adapter(); if (i < 0) i = 0; if (SDL_GetDisplayMode(i, index, &sdl_mode) < 0) return NULL; mode->width = sdl_mode.w; mode->height = sdl_mode.h; mode->format = _al_sdl_get_allegro_pixel_format(sdl_mode.format); mode->refresh_rate = sdl_mode.refresh_rate; return mode; } static bool sdl_inhibit_screensaver(bool inhibit) { if (inhibit) { SDL_DisableScreenSaver(); } else { SDL_EnableScreenSaver(); } return SDL_IsScreenSaverEnabled() != inhibit; } /* Internal function to get a reference to this driver. */ ALLEGRO_SYSTEM_INTERFACE *_al_sdl_system_driver(void) { if (vt) return vt; vt = al_calloc(1, sizeof *vt); vt->id = ALLEGRO_SYSTEM_ID_SDL; vt->initialize = sdl_initialize; vt->get_display_driver = sdl_get_display_driver; vt->get_keyboard_driver = sdl_get_keyboard_driver; vt->get_mouse_driver = sdl_get_mouse_driver; vt->get_touch_input_driver = sdl_get_touch_input_driver; vt->get_joystick_driver = sdl_get_joystick_driver; //vt->get_haptic_driver = sdl_get_haptic_driver; vt->get_num_display_modes = sdl_get_num_display_modes; vt->get_display_mode = sdl_get_display_mode; vt->shutdown_system = sdl_shutdown_system; vt->get_num_video_adapters = sdl_get_num_video_adapters; vt->get_monitor_info = sdl_get_monitor_info; vt->create_mouse_cursor = sdl_create_mouse_cursor; vt->get_monitor_dpi = sdl_get_monitor_dpi; vt->destroy_mouse_cursor = sdl_destroy_mouse_cursor; /*vt->get_cursor_position = sdl_get_cursor_position; vt->grab_mouse = sdl_grab_mouse; vt->ungrab_mouse = sdl_ungrab_mouse;*/ vt->get_path = sdl_get_path; vt->inhibit_screensaver = sdl_inhibit_screensaver; /*vt->thread_init = sdl_thread_init; vt->thread_exit = sdl_thread_exit; vt->open_library = sdl_open_library; vt->import_symbol = sdl_import_symbol; vt->close_library = sdl_close_library;*/ vt->heartbeat = sdl_heartbeat; vt->heartbeat_init = sdl_heartbeat_init; vt->get_time = _al_sdl_get_time; vt->rest = _al_sdl_rest; vt->init_timeout = _al_sdl_init_timeout; return vt; } void _al_register_system_interfaces(void) { ALLEGRO_SYSTEM_INTERFACE **add; add = _al_vector_alloc_back(&_al_system_interfaces); *add = _al_sdl_system_driver(); } allegro5-5.2.10.1/src/sdl/sdl_thread.c000066400000000000000000000055151473414355200173140ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * SDL thread support. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_thread.h" #include "allegro5/platform/allegro_internal_sdl.h" ALLEGRO_DEBUG_CHANNEL("thread") static int thread_trampoline(void* data) { _AL_THREAD *thread = data; (*thread->proc)(thread, thread->arg); return 0; } void _al_thread_create(_AL_THREAD *thread, void (*proc)(_AL_THREAD*, void*), void *arg) { ASSERT(thread); ASSERT(proc); thread->should_stop = false; thread->proc = proc; thread->arg = arg; thread->thread = SDL_CreateThread(thread_trampoline, "allegro", thread); } void _al_thread_create_with_stacksize(_AL_THREAD *thread, void (*proc)(_AL_THREAD*, void*), void *arg, size_t stacksize) { ASSERT(thread); ASSERT(proc); thread->should_stop = false; thread->proc = proc; thread->arg = arg; #if SDL_VERSION_ATLEAST(2,0,9) thread->thread = SDL_CreateThreadWithStackSize(thread_trampoline, "allegro", stacksize, thread); #else (void)stacksize; ALLEGRO_WARN("Creating a thread with a custom thread size is not supported " "on this version of SDL, it is too old.\n"); thread->thread = SDL_CreateThread(thread_trampoline, "allegro", thread); #endif } void _al_thread_set_should_stop(_AL_THREAD *thread) { ASSERT(thread); thread->should_stop = true; } void _al_thread_join(_AL_THREAD *thread) { ASSERT(thread); _al_thread_set_should_stop(thread); int r; SDL_WaitThread(thread->thread, &r); } void _al_thread_detach(_AL_THREAD *thread) { ASSERT(thread); SDL_DetachThread(thread->thread); } /* mutexes */ void _al_mutex_init(_AL_MUTEX *mutex) { ASSERT(mutex); mutex->mutex = SDL_CreateMutex(); } void _al_mutex_init_recursive(_AL_MUTEX *mutex) { _al_mutex_init(mutex); } void _al_mutex_destroy(_AL_MUTEX *mutex) { ASSERT(mutex); if (mutex->mutex) { SDL_DestroyMutex(mutex->mutex); mutex->mutex = NULL; } } /* condition variables */ /* most of the condition variable implementation is actually inline */ int _al_cond_timedwait(_AL_COND *cond, _AL_MUTEX *mutex, const ALLEGRO_TIMEOUT *timeout) { ALLEGRO_TIMEOUT_SDL *timeout_sdl = (void *)timeout; int r = SDL_CondWaitTimeout(cond->cond, mutex->mutex, timeout_sdl->ms); return (r == SDL_MUTEX_TIMEDOUT) ? -1 : 0; } allegro5-5.2.10.1/src/sdl/sdl_time.c000066400000000000000000000021221473414355200167720ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * SDL time driver. * * See LICENSE.txt for copyright information. */ #include "SDL.h" #include "allegro5/altime.h" #include "allegro5/platform/allegro_internal_sdl.h" #include "allegro5/debug.h" ALLEGRO_DEBUG_CHANNEL("SDL") double _al_sdl_get_time(void) { return 1.0 * SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency(); } void _al_sdl_rest(double seconds) { SDL_Delay(seconds * 1000); } void _al_sdl_init_timeout(ALLEGRO_TIMEOUT *timeout, double seconds) { ALLEGRO_TIMEOUT_SDL *timeout_sdl = (void *)timeout; timeout_sdl->ms = seconds * 1000; } /* vim: set sts=3 sw=3 et */ allegro5-5.2.10.1/src/sdl/sdl_touch.c000066400000000000000000000233701473414355200171660ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * SDL touch driver. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/platform/allegro_internal_sdl.h" ALLEGRO_DEBUG_CHANNEL("SDL") typedef struct ALLEGRO_TOUCH_INPUT_SDL { ALLEGRO_TOUCH_INPUT touch_input; ALLEGRO_TOUCH_INPUT_STATE state; ALLEGRO_DISPLAY *display; int touches; } ALLEGRO_TOUCH_INPUT_SDL; static ALLEGRO_TOUCH_INPUT_DRIVER *vt; static ALLEGRO_TOUCH_INPUT_SDL *touch_input; static ALLEGRO_MOUSE_STATE mouse_state; static void generate_touch_input_event(unsigned int type, double timestamp, int id, float x, float y, float dx, float dy, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_EVENT event; bool want_touch_event = _al_event_source_needs_to_generate_event(&touch_input->touch_input.es); bool want_mouse_emulation_event; if (touch_input->touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_5_0_x) { want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input->touch_input.mouse_emulation_es) && al_is_mouse_installed(); } else { want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input->touch_input.mouse_emulation_es) && primary && al_is_mouse_installed(); } if (touch_input->touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_NONE) want_mouse_emulation_event = false; else if (touch_input->touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_INCLUSIVE) want_touch_event = al_is_mouse_installed() ? (want_touch_event && !primary) : want_touch_event; else if (touch_input->touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_EXCLUSIVE) want_touch_event = al_is_mouse_installed() ? false : want_touch_event; if (!want_touch_event && !want_mouse_emulation_event) return; if (want_touch_event) { event.touch.type = type; event.touch.display = (ALLEGRO_DISPLAY*)disp; event.touch.timestamp = timestamp; event.touch.id = id; event.touch.x = x; event.touch.y = y; event.touch.dx = dx; event.touch.dy = dy; event.touch.primary = primary; _al_event_source_lock(&touch_input->touch_input.es); _al_event_source_emit_event(&touch_input->touch_input.es, &event); _al_event_source_unlock(&touch_input->touch_input.es); } if (touch_input->touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_NONE) { mouse_state.x = (int)x; mouse_state.y = (int)y; if (type == ALLEGRO_EVENT_TOUCH_BEGIN) mouse_state.buttons++; else if (type == ALLEGRO_EVENT_TOUCH_END) mouse_state.buttons--; mouse_state.pressure = mouse_state.buttons ? 1.0 : 0.0; /* TODO */ _al_event_source_lock(&touch_input->touch_input.mouse_emulation_es); if (want_mouse_emulation_event) { switch (type) { case ALLEGRO_EVENT_TOUCH_BEGIN: type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN; break; case ALLEGRO_EVENT_TOUCH_CANCEL: case ALLEGRO_EVENT_TOUCH_END: type = ALLEGRO_EVENT_MOUSE_BUTTON_UP; break; case ALLEGRO_EVENT_TOUCH_MOVE: type = ALLEGRO_EVENT_MOUSE_AXES; break; } event.mouse.type = type; event.mouse.timestamp = timestamp; event.mouse.display = (ALLEGRO_DISPLAY*)disp; event.mouse.x = (int)x; event.mouse.y = (int)y; event.mouse.dx = (int)dx; event.mouse.dy = (int)dy; event.mouse.dz = 0; event.mouse.dw = 0; if (touch_input->touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) { event.mouse.button = 1; } else { event.mouse.button = id; } event.mouse.pressure = mouse_state.pressure; if (touch_input->touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) { al_set_mouse_xy(event.mouse.display, event.mouse.x, event.mouse.y); } _al_event_source_emit_event(&touch_input->touch_input.mouse_emulation_es, &event); } _al_event_source_unlock(&touch_input->touch_input.mouse_emulation_es); } } static int find_free_touch_state_index(void) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; i++) if (touch_input->state.touches[i].id < 0) return i; return -1; } static int find_touch_state_index_with_id(int id) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; i++) if (touch_input->state.touches[i].id == id) return i; return -1; } void _al_sdl_touch_input_event(SDL_Event *e) { if (!touch_input) return; ALLEGRO_EVENT_TYPE type; ALLEGRO_DISPLAY *d = NULL; /* Use the first display as event source if we have any displays. */ ALLEGRO_SYSTEM *s = al_get_system_driver(); if (_al_vector_size(&s->displays) > 0) { void **v = (void **)_al_vector_ref(&s->displays, 0); d = *v; } if (!d) { return; } int touch_idx = find_touch_state_index_with_id(e->tfinger.fingerId); if (touch_idx < 0) touch_idx = find_free_touch_state_index(); if (touch_idx < 0) return; // SDL2 touch events also handle indirect touch devices that aren't directly related to the display. // Allegro doesn't really have an equivalent in its API, so filter them out. #if SDL_VERSION_ATLEAST(2,0,10) if (SDL_GetTouchDeviceType(e->tfinger.touchId) != SDL_TOUCH_DEVICE_DIRECT) return; #endif touch_input->state.touches[touch_idx].x = e->tfinger.x * al_get_display_width(d); touch_input->state.touches[touch_idx].y = e->tfinger.y * al_get_display_height(d); touch_input->state.touches[touch_idx].dx = e->tfinger.dx * al_get_display_width(d); touch_input->state.touches[touch_idx].dy = e->tfinger.dy * al_get_display_height(d); if (e->type == SDL_FINGERDOWN) { type = ALLEGRO_EVENT_TOUCH_BEGIN; touch_input->state.touches[touch_idx].id = e->tfinger.fingerId; touch_input->state.touches[touch_idx].primary = (touch_input->touches == 0); touch_input->touches++; } else if (e->type == SDL_FINGERMOTION) { type = ALLEGRO_EVENT_TOUCH_MOVE; } else if (e->type == SDL_FINGERUP) { type = ALLEGRO_EVENT_TOUCH_END; touch_input->touches--; touch_input->state.touches[touch_idx].id = -1; } else { return; } generate_touch_input_event(type, e->tfinger.timestamp / 1000.0, touch_idx, touch_input->state.touches[touch_idx].x, touch_input->state.touches[touch_idx].y, touch_input->state.touches[touch_idx].dx, touch_input->state.touches[touch_idx].dy, touch_input->state.touches[touch_idx].primary, d); } static bool sdl_init_touch_input(void) { touch_input = al_calloc(1, sizeof *touch_input); _al_event_source_init(&touch_input->touch_input.es); _al_event_source_init(&touch_input->touch_input.mouse_emulation_es); touch_input->touch_input.mouse_emulation_mode = ALLEGRO_MOUSE_EMULATION_TRANSPARENT; int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; i++) { touch_input->state.touches[i].id = -1; } return true; } static void sdl_exit_touch_input(void) { } static ALLEGRO_TOUCH_INPUT *sdl_get_touch_input(void) { return &touch_input->touch_input; } static void sdl_get_touch_input_state(ALLEGRO_TOUCH_INPUT_STATE *ret_state) { _al_event_source_lock(&touch_input->touch_input.es); *ret_state = touch_input->state; _al_event_source_unlock(&touch_input->touch_input.es); } static void touch_input_handle_cancel(int index, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_TOUCH_STATE* state = touch_input->state.touches + index; (void)primary; if (NULL == state) return; _al_event_source_lock(&touch_input->touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input->touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_CANCEL, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); _al_event_source_lock(&touch_input->touch_input.es); state->id = -1; _al_event_source_unlock(&touch_input->touch_input.es); } static void sdl_set_mouse_emulation_mode(int mode) { if (touch_input->touch_input.mouse_emulation_mode != mode) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) { ALLEGRO_TOUCH_STATE* touch = touch_input->state.touches + i; if (touch->id > 0) { touch_input_handle_cancel(i, al_get_time(), touch->x, touch->y, touch->primary, touch->display); } } touch_input->touch_input.mouse_emulation_mode = mode; } } ALLEGRO_TOUCH_INPUT_DRIVER *_al_sdl_touch_input_driver(void) { if (vt) return vt; vt = al_calloc(1, sizeof *vt); vt->init_touch_input = sdl_init_touch_input; vt->exit_touch_input = sdl_exit_touch_input; vt->get_touch_input = sdl_get_touch_input; vt->get_touch_input_state = sdl_get_touch_input_state; vt->set_mouse_emulation_mode = sdl_set_mouse_emulation_mode; return vt; } allegro5-5.2.10.1/src/shader.c000066400000000000000000000316211473414355200156640ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Shader API. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_shader.h" #include "allegro5/internal/aintern_system.h" #ifdef ALLEGRO_CFG_SHADER_GLSL #include "allegro5/allegro_opengl.h" #endif ALLEGRO_DEBUG_CHANNEL("shader") #include "shader_source.inc" static ALLEGRO_SHADER_PLATFORM resolve_platform(ALLEGRO_DISPLAY *display, ALLEGRO_SHADER_PLATFORM platform) { if (platform == ALLEGRO_SHADER_AUTO) { ASSERT(display); if (display->flags & ALLEGRO_OPENGL) { platform = ALLEGRO_SHADER_GLSL; } else { platform = ALLEGRO_SHADER_HLSL; } } if (platform == ALLEGRO_SHADER_AUTO_MINIMAL) { ASSERT(display); if (display->flags & ALLEGRO_OPENGL) { platform = ALLEGRO_SHADER_GLSL_MINIMAL; } else { platform = ALLEGRO_SHADER_HLSL_MINIMAL; } } return platform; } /* Function: al_create_shader */ ALLEGRO_SHADER *al_create_shader(ALLEGRO_SHADER_PLATFORM platform) { ALLEGRO_SHADER *shader = NULL; platform = resolve_platform(al_get_current_display(), platform); switch (platform) { #ifdef ALLEGRO_CFG_SHADER_GLSL case ALLEGRO_SHADER_GLSL: case ALLEGRO_SHADER_GLSL_MINIMAL: shader = _al_create_shader_glsl(platform); break; #endif #ifdef ALLEGRO_CFG_SHADER_HLSL case ALLEGRO_SHADER_HLSL: case ALLEGRO_SHADER_HLSL_MINIMAL: shader = _al_create_shader_hlsl(platform, 2); break; case ALLEGRO_SHADER_HLSL_SM_3_0: shader = _al_create_shader_hlsl(platform, 3); break; #endif case ALLEGRO_SHADER_AUTO: case ALLEGRO_SHADER_AUTO_MINIMAL: ASSERT(0); break; default: break; } if (shader) { ASSERT(shader->platform); ASSERT(shader->vt); shader->dtor_item = _al_register_destructor(_al_dtor_list, "shader", shader, (void (*)(void *))al_destroy_shader); } else { ALLEGRO_WARN("Failed to create shader\n"); } return shader; } /* Function: al_attach_shader_source */ bool al_attach_shader_source(ALLEGRO_SHADER *shader, ALLEGRO_SHADER_TYPE type, const char *source) { ASSERT(shader); return shader->vt->attach_shader_source(shader, type, source); } /* Function: al_attach_shader_source_file */ bool al_attach_shader_source_file(ALLEGRO_SHADER *shader, ALLEGRO_SHADER_TYPE type, const char *filename) { ALLEGRO_FILE *fp; ALLEGRO_USTR *str; bool ret; fp = al_fopen(filename, "r"); if (!fp) { ALLEGRO_WARN("Failed to open %s\n", filename); al_ustr_free(shader->log); shader->log = al_ustr_newf("Failed to open %s", filename); return false; } str = al_ustr_new(""); for (;;) { char buf[512]; size_t n; ALLEGRO_USTR_INFO info; n = al_fread(fp, buf, sizeof(buf)); if (n <= 0) break; al_ustr_append(str, al_ref_buffer(&info, buf, n)); } al_fclose(fp); ret = al_attach_shader_source(shader, type, al_cstr(str)); al_ustr_free(str); return ret; } /* Function: al_build_shader */ bool al_build_shader(ALLEGRO_SHADER *shader) { ASSERT(shader); return shader->vt->build_shader(shader); } /* Function: al_get_shader_log */ const char *al_get_shader_log(ALLEGRO_SHADER *shader) { ASSERT(shader); return (shader->log) ? al_cstr(shader->log) : ""; } /* Function: al_get_shader_platform */ ALLEGRO_SHADER_PLATFORM al_get_shader_platform(ALLEGRO_SHADER *shader) { ASSERT(shader); return shader->platform; } /* Function: al_use_shader */ bool al_use_shader(ALLEGRO_SHADER *shader) { ALLEGRO_BITMAP *bmp = al_get_target_bitmap(); ALLEGRO_DISPLAY *disp; if (!bmp) { ALLEGRO_WARN("No current target bitmap.\n"); return false; } if (al_get_bitmap_flags(bmp) & ALLEGRO_MEMORY_BITMAP) { ALLEGRO_WARN("Target bitmap is memory bitmap.\n"); return false; } disp = _al_get_bitmap_display(bmp); ASSERT(disp); if (shader) { if (shader->vt->use_shader(shader, disp, true)) { _al_set_bitmap_shader_field(bmp, shader); ALLEGRO_DEBUG("use_shader succeeded\n"); return true; } else { _al_set_bitmap_shader_field(bmp, NULL); ALLEGRO_ERROR("use_shader failed\n"); if (disp->default_shader) { disp->default_shader->vt->use_shader( disp->default_shader, disp, true); } return false; } } else { if (bmp->shader) { bmp->shader->vt->unuse_shader(bmp->shader, disp); _al_set_bitmap_shader_field(bmp, NULL); } if (disp->default_shader) { disp->default_shader->vt->use_shader( disp->default_shader, disp, true); } return true; } } /* Function: al_get_current_shader */ ALLEGRO_SHADER *al_get_current_shader() { ALLEGRO_BITMAP* bmp = al_get_target_bitmap(); if (bmp != NULL) { return bmp->shader; } else { return NULL; } } /* Function: al_destroy_shader */ void al_destroy_shader(ALLEGRO_SHADER *shader) { ALLEGRO_BITMAP *bmp; unsigned i; if (!shader) return; /* As a convenience, implicitly unuse the shader on the target bitmap * if currently used. */ bmp = al_get_target_bitmap(); if (bmp && _al_vector_contains(&shader->bitmaps, &bmp)) { ALLEGRO_DEBUG("implicitly unusing shader on target bitmap\n"); al_use_shader(NULL); } _al_unregister_destructor(_al_dtor_list, shader->dtor_item); al_ustr_free(shader->vertex_copy); shader->vertex_copy = NULL; al_ustr_free(shader->pixel_copy); shader->pixel_copy = NULL; al_ustr_free(shader->log); shader->log = NULL; /* Clear references to this shader from all bitmaps. */ for (i = 0; i < _al_vector_size(&shader->bitmaps); i++) { ALLEGRO_BITMAP **slot = _al_vector_ref(&shader->bitmaps, i); ALLEGRO_BITMAP *bitmap = *slot; ASSERT(bitmap->shader == shader); bitmap->shader = NULL; } _al_vector_free(&shader->bitmaps); shader->vt->destroy_shader(shader); } /* Function: al_set_shader_sampler */ bool al_set_shader_sampler(const char *name, ALLEGRO_BITMAP *bitmap, int unit) { ALLEGRO_BITMAP *bmp; ALLEGRO_SHADER *shader; if ((bmp = al_get_target_bitmap()) != NULL) { if ((shader = bmp->shader) != NULL) { return shader->vt->set_shader_sampler(shader, name, bitmap, unit); } else { return false; } } else { return false; } } /* Function: al_set_shader_matrix */ bool al_set_shader_matrix(const char *name, const ALLEGRO_TRANSFORM *matrix) { ALLEGRO_BITMAP *bmp; ALLEGRO_SHADER *shader; if ((bmp = al_get_target_bitmap()) != NULL) { if ((shader = bmp->shader) != NULL) { return shader->vt->set_shader_matrix(shader, name, matrix); } else { return false; } } else { return false; } } /* Function: al_set_shader_int */ bool al_set_shader_int(const char *name, int i) { ALLEGRO_BITMAP *bmp; ALLEGRO_SHADER *shader; if ((bmp = al_get_target_bitmap()) != NULL) { if ((shader = bmp->shader) != NULL) { return shader->vt->set_shader_int(shader, name, i); } else { return false; } } else { return false; } } /* Function: al_set_shader_float */ bool al_set_shader_float(const char *name, float f) { ALLEGRO_BITMAP *bmp; ALLEGRO_SHADER *shader; if ((bmp = al_get_target_bitmap()) != NULL) { if ((shader = bmp->shader) != NULL) { return shader->vt->set_shader_float(shader, name, f); } else { return false; } } else { return false; } } /* Function: al_set_shader_int_vector */ bool al_set_shader_int_vector(const char *name, int num_components, const int *i, int num_elems) { ALLEGRO_BITMAP *bmp; ALLEGRO_SHADER *shader; if ((bmp = al_get_target_bitmap()) != NULL) { if ((shader = bmp->shader) != NULL) { return shader->vt->set_shader_int_vector(shader, name, num_components, i, num_elems); } else { return false; } } else { return false; } } /* Function: al_set_shader_float_vector */ bool al_set_shader_float_vector(const char *name, int num_components, const float *f, int num_elems) { ALLEGRO_BITMAP *bmp; ALLEGRO_SHADER *shader; if ((bmp = al_get_target_bitmap()) != NULL) { if ((shader = bmp->shader) != NULL) { return shader->vt->set_shader_float_vector(shader, name, num_components, f, num_elems); } else { return false; } } else { return false; } } /* Function: al_set_shader_bool */ bool al_set_shader_bool(const char *name, bool b) { ALLEGRO_BITMAP *bmp; ALLEGRO_SHADER *shader; if ((bmp = al_get_target_bitmap()) != NULL) { if ((shader = bmp->shader) != NULL) { return shader->vt->set_shader_bool(shader, name, b); } else { return false; } } else { return false; } } /* Function: al_get_default_shader_source */ char const *al_get_default_shader_source(ALLEGRO_SHADER_PLATFORM platform, ALLEGRO_SHADER_TYPE type) { (void)type; switch (resolve_platform(al_get_current_display(), platform)) { case ALLEGRO_SHADER_GLSL: #ifdef ALLEGRO_CFG_SHADER_GLSL switch (type) { case ALLEGRO_VERTEX_SHADER: return default_glsl_vertex_source; case ALLEGRO_PIXEL_SHADER: return default_glsl_pixel_source; } #endif break; case ALLEGRO_SHADER_GLSL_MINIMAL: #ifdef ALLEGRO_CFG_SHADER_GLSL switch (type) { case ALLEGRO_VERTEX_SHADER: return default_glsl_vertex_source; case ALLEGRO_PIXEL_SHADER: return default_glsl_minimal_pixel_source; } #endif break; case ALLEGRO_SHADER_HLSL: case ALLEGRO_SHADER_HLSL_MINIMAL: case ALLEGRO_SHADER_HLSL_SM_3_0: #ifdef ALLEGRO_CFG_SHADER_HLSL switch (type) { case ALLEGRO_VERTEX_SHADER: return default_hlsl_vertex_source; case ALLEGRO_PIXEL_SHADER: return default_hlsl_pixel_source; } #endif break; case ALLEGRO_SHADER_AUTO: case ALLEGRO_SHADER_AUTO_MINIMAL: ASSERT(0); } return NULL; } void _al_set_bitmap_shader_field(ALLEGRO_BITMAP *bmp, ALLEGRO_SHADER *shader) { ASSERT(bmp); if (bmp->shader != shader) { if (bmp->shader) { _al_unregister_shader_bitmap(bmp->shader, bmp); } bmp->shader = shader; if (bmp->shader) { _al_register_shader_bitmap(bmp->shader, bmp); } } } void _al_register_shader_bitmap(ALLEGRO_SHADER *shader, ALLEGRO_BITMAP *bmp) { ALLEGRO_BITMAP **slot; ASSERT(shader); ASSERT(bmp); slot = _al_vector_alloc_back(&shader->bitmaps); *slot = bmp; } void _al_unregister_shader_bitmap(ALLEGRO_SHADER *shader, ALLEGRO_BITMAP *bmp) { bool deleted; ASSERT(shader); ASSERT(bmp); deleted = _al_vector_find_and_delete(&shader->bitmaps, &bmp); ASSERT(deleted); } ALLEGRO_SHADER *_al_create_default_shader(ALLEGRO_DISPLAY *display) { ALLEGRO_SHADER *shader; ALLEGRO_SHADER_PLATFORM platform = resolve_platform( display, display->extra_settings.settings[ALLEGRO_DEFAULT_SHADER_PLATFORM] ); _al_push_destructor_owner(); shader = al_create_shader(platform); _al_pop_destructor_owner(); if (!shader) { ALLEGRO_ERROR("Error creating default shader.\n"); return false; } if (!al_attach_shader_source(shader, ALLEGRO_VERTEX_SHADER, al_get_default_shader_source(platform, ALLEGRO_VERTEX_SHADER))) { ALLEGRO_ERROR("al_attach_shader_source for vertex shader failed: %s\n", al_get_shader_log(shader)); goto fail; } if (!al_attach_shader_source(shader, ALLEGRO_PIXEL_SHADER, al_get_default_shader_source(platform, ALLEGRO_PIXEL_SHADER))) { ALLEGRO_ERROR("al_attach_shader_source for pixel shader failed: %s\n", al_get_shader_log(shader)); goto fail; } if (!al_build_shader(shader)) { ALLEGRO_ERROR("al_build_shader failed: %s\n", al_get_shader_log(shader)); goto fail; } return shader; fail: al_destroy_shader(shader); return NULL; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/shader_source.inc000066400000000000000000000126741473414355200176020ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Default shader sources. * * See LICENSE.txt for copyright information. */ #ifdef ALLEGRO_CFG_SHADER_GLSL static const char *default_glsl_vertex_source = "attribute vec4 " ALLEGRO_SHADER_VAR_POS ";\n" "attribute vec4 " ALLEGRO_SHADER_VAR_COLOR ";\n" "attribute vec2 " ALLEGRO_SHADER_VAR_TEXCOORD ";\n" "uniform mat4 " ALLEGRO_SHADER_VAR_PROJVIEW_MATRIX ";\n" "uniform bool " ALLEGRO_SHADER_VAR_USE_TEX_MATRIX ";\n" "uniform mat4 " ALLEGRO_SHADER_VAR_TEX_MATRIX ";\n" "varying vec4 varying_color;\n" "varying vec2 varying_texcoord;\n" "void main()\n" "{\n" " varying_color = " ALLEGRO_SHADER_VAR_COLOR ";\n" " if (" ALLEGRO_SHADER_VAR_USE_TEX_MATRIX ") {\n" " vec4 uv = " ALLEGRO_SHADER_VAR_TEX_MATRIX " * vec4(" ALLEGRO_SHADER_VAR_TEXCOORD ", 0, 1);\n" " varying_texcoord = vec2(uv.x, uv.y);\n" " }\n" " else\n" " varying_texcoord = " ALLEGRO_SHADER_VAR_TEXCOORD";\n" " gl_Position = " ALLEGRO_SHADER_VAR_PROJVIEW_MATRIX " * " ALLEGRO_SHADER_VAR_POS ";\n" "}\n"; static const char *default_glsl_pixel_source = "#ifdef GL_ES\n" "precision lowp float;\n" "#endif\n" "uniform sampler2D " ALLEGRO_SHADER_VAR_TEX ";\n" "uniform bool " ALLEGRO_SHADER_VAR_USE_TEX ";\n" "uniform bool " ALLEGRO_SHADER_VAR_ALPHA_TEST ";\n" "uniform int " ALLEGRO_SHADER_VAR_ALPHA_FUNCTION ";\n" "uniform float " ALLEGRO_SHADER_VAR_ALPHA_TEST_VALUE ";\n" "varying vec4 varying_color;\n" "varying vec2 varying_texcoord;\n" "\n" "bool alpha_test_func(float x, int op, float compare);\n" "\n" "void main()\n" "{\n" " vec4 c;\n" " if (" ALLEGRO_SHADER_VAR_USE_TEX ")\n" " c = varying_color * texture2D(" ALLEGRO_SHADER_VAR_TEX ", varying_texcoord);\n" " else\n" " c = varying_color;\n" " if (!" ALLEGRO_SHADER_VAR_ALPHA_TEST " || alpha_test_func(c.a, " ALLEGRO_SHADER_VAR_ALPHA_FUNCTION ", " ALLEGRO_SHADER_VAR_ALPHA_TEST_VALUE "))\n" " gl_FragColor = c;\n" " else\n" " discard;\n" "}\n" "\n" "bool alpha_test_func(float x, int op, float compare)\n" "{\n" // Note: These must be aligned with the ALLEGRO_RENDER_FUNCTION enum values. " if (op == 0) return false;\n" // ALLEGRO_RENDER_NEVER " else if (op == 1) return true;\n" // ALLEGRO_RENDER_ALWAYS " else if (op == 2) return x < compare;\n" // ALLEGRO_RENDER_LESS " else if (op == 3) return x == compare;\n" // ALLEGRO_RENDER_EQUAL " else if (op == 4) return x <= compare;\n" // ALLEGRO_RENDER_LESS_EQUAL " else if (op == 5) return x > compare;\n" // ALLEGRO_RENDER_GREATER " else if (op == 6) return x != compare;\n" // ALLEGRO_RENDER_NOT_EQUAL " else if (op == 7) return x >= compare;\n" // ALLEGRO_RENDER_GREATER_EQUAL " return false;\n" "}\n"; static const char *default_glsl_minimal_pixel_source = "#ifdef GL_ES\n" "precision lowp float;\n" "#endif\n" "uniform sampler2D " ALLEGRO_SHADER_VAR_TEX ";\n" "uniform bool " ALLEGRO_SHADER_VAR_USE_TEX ";\n" "varying vec4 varying_color;\n" "varying vec2 varying_texcoord;\n" "\n" "void main()\n" "{\n" " vec4 c;\n" " if (" ALLEGRO_SHADER_VAR_USE_TEX ")\n" " c = varying_color * texture2D(" ALLEGRO_SHADER_VAR_TEX ", varying_texcoord);\n" " else\n" " c = varying_color;\n" " gl_FragColor = c;\n" "}\n"; #endif /* ALLEGRO_CFG_SHADER_GLSL */ #ifdef ALLEGRO_CFG_SHADER_HLSL static const char *default_hlsl_vertex_source = "struct VS_INPUT\n" "{\n" " float4 Position : POSITION0;\n" " float2 TexCoord : TEXCOORD0;\n" " float4 Color : TEXCOORD1;\n" "};\n" "struct VS_OUTPUT\n" "{\n" " float4 Position : POSITION0;\n" " float4 Color : COLOR0;\n" " float2 TexCoord : TEXCOORD0;\n" "};\n" "\n" "float4x4 " ALLEGRO_SHADER_VAR_PROJVIEW_MATRIX ";\n" "bool " ALLEGRO_SHADER_VAR_USE_TEX_MATRIX ";\n" "float4x4 " ALLEGRO_SHADER_VAR_TEX_MATRIX ";\n" "\n" "VS_OUTPUT vs_main(VS_INPUT Input)\n" "{\n" " VS_OUTPUT Output;\n" " Output.Color = Input.Color;\n" " if (" ALLEGRO_SHADER_VAR_USE_TEX_MATRIX ") {\n" " Output.TexCoord = mul(float4(Input.TexCoord, 1.0f, 0.0f), " ALLEGRO_SHADER_VAR_TEX_MATRIX ").xy;\n" " }\n" " else {\n" " Output.TexCoord = Input.TexCoord;\n" " }\n" " Output.Position = mul(Input.Position, " ALLEGRO_SHADER_VAR_PROJVIEW_MATRIX ");\n" " return Output;\n" "}\n"; static const char *default_hlsl_pixel_source = "bool " ALLEGRO_SHADER_VAR_USE_TEX ";\n" "texture " ALLEGRO_SHADER_VAR_TEX ";\n" "sampler2D s = sampler_state {\n" " texture = <" ALLEGRO_SHADER_VAR_TEX ">;\n" "};\n" "\n" "float4 ps_main(VS_OUTPUT Input) : COLOR0\n" "{\n" " if (" ALLEGRO_SHADER_VAR_USE_TEX ") {\n" " return Input.Color * tex2D(s, Input.TexCoord);\n" " }\n" " else {\n" " return Input.Color;\n" " }\n" "}\n"; #endif /* ALLEGRO_CFG_SHADER_HLSL */ /* vim: set ft=c sts=3 sw=3 et: */ allegro5-5.2.10.1/src/system.c000066400000000000000000000326131473414355200157440ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * New system driver. * * By Elias Pschernig. * * Modified by Trent Gamblin. */ /* Title: System routines */ #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #ifdef ALLEGRO_CFG_SHADER_GLSL #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern_opengl.h" #endif #include ALLEGRO_INTERNAL_HEADER #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_debug.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_pixels.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_thread.h" #include "allegro5/internal/aintern_timer.h" #include "allegro5/internal/aintern_tls.h" #include "allegro5/internal/aintern_vector.h" ALLEGRO_DEBUG_CHANNEL("system") static ALLEGRO_SYSTEM *active_sysdrv = NULL; static ALLEGRO_CONFIG *sys_config = NULL; _AL_VECTOR _al_system_interfaces; static _AL_VECTOR _user_system_interfaces = _AL_VECTOR_INITIALIZER(ALLEGRO_SYSTEM_INTERFACE *); _AL_DTOR_LIST *_al_dtor_list = NULL; static bool atexit_virgin = true; static char _al_app_name[256] = ""; static char _al_org_name[256] = ""; static ALLEGRO_SYSTEM *find_system(_AL_VECTOR *vector) { ALLEGRO_SYSTEM_INTERFACE **sptr; ALLEGRO_SYSTEM_INTERFACE *sys_interface; ALLEGRO_SYSTEM *system; unsigned int i; for (i = 0; i < vector->_size; i++) { sptr = _al_vector_ref(vector, i); sys_interface = *sptr; if ((system = sys_interface->initialize(0)) != NULL) return system; } return NULL; } static void shutdown_system_driver(void) { if (active_sysdrv) { if (active_sysdrv->user_exe_path) al_destroy_path(active_sysdrv->user_exe_path); if (active_sysdrv->vt && active_sysdrv->vt->shutdown_system) active_sysdrv->vt->shutdown_system(); active_sysdrv = NULL; while (!_al_vector_is_empty(&_al_system_interfaces)) _al_vector_delete_at(&_al_system_interfaces, _al_vector_size(&_al_system_interfaces)-1); _al_vector_free(&_al_system_interfaces); _al_vector_init(&_al_system_interfaces, sizeof(ALLEGRO_SYSTEM_INTERFACE *)); } al_destroy_config(sys_config); sys_config = NULL; } /* al_get_standard_path() does not work before the system driver is * initialised. Before that, we need to call the underlying functions * directly. */ static ALLEGRO_PATH *early_get_exename_path(void) { #if defined(ALLEGRO_WINDOWS) return _al_win_get_path(ALLEGRO_EXENAME_PATH); #elif defined(ALLEGRO_MACOSX) return _al_osx_get_path(ALLEGRO_EXENAME_PATH); #elif defined(ALLEGRO_IPHONE) return _al_iphone_get_path(ALLEGRO_EXENAME_PATH); #elif defined(ALLEGRO_UNIX) return _al_unix_get_path(ALLEGRO_EXENAME_PATH); #elif defined(ALLEGRO_ANDROID) return _al_android_get_path(ALLEGRO_EXENAME_PATH); #elif defined(ALLEGRO_SDL) char* p = SDL_GetBasePath(); ALLEGRO_PATH *path = al_create_path_for_directory(p); SDL_free(p); return path; #else #error early_get_exename_path not implemented #endif } static void read_allegro_cfg(void) { /* We assume that the stdio file interface is in effect. */ ALLEGRO_PATH *path; ALLEGRO_CONFIG *temp; if (!sys_config) sys_config = al_create_config(); #if defined(ALLEGRO_UNIX) && !defined(ALLEGRO_IPHONE) temp = al_load_config_file("/etc/allegro5rc"); if (temp) { al_merge_config_into(sys_config, temp); al_destroy_config(temp); } path = _al_unix_get_path(ALLEGRO_USER_HOME_PATH); if (path) { al_set_path_filename(path, "allegro5rc"); temp = al_load_config_file(al_path_cstr(path, '/')); if (temp) { al_merge_config_into(sys_config, temp); al_destroy_config(temp); } al_set_path_filename(path, ".allegro5rc"); temp = al_load_config_file(al_path_cstr(path, '/')); if (temp) { al_merge_config_into(sys_config, temp); al_destroy_config(temp); } al_destroy_path(path); } #endif path = early_get_exename_path(); if (path) { al_set_path_filename(path, "allegro5.cfg"); temp = al_load_config_file(al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP)); if (temp) { al_merge_config_into(sys_config, temp); al_destroy_config(temp); } al_destroy_path(path); } /* Reconfigure logging in case something changed. */ _al_configure_logging(); } /* * Can a binary with version a use a library with version b? * * Let a = xa.ya.za.* * Let b = xb.yb.zb.* * * When a has the unstable bit, a is compatible with b if xa.ya.za = xb.yb.zb. * Otherwise, a is compatible with b if xa.ya = xb.yb and zb >= za. * * Otherwise a and b are incompatible. */ static bool compatible_versions(int a, int b) { int a_unstable = a & _ALLEGRO_UNSTABLE_BIT_SET; int a_major = (a & 0x7f000000) >> 24; int a_sub = (a & 0x00ff0000) >> 16; int a_wip = (a & 0x0000ff00) >> 8; int b_major = (b & 0x7f000000) >> 24; int b_sub = (b & 0x00ff0000) >> 16; int b_wip = (b & 0x0000ff00) >> 8; if (a_major != b_major) { return false; } if (a_unstable && a_wip != b_wip) { return false; } if (a_sub != b_sub) { return false; } if (a_wip > b_wip) { return false; } return true; } /* Function: al_install_system */ bool al_install_system(int version, int (*atexit_ptr)(void (*)(void))) { ALLEGRO_SYSTEM bootstrap; ALLEGRO_SYSTEM *real_system; int library_version = al_get_allegro_version(); if (active_sysdrv) { return true; } /* Note: We cannot call logging functions yet. * TODO: Maybe we want to do the check after the "bootstrap" system * is available at least? */ if (!compatible_versions(version, library_version)) return false; _al_tls_init_once(); _al_reinitialize_tls_values(); _al_vector_init(&_al_system_interfaces, sizeof(ALLEGRO_SYSTEM_INTERFACE *)); /* Set up a bootstrap system so the calls expecting it don't freak out */ memset(&bootstrap, 0, sizeof(bootstrap)); active_sysdrv = &bootstrap; read_allegro_cfg(); #ifdef ALLEGRO_BCC32 /* This supresses exceptions on floating point divide by zero */ _control87(MCW_EM, MCW_EM); #endif /* Register builtin system drivers */ _al_register_system_interfaces(); /* Check for a user-defined system driver first */ real_system = find_system(&_user_system_interfaces); /* If a user-defined driver is not found, look for a builtin one */ if (real_system == NULL) { real_system = find_system(&_al_system_interfaces); } if (real_system == NULL) { active_sysdrv = NULL; return false; } active_sysdrv = real_system; active_sysdrv->mouse_wheel_precision = 1; const char *min_bitmap_size = al_get_config_value( al_get_system_config(), "graphics", "min_bitmap_size"); active_sysdrv->min_bitmap_size = min_bitmap_size ? atoi(min_bitmap_size) : 16; ALLEGRO_INFO("Allegro version: %s\n", ALLEGRO_VERSION_STR); if (strcmp(al_get_app_name(), "") == 0) { al_set_app_name(NULL); } _al_add_exit_func(shutdown_system_driver, "shutdown_system_driver"); _al_dtor_list = _al_init_destructors(); _al_init_events(); _al_init_iio_table(); _al_init_convert_bitmap_list(); _al_init_timers(); #ifdef ALLEGRO_CFG_SHADER_GLSL _al_glsl_init_shaders(); #endif if (active_sysdrv->vt->heartbeat_init) active_sysdrv->vt->heartbeat_init(); if (atexit_ptr && atexit_virgin) { #ifndef ALLEGRO_ANDROID atexit_ptr(al_uninstall_system); #endif atexit_virgin = false; } /* Clear errnos set while searching for config files. */ al_set_errno(0); active_sysdrv->installed = true; _al_srand(time(NULL)); return true; } /* Function: al_uninstall_system */ void al_uninstall_system(void) { /* Note: al_uninstall_system may get called multiple times without an * al_install_system in between. For example if the user manually * calls it at the end of the program it is called right again * because it's installed as an atexit function by al_init. */ _al_run_destructors(_al_dtor_list); _al_run_exit_funcs(); _al_shutdown_destructors(_al_dtor_list); _al_dtor_list = NULL; #ifdef ALLEGRO_CFG_SHADER_GLSL _al_glsl_shutdown_shaders(); #endif _al_shutdown_logging(); /* shutdown_system_driver is registered as an exit func so we don't need * to do any more here. */ ASSERT(active_sysdrv == NULL); } /* Function: al_is_system_installed */ bool al_is_system_installed(void) { return (active_sysdrv && active_sysdrv->installed) ? true : false; } /* Hidden function: al_get_system_driver * This was exported and documented in 5.0rc1 but probably shouldn't have been * as ALLEGRO_SYSTEM is not documented. */ ALLEGRO_SYSTEM *al_get_system_driver(void) { return active_sysdrv; } /* Function: al_get_system_id */ ALLEGRO_SYSTEM_ID al_get_system_id(void) { ASSERT(active_sysdrv); return active_sysdrv->vt->id; } /* Function: al_get_system_config */ ALLEGRO_CONFIG *al_get_system_config(void) { if (!sys_config) sys_config = al_create_config(); return sys_config; } /* Function: al_get_standard_path */ ALLEGRO_PATH *al_get_standard_path(int id) { ASSERT(active_sysdrv); ASSERT(active_sysdrv->vt); ASSERT(active_sysdrv->vt->get_path); if (id == ALLEGRO_EXENAME_PATH && active_sysdrv->user_exe_path) return al_clone_path(active_sysdrv->user_exe_path); if (id == ALLEGRO_RESOURCES_PATH && active_sysdrv->user_exe_path) { ALLEGRO_PATH *exe_dir = al_clone_path(active_sysdrv->user_exe_path); al_set_path_filename(exe_dir, NULL); return exe_dir; } if (active_sysdrv->vt->get_path) return active_sysdrv->vt->get_path(id); return NULL; } /* Function: al_set_exe_name */ void al_set_exe_name(char const *path) { ASSERT(active_sysdrv); if (active_sysdrv->user_exe_path) { al_destroy_path(active_sysdrv->user_exe_path); } active_sysdrv->user_exe_path = al_create_path(path); } /* Function: al_set_org_name */ void al_set_org_name(const char *org_name) { if (!org_name) org_name = ""; _al_sane_strncpy(_al_org_name, org_name, sizeof(_al_org_name)); } /* Function: al_set_app_name */ void al_set_app_name(const char *app_name) { if (app_name) { _al_sane_strncpy(_al_app_name, app_name, sizeof(_al_app_name)); } else { ALLEGRO_PATH *path; path = al_get_standard_path(ALLEGRO_EXENAME_PATH); _al_sane_strncpy(_al_app_name, al_get_path_filename(path), sizeof(_al_app_name)); al_destroy_path(path); } } /* Function: al_get_org_name */ const char *al_get_org_name(void) { return _al_org_name; } /* Function: al_get_app_name */ const char *al_get_app_name(void) { return _al_app_name; } /* Function: al_inhibit_screensaver */ bool al_inhibit_screensaver(bool inhibit) { ASSERT(active_sysdrv); if (active_sysdrv->vt->inhibit_screensaver) return active_sysdrv->vt->inhibit_screensaver(inhibit); else return false; } void *_al_open_library(const char *filename) { ASSERT(active_sysdrv); if (active_sysdrv->vt->open_library) return active_sysdrv->vt->open_library(filename); else return NULL; } void *_al_import_symbol(void *library, const char *symbol) { ASSERT(active_sysdrv); if (active_sysdrv->vt->import_symbol) return active_sysdrv->vt->import_symbol(library, symbol); else return NULL; } void _al_close_library(void *library) { ASSERT(active_sysdrv); if (active_sysdrv->vt->close_library) active_sysdrv->vt->close_library(library); } /* Function: al_get_time */ double al_get_time(void) { ASSERT(active_sysdrv); if (active_sysdrv->vt->get_time) return active_sysdrv->vt->get_time(); return 0.0; } /* Function: al_rest */ void al_rest(double seconds) { ASSERT(active_sysdrv); if (active_sysdrv->vt->rest) active_sysdrv->vt->rest(seconds); } /* Function: al_init_timeout */ void al_init_timeout(ALLEGRO_TIMEOUT *timeout, double seconds) { ASSERT(active_sysdrv); if (active_sysdrv->vt->init_timeout) active_sysdrv->vt->init_timeout(timeout, seconds); } static uint32_t get_joystick_compat_version(const char* key) { ALLEGRO_CONFIG *system_config = al_get_system_config(); const char* compat_version = al_get_config_value(system_config, "compatibility", key); if (!compat_version || strlen(compat_version) == 0) return al_get_allegro_version(); int version = 0; int sub_version = 0; int wip_version = 0; /* Ignore the release number, we don't expect that to make a difference */ sscanf(compat_version, "%2d.%2d.%2d", &version, &sub_version, &wip_version); return AL_ID(version, sub_version, wip_version, 0); } uint32_t _al_get_joystick_compat_version(void) { return get_joystick_compat_version("joystick_version"); } uint32_t _al_get_keyboard_compat_version(void) { return get_joystick_compat_version("keyboard_version"); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/threads.c000066400000000000000000000234261473414355200160540ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Public threads interface. * * By Peter Wang. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_thread.h" #include "allegro5/internal/aintern_system.h" typedef enum THREAD_STATE { THREAD_STATE_CREATED, /* -> starting or -> joining */ THREAD_STATE_STARTING, /* -> started */ THREAD_STATE_STARTED, /* -> joining */ THREAD_STATE_JOINING, /* -> joined */ THREAD_STATE_JOINED, /* -> destroyed */ THREAD_STATE_DESTROYED, THREAD_STATE_DETACHED } THREAD_STATE; struct ALLEGRO_THREAD { _AL_THREAD thread; _AL_MUTEX mutex; _AL_COND cond; THREAD_STATE thread_state; void *proc; void *arg; void *retval; }; struct ALLEGRO_MUTEX { _AL_MUTEX mutex; }; struct ALLEGRO_COND { _AL_COND cond; }; static void thread_func_trampoline(_AL_THREAD *inner, void *_outer) { ALLEGRO_THREAD *outer = (ALLEGRO_THREAD *) _outer; ALLEGRO_SYSTEM *system = al_get_system_driver(); (void)inner; if (system && system->vt && system->vt->thread_init) { system->vt->thread_init(outer); } /* Wait to start the actual user thread function. The thread could also be * destroyed before ever running the user function. */ _al_mutex_lock(&outer->mutex); while (outer->thread_state == THREAD_STATE_CREATED) { _al_cond_wait(&outer->cond, &outer->mutex); } _al_mutex_unlock(&outer->mutex); if (outer->thread_state == THREAD_STATE_STARTING) { outer->thread_state = THREAD_STATE_STARTED; outer->retval = ((void *(*)(ALLEGRO_THREAD *, void *))outer->proc)(outer, outer->arg); } if (system && system->vt && system->vt->thread_exit) { system->vt->thread_exit(outer); } } static void detached_thread_func_trampoline(_AL_THREAD *inner, void *_outer) { ALLEGRO_THREAD *outer = (ALLEGRO_THREAD *) _outer; (void)inner; ((void *(*)(void *))outer->proc)(outer->arg); al_free(outer); } static ALLEGRO_THREAD *create_thread(void) { ALLEGRO_THREAD *outer; outer = al_malloc(sizeof(*outer)); if (!outer) { return NULL; } _AL_MARK_MUTEX_UNINITED(outer->mutex); /* required */ outer->retval = NULL; return outer; } /* Function: al_create_thread */ ALLEGRO_THREAD *al_create_thread( void *(*proc)(ALLEGRO_THREAD *thread, void *arg), void *arg) { ALLEGRO_THREAD *outer = create_thread(); outer->thread_state = THREAD_STATE_CREATED; _al_mutex_init(&outer->mutex); _al_cond_init(&outer->cond); outer->arg = arg; outer->proc = proc; _al_thread_create(&outer->thread, thread_func_trampoline, outer); /* XXX _al_thread_create should return an error code */ return outer; } /* Function: al_create_thread_with_stacksize */ ALLEGRO_THREAD *al_create_thread_with_stacksize( void *(*proc)(ALLEGRO_THREAD *thread, void *arg), void *arg, size_t stacksize) { ALLEGRO_THREAD *outer = create_thread(); outer->thread_state = THREAD_STATE_CREATED; _al_mutex_init(&outer->mutex); _al_cond_init(&outer->cond); outer->arg = arg; outer->proc = proc; _al_thread_create_with_stacksize(&outer->thread, thread_func_trampoline, outer, stacksize); /* XXX _al_thread_create should return an error code */ return outer; } /* Function: al_run_detached_thread */ void al_run_detached_thread(void *(*proc)(void *arg), void *arg) { ALLEGRO_THREAD *outer = create_thread(); outer->thread_state = THREAD_STATE_DETACHED; outer->arg = arg; outer->proc = proc; _al_thread_create(&outer->thread, detached_thread_func_trampoline, outer); _al_thread_detach(&outer->thread); } /* Function: al_start_thread */ void al_start_thread(ALLEGRO_THREAD *thread) { ASSERT(thread); switch (thread->thread_state) { case THREAD_STATE_CREATED: _al_mutex_lock(&thread->mutex); thread->thread_state = THREAD_STATE_STARTING; _al_cond_broadcast(&thread->cond); _al_mutex_unlock(&thread->mutex); break; case THREAD_STATE_STARTING: break; case THREAD_STATE_STARTED: break; /* invalid cases */ case THREAD_STATE_JOINING: ASSERT(thread->thread_state != THREAD_STATE_JOINING); break; case THREAD_STATE_JOINED: ASSERT(thread->thread_state != THREAD_STATE_JOINED); break; case THREAD_STATE_DESTROYED: ASSERT(thread->thread_state != THREAD_STATE_DESTROYED); break; case THREAD_STATE_DETACHED: ASSERT(thread->thread_state != THREAD_STATE_DETACHED); break; } } /* Function: al_join_thread */ void al_join_thread(ALLEGRO_THREAD *thread, void **ret_value) { ASSERT(thread); /* If al_join_thread() is called soon after al_start_thread(), the thread * function may not yet have noticed the STARTING state and executed the * user's thread function. Hence we must wait until the thread enters the * STARTED state. */ while (thread->thread_state == THREAD_STATE_STARTING) { al_rest(0.001); } switch (thread->thread_state) { case THREAD_STATE_CREATED: /* fall through */ case THREAD_STATE_STARTED: _al_mutex_lock(&thread->mutex); thread->thread_state = THREAD_STATE_JOINING; _al_cond_broadcast(&thread->cond); _al_mutex_unlock(&thread->mutex); _al_cond_destroy(&thread->cond); _al_mutex_destroy(&thread->mutex); _al_thread_join(&thread->thread); thread->thread_state = THREAD_STATE_JOINED; break; case THREAD_STATE_STARTING: ASSERT(thread->thread_state != THREAD_STATE_STARTING); break; case THREAD_STATE_JOINING: ASSERT(thread->thread_state != THREAD_STATE_JOINING); break; case THREAD_STATE_JOINED: ASSERT(thread->thread_state != THREAD_STATE_JOINED); break; case THREAD_STATE_DESTROYED: ASSERT(thread->thread_state != THREAD_STATE_DESTROYED); break; case THREAD_STATE_DETACHED: ASSERT(thread->thread_state != THREAD_STATE_DETACHED); break; } if (ret_value) { *ret_value = thread->retval; } } /* Function: al_set_thread_should_stop */ void al_set_thread_should_stop(ALLEGRO_THREAD *thread) { ASSERT(thread); _al_thread_set_should_stop(&thread->thread); } /* Function: al_get_thread_should_stop */ bool al_get_thread_should_stop(ALLEGRO_THREAD *thread) { ASSERT(thread); return _al_get_thread_should_stop(&thread->thread); } /* Function: al_destroy_thread */ void al_destroy_thread(ALLEGRO_THREAD *thread) { if (!thread) { return; } /* Join if required. */ switch (thread->thread_state) { case THREAD_STATE_CREATED: /* fall through */ case THREAD_STATE_STARTING: /* fall through */ case THREAD_STATE_STARTED: al_join_thread(thread, NULL); break; case THREAD_STATE_JOINING: ASSERT(thread->thread_state != THREAD_STATE_JOINING); break; case THREAD_STATE_JOINED: break; case THREAD_STATE_DESTROYED: ASSERT(thread->thread_state != THREAD_STATE_DESTROYED); break; case THREAD_STATE_DETACHED: ASSERT(thread->thread_state != THREAD_STATE_DETACHED); break; } /* May help debugging. */ thread->thread_state = THREAD_STATE_DESTROYED; al_free(thread); } /* Function: al_create_mutex */ ALLEGRO_MUTEX *al_create_mutex(void) { ALLEGRO_MUTEX *mutex = al_malloc(sizeof(*mutex)); if (mutex) { _AL_MARK_MUTEX_UNINITED(mutex->mutex); _al_mutex_init(&mutex->mutex); } return mutex; } /* Function: al_create_mutex_recursive */ ALLEGRO_MUTEX *al_create_mutex_recursive(void) { ALLEGRO_MUTEX *mutex = al_malloc(sizeof(*mutex)); if (mutex) { _AL_MARK_MUTEX_UNINITED(mutex->mutex); _al_mutex_init_recursive(&mutex->mutex); } return mutex; } /* Function: al_lock_mutex */ void al_lock_mutex(ALLEGRO_MUTEX *mutex) { ASSERT(mutex); _al_mutex_lock(&mutex->mutex); } /* Function: al_unlock_mutex */ void al_unlock_mutex(ALLEGRO_MUTEX *mutex) { ASSERT(mutex); _al_mutex_unlock(&mutex->mutex); } /* Function: al_destroy_mutex */ void al_destroy_mutex(ALLEGRO_MUTEX *mutex) { if (mutex) { _al_mutex_destroy(&mutex->mutex); al_free(mutex); } } /* Function: al_create_cond */ ALLEGRO_COND *al_create_cond(void) { ALLEGRO_COND *cond = al_malloc(sizeof(*cond)); if (cond) { _al_cond_init(&cond->cond); } return cond; } /* Function: al_destroy_cond */ void al_destroy_cond(ALLEGRO_COND *cond) { if (cond) { _al_cond_destroy(&cond->cond); al_free(cond); } } /* Function: al_wait_cond */ void al_wait_cond(ALLEGRO_COND *cond, ALLEGRO_MUTEX *mutex) { ASSERT(cond); ASSERT(mutex); _al_cond_wait(&cond->cond, &mutex->mutex); } /* Function: al_wait_cond_until */ int al_wait_cond_until(ALLEGRO_COND *cond, ALLEGRO_MUTEX *mutex, const ALLEGRO_TIMEOUT *timeout) { ASSERT(cond); ASSERT(mutex); ASSERT(timeout); return _al_cond_timedwait(&cond->cond, &mutex->mutex, timeout); } /* Function: al_broadcast_cond */ void al_broadcast_cond(ALLEGRO_COND *cond) { ASSERT(cond); _al_cond_broadcast(&cond->cond); } /* Function: al_signal_cond */ void al_signal_cond(ALLEGRO_COND *cond) { ASSERT(cond); _al_cond_signal(&cond->cond); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/timernu.c000066400000000000000000000247351473414355200161110ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * New timer API. * * By Peter Wang. * * See readme.txt for copyright information. */ #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_dtor.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_timer.h" #ifndef ALLEGRO_MSVC #ifndef ALLEGRO_BCC32 #include #endif #endif /* forward declarations */ static void timer_handle_tick(ALLEGRO_TIMER *timer); struct ALLEGRO_TIMER { ALLEGRO_EVENT_SOURCE es; bool started; double speed_secs; int64_t count; double counter; /* counts down to zero=blastoff */ _AL_LIST_ITEM *dtor_item; }; /* * The timer thread that runs in the background to drive the timers. */ static ALLEGRO_MUTEX *timers_mutex; static _AL_VECTOR active_timers = _AL_VECTOR_INITIALIZER(ALLEGRO_TIMER *); static _AL_THREAD * volatile timer_thread = NULL; static ALLEGRO_COND *timer_cond = NULL; static bool destroy_thread = false; // Allegro's al_get_time measures "the time since Allegro started", and so does // not ignore time spent in a suspended state. Further, some implementations // currently use a calendar clock, which changes based on the system clock. // However, the timer control thread needs to ignore suspended time, so that it // always performs the correct number of timer ticks. // This has only been verified for MacOS, so for now fallback to old behavior // on other platforms. `_al_timer_thread_handle_tick` will bound the interval // to a reasonable value to prevent other platforms from behaving poorly when // the clock changes. // See https://github.com/liballeg/allegro5/issues/1510 // Note: perhaps this could move into a new public API: al_get_uptime #if defined(ALLEGRO_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 #define USE_UPTIME struct timespec _al_initial_uptime; #endif static void _init_get_uptime(void) { #ifdef USE_UPTIME clock_gettime(CLOCK_UPTIME_RAW, &_al_initial_uptime); #endif } static double _al_get_uptime(void) { #ifdef USE_UPTIME struct timespec now; double time; clock_gettime(CLOCK_UPTIME_RAW, &now); time = (double) (now.tv_sec - _al_initial_uptime.tv_sec) + (double) (now.tv_nsec - _al_initial_uptime.tv_nsec) * 1.0e-9; return time; #else return al_get_time(); #endif } /* timer_thread_proc: [timer thread] * The timer thread procedure itself. */ static void timer_thread_proc(_AL_THREAD *self, void *unused) { #if 0 /* Block all signals. */ /* This was needed for some reason in v4, but I can't remember why, * and it might not be relevant now. It has a tendency to create * zombie processes if the program is aborted abnormally, so I'm * taking it out for now. */ { sigset_t mask; sigfillset(&mask); pthread_sigmask(SIG_BLOCK, &mask, NULL); } #endif _init_get_uptime(); double old_time = _al_get_uptime(); double new_time; double interval = 0.032768; while (!_al_get_thread_should_stop(self)) { al_lock_mutex(timers_mutex); while (_al_vector_size(&active_timers) == 0 && !destroy_thread) { al_wait_cond(timer_cond, timers_mutex); old_time = _al_get_uptime() - interval; } al_unlock_mutex(timers_mutex); al_rest(interval); al_lock_mutex(timers_mutex); { /* Calculate actual time elapsed. */ new_time = _al_get_uptime(); interval = new_time - old_time; old_time = new_time; /* Handle a tick. */ interval = _al_timer_thread_handle_tick(interval); } al_unlock_mutex(timers_mutex); } (void)unused; } /* timer_thread_handle_tick: [timer thread] * Call handle_tick() method of every timer in active_timers, and * returns the duration that the timer thread should try to sleep * next time. */ double _al_timer_thread_handle_tick(double interval) { double new_delay = 0.032768; unsigned int i; /* Never allow negative time, or greater than 10 seconds delta. * This is to handle clock changes on platforms not using a monotonic, * suspense-free clock. */ interval = _ALLEGRO_CLAMP(0, interval, 10.0); for (i = 0; i < _al_vector_size(&active_timers); i++) { ALLEGRO_TIMER **slot = _al_vector_ref(&active_timers, i); ALLEGRO_TIMER *timer = *slot; timer->counter -= interval; while (timer->counter <= 0) { timer_handle_tick(timer); timer->counter += timer->speed_secs; } if ((timer->counter > 0) && (timer->counter < new_delay)) new_delay = timer->counter; } return new_delay; } static void shutdown_timers(void) { ASSERT(_al_vector_size(&active_timers) == 0); if (timer_thread != NULL) { al_lock_mutex(timers_mutex); _al_vector_free(&active_timers); destroy_thread = true; al_signal_cond(timer_cond); al_unlock_mutex(timers_mutex); _al_thread_join(timer_thread); } else { _al_vector_free(&active_timers); } al_free(timer_thread); timer_thread = NULL; al_destroy_mutex(timers_mutex); al_destroy_cond(timer_cond); } // logic common to al_start_timer and al_resume_timer // al_start_timer : passes reset_counter = true to start from the beginning // al_resume_timer: passes reset_counter = false to preserve the previous time static void enable_timer(ALLEGRO_TIMER *timer, bool reset_counter) { ASSERT(timer); { if (timer->started) return; al_lock_mutex(timers_mutex); { ALLEGRO_TIMER **slot; timer->started = true; if (reset_counter) timer->counter = timer->speed_secs; slot = _al_vector_alloc_back(&active_timers); *slot = timer; al_signal_cond(timer_cond); } al_unlock_mutex(timers_mutex); if (timer_thread == NULL) { destroy_thread = false; timer_thread = al_malloc(sizeof(_AL_THREAD)); _al_thread_create(timer_thread, timer_thread_proc, NULL); } } } void _al_init_timers(void) { timers_mutex = al_create_mutex(); timer_cond = al_create_cond(); _al_add_exit_func(shutdown_timers, "shutdown_timers"); } int _al_get_active_timers_count(void) { return _al_vector_size(&active_timers); } /* * Timer objects */ /* Function: al_create_timer */ ALLEGRO_TIMER *al_create_timer(double speed_secs) { ASSERT(speed_secs > 0); { ALLEGRO_TIMER *timer = al_malloc(sizeof *timer); ASSERT(timer); if (timer) { _al_event_source_init(&timer->es); timer->started = false; timer->count = 0; timer->speed_secs = speed_secs; timer->counter = 0; timer->dtor_item = _al_register_destructor(_al_dtor_list, "timer", timer, (void (*)(void *)) al_destroy_timer); } return timer; } } /* Function: al_destroy_timer */ void al_destroy_timer(ALLEGRO_TIMER *timer) { if (timer) { al_stop_timer(timer); _al_unregister_destructor(_al_dtor_list, timer->dtor_item); _al_event_source_free(&timer->es); al_free(timer); } } /* Function: al_start_timer */ void al_start_timer(ALLEGRO_TIMER *timer) { enable_timer(timer, true); // true to reset the counter } /* Function: al_resume_timer */ void al_resume_timer(ALLEGRO_TIMER *timer) { enable_timer(timer, false); // false to preserve the counter } /* Function: al_stop_timer */ void al_stop_timer(ALLEGRO_TIMER *timer) { ASSERT(timer); { if (!timer->started) return; al_lock_mutex(timers_mutex); { _al_vector_find_and_delete(&active_timers, &timer); timer->started = false; } al_unlock_mutex(timers_mutex); } } /* Function: al_get_timer_started */ bool al_get_timer_started(const ALLEGRO_TIMER *timer) { ASSERT(timer); return timer->started; } /* Function: al_get_timer_speed */ double al_get_timer_speed(const ALLEGRO_TIMER *timer) { ASSERT(timer); return timer->speed_secs; } /* Function: al_set_timer_speed */ void al_set_timer_speed(ALLEGRO_TIMER *timer, double new_speed_secs) { ASSERT(timer); ASSERT(new_speed_secs > 0); al_lock_mutex(timers_mutex); { if (timer->started) { timer->counter -= timer->speed_secs; timer->counter += new_speed_secs; } timer->speed_secs = new_speed_secs; } al_unlock_mutex(timers_mutex); } /* Function: al_get_timer_count */ int64_t al_get_timer_count(const ALLEGRO_TIMER *timer) { ASSERT(timer); return timer->count; } /* Function: al_set_timer_count */ void al_set_timer_count(ALLEGRO_TIMER *timer, int64_t new_count) { ASSERT(timer); al_lock_mutex(timers_mutex); { timer->count = new_count; } al_unlock_mutex(timers_mutex); } /* Function: al_add_timer_count */ void al_add_timer_count(ALLEGRO_TIMER *timer, int64_t diff) { ASSERT(timer); al_lock_mutex(timers_mutex); { timer->count += diff; } al_unlock_mutex(timers_mutex); } /* timer_handle_tick: [timer thread] * Handle a single tick. */ static void timer_handle_tick(ALLEGRO_TIMER *timer) { /* Lock out event source helper functions (e.g. the release hook * could be invoked simultaneously with this function). */ _al_event_source_lock(&timer->es); { /* Update the count. */ timer->count++; /* Generate an event, maybe. */ if (_al_event_source_needs_to_generate_event(&timer->es)) { ALLEGRO_EVENT event; event.timer.type = ALLEGRO_EVENT_TIMER; event.timer.timestamp = al_get_time(); event.timer.count = timer->count; event.timer.error = -timer->counter; _al_event_source_emit_event(&timer->es, &event); } } _al_event_source_unlock(&timer->es); } /* Function: al_get_timer_event_source */ ALLEGRO_EVENT_SOURCE *al_get_timer_event_source(ALLEGRO_TIMER *timer) { return &timer->es; } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/tls.c000066400000000000000000000542401473414355200152220ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Thread local storage. * * By Trent Gamblin. * */ /* FIXME: * * There are several ways to get thread local storage: * * 1. pthreads. * 2. __thread keyword in gcc. * 3. __declspec(thread) in MSVC. * 4. TLS API under Windows. * * Since pthreads is available from the system everywhere except in * Windows, this is the only case which is problematic. It appears * that except for old mingw versions (before gcc 4.2) we can simply * use __thread, and for MSVC we can always use __declspec(thread): * * However there also is a WANT_TLS configuration variable which is on * by default and forces use of the TLS API instead. At the same time, * the implementation using the TLS API in this file does not work * with static linking. Someone should either completely remove * WANT_TLS, or fix the static linking case... */ #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_file.h" #include "allegro5/internal/aintern_fshook.h" #include "allegro5/internal/aintern_shader.h" #include "allegro5/internal/aintern_tls.h" #ifdef ALLEGRO_ANDROID #include "allegro5/internal/aintern_android.h" #endif #if defined(ALLEGRO_MINGW32) && !defined(ALLEGRO_CFG_DLL_TLS) /* * MinGW < 4.2.1 doesn't have builtin thread local storage, so we * must use the Windows API. */ #if __GNUC__ < 4 #define ALLEGRO_CFG_DLL_TLS #elif __GNUC__ == 4 && __GNUC_MINOR__ < 2 #define ALLEGRO_CFG_DLL_TLS #elif __GNUC__ == 4 && __GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ < 1 #define ALLEGRO_CFG_DLL_TLS #endif #endif /* Thread local storage for various per-thread state. */ typedef struct thread_local_state { /* New display parameters */ int new_display_flags; int new_display_refresh_rate; int new_display_adapter; int new_window_x; int new_window_y; int new_bitmap_depth; int new_bitmap_samples; ALLEGRO_EXTRA_DISPLAY_SETTINGS new_display_settings; /* Current display */ ALLEGRO_DISPLAY *current_display; /* Target bitmap */ ALLEGRO_BITMAP *target_bitmap; /* Blender */ ALLEGRO_BLENDER current_blender; /* Bitmap parameters */ int new_bitmap_format; int new_bitmap_flags; int new_bitmap_wrap_u; int new_bitmap_wrap_v; /* Files */ const ALLEGRO_FILE_INTERFACE *new_file_interface; const ALLEGRO_FS_INTERFACE *fs_interface; /* Error code */ int allegro_errno; /* Title to use for a new window/display. * This is a static buffer for API reasons. */ char new_window_title[ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE + 1]; #ifdef ALLEGRO_ANDROID JNIEnv *jnienv; #endif /* Destructor ownership count */ int dtor_owner_count; } thread_local_state; typedef struct INTERNAL_STATE { thread_local_state tls; ALLEGRO_BLENDER stored_blender; ALLEGRO_TRANSFORM stored_transform; ALLEGRO_TRANSFORM stored_projection_transform; int flags; } INTERNAL_STATE; ALLEGRO_STATIC_ASSERT(tls, sizeof(ALLEGRO_STATE) > sizeof(INTERNAL_STATE)); static void initialize_blender(ALLEGRO_BLENDER *b) { b->blend_op = ALLEGRO_ADD; b->blend_source = ALLEGRO_ONE, b->blend_dest = ALLEGRO_INVERSE_ALPHA; b->blend_alpha_op = ALLEGRO_ADD; b->blend_alpha_source = ALLEGRO_ONE; b->blend_alpha_dest = ALLEGRO_INVERSE_ALPHA; b->blend_color = al_map_rgba_f(1.0f, 1.0f, 1.0f, 1.0f); } static void initialize_tls_values(thread_local_state *tls) { memset(tls, 0, sizeof *tls); tls->new_display_adapter = ALLEGRO_DEFAULT_DISPLAY_ADAPTER; tls->new_window_x = INT_MAX; tls->new_window_y = INT_MAX; initialize_blender(&tls->current_blender); tls->new_bitmap_flags = ALLEGRO_CONVERT_BITMAP; tls->new_bitmap_format = ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA; tls->new_bitmap_wrap_u = ALLEGRO_BITMAP_WRAP_DEFAULT; tls->new_bitmap_wrap_v = ALLEGRO_BITMAP_WRAP_DEFAULT; tls->new_file_interface = &_al_file_interface_stdio; tls->fs_interface = &_al_fs_interface_stdio; memset(tls->new_window_title, 0, ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE + 1); _al_fill_display_settings(&tls->new_display_settings); } // FIXME: The TLS implementation below only works for dynamic linking // right now - instead of using DllMain we should simply initialize // on first request. #ifdef ALLEGRO_STATICLINK #undef ALLEGRO_CFG_DLL_TLS #endif #if defined(ALLEGRO_CFG_DLL_TLS) #include "tls_dll.inc" #elif defined(ALLEGRO_MACOSX) || defined(ALLEGRO_IPHONE) || defined(ALLEGRO_ANDROID) || defined(ALLEGRO_RASPBERRYPI) #include "tls_pthread.inc" #else #include "tls_native.inc" #endif void _al_reinitialize_tls_values(void) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; initialize_tls_values(tls); } void _al_set_new_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS *settings) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; memmove(&tls->new_display_settings, settings, sizeof(ALLEGRO_EXTRA_DISPLAY_SETTINGS)); } ALLEGRO_EXTRA_DISPLAY_SETTINGS *_al_get_new_display_settings(void) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return 0; return &tls->new_display_settings; } /* Function: al_set_new_window_title */ void al_set_new_window_title(const char *title) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; _al_sane_strncpy(tls->new_window_title, title, sizeof(tls->new_window_title)); } /* Function: al_get_new_window_title */ const char *al_get_new_window_title(void) { thread_local_state *tls; /* Return app name in case of error or if not set before. */ if ((tls = tls_get()) == NULL) return al_get_app_name(); if (tls->new_window_title[0] == '\0') return al_get_app_name(); return (const char *)tls->new_window_title; } /* Function: al_set_new_display_flags */ void al_set_new_display_flags(int flags) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; tls->new_display_flags = flags; } /* Function: al_get_new_display_flags */ int al_get_new_display_flags(void) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return 0; return tls->new_display_flags; } /* Function: al_set_new_display_refresh_rate */ void al_set_new_display_refresh_rate(int refresh_rate) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; tls->new_display_refresh_rate = refresh_rate; } /* Function: al_get_new_display_refresh_rate */ int al_get_new_display_refresh_rate(void) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return 0; return tls->new_display_refresh_rate; } /* Function: al_set_new_display_adapter */ void al_set_new_display_adapter(int adapter) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; if (adapter < 0) { tls->new_display_adapter = ALLEGRO_DEFAULT_DISPLAY_ADAPTER; } tls->new_display_adapter = adapter; } /* Function: al_get_new_display_adapter */ int al_get_new_display_adapter(void) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return ALLEGRO_DEFAULT_DISPLAY_ADAPTER; return tls->new_display_adapter; } /* Function: al_set_new_window_position */ void al_set_new_window_position(int x, int y) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; tls->new_window_x = x; tls->new_window_y = y; } /* Function: al_get_new_window_position */ void al_get_new_window_position(int *x, int *y) { thread_local_state *tls; int new_window_x = INT_MAX; int new_window_y = INT_MAX; if ((tls = tls_get()) != NULL) { new_window_x = tls->new_window_x; new_window_y = tls->new_window_y; } if (x) *x = new_window_x; if (y) *y = new_window_y; } /* Make the given display current, without changing the target bitmap. * This is used internally to change the current display transiently. */ bool _al_set_current_display_only(ALLEGRO_DISPLAY *display) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return false; if (tls->current_display && tls->current_display->vt && tls->current_display->vt->unset_current_display) { tls->current_display->vt->unset_current_display(tls->current_display); tls->current_display = NULL; } if (display && display->vt && display->vt->set_current_display) { if (!display->vt->set_current_display(display)) return false; } tls->current_display = display; return true; } /* Function: al_get_current_display */ ALLEGRO_DISPLAY *al_get_current_display(void) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return NULL; return tls->current_display; } /* Function: al_set_target_bitmap */ void al_set_target_bitmap(ALLEGRO_BITMAP *bitmap) { thread_local_state *tls; ALLEGRO_DISPLAY *old_display; ALLEGRO_DISPLAY *new_display; ALLEGRO_SHADER *old_shader; ALLEGRO_SHADER *new_shader; bool same_shader; int bitmap_flags = bitmap ? al_get_bitmap_flags(bitmap) : 0; ASSERT(!al_is_bitmap_drawing_held()); if (bitmap) { if (bitmap->parent) { bitmap->parent->dirty = true; } else { bitmap->dirty = true; } } if ((tls = tls_get()) == NULL) return; old_display = tls->current_display; if (tls->target_bitmap) old_shader = tls->target_bitmap->shader; else old_shader = NULL; if (bitmap == NULL) { /* Explicitly releasing the current rendering context. */ new_display = NULL; new_shader = NULL; } else if (bitmap_flags & ALLEGRO_MEMORY_BITMAP) { /* Setting a memory bitmap doesn't change the rendering context. */ new_display = old_display; new_shader = NULL; } else { new_display = _al_get_bitmap_display(bitmap); new_shader = bitmap->shader; } same_shader = (old_shader == new_shader && old_display == new_display); /* Unset the old shader if necessary. */ if (old_shader && !same_shader) { old_shader->vt->unuse_shader(old_shader, old_display); } /* Change the rendering context if necessary. */ if (old_display != new_display) { if (old_display && old_display->vt && old_display->vt->unset_current_display) { old_display->vt->unset_current_display(old_display); } tls->current_display = new_display; if (new_display && new_display->vt && new_display->vt->set_current_display) { new_display->vt->set_current_display(new_display); } } /* Change the target bitmap itself. */ tls->target_bitmap = bitmap; if (bitmap && !(bitmap_flags & ALLEGRO_MEMORY_BITMAP) && new_display && new_display->vt && new_display->vt->set_target_bitmap) { new_display->vt->set_target_bitmap(new_display, bitmap); /* Set the new shader if necessary. This should done before the * update_transformation call, which will also update the shader's * al_projview_matrix variable. */ if (!same_shader || !new_shader) { al_use_shader(new_shader); } new_display->vt->update_transformation(new_display, bitmap); } } /* Function: al_set_target_backbuffer */ void al_set_target_backbuffer(ALLEGRO_DISPLAY *display) { al_set_target_bitmap(al_get_backbuffer(display)); } /* Function: al_get_target_bitmap */ ALLEGRO_BITMAP *al_get_target_bitmap(void) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return 0; return tls->target_bitmap; } /* Function: al_set_blender */ void al_set_blender(int op, int src, int dst) { al_set_separate_blender(op, src, dst, op, src, dst); } /* Function: al_set_blend_color */ void al_set_blend_color(ALLEGRO_COLOR color) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; tls->current_blender.blend_color = color; } /* Function: al_set_separate_blender */ void al_set_separate_blender(int op, int src, int dst, int alpha_op, int alpha_src, int alpha_dst) { thread_local_state *tls; ALLEGRO_BLENDER *b; ASSERT(op >= 0 && op < ALLEGRO_NUM_BLEND_OPERATIONS); ASSERT(src >= 0 && src < ALLEGRO_NUM_BLEND_MODES); ASSERT(dst >= 0 && src < ALLEGRO_NUM_BLEND_MODES); ASSERT(alpha_op >= 0 && alpha_op < ALLEGRO_NUM_BLEND_OPERATIONS); ASSERT(alpha_src >= 0 && alpha_src < ALLEGRO_NUM_BLEND_MODES); ASSERT(alpha_dst >= 0 && alpha_dst < ALLEGRO_NUM_BLEND_MODES); if ((tls = tls_get()) == NULL) return; b = &tls->current_blender; b->blend_op = op; b->blend_source = src; b->blend_dest = dst; b->blend_alpha_op = alpha_op; b->blend_alpha_source = alpha_src; b->blend_alpha_dest = alpha_dst; } /* Function: al_get_blender */ void al_get_blender(int *op, int *src, int *dst) { al_get_separate_blender(op, src, dst, NULL, NULL, NULL); } /* Function: al_get_blend_color */ ALLEGRO_COLOR al_get_blend_color(void) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return al_map_rgba(255, 255, 255, 255); return tls->current_blender.blend_color; } /* Function: al_get_separate_blender */ void al_get_separate_blender(int *op, int *src, int *dst, int *alpha_op, int *alpha_src, int *alpha_dst) { thread_local_state *tls; ALLEGRO_BLENDER *b; if ((tls = tls_get()) == NULL) return; b = &tls->current_blender; if (op) *op = b->blend_op; if (src) *src = b->blend_source; if (dst) *dst = b->blend_dest; if (alpha_op) *alpha_op = b->blend_alpha_op; if (alpha_src) *alpha_src = b->blend_alpha_source; if (alpha_dst) *alpha_dst = b->blend_alpha_dest; } /* Function: al_set_new_bitmap_format */ void al_set_new_bitmap_format(int format) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; tls->new_bitmap_format = format; } /* Function: al_set_new_bitmap_flags */ void al_set_new_bitmap_flags(int flags) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; tls->new_bitmap_flags = flags; } /* Function: al_add_new_bitmap_flag */ void al_add_new_bitmap_flag(int flag) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; tls->new_bitmap_flags |= flag; } /* Function: al_get_new_bitmap_format */ int al_get_new_bitmap_format(void) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return 0; return tls->new_bitmap_format; } /* Function: al_get_new_bitmap_flags */ int al_get_new_bitmap_flags(void) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return 0; return tls->new_bitmap_flags; } /* Function: al_store_state */ void al_store_state(ALLEGRO_STATE *state, int flags) { thread_local_state *tls; INTERNAL_STATE *stored; if ((tls = tls_get()) == NULL) return; stored = (void *)state; stored->flags = flags; #define _STORE(x) (stored->tls.x = tls->x) if (flags & ALLEGRO_STATE_NEW_DISPLAY_PARAMETERS) { _STORE(new_display_flags); _STORE(new_display_refresh_rate); _STORE(new_display_adapter); _STORE(new_window_x); _STORE(new_window_y); _STORE(new_display_settings); _al_sane_strncpy(stored->tls.new_window_title, tls->new_window_title, sizeof(stored->tls.new_window_title)); } if (flags & ALLEGRO_STATE_NEW_BITMAP_PARAMETERS) { _STORE(new_bitmap_format); _STORE(new_bitmap_flags); _STORE(new_bitmap_wrap_u); _STORE(new_bitmap_wrap_v); } if (flags & ALLEGRO_STATE_DISPLAY) { _STORE(current_display); } if (flags & ALLEGRO_STATE_TARGET_BITMAP) { _STORE(target_bitmap); } if (flags & ALLEGRO_STATE_BLENDER) { stored->stored_blender = tls->current_blender; } if (flags & ALLEGRO_STATE_NEW_FILE_INTERFACE) { _STORE(new_file_interface); _STORE(fs_interface); } if (flags & ALLEGRO_STATE_TRANSFORM) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); if (!target) al_identity_transform(&stored->stored_transform); else stored->stored_transform = target->transform; } if (flags & ALLEGRO_STATE_PROJECTION_TRANSFORM) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); if (target) { stored->stored_projection_transform = target->proj_transform; } } #undef _STORE } /* Function: al_restore_state */ void al_restore_state(ALLEGRO_STATE const *state) { thread_local_state *tls; INTERNAL_STATE *stored; int flags; if ((tls = tls_get()) == NULL) return; stored = (void *)state; flags = stored->flags; #define _RESTORE(x) (tls->x = stored->tls.x) if (flags & ALLEGRO_STATE_NEW_DISPLAY_PARAMETERS) { _RESTORE(new_display_flags); _RESTORE(new_display_refresh_rate); _RESTORE(new_display_adapter); _RESTORE(new_window_x); _RESTORE(new_window_y); _RESTORE(new_display_settings); _al_sane_strncpy(tls->new_window_title, stored->tls.new_window_title, sizeof(tls->new_window_title)); } if (flags & ALLEGRO_STATE_NEW_BITMAP_PARAMETERS) { _RESTORE(new_bitmap_format); _RESTORE(new_bitmap_flags); _RESTORE(new_bitmap_wrap_u); _RESTORE(new_bitmap_wrap_v); } if (flags & ALLEGRO_STATE_DISPLAY) { if (tls->current_display != stored->tls.current_display) { _al_set_current_display_only(stored->tls.current_display); ASSERT(tls->current_display == stored->tls.current_display); } } if (flags & ALLEGRO_STATE_TARGET_BITMAP) { if (tls->target_bitmap != stored->tls.target_bitmap) { al_set_target_bitmap(stored->tls.target_bitmap); ASSERT(tls->target_bitmap == stored->tls.target_bitmap); } } if (flags & ALLEGRO_STATE_BLENDER) { tls->current_blender = stored->stored_blender; } if (flags & ALLEGRO_STATE_NEW_FILE_INTERFACE) { _RESTORE(new_file_interface); _RESTORE(fs_interface); } if (flags & ALLEGRO_STATE_TRANSFORM) { ALLEGRO_BITMAP *bitmap = al_get_target_bitmap(); if (bitmap) al_use_transform(&stored->stored_transform); } if (flags & ALLEGRO_STATE_PROJECTION_TRANSFORM) { ALLEGRO_BITMAP *bitmap = al_get_target_bitmap(); if (bitmap) al_use_projection_transform(&stored->stored_projection_transform); } #undef _RESTORE } /* Function: al_get_new_file_interface * FIXME: added a work-around for the situation where TLS has not yet been * initialised when this function is called. This may happen if Allegro * tries to load a configuration file before the system has been * initialised. Should probably rethink the logic here... */ const ALLEGRO_FILE_INTERFACE *al_get_new_file_interface(void) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return &_al_file_interface_stdio; /* FIXME: this situation should never arise because tls_ has the stdio * interface set as a default, but it arises on OS X if * pthread_getspecific() is called before pthreads_thread_init()... */ if (tls->new_file_interface) return tls->new_file_interface; else return &_al_file_interface_stdio; } /* Function: al_set_new_file_interface */ void al_set_new_file_interface(const ALLEGRO_FILE_INTERFACE *file_interface) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; tls->new_file_interface = file_interface; } /* Function: al_get_fs_interface */ const ALLEGRO_FS_INTERFACE *al_get_fs_interface(void) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return &_al_fs_interface_stdio; if (tls->fs_interface) return tls->fs_interface; else return &_al_fs_interface_stdio; } /* Function: al_set_fs_interface */ void al_set_fs_interface(const ALLEGRO_FS_INTERFACE *fs_interface) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; tls->fs_interface = fs_interface; } /* Function: al_set_standard_fs_interface */ void al_set_standard_fs_interface(void) { al_set_fs_interface(&_al_fs_interface_stdio); } #define SETTER(name, value) \ { \ thread_local_state *tls; \ if ((tls = tls_get()) == NULL) \ return; \ tls->name = value; \ } #define GETTER(name, value) \ { \ thread_local_state *tls; \ if ((tls = tls_get()) == NULL) \ return value; \ return tls->name; \ } /* Function: al_get_errno */ int al_get_errno(void) GETTER(allegro_errno, 0) /* Function: al_set_errno */ void al_set_errno(int errnum) SETTER(allegro_errno, errnum) /* Function: al_get_new_bitmap_depth */ int al_get_new_bitmap_depth(void) GETTER(new_bitmap_depth, 0) /* Function: al_set_new_bitmap_depth */ void al_set_new_bitmap_depth(int depth) SETTER(new_bitmap_depth, depth) /* Function: al_get_new_bitmap_samples */ int al_get_new_bitmap_samples(void) GETTER(new_bitmap_samples, 0) /* Function: al_set_new_bitmap_samples */ void al_set_new_bitmap_samples(int samples) SETTER(new_bitmap_samples, samples) /* Function: al_get_bitmap_wrap */ void al_get_new_bitmap_wrap(ALLEGRO_BITMAP_WRAP *u, ALLEGRO_BITMAP_WRAP *v) { ASSERT(u); ASSERT(v); thread_local_state *tls; if ((tls = tls_get()) == NULL) return; *u = tls->new_bitmap_wrap_u; *v = tls->new_bitmap_wrap_v; } /* Function: al_set_new_bitmap_wrap */ void al_set_new_bitmap_wrap(ALLEGRO_BITMAP_WRAP u, ALLEGRO_BITMAP_WRAP v) { thread_local_state *tls; if ((tls = tls_get()) == NULL) return; tls->new_bitmap_wrap_u = u; tls->new_bitmap_wrap_v = v; } #ifdef ALLEGRO_ANDROID JNIEnv *_al_android_get_jnienv(void) GETTER(jnienv, 0) void _al_android_set_jnienv(JNIEnv *jnienv) SETTER(jnienv, jnienv) #endif int *_al_tls_get_dtor_owner_count(void) { thread_local_state *tls; tls = tls_get(); return &tls->dtor_owner_count; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/tls_dll.inc000066400000000000000000000040131473414355200163750ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Thread local storage. * * See LICENSE.txt for copyright information. */ #include /* Forward declaration to bypass strict warning. */ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); static DWORD tls_index; void _al_tls_init_once(void) { /* nothing */ } static thread_local_state *tls_get(void) { thread_local_state *t = TlsGetValue(tls_index); if (t == NULL) { t = al_malloc(sizeof(*t)); TlsSetValue(tls_index, t); initialize_tls_values(t); } return t; } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { thread_local_state *data; (void)hinstDLL; (void)fdwReason; (void)lpvReserved; switch (fdwReason) { case DLL_PROCESS_ATTACH: if ((tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) { return false; } break; // The thread of the attached process terminates. case DLL_THREAD_DETACH: // Release the allocated memory for this thread. data = TlsGetValue(tls_index); if (data != NULL) al_free(data); break; // DLL unload due to process termination or FreeLibrary. case DLL_PROCESS_DETACH: // Release the allocated memory for this thread. data = TlsGetValue(tls_index); if (data != NULL) al_free(data); // Release the TLS index. TlsFree(tls_index); break; default: break; } return true; } /* vim: set ft=c sts=3 sw=3: */ allegro5-5.2.10.1/src/tls_native.inc000066400000000000000000000020711473414355200171120ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Thread local storage. * * See LICENSE.txt for copyright information. */ #if defined(ALLEGRO_MSVC) || defined(ALLEGRO_BCC32) #define THREAD_LOCAL_QUALIFIER __declspec(thread) #else #define THREAD_LOCAL_QUALIFIER __thread #endif static THREAD_LOCAL_QUALIFIER thread_local_state _tls; void _al_tls_init_once(void) { /* nothing */ } static thread_local_state *tls_get(void) { static THREAD_LOCAL_QUALIFIER thread_local_state *ptr = NULL; if (!ptr) { ptr = &_tls; initialize_tls_values(ptr); } return ptr; } /* vim: set ft=c sts=3 sw=3 et: */ allegro5-5.2.10.1/src/tls_pthread.inc000066400000000000000000000026441473414355200172610ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Thread local storage. * * See LICENSE.txt for copyright information. */ static pthread_key_t tls_key = 0; static thread_local_state _tls; static void tls_dtor(void *ptr) { al_free(ptr); } void _al_tls_init_once(void) { pthread_key_create(&tls_key, tls_dtor); } static thread_local_state *pthreads_thread_init(void) { /* Allocate and copy the 'template' object */ thread_local_state *ptr = (thread_local_state *)al_malloc(sizeof(thread_local_state)); memcpy(ptr, &_tls, sizeof(thread_local_state)); pthread_setspecific(tls_key, ptr); return ptr; } /* This function is short so it can hopefully be inlined. */ static thread_local_state *tls_get(void) { thread_local_state *ptr = (thread_local_state*)pthread_getspecific(tls_key); if (ptr == NULL) { /* Must create object. */ ptr = pthreads_thread_init(); initialize_tls_values(ptr); } return ptr; } /* vim: set ft=c sts=3 sw=3: */ allegro5-5.2.10.1/src/touch_input.c000066400000000000000000000065651473414355200167700ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Touch input API. * * By Michał Cichoń. * * See readme.txt for copyright information. */ #define ALLEGRO_NO_COMPATIBILITY #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_exitfunc.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_touch_input.h" /* the active driver */ static ALLEGRO_TOUCH_INPUT_DRIVER *touch_input_driver = NULL; /* Function: al_is_touch_input_installed */ bool al_is_touch_input_installed(void) { return (touch_input_driver ? true : false); } /* Function: al_install_touch_input */ bool al_install_touch_input(void) { if (touch_input_driver) return true; if (al_get_system_driver()->vt->get_touch_input_driver) { touch_input_driver = al_get_system_driver()->vt->get_touch_input_driver(); if (touch_input_driver) { if (!touch_input_driver->init_touch_input()) { touch_input_driver = NULL; return false; } _al_add_exit_func(al_uninstall_touch_input, "al_uninstall_touch_input"); return true; } } return false; } /* Function: al_uninstall_touch_input */ void al_uninstall_touch_input(void) { if (!touch_input_driver) return; touch_input_driver->exit_touch_input(); touch_input_driver = NULL; } static ALLEGRO_TOUCH_INPUT *get_touch_input(void) { ALLEGRO_TOUCH_INPUT *touch_input; ASSERT(touch_input_driver); touch_input = touch_input_driver->get_touch_input(); ASSERT(touch_input); return touch_input; } /* Function: al_get_touch_input_state */ void al_get_touch_input_state(ALLEGRO_TOUCH_INPUT_STATE *ret_state) { ASSERT(touch_input_driver); ASSERT(ret_state); touch_input_driver->get_touch_input_state(ret_state); } /* Function: al_set_mouse_emulation_mode */ void al_set_mouse_emulation_mode(int mode) { ASSERT(touch_input_driver); if (touch_input_driver->set_mouse_emulation_mode) touch_input_driver->set_mouse_emulation_mode(mode); else get_touch_input()->mouse_emulation_mode = mode; } /* Function: al_get_mouse_emulation_mode */ int al_get_mouse_emulation_mode(void) { ASSERT(touch_input_driver); if (touch_input_driver->get_mouse_emulation_mode) return touch_input_driver->get_mouse_emulation_mode(); else return get_touch_input()->mouse_emulation_mode; } /* Function: al_get_touch_input_event_source */ ALLEGRO_EVENT_SOURCE *al_get_touch_input_event_source(void) { ALLEGRO_TOUCH_INPUT *touch_input = get_touch_input(); return (touch_input) ? &touch_input->es : NULL; } /* Function: al_get_touch_input_mouse_emulation_event_source */ ALLEGRO_EVENT_SOURCE *al_get_touch_input_mouse_emulation_event_source(void) { ALLEGRO_TOUCH_INPUT *touch_input = get_touch_input(); return (touch_input) ? &touch_input->mouse_emulation_es : NULL; } allegro5-5.2.10.1/src/transformations.c000066400000000000000000000367071473414355200176610ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Transformations. * * By Pavel Sountsov. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_transform.h" #include /* ALLEGRO_DEBUG_CHANNEL("transformations") */ /* Function: al_copy_transform */ void al_copy_transform(ALLEGRO_TRANSFORM *dest, const ALLEGRO_TRANSFORM *src) { ASSERT(src); ASSERT(dest); memcpy(dest, src, sizeof(ALLEGRO_TRANSFORM)); } /* Function: al_use_transform */ void al_use_transform(const ALLEGRO_TRANSFORM *trans) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); ALLEGRO_DISPLAY *display; if (!target) return; /* Changes to a back buffer should affect the front buffer, and vice versa. * Currently we rely on the fact that in the OpenGL drivers the back buffer * and front buffer bitmaps are exactly the same, and the DirectX driver * doesn't support front buffer bitmaps. */ if (trans != &target->transform) { al_copy_transform(&target->transform, trans); target->inverse_transform_dirty = true; } /* * When the drawing is held, we apply the transformations in software, * so the hardware transformation has to be kept at identity. */ if (!al_is_bitmap_drawing_held()) { display = _al_get_bitmap_display(target); if (display) { display->vt->update_transformation(display, target); } } } /* Function: al_use_projection_transform */ void al_use_projection_transform(const ALLEGRO_TRANSFORM *trans) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); ALLEGRO_DISPLAY *display; if (!target) return; /* Memory bitmaps don't support custom projection transforms */ if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP) return; /* Changes to a back buffer should affect the front buffer, and vice versa. * Currently we rely on the fact that in the OpenGL drivers the back buffer * and front buffer bitmaps are exactly the same, and the DirectX driver * doesn't support front buffer bitmaps. */ if (trans != &target->transform) { al_copy_transform(&target->proj_transform, trans); } display = _al_get_bitmap_display(target); if (display) { display->vt->update_transformation(display, target); } } /* Function: al_get_current_transform */ const ALLEGRO_TRANSFORM *al_get_current_transform(void) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); if (!target) return NULL; return &target->transform; } /* Function: al_get_current_projection_transform */ const ALLEGRO_TRANSFORM *al_get_current_projection_transform(void) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); if (!target) return NULL; return &target->proj_transform; } /* Function: al_get_current_inverse_transform */ const ALLEGRO_TRANSFORM *al_get_current_inverse_transform(void) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); if (!target) return NULL; if (target->inverse_transform_dirty) { al_copy_transform(&target->inverse_transform, &target->transform); al_invert_transform(&target->inverse_transform); target->inverse_transform_dirty = false; } return &target->inverse_transform; } /* Function: al_identity_transform */ void al_identity_transform(ALLEGRO_TRANSFORM *trans) { ASSERT(trans); trans->m[0][0] = 1; trans->m[0][1] = 0; trans->m[0][2] = 0; trans->m[0][3] = 0; trans->m[1][0] = 0; trans->m[1][1] = 1; trans->m[1][2] = 0; trans->m[1][3] = 0; trans->m[2][0] = 0; trans->m[2][1] = 0; trans->m[2][2] = 1; trans->m[2][3] = 0; trans->m[3][0] = 0; trans->m[3][1] = 0; trans->m[3][2] = 0; trans->m[3][3] = 1; } /* Function: al_build_transform */ void al_build_transform(ALLEGRO_TRANSFORM *trans, float x, float y, float sx, float sy, float theta) { float c, s; ASSERT(trans); c = cosf(theta); s = sinf(theta); trans->m[0][0] = sx * c; trans->m[0][1] = sy * s; trans->m[0][2] = 0; trans->m[0][3] = 0; trans->m[1][0] = -sx * s; trans->m[1][1] = sy * c; trans->m[1][2] = 0; trans->m[1][3] = 0; trans->m[2][0] = 0; trans->m[2][1] = 0; trans->m[2][2] = 1; trans->m[2][3] = 0; trans->m[3][0] = x; trans->m[3][1] = y; trans->m[3][2] = 0; trans->m[3][3] = 1; } /* Function: al_build_camera_transform */ void al_build_camera_transform(ALLEGRO_TRANSFORM *trans, float position_x, float position_y, float position_z, float look_x, float look_y, float look_z, float up_x, float up_y, float up_z) { float x = position_x; float y = position_y; float z = position_z; float xx, xy, xz, xnorm; float yx, yy, yz; float zx, zy, zz, znorm; al_identity_transform(trans); /* Get the z-axis (direction towards viewer) and normalize it. */ zx = x - look_x; zy = y - look_y; zz = z - look_z; znorm = sqrt(zx * zx + zy * zy + zz * zz); if (znorm == 0) return; zx /= znorm; zy /= znorm; zz /= znorm; /* Get the x-axis (direction pointing to the right) as the cross product of * the up-vector times the z-axis. We need to normalize it because we do * neither require the up-vector to be normalized nor perpendicular. */ xx = up_y * zz - zy * up_z; xy = up_z * zx - zz * up_x; xz = up_x * zy - zx * up_y; xnorm = sqrt(xx * xx + xy * xy + xz * xz); if (xnorm == 0) return; xx /= xnorm; xy /= xnorm; xz /= xnorm; /* Now use the cross product of z-axis and x-axis as our y-axis. This can * have a different direction than the original up-vector but it will * already be normalized. */ yx = zy * xz - xy * zz; yy = zz * xx - xz * zx; yz = zx * xy - xx * zy; /* This is an inverse translation (subtract the camera position) followed by * an inverse rotation (rotate in the opposite direction of the camera * orientation). */ trans->m[0][0] = xx; trans->m[1][0] = xy; trans->m[2][0] = xz; trans->m[3][0] = xx * -x + xy * -y + xz * -z; trans->m[0][1] = yx; trans->m[1][1] = yy; trans->m[2][1] = yz; trans->m[3][1] = yx * -x + yy * -y + yz * -z; trans->m[0][2] = zx; trans->m[1][2] = zy; trans->m[2][2] = zz; trans->m[3][2] = zx * -x + zy * -y + zz * -z; } /* Function: al_invert_transform */ void al_invert_transform(ALLEGRO_TRANSFORM *trans) { float det, t; ASSERT(trans); det = trans->m[0][0] * trans->m[1][1] - trans->m[1][0] * trans->m[0][1]; t = trans->m[3][0]; trans->m[3][0] = ( trans->m[1][0] * trans->m[3][1] - t * trans->m[1][1]) / det; trans->m[3][1] = (t * trans->m[0][1] - trans->m[0][0] * trans->m[3][1]) / det; t = trans->m[0][0]; trans->m[0][0] = trans->m[1][1] / det; trans->m[1][1] = t / det; trans->m[0][1] = - trans->m[0][1] / det; trans->m[1][0] = - trans->m[1][0] / det; } /* Function: al_transpose_transform */ void al_transpose_transform(ALLEGRO_TRANSFORM *trans) { int i, j; ASSERT(trans); ALLEGRO_TRANSFORM t = *trans; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { trans->m[i][j] = t.m[j][i]; } } } /* Function: al_check_inverse */ int al_check_inverse(const ALLEGRO_TRANSFORM *trans, float tol) { float det, norm, c0, c1, c3; ASSERT(trans); det = fabsf(trans->m[0][0] * trans->m[1][1] - trans->m[1][0] * trans->m[0][1]); /* We'll use the 1-norm, as it is the easiest to compute */ c0 = fabsf(trans->m[0][0]) + fabsf(trans->m[0][1]); c1 = fabsf(trans->m[1][0]) + fabsf(trans->m[1][1]); c3 = fabsf(trans->m[3][0]) + fabsf(trans->m[3][1]) + 1; norm = _ALLEGRO_MAX(_ALLEGRO_MAX(1, c0), _ALLEGRO_MAX(c1, c3)); return det > tol * norm; } /* Function: al_translate_transform */ void al_translate_transform(ALLEGRO_TRANSFORM *trans, float x, float y) { ASSERT(trans); trans->m[3][0] += x; trans->m[3][1] += y; } /* Function: al_translate_transform_3d */ void al_translate_transform_3d(ALLEGRO_TRANSFORM *trans, float x, float y, float z) { ASSERT(trans); trans->m[3][0] += x; trans->m[3][1] += y; trans->m[3][2] += z; } /* Function: al_rotate_transform */ void al_rotate_transform(ALLEGRO_TRANSFORM *trans, float theta) { float c, s; float t; ASSERT(trans); c = cosf(theta); s = sinf(theta); t = trans->m[0][0]; trans->m[0][0] = t * c - trans->m[0][1] * s; trans->m[0][1] = t * s + trans->m[0][1] * c; t = trans->m[1][0]; trans->m[1][0] = t * c - trans->m[1][1] * s; trans->m[1][1] = t * s + trans->m[1][1] * c; t = trans->m[3][0]; trans->m[3][0] = t * c - trans->m[3][1] * s; trans->m[3][1] = t * s + trans->m[3][1] * c; } /* Function: al_scale_transform */ void al_scale_transform(ALLEGRO_TRANSFORM *trans, float sx, float sy) { ASSERT(trans); trans->m[0][0] *= sx; trans->m[0][1] *= sy; trans->m[1][0] *= sx; trans->m[1][1] *= sy; trans->m[3][0] *= sx; trans->m[3][1] *= sy; } /* Function: al_scale_transform_3d */ void al_scale_transform_3d(ALLEGRO_TRANSFORM *trans, float sx, float sy, float sz) { ASSERT(trans); trans->m[0][0] *= sx; trans->m[0][1] *= sy; trans->m[0][2] *= sz; trans->m[1][0] *= sx; trans->m[1][1] *= sy; trans->m[1][2] *= sz; trans->m[2][0] *= sx; trans->m[2][1] *= sy; trans->m[2][2] *= sz; trans->m[3][0] *= sx; trans->m[3][1] *= sy; trans->m[3][2] *= sz; } /* Function: al_transform_coordinates */ void al_transform_coordinates(const ALLEGRO_TRANSFORM *trans, float *x, float *y) { float t; ASSERT(trans); ASSERT(x); ASSERT(y); t = *x; *x = t * trans->m[0][0] + *y * trans->m[1][0] + trans->m[3][0]; *y = t * trans->m[0][1] + *y * trans->m[1][1] + trans->m[3][1]; } /* Function: al_transform_coordinates_3d */ void al_transform_coordinates_3d(const ALLEGRO_TRANSFORM *trans, float *x, float *y, float *z) { float rx, ry, rz; ASSERT(trans); ASSERT(x); ASSERT(y); ASSERT(z); #define M(i, j) trans->m[i][j] rx = M(0, 0) * *x + M(1, 0) * *y + M(2, 0) * *z + M(3, 0); ry = M(0, 1) * *x + M(1, 1) * *y + M(2, 1) * *z + M(3, 1); rz = M(0, 2) * *x + M(1, 2) * *y + M(2, 2) * *z + M(3, 2); #undef M *x = rx; *y = ry; *z = rz; } /* Function: al_transform_coordinates_4d */ void al_transform_coordinates_4d(const ALLEGRO_TRANSFORM *trans, float *x, float *y, float *z, float *w) { float rx, ry, rz, rw; ASSERT(trans); ASSERT(x); ASSERT(y); ASSERT(z); ASSERT(w); #define M(i, j) trans->m[i][j] rx = M(0, 0) * *x + M(1, 0) * *y + M(2, 0) * *z + M(3, 0) * *w; ry = M(0, 1) * *x + M(1, 1) * *y + M(2, 1) * *z + M(3, 1) * *w; rz = M(0, 2) * *x + M(1, 2) * *y + M(2, 2) * *z + M(3, 2) * *w; rw = M(0, 3) * *x + M(1, 3) * *y + M(2, 3) * *z + M(3, 3) * *w; #undef M *x = rx; *y = ry; *z = rz; *w = rw; } /* Function: al_transform_coordinates_3d_projective */ void al_transform_coordinates_3d_projective(const ALLEGRO_TRANSFORM *trans, float *x, float *y, float *z) { float w = 1; al_transform_coordinates_4d(trans, x, y, z, &w); *x /= w; *y /= w; *z /= w; } /* Function: al_compose_transform */ void al_compose_transform(ALLEGRO_TRANSFORM *trans, const ALLEGRO_TRANSFORM *other) { #define E(x, y) \ (other->m[0][y] * trans->m[x][0] + \ other->m[1][y] * trans->m[x][1] + \ other->m[2][y] * trans->m[x][2] + \ other->m[3][y] * trans->m[x][3]) \ const ALLEGRO_TRANSFORM tmp = {{ { E(0, 0), E(0, 1), E(0, 2), E(0, 3) }, { E(1, 0), E(1, 1), E(1, 2), E(1, 3) }, { E(2, 0), E(2, 1), E(2, 2), E(2, 3) }, { E(3, 0), E(3, 1), E(3, 2), E(3, 3) } }}; *trans = tmp; #undef E } bool _al_transform_is_translation(const ALLEGRO_TRANSFORM* trans, float *dx, float *dy) { if (trans->m[0][0] == 1 && trans->m[1][0] == 0 && trans->m[2][0] == 0 && trans->m[0][1] == 0 && trans->m[1][1] == 1 && trans->m[2][1] == 0 && trans->m[0][2] == 0 && trans->m[1][2] == 0 && trans->m[2][2] == 1 && trans->m[3][2] == 0 && trans->m[0][3] == 0 && trans->m[1][3] == 0 && trans->m[2][3] == 0 && trans->m[3][3] == 1) { *dx = trans->m[3][0]; *dy = trans->m[3][1]; return true; } return false; } /* Function: al_orthographic_transform */ void al_orthographic_transform(ALLEGRO_TRANSFORM *trans, float left, float top, float n, float right, float bottom, float f) { float delta_x = right - left; float delta_y = top - bottom; float delta_z = f - n; ALLEGRO_TRANSFORM tmp; al_identity_transform(&tmp); tmp.m[0][0] = 2.0f / delta_x; tmp.m[1][1] = 2.0f / delta_y; tmp.m[2][2] = 2.0f / delta_z; tmp.m[3][0] = -(right + left) / delta_x; tmp.m[3][1] = -(top + bottom) / delta_y; tmp.m[3][2] = -(f + n) / delta_z; tmp.m[3][3] = 1.0f; al_compose_transform(trans, &tmp); } /* Function: al_rotate_transform_3d */ void al_rotate_transform_3d(ALLEGRO_TRANSFORM *trans, float x, float y, float z, float angle) { double s = sin(angle); double c = cos(angle); double cc = 1 - c; ALLEGRO_TRANSFORM tmp; al_identity_transform(&tmp); tmp.m[0][0] = (cc * x * x) + c; tmp.m[0][1] = (cc * x * y) + (z * s); tmp.m[0][2] = (cc * x * z) - (y * s); tmp.m[0][3] = 0; tmp.m[1][0] = (cc * x * y) - (z * s); tmp.m[1][1] = (cc * y * y) + c; tmp.m[1][2] = (cc * z * y) + (x * s); tmp.m[1][3] = 0; tmp.m[2][0] = (cc * x * z) + (y * s); tmp.m[2][1] = (cc * y * z) - (x * s); tmp.m[2][2] = (cc * z * z) + c; tmp.m[2][3] = 0; tmp.m[3][0] = 0; tmp.m[3][1] = 0; tmp.m[3][2] = 0; tmp.m[3][3] = 1; al_compose_transform(trans, &tmp); } /* Function: al_perspective_transform */ void al_perspective_transform(ALLEGRO_TRANSFORM *trans, float left, float top, float n, float right, float bottom, float f) { float delta_x = right - left; float delta_y = top - bottom; float delta_z = f - n; ALLEGRO_TRANSFORM tmp; al_identity_transform(&tmp); tmp.m[0][0] = 2.0f * n / delta_x; tmp.m[1][1] = 2.0f * n / delta_y; tmp.m[2][0] = (right + left) / delta_x; tmp.m[2][1] = (top + bottom) / delta_y; tmp.m[2][2] = -(f + n) / delta_z; tmp.m[2][3] = -1.0f; tmp.m[3][2] = -2.0f * f * n / delta_z; tmp.m[3][3] = 0; al_compose_transform(trans, &tmp); } /* Function: al_horizontal_shear_transform */ void al_horizontal_shear_transform(ALLEGRO_TRANSFORM* trans, float theta) { float s; ASSERT(trans); s = -tanf(theta); trans->m[0][0] += trans->m[0][1] * s; trans->m[1][0] += trans->m[1][1] * s; trans->m[3][0] += trans->m[3][1] * s; } /* Function: al_vertical_shear_transform */ void al_vertical_shear_transform(ALLEGRO_TRANSFORM* trans, float theta) { float s; ASSERT(trans); s = tanf(theta); trans->m[0][1] += trans->m[0][0] * s; trans->m[1][1] += trans->m[1][0] * s; trans->m[3][1] += trans->m[3][0] * s; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/tri_soft.c000066400000000000000000000671061473414355200162560ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Software triangle implementation functions. * * * By Pavel Sountsov. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_blend.h" #include "allegro5/internal/aintern_pixels.h" #include "allegro5/internal/aintern_tri_soft.h" #include ALLEGRO_DEBUG_CHANNEL("tri_soft") #define MIN _ALLEGRO_MIN #define MAX _ALLEGRO_MAX typedef void (*shader_draw)(uintptr_t, int, int, int); typedef void (*shader_init)(uintptr_t, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*); typedef void (*shader_first)(uintptr_t, int, int, int, int); typedef void (*shader_step)(uintptr_t, int); typedef struct { ALLEGRO_BITMAP *target; ALLEGRO_COLOR cur_color; } state_solid_any_2d; static void shader_solid_any_init(uintptr_t state, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, ALLEGRO_VERTEX* v3) { state_solid_any_2d* s = (state_solid_any_2d*)state; s->target = al_get_target_bitmap(); s->cur_color = v1->color; (void)v2; (void)v3; } static void shader_solid_any_first(uintptr_t state, int x1, int y, int left_minor, int left_major) { (void)state; (void)x1; (void)y; (void)left_minor; (void)left_major; } static void shader_solid_any_step(uintptr_t state, int minor) { (void)state; (void)minor; } /*----------------------------------------------------------------------------*/ typedef struct { state_solid_any_2d solid; ALLEGRO_COLOR color_dx; ALLEGRO_COLOR color_dy; ALLEGRO_COLOR color_const; /* These are catched for the left edge walking */ ALLEGRO_COLOR minor_color; ALLEGRO_COLOR major_color; /* We use these to increase the precision of interpolation */ float off_x; float off_y; } state_grad_any_2d; #define PLANE_DETS(var, u1, u2, u3) \ float var##_det = u1 * minor3 - u2 * minor2 + u3 * minor1; \ float var##_det_x = u1 * y32 - u2 * y31 + u3 * y21; \ float var##_det_y = u1 * x23 - u2 * x13 + u3 * x12; #define INIT_PREAMBLE \ const float x1 = 0; \ const float y1 = 0; \ \ const float x2 = v2->x - v1->x; \ const float y2 = v2->y - v1->y; \ \ const float x3 = v3->x - v1->x; \ const float y3 = v3->y - v1->y; \ \ const float minor1 = x1 * y2 - x2 * y1; \ const float minor2 = x1 * y3 - x3 * y1; \ const float minor3 = x2 * y3 - x3 * y2; \ \ const float y32 = y3 - y2; \ const float y31 = y3 - y1; \ const float y21 = y2 - y1; \ \ const float x23 = x2 - x3; \ const float x13 = x1 - x3; \ const float x12 = x1 - x2; \ \ const float det_u = minor3 - minor1 + minor2; static void shader_grad_any_init(uintptr_t state, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, ALLEGRO_VERTEX* v3) { INIT_PREAMBLE ALLEGRO_COLOR v1c = v1->color; ALLEGRO_COLOR v2c = v2->color; ALLEGRO_COLOR v3c = v3->color; PLANE_DETS(r, v1c.r, v2c.r, v3c.r) PLANE_DETS(g, v1c.g, v2c.g, v3c.g) PLANE_DETS(b, v1c.b, v2c.b, v3c.b) PLANE_DETS(a, v1c.a, v2c.a, v3c.a) state_grad_any_2d* s = (state_grad_any_2d*)state; s->solid.target = al_get_target_bitmap(); s->off_x = v1->x - 0.5f; s->off_y = v1->y + 0.5f; if (det_u == 0.0) { s->color_dx = s->color_dy = s->color_const = al_map_rgba_f(0, 0, 0, 0); } else { s->color_dx.r = -r_det_x / det_u; s->color_dy.r = -r_det_y / det_u; s->color_const.r = r_det / det_u; s->color_dx.g = -g_det_x / det_u; s->color_dy.g = -g_det_y / det_u; s->color_const.g = g_det / det_u; s->color_dx.b = -b_det_x / det_u; s->color_dy.b = -b_det_y / det_u; s->color_const.b = b_det / det_u; s->color_dx.a = -a_det_x / det_u; s->color_dy.a = -a_det_y / det_u; s->color_const.a = a_det / det_u; } } static void shader_grad_any_first(uintptr_t state, int x1, int y, int left_minor, int left_major) { state_grad_any_2d* s = (state_grad_any_2d*)state; const float cur_x = (float)x1 - s->off_x; const float cur_y = (float)y - s->off_y; s->solid.cur_color.r = cur_x * s->color_dx.r + cur_y * s->color_dy.r + s->color_const.r; s->solid.cur_color.g = cur_x * s->color_dx.g + cur_y * s->color_dy.g + s->color_const.g; s->solid.cur_color.b = cur_x * s->color_dx.b + cur_y * s->color_dy.b + s->color_const.b; s->solid.cur_color.a = cur_x * s->color_dx.a + cur_y * s->color_dy.a + s->color_const.a; s->minor_color.r = (float)left_minor * s->color_dx.r + s->color_dy.r; s->minor_color.g = (float)left_minor * s->color_dx.g + s->color_dy.g; s->minor_color.b = (float)left_minor * s->color_dx.b + s->color_dy.b; s->minor_color.a = (float)left_minor * s->color_dx.a + s->color_dy.a; s->major_color.r = (float)left_major * s->color_dx.r + s->color_dy.r; s->major_color.g = (float)left_major * s->color_dx.g + s->color_dy.g; s->major_color.b = (float)left_major * s->color_dx.b + s->color_dy.b; s->major_color.a = (float)left_major * s->color_dx.a + s->color_dy.a; } static void shader_grad_any_step(uintptr_t state, int minor) { state_grad_any_2d* s = (state_grad_any_2d*)state; if (minor) { s->solid.cur_color.r += s->minor_color.r; s->solid.cur_color.g += s->minor_color.g; s->solid.cur_color.b += s->minor_color.b; s->solid.cur_color.a += s->minor_color.a; } else { s->solid.cur_color.r += s->major_color.r; s->solid.cur_color.g += s->major_color.g; s->solid.cur_color.b += s->major_color.b; s->solid.cur_color.a += s->major_color.a; } } /*========================== Textured Shaders ================================*/ #define SHADE_COLORS(A, B) \ A.r = B.r * A.r; \ A.g = B.g * A.g; \ A.b = B.b * A.b; \ A.a = B.a * A.a; typedef struct { ALLEGRO_BITMAP *target; ALLEGRO_COLOR cur_color; float du_dx, du_dy, u_const; float dv_dx, dv_dy, v_const; double u, v; double minor_du; double minor_dv; double major_du; double major_dv; float off_x; float off_y; ALLEGRO_BITMAP* texture; ALLEGRO_BITMAP_WRAP default_wrap; int w, h; } state_texture_solid_any_2d; static void shader_texture_solid_any_init(uintptr_t state, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, ALLEGRO_VERTEX* v3) { INIT_PREAMBLE PLANE_DETS(u, v1->u, v2->u, v3->u) PLANE_DETS(v, v1->v, v2->v, v3->v) state_texture_solid_any_2d* s = (state_texture_solid_any_2d*)state; s->target = al_get_target_bitmap(); s->cur_color = v1->color; s->off_x = v1->x - 0.5f; s->off_y = v1->y + 0.5f; s->w = al_get_bitmap_width(s->texture); s->h = al_get_bitmap_height(s->texture); if (det_u == 0.0f) { s->du_dx = s->du_dy = s->u_const = 0.0f; s->dv_dx = s->dv_dy = s->v_const = 0.0f; } else { s->du_dx = -u_det_x / det_u; s->du_dy = -u_det_y / det_u; s->u_const = u_det / det_u; s->dv_dx = -v_det_x / det_u; s->dv_dy = -v_det_y / det_u; s->v_const = v_det / det_u; } } static void shader_texture_solid_any_first(uintptr_t state, int x1, int y, int left_minor, int left_major) { state_texture_solid_any_2d* s = (state_texture_solid_any_2d*)state; const float cur_x = (float)x1 - s->off_x; const float cur_y = (float)y - s->off_y; s->u = cur_x * s->du_dx + cur_y * s->du_dy + s->u_const; s->v = cur_x * s->dv_dx + cur_y * s->dv_dy + s->v_const; s->minor_du = (double)left_minor * s->du_dx + s->du_dy; s->minor_dv = (double)left_minor * s->dv_dx + s->dv_dy; s->major_du = (float)left_major * s->du_dx + s->du_dy; s->major_dv = (float)left_major * s->dv_dx + s->dv_dy; } static void shader_texture_solid_any_step(uintptr_t state, int minor) { state_texture_solid_any_2d* s = (state_texture_solid_any_2d*)state; if (minor) { s->u += s->minor_du; s->v += s->minor_dv; } else { s->u += s->major_du; s->v += s->major_dv; } } /*----------------------------------------------------------------------------*/ typedef struct { state_texture_solid_any_2d solid; ALLEGRO_COLOR color_dx; ALLEGRO_COLOR color_dy; ALLEGRO_COLOR color_const; /* These are catched for the left edge walking */ ALLEGRO_COLOR minor_color; ALLEGRO_COLOR major_color; } state_texture_grad_any_2d; static void shader_texture_grad_any_init(uintptr_t state, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, ALLEGRO_VERTEX* v3) { INIT_PREAMBLE ALLEGRO_COLOR v1c = v1->color; ALLEGRO_COLOR v2c = v2->color; ALLEGRO_COLOR v3c = v3->color; PLANE_DETS(r, v1c.r, v2c.r, v3c.r) PLANE_DETS(g, v1c.g, v2c.g, v3c.g) PLANE_DETS(b, v1c.b, v2c.b, v3c.b) PLANE_DETS(a, v1c.a, v2c.a, v3c.a) PLANE_DETS(u, v1->u, v2->u, v3->u) PLANE_DETS(v, v1->v, v2->v, v3->v) state_texture_grad_any_2d* s = (state_texture_grad_any_2d*)state; s->solid.target = al_get_target_bitmap(); s->solid.w = al_get_bitmap_width(s->solid.texture); s->solid.h = al_get_bitmap_height(s->solid.texture); s->solid.off_x = v1->x - 0.5f; s->solid.off_y = v1->y + 0.5f; if (det_u == 0.0) { s->solid.du_dx = s->solid.du_dy = s->solid.u_const = 0.0; s->solid.dv_dx = s->solid.dv_dy = s->solid.v_const = 0.0; s->color_dx = s->color_dy = s->color_const = al_map_rgba_f(0, 0, 0, 0); } else { s->solid.du_dx = -u_det_x / det_u; s->solid.du_dy = -u_det_y / det_u; s->solid.u_const = u_det / det_u; s->solid.dv_dx = -v_det_x / det_u; s->solid.dv_dy = -v_det_y / det_u; s->solid.v_const = v_det / det_u; s->color_dx.r = -r_det_x / det_u; s->color_dy.r = -r_det_y / det_u; s->color_const.r = r_det / det_u; s->color_dx.g = -g_det_x / det_u; s->color_dy.g = -g_det_y / det_u; s->color_const.g = g_det / det_u; s->color_dx.b = -b_det_x / det_u; s->color_dy.b = -b_det_y / det_u; s->color_const.b = b_det / det_u; s->color_dx.a = -a_det_x / det_u; s->color_dy.a = -a_det_y / det_u; s->color_const.a = a_det / det_u; } } static void shader_texture_grad_any_first(uintptr_t state, int x1, int y, int left_minor, int left_major) { state_texture_grad_any_2d* s = (state_texture_grad_any_2d*)state; float cur_x; float cur_y; shader_texture_solid_any_first(state, x1, y, left_minor, left_major); cur_x = (float)x1 - s->solid.off_x; cur_y = (float)y - s->solid.off_y; s->solid.cur_color.r = cur_x * s->color_dx.r + cur_y * s->color_dy.r + s->color_const.r; s->solid.cur_color.g = cur_x * s->color_dx.g + cur_y * s->color_dy.g + s->color_const.g; s->solid.cur_color.b = cur_x * s->color_dx.b + cur_y * s->color_dy.b + s->color_const.b; s->solid.cur_color.a = cur_x * s->color_dx.a + cur_y * s->color_dy.a + s->color_const.a; s->minor_color.r = (float)left_minor * s->color_dx.r + s->color_dy.r; s->minor_color.g = (float)left_minor * s->color_dx.g + s->color_dy.g; s->minor_color.b = (float)left_minor * s->color_dx.b + s->color_dy.b; s->minor_color.a = (float)left_minor * s->color_dx.a + s->color_dy.a; s->major_color.r = (float)left_major * s->color_dx.r + s->color_dy.r; s->major_color.g = (float)left_major * s->color_dx.g + s->color_dy.g; s->major_color.b = (float)left_major * s->color_dx.b + s->color_dy.b; s->major_color.a = (float)left_major * s->color_dx.a + s->color_dy.a; } static void shader_texture_grad_any_step(uintptr_t state, int minor) { state_texture_grad_any_2d* s = (state_texture_grad_any_2d*)state; shader_texture_solid_any_step(state, minor); if (minor) { s->solid.cur_color.r += s->minor_color.r; s->solid.cur_color.g += s->minor_color.g; s->solid.cur_color.b += s->minor_color.b; s->solid.cur_color.a += s->minor_color.a; } else { s->solid.cur_color.r += s->major_color.r; s->solid.cur_color.g += s->major_color.g; s->solid.cur_color.b += s->major_color.b; s->solid.cur_color.a += s->major_color.a; } } /* Include generated routines. */ #include "scanline_drawers.inc" static void triangle_stepper(uintptr_t state, shader_init init, shader_first first, shader_step step, shader_draw draw, ALLEGRO_VERTEX* vtx1, ALLEGRO_VERTEX* vtx2, ALLEGRO_VERTEX* vtx3) { float Coords[6] = {vtx1->x - 0.5f, vtx1->y + 0.5f, vtx2->x - 0.5f, vtx2->y + 0.5f, vtx3->x - 0.5f, vtx3->y + 0.5f}; float *V1 = Coords, *V2 = &Coords[2], *V3 = &Coords[4], *s; float left_error = 0; float right_error = 0; float left_y_delta; float right_y_delta; float left_x_delta; float right_x_delta; int left_first, right_first, left_step, right_step; int left_x, right_x, cur_y, mid_y, end_y; float left_d_er, right_d_er; /* The reason these things are declared implicitly, is because we need to determine which of the edges is on the left, and which is on the right (because they are treated differently, as described above) We then can reuse these values in the actual calculation */ float major_x_delta, major_y_delta, minor_x_delta, minor_y_delta; int major_on_the_left; // sort vertices so that V1 <= V2 <= V3 if (V2[1] < V1[1]) { s = V2; V2 = V1; V1 = s; } if (V3[1] < V1[1]) { s = V3; V3 = V1; V1 = s; } if (V3[1] < V2[1]) { s = V3; V3 = V2; V2 = s; } /* We set our integer based coordinates to be above their floating point counterparts */ cur_y = ceilf(V1[1]); mid_y = ceilf(V2[1]); end_y = ceilf(V3[1]); if (cur_y == end_y) return; /* As per definition, we take the ceiling */ left_x = ceilf(V1[0]); /* Determine which edge is the left one V1-V2 | / V3 When the cross product is negative, the major is on the left */ major_x_delta = V3[0] - V1[0]; major_y_delta = V3[1] - V1[1]; minor_x_delta = V2[0] - V1[0]; minor_y_delta = V2[1] - V1[1]; if (major_x_delta * minor_y_delta - major_y_delta * minor_x_delta < 0) major_on_the_left = 1; else major_on_the_left = 0; init(state, vtx1, vtx2, vtx3); /* Do the first segment, if it exists */ if (cur_y != mid_y) { /* As per definition, we take the floor */ right_x = floorf(V1[0]); /* Depending on where V2 is located, choose the correct delta's */ if (major_on_the_left) { left_x_delta = major_x_delta; right_x_delta = minor_x_delta; left_y_delta = major_y_delta; right_y_delta = minor_y_delta; } else { left_x_delta = minor_x_delta; right_x_delta = major_x_delta; left_y_delta = minor_y_delta; right_y_delta = major_y_delta; } /* Calculate the initial errors... doesn't look too pretty, but it only has to be done a couple of times per triangle drawing operation, so its not that bad */ left_error = ((float)cur_y - V1[1]) * left_x_delta - ((float)left_x - V1[0]) * left_y_delta; right_error = ((float)cur_y - V1[1]) * right_x_delta - ((float)right_x - V1[0]) * right_y_delta; /* Calculate the first step of the edge steppers, it is potentially different from all other steps */ left_first = ceilf((left_error) / left_y_delta); /* Introduce a tiny bias into the calculation, a problem with the floorf implementation because it does not have a properly defined 0 point. I think this is a hack, however, so if anyone has a better idea of how to fix this, by all means implement it. N.B. the same offset in the bottom segment as well */ right_first = floorf((right_error) / right_y_delta - 0.000001f); /* Calculate the normal steps */ left_step = ceilf(left_x_delta / left_y_delta); left_d_er = -(float)left_step * left_y_delta; right_step = ceilf(right_x_delta / right_y_delta); right_d_er = -(float)right_step * right_y_delta; /* Take the first step */ if (cur_y < mid_y) { left_x += left_first; left_error -= (float)left_first * left_y_delta; right_x += right_first; right_error -= (float)right_first * right_y_delta; first(state, left_x, cur_y, left_step, left_step - 1); if (right_x >= left_x) { draw(state, left_x, cur_y, right_x); } cur_y++; left_error += left_x_delta; right_error += right_x_delta; } /* ...and then continue taking normal steps until we finish the segment */ while (cur_y < mid_y) { left_error += left_d_er; left_x += left_step; /* If we dip to the right of the line, we shift one pixel to the left If dx > 0, this corresponds to taking the minor step If dx < 0, this corresponds to taking the major step */ if (left_error + left_y_delta <= 0) { left_error += left_y_delta; left_x -= 1; step(state, 0); } else step(state, 1); right_error += right_d_er; right_x += right_step; if (right_error <= 0) { right_error += right_y_delta; right_x -= 1; } if (right_x >= left_x) { draw(state, left_x, cur_y, right_x); } cur_y++; left_error += left_x_delta; right_error += right_x_delta; } } /* Draw the second segment, if possible */ if (cur_y < end_y) { if (major_on_the_left) { right_x = ceilf(V2[0]); left_x_delta = major_x_delta; right_x_delta = V3[0] - V2[0]; left_y_delta = major_y_delta; right_y_delta = V3[1] - V2[1]; left_error = ((float)cur_y - V1[1]) * left_x_delta - ((float)left_x - V1[0]) * left_y_delta; right_error = ((float)cur_y - V2[1]) * right_x_delta - ((float)right_x - V2[0]) * right_y_delta; } else { right_x = floorf(V2[0]); left_x_delta = V3[0] - V2[0]; right_x_delta = major_x_delta; left_y_delta = V3[1] - V2[1]; right_y_delta = major_y_delta; left_error = ((float)cur_y - V2[1]) * left_x_delta - ((float)left_x - V2[0]) * left_y_delta; right_error = ((float)cur_y - V1[1]) * right_x_delta - ((float)right_x - V1[0]) * right_y_delta; } left_first = ceilf((left_error) / left_y_delta); right_first = floorf((right_error) / right_y_delta - 0.000001f); left_step = ceilf(left_x_delta / left_y_delta); left_d_er = -(float)left_step * left_y_delta; right_step = ceilf(right_x_delta / right_y_delta); right_d_er = -(float)right_step * right_y_delta; if (cur_y < end_y) { left_x += left_first; left_error -= (float)left_first * left_y_delta; right_x += right_first; right_error -= (float)right_first * right_y_delta; first(state, left_x, cur_y, left_step, left_step - 1); if (right_x >= left_x) { draw(state, left_x, cur_y, right_x); } cur_y++; left_error += left_x_delta; right_error += right_x_delta; } while (cur_y < end_y) { left_error += left_d_er; left_x += left_step; if (left_error + left_y_delta <= 0) { left_error += left_y_delta; left_x -= 1; step(state, 0); } else step(state, 1); right_error += right_d_er; right_x += right_step; if (right_error <= 0) { right_error += right_y_delta; right_x -= 1; } if (right_x >= left_x) { draw(state, left_x, cur_y, right_x); } cur_y++; left_error += left_x_delta; right_error += right_x_delta; } } } /* This one will check to see what exactly we need to draw... I.e. this will call all of the actual renderers and set the appropriate callbacks */ void _al_triangle_2d(ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, ALLEGRO_VERTEX* v3) { int shade = 1; int grad = 1; int op, src_mode, dst_mode, op_alpha, src_alpha, dst_alpha; ALLEGRO_COLOR v1c, v2c, v3c; v1c = v1->color; v2c = v2->color; v3c = v3->color; al_get_separate_bitmap_blender(&op, &src_mode, &dst_mode, &op_alpha, &src_alpha, &dst_alpha); if (_AL_DEST_IS_ZERO && _AL_SRC_NOT_MODIFIED) { shade = 0; } if ((v1c.r == v2c.r && v2c.r == v3c.r) && (v1c.g == v2c.g && v2c.g == v3c.g) && (v1c.b == v2c.b && v2c.b == v3c.b) && (v1c.a == v2c.a && v2c.a == v3c.a)) { grad = 0; } if (texture) { ALLEGRO_BITMAP_WRAP wrap_u, wrap_v; _al_get_bitmap_wrap(texture, &wrap_u, &wrap_v); /* XXX: Why are we using repeat for regular bitmaps by default? For some reason the scanline drawers were always designed to repeat even for regular bitmaps. This does not match what we do with OpenGL/Direct3D. */ bool repeat = (wrap_u == ALLEGRO_BITMAP_WRAP_DEFAULT || wrap_u == ALLEGRO_BITMAP_WRAP_REPEAT) && (wrap_v == ALLEGRO_BITMAP_WRAP_DEFAULT || wrap_v == ALLEGRO_BITMAP_WRAP_REPEAT); if (grad) { state_texture_grad_any_2d state; state.solid.texture = texture; if (shade) { _al_draw_soft_triangle(v1, v2, v3, (uintptr_t)&state, shader_texture_grad_any_init, shader_texture_grad_any_first, shader_texture_grad_any_step, shader_texture_grad_any_draw_shade); } else { _al_draw_soft_triangle(v1, v2, v3, (uintptr_t)&state, shader_texture_grad_any_init, shader_texture_grad_any_first, shader_texture_grad_any_step, shader_texture_grad_any_draw_opaque); } } else { int white = 0; state_texture_solid_any_2d state; if (v1c.r == 1 && v1c.g == 1 && v1c.b == 1 && v1c.a == 1) { white = 1; } state.texture = texture; if (shade) { if (white) { if (repeat) { _al_draw_soft_triangle(v1, v2, v3, (uintptr_t)&state, shader_texture_solid_any_init, shader_texture_solid_any_first, shader_texture_solid_any_step, shader_texture_solid_any_draw_shade_white_repeat); } else { _al_draw_soft_triangle(v1, v2, v3, (uintptr_t)&state, shader_texture_solid_any_init, shader_texture_solid_any_first, shader_texture_solid_any_step, shader_texture_solid_any_draw_shade_white); } } else { if (repeat) { _al_draw_soft_triangle(v1, v2, v3, (uintptr_t)&state, shader_texture_solid_any_init, shader_texture_solid_any_first, shader_texture_solid_any_step, shader_texture_solid_any_draw_shade_repeat); } else { _al_draw_soft_triangle(v1, v2, v3, (uintptr_t)&state, shader_texture_solid_any_init, shader_texture_solid_any_first, shader_texture_solid_any_step, shader_texture_solid_any_draw_shade); } } } else { if (white) { _al_draw_soft_triangle(v1, v2, v3, (uintptr_t)&state, shader_texture_solid_any_init, shader_texture_solid_any_first, shader_texture_solid_any_step, shader_texture_solid_any_draw_opaque_white); } else { _al_draw_soft_triangle(v1, v2, v3, (uintptr_t)&state, shader_texture_solid_any_init, shader_texture_solid_any_first, shader_texture_solid_any_step, shader_texture_solid_any_draw_opaque); } } } } else { if (grad) { state_grad_any_2d state; if (shade) { _al_draw_soft_triangle(v1, v2, v3, (uintptr_t)&state, shader_grad_any_init, shader_grad_any_first, shader_grad_any_step, shader_grad_any_draw_shade); } else { _al_draw_soft_triangle(v1, v2, v3, (uintptr_t)&state, shader_grad_any_init, shader_grad_any_first, shader_grad_any_step, shader_grad_any_draw_opaque); } } else { state_solid_any_2d state; if (shade) { _al_draw_soft_triangle(v1, v2, v3, (uintptr_t)&state, shader_solid_any_init, shader_solid_any_first, shader_solid_any_step, shader_solid_any_draw_shade); } else { _al_draw_soft_triangle(v1, v2, v3, (uintptr_t)&state, shader_solid_any_init, shader_solid_any_first, shader_solid_any_step, shader_solid_any_draw_opaque); } } } } static int bitmap_region_is_locked(ALLEGRO_BITMAP* bmp, int x1, int y1, int w, int h) { ASSERT(bmp); if (!al_is_bitmap_locked(bmp)) return 0; if (x1 + w > bmp->lock_x && y1 + h > bmp->lock_y && x1 < bmp->lock_x + bmp->lock_w && y1 < bmp->lock_y + bmp->lock_h) return 1; return 0; } void _al_draw_soft_triangle( ALLEGRO_VERTEX* v1, ALLEGRO_VERTEX* v2, ALLEGRO_VERTEX* v3, uintptr_t state, void (*init)(uintptr_t, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*, ALLEGRO_VERTEX*), void (*first)(uintptr_t, int, int, int, int), void (*step)(uintptr_t, int), void (*draw)(uintptr_t, int, int, int)) { /* ALLEGRO_VERTEX copy_v1, copy_v2; <- may be needed for clipping later on */ ALLEGRO_VERTEX* vtx1 = v1; ALLEGRO_VERTEX* vtx2 = v2; ALLEGRO_VERTEX* vtx3 = v3; ALLEGRO_BITMAP *target = al_get_target_bitmap(); int need_unlock = 0; ALLEGRO_LOCKED_REGION *lr; int min_x, max_x, min_y, max_y; int clip_min_x, clip_min_y, clip_max_x, clip_max_y; al_get_clipping_rectangle(&clip_min_x, &clip_min_y, &clip_max_x, &clip_max_y); clip_max_x += clip_min_x; clip_max_y += clip_min_y; /* TODO: Need to clip them first, make a copy of the vertices first then */ /* Lock the region we are drawing to. We are choosing the minimum and maximum possible pixels touched from the formula (easily verified by following the above algorithm. */ min_x = (int)floorf(MIN(vtx1->x, MIN(vtx2->x, vtx3->x))) - 1; min_y = (int)floorf(MIN(vtx1->y, MIN(vtx2->y, vtx3->y))) - 1; max_x = (int)ceilf(MAX(vtx1->x, MAX(vtx2->x, vtx3->x))) + 1; max_y = (int)ceilf(MAX(vtx1->y, MAX(vtx2->y, vtx3->y))) + 1; /* TODO: This bit is temporary, the min max's will be guaranteed to be within the bitmap once clipping is implemented */ if (min_x >= clip_max_x || min_y >= clip_max_y) return; if (max_x >= clip_max_x) max_x = clip_max_x; if (max_y >= clip_max_y) max_y = clip_max_y; if (max_x < clip_min_x || max_y < clip_min_y) return; if (min_x < clip_min_x) min_x = clip_min_x; if (min_y < clip_min_y) min_y = clip_min_y; if (al_is_bitmap_locked(target)) { if (!bitmap_region_is_locked(target, min_x, min_y, max_x - min_x, max_y - min_y) || _al_pixel_format_is_video_only(target->locked_region.format)) return; } else { if (!(lr = al_lock_bitmap_region(target, min_x, min_y, max_x - min_x, max_y - min_y, ALLEGRO_PIXEL_FORMAT_ANY, 0))) return; need_unlock = 1; } triangle_stepper(state, init, first, step, draw, v1, v2, v3); if (need_unlock) al_unlock_bitmap(target); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/unix/000077500000000000000000000000001473414355200152325ustar00rootroot00000000000000allegro5-5.2.10.1/src/unix/udrvlist.c000066400000000000000000000026461473414355200172620ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Dynamic driver lists shared by Unixy system drivers. * * By Peter Wang. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_system.h" #if defined ALLEGRO_WITH_XWINDOWS #ifndef ALLEGRO_RASPBERRYPI #include "allegro5/platform/aintxglx.h" #else #include "allegro5/internal/aintern_raspberrypi.h" #endif #endif /* This is a function each platform must define to register all available * system drivers. */ void _al_register_system_interfaces(void) { ALLEGRO_SYSTEM_INTERFACE **add; #if defined ALLEGRO_WITH_XWINDOWS && !defined ALLEGRO_RASPBERRYPI add = _al_vector_alloc_back(&_al_system_interfaces); *add = _al_system_xglx_driver(); #elif defined ALLEGRO_RASPBERRYPI add = _al_vector_alloc_back(&_al_system_interfaces); *add = _al_system_raspberrypi_driver(); #endif } allegro5-5.2.10.1/src/unix/ufdwatch.c000066400000000000000000000123071473414355200172060ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Unix fd watcher thread. * * By Peter Wang. * * See readme.txt for copyright information. * * This module implements a background thread that waits for data * to arrive in file descriptors, at which point it dispatches to * functions which will process that data. */ #include #include #include #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_thread.h" #include "allegro5/internal/aintern_vector.h" #include "allegro5/platform/aintunix.h" typedef struct WATCH_ITEM { int fd; void (*callback)(void *); void *cb_data; } WATCH_ITEM; static _AL_THREAD fd_watch_thread; static _AL_MUTEX fd_watch_mutex = _AL_MUTEX_UNINITED; static _AL_VECTOR fd_watch_list = _AL_VECTOR_INITIALIZER(WATCH_ITEM); /* fd_watch_thread_func: [fdwatch thread] * The thread loop function. */ static void fd_watch_thread_func(_AL_THREAD *self, void *unused) { (void)unused; while (!_al_get_thread_should_stop(self)) { fd_set rfds; int max_fd; /* set up max_fd and rfds */ _al_mutex_lock(&fd_watch_mutex); { WATCH_ITEM *wi; unsigned int i; FD_ZERO(&rfds); max_fd = -1; for (i = 0; i < _al_vector_size(&fd_watch_list); i++) { wi = _al_vector_ref(&fd_watch_list, i); FD_SET(wi->fd, &rfds); if (wi->fd > max_fd) max_fd = wi->fd; } } _al_mutex_unlock(&fd_watch_mutex); /* wait for something to happen on one of the fds */ { struct timeval tv; int retval; tv.tv_sec = 0; tv.tv_usec = 250000; retval = select(max_fd+1, &rfds, NULL, NULL, &tv); if (retval < 1) continue; } /* one or more of the fds has activity */ _al_mutex_lock(&fd_watch_mutex); { WATCH_ITEM *wi; unsigned int i; for (i = 0; i < _al_vector_size(&fd_watch_list); i++) { wi = _al_vector_ref(&fd_watch_list, i); if (FD_ISSET(wi->fd, &rfds)) { /* The callback is allowed to modify the watch list so the mutex * must be recursive. */ wi->callback(wi->cb_data); } } } _al_mutex_unlock(&fd_watch_mutex); } } /* _al_unix_start_watching_fd: [primary thread] * * Start watching for data on file descriptor `fd'. This is done in * a background thread, which is started if necessary. When there is * data waiting to be read on fd, `callback' is applied to `cb_data'. * The callback function should read as much data off fd as possible. * * Note: the callback is run from the background thread. You can * assume there is only one callback being called from the fdwatch * module at a time. */ void _al_unix_start_watching_fd(int fd, void (*callback)(void *), void *cb_data) { ASSERT(fd >= 0); ASSERT(callback); /* start the background thread if necessary */ if (_al_vector_size(&fd_watch_list) == 0) { /* We need a recursive mutex to allow callbacks to modify the fd watch * list. */ _al_mutex_init_recursive(&fd_watch_mutex); _al_thread_create(&fd_watch_thread, fd_watch_thread_func, NULL); } /* now add the watch item to the list */ _al_mutex_lock(&fd_watch_mutex); { WATCH_ITEM *wi = _al_vector_alloc_back(&fd_watch_list); wi->fd = fd; wi->callback = callback; wi->cb_data = cb_data; } _al_mutex_unlock(&fd_watch_mutex); } /* _al_unix_stop_watching_fd: [primary thread] * * Stop watching for data on `fd'. Once there are no more file * descriptors to watch, the background thread will be stopped. This * function is synchronised with the background thread, so you don't * have to do any locking before calling it. */ void _al_unix_stop_watching_fd(int fd) { bool list_empty = false; /* find the fd in the watch list and remove it */ _al_mutex_lock(&fd_watch_mutex); { WATCH_ITEM *wi; unsigned int i; for (i = 0; i < _al_vector_size(&fd_watch_list); i++) { wi = _al_vector_ref(&fd_watch_list, i); if (wi->fd == fd) { _al_vector_delete_at(&fd_watch_list, i); list_empty = _al_vector_is_empty(&fd_watch_list); break; } } } _al_mutex_unlock(&fd_watch_mutex); /* if no more fd's are being watched, stop the background thread */ if (list_empty) { _al_thread_join(&fd_watch_thread); _al_mutex_destroy(&fd_watch_mutex); _al_vector_free(&fd_watch_list); } } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ allegro5-5.2.10.1/src/unix/ugfxdrv.c000066400000000000000000000000001473414355200170510ustar00rootroot00000000000000allegro5-5.2.10.1/src/unix/uhapdrv.c000066400000000000000000000017411473414355200170520ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * List of Unix haptic drivers. * * By Beoran. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/platform/aintunix.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_haptic.h" _AL_BEGIN_HAPTIC_DRIVER_LIST #if defined ALLEGRO_HAVE_LINUX_INPUT_H && (defined ALLEGRO_WITH_XWINDOWS || defined ALLEGRO_RASPBERRYPI) { _ALLEGRO_HAPDRV_LINUX, &_al_hapdrv_linux, true }, #endif _AL_END_HAPTIC_DRIVER_LIST allegro5-5.2.10.1/src/unix/ujoydrv.c000066400000000000000000000017631473414355200171070ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * List of Unix joystick drivers. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/platform/aintunix.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_joystick.h" _AL_BEGIN_JOYSTICK_DRIVER_LIST #if defined ALLEGRO_HAVE_LINUX_INPUT_H && (defined ALLEGRO_WITH_XWINDOWS || defined ALLEGRO_RASPBERRYPI) { _ALLEGRO_JOYDRV_LINUX, &_al_joydrv_linux, true }, #endif _AL_END_JOYSTICK_DRIVER_LIST allegro5-5.2.10.1/src/unix/ukeybd.c000066400000000000000000000014621473414355200166640ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Unix keyboard module. * * By Michael Bukin. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_driver.h" /* list the available drivers */ _AL_DRIVER_INFO _al_keyboard_driver_list[] = { { 0, NULL, 0 } }; allegro5-5.2.10.1/src/unix/umouse.c000066400000000000000000000014171473414355200167160ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Unix mouse module. * * By Michael Bukin. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_driver.h" /* list the available drivers */ _AL_DRIVER_INFO _al_mouse_driver_list[] = { { 0, NULL, 0 } }; allegro5-5.2.10.1/src/unix/upath.c000066400000000000000000000345131473414355200165250ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * List of system pathes for the Unix library. * * By Michael Bukin. * * See readme.txt for copyright information. */ #include #include #include #include #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/platform/aintunix.h" #include "allegro5/fshook.h" #include "allegro5/path.h" #ifdef ALLEGRO_HAVE_SYS_UTSNAME_H #include #endif #ifdef ALLEGRO_HAVE_SV_PROCFS_H #include #include #include #endif ALLEGRO_DEBUG_CHANNEL("upath") #ifndef PATH_MAX #define PATH_MAX 4096 #endif #ifndef ALLEGRO_MACOSX /* _find_executable_file: * Helper function: searches path and current directory for executable. * Returns 1 on succes, 0 on failure. */ static ALLEGRO_PATH *_find_executable_file(const char *filename) { char *env; /* If filename has an explicit path, search current directory */ if (strchr(filename, '/')) { if (filename[0] == '/') { /* Full path; done */ return al_create_path(filename); } else { struct stat finfo; char *cwd; /* Prepend current directory */ cwd = al_get_current_directory(); if (cwd) { ALLEGRO_PATH *path = al_create_path_for_directory(cwd); al_free(cwd); al_set_path_filename(path, filename); if (stat(al_path_cstr(path, '/'), &finfo) == 0 && !S_ISDIR(finfo.st_mode)) { return path; } al_destroy_path(path); } } } /* If filename has no explicit path, but we do have $PATH, search * there */ else if ((env = getenv("PATH"))) { struct stat finfo; ALLEGRO_USTR *us = al_ustr_new(env); int start_pos = 0; while (start_pos >= 0) { int next_start_pos = al_ustr_find_chr(us, start_pos + 1, ':'); int end_pos = next_start_pos; if (next_start_pos < 0) end_pos = al_ustr_size(us); ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *sub = al_ref_ustr(&info, us, start_pos, end_pos); ALLEGRO_PATH *path = al_create_path_for_directory(al_cstr(sub)); al_set_path_filename(path, filename); if (stat(al_path_cstr(path, '/'), &finfo) == 0 && !S_ISDIR (finfo.st_mode)) { al_ustr_free(us); return path; } al_destroy_path(path); start_pos = next_start_pos; } al_ustr_free(us); } return NULL; } /* Return full path to the current executable, use proc fs if * available. */ static ALLEGRO_PATH *get_executable_name(void) { ALLEGRO_PATH *path; #ifdef ALLEGRO_HAVE_GETEXECNAME { const char *s = getexecname(); if (s) { if (s[0] == '/') { /* Absolute path */ return al_create_path(s); } else { /* Not an absolute path */ path = _find_executable_file(s); if (path) return path; } } } #endif /* We need the PID in order to query procfs */ pid_t pid = getpid(); /* Try a Linux-like procfs */ /* get symolic link to executable from proc fs */ char linkname[1024]; char filename[1024]; struct stat finfo; sprintf(linkname, "/proc/%d/exe", (int)pid); if (stat(linkname, &finfo) == 0) { int len = readlink(linkname, filename, sizeof(filename) - 1); if (len > -1) { filename[len] = '\0'; return al_create_path(filename); } } /* Use System V procfs calls if available */ #ifdef ALLEGRO_HAVE_SV_PROCFS_H struct prpsinfo psinfo; int fd; sprintf(linkname, "/proc/%d/exe", (int)pid); fd = open(linkname, O_RDONLY); if (fd != -1) { ioctl(fd, PIOCPSINFO, &psinfo); close(fd); /* Use argv[0] directly if we can */ #ifdef ALLEGRO_HAVE_PROCFS_ARGCV if (psinfo.pr_argv && psinfo.pr_argc) { path = _find_executable_file(psinfo.pr_argv[0]); if (path) return path; } else #endif { /* Emulate it */ /* We use the pr_psargs field to find argv[0] * This is better than using the pr_fname field because we need * the additional path information that may be present in argv[0] */ /* Skip other args */ char *s = strchr(psinfo.pr_psargs, ' '); if (s) s[0] = '\0'; path = _find_executable_file(psinfo.pr_psargs); if (path) return path; } /* Try the pr_fname just for completeness' sake if argv[0] fails */ path = _find_executable_file(psinfo.pr_fname); if (path) return path; } #endif /* Last resort: try using the output of the ps command to at least find */ /* the name of the file if not the full path */ char command[1024]; sprintf(command, "ps -p %d", (int)pid); FILE *pipe = popen(command, "r"); if (pipe) { char* ret; /* The first line of output is a header */ ret = fgets(linkname, sizeof(linkname), pipe); if (!ret) ALLEGRO_ERROR("Failed to read the name of the executable file.\n"); /* The information we want is in the last column; find it */ int len = strlen(linkname); while (linkname[len] != ' ' && linkname[len] != '\t') len--; /* The second line contains the info we want */ ret = fgets(linkname, sizeof(linkname), pipe); if (!ret) ALLEGRO_ERROR("Failed to read the name of the executable file.\n"); pclose(pipe); /* Treat special cases: filename between [] and - for login shell */ if (linkname[len] == '-') len++; if (linkname[len] == '[' && linkname[strlen(linkname)] == ']') { len++; linkname[strlen(linkname)] = '\0'; } /* Now, the filename should be in the last column */ _al_sane_strncpy(filename, linkname+len+1, strlen(linkname)-len+1); path = _find_executable_file(filename); if (path) return path; /* Just return the output from ps... */ return al_create_path(filename); } /* Give up; return empty string */ return al_create_path(""); } static ALLEGRO_PATH *follow_symlinks(ALLEGRO_PATH *path) { for (;;) { const char *path_str = al_path_cstr(path, '/'); char buf[PATH_MAX]; int len; len = readlink(path_str, buf, sizeof(buf) - 1); if (len <= 0) break; buf[len] = '\0'; al_destroy_path(path); path = al_create_path(buf); } /* Make absolute path. */ { const char *cwd = al_get_current_directory(); ALLEGRO_PATH *cwd_path = al_create_path_for_directory(cwd); if (al_rebase_path(cwd_path, path)) al_make_path_canonical(path); al_destroy_path(cwd_path); al_free((void *) cwd); } return path; } #endif #define XDG_MAX_PATH_LEN 1000 /* get_xdg_path - locate an XDG user dir */ static ALLEGRO_PATH *_get_xdg_path(const char *location) { ALLEGRO_PATH *location_path = NULL; ALLEGRO_PATH *xdg_config_path = NULL; ALLEGRO_FILE *xdg_config_file = NULL; const char *xdg_config_home = getenv("XDG_CONFIG_HOME"); int fd; if (xdg_config_home) { /* use $XDG_CONFIG_HOME since it exists */ xdg_config_path = al_create_path_for_directory(xdg_config_home); } else { /* the default XDG location is ~/.config */ xdg_config_path = al_get_standard_path(ALLEGRO_USER_HOME_PATH); if (!xdg_config_path) return NULL; al_append_path_component(xdg_config_path, ".config"); } al_set_path_filename(xdg_config_path, "user-dirs.dirs"); fd = open(al_path_cstr(xdg_config_path, '/'), O_RDONLY); if (fd != -1) { xdg_config_file = al_fopen_fd(fd, "r"); } al_destroy_path(xdg_config_path); if (!xdg_config_file) return NULL; while (!al_feof(xdg_config_file)) { char line[XDG_MAX_PATH_LEN]; /* one line of the config file */ const char *p = line; /* where we're at in the line */ char component[XDG_MAX_PATH_LEN]; /* the path component being parsed */ int i = 0; /* how long the current component is */ al_fgets(xdg_config_file, line, XDG_MAX_PATH_LEN); /* skip leading white space */ while (*p == ' ' || *p == '\t') p++; /* skip the line if it does not begin with XDG_location_DIR */ if (strncmp(p, "XDG_", 4)) continue; p += 4; if (strncmp(p, location, strlen(location))) continue; p += strlen(location); if (strncmp(p, "_DIR", 4)) continue; p += 4; /* skip past the =", allowing for white space */ while (*p == ' ' || *p == '\t') p++; if (*p++ != '=') continue; while (*p == ' ' || *p == '\t') p++; if (*p++ != '"') continue; /* We've found the right line. Now parse it, basically assuming that it is in a sane format. */ if (!strncmp(p, "$HOME", 5)) { /* $HOME is the only environment variable that the path is allowed to use, and it must be first, by specification. */ location_path = al_get_standard_path(ALLEGRO_USER_HOME_PATH); p += 5; } else { location_path = al_create_path("/"); } while (*p) { if (*p == '"' || *p == '/') { /* add the component (if non-empty) to the path */ if (i > 0) { component[i] = 0; al_append_path_component(location_path, component); i = 0; } if (*p == '"') break; } else { if (*p == '\\') { /* treat any escaped character as a literal */ p++; if (!*p) break; } component[i++] = *p; } p++; } /* Finished parsing the path. */ break; } al_fclose(xdg_config_file); return location_path; } static ALLEGRO_PATH *_unix_find_home(void) { char *home_env = getenv("HOME"); if (!home_env || home_env[0] == '\0') { /* since HOME isn't set, we have to ask libc for the info */ /* get user id */ uid_t uid = getuid(); /* grab user information */ struct passwd *pass = getpwuid(uid); if (!pass) { al_set_errno(errno); return NULL; } if (pass->pw_dir) { /* hey, we got our home directory */ return al_create_path_for_directory(pass->pw_dir); } al_set_errno(ENOENT); return NULL; } else { return al_create_path_for_directory(home_env); } } ALLEGRO_PATH *_al_unix_get_path(int id) { switch (id) { case ALLEGRO_TEMP_PATH: { /* Check: TMP, TMPDIR, TEMP or TEMPDIR */ char *envs[] = { "TMP", "TMPDIR", "TEMP", "TEMPDIR", NULL}; uint32_t i = 0; for (; envs[i] != NULL; ++i) { char *tmp = getenv(envs[i]); if (tmp) { return al_create_path_for_directory(tmp); } } /* next try: /tmp /var/tmp /usr/tmp */ char *paths[] = { "/tmp/", "/var/tmp/", "/usr/tmp/", NULL }; for (i=0; paths[i] != NULL; ++i) { ALLEGRO_FS_ENTRY *fse = al_create_fs_entry(paths[i]); bool found = (al_get_fs_entry_mode(fse) & ALLEGRO_FILEMODE_ISDIR) != 0; al_destroy_fs_entry(fse); if (found) { return al_create_path_for_directory(paths[i]); } } /* Give up? */ return NULL; } break; case ALLEGRO_RESOURCES_PATH: { ALLEGRO_PATH *exe = get_executable_name(); exe = follow_symlinks(exe); al_set_path_filename(exe, NULL); return exe; } break; case ALLEGRO_USER_DATA_PATH: case ALLEGRO_USER_SETTINGS_PATH: { ALLEGRO_PATH *local_path = NULL; const char *org_name = al_get_org_name(); const char *app_name = al_get_app_name(); /* to avoid writing directly into the user's directory, require at least an app name */ if (!app_name) return NULL; /* find the appropriate path from the xdg environment variables, if possible */ if (id == ALLEGRO_USER_DATA_PATH) { const char *xdg_data_home = getenv("XDG_DATA_HOME"); local_path = al_create_path_for_directory(xdg_data_home ? xdg_data_home : ".local/share"); } else { const char *xdg_config_home = getenv("XDG_CONFIG_HOME"); local_path = al_create_path_for_directory(xdg_config_home ? xdg_config_home : ".config"); } if (!local_path) return NULL; /* if the path is relative, prepend the user's home directory */ if (al_path_cstr(local_path, '/')[0] != '/') { ALLEGRO_PATH *home_path = _unix_find_home(); if (!home_path) return NULL; al_rebase_path(home_path, local_path); al_destroy_path(home_path); } /* only add org name if not blank */ if (org_name && org_name[0]) { al_append_path_component(local_path, al_get_org_name()); } al_append_path_component(local_path, al_get_app_name()); return local_path; } break; case ALLEGRO_USER_HOME_PATH: return _unix_find_home(); case ALLEGRO_USER_DOCUMENTS_PATH: { ALLEGRO_PATH *local_path = _get_xdg_path("DOCUMENTS"); return local_path ? local_path : _unix_find_home(); } break; case ALLEGRO_EXENAME_PATH: return get_executable_name(); break; default: return NULL; } return NULL; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/unix/utime.c000066400000000000000000000062051473414355200165240ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Unix time module. * * By Peter Wang. * * See readme.txt for copyright information. */ #include #include #include "allegro5/altime.h" #include "allegro5/debug.h" #include "allegro5/platform/aintunix.h" #include "allegro5/platform/aintuthr.h" ALLEGRO_STATIC_ASSERT(utime, sizeof(ALLEGRO_TIMEOUT_UNIX) <= sizeof(ALLEGRO_TIMEOUT)); /* Marks the time Allegro was initialised, for al_get_time(). */ struct timespec _al_unix_initial_time; /* clock_gettime() doesn't exist in MacOSX versions < 10.12. Use * gettimeofday() if building for MacOSX and targeting version < 10.12. */ #if defined(ALLEGRO_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < 101200 #include int _internal_clock_gettime(clockid_t clock_id, struct timespec* t) { struct timeval now; (void)clock_id; gettimeofday(&now, NULL); t->tv_sec = now.tv_sec; t->tv_nsec = now.tv_usec * 1000; return 0; } #define _al_clock_gettime _internal_clock_gettime #else #define _al_clock_gettime clock_gettime #endif // Prefer clock that never decreases and includes time suspended. // Can probably use CLOCK_MONOTONIC_RAW for non-mac too, but remains to be // verified. #if defined(ALLEGRO_MACOSX) #define CLOCK_ID CLOCK_MONOTONIC_RAW #else #define CLOCK_ID CLOCK_REALTIME #endif /* _al_unix_init_time: * Called by the system driver to mark the beginning of time. */ void _al_unix_init_time(void) { _al_clock_gettime(CLOCK_ID, &_al_unix_initial_time); } double _al_unix_get_time(void) { struct timespec now; double time; _al_clock_gettime(CLOCK_ID, &now); time = (double) (now.tv_sec - _al_unix_initial_time.tv_sec) + (double) (now.tv_nsec - _al_unix_initial_time.tv_nsec) * 1.0e-9; return time; } void _al_unix_rest(double seconds) { struct timespec timeout; double integral; double frac; frac = modf(seconds, &integral); timeout.tv_sec = (time_t)integral; timeout.tv_nsec = (suseconds_t)(frac * 1e9); nanosleep(&timeout, 0); } void _al_unix_init_timeout(ALLEGRO_TIMEOUT *timeout, double seconds) { ALLEGRO_TIMEOUT_UNIX *ut = (ALLEGRO_TIMEOUT_UNIX *) timeout; struct timespec now; double integral; double frac; ASSERT(ut); _al_clock_gettime(CLOCK_REALTIME, &now); if (seconds <= 0.0) { ut->abstime.tv_sec = now.tv_sec; ut->abstime.tv_nsec = now.tv_nsec; } else { frac = modf(seconds, &integral); ut->abstime.tv_sec = now.tv_sec + integral; ut->abstime.tv_nsec = now.tv_nsec + (frac * 1000000000L); ut->abstime.tv_sec += ut->abstime.tv_nsec / 1000000000L; ut->abstime.tv_nsec = ut->abstime.tv_nsec % 1000000000L; } } /* vim: set sts=3 sw=3 et */ allegro5-5.2.10.1/src/unix/uxthread.c000066400000000000000000000106041473414355200172230ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Internal cross-platform threading API for Unix. * * By Peter Wang. * * See readme.txt for copyright information. */ #define _XOPEN_SOURCE 500 /* for Unix98 recursive mutexes */ /* XXX: added configure test */ #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_thread.h" #include "allegro5/platform/aintunix.h" #ifdef ALLEGRO_ANDROID #include "allegro5/internal/aintern_android.h" #endif /* threads */ static void *thread_proc_trampoline(void *data) { _AL_THREAD *thread = data; /* Android is special and needs to attach/detach threads with Java */ #ifdef ALLEGRO_ANDROID _al_android_thread_created(); #endif (*thread->proc)(thread, thread->arg); #ifdef ALLEGRO_ANDROID _al_android_thread_ended(); #endif return NULL; } void _al_thread_create(_AL_THREAD *thread, void (*proc)(_AL_THREAD*, void*), void *arg) { ASSERT(thread); ASSERT(proc); { int status; pthread_mutex_init(&thread->mutex, NULL); thread->should_stop = false; thread->proc = proc; thread->arg = arg; status = pthread_create(&thread->thread, NULL, thread_proc_trampoline, thread); ASSERT(status == 0); if (status != 0) abort(); } } void _al_thread_create_with_stacksize(_AL_THREAD* thread, void (*proc)(_AL_THREAD*, void*), void *arg, size_t stacksize) { #ifndef __GNU__ ASSERT(stacksize >= PTHREAD_STACK_MIN); #endif ASSERT(thread); ASSERT(proc); { int status; pthread_mutex_init(&thread->mutex, NULL); thread->should_stop = false; thread->proc = proc; thread->arg = arg; pthread_attr_t thread_attr; int result = 0; result = pthread_attr_init(&thread_attr); ASSERT(result == 0); // On some systems, pthread_attr_setstacksize() can fail // if stacksize is not a multiple of the system page size. result = pthread_attr_setstacksize(&thread_attr, stacksize); ASSERT(result == 0); status = pthread_create(&thread->thread, &thread_attr, thread_proc_trampoline, thread); ASSERT(status == 0); if (status != 0) abort(); } } void _al_thread_set_should_stop(_AL_THREAD *thread) { ASSERT(thread); pthread_mutex_lock(&thread->mutex); { thread->should_stop = true; } pthread_mutex_unlock(&thread->mutex); } void _al_thread_join(_AL_THREAD *thread) { ASSERT(thread); _al_thread_set_should_stop(thread); pthread_join(thread->thread, NULL); pthread_mutex_destroy(&thread->mutex); } void _al_thread_detach(_AL_THREAD *thread) { ASSERT(thread); pthread_mutex_destroy(&thread->mutex); pthread_detach(thread->thread); } /* mutexes */ void _al_mutex_init(_AL_MUTEX *mutex) { ASSERT(mutex); pthread_mutex_init(&mutex->mutex, NULL); mutex->inited = true; } void _al_mutex_init_recursive(_AL_MUTEX *mutex) { pthread_mutexattr_t attr; ASSERT(mutex); pthread_mutexattr_init(&attr); if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == EINVAL) { pthread_mutexattr_destroy(&attr); abort(); /* XXX */ } pthread_mutex_init(&mutex->mutex, &attr); mutex->inited = true; pthread_mutexattr_destroy(&attr); } void _al_mutex_destroy(_AL_MUTEX *mutex) { ASSERT(mutex); if (mutex->inited) { pthread_mutex_destroy(&mutex->mutex); mutex->inited = false; } } /* condition variables */ /* most of the condition variable implementation is actually inline */ int _al_cond_timedwait(_AL_COND *cond, _AL_MUTEX *mutex, const ALLEGRO_TIMEOUT *timeout) { ALLEGRO_TIMEOUT_UNIX *unix_timeout = (ALLEGRO_TIMEOUT_UNIX *) timeout; int retcode; retcode = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &unix_timeout->abstime); return (retcode == ETIMEDOUT) ? -1 : 0; } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ allegro5-5.2.10.1/src/utf8.c000066400000000000000000000553311473414355200153100ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * UTF-8 string handling functions. * * By Peter Wang. * * See LICENSE.txt for copyright information. */ #include #include "allegro5/allegro.h" #include "allegro5/utf8.h" #include "allegro5/internal/bstrlib.h" #include "allegro5/internal/aintern.h" ALLEGRO_STATIC_ASSERT(utf8, sizeof(ALLEGRO_USTR_INFO) >= sizeof(struct _al_tagbstring)); #ifdef ALLEGRO_MSVC #pragma warning (disable: 4066) #endif #ifndef ALLEGRO_HAVE_VA_COPY /* If va_copy() is not defined we assume that a simple assignment suffices. * From a few web searches, this appears to be true for MSVC 7. */ #define va_copy(a, b) ((a) = (b)) #endif #define IS_SINGLE_BYTE(c) (((unsigned)(c) & 0x80) == 0) #define IS_LEAD_BYTE(c) (((unsigned)(c) - 0xC0) < 0x3E) #define IS_TRAIL_BYTE(c) (((unsigned)(c) & 0xC0) == 0x80) static bool all_ascii(const ALLEGRO_USTR *us) { const unsigned char *data = (const unsigned char *) _al_bdata(us); int size = _al_blength(us); while (size-- > 0) { if (*data > 127) return false; data++; } return true; } /* Function: al_ustr_new */ ALLEGRO_USTR *al_ustr_new(const char *s) { return _al_bfromcstr(s); } /* Function: al_ustr_new_from_buffer */ ALLEGRO_USTR *al_ustr_new_from_buffer(const char *s, size_t size) { return _al_blk2bstr(s, size); } /* Function: al_ustr_newf */ ALLEGRO_USTR *al_ustr_newf(const char *fmt, ...) { ALLEGRO_USTR *us; va_list ap; us = al_ustr_new(""); va_start(ap, fmt); al_ustr_vappendf(us, fmt, ap); va_end(ap); return us; } /* Function: al_ustr_free */ void al_ustr_free(ALLEGRO_USTR *us) { _al_bdestroy(us); } /* Function: al_cstr */ const char *al_cstr(const ALLEGRO_USTR *us) { /* May or may not be NUL terminated. */ return _al_bdata(us); } /* Function: al_ustr_to_buffer */ void al_ustr_to_buffer(const ALLEGRO_USTR *us, char *buffer, int size) { int need; if (size <= 0) return; /* add 1 for terminating 0 byte */ need = _al_blength(us) + 1; if (size > need) size = need; _al_sane_strncpy(buffer, _al_bdata(us), size); } /* Function: al_cstr_dup */ char *al_cstr_dup(const ALLEGRO_USTR *us) { return _al_bstr2cstr(us, '\0'); } /* Function: al_ustr_dup */ ALLEGRO_USTR *al_ustr_dup(const ALLEGRO_USTR *us) { return _al_bstrcpy(us); } /* Function: al_ustr_dup_substr */ ALLEGRO_USTR *al_ustr_dup_substr(const ALLEGRO_USTR *us, int start_pos, int end_pos) { return _al_bmidstr(us, start_pos, end_pos - start_pos); } /* Function: al_ustr_empty_string */ const ALLEGRO_USTR *al_ustr_empty_string(void) { static struct _al_tagbstring empty = _al_bsStatic(""); return ∅ } /* Function: al_ref_cstr */ const ALLEGRO_USTR *al_ref_cstr(ALLEGRO_USTR_INFO *info, const char *s) { struct _al_tagbstring *tb = (struct _al_tagbstring *) info; ASSERT(info); ASSERT(s); _al_btfromcstr(*tb, s); return tb; } /* Function: al_ref_buffer */ const ALLEGRO_USTR *al_ref_buffer(ALLEGRO_USTR_INFO *info, const char *s, size_t size) { struct _al_tagbstring *tb = (struct _al_tagbstring *) info; ASSERT(s); _al_blk2tbstr(*tb, s, size); return tb; } /* Function: al_ref_ustr */ const ALLEGRO_USTR *al_ref_ustr(ALLEGRO_USTR_INFO *info, const ALLEGRO_USTR *us, int start_pos, int end_pos) { struct _al_tagbstring *tb = (struct _al_tagbstring *) info; _al_bmid2tbstr(*tb, us, start_pos, end_pos - start_pos); return tb; } /* Function: al_ref_info */ const ALLEGRO_USTR *al_ref_info(const ALLEGRO_USTR_INFO *info) { return info; } /* Function: al_ustr_size */ size_t al_ustr_size(const ALLEGRO_USTR *us) { return _al_blength(us); } /* Function: al_ustr_length */ size_t al_ustr_length(const ALLEGRO_USTR *us) { int pos = 0; int c = 0; while (al_ustr_next(us, &pos)) c++; return c; } /* Function: al_ustr_offset */ int al_ustr_offset(const ALLEGRO_USTR *us, int index) { int pos = 0; if (index < 0) index += al_ustr_length(us); while (index-- > 0) { if (!al_ustr_next(us, &pos)) return pos; } return pos; } /* Function: al_ustr_next */ bool al_ustr_next(const ALLEGRO_USTR *us, int *pos) { const unsigned char *data = (const unsigned char *) _al_bdata(us); int size = _al_blength(us); int c; if (*pos >= size) { return false; } while (++(*pos) < size) { c = data[*pos]; if (IS_SINGLE_BYTE(c) || IS_LEAD_BYTE(c)) break; } return true; } /* Function: al_ustr_prev */ bool al_ustr_prev(const ALLEGRO_USTR *us, int *pos) { const unsigned char *data = (const unsigned char *) _al_bdata(us); int c; if (!data) return false; if (*pos <= 0) return false; while (*pos > 0) { (*pos)--; c = data[*pos]; if (IS_SINGLE_BYTE(c) || IS_LEAD_BYTE(c)) break; } return true; } /* Function: al_ustr_get */ int32_t al_ustr_get(const ALLEGRO_USTR *ub, int pos) { int32_t c; int remain; int32_t minc; const unsigned char *data; c = _al_bchare(ub, pos, -1); if (c < 0) { /* Out of bounds. */ al_set_errno(ERANGE); return -1; } if (c <= 0x7F) { /* Plain ASCII. */ return c; } if (c <= 0xC1) { /* Trailing byte of multi-byte sequence or an overlong encoding for * code point <= 127. */ al_set_errno(EILSEQ); return -2; } if (c <= 0xDF) { /* 2-byte sequence. */ c &= 0x1F; remain = 1; minc = 0x80; } else if (c <= 0xEF) { /* 3-byte sequence. */ c &= 0x0F; remain = 2; minc = 0x800; } else if (c <= 0xF4) { /* 4-byte sequence. */ c &= 0x07; remain = 3; minc = 0x10000; } else { /* Otherwise invalid. */ al_set_errno(EILSEQ); return -2; } if (pos + remain > _al_blength(ub)) { al_set_errno(EILSEQ); return -2; } data = (const unsigned char *) _al_bdata(ub); while (remain--) { int d = data[++pos]; if (!IS_TRAIL_BYTE(d)) { al_set_errno(EILSEQ); return -2; } c = (c << 6) | (d & 0x3F); } /* Check for overlong forms, which could be used to bypass security * validations. We could also check code points aren't above U+10FFFF or in * the surrogate ranges, but we don't. */ if (c < minc) { al_set_errno(EILSEQ); return -2; } return c; } /* Function: al_ustr_get_next */ int32_t al_ustr_get_next(const ALLEGRO_USTR *us, int *pos) { int32_t c = al_ustr_get(us, *pos); if (c >= 0) { (*pos) += al_utf8_width(c); return c; } if (c == -1) { /* Past end. */ return c; } /* Some invalid byte sequence. */ al_ustr_next(us, pos); return c; } /* Function: al_ustr_prev_get */ int32_t al_ustr_prev_get(const ALLEGRO_USTR *us, int *pos) { if (al_ustr_prev(us, pos)) { return al_ustr_get(us, *pos); } /* Past beginning. */ return -1; } /* Function: al_ustr_insert */ bool al_ustr_insert(ALLEGRO_USTR *us1, int pos, const ALLEGRO_USTR *us2) { return _al_binsert(us1, pos, us2, '\0') == _AL_BSTR_OK; } /* Function: al_ustr_insert_cstr */ bool al_ustr_insert_cstr(ALLEGRO_USTR *us, int pos, const char *s) { ALLEGRO_USTR_INFO info; return al_ustr_insert(us, pos, al_ref_cstr(&info, s)); } /* Function: al_ustr_insert_chr */ size_t al_ustr_insert_chr(ALLEGRO_USTR *us, int pos, int32_t c) { uint32_t uc = c; size_t sz; if (uc < 128) { return (_al_binsertch(us, pos, 1, uc) == _AL_BSTR_OK) ? 1 : 0; } sz = al_utf8_width(c); if (_al_binsertch(us, pos, sz, '\0') == _AL_BSTR_OK) { char* data = _al_bdataofs(us, pos); if (data) return al_utf8_encode(data, c); else return 0; } return 0; } /* Function: al_ustr_append */ bool al_ustr_append(ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2) { return _al_bconcat(us1, us2) == _AL_BSTR_OK; } /* Function: al_ustr_append_cstr */ bool al_ustr_append_cstr(ALLEGRO_USTR *us, const char *s) { return _al_bcatcstr(us, s) == _AL_BSTR_OK; } /* Function: al_ustr_append_chr */ size_t al_ustr_append_chr(ALLEGRO_USTR *us, int32_t c) { uint32_t uc = c; if (uc < 128) { return (_al_bconchar(us, uc) == _AL_BSTR_OK) ? 1 : 0; } return al_ustr_insert_chr(us, al_ustr_size(us), c); } /* Function: al_ustr_appendf */ bool al_ustr_appendf(ALLEGRO_USTR *us, const char *fmt, ...) { va_list ap; bool rc; va_start(ap, fmt); rc = al_ustr_vappendf(us, fmt, ap); va_end(ap); return rc; } /* Function: al_ustr_vappendf */ bool al_ustr_vappendf(ALLEGRO_USTR *us, const char *fmt, va_list ap) { va_list arglist; int sz; int rc; #ifdef DEBUGMODE /* Exercise resizing logic more often. */ sz = 1; #else sz = 128; #endif for (;;) { /* Make a copy of the argument list as vsnprintf() may clobber it. */ va_copy(arglist, ap); rc = _al_bvcformata(us, sz, fmt, arglist); va_end(arglist); if (rc >= 0) { return true; } if (rc == _AL_BSTR_ERR) { /* A real error? */ return false; } /* Increase size */ sz = -rc; } } /* Function: al_ustr_remove_chr */ bool al_ustr_remove_chr(ALLEGRO_USTR *us, int pos) { int32_t c; size_t w; c = al_ustr_get(us, pos); if (c < 0) return false; w = al_utf8_width(c); return _al_bdelete(us, pos, w) == _AL_BSTR_OK; } /* Function: al_ustr_remove_range */ bool al_ustr_remove_range(ALLEGRO_USTR *us, int start_pos, int end_pos) { return _al_bdelete(us, start_pos, end_pos - start_pos) == _AL_BSTR_OK; } /* Function: al_ustr_truncate */ bool al_ustr_truncate(ALLEGRO_USTR *us, int start_pos) { return _al_btrunc(us, start_pos) == _AL_BSTR_OK; } /* Function: al_ustr_ltrim_ws */ bool al_ustr_ltrim_ws(ALLEGRO_USTR *us) { return _al_bltrimws(us) == _AL_BSTR_OK; } /* Function: al_ustr_rtrim_ws */ bool al_ustr_rtrim_ws(ALLEGRO_USTR *us) { return _al_brtrimws(us) == _AL_BSTR_OK; } /* Function: al_ustr_trim_ws */ bool al_ustr_trim_ws(ALLEGRO_USTR *us) { return _al_btrimws(us) == _AL_BSTR_OK; } /* Function: al_ustr_assign */ bool al_ustr_assign(ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2) { return _al_bassign(us1, us2) == _AL_BSTR_OK; } /* Function: al_ustr_assign_substr */ bool al_ustr_assign_substr(ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2, int start_pos, int end_pos) { int rc = _al_bassignmidstr(us1, us2, start_pos, end_pos - start_pos); return rc == _AL_BSTR_OK; } /* Function: al_ustr_assign_cstr */ bool al_ustr_assign_cstr(ALLEGRO_USTR *us1, const char *s) { return _al_bassigncstr(us1, s) == _AL_BSTR_OK; } /* Function: al_ustr_set_chr */ size_t al_ustr_set_chr(ALLEGRO_USTR *us, int start_pos, int32_t c) { int32_t oldc; size_t oldw; size_t neww; int rc; oldc = al_ustr_get(us, start_pos); if (oldc == -2) return 0; oldw = al_utf8_width(oldc); neww = al_utf8_width(c); if (neww == 0) return 0; if (oldw > neww) rc = _al_bdelete(us, start_pos, oldw - neww); else if (neww > oldw) rc = _al_binsertch(us, start_pos, neww - oldw, '\0'); else rc = _AL_BSTR_OK; if (rc == _AL_BSTR_OK) { char* data = _al_bdataofs(us, start_pos); if (data) { return al_utf8_encode(data, c); } else { return 0; } } else { return 0; } } /* Function: al_ustr_replace_range */ bool al_ustr_replace_range(ALLEGRO_USTR *us1, int start_pos1, int end_pos1, const ALLEGRO_USTR *us2) { return _al_breplace(us1, start_pos1, end_pos1 - start_pos1, us2, '\0') == _AL_BSTR_OK; } /* Function: al_ustr_find_chr */ int al_ustr_find_chr(const ALLEGRO_USTR *us, int start_pos, int32_t c) { char encc[4]; size_t sizec; struct _al_tagbstring enctb; int rc; /* Fast path for ASCII characters. */ if (c < 128) { rc = _al_bstrchrp(us, c, start_pos); return (rc == _AL_BSTR_ERR) ? -1 : rc; } /* Non-ASCII. We can simply encode the character into a string and search * for that. */ sizec = al_utf8_encode(encc, c); if (!sizec) { al_set_errno(EINVAL); return -1; /* error */ } _al_blk2tbstr(enctb, encc, sizec); rc = _al_binstr(us, start_pos, &enctb); return (rc == _AL_BSTR_ERR) ? -1 : rc; } /* Function: al_ustr_rfind_chr */ int al_ustr_rfind_chr(const ALLEGRO_USTR *us, int end_pos, int32_t c) { char encc[4]; size_t sizec; struct _al_tagbstring enctb; int rc; /* Fast path for ASCII characters. */ if (c < 128) { rc = _al_bstrrchrp(us, c, end_pos - 1); return (rc == _AL_BSTR_ERR) ? -1 : rc; } /* Non-ASCII. We can simply encode the character into a string and search * for that. */ sizec = al_utf8_encode(encc, c); if (!sizec) { al_set_errno(EINVAL); return -1; /* error */ } _al_blk2tbstr(enctb, encc, sizec); rc = _al_binstrr(us, end_pos - sizec, &enctb); return (rc == _AL_BSTR_ERR) ? -1 : rc; } /* Function: al_ustr_find_set */ int al_ustr_find_set(const ALLEGRO_USTR *us, int start_pos, const ALLEGRO_USTR *accept) { int rc; int32_t c, d; int pos; int set_pos; /* Fast path for ASCII characters. */ if (all_ascii(accept)) { rc = _al_binchr(us, start_pos, accept); return (rc == _AL_BSTR_ERR) ? -1 : rc; } /* Non-ASCII. */ pos = 0; while ((c = al_ustr_get(us, pos)) != -1) { if (c == -2) { /* Invalid byte sequence. */ pos++; continue; } set_pos = 0; while ((d = al_ustr_get_next(accept, &set_pos)) != -1) { if (c == d) return pos; } pos += al_utf8_width(c); } return -1; } /* Function: al_ustr_find_set_cstr */ int al_ustr_find_set_cstr(const ALLEGRO_USTR *us, int start_pos, const char *accept) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *accept_us = al_ref_cstr(&info, accept); return al_ustr_find_set(us, start_pos, accept_us); } /* Function: al_ustr_find_cset */ int al_ustr_find_cset(const ALLEGRO_USTR *us, int start_pos, const ALLEGRO_USTR *reject) { int rc; int32_t c, d; int pos; int set_pos; /* Fast path for ASCII characters. */ if (all_ascii(reject)) { rc = _al_bninchr(us, start_pos, reject); return (rc == _AL_BSTR_ERR) ? -1 : rc; } /* Non-ASCII. */ pos = 0; while ((c = al_ustr_get(us, pos)) != -1) { if (c == -2) { /* Invalid byte sequence. */ pos++; continue; } set_pos = 0; while ((d = al_ustr_get_next(reject, &set_pos)) != -1) { if (c == d) break; } if (d == -1) { return pos; } pos += al_utf8_width(c); } return -1; } /* Function: al_ustr_find_cset_cstr */ int al_ustr_find_cset_cstr(const ALLEGRO_USTR *us, int start_pos, const char *reject) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *reject_us = al_ref_cstr(&info, reject); return al_ustr_find_cset(us, start_pos, reject_us); } /* Function: al_ustr_find_str */ int al_ustr_find_str(const ALLEGRO_USTR *haystack, int start_pos, const ALLEGRO_USTR *needle) { int rc = _al_binstr(haystack, start_pos, needle); return (rc == _AL_BSTR_ERR) ? -1 : rc; } /* Function: al_ustr_find_cstr */ int al_ustr_find_cstr(const ALLEGRO_USTR *haystack, int start_pos, const char *needle) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *needle_us = al_ref_cstr(&info, needle); return al_ustr_find_str(haystack, start_pos, needle_us); } /* Function: al_ustr_rfind_str */ int al_ustr_rfind_str(const ALLEGRO_USTR *haystack, int end_pos, const ALLEGRO_USTR *needle) { int rc = _al_binstrr(haystack, end_pos - _al_blength(needle), needle); return (rc == _AL_BSTR_ERR) ? -1 : rc; } /* Function: al_ustr_rfind_cstr */ int al_ustr_rfind_cstr(const ALLEGRO_USTR *haystack, int end_pos, const char *needle) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *needle_us = al_ref_cstr(&info, needle); return al_ustr_rfind_str(haystack, end_pos, needle_us); } /* Function: al_ustr_find_replace */ bool al_ustr_find_replace(ALLEGRO_USTR *us, int start_pos, const ALLEGRO_USTR *find, const ALLEGRO_USTR *replace) { return _al_bfindreplace(us, find, replace, start_pos) == _AL_BSTR_OK; } /* Function: al_ustr_find_replace_cstr */ bool al_ustr_find_replace_cstr(ALLEGRO_USTR *us, int start_pos, const char *find, const char *replace) { ALLEGRO_USTR_INFO find_info; ALLEGRO_USTR_INFO repl_info; const ALLEGRO_USTR *find_us = al_ref_cstr(&find_info, find); const ALLEGRO_USTR *repl_us = al_ref_cstr(&repl_info, replace); return al_ustr_find_replace(us, start_pos, find_us, repl_us); } /* Function: al_ustr_equal */ bool al_ustr_equal(const ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2) { return _al_biseq(us1, us2) == 1; } /* Function: al_ustr_compare */ int al_ustr_compare(const ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2) { int pos1 = 0; int pos2 = 0; for (;;) { int32_t c1 = al_ustr_get_next(us1, &pos1); int32_t c2 = al_ustr_get_next(us2, &pos2); if (c1 != c2) { /* This happens to work even when one of c1 or c2 is -1. */ return c1 - c2; } if (c1 == -1) /* == c2 */ return 0; } } /* Function: al_ustr_ncompare */ int al_ustr_ncompare(const ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2, int n) { int pos1 = 0; int pos2 = 0; if (n <= 0) return 0; for (;;) { int32_t c1 = al_ustr_get_next(us1, &pos1); int32_t c2 = al_ustr_get_next(us2, &pos2); if (c1 != c2) { /* This happens to work even when one of c1 or c2 is -1. */ return c1 - c2; } if ((c1 == -1) || (--n <= 0)) return 0; } } /* Function: al_ustr_has_prefix */ bool al_ustr_has_prefix(const ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2) { return 0 == _al_bstrncmp(us1, us2, _al_blength(us2)); } /* Function: al_ustr_has_prefix_cstr */ bool al_ustr_has_prefix_cstr(const ALLEGRO_USTR *us1, const char *s2) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us2 = al_ref_cstr(&info, s2); return al_ustr_has_prefix(us1, us2); } /* Function: al_ustr_has_suffix */ bool al_ustr_has_suffix(const ALLEGRO_USTR *us1, const ALLEGRO_USTR *us2) { struct _al_tagbstring tb1; int pos; pos = _al_blength(us1) - _al_blength(us2); _al_bmid2tbstr(tb1, us1, pos, INT_MAX); return _al_biseq(&tb1, us2); } /* Function: al_ustr_has_suffix_cstr */ bool al_ustr_has_suffix_cstr(const ALLEGRO_USTR *us1, const char *s2) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us2 = al_ref_cstr(&info, s2); return al_ustr_has_suffix(us1, us2); } /* Function: al_utf8_width */ size_t al_utf8_width(int32_t c) { /* So we don't need to check for negative values nor use unsigned ints * in the interface, which are a pain. */ uint32_t uc = c; if (uc <= 0x7f) return 1; if (uc <= 0x7ff) return 2; if (uc <= 0xffff) return 3; if (uc <= 0x10ffff) return 4; /* The rest are illegal. */ return 0; } /* Function: al_utf8_encode */ size_t al_utf8_encode(char s[], int32_t c) { uint32_t uc = c; if (uc <= 0x7f) { s[0] = uc; return 1; } if (uc <= 0x7ff) { s[0] = 0xC0 | ((uc >> 6) & 0x1F); s[1] = 0x80 | (uc & 0x3F); return 2; } if (uc <= 0xffff) { s[0] = 0xE0 | ((uc >> 12) & 0x0F); s[1] = 0x80 | ((uc >> 6) & 0x3F); s[2] = 0x80 | (uc & 0x3F); return 3; } if (uc <= 0x10ffff) { s[0] = 0xF0 | ((uc >> 18) & 0x07); s[1] = 0x80 | ((uc >> 12) & 0x3F); s[2] = 0x80 | ((uc >> 6) & 0x3F); s[3] = 0x80 | (uc & 0x3F); return 4; } /* Otherwise is illegal. */ return 0; } /* Function: al_utf16_width */ size_t al_utf16_width(int c) { /* So we don't need to check for negative values nor use unsigned ints * in the interface, which are a pain. */ uint32_t uc = c; /* We do not check for invalid code points. */ if (uc <= 0xffff) return 2; if (uc <= 0x10ffff) return 4; /* The rest are illegal. */ return 0; } /* Function: al_utf16_encode */ size_t al_utf16_encode(uint16_t s[], int32_t c) { uint32_t uc = c; if (uc <= 0xffff) { /* Note: We always assume the native endianness here. */ s[0] = uc; return 2; } if (uc <= 0x10ffff) { uint32_t u_ = uc - 0x10000; /* Note: We always assume the native endianness here. */ s[0] = 0xd800 | (u_ >> 10); s[1] = 0xdc00 | (u_ & 0x3ff); return 4; } /* Otherwise is illegal. */ return 0; } static size_t _al_utf16_get(uint16_t const *s, int n, int *c) { if (s[0] < 0xd800 || s[0] > 0xdfff) { *c = s[0]; return 1; } if (n < 2) return 0; *c = 0x10000 | ((s[0] & 0x3ff) << 10) | (s[1] & 0x3ff); return 2; } /* Function: al_ustr_new_from_utf16 */ ALLEGRO_USTR *al_ustr_new_from_utf16(uint16_t const *s) { unsigned int i = 0; ALLEGRO_USTR *ustr = al_ustr_new(""); while (1) { int c; /* We expect the passed string to be 0 terminated, so there are * always 2 words available. */ size_t n = _al_utf16_get(s + i, 2, &c); /* Note: The string already is 0 terminated. */ if (c == 0) break; al_ustr_append_chr(ustr, c); i += n; } return ustr; } /* Function: al_ustr_size_utf16 */ size_t al_ustr_size_utf16(const ALLEGRO_USTR *us) { int pos = 0; size_t sz = 0; while (1) { int32_t c = al_ustr_get_next(us, &pos); if (c < 0) break; sz += al_utf16_width(c); } /* Size of terminating 0 character - al_ustr_get_next will not * return it. */ sz += 2; return sz; } /* Function: al_ustr_encode_utf16 */ size_t al_ustr_encode_utf16(const ALLEGRO_USTR *us, uint16_t *s, size_t n) { int pos = 0; size_t i = 0; while (1) { /* Used to hold one encoded UTF-16 character. */ uint16_t encoded[2] = {0, 0}; size_t sz; int32_t c = al_ustr_get_next(us, &pos); if (c < 0) break; sz = al_utf16_encode(encoded, c); /* Need two bytes for terminating 0. */ if (i * 2 + sz > n - 2) break; s[i++] = encoded[0]; if (sz == 4) s[i++] = encoded[1]; } /* Append terminating 0 - al_ustr_get_next withheld it. */ if (i * 2 + 1 < n) s[i++] = 0; return i * 2; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/000077500000000000000000000000001473414355200150445ustar00rootroot00000000000000allegro5-5.2.10.1/src/win/d3d.h000066400000000000000000000051031473414355200156660ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_direct3d.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_direct3d.h" #include "allegro5/internal/aintern_shader.h" #include "allegro5/platform/aintwin.h" #include "allegro5/platform/alplatf.h" #include /* The MinGW copy of d3d9.h doesn't currently define this constant. */ #ifndef D3D9b_SDK_VERSION #ifdef D3D_DEBUG_INFO #define D3D9b_SDK_VERSION (31 | 0x80000000) #else #define D3D9b_SDK_VERSION 31 #endif #endif #ifdef __cplusplus extern "C" { #endif /* Flexible vertex formats */ // Fixed pipeline vertex #define D3DFVF_FIXED_VERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1) // Programmable pipeline vertex #define D3DFVF_ALLEGRO_VERTEX (D3DFVF_XYZ | D3DFVF_TEX2 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE4(1)) // Vertex structure when using fixed pipeline (otherwise it's ALLEGRO_VERTEX) struct D3D_FIXED_VERTEX { float x, y, z; D3DCOLOR color; float u, v; }; typedef struct ALLEGRO_SYSTEM_D3D ALLEGRO_SYSTEM_D3D; extern LPDIRECT3D9 _al_d3d; ALLEGRO_BITMAP_INTERFACE *_al_bitmap_d3d_driver(void); int _al_pixel_format_to_d3d(int format); int _al_d3d_format_to_allegro(int d3d_fmt); bool _al_d3d_render_to_texture_supported(void); void _al_d3d_set_bitmap_clip(ALLEGRO_BITMAP *bitmap); void _al_d3d_release_default_pool_textures(ALLEGRO_DISPLAY *display); void _al_d3d_refresh_texture_memory(ALLEGRO_DISPLAY *display); bool _al_d3d_recreate_bitmap_textures(ALLEGRO_DISPLAY_D3D *disp); void _al_d3d_set_bitmap_clip(ALLEGRO_BITMAP *bitmap); bool _al_d3d_supports_separate_alpha_blend(ALLEGRO_DISPLAY *display); void _al_d3d_bmp_destroy(void); void _al_d3d_generate_display_format_list(void); int _al_d3d_num_display_formats(void); void _al_d3d_get_nth_format(int i, int *allegro, D3DFORMAT *d3d); void _al_d3d_score_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref); void _al_d3d_destroy_display_format_list(void); ALLEGRO_EXTRA_DISPLAY_SETTINGS *_al_d3d_get_display_settings(int i); void _al_d3d_resort_display_settings(void); #ifdef ALLEGRO_CFG_SHADER_HLSL void _al_d3d_on_lost_shaders(ALLEGRO_DISPLAY *display); void _al_d3d_on_reset_shaders(ALLEGRO_DISPLAY *display); void _al_d3d_init_shaders(void); void _al_d3d_shutdown_shaders(void); #endif extern ALLEGRO_MUTEX *_al_d3d_lost_device_mutex; /* Helper to get smallest fitting power of two. */ AL_INLINE_STATIC(int, pot, (int x), { int y = 1; while (y < x) y *= 2; return y; }) #ifdef __cplusplus } #endif allegro5-5.2.10.1/src/win/d3d_bmp.cpp000066400000000000000000000767041473414355200170760ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Direct3D bitmap driver * * By Trent Gamblin. * */ #include #include #include #include "allegro5/allegro.h" #include "allegro5/system.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_memblit.h" #include "allegro5/internal/aintern_pixels.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_tri_soft.h" // For ALLEGRO_VERTEX #include "allegro5/platform/aintwin.h" #include "d3d.h" ALLEGRO_DEBUG_CHANNEL("d3d") static ALLEGRO_BITMAP_INTERFACE *vt; // C++ needs to cast void pointers #define get_extra(b) ((ALLEGRO_BITMAP_EXTRA_D3D *)\ (b->parent ? b->parent->extra : b->extra)) static bool convert_compressed(LPDIRECT3DTEXTURE9 dest, LPDIRECT3DTEXTURE9 src, int x, int y, int width, int height) { #ifdef ALLEGRO_CFG_D3DX9 bool ok = true; LPDIRECT3DSURFACE9 dest_texture_surface = NULL; LPDIRECT3DSURFACE9 src_texture_surface = NULL; if (dest->GetSurfaceLevel(0, &dest_texture_surface) != D3D_OK) { ALLEGRO_ERROR("convert_compressed: GetSurfaceLevel failed on dest.\n"); ok = false; } if (ok && src->GetSurfaceLevel(0, &src_texture_surface) != D3D_OK) { ALLEGRO_ERROR("convert_compressed: GetSurfaceLevel failed on src.\n"); ok = false; } RECT rect; rect.left = x; rect.top = y; rect.right = x + width; rect.bottom = y + height; if (ok && _al_imp_D3DXLoadSurfaceFromSurface && _al_imp_D3DXLoadSurfaceFromSurface(dest_texture_surface, NULL, &rect, src_texture_surface, NULL, &rect, D3DX_FILTER_NONE, 0) != D3D_OK) { ALLEGRO_ERROR("convert_compressed: D3DXLoadSurfaceFromSurface failed.\n"); ok = false; } int i; if (src_texture_surface) { if ((i = src_texture_surface->Release()) != 0) { ALLEGRO_DEBUG("convert_compressed (src) ref count == %d\n", i); } } if (dest_texture_surface) { if ((i = dest_texture_surface->Release()) != 0) { // This can be non-zero ALLEGRO_DEBUG("convert_compressed (dest) ref count == %d\n", i); } } return ok; #else (void)dest; (void)src; (void)x; (void)y; (void)width; (void)height; return false; #endif } /* Function: al_get_d3d_texture_size */ bool al_get_d3d_texture_size(ALLEGRO_BITMAP *bitmap, int *width, int *height) { int bitmap_flags = al_get_bitmap_flags(bitmap); ASSERT(bitmap); ASSERT(width); ASSERT(height); if (!(bitmap_flags & _ALLEGRO_INTERNAL_OPENGL) && !(bitmap_flags & ALLEGRO_MEMORY_BITMAP)) { ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap); *width = d3d_bmp->texture_w; *height = d3d_bmp->texture_h; return true; } else { *width = 0; *height = 0; return false; } } void _al_d3d_bmp_destroy(void) { al_free(vt); vt = NULL; } static INLINE void transform_vertex(float* x, float* y, float* z) { al_transform_coordinates_3d(al_get_current_transform(), x, y, z); } /* * Draw a textured quad */ static void d3d_draw_textured_quad( ALLEGRO_DISPLAY_D3D *disp, ALLEGRO_BITMAP *bmp, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, int flags) { float right; float bottom; float tu_start; float tv_start; float tu_end; float tv_end; int texture_w; int texture_h; ALLEGRO_BITMAP_EXTRA_D3D *extra = get_extra(bmp); const float z = 0.0f; ALLEGRO_DISPLAY* aldisp = (ALLEGRO_DISPLAY*)disp; if (aldisp->num_cache_vertices != 0 && (uintptr_t)bmp != aldisp->cache_texture) { aldisp->vt->flush_vertex_cache(aldisp); } aldisp->cache_texture = (uintptr_t)bmp; right = sw; bottom = sh; texture_w = extra->texture_w; texture_h = extra->texture_h; tu_start = sx / texture_w; tv_start = sy / texture_h; tu_end = sw / texture_w + tu_start; tv_end = sh / texture_h + tv_start; if (flags & ALLEGRO_FLIP_HORIZONTAL) { float temp = tu_start; tu_start = tu_end; tu_end = temp; } if (flags & ALLEGRO_FLIP_VERTICAL) { float temp = tv_start; tv_start = tv_end; tv_end = temp; } #define ALLEGRO_COLOR_TO_D3D(c) D3DCOLOR_COLORVALUE(c.r, c.g, c.b, c.a) #define SET(f) \ vertices[0].x = 0; \ vertices[0].y = 0; \ vertices[0].z = z; \ vertices[0].color = f(tint); \ vertices[0].u = tu_start; \ vertices[0].v = tv_start; \ \ vertices[1].x = right; \ vertices[1].y = 0; \ vertices[1].z = z; \ vertices[1].color = f(tint); \ vertices[1].u = tu_end; \ vertices[1].v = tv_start; \ \ vertices[2].x = right; \ vertices[2].y = bottom; \ vertices[2].z = z; \ vertices[2].color = f(tint); \ vertices[2].u = tu_end; \ vertices[2].v = tv_end; \ \ vertices[5].x = 0; \ vertices[5].y = bottom; \ vertices[5].z = z; \ vertices[5].color = f(tint); \ vertices[5].u = tu_start; \ vertices[5].v = tv_end; \ \ if (aldisp->cache_enabled) { \ transform_vertex(&vertices[0].x, &vertices[0].y, &vertices[0].z); \ transform_vertex(&vertices[1].x, &vertices[1].y, &vertices[1].z); \ transform_vertex(&vertices[2].x, &vertices[2].y, &vertices[2].z); \ transform_vertex(&vertices[5].x, &vertices[5].y, &vertices[5].z); \ } \ \ vertices[3] = vertices[0]; \ vertices[4] = vertices[2]; bool pp = (aldisp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) != 0; if (pp) { ALLEGRO_VERTEX *vertices = (ALLEGRO_VERTEX *)aldisp->vt->prepare_vertex_cache(aldisp, 6); SET(ALLEGRO_COLOR) } else { D3D_FIXED_VERTEX *vertices = (D3D_FIXED_VERTEX *)aldisp->vt->prepare_vertex_cache(aldisp, 6); SET(ALLEGRO_COLOR_TO_D3D) } if (!aldisp->cache_enabled) aldisp->vt->flush_vertex_cache(aldisp); } /* Copy texture memory to bitmap->memory */ static void d3d_sync_bitmap_memory(ALLEGRO_BITMAP *bitmap) { D3DLOCKED_RECT locked_rect; ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap); LPDIRECT3DTEXTURE9 texture; int bitmap_format = al_get_bitmap_format(bitmap); if (_al_d3d_render_to_texture_supported() && !_al_pixel_format_is_compressed(bitmap_format)) texture = d3d_bmp->system_texture; else texture = d3d_bmp->video_texture; if (texture->LockRect(0, &locked_rect, NULL, 0) == D3D_OK) { int block_size = al_get_pixel_block_size(bitmap_format); int block_width = al_get_pixel_block_width(bitmap_format); int block_height = al_get_pixel_block_height(bitmap_format); int mem_pitch = _al_get_least_multiple(bitmap->w, block_width) * block_size / block_width; _al_copy_bitmap_data(locked_rect.pBits, locked_rect.Pitch, bitmap->memory, mem_pitch, 0, 0, 0, 0, _al_get_least_multiple(bitmap->w, block_width), _al_get_least_multiple(bitmap->h, block_height), bitmap_format); texture->UnlockRect(0); } else { ALLEGRO_ERROR("d3d_sync_bitmap_memory: Couldn't lock texture.\n"); } } /* Copy bitmap->memory to texture memory */ static void d3d_sync_bitmap_texture(ALLEGRO_BITMAP *bitmap, int x, int y, int width, int height) { D3DLOCKED_RECT locked_rect; RECT rect; ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap); LPDIRECT3DTEXTURE9 texture; int bitmap_format = al_get_bitmap_format(bitmap); if (bitmap->parent) return; rect.left = x; rect.top = y; rect.right = x + width; rect.bottom = y + height; if (_al_d3d_render_to_texture_supported() && !_al_pixel_format_is_compressed(bitmap_format)) texture = d3d_bmp->system_texture; else texture = d3d_bmp->video_texture; if (texture->LockRect(0, &locked_rect, &rect, 0) == D3D_OK) { int block_size = al_get_pixel_block_size(bitmap_format); int block_width = al_get_pixel_block_width(bitmap_format); int mem_pitch = _al_get_least_multiple(bitmap->w, block_width) * block_size / block_width; _al_copy_bitmap_data(bitmap->memory, mem_pitch, locked_rect.pBits, locked_rect.Pitch, x, y, 0, 0, width, height, bitmap_format); texture->UnlockRect(0); } else { ALLEGRO_ERROR("d3d_sync_bitmap_texture: Couldn't lock texture to upload.\n"); } } static void d3d_do_upload(ALLEGRO_BITMAP *bmp, int x, int y, int width, int height, bool sync_from_memory) { if (sync_from_memory) { d3d_sync_bitmap_texture(bmp, x, y, width, height); } if (_al_d3d_render_to_texture_supported() && !_al_pixel_format_is_compressed(al_get_bitmap_format(bmp))) { ALLEGRO_BITMAP_EXTRA_D3D *d3d_bitmap = get_extra(bmp); if (d3d_bitmap->display->device->UpdateTexture( (IDirect3DBaseTexture9 *)d3d_bitmap->system_texture, (IDirect3DBaseTexture9 *)d3d_bitmap->video_texture) != D3D_OK) { ALLEGRO_ERROR("d3d_do_upload: Couldn't update texture.\n"); return; } } } /* * Release all default pool textures. This must be done before * resetting the device. */ void _al_d3d_release_default_pool_textures(ALLEGRO_DISPLAY *disp) { unsigned int i; for (i = 0; i < disp->bitmaps._size; i++) { ALLEGRO_BITMAP **bptr = (ALLEGRO_BITMAP **)_al_vector_ref(&disp->bitmaps, i); ALLEGRO_BITMAP *albmp = *bptr; if ((al_get_bitmap_flags(albmp) & ALLEGRO_MEMORY_BITMAP) || (albmp->parent)) continue; ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(albmp); if (!d3d_bmp->is_backbuffer && d3d_bmp->render_target) { d3d_bmp->render_target->Release(); d3d_bmp->render_target = NULL; } if (d3d_bmp->video_texture) { d3d_bmp->video_texture->Release(); d3d_bmp->video_texture = NULL; } } } static bool d3d_create_textures(ALLEGRO_DISPLAY_D3D *disp, int w, int h, int flags, LPDIRECT3DTEXTURE9 *video_texture, LPDIRECT3DTEXTURE9 *system_texture, int video_format, int system_format) { int levels; int autogenmipmap; int err; bool compressed = _al_pixel_format_is_compressed(video_format); if (flags & ALLEGRO_MIPMAP) { /* "0" for all possible levels, required for auto mipmap generation. */ levels = 0; autogenmipmap = D3DUSAGE_AUTOGENMIPMAP; } else { levels = 1; autogenmipmap = 0; } if (_al_d3d_render_to_texture_supported()) { if (video_texture) { int usage = compressed ? 0 : D3DUSAGE_RENDERTARGET; /* XXX: Compressed video bitmaps are managed, so in principle * there is no need to manually sync them for device loss. * It is still necessary to do so for resizing purposes, * however... not sure there's any real savings to be had here. */ D3DPOOL pool = compressed ? D3DPOOL_MANAGED : D3DPOOL_DEFAULT; err = disp->device->CreateTexture(w, h, levels, usage | autogenmipmap, (D3DFORMAT)_al_pixel_format_to_d3d(video_format), pool, video_texture, NULL); if (err != D3D_OK && err != D3DOK_NOAUTOGEN) { ALLEGRO_ERROR("d3d_create_textures: Unable to create video texture.\n"); return false; } } if (system_texture) { err = disp->device->CreateTexture(w, h, 1, 0, (D3DFORMAT)_al_pixel_format_to_d3d(system_format), D3DPOOL_SYSTEMMEM, system_texture, NULL); if (err != D3D_OK) { ALLEGRO_ERROR("d3d_create_textures: Unable to create system texture.\n"); if (video_texture && (*video_texture)) { (*video_texture)->Release(); *video_texture = NULL; } return false; } } return true; } else { if (video_texture) { err = disp->device->CreateTexture(w, h, 1, 0, (D3DFORMAT)_al_pixel_format_to_d3d(video_format), D3DPOOL_MANAGED, video_texture, NULL); if (err != D3D_OK) { ALLEGRO_ERROR("d3d_create_textures: Unable to create video texture (no render-to-texture).\n"); return false; } } return true; } } static ALLEGRO_BITMAP *d3d_create_bitmap_from_surface(LPDIRECT3DSURFACE9 surface, int format, int flags) { ALLEGRO_BITMAP *bitmap; ALLEGRO_BITMAP_EXTRA_D3D *extra; D3DSURFACE_DESC desc; D3DLOCKED_RECT surf_locked_rect; D3DLOCKED_RECT sys_locked_rect; unsigned int y; ASSERT(!_al_pixel_format_is_compressed(format)); if (surface->GetDesc(&desc) != D3D_OK) { ALLEGRO_ERROR("d3d_create_bitmap_from_surface: GetDesc failed.\n"); return NULL; } if (surface->LockRect(&surf_locked_rect, 0, D3DLOCK_READONLY) != D3D_OK) { ALLEGRO_ERROR("d3d_create_bitmap_from_surface: LockRect failed.\n"); return NULL; } bitmap = _al_create_bitmap_params(al_get_current_display(), desc.Width, desc.Height, format, flags, 0, 0); if (!bitmap) { surface->UnlockRect(); return NULL; } extra = get_extra(bitmap); if (extra->system_texture->LockRect(0, &sys_locked_rect, 0, 0) != D3D_OK) { surface->UnlockRect(); al_destroy_bitmap(bitmap); ALLEGRO_ERROR("d3d_create_bitmap_from_surface: Lock system texture failed.\n"); return NULL; } for (y = 0; y < desc.Height; y++) { memcpy( ((char*)sys_locked_rect.pBits)+(sys_locked_rect.Pitch*y), ((char*)surf_locked_rect.pBits)+(surf_locked_rect.Pitch*y), desc.Width*al_get_pixel_size(format) ); } surface->UnlockRect(); extra->system_texture->UnlockRect(0); if (extra->display->device->UpdateTexture( (IDirect3DBaseTexture9 *)extra->system_texture, (IDirect3DBaseTexture9 *)extra->video_texture) != D3D_OK) { ALLEGRO_ERROR("d3d_create_bitmap_from_surface: Couldn't update texture.\n"); } return bitmap; } /* Copies video texture to system texture and bitmap->memory */ static bool _al_d3d_sync_bitmap(ALLEGRO_BITMAP *dest) { ALLEGRO_BITMAP_EXTRA_D3D *d3d_dest; LPDIRECT3DSURFACE9 system_texture_surface; LPDIRECT3DSURFACE9 video_texture_surface; bool ok; UINT i; if (!_al_d3d_render_to_texture_supported()) { ALLEGRO_ERROR("Render-to-texture not supported.\n"); return false; } if (dest->locked) { ALLEGRO_ERROR("Already locked.\n"); return false; } d3d_dest = get_extra(dest); if (d3d_dest->system_texture == NULL || d3d_dest->video_texture == NULL) { ALLEGRO_ERROR("A texture is null.\n"); return false; } if (dest->parent) { dest = dest->parent; } ok = true; system_texture_surface = NULL; video_texture_surface = NULL; if (d3d_dest->system_texture->GetSurfaceLevel( 0, &system_texture_surface) != D3D_OK) { ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetSurfaceLevel failed while updating system texture.\n"); ok = false; } if (ok && d3d_dest->video_texture->GetSurfaceLevel( 0, &video_texture_surface) != D3D_OK) { ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetSurfaceLevel failed while updating system texture.\n"); ok = false; } if (ok && d3d_dest->display->device->GetRenderTargetData( video_texture_surface, system_texture_surface) != D3D_OK) { ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetRenderTargetData failed.\n"); ok = false; } if (system_texture_surface) { if ((i = system_texture_surface->Release()) != 0) { ALLEGRO_DEBUG("_al_d3d_sync_bitmap (system) ref count == %d\n", i); } } if (video_texture_surface) { if ((i = video_texture_surface->Release()) != 0) { // This can be non-zero ALLEGRO_DEBUG("_al_d3d_sync_bitmap (video) ref count == %d\n", i); } } if (ok) { d3d_sync_bitmap_memory(dest); } return ok; } // Copy texture to system memory static void d3d_backup_dirty_bitmap(ALLEGRO_BITMAP *bitmap) { ALLEGRO_DISPLAY *display = bitmap->_display; ALLEGRO_DISPLAY_D3D *d3d_display = (ALLEGRO_DISPLAY_D3D *)display; if (d3d_display->device_lost) return; if (!_al_d3d_render_to_texture_supported()) return; al_lock_mutex(_al_d3d_lost_device_mutex); ALLEGRO_BITMAP_EXTRA_D3D *extra = get_extra(bitmap); int bitmap_flags = al_get_bitmap_flags(bitmap); if (!( (bitmap_flags & ALLEGRO_MEMORY_BITMAP) || (bitmap_flags & ALLEGRO_NO_PRESERVE_TEXTURE) || !bitmap->dirty || extra->is_backbuffer || bitmap->parent )) { if (_al_pixel_format_is_compressed(al_get_bitmap_format(bitmap))) d3d_sync_bitmap_memory(bitmap); else _al_d3d_sync_bitmap(bitmap); } bitmap->dirty = false; al_unlock_mutex(_al_d3d_lost_device_mutex); } /* * Called after the resize is done. */ bool _al_d3d_recreate_bitmap_textures(ALLEGRO_DISPLAY_D3D *disp) { unsigned int i; ALLEGRO_DISPLAY *display = (ALLEGRO_DISPLAY *)disp; for (i = 0; i < display->bitmaps._size; i++) { ALLEGRO_BITMAP **bptr = (ALLEGRO_BITMAP **)_al_vector_ref(&display->bitmaps, i); ALLEGRO_BITMAP *bmp = *bptr; ALLEGRO_BITMAP_EXTRA_D3D *extra = get_extra(bmp); if ((void *)_al_get_bitmap_display(bmp) == (void *)disp) { int block_width = al_get_pixel_block_width(al_get_bitmap_format(bmp)); int block_height = al_get_pixel_block_height(al_get_bitmap_format(bmp)); if (!d3d_create_textures(disp, extra->texture_w, extra->texture_h, al_get_bitmap_flags(bmp), &extra->video_texture, &extra->system_texture, al_get_bitmap_format(bmp), extra->system_format)) return false; d3d_do_upload(bmp, 0, 0, _al_get_least_multiple(bmp->w, block_width), _al_get_least_multiple(bmp->h, block_height), true); } } return true; } /* * Refresh the texture memory. This must be done after a device is * lost or after it is reset. */ void _al_d3d_refresh_texture_memory(ALLEGRO_DISPLAY *display) { unsigned int i; /* Refresh video hardware textures */ for (i = 0; i < display->bitmaps._size; i++) { ALLEGRO_BITMAP **bptr = (ALLEGRO_BITMAP **)_al_vector_ref(&display->bitmaps, i); ALLEGRO_BITMAP *bmp = *bptr; ALLEGRO_BITMAP_EXTRA_D3D *extra = get_extra(bmp); ALLEGRO_DISPLAY_D3D *bmps_display = (ALLEGRO_DISPLAY_D3D *)_al_get_bitmap_display(bmp); int bitmap_flags = al_get_bitmap_flags(bmp); if ((bitmap_flags & ALLEGRO_MEMORY_BITMAP) || bmp->parent) { continue; } d3d_create_textures(bmps_display, extra->texture_w, extra->texture_h, bitmap_flags, &extra->video_texture, /*&bmp->system_texture*/0, al_get_bitmap_format(bmp), 0); if (!(bitmap_flags & ALLEGRO_NO_PRESERVE_TEXTURE)) { int block_width = al_get_pixel_block_width(al_get_bitmap_format(bmp)); int block_height = al_get_pixel_block_height(al_get_bitmap_format(bmp)); d3d_sync_bitmap_texture(bmp, 0, 0, _al_get_least_multiple(bmp->w, block_width), _al_get_least_multiple(bmp->h, block_height)); if (_al_d3d_render_to_texture_supported() && !_al_pixel_format_is_compressed(al_get_bitmap_format(bmp))) { extra->display->device->UpdateTexture( (IDirect3DBaseTexture9 *)extra->system_texture, (IDirect3DBaseTexture9 *)extra->video_texture); } } } } static bool d3d_upload_bitmap(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap); ALLEGRO_SYSTEM *system = al_get_system_driver(); int bitmap_format = al_get_bitmap_format(bitmap); int system_format = d3d_bmp->system_format; int block_width = al_get_pixel_block_width(bitmap_format); int block_height = al_get_pixel_block_height(bitmap_format); int w = _al_get_least_multiple(bitmap->w, block_width); int h = _al_get_least_multiple(bitmap->h, block_height); if (d3d_bmp->display->device_lost) return false; if (d3d_bmp->initialized != true) { bool non_pow2 = al_have_d3d_non_pow2_texture_support(); bool non_square = al_have_d3d_non_square_texture_support(); if (non_pow2 && non_square) { // Any shape and size d3d_bmp->texture_w = w; d3d_bmp->texture_h = h; } else if (non_pow2) { // Must be square int max = _ALLEGRO_MAX(w, h); d3d_bmp->texture_w = max; d3d_bmp->texture_h = max; } else { // Must be POW2 d3d_bmp->texture_w = pot(w); d3d_bmp->texture_h = pot(h); } // Some cards/drivers don't like small textures if ((int)d3d_bmp->texture_w < system->min_bitmap_size) d3d_bmp->texture_w = system->min_bitmap_size; if ((int)d3d_bmp->texture_h < system->min_bitmap_size) d3d_bmp->texture_h = system->min_bitmap_size; ASSERT(d3d_bmp->texture_w % block_width == 0); ASSERT(d3d_bmp->texture_h % block_height == 0); if (d3d_bmp->video_texture == 0) if (!d3d_create_textures(d3d_bmp->display, d3d_bmp->texture_w, d3d_bmp->texture_h, al_get_bitmap_flags(bitmap), &d3d_bmp->video_texture, &d3d_bmp->system_texture, bitmap_format, system_format)) { return false; } d3d_bmp->initialized = true; } d3d_do_upload(bitmap, 0, 0, w, h, false); return true; } static void d3d_draw_bitmap_region( ALLEGRO_BITMAP *src, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, int flags) { ALLEGRO_BITMAP *dest = al_get_target_bitmap(); ALLEGRO_BITMAP_EXTRA_D3D *d3d_dest = get_extra(dest); ALLEGRO_BITMAP_EXTRA_D3D *d3d_src = get_extra(src); ASSERT(src->parent == NULL); if (!_al_d3d_render_to_texture_supported()) { _al_draw_bitmap_region_memory(src, tint, (int)sx, (int)sy, (int)sw, (int)sh, 0, 0, (int)flags); return; } if (d3d_dest->display->device_lost) return; _al_d3d_set_bitmap_clip(dest); /* For sub-bitmaps */ if (dest->parent) { dest = dest->parent; d3d_dest = get_extra(dest); } if (d3d_src->is_backbuffer) { IDirect3DSurface9 *surface; D3DSURFACE_DESC desc; if (d3d_src->display->render_target->GetDesc(&desc) != D3D_OK) { ALLEGRO_ERROR("d3d_draw_bitmap_region: GetDesc failed.\n"); return; } if (desc.MultiSampleType == D3DMULTISAMPLE_NONE) { surface = d3d_src->display->render_target; } else { RECT r; if (d3d_src->display->device->CreateRenderTarget( desc.Width, desc.Height, desc.Format, D3DMULTISAMPLE_NONE, 0, TRUE, &surface, NULL ) != D3D_OK) { ALLEGRO_ERROR( "d3d_draw_bitmap_region: CreateRenderTarget failed.\n"); return; } r.top = 0; r.left = 0; r.right = desc.Width; r.bottom = desc.Height; if (d3d_src->display->device->StretchRect( d3d_src->display->render_target, &r, surface, &r, D3DTEXF_NONE ) != D3D_OK) { ALLEGRO_ERROR("d3d_draw_bitmap_region: StretchRect failed.\n"); surface->Release(); return; } } ALLEGRO_BITMAP *tmp_bmp = d3d_create_bitmap_from_surface( surface, al_get_bitmap_format(src), al_get_bitmap_flags(src) ); if (tmp_bmp) { d3d_draw_bitmap_region(tmp_bmp, tint, sx, sy, sw, sh, flags); al_destroy_bitmap(tmp_bmp); if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) { surface->Release(); } } return; } _al_d3d_set_blender(d3d_dest->display); d3d_draw_textured_quad( d3d_dest->display, src, tint, sx, sy, sw, sh, flags); } static ALLEGRO_LOCKED_REGION *d3d_lock_region(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int format, int flags) { ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap); int bitmap_format = al_get_bitmap_format(bitmap); int system_format = d3d_bmp->system_format; if (d3d_bmp->display->device_lost) return NULL; RECT rect; DWORD Flags = flags & ALLEGRO_LOCK_READONLY ? D3DLOCK_READONLY : 0; int f = _al_get_real_pixel_format(al_get_current_display(), format); if (f < 0) { return NULL; } rect.left = x; rect.right = x + w; rect.top = y; rect.bottom = y + h; if (d3d_bmp->is_backbuffer) { ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)_al_get_bitmap_display(bitmap); if (d3d_disp->render_target->LockRect(&d3d_bmp->locked_rect, &rect, Flags) != D3D_OK) { ALLEGRO_ERROR("LockRect failed in d3d_lock_region.\n"); return NULL; } } else { LPDIRECT3DTEXTURE9 texture; if (_al_pixel_format_is_compressed(bitmap_format)) { if (!(flags & ALLEGRO_LOCK_WRITEONLY)) { if(!convert_compressed( d3d_bmp->system_texture, d3d_bmp->video_texture, x, y, w, h)) { ALLEGRO_ERROR("Could not decompress.\n"); return NULL; } } texture = d3d_bmp->system_texture; } else if (_al_d3d_render_to_texture_supported()) { /* * Sync bitmap->memory with texture */ bitmap->locked = false; if (!(flags & ALLEGRO_LOCK_WRITEONLY) && !_al_d3d_sync_bitmap(bitmap)) { return NULL; } bitmap->locked = true; texture = d3d_bmp->system_texture; } else { texture = d3d_bmp->video_texture; } if (texture->LockRect(0, &d3d_bmp->locked_rect, &rect, Flags) != D3D_OK) { ALLEGRO_ERROR("LockRect failed in d3d_lock_region.\n"); return NULL; } } if (format == ALLEGRO_PIXEL_FORMAT_ANY || system_format == format || system_format == f) { bitmap->locked_region.data = d3d_bmp->locked_rect.pBits; bitmap->locked_region.format = system_format; bitmap->locked_region.pitch = d3d_bmp->locked_rect.Pitch; bitmap->locked_region.pixel_size = al_get_pixel_size(system_format); } else { bitmap->locked_region.pitch = al_get_pixel_size(f) * w; bitmap->locked_region.data = al_malloc(bitmap->locked_region.pitch*h); bitmap->locked_region.format = f; bitmap->locked_region.pixel_size = al_get_pixel_size(f); if (!(bitmap->lock_flags & ALLEGRO_LOCK_WRITEONLY)) { _al_convert_bitmap_data( d3d_bmp->locked_rect.pBits, system_format, d3d_bmp->locked_rect.Pitch, bitmap->locked_region.data, f, bitmap->locked_region.pitch, 0, 0, 0, 0, w, h); } } return &bitmap->locked_region; } static void d3d_unlock_region(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap); int system_format = d3d_bmp->system_format; if (bitmap->locked_region.format != 0 && bitmap->locked_region.format != system_format) { if (!(bitmap->lock_flags & ALLEGRO_LOCK_READONLY)) { _al_convert_bitmap_data( bitmap->locked_region.data, bitmap->locked_region.format, bitmap->locked_region.pitch, d3d_bmp->locked_rect.pBits, system_format, d3d_bmp->locked_rect.Pitch, 0, 0, 0, 0, bitmap->lock_w, bitmap->lock_h); } al_free(bitmap->locked_region.data); } if (d3d_bmp->is_backbuffer) { ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)_al_get_bitmap_display(bitmap); d3d_disp->render_target->UnlockRect(); } else { LPDIRECT3DTEXTURE9 texture; int bitmap_format = al_get_bitmap_format(bitmap); bool compressed = _al_pixel_format_is_compressed(bitmap_format); if (_al_d3d_render_to_texture_supported() || compressed) texture = d3d_bmp->system_texture; else texture = d3d_bmp->video_texture; texture->UnlockRect(0); if (bitmap->lock_flags & ALLEGRO_LOCK_READONLY) return; if (compressed) { int block_width = al_get_pixel_block_width(bitmap_format); int block_height = al_get_pixel_block_height(bitmap_format); int xc = (bitmap->lock_x / block_width) * block_width; int yc = (bitmap->lock_y / block_height) * block_height; int wc = _al_get_least_multiple(bitmap->lock_x + bitmap->lock_w, block_width) - xc; int hc = _al_get_least_multiple(bitmap->lock_y + bitmap->lock_h, block_height) - yc; if(!convert_compressed( d3d_bmp->video_texture, d3d_bmp->system_texture, xc, yc, wc, hc)) { ALLEGRO_ERROR("Could not compress.\n"); } } else { d3d_do_upload(bitmap, bitmap->lock_x, bitmap->lock_y, bitmap->lock_w, bitmap->lock_h, false); } } } static void d3d_update_clipping_rectangle(ALLEGRO_BITMAP *bitmap) { _al_d3d_set_bitmap_clip(bitmap); } static ALLEGRO_LOCKED_REGION *d3d_lock_compressed_region( ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int flags) { ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap); int bitmap_format = al_get_bitmap_format(bitmap); if (d3d_bmp->display->device_lost) return NULL; ASSERT(_al_pixel_format_is_compressed(bitmap_format)); RECT rect; DWORD Flags = flags & ALLEGRO_LOCK_READONLY ? D3DLOCK_READONLY : 0; rect.left = x; rect.right = x + w; rect.top = y; rect.bottom = y + h; if (d3d_bmp->video_texture->LockRect(0, &d3d_bmp->locked_rect, &rect, Flags) != D3D_OK) { ALLEGRO_ERROR("LockRect failed in d3d_lock_region.\n"); return NULL; } bitmap->locked_region.data = d3d_bmp->locked_rect.pBits; bitmap->locked_region.format = bitmap_format; bitmap->locked_region.pitch = d3d_bmp->locked_rect.Pitch; bitmap->locked_region.pixel_size = al_get_pixel_block_size(bitmap_format); return &bitmap->locked_region; } static void d3d_unlock_compressed_region(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap); ASSERT(_al_pixel_format_is_compressed(al_get_bitmap_format(bitmap))); d3d_bmp->video_texture->UnlockRect(0); } /* Obtain a reference to this driver. */ ALLEGRO_BITMAP_INTERFACE *_al_bitmap_d3d_driver(void) { if (vt) return vt; vt = (ALLEGRO_BITMAP_INTERFACE *)al_malloc(sizeof *vt); memset(vt, 0, sizeof *vt); vt->draw_bitmap_region = d3d_draw_bitmap_region; vt->upload_bitmap = d3d_upload_bitmap; vt->update_clipping_rectangle = NULL; vt->destroy_bitmap = _al_d3d_destroy_bitmap; vt->lock_region = d3d_lock_region; vt->unlock_region = d3d_unlock_region; vt->lock_compressed_region = d3d_lock_compressed_region; vt->unlock_compressed_region = d3d_unlock_compressed_region; vt->update_clipping_rectangle = d3d_update_clipping_rectangle; vt->backup_dirty_bitmap = d3d_backup_dirty_bitmap; return vt; } allegro5-5.2.10.1/src/win/d3d_d3dx9.cpp000066400000000000000000000070321473414355200172370ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * D3DX9 DLL dynamic loading. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_direct3d.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_direct3d.h" #ifdef ALLEGRO_CFG_D3DX9 #include #include #include "d3d.h" ALLEGRO_DEBUG_CHANNEL("d3dx9") // DXSDK redistributable install d3dx9_xx.dll from version // 24 to 43. It's unlikely that any new version will come, // since HLSL compiler was moved to D3DCompiler_xx.dll and // most recent versions of this utility library are bound // to DirectX 11. // // However, if any new version appears anyway, this range // should be changed. #define D3DX9_MIN_VERSION 24 #define D3DX9_MAX_VERSION 43 static HMODULE _imp_d3dx9_module = 0; _ALLEGRO_D3DXCREATEEFFECTPROC _al_imp_D3DXCreateEffect = NULL; _ALLEGRO_D3DXLSFLSPROC _al_imp_D3DXLoadSurfaceFromSurface = NULL; extern "C" void _al_unload_d3dx9_module() { FreeLibrary(_imp_d3dx9_module); _imp_d3dx9_module = NULL; } static bool _imp_load_d3dx9_module_version(int version) { char module_name[16]; // Sanity check // Comented out, to not reject choice of the user if any new version // appears. See force_d3dx9_version entry in config file. /* if (version < 24 || version > 43) { ALLEGRO_ERROR("Error: Requested version (%d) of D3DX9 library is invalid.\n", version); return false; } */ sprintf(module_name, "d3dx9_%d.dll", version); _imp_d3dx9_module = _al_win_safe_load_library(module_name); if (NULL == _imp_d3dx9_module) return false; _al_imp_D3DXCreateEffect = (_ALLEGRO_D3DXCREATEEFFECTPROC)GetProcAddress(_imp_d3dx9_module, "D3DXCreateEffect"); if (NULL == _al_imp_D3DXCreateEffect) { FreeLibrary(_imp_d3dx9_module); _imp_d3dx9_module = NULL; return false; } _al_imp_D3DXLoadSurfaceFromSurface = (_ALLEGRO_D3DXLSFLSPROC)GetProcAddress(_imp_d3dx9_module, "D3DXLoadSurfaceFromSurface"); if (NULL == _al_imp_D3DXLoadSurfaceFromSurface) { FreeLibrary(_imp_d3dx9_module); _imp_d3dx9_module = NULL; return false; } ALLEGRO_INFO("Module \"%s\" loaded.\n", module_name); return true; } extern "C" bool _al_load_d3dx9_module() { long version; char const *value; if (_imp_d3dx9_module) { return true; } value = al_get_config_value(al_get_system_config(), "shader", "force_d3dx9_version"); if (value) { errno = 0; version = strtol(value, NULL, 10); if (errno) { ALLEGRO_ERROR("Failed to override D3DX9 version. \"%s\" is not valid integer number.\n", value); return false; } else return _imp_load_d3dx9_module_version((int)version); } // Iterate over all valid versions. for (version = D3DX9_MAX_VERSION; version >= D3DX9_MIN_VERSION; version--) if (_imp_load_d3dx9_module_version((int)version)) return true; ALLEGRO_ERROR("Failed to load D3DX9 library. Library is not installed.\n"); return false; } #endif allegro5-5.2.10.1/src/win/d3d_disp.cpp000066400000000000000000002741221473414355200172510ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Direct3D display driver * * By Trent Gamblin. * */ #include #include #include #include #include #include "allegro5/allegro.h" #include "allegro5/system.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_pixels.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/internal/aintern_thread.h" #include "allegro5/internal/aintern_tri_soft.h" // For ALLEGRO_VERTEX #include "allegro5/internal/aintern_vector.h" #include "allegro5/internal/aintern_wclipboard.h" #include "allegro5/platform/aintwin.h" #include "d3d.h" // Based on the code in but that header is not // available on Windows 7 SDK and earlier. static BOOL is_windows_vista_or_greater() { OSVERSIONINFOEX info; ULONGLONG mask = 0; VER_SET_CONDITION(mask, VER_MAJORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(mask, VER_MINORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); memset(&info, 0, sizeof(info)); info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); info.dwMajorVersion = 6; return VerifyVersionInfo(&info, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, mask) != FALSE; } static void d3d_set_target_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap); static void d3d_update_transformation(ALLEGRO_DISPLAY* disp, ALLEGRO_BITMAP *target); static bool d3d_init_display(); // C++ needs to cast void pointers #define get_extra(b) ((ALLEGRO_BITMAP_EXTRA_D3D *)\ (b->parent ? b->parent->extra : b->extra)) static const char* _al_d3d_module_name = "d3d9.dll"; ALLEGRO_DEBUG_CHANNEL("d3d") static ALLEGRO_DISPLAY_INTERFACE *vt = 0; static HMODULE _al_d3d_module = 0; typedef LPDIRECT3D9 (WINAPI *DIRECT3DCREATE9PROC)(UINT); static DIRECT3DCREATE9PROC _al_d3d_create = (DIRECT3DCREATE9PROC)NULL; #ifdef ALLEGRO_CFG_D3D9EX typedef HRESULT (WINAPI *DIRECT3DCREATE9EXPROC)(UINT, LPDIRECT3D9EX*); static DIRECT3DCREATE9EXPROC _al_d3d_create_ex = (DIRECT3DCREATE9EXPROC)NULL; #endif LPDIRECT3D9 _al_d3d = 0; static D3DPRESENT_PARAMETERS d3d_pp; static HWND fullscreen_focus_window; static bool ffw_set = false; static bool d3d_can_wait_for_vsync; static bool render_to_texture_supported = true; static bool is_vista = false; static int num_faux_fullscreen_windows = 0; static bool already_fullscreen = false; /* real fullscreen */ static ALLEGRO_MUTEX *present_mutex; ALLEGRO_MUTEX *_al_d3d_lost_device_mutex; #define FOURCC(c0, c1, c2, c3) ((int)(c0) | ((int)(c1) << 8) | ((int)(c2) << 16) | ((int)(c3) << 24)) /* * These parameters cannot be gotten by the display thread because * they're thread local. We get them in the calling thread first. */ struct D3D_DISPLAY_PARAMETERS { ALLEGRO_DISPLAY_D3D *display; volatile bool init_failed; HANDLE AckEvent; int window_x, window_y; /* Not owned. */ const char *window_title; }; static int allegro_formats[] = { ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_15_NO_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA, ALLEGRO_PIXEL_FORMAT_XRGB_8888, ALLEGRO_PIXEL_FORMAT_ARGB_8888, //ALLEGRO_PIXEL_FORMAT_ARGB_4444, this format seems not to be allowed ALLEGRO_PIXEL_FORMAT_RGB_565, //ALLEGRO_PIXEL_FORMAT_ARGB_1555, this format seems not to be allowed ALLEGRO_PIXEL_FORMAT_ABGR_F32, ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8, ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1, ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3, ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5, -1 }; /* Mapping of Allegro formats to D3D formats */ static int d3d_formats[] = { ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_15_NO_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA, ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, //D3DFMT_A4R4G4B4, D3DFMT_R5G6B5, //D3DFMT_A1R5G5B5, D3DFMT_A32B32G32R32F, D3DFMT_L8, FOURCC('D', 'X', 'T', '1'), FOURCC('D', 'X', 'T', '3'), FOURCC('D', 'X', 'T', '5'), -1 }; static void (*d3d_release_callback)(ALLEGRO_DISPLAY *display) = NULL; static void (*d3d_restore_callback)(ALLEGRO_DISPLAY *display) = NULL; #define ERR(e) case e: return #e; static char const *_al_d3d_error_string(HRESULT e) { switch (e) { ERR(D3D_OK) ERR(D3DERR_NOTAVAILABLE) ERR(D3DERR_DEVICELOST) ERR(D3DERR_INVALIDCALL) ERR(D3DERR_OUTOFVIDEOMEMORY) ERR(E_OUTOFMEMORY) } return "UNKNOWN"; } #undef ERR static D3DFORMAT d3d_get_depth_stencil_format(ALLEGRO_EXTRA_DISPLAY_SETTINGS *settings) { struct DEPTH_STENCIL_DESC { int d; int s; D3DFORMAT format; }; DEPTH_STENCIL_DESC formats[] = { { 0, 0, (D3DFORMAT)0 }, { 32, 0, D3DFMT_D32 }, { 15, 1, D3DFMT_D15S1 }, { 24, 8, D3DFMT_D24S8 }, { 24, 0, D3DFMT_D24X8 }, { 24, 4, D3DFMT_D24X4S4 }, { 16, 0, D3DFMT_D16 }, { -1, -1, (D3DFORMAT)0 } }; for (int i = 0; formats[i].d >= 0; i++) { if (settings->settings[ALLEGRO_DEPTH_SIZE] == formats[i].d && settings->settings[ALLEGRO_STENCIL_SIZE] == formats[i].s) return formats[i].format; } return (D3DFORMAT)0; } static void d3d_call_callbacks(_AL_VECTOR *v, ALLEGRO_DISPLAY *display) { int i; for (i = 0; i < (int)v->_size; i++) { void (**callback)(ALLEGRO_DISPLAY *) = (void (**)(ALLEGRO_DISPLAY *))_al_vector_ref(v, i); (*callback)(display); } } /* Function: al_set_d3d_device_release_callback */ void al_set_d3d_device_release_callback( void (*callback)(ALLEGRO_DISPLAY *display)) { d3d_release_callback = callback; } /* Function: al_set_d3d_device_restore_callback */ void al_set_d3d_device_restore_callback( void (*callback)(ALLEGRO_DISPLAY *display)) { d3d_restore_callback = callback; } bool _al_d3d_supports_separate_alpha_blend(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)display; return d3d_disp->supports_separate_alpha_blend; } /* Function: al_have_d3d_non_pow2_texture_support */ bool al_have_d3d_non_pow2_texture_support(void) { D3DCAPS9 caps; int adapter = al_get_new_display_adapter(); if (!_al_d3d && !d3d_init_display()) return false; if (adapter < 0) adapter = 0; /* This might have to change for multihead */ if (_al_d3d->GetDeviceCaps(adapter, D3DDEVTYPE_HAL, &caps) != D3D_OK) { if (_al_d3d->GetDeviceCaps(adapter, D3DDEVTYPE_REF, &caps) != D3D_OK) { return false; } } if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) == 0) { return true; } return false; } static int d3d_get_max_texture_size(int adapter) { D3DCAPS9 caps; if (!_al_d3d && !d3d_init_display()) return -1; if (_al_d3d->GetDeviceCaps(adapter, D3DDEVTYPE_HAL, &caps) != D3D_OK) { if (_al_d3d->GetDeviceCaps(adapter, D3DDEVTYPE_REF, &caps) != D3D_OK) { return -1; } } return _ALLEGRO_MIN(caps.MaxTextureWidth, caps.MaxTextureHeight); } /* Function: al_have_d3d_non_square_texture_support */ bool al_have_d3d_non_square_texture_support(void) { D3DCAPS9 caps; int adapter = al_get_new_display_adapter(); if (!_al_d3d && !d3d_init_display()) return false; if (adapter < 0) adapter = 0; /* This might have to change for multihead */ if (_al_d3d->GetDeviceCaps(adapter, D3DDEVTYPE_HAL, &caps) != D3D_OK) { if (_al_d3d->GetDeviceCaps(adapter, D3DDEVTYPE_REF, &caps) != D3D_OK) { return false; } } if ((caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) == 0) { return true; } return false; } int _al_pixel_format_to_d3d(int format) { int i; for (i = 0; allegro_formats[i] >= 0; i++) { if (!_al_pixel_format_is_real(allegro_formats[i])) continue; if (allegro_formats[i] == format) { return d3d_formats[i]; } } //return D3DFMT_R5G6B5; return -1; } int _al_d3d_format_to_allegro(int d3d_fmt) { int i; for (i = 0; d3d_formats[i] >= 0; i++) { if (!_al_pixel_format_is_real(allegro_formats[i])) continue; if (d3d_formats[i] == d3d_fmt) { return allegro_formats[i]; } } return -1; } int _al_d3d_num_display_formats(void) { return sizeof(d3d_formats) / sizeof(d3d_formats[0]); } void _al_d3d_get_nth_format(int i, int *allegro, D3DFORMAT *d3d) { *allegro = allegro_formats[i]; *d3d = (D3DFORMAT)d3d_formats[i]; } static void d3d_reset_state(ALLEGRO_DISPLAY_D3D *disp) { if (disp->device_lost) return; disp->blender_state_op = -1; disp->blender_state_src = -1; disp->blender_state_dst = -1; disp->blender_state_alpha_op = -1; disp->blender_state_alpha_src = -1; disp->blender_state_alpha_dst = -1; disp->scissor_state.bottom = -1; disp->scissor_state.top = -1; disp->scissor_state.left = -1; disp->scissor_state.right = -1; disp->device->SetRenderState(D3DRS_LIGHTING, FALSE); disp->device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); disp->device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); _al_d3d_update_render_state((ALLEGRO_DISPLAY *)disp); } static bool d3d_display_mode_matches(D3DDISPLAYMODE *dm, int w, int h, int format, int refresh_rate) { if ((dm->Width == (unsigned int)w) && (dm->Height == (unsigned int)h) && ((!refresh_rate) || (dm->RefreshRate == (unsigned int)refresh_rate)) && ((int)dm->Format == (int)_al_pixel_format_to_d3d(format))) { return true; } return false; } static bool d3d_check_mode(int w, int h, int format, int refresh_rate, UINT adapter) { UINT num_modes; UINT i; D3DDISPLAYMODE display_mode; if (!_al_d3d && !d3d_init_display()) return false; num_modes = _al_d3d->GetAdapterModeCount(adapter, (D3DFORMAT)_al_pixel_format_to_d3d(format)); for (i = 0; i < num_modes; i++) { if (_al_d3d->EnumAdapterModes(adapter, (D3DFORMAT)_al_pixel_format_to_d3d(format), i, &display_mode) != D3D_OK) { return false; } if (d3d_display_mode_matches(&display_mode, w, h, format, refresh_rate)) { return true; } } return false; } static int d3d_get_default_refresh_rate(UINT adapter) { D3DDISPLAYMODE d3d_dm; if (!_al_d3d && !d3d_init_display()) return 0; _al_d3d->GetAdapterDisplayMode(adapter, &d3d_dm); return d3d_dm.RefreshRate; } static bool d3d_create_fullscreen_device(ALLEGRO_DISPLAY_D3D *d, int format, int refresh_rate, int flags) { int ret; bool reset_all = false; ALLEGRO_DISPLAY_WIN *win_display = &d->win_display; ALLEGRO_DISPLAY *al_display = &win_display->display; (void)flags; if (!d3d_check_mode(al_display->w, al_display->h, format, refresh_rate, win_display->adapter)) { ALLEGRO_ERROR("d3d_create_fullscreen_device: Mode not supported.\n"); return 0; } ZeroMemory(&d3d_pp, sizeof(d3d_pp)); d3d_pp.BackBufferFormat = (D3DFORMAT)_al_pixel_format_to_d3d(format); d3d_pp.BackBufferWidth = al_display->w; d3d_pp.BackBufferHeight = al_display->h; d3d_pp.BackBufferCount = 1; d3d_pp.Windowed = 0; if (d->vsync) { d3d_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; } else { d3d_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; } if (d->depth_stencil_format) { d3d_pp.EnableAutoDepthStencil = true; d3d_pp.AutoDepthStencilFormat = d->depth_stencil_format; } if (d->samples) { d3d_pp.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE; d3d_pp.MultiSampleQuality = d->samples; } else d3d_pp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; if (d->single_buffer) { d3d_pp.SwapEffect = D3DSWAPEFFECT_COPY; } else { d3d_pp.SwapEffect = D3DSWAPEFFECT_DISCARD; } d3d_pp.hDeviceWindow = win_display->window; if (refresh_rate) { d3d_pp.FullScreen_RefreshRateInHz = refresh_rate; } else { d3d_pp.FullScreen_RefreshRateInHz = d3d_get_default_refresh_rate(win_display->adapter); al_display->refresh_rate = d3d_pp.FullScreen_RefreshRateInHz; } if (ffw_set == false) { fullscreen_focus_window = win_display->window; ffw_set = true; } else { reset_all = true; } #ifdef ALLEGRO_CFG_D3D9EX if (is_vista) { D3DDISPLAYMODEEX mode; IDirect3D9Ex *d3d = (IDirect3D9Ex *)_al_d3d; mode.Size = sizeof(D3DDISPLAYMODEEX); mode.Width = al_display->w; mode.Height = al_display->h; mode.RefreshRate = d3d_pp.FullScreen_RefreshRateInHz; mode.Format = d3d_pp.BackBufferFormat; mode.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE; if ((ret = d3d->CreateDeviceEx(win_display->adapter, D3DDEVTYPE_HAL, fullscreen_focus_window, D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE|D3DCREATE_MULTITHREADED|D3DCREATE_SCREENSAVER, &d3d_pp, &mode, (IDirect3DDevice9Ex **)(&d->device))) != D3D_OK) { if ((ret = d3d->CreateDeviceEx(win_display->adapter, D3DDEVTYPE_HAL, fullscreen_focus_window, D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE|D3DCREATE_MULTITHREADED|D3DCREATE_SCREENSAVER, &d3d_pp, &mode, (IDirect3DDevice9Ex **)(&d->device))) != D3D_OK) { if ((ret = d3d->CreateDeviceEx(win_display->adapter, D3DDEVTYPE_REF, fullscreen_focus_window, D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE|D3DCREATE_MULTITHREADED|D3DCREATE_SCREENSAVER, &d3d_pp, &mode, (IDirect3DDevice9Ex **)(&d->device))) != D3D_OK) { if ((ret = d3d->CreateDeviceEx(win_display->adapter, D3DDEVTYPE_REF, fullscreen_focus_window, D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE|D3DCREATE_MULTITHREADED|D3DCREATE_SCREENSAVER, &d3d_pp, &mode, (IDirect3DDevice9Ex **)(&d->device))) != D3D_OK) { switch (ret) { case D3DERR_INVALIDCALL: ALLEGRO_ERROR("D3DERR_INVALIDCALL in create_device.\n"); break; case D3DERR_NOTAVAILABLE: ALLEGRO_ERROR("D3DERR_NOTAVAILABLE in create_device.\n"); break; case D3DERR_OUTOFVIDEOMEMORY: ALLEGRO_ERROR("D3DERR_OUTOFVIDEOMEMORY in create_device.\n"); break; case D3DERR_DEVICELOST: ALLEGRO_ERROR("D3DERR_DEVICELOST in create_device.\n"); break; default: ALLEGRO_ERROR("Direct3D Device creation failed.\n"); break; } return 0; } } } } } else #endif { if ((ret = _al_d3d->CreateDevice(win_display->adapter, D3DDEVTYPE_HAL, fullscreen_focus_window, D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE|D3DCREATE_MULTITHREADED, &d3d_pp, &d->device)) != D3D_OK) { if ((ret = _al_d3d->CreateDevice(win_display->adapter, D3DDEVTYPE_HAL, fullscreen_focus_window, D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE|D3DCREATE_MULTITHREADED, &d3d_pp, &d->device)) != D3D_OK) { if ((ret = _al_d3d->CreateDevice(win_display->adapter, D3DDEVTYPE_REF, fullscreen_focus_window, D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE|D3DCREATE_MULTITHREADED, &d3d_pp, &d->device)) != D3D_OK) { if ((ret = _al_d3d->CreateDevice(win_display->adapter, D3DDEVTYPE_REF, fullscreen_focus_window, D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE|D3DCREATE_MULTITHREADED, &d3d_pp, &d->device)) != D3D_OK) { switch (ret) { case D3DERR_INVALIDCALL: ALLEGRO_ERROR("D3DERR_INVALIDCALL in create_device.\n"); break; case D3DERR_NOTAVAILABLE: ALLEGRO_ERROR("D3DERR_NOTAVAILABLE in create_device.\n"); break; case D3DERR_OUTOFVIDEOMEMORY: ALLEGRO_ERROR("D3DERR_OUTOFVIDEOMEMORY in create_device.\n"); break; case D3DERR_DEVICELOST: ALLEGRO_ERROR("D3DERR_DEVICELOST in create_device.\n"); break; default: ALLEGRO_ERROR("Direct3D Device creation failed.\n"); break; } return 0; } } } } } d->device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d->render_target); ALLEGRO_INFO("Fullscreen Direct3D device created.\n"); d->device->BeginScene(); ALLEGRO_SYSTEM *system = (ALLEGRO_SYSTEM *)al_get_system_driver(); if (reset_all) { int i; for (i = 0; i < (int)system->displays._size; i++) { ALLEGRO_DISPLAY_D3D **dptr = (ALLEGRO_DISPLAY_D3D **)_al_vector_ref(&system->displays, i); ALLEGRO_DISPLAY_D3D *disp = *dptr; if (disp != d) { if (disp != d && (disp->win_display.display.flags & ALLEGRO_FULLSCREEN)) { disp->do_reset = true; while (!disp->reset_done) { al_rest(0.001); } disp->reset_done = false; } } } } return 1; } static void d3d_destroy_device(ALLEGRO_DISPLAY_D3D *disp) { while (disp->device->Release() != 0) { ALLEGRO_WARN("d3d_destroy_device: ref count not 0\n"); } disp->device = NULL; } bool _al_d3d_render_to_texture_supported(void) { return render_to_texture_supported; } static bool d3d_init_display() { D3DDISPLAYMODE d3d_dm; _al_d3d_module = _al_win_safe_load_library(_al_d3d_module_name); if (_al_d3d_module == NULL) { ALLEGRO_ERROR("Failed to open '%s' library\n", _al_d3d_module_name); return false; } is_vista = is_windows_vista_or_greater(); #ifdef ALLEGRO_CFG_D3D9EX if (is_vista) { _al_d3d_create_ex = (DIRECT3DCREATE9EXPROC)GetProcAddress(_al_d3d_module, "Direct3DCreate9Ex"); if (_al_d3d_create_ex != NULL) { if (_al_d3d_create_ex(D3D_SDK_VERSION, (LPDIRECT3D9EX *)&_al_d3d) != D3D_OK) { ALLEGRO_ERROR("Direct3DCreate9Ex failed\n"); FreeLibrary(_al_d3d_module); return false; } } else { ALLEGRO_INFO("Direct3DCreate9Ex not in %s\n", _al_d3d_module_name); is_vista = false; } } if (!is_vista) #endif { _al_d3d_create = (DIRECT3DCREATE9PROC)GetProcAddress(_al_d3d_module, "Direct3DCreate9"); if (_al_d3d_create != NULL) { if ((_al_d3d = _al_d3d_create(D3D9b_SDK_VERSION)) == NULL) { ALLEGRO_ERROR("Direct3DCreate9 failed.\n"); FreeLibrary(_al_d3d_module); return false; } } else { ALLEGRO_ERROR("Direct3DCreate9 not in %s\n", _al_d3d_module_name); FreeLibrary(_al_d3d_module); return false; } } _al_d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3d_dm); if (_al_d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3d_dm.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, d3d_dm.Format) != D3D_OK) { if (_al_d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, d3d_dm.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, d3d_dm.Format) != D3D_OK) { render_to_texture_supported = false; } else render_to_texture_supported = true; } else render_to_texture_supported = true; ALLEGRO_INFO("Render-to-texture: %d\n", render_to_texture_supported); present_mutex = al_create_mutex(); _al_d3d_lost_device_mutex = al_create_mutex(); #ifdef ALLEGRO_CFG_SHADER_HLSL _al_d3d_init_shaders(); #endif return true; } static ALLEGRO_DISPLAY_D3D *d3d_create_display_internals(ALLEGRO_DISPLAY_D3D *d3d_display, bool free_on_error); static void d3d_destroy_display_internals(ALLEGRO_DISPLAY_D3D *display); static void d3d_make_faux_fullscreen_stage_one(ALLEGRO_DISPLAY_D3D *d3d_display) { ALLEGRO_SYSTEM *system = al_get_system_driver(); if (already_fullscreen || num_faux_fullscreen_windows) { int i; for (i = 0; i < (int)system->displays._size; i++) { ALLEGRO_DISPLAY_D3D **dptr = (ALLEGRO_DISPLAY_D3D **)_al_vector_ref(&system->displays, i); ALLEGRO_DISPLAY_D3D *disp = *dptr; if (disp != d3d_display) {// && (disp->win_display.display.flags & ALLEGRO_FULLSCREEN)) { d3d_destroy_display_internals(disp); disp->win_display.end_thread = false; disp->win_display.thread_ended = false; } } } } static void d3d_make_faux_fullscreen_stage_two(ALLEGRO_DISPLAY_D3D *d3d_display) { ALLEGRO_SYSTEM *system = al_get_system_driver(); if (already_fullscreen || num_faux_fullscreen_windows) { int i; already_fullscreen = false; for (i = 0; i < (int)system->displays._size; i++) { ALLEGRO_DISPLAY_D3D **dptr = (ALLEGRO_DISPLAY_D3D **)_al_vector_ref(&system->displays, i); ALLEGRO_DISPLAY_D3D *disp = *dptr; if (disp != d3d_display) {// && (disp->win_display.display.flags & ALLEGRO_FULLSCREEN)) { if (disp->win_display.display.flags & ALLEGRO_FULLSCREEN) disp->faux_fullscreen = true; disp = d3d_create_display_internals(disp, true); if (!disp) { ALLEGRO_ERROR("d3d_create_display_internals failed.\n"); /* XXX we don't try to recover from this yet */ abort(); } ASSERT(disp); _al_d3d_recreate_bitmap_textures(disp); } } } } static bool d3d_create_device(ALLEGRO_DISPLAY_D3D *d, int format, int refresh_rate, int flags, bool convert_to_faux) { HRESULT hr; ALLEGRO_DISPLAY_WIN *win_display = &d->win_display; ALLEGRO_DISPLAY *al_display = &win_display->display; int adapter = win_display->adapter; (void)refresh_rate; (void)flags; /* Ideally if you're targetting vanilla Direct3D 9 you should create * your windowed displays before any fullscreen ones. If you don't, * your fullscreen displays will be turned into "faux-fullscreen" * displays, basically screen-filling windows set out in front of * everything else. */ #ifdef ALLEGRO_CFG_D3D9EX if (convert_to_faux) d3d_make_faux_fullscreen_stage_one(d); #else (void)convert_to_faux; #endif ZeroMemory(&d3d_pp, sizeof(d3d_pp)); d3d_pp.BackBufferFormat = (D3DFORMAT)_al_pixel_format_to_d3d(format); d3d_pp.BackBufferWidth = al_display->w; d3d_pp.BackBufferHeight = al_display->h; d3d_pp.BackBufferCount = 1; d3d_pp.Windowed = 1; if (d->vsync) { d3d_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; } else { d3d_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; } if (d->depth_stencil_format) { d3d_pp.EnableAutoDepthStencil = true; d3d_pp.AutoDepthStencilFormat = d->depth_stencil_format; ALLEGRO_INFO("Chose depth stencil format %d\n", d->depth_stencil_format); } else { ALLEGRO_INFO("Using no depth stencil buffer\n"); } if (d->samples) { d3d_pp.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE; d3d_pp.MultiSampleQuality = d->samples; } else d3d_pp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; if (d->single_buffer) { d3d_pp.SwapEffect = D3DSWAPEFFECT_COPY; } else { d3d_pp.SwapEffect = D3DSWAPEFFECT_DISCARD; } d3d_pp.hDeviceWindow = win_display->window; if (!refresh_rate) { al_display->refresh_rate = d3d_get_default_refresh_rate(win_display->adapter); } if (adapter < 0) adapter = 0; if ((hr = _al_d3d->CreateDevice(adapter, D3DDEVTYPE_HAL, win_display->window, D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE|D3DCREATE_MULTITHREADED, &d3d_pp, (LPDIRECT3DDEVICE9 *)&d->device)) != D3D_OK) { ALLEGRO_DEBUG("trying D3DCREATE_SOFTWARE_VERTEXPROCESSING\n"); if ((hr = _al_d3d->CreateDevice(adapter, D3DDEVTYPE_HAL, win_display->window, D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE|D3DCREATE_MULTITHREADED, &d3d_pp, (LPDIRECT3DDEVICE9 *)&d->device)) != D3D_OK) { ALLEGRO_DEBUG("trying D3DDEVTYPE_REF\n"); if ((hr = _al_d3d->CreateDevice(adapter, D3DDEVTYPE_REF, win_display->window, D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE|D3DCREATE_MULTITHREADED, &d3d_pp, (LPDIRECT3DDEVICE9 *)&d->device)) != D3D_OK) { ALLEGRO_DEBUG("trying D3DDEVTYPE_REF|D3DCREATE_SOFTWARE_VERTEXPROCESSING\n"); if ((hr = _al_d3d->CreateDevice(adapter, D3DDEVTYPE_REF, win_display->window, D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE|D3DCREATE_MULTITHREADED, &d3d_pp, (LPDIRECT3DDEVICE9 *)&d->device)) != D3D_OK) { ALLEGRO_ERROR("CreateDevice failed: %s\n", _al_d3d_error_string(hr)); return 0; } } } } if (d->device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d->render_target) != D3D_OK) { //if (d->device->GetRenderTarget(0, &d->render_target) != D3D_OK) { ALLEGRO_ERROR("d3d_create_device: GetBackBuffer failed.\n"); return 0; } if (d->device->BeginScene() != D3D_OK) { ALLEGRO_ERROR("BeginScene failed in create_device\n"); } else { ALLEGRO_DEBUG("BeginScene succeeded in create_device\n"); } #ifdef ALLEGRO_CFG_D3D9EX if (convert_to_faux) d3d_make_faux_fullscreen_stage_two(d); #endif ALLEGRO_DEBUG("Success\n"); return 1; } /* When a display is destroyed, its bitmaps get converted * to memory bitmaps */ static void d3d_release_bitmaps(ALLEGRO_DISPLAY *display) { while (display->bitmaps._size > 0) { ALLEGRO_BITMAP **bptr = (ALLEGRO_BITMAP **)_al_vector_ref_back(&display->bitmaps); ALLEGRO_BITMAP *b = *bptr; _al_convert_to_memory_bitmap(b); } } static void d3d_destroy_display_internals(ALLEGRO_DISPLAY_D3D *d3d_display) { ALLEGRO_DISPLAY *al_display = (ALLEGRO_DISPLAY *)d3d_display; ALLEGRO_DISPLAY_WIN *win_display = &d3d_display->win_display; if (d3d_display->device) { #ifdef ALLEGRO_CFG_SHADER_HLSL _al_remove_display_invalidated_callback(al_display, _al_d3d_on_lost_shaders); _al_remove_display_validated_callback(al_display, _al_d3d_on_reset_shaders); #endif d3d_call_callbacks(&al_display->display_invalidated_callbacks, al_display); #ifdef ALLEGRO_CFG_SHADER_HLSL _al_add_display_invalidated_callback(al_display, _al_d3d_on_lost_shaders); _al_add_display_validated_callback(al_display, _al_d3d_on_reset_shaders); #endif d3d_display->device->EndScene(); } d3d_release_bitmaps((ALLEGRO_DISPLAY *)d3d_display); ALLEGRO_DEBUG("waiting for display %p's thread to end\n", d3d_display); if (win_display->window) { SendMessage(win_display->window, _al_win_msg_suicide, 0, 0); while (!win_display->thread_ended) al_rest(0.001); } ASSERT(al_display->vt); } static void d3d_destroy_display(ALLEGRO_DISPLAY *display) { ALLEGRO_SYSTEM_WIN *system = (ALLEGRO_SYSTEM_WIN *)al_get_system_driver(); ALLEGRO_DISPLAY_D3D *d3d_display = (ALLEGRO_DISPLAY_D3D *)display; ALLEGRO_DISPLAY *old_disp = al_get_current_display(); ALLEGRO_INFO("destroying display %p (current %p)\n", display, old_disp); if (old_disp != display) _al_set_current_display_only(display); if (system->mouse_grab_display == display) al_ungrab_mouse(); _al_win_destroy_display_icons(display); d3d_destroy_display_internals(d3d_display); _al_vector_free(&display->display_invalidated_callbacks); _al_vector_free(&display->display_validated_callbacks); _al_vector_find_and_delete(&system->system.displays, &display); if (system->system.displays._size <= 0) { ffw_set = false; already_fullscreen = false; } if (d3d_display->es_inited) { _al_event_source_free(&display->es); d3d_display->es_inited = false; } _al_vector_free(&display->bitmaps); _al_vector_free(&((ALLEGRO_DISPLAY_WIN*) display)->msg_callbacks); if (old_disp != display) _al_set_current_display_only(old_disp); al_free(display->vertex_cache); al_free(display); } void _al_d3d_prepare_for_reset(ALLEGRO_DISPLAY_D3D *disp) { ALLEGRO_DISPLAY *al_display = (ALLEGRO_DISPLAY *)disp; if (d3d_release_callback) { (*d3d_release_callback)(al_display); } d3d_call_callbacks(&al_display->display_invalidated_callbacks, al_display); _al_d3d_release_default_pool_textures((ALLEGRO_DISPLAY *)disp); while (disp->render_target && disp->render_target->Release() != 0) { ALLEGRO_WARN("_al_d3d_prepare_for_reset: (bb) ref count not 0\n"); } disp->render_target = NULL; get_extra(al_get_backbuffer(al_display))->render_target = NULL; } static bool _al_d3d_reset_device(ALLEGRO_DISPLAY_D3D *d3d_display) { ALLEGRO_DISPLAY_WIN *win_display = &d3d_display->win_display; ALLEGRO_DISPLAY *al_display = &win_display->display; al_lock_mutex(_al_d3d_lost_device_mutex); _al_d3d_prepare_for_reset(d3d_display); if (al_display->flags & ALLEGRO_FULLSCREEN) { HRESULT hr; ZeroMemory(&d3d_pp, sizeof(d3d_pp)); d3d_pp.BackBufferFormat = (D3DFORMAT)_al_pixel_format_to_d3d(_al_deduce_color_format(&al_display->extra_settings)); d3d_pp.BackBufferWidth = al_display->w; d3d_pp.BackBufferHeight = al_display->h; d3d_pp.BackBufferCount = 1; d3d_pp.Windowed = 0; d3d_pp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3d_pp.hDeviceWindow = win_display->window; if (d3d_display->vsync) { d3d_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; } else { d3d_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; } if (d3d_display->depth_stencil_format) { d3d_pp.EnableAutoDepthStencil = true; d3d_pp.AutoDepthStencilFormat = d3d_display->depth_stencil_format; } if (d3d_display->samples) { d3d_pp.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE; d3d_pp.MultiSampleQuality = d3d_display->samples; } else d3d_pp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; if (d3d_display->single_buffer) { d3d_pp.SwapEffect = D3DSWAPEFFECT_COPY; } else { d3d_pp.SwapEffect = D3DSWAPEFFECT_DISCARD; } if (al_display->refresh_rate) { d3d_pp.FullScreen_RefreshRateInHz = al_display->refresh_rate; } else { d3d_pp.FullScreen_RefreshRateInHz = d3d_get_default_refresh_rate(win_display->adapter); } #ifdef ALLEGRO_CFG_D3D9EX if (is_vista) { D3DDISPLAYMODEEX mode; IDirect3DDevice9Ex *dev = (IDirect3DDevice9Ex *)d3d_display->device; mode.Size = sizeof(D3DDISPLAYMODEEX); mode.Width = d3d_pp.BackBufferWidth; mode.Height = d3d_pp.BackBufferHeight; mode.RefreshRate = d3d_pp.FullScreen_RefreshRateInHz; mode.Format = d3d_pp.BackBufferFormat; mode.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE; hr = dev->ResetEx(&d3d_pp, &mode); } else #endif { hr = d3d_display->device->Reset(&d3d_pp); } if (hr != D3D_OK) { switch (hr) { case D3DERR_INVALIDCALL: ALLEGRO_ERROR("D3DERR_INVALIDCALL in reset.\n"); break; case D3DERR_NOTAVAILABLE: ALLEGRO_ERROR("D3DERR_NOTAVAILABLE in reset.\n"); break; case D3DERR_OUTOFVIDEOMEMORY: ALLEGRO_ERROR("D3DERR_OUTOFVIDEOMEMORY in reset.\n"); break; case D3DERR_DEVICELOST: ALLEGRO_ERROR("D3DERR_DEVICELOST in reset.\n"); d3d_display->device_lost = true; break; default: ALLEGRO_ERROR("Direct3D Device reset failed (unknown reason).\n"); break; } al_unlock_mutex(_al_d3d_lost_device_mutex); return 0; } } else { ZeroMemory(&d3d_pp, sizeof(d3d_pp)); d3d_pp.BackBufferFormat = (D3DFORMAT)_al_pixel_format_to_d3d(_al_deduce_color_format(&al_display->extra_settings)); d3d_pp.BackBufferWidth = al_display->w; d3d_pp.BackBufferHeight = al_display->h; d3d_pp.BackBufferCount = 1; d3d_pp.Windowed = 1; d3d_pp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3d_pp.hDeviceWindow = win_display->window; if (d3d_display->vsync) { d3d_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; } else { d3d_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; } if (d3d_display->depth_stencil_format) { d3d_pp.EnableAutoDepthStencil = true; d3d_pp.AutoDepthStencilFormat = d3d_display->depth_stencil_format; } if (d3d_display->samples) { d3d_pp.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE; d3d_pp.MultiSampleQuality = d3d_display->samples; } else d3d_pp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; if (d3d_display->single_buffer) { d3d_pp.SwapEffect = D3DSWAPEFFECT_COPY; } else { d3d_pp.SwapEffect = D3DSWAPEFFECT_DISCARD; } /* Must be 0 for windowed modes */ d3d_pp.FullScreen_RefreshRateInHz = 0; HRESULT hr = d3d_display->device->Reset(&d3d_pp); if (hr != D3D_OK) { switch (hr) { case D3DERR_INVALIDCALL: ALLEGRO_ERROR("D3DERR_INVALIDCALL in reset.\n"); break; case D3DERR_NOTAVAILABLE: ALLEGRO_ERROR("D3DERR_NOTAVAILABLE in reset.\n"); break; case D3DERR_OUTOFVIDEOMEMORY: ALLEGRO_ERROR("D3DERR_OUTOFVIDEOMEMORY in reset.\n"); break; case D3DERR_DEVICELOST: ALLEGRO_ERROR("D3DERR_DEVICELOST in reset.\n"); d3d_display->device_lost = true; break; default: ALLEGRO_ERROR("Direct3D Device reset failed (unknown reason).\n"); break; } al_unlock_mutex(_al_d3d_lost_device_mutex); return 0; } } d3d_display->device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3d_display->render_target); _al_d3d_refresh_texture_memory(al_display); d3d_display->device->BeginScene(); d3d_reset_state(d3d_display); /* Restore the target bitmap. */ if (d3d_display->target_bitmap) { ALLEGRO_DISPLAY *display = (ALLEGRO_DISPLAY*)d3d_display; d3d_set_target_bitmap(display, d3d_display->target_bitmap); d3d_update_transformation(display, d3d_display->target_bitmap); } al_unlock_mutex(_al_d3d_lost_device_mutex); return 1; } static int d3d_choose_display_format(int fake) { /* Pick an appropriate format if the user is vague */ switch (fake) { case ALLEGRO_PIXEL_FORMAT_ANY: case ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA: case ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA: fake = ALLEGRO_PIXEL_FORMAT_XRGB_8888; break; case ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA: fake = ALLEGRO_PIXEL_FORMAT_RGB_565; break; default: break; } return fake; } static BOOL IsTextureFormatOk(D3DFORMAT TextureFormat, D3DFORMAT AdapterFormat) { HRESULT hr = _al_d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, AdapterFormat, 0, D3DRTYPE_TEXTURE, TextureFormat); if (hr != D3D_OK) { hr = _al_d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, AdapterFormat, 0, D3DRTYPE_TEXTURE, TextureFormat); } return SUCCEEDED(hr); } /* Same as above, but using Allegro's formats */ static bool is_texture_format_ok(ALLEGRO_DISPLAY *display, int texture_format) { ALLEGRO_DISPLAY_D3D *d3d_display = (ALLEGRO_DISPLAY_D3D*)display; return IsTextureFormatOk((D3DFORMAT)_al_pixel_format_to_d3d(texture_format), (D3DFORMAT)_al_pixel_format_to_d3d(d3d_display->format)); } static int real_choose_bitmap_format(ALLEGRO_DISPLAY_D3D *d3d_display, int bits, bool alpha) { int i; for (i = 0; allegro_formats[i] >= 0; i++) { int aformat = allegro_formats[i]; D3DFORMAT dformat; D3DFORMAT adapter_format; int adapter_format_allegro; if (!_al_pixel_format_is_real(aformat)) { ALLEGRO_DEBUG("Fake format\n"); continue; } if (bits && al_get_pixel_format_bits(aformat) != bits) { ALLEGRO_DEBUG("#Bits don't match\n"); continue; } if (alpha && !_al_pixel_format_has_alpha(aformat)) { ALLEGRO_DEBUG("Alpha doesn't match\n"); continue; } dformat = (D3DFORMAT)d3d_formats[i]; adapter_format_allegro = d3d_display->format; if (!_al_pixel_format_is_real(adapter_format_allegro)) adapter_format_allegro = d3d_choose_display_format(adapter_format_allegro); ALLEGRO_DEBUG("Adapter format is %d\n", adapter_format_allegro); adapter_format = (D3DFORMAT)_al_pixel_format_to_d3d(adapter_format_allegro); if (IsTextureFormatOk(dformat, adapter_format)) { ALLEGRO_DEBUG("Found a format\n"); return aformat; } ALLEGRO_DEBUG("Texture format not OK\n"); } ALLEGRO_WARN("Failed to find format\n"); return -1; } static int d3d_choose_bitmap_format(ALLEGRO_DISPLAY_D3D *d3d_display, int fake) { switch (fake) { case ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA: fake = real_choose_bitmap_format(d3d_display, 0, false); break; case ALLEGRO_PIXEL_FORMAT_ANY: case ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA: fake = real_choose_bitmap_format(d3d_display, 0, true); break; case ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA: fake = real_choose_bitmap_format(d3d_display, 32, false); break; case ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA: fake = real_choose_bitmap_format(d3d_display, 32, true); break; case ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA: fake = real_choose_bitmap_format(d3d_display, 24, false); break; case ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA: fake = real_choose_bitmap_format(d3d_display, 16, false); break; case ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA: fake = real_choose_bitmap_format(d3d_display, 16, true); break; case ALLEGRO_PIXEL_FORMAT_ANY_15_NO_ALPHA: fake = real_choose_bitmap_format(d3d_display, 15, false); break; default: fake = -1; } return fake; } struct CREATE_WINDOW_INFO { ALLEGRO_DISPLAY *display; DISPLAY_DEVICE dd; ALLEGRO_MONITOR_INFO mi; int w; int h; int refresh_rate; int flags; bool inited; bool quit; }; static void d3d_create_window_proc(CREATE_WINDOW_INFO *info) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)info->display; win_display->window = _al_win_create_window( info->display, info->w, info->h, info->flags ); } static void *d3d_create_faux_fullscreen_window_proc(void *arg) { CREATE_WINDOW_INFO *info = (CREATE_WINDOW_INFO *)arg; ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)info->display; win_display->window = _al_win_create_faux_fullscreen_window( info->dd.DeviceName, info->display, info->mi.x1, info->mi.y1, info->w, info->h, info->refresh_rate, info->flags ); return NULL; } /* * Display must be created in same thread that resets it */ static void *d3d_display_thread_proc(void *arg) { ALLEGRO_DISPLAY_D3D *d3d_display; ALLEGRO_DISPLAY_WIN *win_display; ALLEGRO_DISPLAY *al_display; D3D_DISPLAY_PARAMETERS *params = (D3D_DISPLAY_PARAMETERS *)arg; int new_format; bool convert_to_faux; CREATE_WINDOW_INFO *info = (CREATE_WINDOW_INFO *)al_calloc(1, sizeof(*info)); HRESULT hr; bool lost_event_generated = false; D3DCAPS9 caps; MSG msg; d3d_display = params->display; win_display = &d3d_display->win_display; al_display = &win_display->display; if (al_display->flags & ALLEGRO_FULLSCREEN) { convert_to_faux = true; } else { convert_to_faux = false; } /* So that we can call the functions using TLS from this thread. */ al_set_new_display_flags(al_display->flags); al_set_new_window_position(params->window_x, params->window_y); al_set_new_window_title(params->window_title); new_format = _al_deduce_color_format(&al_display->extra_settings); /* This should never happen, I think */ if (!_al_pixel_format_is_real(_al_deduce_color_format(&al_display->extra_settings))) { int f = d3d_choose_display_format(_al_deduce_color_format(&al_display->extra_settings)); if (f < 0) { d3d_destroy_display(al_display); params->init_failed = true; SetEvent(params->AckEvent); return NULL; } new_format = f; _al_set_color_components(new_format, &al_display->extra_settings, ALLEGRO_REQUIRE); } ALLEGRO_INFO("Chose a display format: %d\n", new_format); d3d_display->format = new_format; if (d3d_display->faux_fullscreen) { DEVMODE dm; bool found = true; int refresh_rate; num_faux_fullscreen_windows++; d3d_make_faux_fullscreen_stage_one(d3d_display); al_get_monitor_info(win_display->adapter, &info->mi); /* Yes this is an "infinite" loop (suggested by MS on msdn) */ for (int i = 0; ; i++) { info->dd.cb = sizeof(info->dd); if (!EnumDisplayDevices(NULL, i, &info->dd, 0)) { found = false; break; } if (!EnumDisplaySettings(info->dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { continue; } if (info->mi.x1 == dm.dmPosition.x && info->mi.y1 == dm.dmPosition.y) { break; } } if (!found) { ALLEGRO_ERROR("d3d_display_thread_proc: Error setting faux fullscreen mode.\n"); num_faux_fullscreen_windows--; d3d_destroy_display(al_display); params->init_failed = true; SetEvent(params->AckEvent); return NULL; } if (al_display->refresh_rate) { refresh_rate = al_display->refresh_rate; } else { refresh_rate = d3d_get_default_refresh_rate(win_display->adapter); } d3d_display->device_name = (TCHAR *)al_malloc(sizeof(TCHAR)*32); strcpy((char*)d3d_display->device_name, (char*)info->dd.DeviceName); ALLEGRO_DEBUG("going to call _al_win_create_faux_fullscreen_window\n"); info->display = al_display; info->w = al_display->w; info->h = al_display->h; info->refresh_rate = refresh_rate; info->flags = al_display->flags; d3d_create_faux_fullscreen_window_proc(info); if (!win_display->window) { ALLEGRO_DEBUG("Failed to create window (faux)fullscreen.\n"); d3d_destroy_display(al_display); params->init_failed = true; SetEvent(params->AckEvent); return NULL; } ALLEGRO_DEBUG("Called _al_win_create_faux_fullscreen_window.\n"); d3d_make_faux_fullscreen_stage_two(d3d_display); convert_to_faux = false; } else { ALLEGRO_INFO("Normal window.\n"); info->display = al_display; info->w = al_display->w; info->h = al_display->h; info->flags = al_display->flags; d3d_create_window_proc(info); } if (!win_display->window) { ALLEGRO_DEBUG("Failed to create regular window.\n"); d3d_destroy_display(al_display); params->init_failed = true; SetEvent(params->AckEvent); return NULL; } if (!(al_display->flags & ALLEGRO_FULLSCREEN) || d3d_display->faux_fullscreen) { if (!d3d_create_device(d3d_display, _al_deduce_color_format(&al_display->extra_settings), al_display->refresh_rate, al_display->flags, convert_to_faux)) { d3d_destroy_display(al_display); params->init_failed = true; SetEvent(params->AckEvent); return NULL; } } else { ALLEGRO_DEBUG("Creating real fullscreen device\n"); if (!d3d_create_fullscreen_device(d3d_display, _al_deduce_color_format(&al_display->extra_settings), al_display->refresh_rate, al_display->flags)) { d3d_destroy_display(al_display); params->init_failed = true; SetEvent(params->AckEvent); return NULL; } ALLEGRO_INFO("Real fullscreen device created\n"); } al_display->backbuffer_format = _al_deduce_color_format(&al_display->extra_settings); d3d_display->device->GetDeviceCaps(&caps); d3d_can_wait_for_vsync = ((caps.Caps & D3DCAPS_READ_SCANLINE) != 0); params->init_failed = false; win_display->thread_ended = false; win_display->end_thread = false; SetEvent(params->AckEvent); while (!win_display->end_thread) { al_rest(0.001); if (PeekMessage(&msg, NULL, 0, 0, FALSE)) { if (GetMessage(&msg, NULL, 0, 0) != 0) DispatchMessage(&msg); else break; /* WM_QUIT received or error (GetMessage returned -1) */ } if (!d3d_display->device) { continue; } if (d3d_display->device_lost) { hr = d3d_display->device->TestCooperativeLevel(); if (hr == D3D_OK) { d3d_display->device_lost = false; } else if (hr == D3DERR_DEVICELOST) { /* device remains lost */ if (!lost_event_generated) { ALLEGRO_DEBUG("D3DERR_DEVICELOST: d3d_display=%p\n", d3d_display); lost_event_generated = true; if (d3d_display->suppress_lost_events) { ALLEGRO_DEBUG("DISPLAY_LOST event suppressed\n"); } else { _al_event_source_lock(&al_display->es); if (_al_event_source_needs_to_generate_event(&al_display->es)) { ALLEGRO_EVENT event; memset(&event, 0, sizeof(event)); event.display.type = ALLEGRO_EVENT_DISPLAY_LOST; event.display.timestamp = al_get_time(); _al_event_source_emit_event(&al_display->es, &event); } _al_event_source_unlock(&al_display->es); al_rest(0.5); // give user time to respond } } } else if (hr == D3DERR_DEVICENOTRESET) { if (_al_d3d_reset_device(d3d_display)) { d3d_display->device_lost = false; d3d_reset_state(d3d_display); _al_event_source_lock(&al_display->es); if (_al_event_source_needs_to_generate_event(&al_display->es)) { ALLEGRO_EVENT event; memset(&event, 0, sizeof(event)); event.display.type = ALLEGRO_EVENT_DISPLAY_FOUND; event.display.timestamp = al_get_time(); _al_event_source_emit_event(&al_display->es, &event); } _al_event_source_unlock(&al_display->es); lost_event_generated = false; d3d_call_callbacks(&al_display->display_validated_callbacks, al_display); if (d3d_restore_callback) { (*d3d_restore_callback)(al_display); } } } } if (d3d_display->do_reset) { d3d_display->reset_success = _al_d3d_reset_device(d3d_display); if (d3d_restore_callback) { (*d3d_restore_callback)(al_display); } d3d_display->do_reset = false; d3d_display->reset_done = true; } } d3d_destroy_device(d3d_display); if (d3d_display->faux_fullscreen) { ChangeDisplaySettingsEx(d3d_display->device_name, NULL, NULL, 0, NULL); al_free(d3d_display->device_name); num_faux_fullscreen_windows--; } win_display->thread_ended = true; al_free(info); ALLEGRO_INFO("d3d display thread exits\n"); return NULL; } static ALLEGRO_DISPLAY_D3D *d3d_create_display_helper(int w, int h) { ALLEGRO_SYSTEM_WIN *system = (ALLEGRO_SYSTEM_WIN *)al_get_system_driver(); ALLEGRO_DISPLAY_D3D *d3d_display = (ALLEGRO_DISPLAY_D3D *)al_malloc(sizeof(ALLEGRO_DISPLAY_D3D)); ALLEGRO_DISPLAY_WIN *win_display = &d3d_display->win_display; ALLEGRO_DISPLAY *al_display = &win_display->display; memset(d3d_display, 0, sizeof *d3d_display); win_display->adapter = _al_win_determine_adapter(); /* w/h may be reset below if ALLEGRO_FULLSCREEN_WINDOW is set */ al_display->w = w; al_display->h = h; al_display->refresh_rate = al_get_new_display_refresh_rate(); al_display->flags = al_get_new_display_flags(); al_display->vt = vt; ASSERT(al_display->vt); #ifdef ALLEGRO_CFG_D3D9EX if (!is_vista) #endif { if (al_display->flags & ALLEGRO_FULLSCREEN) { if (already_fullscreen || system->system.displays._size != 0) { d3d_display->faux_fullscreen = true; } else { already_fullscreen = true; d3d_display->faux_fullscreen = false; } } } #ifdef ALLEGRO_CFG_D3D9EX else { d3d_display->faux_fullscreen = false; } #endif if (!(al_display->flags & ALLEGRO_FULLSCREEN)) { if (al_display->flags & ALLEGRO_FULLSCREEN_WINDOW) { ALLEGRO_MONITOR_INFO mi; al_get_monitor_info(win_display->adapter, &mi); al_display->w = mi.x2 - mi.x1; al_display->h = mi.y2 - mi.y1; d3d_display->faux_fullscreen = true; } else { d3d_display->faux_fullscreen = false; } win_display->toggle_w = w; win_display->toggle_h = h; } return d3d_display; } /* This function may return the original d3d_display argument, * or a new one, or NULL on error. */ static ALLEGRO_DISPLAY_D3D *d3d_create_display_internals( ALLEGRO_DISPLAY_D3D *d3d_display, bool free_on_error) { D3D_DISPLAY_PARAMETERS params; ALLEGRO_DISPLAY_WIN *win_display = &d3d_display->win_display; ALLEGRO_DISPLAY *al_display = &win_display->display; ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref = _al_get_new_display_settings(); int num_modes; int i; int window_x, window_y; /* save width and height in case new fullscreen-mode * fails inside d3d_display_thread_proc and destroys al_display */ int pre_destroy_w = al_display->w; int pre_destroy_h = al_display->h; params.display = d3d_display; /* The window is created in a separate thread so we need to pass this * TLS on */ al_get_new_window_position(&window_x, &window_y); params.window_x = window_x; params.window_y = window_y; params.window_title = al_get_new_window_title(); _al_d3d_generate_display_format_list(); _al_d3d_score_display_settings(ref); /* Checking each mode is slow, so do a resolution check first */ if (al_display->flags & ALLEGRO_FULLSCREEN) { num_modes = al_get_num_display_modes(); while (num_modes >= 0) { ALLEGRO_DISPLAY_MODE mode; al_get_display_mode(num_modes, &mode); if (mode.width == al_display->w && mode.height == al_display->h) { break; } num_modes--; } if (num_modes < 0) { // Failing resolution test is like failing to create a window // This helps determining if the window message thread needs // to be destroyed. win_display->window = NULL; if (free_on_error) { al_free(d3d_display); } return NULL; } } ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = NULL; for (i = 0; (eds = _al_d3d_get_display_settings(i)); i++) { ALLEGRO_DEBUG("Trying format %d.\n", eds->index); d3d_display->depth_stencil_format = d3d_get_depth_stencil_format(eds); if (eds->settings[ALLEGRO_SAMPLES] > 0) d3d_display->samples = eds->settings[ALLEGRO_SAMPLES] - 1; else d3d_display->samples = 0; d3d_display->single_buffer = eds->settings[ALLEGRO_SINGLE_BUFFER] ? true : false; d3d_display->vsync = eds->settings[ALLEGRO_VSYNC] == 1; memcpy(&al_display->extra_settings, eds, sizeof al_display->extra_settings); params.init_failed = true; win_display->thread_ended = true; params.AckEvent = CreateEvent(NULL, false, false, NULL); al_run_detached_thread(d3d_display_thread_proc, ¶ms); /* Wait some _finite_ time (10 secs or so) for display thread to init, and * give up if something horrible happened to it, unless we're in debug mode * and we may have intentionally stopped the execution to analyze the code. */ #ifdef DEBUGMODE WaitForSingleObject(params.AckEvent, INFINITE); #else WaitForSingleObject(params.AckEvent, 10*1000); #endif ALLEGRO_DEBUG("Resumed after wait.\n"); CloseHandle(params.AckEvent); if (!params.init_failed) { break; } ALLEGRO_INFO("Format %d failed.\n", i); // Display has been destroyed in d3d_display_thread_proc, create empty template again d3d_display = d3d_create_display_helper(pre_destroy_w, pre_destroy_h); win_display = &d3d_display->win_display; al_display = &win_display->display; params.display = d3d_display; ALLEGRO_DEBUG("d3d_display = %p\n", d3d_display); ALLEGRO_DEBUG("win_display = %p\n", win_display); ALLEGRO_DEBUG("al_display = %p\n", al_display); ASSERT(al_display->vt); } // Re-sort the display format list for use later _al_d3d_resort_display_settings(); if (!eds) { ALLEGRO_WARN("All %d formats failed.\n", i); if (free_on_error) { al_free(d3d_display); } return NULL; } ALLEGRO_INFO("Format %d succeeded.\n", eds->index); d3d_reset_state(d3d_display); d3d_display->backbuffer_bmp.extra = &d3d_display->backbuffer_bmp_extra; d3d_display->backbuffer_bmp_extra.is_backbuffer = true; d3d_display->backbuffer_bmp._display = al_display; d3d_display->backbuffer_bmp._format = _al_deduce_color_format(&al_display->extra_settings); d3d_display->backbuffer_bmp._memory_format = d3d_display->backbuffer_bmp._format; d3d_display->backbuffer_bmp_extra.system_format = d3d_display->backbuffer_bmp._format; d3d_display->backbuffer_bmp._flags = ALLEGRO_VIDEO_BITMAP; d3d_display->backbuffer_bmp.w = al_display->w; d3d_display->backbuffer_bmp.h = al_display->h; d3d_display->backbuffer_bmp_extra.texture_w = al_display->w; d3d_display->backbuffer_bmp_extra.texture_h = al_display->h; d3d_display->backbuffer_bmp.cl = 0; d3d_display->backbuffer_bmp.ct = 0; d3d_display->backbuffer_bmp.cr_excl = al_display->w; d3d_display->backbuffer_bmp.cb_excl = al_display->h; d3d_display->backbuffer_bmp.vt = (ALLEGRO_BITMAP_INTERFACE *)_al_bitmap_d3d_driver(); d3d_display->backbuffer_bmp_extra.display = d3d_display; d3d_display->target_bitmap = NULL; al_identity_transform(&d3d_display->backbuffer_bmp.transform); al_identity_transform(&d3d_display->backbuffer_bmp.proj_transform); al_orthographic_transform(&d3d_display->backbuffer_bmp.proj_transform, 0, 0, -1.0, al_display->w, al_display->h, 1.0); /* Alpha blending is the default */ d3d_display->device->SetRenderState(D3DRS_ALPHABLENDENABLE, true); d3d_display->device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); d3d_display->device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); ALLEGRO_DEBUG("Returning d3d_display: %p\n", d3d_display); return d3d_display; } static ALLEGRO_DISPLAY *d3d_create_display_locked(int w, int h) { ALLEGRO_SYSTEM_WIN *system = (ALLEGRO_SYSTEM_WIN *)al_get_system_driver(); ALLEGRO_DISPLAY_D3D *d3d_display = d3d_create_display_helper(w, h); ALLEGRO_DISPLAY_WIN *win_display = &d3d_display->win_display; ALLEGRO_DISPLAY *al_display = &win_display->display; ALLEGRO_DISPLAY_D3D **add; D3DCAPS9 caps; ALLEGRO_INFO("faux_fullscreen=%d\n", d3d_display->faux_fullscreen); ALLEGRO_DEBUG("al_display=%p\n", al_display); ALLEGRO_DEBUG("al_display->vt=%p\n", al_display->vt); ASSERT(al_display->vt); d3d_display = d3d_create_display_internals(d3d_display, true); if (!d3d_display) { ALLEGRO_ERROR("d3d_create_display failed.\n"); return NULL; } win_display = &d3d_display->win_display; al_display = &win_display->display; ALLEGRO_DEBUG("al_display=%p\n", al_display); ALLEGRO_DEBUG("al_display->vt=%p\n", al_display->vt); ASSERT(al_display->vt); /* Add ourself to the list of displays. */ add = (ALLEGRO_DISPLAY_D3D **)_al_vector_alloc_back(&system->system.displays); *add = d3d_display; /* Each display is an event source. */ _al_event_source_init(&al_display->es); d3d_display->es_inited = true; #if 0 /* Setup the mouse */ if (al_display->flags & ALLEGRO_FULLSCREEN && al_is_mouse_installed()) { RAWINPUTDEVICE rid[1]; rid[0].usUsagePage = 0x01; rid[0].usUsage = 0x02; rid[0].dwFlags = RIDEV_NOLEGACY; rid[0].hwndTarget = 0; if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == FALSE) { ALLEGRO_WARN("Failed to init mouse.\n"); } } #endif win_display->mouse_selected_hcursor = 0; win_display->mouse_cursor_shown = false; win_display->hide_mouse_on_move = false; SetForegroundWindow(win_display->window); _al_win_grab_input(win_display); _al_win_show_mouse_cursor(al_display); if (_al_d3d->GetDeviceCaps(win_display->adapter, D3DDEVTYPE_HAL, &caps) != D3D_OK && _al_d3d->GetDeviceCaps(win_display->adapter, D3DDEVTYPE_REF, &caps) != D3D_OK) { d3d_display->supports_separate_alpha_blend = false; } else { d3d_display->supports_separate_alpha_blend = ((caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) != 0); } ASSERT(al_display->vt); return al_display; } static ALLEGRO_DISPLAY *d3d_create_display(int w, int h) { ALLEGRO_DISPLAY *display; ALLEGRO_DISPLAY_WIN *win_display; int *s; al_lock_mutex(present_mutex); display = d3d_create_display_locked(w, h); win_display = (ALLEGRO_DISPLAY_WIN *)display; al_unlock_mutex(present_mutex); if (!display) return NULL; ASSERT(display->vt); s = display->extra_settings.settings; s[ALLEGRO_MAX_BITMAP_SIZE] = d3d_get_max_texture_size(win_display->adapter); s[ALLEGRO_SUPPORT_SEPARATE_ALPHA] = _al_d3d_supports_separate_alpha_blend(display); s[ALLEGRO_SUPPORT_NPOT_BITMAP] = al_have_d3d_non_pow2_texture_support(); s[ALLEGRO_CAN_DRAW_INTO_BITMAP] = render_to_texture_supported; #ifdef ALLEGRO_CFG_D3DX9 _al_load_d3dx9_module(); #endif _al_win_post_create_window(display); return display; } static bool d3d_set_current_display(ALLEGRO_DISPLAY *d) { ALLEGRO_DISPLAY_D3D *d3d_display = (ALLEGRO_DISPLAY_D3D *)d; if (d3d_display->do_reset) return false; _al_d3d_update_render_state(d); return true; } static int d3d_al_blender_to_d3d(int al_mode) { const int d3d_modes[ALLEGRO_NUM_BLEND_MODES] = { D3DBLEND_ZERO, D3DBLEND_ONE, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLEND_SRCCOLOR, D3DBLEND_DESTCOLOR, D3DBLEND_INVSRCCOLOR, D3DBLEND_INVDESTCOLOR, D3DBLEND_BLENDFACTOR, D3DBLEND_INVBLENDFACTOR }; return d3d_modes[al_mode]; } void _al_d3d_set_blender(ALLEGRO_DISPLAY_D3D *d3d_display) { bool blender_changed; int op, src, dst, alpha_op, alpha_src, alpha_dst; ALLEGRO_COLOR color; unsigned char r, g, b, a; DWORD allegro_to_d3d_blendop[ALLEGRO_NUM_BLEND_OPERATIONS] = { D3DBLENDOP_ADD, D3DBLENDOP_SUBTRACT, D3DBLENDOP_REVSUBTRACT }; blender_changed = false; al_get_separate_bitmap_blender(&op, &src, &dst, &alpha_op, &alpha_src, &alpha_dst); color = al_get_bitmap_blend_color(); al_unmap_rgba(color, &r, &g, &b, &a); if (d3d_display->blender_state_op != op) { /* These may not be supported but they will always fall back to ADD * in that case. */ d3d_display->device->SetRenderState(D3DRS_BLENDOP, allegro_to_d3d_blendop[op]); d3d_display->blender_state_op = op; blender_changed = true; } if (d3d_display->blender_state_alpha_op != alpha_op) { /* These may not be supported but they will always fall back to ADD * in that case. */ d3d_display->device->SetRenderState(D3DRS_BLENDOPALPHA, allegro_to_d3d_blendop[alpha_op]); d3d_display->blender_state_alpha_op = alpha_op; blender_changed = true; } if (d3d_display->blender_state_src != src) { if (d3d_display->device->SetRenderState(D3DRS_SRCBLEND, d3d_al_blender_to_d3d(src)) != D3D_OK) ALLEGRO_ERROR("Failed to set source blender\n"); d3d_display->blender_state_src = src; blender_changed = true; } if (d3d_display->blender_state_dst != dst) { if (d3d_display->device->SetRenderState(D3DRS_DESTBLEND, d3d_al_blender_to_d3d(dst)) != D3D_OK) ALLEGRO_ERROR("Failed to set dest blender\n"); d3d_display->blender_state_dst = dst; blender_changed = true; } if (d3d_display->blender_state_alpha_src != alpha_src) { if (d3d_display->device->SetRenderState(D3DRS_SRCBLENDALPHA, d3d_al_blender_to_d3d(alpha_src)) != D3D_OK) ALLEGRO_ERROR("Failed to set source alpha blender\n"); d3d_display->blender_state_alpha_src = alpha_src; blender_changed = true; } if (d3d_display->blender_state_alpha_dst != alpha_dst) { if (d3d_display->device->SetRenderState(D3DRS_DESTBLENDALPHA, d3d_al_blender_to_d3d(alpha_dst)) != D3D_OK) ALLEGRO_ERROR("Failed to set dest alpha blender\n"); d3d_display->blender_state_alpha_dst = alpha_dst; blender_changed = true; } if (blender_changed) { bool enable_separate_blender = (op != alpha_op) || (src != alpha_src) || (dst != alpha_dst); d3d_display->device->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(r, g, b, a)); if (enable_separate_blender) { if (d3d_display->device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, true) != D3D_OK) ALLEGRO_ERROR("D3DRS_SEPARATEALPHABLENDENABLE failed\n"); } /* thedmd: Why is this function called anyway? */ d3d_display->device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); } } static void d3d_clear(ALLEGRO_DISPLAY *al_display, ALLEGRO_COLOR *color) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); ALLEGRO_DISPLAY_D3D* d3d_display = (ALLEGRO_DISPLAY_D3D*)al_display; if (target->parent) target = target->parent; if (d3d_display->device_lost) return; if (d3d_display->device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB((int)(color->a*255), (int)(color->r*255), (int)(color->g*255), (int)(color->b*255)), 0, 0) != D3D_OK) { ALLEGRO_ERROR("Clear failed\n"); } } static void d3d_clear_depth_buffer(ALLEGRO_DISPLAY *al_display, float z) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); ALLEGRO_DISPLAY_D3D* d3d_display = (ALLEGRO_DISPLAY_D3D*)al_display; if (target->parent) target = target->parent; if (d3d_display->device_lost) return; if (d3d_display->device->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, z, 0) != D3D_OK) { ALLEGRO_ERROR("Clear zbuffer failed\n"); } } // FIXME: does this need a programmable pipeline path? static void d3d_draw_pixel(ALLEGRO_DISPLAY *disp, float x, float y, ALLEGRO_COLOR *color) { ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)disp; _al_d3d_set_blender(d3d_disp); #ifdef ALLEGRO_CFG_SHADER_HLSL if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { UINT required_passes; ALLEGRO_VERTEX vertices[1]; vertices[0].x = x; vertices[0].y = y; vertices[0].z = 0; vertices[0].color = *color; d3d_disp->device->SetFVF(D3DFVF_ALLEGRO_VERTEX); d3d_disp->effect->SetBool(ALLEGRO_SHADER_VAR_USE_TEX, false); d3d_disp->effect->Begin(&required_passes, 0); for (unsigned int i = 0; i < required_passes; i++) { d3d_disp->effect->BeginPass(i); if (d3d_disp->device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, vertices, sizeof(ALLEGRO_VERTEX)) != D3D_OK) { ALLEGRO_ERROR("d3d_draw_pixel: DrawPrimitive failed.\n"); return; } d3d_disp->effect->EndPass(); } d3d_disp->effect->End(); } else #endif { D3D_FIXED_VERTEX vertices[1]; vertices[0].x = x; vertices[0].y = y; vertices[0].z = 0; vertices[0].color = D3DCOLOR_COLORVALUE(color->r, color->g, color->b, color->a); d3d_disp->device->SetFVF(D3DFVF_FIXED_VERTEX); d3d_disp->device->SetTexture(0, NULL); if (d3d_disp->device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, vertices, sizeof(D3D_FIXED_VERTEX)) != D3D_OK) { ALLEGRO_ERROR("d3d_draw_pixel: DrawPrimitive failed.\n"); return; } } } static void d3d_flip_display(ALLEGRO_DISPLAY *al_display) { ALLEGRO_DISPLAY_D3D* d3d_display = (ALLEGRO_DISPLAY_D3D*)al_display; ALLEGRO_DISPLAY_WIN *win_display = &d3d_display->win_display; HRESULT hr; if (d3d_display->device_lost) return; al_lock_mutex(present_mutex); d3d_display->device->EndScene(); hr = d3d_display->device->Present(NULL, NULL, win_display->window, NULL); d3d_display->device->BeginScene(); al_unlock_mutex(present_mutex); if (hr == D3DERR_DEVICELOST) { d3d_display->device_lost = true; return; } else { al_backup_dirty_bitmaps(al_display); } } static void d3d_update_display_region(ALLEGRO_DISPLAY *al_display, int x, int y, int width, int height) { ALLEGRO_DISPLAY_D3D* d3d_display = (ALLEGRO_DISPLAY_D3D*)al_display; ALLEGRO_DISPLAY_WIN *win_display = &d3d_display->win_display; HRESULT hr; RGNDATA *rgndata; if (d3d_display->device_lost) return; if (d3d_display->single_buffer) { RECT rect; rect.left = x; rect.right = x+width; rect.top = y; rect.bottom = y+height; rgndata = (RGNDATA *)al_malloc(sizeof(RGNDATA)+sizeof(RECT)-1); rgndata->rdh.dwSize = sizeof(RGNDATAHEADER); rgndata->rdh.iType = RDH_RECTANGLES; rgndata->rdh.nCount = 1; rgndata->rdh.nRgnSize = sizeof(RECT); memcpy(&rgndata->rdh.rcBound, &rect, sizeof(RECT)); memcpy(rgndata->Buffer, &rect, sizeof(RECT)); d3d_display->device->EndScene(); hr = d3d_display->device->Present(&rect, &rect, win_display->window, rgndata); d3d_display->device->BeginScene(); al_free(rgndata); if (hr == D3DERR_DEVICELOST) { d3d_display->device_lost = true; return; } } else { d3d_flip_display(al_display); } } /* * Sets a clipping rectangle */ void _al_d3d_set_bitmap_clip(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap); ALLEGRO_DISPLAY_D3D *disp = d3d_bmp->display; RECT rect; if (!disp) return; if (bitmap->parent) { rect.left = bitmap->xofs + bitmap->cl; rect.right = bitmap->xofs + bitmap->cr_excl; rect.top = bitmap->yofs + bitmap->ct; rect.bottom = bitmap->yofs + bitmap->cb_excl; } else { rect.left = bitmap->cl; rect.right = bitmap->cr_excl; rect.top = bitmap->ct; rect.bottom = bitmap->cb_excl; } if (memcmp(&disp->scissor_state, &rect, sizeof(RECT)) != 0) { if (rect.left == 0 && rect.top == 0 && rect.right == disp->win_display.display.w && rect.left == disp->win_display.display.h) { disp->device->SetRenderState(D3DRS_SCISSORTESTENABLE, false); return; } disp->device->SetRenderState(D3DRS_SCISSORTESTENABLE, true); disp->device->SetScissorRect(&rect); disp->scissor_state = rect; } } static bool d3d_acknowledge_resize(ALLEGRO_DISPLAY *d) { WINDOWINFO wi; ALLEGRO_DISPLAY_D3D *disp = (ALLEGRO_DISPLAY_D3D *)d; ALLEGRO_DISPLAY_WIN *win_display = &disp->win_display; int w, h; ALLEGRO_STATE state; wi.cbSize = sizeof(WINDOWINFO); GetWindowInfo(win_display->window, &wi); w = wi.rcClient.right - wi.rcClient.left; h = wi.rcClient.bottom - wi.rcClient.top; if (w > 0 && h > 0) { d->w = w; d->h = h; } disp->backbuffer_bmp.w = d->w; disp->backbuffer_bmp.h = d->h; disp->backbuffer_bmp.cl = 0; disp->backbuffer_bmp.ct = 0; disp->backbuffer_bmp.cr_excl = w; disp->backbuffer_bmp.cb_excl = h; al_identity_transform(&disp->backbuffer_bmp.proj_transform); al_orthographic_transform(&disp->backbuffer_bmp.proj_transform, 0, 0, -1.0, w, h, 1.0); disp->do_reset = true; while (!disp->reset_done) { al_rest(0.001); } disp->reset_done = false; /* XXX: This is not very efficient, it'd probably be better to call * the necessary functions directly. */ al_store_state(&state, ALLEGRO_STATE_DISPLAY | ALLEGRO_STATE_TARGET_BITMAP); al_set_target_bitmap(al_get_backbuffer(d)); al_set_clipping_rectangle(0, 0, d->w, d->h); al_restore_state(&state); return disp->reset_success; } static bool d3d_resize_helper(ALLEGRO_DISPLAY *d, int width, int height) { ALLEGRO_DISPLAY_D3D *disp = (ALLEGRO_DISPLAY_D3D *)d; ALLEGRO_DISPLAY_WIN *win_display = &disp->win_display; ALLEGRO_DISPLAY_D3D *new_disp; int full_w, full_h; ALLEGRO_MONITOR_INFO mi; int adapter = win_display->adapter; ALLEGRO_STATE backup; al_get_monitor_info(adapter, &mi); full_w = mi.x2 - mi.x1; full_h = mi.y2 - mi.y1; if ((d->flags & ALLEGRO_FULLSCREEN_WINDOW) && (full_w != width || full_h != height)) { win_display->toggle_w = width; win_display->toggle_h = height; return true; } if (d->flags & ALLEGRO_FULLSCREEN) { /* Don't generate ALLEGRO_EVENT_DISPLAY_LOST events when destroying a * display for resizing. */ disp->suppress_lost_events = true; d3d_destroy_display_internals(disp); d->w = width; d->h = height; /* reset refresh rate (let new mode choose one) */ d->refresh_rate = 0; win_display->end_thread = false; win_display->thread_ended = false; /* What's this? */ ALLEGRO_SYSTEM *system = al_get_system_driver(); if (system->displays._size <= 1) { ffw_set = false; } /* The original display needs to remain intact so we can * recover if resizing a display fails. */ new_disp = d3d_create_display_internals(disp, false); if (!new_disp) { ALLEGRO_ERROR("d3d_create_display_internals failed.\n"); ASSERT(d->vt); return false; } ASSERT(new_disp == disp); ASSERT(d->vt); disp->suppress_lost_events = false; _al_d3d_recreate_bitmap_textures(disp); disp->backbuffer_bmp.w = width; disp->backbuffer_bmp.h = height; } else { RECT win_size; WINDOWINFO wi; win_size.left = 0; win_size.top = 0; win_size.right = width; win_size.bottom = height; wi.cbSize = sizeof(WINDOWINFO); GetWindowInfo(win_display->window, &wi); AdjustWindowRectEx(&win_size, wi.dwStyle, GetMenu(win_display->window) ? TRUE : FALSE, wi.dwExStyle); // FIXME: Handle failure (for example if window constraints are active?) SetWindowPos(win_display->window, HWND_TOP, 0, 0, win_size.right-win_size.left, win_size.bottom-win_size.top, SWP_NOMOVE|SWP_NOZORDER); if (!(d->flags & ALLEGRO_FULLSCREEN_WINDOW)) { win_display->toggle_w = width; win_display->toggle_h = height; } /* * The clipping rectangle and bitmap size must be * changed to match the new size. */ al_store_state(&backup, ALLEGRO_STATE_TARGET_BITMAP); al_set_target_bitmap(&disp->backbuffer_bmp); disp->backbuffer_bmp.w = width; disp->backbuffer_bmp.h = height; al_set_clipping_rectangle(0, 0, width, height); _al_d3d_set_bitmap_clip(&disp->backbuffer_bmp); al_restore_state(&backup); } return true; } static bool d3d_resize_display(ALLEGRO_DISPLAY *d, int width, int height) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)d; int orig_w = d->w; int orig_h = d->h; bool ret; al_backup_dirty_bitmaps(d); win_display->ignore_resize = true; if (!d3d_resize_helper(d, width, height)) { ALLEGRO_WARN("trying to restore original size: %d, %d\n", orig_w, orig_h); if (!d3d_resize_helper(d, orig_w, orig_h)) { ALLEGRO_ERROR("failed to restore original size: %d, %d\n", orig_w, orig_h); } ret = false; } else { ret = true; d3d_acknowledge_resize(d); } win_display->ignore_resize = false; return ret; } static ALLEGRO_BITMAP *d3d_create_bitmap(ALLEGRO_DISPLAY *d, int w, int h, int format, int flags) { ALLEGRO_BITMAP *bitmap; ALLEGRO_BITMAP_EXTRA_D3D *extra; if (!_al_pixel_format_is_real(format)) { format = d3d_choose_bitmap_format((ALLEGRO_DISPLAY_D3D *)d, format); if (format < 0) { return NULL; } } if (_al_pixel_format_to_d3d(format) < 0) { ALLEGRO_ERROR("Requested bitmap format not supported (%s).\n", _al_pixel_format_name((ALLEGRO_PIXEL_FORMAT)format)); return NULL; } if (!is_texture_format_ok(d, format)) { ALLEGRO_ERROR("Requested bitmap format not supported (%s).\n", _al_pixel_format_name((ALLEGRO_PIXEL_FORMAT)format)); return NULL; } bool compressed = _al_pixel_format_is_compressed(format); if (compressed) { if (!_al_d3d_render_to_texture_supported()) { /* Not implemented. XXX: Why not? */ return NULL; } } int block_width = al_get_pixel_block_width(format); int block_height = al_get_pixel_block_height(format); int block_size = al_get_pixel_block_size(format); ALLEGRO_INFO("Chose bitmap format %d\n", format); bitmap = (ALLEGRO_BITMAP *)al_malloc(sizeof *bitmap); ASSERT(bitmap); memset(bitmap, 0, sizeof(*bitmap)); bitmap->vt = _al_bitmap_d3d_driver(); bitmap->_format = format; bitmap->_flags = flags; al_identity_transform(&bitmap->transform); bitmap->pitch = _al_get_least_multiple(w, block_width) / block_width * block_size; bitmap->memory = (unsigned char *)al_malloc( bitmap->pitch * _al_get_least_multiple(h, block_height) / block_height); extra = (ALLEGRO_BITMAP_EXTRA_D3D *)al_calloc(1, sizeof *extra); bitmap->extra = extra; extra->video_texture = 0; extra->system_texture = 0; extra->initialized = false; extra->is_backbuffer = false; extra->render_target = NULL; extra->system_format = compressed ? ALLEGRO_PIXEL_FORMAT_ARGB_8888 : format; extra->display = (ALLEGRO_DISPLAY_D3D *)d; return bitmap; } void _al_d3d_destroy_bitmap(ALLEGRO_BITMAP *bitmap) { ASSERT(!al_is_sub_bitmap(bitmap)); ALLEGRO_DISPLAY_D3D *d3d_display = (ALLEGRO_DISPLAY_D3D*)_al_get_bitmap_display(bitmap); if (bitmap == d3d_display->target_bitmap) { d3d_display->target_bitmap = NULL; } ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(bitmap); if (d3d_bmp->video_texture) { if (d3d_bmp->video_texture->Release() != 0) { ALLEGRO_WARN("d3d_destroy_bitmap: Release video texture failed.\n"); } } if (d3d_bmp->system_texture) { if (d3d_bmp->system_texture->Release() != 0) { ALLEGRO_WARN("d3d_destroy_bitmap: Release system texture failed.\n"); } } if (d3d_bmp->render_target) { if (d3d_bmp->render_target->Release() != 0) { ALLEGRO_WARN("d3d_destroy_bitmap: Release render target failed.\n"); } } al_free(bitmap->extra); } static void d3d_set_target_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP *target; ALLEGRO_BITMAP_EXTRA_D3D *d3d_target; ALLEGRO_BITMAP_EXTRA_D3D *old_target = NULL; ALLEGRO_DISPLAY_D3D *d3d_display = (ALLEGRO_DISPLAY_D3D *)display; if (d3d_display->device_lost) return; if (bitmap->parent) { target = bitmap->parent; } else { target = bitmap; } d3d_target = get_extra(target); if (d3d_display->target_bitmap) old_target = get_extra(d3d_display->target_bitmap); /* Release the previous target bitmap if it was not the backbuffer */ if (old_target && !old_target->is_backbuffer) { ALLEGRO_BITMAP *parent; if (d3d_display->target_bitmap->parent) parent = d3d_display->target_bitmap->parent; else parent = d3d_display->target_bitmap; ALLEGRO_BITMAP_EXTRA_D3D *e = get_extra(parent); if (e && e->render_target) { e->render_target->Release(); e->render_target = NULL; } } d3d_display->target_bitmap = NULL; /* Set the render target */ if (d3d_target->is_backbuffer) { d3d_display = d3d_target->display; if (d3d_display->device->SetRenderTarget(0, d3d_display->render_target) != D3D_OK) { ALLEGRO_ERROR("d3d_set_target_bitmap: Unable to set render target to texture surface.\n"); return; } d3d_target->render_target = d3d_display->render_target; d3d_display->target_bitmap = bitmap; } else if (_al_pixel_format_is_compressed(al_get_bitmap_format(target))) { /* Do nothing, as it is impossible to directly draw to compressed textures via D3D. * Instead, everything will be handled by the memory routines. */ } else { d3d_display = (ALLEGRO_DISPLAY_D3D *)display; if (_al_d3d_render_to_texture_supported()) { d3d_display->target_bitmap = bitmap; if (!d3d_target->video_texture) { /* This can happen if the user tries to set the target bitmap as * the device is lost, before the DISPLAY_LOST event is received. */ ALLEGRO_WARN("d3d_set_target_bitmap: No video texture.\n"); return; } if (d3d_target->video_texture->GetSurfaceLevel(0, &d3d_target->render_target) != D3D_OK) { ALLEGRO_ERROR("d3d_set_target_bitmap: Unable to get texture surface level.\n"); return; } if (d3d_display->device->SetRenderTarget(0, d3d_target->render_target) != D3D_OK) { ALLEGRO_ERROR("d3d_set_target_bitmap: Unable to set render target to texture surface.\n"); d3d_target->render_target->Release(); return; } } if (d3d_display->samples) { d3d_display->device->SetDepthStencilSurface(NULL); } } d3d_reset_state(d3d_display); _al_d3d_set_bitmap_clip(bitmap); } static ALLEGRO_BITMAP *d3d_get_backbuffer(ALLEGRO_DISPLAY *display) { return (ALLEGRO_BITMAP *)&(((ALLEGRO_DISPLAY_D3D *)display)->backbuffer_bmp); } static bool d3d_is_compatible_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { return display == _al_get_bitmap_display(bitmap); } static void d3d_switch_out(ALLEGRO_DISPLAY *display) { (void)display; } static void d3d_switch_in(ALLEGRO_DISPLAY *display) { (void)display; } static bool d3d_wait_for_vsync(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_D3D *d3d_display; D3DRASTER_STATUS status; if (!d3d_can_wait_for_vsync) return false; d3d_display = (ALLEGRO_DISPLAY_D3D *)display; do { d3d_display->device->GetRasterStatus(0, &status); } while (!status.InVBlank); return true; } /* Exposed stuff */ /* Function: al_get_d3d_device */ LPDIRECT3DDEVICE9 al_get_d3d_device(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_D3D *d3d_display = (ALLEGRO_DISPLAY_D3D *)display; return d3d_display->device; } /* Function: al_get_d3d_system_texture */ LPDIRECT3DTEXTURE9 al_get_d3d_system_texture(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_D3D *e = get_extra(bitmap); return e->system_texture; } /* Function: al_get_d3d_video_texture */ LPDIRECT3DTEXTURE9 al_get_d3d_video_texture(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_D3D *e = get_extra(bitmap); return e->video_texture; } /* Function: al_get_d3d_texture_position */ void al_get_d3d_texture_position(ALLEGRO_BITMAP *bitmap, int *u, int *v) { ASSERT(bitmap); ASSERT(u); ASSERT(v); *u = bitmap->xofs; *v = bitmap->yofs; } /* Function: al_is_d3d_device_lost */ bool al_is_d3d_device_lost(ALLEGRO_DISPLAY *display) { return ((ALLEGRO_DISPLAY_D3D *)display)->device_lost; } static void d3d_set_window_position(ALLEGRO_DISPLAY *display, int x, int y) { _al_win_set_window_position(((ALLEGRO_DISPLAY_WIN *)display)->window, x, y); } static void d3d_get_window_position(ALLEGRO_DISPLAY *display, int *x, int *y) { if (display->flags & ALLEGRO_FULLSCREEN) { ALLEGRO_MONITOR_INFO info; ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)display; al_get_monitor_info(win_display->adapter, &info); *x = info.x1; *y = info.y1; } else { _al_win_get_window_position(((ALLEGRO_DISPLAY_WIN *)display)->window, x, y); } } void _al_d3d_shutdown_display(void) { if (!vt) return; _al_d3d_destroy_display_format_list(); if (_al_d3d) _al_d3d->Release(); al_destroy_mutex(present_mutex); al_destroy_mutex(_al_d3d_lost_device_mutex); _al_d3d_bmp_destroy(); #ifdef ALLEGRO_CFG_SHADER_HLSL _al_d3d_shutdown_shaders(); #endif FreeLibrary(_al_d3d_module); _al_d3d_module = NULL; #ifdef ALLEGRO_CFG_D3DX9 _al_unload_d3dx9_module(); #endif al_free(vt); vt = NULL; } static void* d3d_prepare_vertex_cache(ALLEGRO_DISPLAY* disp, int num_new_vertices) { int size; if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { size = sizeof(ALLEGRO_VERTEX); } else { size = sizeof(D3D_FIXED_VERTEX); } disp->num_cache_vertices += num_new_vertices; if (!disp->vertex_cache) { disp->vertex_cache = al_malloc(num_new_vertices * size); disp->vertex_cache_size = num_new_vertices; } else if (disp->num_cache_vertices > disp->vertex_cache_size) { disp->vertex_cache = al_realloc(disp->vertex_cache, 2 * disp->num_cache_vertices * size); disp->vertex_cache_size = 2 * disp->num_cache_vertices; } return (unsigned char *)disp->vertex_cache + (disp->num_cache_vertices - num_new_vertices) * size; } static D3DTEXTUREADDRESS d3d_bitmap_wrap(ALLEGRO_BITMAP_WRAP wrap) { switch (wrap) { default: case ALLEGRO_BITMAP_WRAP_DEFAULT: return D3DTADDRESS_CLAMP; case ALLEGRO_BITMAP_WRAP_REPEAT: return D3DTADDRESS_WRAP; case ALLEGRO_BITMAP_WRAP_CLAMP: return D3DTADDRESS_CLAMP; case ALLEGRO_BITMAP_WRAP_MIRROR: return D3DTADDRESS_MIRROR; } } void _al_set_d3d_sampler_state(IDirect3DDevice9* device, int sampler, ALLEGRO_BITMAP* bitmap, bool prim_default) { int bitmap_flags = al_get_bitmap_flags(bitmap); ALLEGRO_BITMAP_WRAP wrap_u, wrap_v; _al_get_bitmap_wrap(bitmap, &wrap_u, &wrap_v); if (prim_default && wrap_u == ALLEGRO_BITMAP_WRAP_DEFAULT) { device->SetSamplerState(sampler, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); } else { device->SetSamplerState(sampler, D3DSAMP_ADDRESSU, d3d_bitmap_wrap(wrap_u)); } if (prim_default && wrap_v == ALLEGRO_BITMAP_WRAP_DEFAULT) { device->SetSamplerState(sampler, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); } else { device->SetSamplerState(sampler, D3DSAMP_ADDRESSV, d3d_bitmap_wrap(wrap_v)); } if (bitmap_flags & ALLEGRO_MIN_LINEAR) { device->SetSamplerState(sampler, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); } else { device->SetSamplerState(sampler, D3DSAMP_MINFILTER, D3DTEXF_POINT); } if (bitmap_flags & ALLEGRO_MAG_LINEAR) { device->SetSamplerState(sampler, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); } else { device->SetSamplerState(sampler, D3DSAMP_MAGFILTER, D3DTEXF_POINT); } if (bitmap_flags & ALLEGRO_MIPMAP) { device->SetSamplerState(sampler, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); } else { device->SetSamplerState(sampler, D3DSAMP_MIPFILTER, D3DTEXF_NONE); } } static void d3d_flush_vertex_cache(ALLEGRO_DISPLAY* disp) { if (!disp->vertex_cache) return; if (disp->num_cache_vertices == 0) return; ALLEGRO_DISPLAY_D3D* d3d_disp = (ALLEGRO_DISPLAY_D3D*)disp; ALLEGRO_BITMAP* cache_bmp = (ALLEGRO_BITMAP*)disp->cache_texture; ALLEGRO_BITMAP_EXTRA_D3D *d3d_bmp = get_extra(cache_bmp); if (d3d_disp->device_lost) return; _al_set_d3d_sampler_state(d3d_disp->device, 0, cache_bmp, false); if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { d3d_disp->device->SetFVF(D3DFVF_ALLEGRO_VERTEX); } #ifdef ALLEGRO_CFG_SHADER_HLSL UINT required_passes; if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { d3d_disp->effect->SetBool(ALLEGRO_SHADER_VAR_USE_TEX, true); d3d_disp->effect->SetTexture(ALLEGRO_SHADER_VAR_TEX, d3d_bmp->video_texture); d3d_disp->effect->Begin(&required_passes, 0); ASSERT(required_passes > 0); } #endif if (d3d_disp->device->SetTexture(0, d3d_bmp->video_texture) != D3D_OK) { ALLEGRO_ERROR("d3d_flush_vertex_cache: SetTexture failed.\n"); return; } int size; #ifdef ALLEGRO_CFG_SHADER_HLSL if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { size = sizeof(ALLEGRO_VERTEX); for (unsigned int i = 0; i < required_passes; i++) { d3d_disp->effect->BeginPass(i); if (d3d_disp->device->DrawPrimitiveUP(D3DPT_TRIANGLELIST, disp->num_cache_vertices / 3, (void *)disp->vertex_cache, size) != D3D_OK) { ALLEGRO_ERROR("d3d_flush_vertex_cache: DrawPrimitive failed.\n"); return; } d3d_disp->effect->EndPass(); } } else #endif { d3d_disp->device->SetFVF(D3DFVF_FIXED_VERTEX); size = sizeof(D3D_FIXED_VERTEX); if (d3d_disp->device->DrawPrimitiveUP(D3DPT_TRIANGLELIST, disp->num_cache_vertices / 3, (void *)disp->vertex_cache, size) != D3D_OK) { ALLEGRO_ERROR("d3d_flush_vertex_cache: DrawPrimitive failed.\n"); return; } } disp->num_cache_vertices = 0; #ifdef ALLEGRO_CFG_SHADER_HLSL if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { d3d_disp->effect->End(); d3d_disp->effect->SetBool(ALLEGRO_SHADER_VAR_USE_TEX, false); d3d_disp->effect->SetTexture(ALLEGRO_SHADER_VAR_TEX, NULL); } #endif d3d_disp->device->SetTexture(0, NULL); } static void d3d_update_transformation(ALLEGRO_DISPLAY* disp, ALLEGRO_BITMAP *target) { ALLEGRO_DISPLAY_D3D* d3d_disp = (ALLEGRO_DISPLAY_D3D*)disp; ALLEGRO_TRANSFORM proj; al_copy_transform(&proj, &target->proj_transform); /* Direct3D uses different clipping in projection space than OpenGL. * In OpenGL the final clip space is [-1..1] x [-1..1] x [-1..1]. * * In D3D the clip space is [-1..1] x [-1..1] x [0..1]. * * So we need to scale and translate the final z component from [-1..1] * to [0..1]. We do that by scaling with 0.5 then translating by 0.5 * below. * * The effect can be seen for example ex_projection - it is broken * without this. */ ALLEGRO_TRANSFORM fix_d3d; al_identity_transform(&fix_d3d); al_scale_transform_3d(&fix_d3d, 1, 1, 0.5); al_translate_transform_3d(&fix_d3d, 0.0, 0.0, 0.5); /* * Shift by half a pixel to make the output match the OpenGL output. * Don't shift the actual proj_transform because if the user grabs it via * al_get_current_projection_transform() and then sends it to * al_use_projection_transform() the shift will be applied twice. */ al_translate_transform(&fix_d3d, -1.0 / al_get_bitmap_width(target), 1.0 / al_get_bitmap_height(target)); al_compose_transform(&proj, &fix_d3d); if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { #ifdef ALLEGRO_CFG_SHADER_HLSL LPD3DXEFFECT effect = d3d_disp->effect; ALLEGRO_TRANSFORM projview; al_copy_transform(&projview, &target->transform); al_compose_transform(&projview, &proj); al_copy_transform(&disp->projview_transform, &projview); if (effect) { _al_hlsl_set_projview_matrix(effect, &projview); } #endif } else { d3d_disp->device->SetTransform(D3DTS_PROJECTION, (D3DMATRIX *)proj.m); d3d_disp->device->SetTransform(D3DTS_VIEW, (D3DMATRIX *)target->transform.m); } D3DVIEWPORT9 viewport; viewport.MinZ = 0; viewport.MaxZ = 1; viewport.Width = al_get_bitmap_width(target); viewport.Height = al_get_bitmap_height(target); if (target->parent) { viewport.X = target->xofs; viewport.Y = target->yofs; } else { viewport.X = 0; viewport.Y = 0; } d3d_disp->device->SetViewport(&viewport); } /* Initialize and obtain a reference to this driver. */ ALLEGRO_DISPLAY_INTERFACE *_al_display_d3d_driver(void) { if (vt) return vt; if (!d3d_init_display()) return NULL; vt = (ALLEGRO_DISPLAY_INTERFACE *)al_malloc(sizeof *vt); memset(vt, 0, sizeof *vt); vt->create_display = d3d_create_display; vt->destroy_display = d3d_destroy_display; vt->set_current_display = d3d_set_current_display; vt->clear = d3d_clear; vt->clear_depth_buffer = d3d_clear_depth_buffer; vt->draw_pixel = d3d_draw_pixel; vt->flip_display = d3d_flip_display; vt->update_display_region = d3d_update_display_region; vt->acknowledge_resize = d3d_acknowledge_resize; vt->resize_display = d3d_resize_display; vt->create_bitmap = d3d_create_bitmap; vt->set_target_bitmap = d3d_set_target_bitmap; vt->get_backbuffer = d3d_get_backbuffer; vt->is_compatible_bitmap = d3d_is_compatible_bitmap; vt->switch_out = d3d_switch_out; vt->switch_in = d3d_switch_in; vt->draw_memory_bitmap_region = NULL; vt->wait_for_vsync = d3d_wait_for_vsync; vt->set_mouse_cursor = _al_win_set_mouse_cursor; vt->set_system_mouse_cursor = _al_win_set_system_mouse_cursor; vt->show_mouse_cursor = _al_win_show_mouse_cursor; vt->hide_mouse_cursor = _al_win_hide_mouse_cursor; vt->set_icons = _al_win_set_display_icons; vt->set_window_position = d3d_set_window_position; vt->get_window_position = d3d_get_window_position; vt->get_window_borders = _al_win_get_window_borders; vt->set_window_constraints = _al_win_set_window_constraints; vt->get_window_constraints = _al_win_get_window_constraints; vt->apply_window_constraints = _al_win_apply_window_constraints; vt->set_display_flag = _al_win_set_display_flag; vt->set_window_title = _al_win_set_window_title; vt->flush_vertex_cache = d3d_flush_vertex_cache; vt->prepare_vertex_cache = d3d_prepare_vertex_cache; vt->update_transformation = d3d_update_transformation; vt->update_render_state = _al_d3d_update_render_state; _al_win_add_clipboard_functions(vt); return vt; } int _al_d3d_get_num_display_modes(int format, int refresh_rate, int flags) { UINT num_modes; UINT i, j; D3DDISPLAYMODE display_mode; int matches = 0; if (!_al_d3d && !d3d_init_display()) return 0; (void)flags; /* If any, go through all formats */ if (!_al_pixel_format_is_real(format)) { j = 0; } /* Else find the matching format */ else { for (j = 0; allegro_formats[j] != -1; j++) { if (allegro_formats[j] == format) break; } if (allegro_formats[j] == -1) return 0; } for (; allegro_formats[j] != -1; j++) { int adapter = al_get_new_display_adapter(); if (adapter < 0) adapter = 0; if (!_al_pixel_format_is_real(allegro_formats[j]) || _al_pixel_format_has_alpha(allegro_formats[j])) continue; num_modes = _al_d3d->GetAdapterModeCount(adapter, (D3DFORMAT)d3d_formats[j]); for (i = 0; i < num_modes; i++) { if (_al_d3d->EnumAdapterModes(adapter, (D3DFORMAT)d3d_formats[j], i, &display_mode) != D3D_OK) { return matches; } if (refresh_rate && display_mode.RefreshRate != (unsigned)refresh_rate) continue; matches++; } if (_al_pixel_format_is_real(format)) break; } return matches; } ALLEGRO_DISPLAY_MODE *_al_d3d_get_display_mode(int index, int format, int refresh_rate, int flags, ALLEGRO_DISPLAY_MODE *mode) { UINT num_modes; UINT i, j; D3DDISPLAYMODE display_mode; int matches = 0; if (!_al_d3d && !d3d_init_display()) return NULL; (void)flags; /* If any, go through all formats */ if (!_al_pixel_format_is_real(format)) { j = 0; } /* Else find the matching format */ else { for (j = 0; allegro_formats[j] != -1; j++) { if (allegro_formats[j] == format) break; } if (allegro_formats[j] == -1) return NULL; } for (; allegro_formats[j] != -1; j++) { int adapter = al_get_new_display_adapter(); if (adapter < 0) adapter = 0; if (!_al_pixel_format_is_real(allegro_formats[j]) || _al_pixel_format_has_alpha(allegro_formats[j])) continue; num_modes = _al_d3d->GetAdapterModeCount(adapter, (D3DFORMAT)d3d_formats[j]); for (i = 0; i < num_modes; i++) { if (_al_d3d->EnumAdapterModes(adapter, (D3DFORMAT)d3d_formats[j], i, &display_mode) != D3D_OK) { return NULL; } if (refresh_rate && display_mode.RefreshRate != (unsigned)refresh_rate) continue; if (matches == index) { mode->width = display_mode.Width; mode->height = display_mode.Height; mode->format = allegro_formats[j]; mode->refresh_rate = display_mode.RefreshRate; return mode; } matches++; } if (_al_pixel_format_is_real(format)) break; } return mode; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/d3d_display_formats.cpp000066400000000000000000000144631473414355200215120ustar00rootroot00000000000000#include "d3d.h" ALLEGRO_DEBUG_CHANNEL("d3d") struct DEPTH_STENCIL_DESC { int d; int s; D3DFORMAT format; }; static DEPTH_STENCIL_DESC depth_stencil_formats[] = { { 0, 0, (D3DFORMAT)0 }, { 32, 0, D3DFMT_D32 }, { 15, 1, D3DFMT_D15S1 }, { 24, 8, D3DFMT_D24S8 }, { 24, 0, D3DFMT_D24X8 }, { 24, 4, D3DFMT_D24X4S4 }, { 16, 0, D3DFMT_D16 }, }; static BOOL IsDepthFormatExisting(D3DFORMAT DepthFormat, D3DFORMAT AdapterFormat) { HRESULT hr = _al_d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, AdapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, DepthFormat); return SUCCEEDED(hr); } static const int D3D_DEPTH_FORMATS = sizeof(depth_stencil_formats) / sizeof(*depth_stencil_formats); static _AL_VECTOR eds_list; void _al_d3d_destroy_display_format_list(void) { /* Free the display format list */ for (int j = 0; j < (int)_al_vector_size(&eds_list); j++) { void **eds = (void **)_al_vector_ref(&eds_list, j); al_free(*eds); } _al_vector_free(&eds_list); } void _al_d3d_generate_display_format_list(void) { static bool fullscreen = !(al_get_new_display_flags() & ALLEGRO_FULLSCREEN); /* stop warning */ static int adapter = ~al_get_new_display_adapter(); /* stop warning */ int i; if (!_al_vector_is_empty(&eds_list) && (fullscreen == (bool)(al_get_new_display_flags() & ALLEGRO_FULLSCREEN)) && (adapter == al_get_new_display_adapter())) { return; } else if (!_al_vector_is_empty(&eds_list)) { _al_d3d_destroy_display_format_list(); } fullscreen = (al_get_new_display_flags() & ALLEGRO_FULLSCREEN) != 0; adapter = al_get_new_display_adapter(); if (adapter < 0) adapter = 0; _al_vector_init(&eds_list, sizeof(ALLEGRO_EXTRA_DISPLAY_SETTINGS *)); /* Loop through each bit combination of: * bit 0: 16/32 bit * bit 1: single-buffer * bit 2: vsync */ for (i = 0; i < 8; i++) { int format_num = !!(i & 1); int single_buffer = !!(i & 2); int vsync = !!(i & 4); int allegro_format = ALLEGRO_PIXEL_FORMAT_XRGB_8888; if (format_num == 1) allegro_format = ALLEGRO_PIXEL_FORMAT_RGB_565; D3DFORMAT d3d_format = (D3DFORMAT)_al_pixel_format_to_d3d(allegro_format); /* Count available multisample quality levels. */ DWORD quality_levels = 0; if (_al_d3d->CheckDeviceMultiSampleType(adapter, D3DDEVTYPE_HAL, d3d_format, !fullscreen, D3DMULTISAMPLE_NONMASKABLE, &quality_levels) != D3D_OK) { _al_d3d->CheckDeviceMultiSampleType(adapter, D3DDEVTYPE_REF, d3d_format, !fullscreen, D3DMULTISAMPLE_NONMASKABLE, &quality_levels); } /* Loop through available depth/stencil formats. */ for (int j = 0; j < D3D_DEPTH_FORMATS; j++) { if (j == 0 || IsDepthFormatExisting( depth_stencil_formats[j].format, d3d_format)) { DEPTH_STENCIL_DESC *ds = depth_stencil_formats + j; for (int k = 0; k < (int)quality_levels + 1; k++) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds, **peds; peds = (ALLEGRO_EXTRA_DISPLAY_SETTINGS **)_al_vector_alloc_back(&eds_list); eds = *peds = (ALLEGRO_EXTRA_DISPLAY_SETTINGS *)al_malloc(sizeof *eds); memset(eds->settings, 0, sizeof(int) * ALLEGRO_DISPLAY_OPTIONS_COUNT); eds->settings[ALLEGRO_COMPATIBLE_DISPLAY] = 1; if (format_num == 0) { eds->settings[ALLEGRO_RED_SIZE] = 8; eds->settings[ALLEGRO_GREEN_SIZE] = 8; eds->settings[ALLEGRO_BLUE_SIZE] = 8; eds->settings[ALLEGRO_RED_SHIFT] = 16; eds->settings[ALLEGRO_GREEN_SHIFT] = 8; eds->settings[ALLEGRO_BLUE_SHIFT] = 0; eds->settings[ALLEGRO_COLOR_SIZE] = 32; } else if (format_num == 1) { eds->settings[ALLEGRO_RED_SIZE] = 5; eds->settings[ALLEGRO_GREEN_SIZE] = 6; eds->settings[ALLEGRO_BLUE_SIZE] = 5; eds->settings[ALLEGRO_RED_SHIFT] = 11; eds->settings[ALLEGRO_GREEN_SHIFT] = 5; eds->settings[ALLEGRO_BLUE_SHIFT] = 0; eds->settings[ALLEGRO_COLOR_SIZE] = 16; } if (single_buffer) { eds->settings[ALLEGRO_SINGLE_BUFFER] = 1; eds->settings[ALLEGRO_UPDATE_DISPLAY_REGION] = 1; } if (vsync) { eds->settings[ALLEGRO_VSYNC] = 1; } eds->settings[ALLEGRO_DEPTH_SIZE] = ds->d; eds->settings[ALLEGRO_STENCIL_SIZE] = ds->s; if (k > 1) { eds->settings[ALLEGRO_SAMPLE_BUFFERS] = 1; // TODO: Is it ok to use the quality level here? eds->settings[ALLEGRO_SAMPLES] = k; } } } } } ALLEGRO_INFO("found %d format combinations\n", (int)_al_vector_size(&eds_list)); } void _al_d3d_score_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref) { for (int i = 0; i < (int)_al_vector_size(&eds_list); i++) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds, **peds; peds = (ALLEGRO_EXTRA_DISPLAY_SETTINGS **)_al_vector_ref(&eds_list, i); eds = *peds; eds->score = _al_score_display_settings(eds, ref); eds->index = i; } qsort(eds_list._items, eds_list._size, eds_list._itemsize, _al_display_settings_sorter); } /* Helper function for sorting pixel formats by index */ static int d3d_display_list_resorter(const void *p0, const void *p1) { const ALLEGRO_EXTRA_DISPLAY_SETTINGS *f0 = *((ALLEGRO_EXTRA_DISPLAY_SETTINGS **)p0); const ALLEGRO_EXTRA_DISPLAY_SETTINGS *f1 = *((ALLEGRO_EXTRA_DISPLAY_SETTINGS **)p1); if (!f0) return 1; if (!f1) return -1; if (f0->index == f1->index) { return 0; } else if (f0->index < f1->index) { return -1; } else { return 1; } } void _al_d3d_resort_display_settings(void) { qsort(eds_list._items, eds_list._size, eds_list._itemsize, d3d_display_list_resorter); } ALLEGRO_EXTRA_DISPLAY_SETTINGS *_al_d3d_get_display_settings(int i) { if (i < (int)_al_vector_size(&eds_list)) return *(ALLEGRO_EXTRA_DISPLAY_SETTINGS **)_al_vector_ref(&eds_list, i); return NULL; } allegro5-5.2.10.1/src/win/d3d_render_state.cpp000066400000000000000000000031231473414355200207600ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/internal/aintern_display.h" #include "d3d.h" /* Note: synched to ALLEGRO_RENDER_FUNCTION values as array indices */ static int _d3d_funcs[] = { D3DCMP_NEVER, D3DCMP_ALWAYS, D3DCMP_LESS, D3DCMP_EQUAL, D3DCMP_LESSEQUAL, D3DCMP_GREATER, D3DCMP_NOTEQUAL, D3DCMP_GREATEREQUAL }; void _al_d3d_update_render_state(ALLEGRO_DISPLAY *display) { _ALLEGRO_RENDER_STATE *r = &display->render_state; ALLEGRO_DISPLAY_D3D *disp = (ALLEGRO_DISPLAY_D3D *)display; if (!disp->device) return; /* TODO: We could store the previous state and/or mark updated states to * avoid so many redundant SetRenderState calls. */ disp->device->SetRenderState(D3DRS_ALPHATESTENABLE, r->alpha_test ? TRUE : FALSE); disp->device->SetRenderState(D3DRS_ALPHAFUNC, _d3d_funcs[r->alpha_function]); disp->device->SetRenderState(D3DRS_ALPHAREF, r->alpha_test_value); disp->device->SetRenderState(D3DRS_ZENABLE, r->depth_test ? D3DZB_TRUE : D3DZB_FALSE); disp->device->SetRenderState(D3DRS_ZFUNC, _d3d_funcs[r->depth_function]); disp->device->SetRenderState(D3DRS_ZWRITEENABLE, (r->write_mask & ALLEGRO_MASK_DEPTH) ? TRUE : FALSE); disp->device->SetRenderState(D3DRS_COLORWRITEENABLE, ((r->write_mask & ALLEGRO_MASK_RED) ? D3DCOLORWRITEENABLE_RED : 0) | ((r->write_mask & ALLEGRO_MASK_GREEN) ? D3DCOLORWRITEENABLE_GREEN : 0) | ((r->write_mask & ALLEGRO_MASK_BLUE) ? D3DCOLORWRITEENABLE_BLUE : 0) | ((r->write_mask & ALLEGRO_MASK_ALPHA) ? D3DCOLORWRITEENABLE_ALPHA : 0)); } allegro5-5.2.10.1/src/win/d3d_shader.cpp000066400000000000000000000340341473414355200175540ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Direct3D shader support. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/allegro_direct3d.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_direct3d.h" #include "allegro5/internal/aintern_shader.h" #ifdef ALLEGRO_CFG_SHADER_HLSL #include #include #include "d3d.h" ALLEGRO_DEBUG_CHANNEL("shader") static _AL_VECTOR shaders; struct ALLEGRO_SHADER_HLSL_S { ALLEGRO_SHADER shader; LPD3DXEFFECT hlsl_shader; int shader_model; }; static const char *null_source = ""; static const char *technique_source_vertex_v2 = "technique TECH\n" "{\n" " pass p1\n" " {\n" " VertexShader = compile vs_2_0 vs_main();\n" " PixelShader = null;\n" " }\n" "}\n"; static const char *technique_source_pixel_v2 = "technique TECH\n" "{\n" " pass p1\n" " {\n" " VertexShader = null;\n" " PixelShader = compile ps_2_0 ps_main();\n" " }\n" "}\n\n"; static const char *technique_source_both_v2 = "technique TECH\n" "{\n" " pass p1\n" " {\n" " VertexShader = compile vs_2_0 vs_main();\n" " PixelShader = compile ps_2_0 ps_main();\n" " }\n" "}\n"; static const char *technique_source_vertex_v3 = "technique TECH\n" "{\n" " pass p1\n" " {\n" " VertexShader = compile vs_3_0 vs_main();\n" " PixelShader = null;\n" " }\n" "}\n"; static const char *technique_source_pixel_v3 = "technique TECH\n" "{\n" " pass p1\n" " {\n" " VertexShader = null;\n" " PixelShader = compile ps_3_0 ps_main();\n" " }\n" "}\n\n"; static const char *technique_source_both_v3 = "technique TECH\n" "{\n" " pass p1\n" " {\n" " VertexShader = compile vs_3_0 vs_main();\n" " PixelShader = compile ps_3_0 ps_main();\n" " }\n" "}\n"; static bool hlsl_attach_shader_source(ALLEGRO_SHADER *shader, ALLEGRO_SHADER_TYPE type, const char *source); static bool hlsl_build_shader(ALLEGRO_SHADER *shader); static bool hlsl_use_shader(ALLEGRO_SHADER *shader, ALLEGRO_DISPLAY *display, bool set_projview_matrix_from_display); static void hlsl_unuse_shader(ALLEGRO_SHADER *shader, ALLEGRO_DISPLAY *display); static void hlsl_destroy_shader(ALLEGRO_SHADER *shader); static void hlsl_on_lost_device(ALLEGRO_SHADER *shader); static void hlsl_on_reset_device(ALLEGRO_SHADER *shader); static bool hlsl_set_shader_sampler(ALLEGRO_SHADER *shader, const char *name, ALLEGRO_BITMAP *bitmap, int unit); static bool hlsl_set_shader_matrix(ALLEGRO_SHADER *shader, const char *name, const ALLEGRO_TRANSFORM *matrix); static bool hlsl_set_shader_int(ALLEGRO_SHADER *shader, const char *name, int i); static bool hlsl_set_shader_float(ALLEGRO_SHADER *shader, const char *name, float f); static bool hlsl_set_shader_int_vector(ALLEGRO_SHADER *shader, const char *name, int num_components, const int *i, int num_elems); static bool hlsl_set_shader_float_vector(ALLEGRO_SHADER *shader, const char *name, int num_components, const float *f, int num_elems); static bool hlsl_set_shader_bool(ALLEGRO_SHADER *shader, const char *name, bool b); static struct ALLEGRO_SHADER_INTERFACE shader_hlsl_vt = { hlsl_attach_shader_source, hlsl_build_shader, hlsl_use_shader, hlsl_unuse_shader, hlsl_destroy_shader, hlsl_on_lost_device, hlsl_on_reset_device, hlsl_set_shader_sampler, hlsl_set_shader_matrix, hlsl_set_shader_int, hlsl_set_shader_float, hlsl_set_shader_int_vector, hlsl_set_shader_float_vector, hlsl_set_shader_bool }; void _al_d3d_on_lost_shaders(ALLEGRO_DISPLAY *display) { unsigned i; (void)display; for (i = 0; i < _al_vector_size(&shaders); i++) { ALLEGRO_SHADER **shader = (ALLEGRO_SHADER **)_al_vector_ref(&shaders, i); (*shader)->vt->on_lost_device(*shader); } } void _al_d3d_on_reset_shaders(ALLEGRO_DISPLAY *display) { unsigned i; (void)display; for (i = 0; i < _al_vector_size(&shaders); i++) { ALLEGRO_SHADER **shader = (ALLEGRO_SHADER **)_al_vector_ref(&shaders, i); (*shader)->vt->on_reset_device(*shader); } } ALLEGRO_SHADER *_al_create_shader_hlsl(ALLEGRO_SHADER_PLATFORM platform, int shader_model) { ALLEGRO_SHADER_HLSL_S *shader; if (NULL == _al_imp_D3DXCreateEffect) { ALLEGRO_ERROR("D3DXCreateEffect unavailable\n"); return NULL; } shader = (ALLEGRO_SHADER_HLSL_S *)al_calloc(1, sizeof(ALLEGRO_SHADER_HLSL_S)); if (!shader) return NULL; shader->shader.platform = platform; shader->shader.vt = &shader_hlsl_vt; shader->shader_model = shader_model; _al_vector_init(&shader->shader.bitmaps, sizeof(ALLEGRO_BITMAP *)); // For simplicity, these fields are never NULL in this backend. shader->shader.pixel_copy = al_ustr_new(""); shader->shader.vertex_copy = al_ustr_new(""); ALLEGRO_SHADER **back = (ALLEGRO_SHADER **)_al_vector_alloc_back(&shaders); *back = (ALLEGRO_SHADER *)shader; _al_add_display_invalidated_callback(al_get_current_display(), _al_d3d_on_lost_shaders); _al_add_display_validated_callback(al_get_current_display(), _al_d3d_on_reset_shaders); return (ALLEGRO_SHADER *)shader; } static bool hlsl_attach_shader_source(ALLEGRO_SHADER *shader, ALLEGRO_SHADER_TYPE type, const char *source) { bool add_technique; ALLEGRO_USTR *full_source; LPD3DXBUFFER errors; const char *vertex_source, *pixel_source, *technique_source; ALLEGRO_SHADER_HLSL_S *hlsl_shader = (ALLEGRO_SHADER_HLSL_S *)shader; ALLEGRO_DISPLAY *display = al_get_current_display(); ASSERT(display); ASSERT(display->flags & ALLEGRO_DIRECT3D); if (source == NULL) { if (type == ALLEGRO_VERTEX_SHADER) { if (shader->vertex_copy) { al_ustr_truncate(shader->vertex_copy, 0); hlsl_shader->hlsl_shader->Release(); } vertex_source = null_source; pixel_source = al_cstr(shader->pixel_copy); } else { if (shader->pixel_copy) { al_ustr_truncate(shader->pixel_copy, 0); hlsl_shader->hlsl_shader->Release(); } pixel_source = null_source; vertex_source = al_cstr(shader->vertex_copy); } } else { if (type == ALLEGRO_VERTEX_SHADER) { vertex_source = source; al_ustr_truncate(shader->vertex_copy, 0); al_ustr_append_cstr(shader->vertex_copy, vertex_source); pixel_source = al_cstr(shader->pixel_copy); } else { pixel_source = source; al_ustr_truncate(shader->pixel_copy, 0); al_ustr_append_cstr(shader->pixel_copy, pixel_source); vertex_source = al_cstr(shader->vertex_copy); } } if (vertex_source[0] == 0 && pixel_source[0] == 0) { return false; } if (strstr(vertex_source, "technique") || strstr(pixel_source, "technique")) add_technique = false; else add_technique = true; if (hlsl_shader->shader_model == 3) { if (add_technique) { if (vertex_source[0] == 0) { technique_source = technique_source_pixel_v3; } else if (pixel_source[0] == 0) { technique_source = technique_source_vertex_v3; } else { technique_source = technique_source_both_v3; } } else { technique_source = null_source; } } else { if (add_technique) { if (vertex_source[0] == 0) { technique_source = technique_source_pixel_v2; } else if (pixel_source[0] == 0) { technique_source = technique_source_vertex_v2; } else { technique_source = technique_source_both_v2; } } else { technique_source = null_source; } } // HLSL likes the source in one buffer full_source = al_ustr_newf("%s\n#line 1\n%s\n%s\n", vertex_source, pixel_source, technique_source); // Release the shader if we already created it if (hlsl_shader->hlsl_shader) hlsl_shader->hlsl_shader->Release(); DWORD ok = _al_imp_D3DXCreateEffect( al_get_d3d_device(display), al_cstr(full_source), al_ustr_size(full_source), NULL, NULL, D3DXSHADER_PACKMATRIX_ROWMAJOR, NULL, &hlsl_shader->hlsl_shader, &errors ); al_ustr_free(full_source); if (ok != D3D_OK) { hlsl_shader->hlsl_shader = NULL; char *msg = (char *)errors->GetBufferPointer(); if (shader->log) { al_ustr_truncate(shader->log, 0); al_ustr_append_cstr(shader->log, msg); } else { shader->log = al_ustr_new(msg); } ALLEGRO_ERROR("Error: %s\n", msg); return false; } D3DXHANDLE hTech; hTech = hlsl_shader->hlsl_shader->GetTechniqueByName("TECH"); hlsl_shader->hlsl_shader->ValidateTechnique(hTech); hlsl_shader->hlsl_shader->SetTechnique(hTech); return true; } static bool hlsl_build_shader(ALLEGRO_SHADER *shader) { (void)shader; return true; } static bool hlsl_use_shader(ALLEGRO_SHADER *shader, ALLEGRO_DISPLAY *display, bool set_projview_matrix_from_display) { ALLEGRO_SHADER_HLSL_S *hlsl_shader = (ALLEGRO_SHADER_HLSL_S *)shader; LPD3DXEFFECT effect = hlsl_shader->hlsl_shader; ALLEGRO_DISPLAY_D3D *d3d_disp; if (!(display->flags & ALLEGRO_DIRECT3D)) { return false; } d3d_disp = (ALLEGRO_DISPLAY_D3D *)display; if (set_projview_matrix_from_display) { if (!_al_hlsl_set_projview_matrix(effect, &display->projview_transform)) { d3d_disp->effect = NULL; return false; } } d3d_disp->effect = hlsl_shader->hlsl_shader; return true; } static void hlsl_unuse_shader(ALLEGRO_SHADER *shader, ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)display; (void)shader; //effect->EndPass(); //effect->End(); d3d_disp->effect = NULL; } static void hlsl_destroy_shader(ALLEGRO_SHADER *shader) { ALLEGRO_SHADER_HLSL_S *hlsl_shader = (ALLEGRO_SHADER_HLSL_S *)shader; if (hlsl_shader->hlsl_shader) hlsl_shader->hlsl_shader->Release(); _al_vector_find_and_delete(&shaders, &shader); al_free(shader); } static void hlsl_on_lost_device(ALLEGRO_SHADER *shader) { ALLEGRO_SHADER_HLSL_S *hlsl_shader = (ALLEGRO_SHADER_HLSL_S *)shader; hlsl_shader->hlsl_shader->OnLostDevice(); } static void hlsl_on_reset_device(ALLEGRO_SHADER *shader) { ALLEGRO_SHADER_HLSL_S *hlsl_shader = (ALLEGRO_SHADER_HLSL_S *)shader; hlsl_shader->hlsl_shader->OnResetDevice(); } static bool hlsl_set_shader_sampler(ALLEGRO_SHADER *shader, const char *name, ALLEGRO_BITMAP *bitmap, int unit) { ALLEGRO_SHADER_HLSL_S *hlsl_shader = (ALLEGRO_SHADER_HLSL_S *)shader; HRESULT result; if (al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP) return false; LPDIRECT3DTEXTURE9 vid_texture = al_get_d3d_video_texture(bitmap); result = hlsl_shader->hlsl_shader->SetTexture(name, vid_texture); ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)_al_get_bitmap_display(bitmap); d3d_disp->device->SetTexture(unit, vid_texture); _al_set_d3d_sampler_state(d3d_disp->device, unit, bitmap, false); return result == D3D_OK; } static bool hlsl_set_shader_matrix(ALLEGRO_SHADER *shader, const char *name, const ALLEGRO_TRANSFORM *matrix) { ALLEGRO_SHADER_HLSL_S *hlsl_shader = (ALLEGRO_SHADER_HLSL_S *)shader; HRESULT result; D3DXMATRIX m; memcpy(m.m, matrix->m, sizeof(float)*16); result = hlsl_shader->hlsl_shader->SetMatrix(name, &m); return result == D3D_OK; } static bool hlsl_set_shader_int(ALLEGRO_SHADER *shader, const char *name, int i) { ALLEGRO_SHADER_HLSL_S *hlsl_shader = (ALLEGRO_SHADER_HLSL_S *)shader; HRESULT result; result = hlsl_shader->hlsl_shader->SetInt(name, i); return result == D3D_OK; } static bool hlsl_set_shader_float(ALLEGRO_SHADER *shader, const char *name, float f) { ALLEGRO_SHADER_HLSL_S *hlsl_shader = (ALLEGRO_SHADER_HLSL_S *)shader; HRESULT result; result = hlsl_shader->hlsl_shader->SetFloat(name, f); return result == D3D_OK; } static bool hlsl_set_shader_int_vector(ALLEGRO_SHADER *shader, const char *name, int num_components, const int *i, int num_elems) { ALLEGRO_SHADER_HLSL_S *hlsl_shader = (ALLEGRO_SHADER_HLSL_S *)shader; HRESULT result; result = hlsl_shader->hlsl_shader->SetIntArray(name, i, num_components * num_elems); return result == D3D_OK; } static bool hlsl_set_shader_float_vector(ALLEGRO_SHADER *shader, const char *name, int num_components, const float *f, int num_elems) { ALLEGRO_SHADER_HLSL_S *hlsl_shader = (ALLEGRO_SHADER_HLSL_S *)shader; HRESULT result; result = hlsl_shader->hlsl_shader->SetFloatArray(name, f, num_components * num_elems); return result == D3D_OK; } static bool hlsl_set_shader_bool(ALLEGRO_SHADER *shader, const char *name, bool b) { ALLEGRO_SHADER_HLSL_S *hlsl_shader = (ALLEGRO_SHADER_HLSL_S *)shader; HRESULT result; result = hlsl_shader->hlsl_shader->SetBool(name, b); return result == D3D_OK; } bool _al_hlsl_set_projview_matrix( LPD3DXEFFECT effect, const ALLEGRO_TRANSFORM *t) { HRESULT result = effect->SetMatrix(ALLEGRO_SHADER_VAR_PROJVIEW_MATRIX, (LPD3DXMATRIX)t->m); return result == D3D_OK; } void _al_d3d_init_shaders(void) { _al_vector_init(&shaders, sizeof(ALLEGRO_SHADER *)); } void _al_d3d_shutdown_shaders(void) { _al_vector_free(&shaders); } #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/wclipboard.c000066400000000000000000000070751473414355200173470ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_//_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows clipboard handling. * * By Beoran. * * See readme.txt for copyright information. */ #define _WIN32_WINNT 0x0501 #ifndef WINVER #define WINVER 0x0501 #endif #include #include #include #include "allegro5/allegro_windows.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_wclipboard.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_wunicode.h" #include "allegro5/platform/aintwin.h" ALLEGRO_DEBUG_CHANNEL("clipboard") #ifdef UNICODE #define TEXT_FORMAT CF_UNICODETEXT #else #define TEXT_FORMAT CF_TEXT #endif /* Get any application owned window handle for clipboard association */ static HWND get_window_handle(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)display; if (!win_display) return NULL; return win_display->window; } static bool win_set_clipboard_text(ALLEGRO_DISPLAY *display, const char *text) { HWND handle = get_window_handle(display); HANDLE hMem = NULL; TCHAR *tstr = NULL; size_t size; size_t len; LPTSTR dst; if (!OpenClipboard(handle)) { ALLEGRO_DEBUG("Could not open clipboard for handle %p", handle); return false; } /* Convert the text from UTF-8 to Windows Unicode */ tstr = _twin_utf8_to_tchar(text); len = _twin_tchar_strlen(tstr); size = (len+1) * sizeof(TCHAR); /* Save the data to the clipboard */ hMem = GlobalAlloc(GMEM_MOVEABLE, size); if (!hMem) { al_free(tstr); ALLEGRO_DEBUG("GlobalAlloc failed to allocate memory for the clipboard data"); return false; } dst = (LPTSTR)GlobalLock(hMem); /* Copy the text over. Unlike SDL, do NOT convert newlines, that's for the * use to decide. */ memmove(dst, tstr, size); dst[len] = 0; GlobalUnlock(hMem); EmptyClipboard(); if (!SetClipboardData(TEXT_FORMAT, hMem)) { al_free(tstr); ALLEGRO_DEBUG("Couldn't set clipboard data"); return false; } al_free(tstr); CloseClipboard(); return true; } static char *win_get_clipboard_text(ALLEGRO_DISPLAY *display) { char *text; text = NULL; if (IsClipboardFormatAvailable(TEXT_FORMAT) && OpenClipboard(get_window_handle(display))) { HANDLE hMem; LPTSTR tstr; hMem = GetClipboardData(TEXT_FORMAT); if (hMem) { tstr = (LPTSTR)GlobalLock(hMem); text = _twin_tchar_to_utf8(tstr); GlobalUnlock(hMem); } else { ALLEGRO_DEBUG("Couldn't get clipboard data"); } CloseClipboard(); } return text; } static bool win_has_clipboard_text(ALLEGRO_DISPLAY *display) { if (!IsClipboardFormatAvailable(TEXT_FORMAT)) return false; if (!OpenClipboard(get_window_handle(display))) return false; CloseClipboard(); return true; } void _al_win_add_clipboard_functions(ALLEGRO_DISPLAY_INTERFACE *vt) { vt->set_clipboard_text = win_set_clipboard_text; vt->get_clipboard_text = win_get_clipboard_text; vt->has_clipboard_text = win_has_clipboard_text; } /* vi: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/wgl.h000066400000000000000000000005161473414355200160100ustar00rootroot00000000000000#include "allegro5/internal/aintern_display.h" #include "allegro5/platform/aintwin.h" #include typedef struct ALLEGRO_DISPLAY_WGL { ALLEGRO_DISPLAY_WIN win_display; /* This must be the first member. */ /* Driver specifics */ HDC dc; HGLRC glrc; } ALLEGRO_DISPLAY_WGL; int _al_win_determine_adapter(void); allegro5-5.2.10.1/src/win/wgl_disp.c000066400000000000000000001421321473414355200170230ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows OpenGL display driver * * By Milan Mimica. * Based on AllegroGL Windows display driver. * */ #if 0 /* Raw input */ #define _WIN32_WINNT 0x0501 #ifndef WINVER #define WINVER 0x0501 #endif #endif #include #include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/system.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_vector.h" #include "allegro5/internal/aintern_wclipboard.h" #include "allegro5/platform/aintwin.h" #include "allegro5/internal/aintern_wunicode.h" #include "wgl.h" #include ALLEGRO_DEBUG_CHANNEL("display") static ALLEGRO_DISPLAY_INTERFACE vt; /* Forward declarations: */ static void display_thread_proc(void *arg); static void destroy_display_internals(ALLEGRO_DISPLAY_WGL *wgl_disp); static bool wgl_acknowledge_resize(ALLEGRO_DISPLAY *d); /* Prevents switching to desktop resolution when destroying the display. Used on full screen resize. */ static bool _wgl_do_not_change_display_mode = false; /* * These parameters cannot be gotten by the display thread because * they're thread local. We get them in the calling thread first. */ typedef struct WGL_DISPLAY_PARAMETERS { ALLEGRO_DISPLAY_WGL *display; volatile bool init_failed; HANDLE AckEvent; int window_x, window_y; /* Not owned. */ const char* window_title; } WGL_DISPLAY_PARAMETERS; static bool is_wgl_extension_supported(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB, const char *extension, HDC dc) { bool ret = false; const GLubyte* extensions; if (_wglGetExtensionsStringARB) { extensions = (const GLubyte*)_wglGetExtensionsStringARB(dc); } else { /* XXX deprecated in OpenGL 3.0 */ extensions = glGetString(GL_EXTENSIONS); } if (extensions) { ret = _al_ogl_look_for_an_extension(extension, extensions); } return ret; } static HGLRC init_temp_context(HWND wnd) { PIXELFORMATDESCRIPTOR pfd; int pf; HDC dc; HGLRC glrc; dc = GetDC(wnd); memset(&pfd, 0, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER_DONTCARE | PFD_STEREO_DONTCARE; pfd.iPixelType = PFD_TYPE_RGBA; pfd.iLayerType = PFD_MAIN_PLANE; pfd.cColorBits = 32; pf = ChoosePixelFormat(dc, &pfd); if (!pf) { ALLEGRO_ERROR("Unable to chose a temporary pixel format. %s\n", _al_win_last_error()); return NULL; } memset(&pfd, 0, sizeof(pfd)); if (!SetPixelFormat(dc, pf, &pfd)) { ALLEGRO_ERROR("Unable to set a temporary pixel format. %s\n", _al_win_last_error()); return NULL; } glrc = wglCreateContext(dc); if (!glrc) { ALLEGRO_ERROR("Unable to create a render context. %s\n", _al_win_last_error()); return NULL; } if (!wglMakeCurrent(dc, glrc)) { ALLEGRO_ERROR("Unable to set the render context as current. %s\n", _al_win_last_error()); wglDeleteContext(glrc); return NULL; } return glrc; } static _ALLEGRO_wglGetPixelFormatAttribivARB_t _wglGetPixelFormatAttribivARB = NULL; static _ALLEGRO_wglGetPixelFormatAttribivEXT_t _wglGetPixelFormatAttribivEXT = NULL; static bool init_pixel_format_extensions(void) { /* Load the ARB_p_f symbol - Note, we shouldn't use the extension * mechanism here, because it hasn't been initialized yet! */ _wglGetPixelFormatAttribivARB = (_ALLEGRO_wglGetPixelFormatAttribivARB_t)wglGetProcAddress("wglGetPixelFormatAttribivARB"); _wglGetPixelFormatAttribivEXT = (_ALLEGRO_wglGetPixelFormatAttribivEXT_t)wglGetProcAddress("wglGetPixelFormatAttribivEXT"); if (!_wglGetPixelFormatAttribivARB && !_wglGetPixelFormatAttribivEXT) { ALLEGRO_ERROR("WGL_ARB/EXT_pf not supported.\n"); return false; } return true; } static _ALLEGRO_wglCreateContextAttribsARB_t _wglCreateContextAttribsARB = NULL; static bool init_context_creation_extensions(void) { _wglCreateContextAttribsARB = (_ALLEGRO_wglCreateContextAttribsARB_t)wglGetProcAddress("wglCreateContextAttribsARB"); if (!_wglCreateContextAttribsARB) { ALLEGRO_ERROR("wglCreateContextAttribs not supported!\n"); return false; } return true; } static int get_pixel_formats_count_old(HDC dc) { PIXELFORMATDESCRIPTOR pfd; int ret; ret = DescribePixelFormat(dc, 1, sizeof(pfd), &pfd); if (!ret) { ALLEGRO_ERROR("DescribePixelFormat failed! %s\n", _al_win_last_error()); } return ret; } static int get_pixel_formats_count_ext(HDC dc) { int attrib[1]; int value[1]; attrib[0] = WGL_NUMBER_PIXEL_FORMATS_ARB; if ((_wglGetPixelFormatAttribivARB(dc, 0, 0, 1, attrib, value) == GL_FALSE) && (_wglGetPixelFormatAttribivEXT(dc, 0, 0, 1, attrib, value) == GL_FALSE)) { ALLEGRO_ERROR("WGL_ARB/EXT_pixel_format use failed! %s\n", _al_win_last_error()); } return value[0]; } static void display_pixel_format(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds) { ALLEGRO_INFO("Accelerated: %s\n", eds->settings[ALLEGRO_RENDER_METHOD] ? "yes" : "no"); ALLEGRO_INFO("Single-buffer: %s\n", eds->settings[ALLEGRO_SINGLE_BUFFER] ? "yes" : "no"); if (eds->settings[ALLEGRO_SWAP_METHOD] > 0) ALLEGRO_INFO("Swap method: %s\n", eds->settings[ALLEGRO_SWAP_METHOD] == 2 ? "flip" : "copy"); else ALLEGRO_INFO("Swap method: undefined\n"); ALLEGRO_INFO("Color format: r%i g%i b%i a%i, %i bit\n", eds->settings[ALLEGRO_RED_SIZE], eds->settings[ALLEGRO_GREEN_SIZE], eds->settings[ALLEGRO_BLUE_SIZE], eds->settings[ALLEGRO_ALPHA_SIZE], eds->settings[ALLEGRO_COLOR_SIZE]); ALLEGRO_INFO("Depth buffer: %i bits\n", eds->settings[ALLEGRO_DEPTH_SIZE]); ALLEGRO_INFO("Sample buffers: %s\n", eds->settings[ALLEGRO_SAMPLE_BUFFERS] ? "yes" : "no"); ALLEGRO_INFO("Samples: %i\n", eds->settings[ALLEGRO_SAMPLES]); } static int decode_pixel_format_old(PIXELFORMATDESCRIPTOR *pfd, ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds) { ALLEGRO_INFO("Decoding:\n"); /* Not interested if it doesn't support OpenGL and RGBA */ if (!(pfd->dwFlags & PFD_SUPPORT_OPENGL)) { ALLEGRO_INFO("OpenGL Unsupported\n"); return false; } if (pfd->iPixelType != PFD_TYPE_RGBA) { ALLEGRO_INFO("Not RGBA mode\n"); return false; } /* hardware acceleration */ if (((pfd->dwFlags & PFD_GENERIC_ACCELERATED) && (pfd->dwFlags & PFD_GENERIC_FORMAT)) || (!(pfd->dwFlags & PFD_GENERIC_ACCELERATED) && !(pfd->dwFlags & PFD_GENERIC_FORMAT))) eds->settings[ALLEGRO_RENDER_METHOD] = 1; else eds->settings[ALLEGRO_RENDER_METHOD] = 0; /* Depths of colour buffers */ eds->settings[ALLEGRO_RED_SIZE] = pfd->cRedBits; eds->settings[ALLEGRO_GREEN_SIZE] = pfd->cGreenBits; eds->settings[ALLEGRO_BLUE_SIZE] = pfd->cBlueBits; eds->settings[ALLEGRO_ALPHA_SIZE] = pfd->cAlphaBits; /* Depths of accumulation buffer */ eds->settings[ALLEGRO_ACC_RED_SIZE] = pfd->cAccumRedBits; eds->settings[ALLEGRO_ACC_GREEN_SIZE] = pfd->cAccumGreenBits; eds->settings[ALLEGRO_ACC_BLUE_SIZE] = pfd->cAccumBlueBits; eds->settings[ALLEGRO_ACC_ALPHA_SIZE] = pfd->cAccumAlphaBits; /* Miscellaneous settings */ eds->settings[ALLEGRO_SINGLE_BUFFER] = !(pfd->dwFlags & PFD_DOUBLEBUFFER); eds->settings[ALLEGRO_DEPTH_SIZE] = pfd->cDepthBits; eds->settings[ALLEGRO_STENCIL_SIZE] = pfd->cStencilBits; eds->settings[ALLEGRO_COLOR_SIZE] = pfd->cColorBits; eds->settings[ALLEGRO_STEREO] = pfd->dwFlags & PFD_STEREO; eds->settings[ALLEGRO_AUX_BUFFERS] = pfd->cAuxBuffers; /* These are the component shifts. */ eds->settings[ALLEGRO_RED_SHIFT] = pfd->cRedShift; eds->settings[ALLEGRO_GREEN_SHIFT] = pfd->cGreenShift; eds->settings[ALLEGRO_BLUE_SHIFT] = pfd->cBlueShift; eds->settings[ALLEGRO_ALPHA_SHIFT] = pfd->cAlphaShift; /* Multisampling isn't supported under Windows if we don't also use * WGL_ARB_pixel_format or WGL_EXT_pixel_format. */ eds->settings[ALLEGRO_SAMPLE_BUFFERS] = 0; eds->settings[ALLEGRO_SAMPLES] = 0; /* Swap method can't be detected without WGL_ARB_pixel_format or * WGL_EXT_pixel_format */ eds->settings[ALLEGRO_SWAP_METHOD] = 0; /* Float depth/color isn't supported under Windows if we don't also use * AGL_ARB_pixel_format or WGL_EXT_pixel_format. */ eds->settings[ALLEGRO_FLOAT_COLOR] = 0; eds->settings[ALLEGRO_FLOAT_DEPTH] = 0; // FIXME eds->settings[ALLEGRO_COMPATIBLE_DISPLAY] = 1; return true; } static bool decode_pixel_format_attrib(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds, int num_attribs, const int *attrib, const int *value) { int i; ALLEGRO_INFO("Decoding:\n"); eds->settings[ALLEGRO_SAMPLES] = 0; eds->settings[ALLEGRO_SAMPLE_BUFFERS] = 0; eds->settings[ALLEGRO_FLOAT_DEPTH] = 0; eds->settings[ALLEGRO_FLOAT_COLOR] = 0; eds->settings[ALLEGRO_COMPATIBLE_DISPLAY] = 1; for (i = 0; i < num_attribs; i++) { /* Not interested if it doesn't support OpenGL or window drawing or RGBA. */ if (attrib[i] == WGL_SUPPORT_OPENGL_ARB && value[i] == 0) { ALLEGRO_INFO("OpenGL Unsupported\n"); return false; } else if (attrib[i] == WGL_DRAW_TO_WINDOW_ARB && value[i] == 0) { ALLEGRO_INFO("Can't draw to window\n"); return false; } else if (attrib[i] == WGL_PIXEL_TYPE_ARB && (value[i] != WGL_TYPE_RGBA_ARB && value[i] != WGL_TYPE_RGBA_FLOAT_ARB)) { ALLEGRO_INFO("Not RGBA mode\n"); return false; } /* hardware acceleration */ else if (attrib[i] == WGL_ACCELERATION_ARB) { eds->settings[ALLEGRO_RENDER_METHOD] = (value[i] == WGL_NO_ACCELERATION_ARB) ? 0 : 1; } /* Depths of colour buffers */ else if (attrib[i] == WGL_RED_BITS_ARB) { eds->settings[ALLEGRO_RED_SIZE] = value[i]; } else if (attrib[i] == WGL_GREEN_BITS_ARB) { eds->settings[ALLEGRO_GREEN_SIZE] = value[i]; } else if (attrib[i] == WGL_BLUE_BITS_ARB) { eds->settings[ALLEGRO_BLUE_SIZE] = value[i]; } else if (attrib[i] == WGL_ALPHA_BITS_ARB) { eds->settings[ALLEGRO_ALPHA_SIZE] = value[i]; } /* Shift of color components */ else if (attrib[i] == WGL_RED_SHIFT_ARB) { eds->settings[ALLEGRO_RED_SHIFT] = value[i]; } else if (attrib[i] == WGL_GREEN_SHIFT_ARB) { eds->settings[ALLEGRO_GREEN_SHIFT] = value[i]; } else if (attrib[i] == WGL_BLUE_SHIFT_ARB) { eds->settings[ALLEGRO_BLUE_SHIFT] = value[i]; } else if (attrib[i] == WGL_ALPHA_SHIFT_ARB) { eds->settings[ALLEGRO_ALPHA_SHIFT] = value[i]; } /* Miscellaneous settings */ else if (attrib[i] == WGL_DOUBLE_BUFFER_ARB) { eds->settings[ALLEGRO_SINGLE_BUFFER] = !(value[i]); } else if (attrib[i] == WGL_SWAP_METHOD_ARB) { if (value[i] == WGL_SWAP_UNDEFINED_ARB) eds->settings[ALLEGRO_SWAP_METHOD] = 0; else if (value[i] == WGL_SWAP_COPY_ARB) eds->settings[ALLEGRO_SWAP_METHOD] = 1; else if (value[i] == WGL_SWAP_EXCHANGE_ARB) eds->settings[ALLEGRO_SWAP_METHOD] = 2; } else if (attrib[i] == WGL_STEREO_ARB) { eds->settings[ALLEGRO_STEREO] = value[i]; } else if (attrib[i] == WGL_AUX_BUFFERS_ARB) { eds->settings[ALLEGRO_AUX_BUFFERS] = value[i]; } else if (attrib[i] == WGL_STENCIL_BITS_ARB) { eds->settings[ALLEGRO_STENCIL_SIZE] = value[i]; } /* Depths of accumulation buffer */ else if (attrib[i] == WGL_ACCUM_RED_BITS_ARB) { eds->settings[ALLEGRO_ACC_RED_SIZE] = value[i]; } else if (attrib[i] == WGL_ACCUM_GREEN_BITS_ARB) { eds->settings[ALLEGRO_ACC_GREEN_SIZE] = value[i]; } else if (attrib[i] == WGL_ACCUM_BLUE_BITS_ARB) { eds->settings[ALLEGRO_ACC_BLUE_SIZE] = value[i]; } else if (attrib[i] == WGL_ACCUM_ALPHA_BITS_ARB) { eds->settings[ALLEGRO_ACC_ALPHA_SIZE] = value[i]; } else if (attrib[i] == WGL_DEPTH_BITS_ARB) { eds->settings[ALLEGRO_DEPTH_SIZE] = value[i]; } else if (attrib[i] == WGL_COLOR_BITS_ARB) { eds->settings[ALLEGRO_COLOR_SIZE] = value[i]; } /* Multisampling bits */ else if (attrib[i] == WGL_SAMPLE_BUFFERS_ARB) { eds->settings[ALLEGRO_SAMPLE_BUFFERS] = value[i]; } else if (attrib[i] == WGL_SAMPLES_ARB) { eds->settings[ALLEGRO_SAMPLES] = value[i]; } /* Float color */ if (attrib[i] == WGL_PIXEL_TYPE_ARB && value[i] == WGL_TYPE_RGBA_FLOAT_ARB) { eds->settings[ALLEGRO_FLOAT_COLOR] = true; } /* Float depth */ else if (attrib[i] == WGL_DEPTH_FLOAT_EXT) { eds->settings[ALLEGRO_FLOAT_DEPTH] = value[i]; } } return true; } static ALLEGRO_EXTRA_DISPLAY_SETTINGS* read_pixel_format_old(int fmt, HDC dc) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = NULL; PIXELFORMATDESCRIPTOR pfd; int result; result = DescribePixelFormat(dc, fmt+1, sizeof(pfd), &pfd); if (!result) { ALLEGRO_WARN("DescribePixelFormat() failed. %s\n", _al_win_last_error()); return NULL; } eds = al_calloc(1, sizeof *eds); if (!decode_pixel_format_old(&pfd, eds)) { al_free(eds); return NULL; } return eds; } static ALLEGRO_EXTRA_DISPLAY_SETTINGS* read_pixel_format_ext(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB, int fmt, HDC dc) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = NULL; /* Note: Even though we use te ARB suffix, all those enums are compatible * with EXT_pixel_format. */ int attrib[] = { WGL_SUPPORT_OPENGL_ARB, WGL_DRAW_TO_WINDOW_ARB, WGL_PIXEL_TYPE_ARB, WGL_ACCELERATION_ARB, WGL_DOUBLE_BUFFER_ARB, WGL_DEPTH_BITS_ARB, WGL_SWAP_METHOD_ARB, WGL_COLOR_BITS_ARB, WGL_RED_BITS_ARB, WGL_GREEN_BITS_ARB, WGL_BLUE_BITS_ARB, WGL_ALPHA_BITS_ARB, WGL_RED_SHIFT_ARB, WGL_GREEN_SHIFT_ARB, WGL_BLUE_SHIFT_ARB, WGL_ALPHA_SHIFT_ARB, WGL_STENCIL_BITS_ARB, WGL_STEREO_ARB, WGL_ACCUM_BITS_ARB, WGL_ACCUM_RED_BITS_ARB, WGL_ACCUM_GREEN_BITS_ARB, WGL_ACCUM_BLUE_BITS_ARB, WGL_ACCUM_ALPHA_BITS_ARB, WGL_AUX_BUFFERS_ARB, /* The following are used by extensions that add to WGL_pixel_format. * If WGL_p_f isn't supported though, we can't use the (then invalid) * enums. We can't use any magic number either, so we settle for * replicating one. The pixel format decoder * (decode_pixel_format_attrib()) doesn't care about duplicates. */ WGL_AUX_BUFFERS_ARB, /* placeholder for WGL_SAMPLE_BUFFERS_ARB */ WGL_AUX_BUFFERS_ARB, /* placeholder for WGL_SAMPLES_ARB */ WGL_AUX_BUFFERS_ARB, /* placeholder for WGL_DEPTH_FLOAT_EXT */ }; const int num_attribs = sizeof(attrib) / sizeof(attrib[0]); int *value = (int*)al_malloc(sizeof(int) * num_attribs); int ret; if (!value) return NULL; /* If multisampling is supported, query for it. */ if (is_wgl_extension_supported(_wglGetExtensionsStringARB, "WGL_ARB_multisample", dc)) { attrib[num_attribs - 3] = WGL_SAMPLE_BUFFERS_ARB; attrib[num_attribs - 2] = WGL_SAMPLES_ARB; } if (is_wgl_extension_supported(_wglGetExtensionsStringARB, "WGL_EXT_depth_float", dc)) { attrib[num_attribs - 1] = WGL_DEPTH_FLOAT_EXT; } /* Get the pf attributes */ if (_wglGetPixelFormatAttribivARB) { ret = _wglGetPixelFormatAttribivARB(dc, fmt+1, 0, num_attribs, attrib, value); } else if (_wglGetPixelFormatAttribivEXT) { ret = _wglGetPixelFormatAttribivEXT(dc, fmt+1, 0, num_attribs, attrib, value); } else { ret = 0; } if (!ret) { ALLEGRO_ERROR("wglGetPixelFormatAttrib failed! %s\n", _al_win_last_error()); al_free(value); return NULL; } eds = al_calloc(1, sizeof *eds); if (!decode_pixel_format_attrib(eds, num_attribs, attrib, value)) { al_free(eds); eds = NULL; } al_free(value); /* Hack: for some reason this happens for me under Wine. */ if (eds && eds->settings[ALLEGRO_RED_SHIFT] == 0 && eds->settings[ALLEGRO_GREEN_SHIFT] == 0 && eds->settings[ALLEGRO_BLUE_SHIFT] == 0 && eds->settings[ALLEGRO_ALPHA_SHIFT] == 0) { eds->settings[ALLEGRO_RED_SHIFT] = 0; eds->settings[ALLEGRO_GREEN_SHIFT] = 8; eds->settings[ALLEGRO_BLUE_SHIFT] = 16; eds->settings[ALLEGRO_ALPHA_SHIFT] = 24; } return eds; } static bool change_display_mode(ALLEGRO_DISPLAY *d) { DEVMODE dm; DEVMODE fallback_dm; DISPLAY_DEVICE dd; TCHAR* dev_name = NULL; int i, modeswitch, result; int fallback_dm_valid = 0; int bpp; int adapter = al_get_new_display_adapter(); if (adapter >= 0) { memset(&dd, 0, sizeof(dd)); dd.cb = sizeof(dd); if (EnumDisplayDevices(NULL, adapter, &dd, 0) == false) return false; dev_name = dd.DeviceName; } memset(&fallback_dm, 0, sizeof(fallback_dm)); memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(DEVMODE); bpp = d->extra_settings.settings[ALLEGRO_COLOR_SIZE]; if (!bpp) bpp = 32; i = 0; do { modeswitch = EnumDisplaySettings(dev_name, i, &dm); if (!modeswitch) break; if ((dm.dmPelsWidth == (unsigned) d->w) && (dm.dmPelsHeight == (unsigned) d->h) && (dm.dmBitsPerPel == (unsigned) bpp) && (dm.dmDisplayFrequency != (unsigned) d->refresh_rate)) { /* Keep it as fallback if refresh rate request could not * be satisfied. Try to get as close to 60Hz as possible though, * it's a bit better for a fallback than just blindly picking * something like 47Hz or 200Hz. */ if (!fallback_dm_valid) { fallback_dm = dm; fallback_dm_valid = 1; } else if (dm.dmDisplayFrequency >= 60) { if (dm.dmDisplayFrequency < fallback_dm.dmDisplayFrequency) { fallback_dm = dm; } } } i++; } while ((dm.dmPelsWidth != (unsigned) d->w) || (dm.dmPelsHeight != (unsigned) d->h) || (dm.dmBitsPerPel != (unsigned) bpp) || (dm.dmDisplayFrequency != (unsigned) d->refresh_rate)); if (!modeswitch && !fallback_dm_valid) { ALLEGRO_ERROR("Mode not found.\n"); return false; } if (!modeswitch && fallback_dm_valid) dm = fallback_dm; dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; result = ChangeDisplaySettingsEx(dev_name, &dm, NULL, CDS_FULLSCREEN, 0); d->refresh_rate = dm.dmDisplayFrequency; if (result != DISP_CHANGE_SUCCESSFUL) { ALLEGRO_ERROR("Unable to set mode. %s\n", _al_win_last_error()); return false; } ALLEGRO_INFO("Mode seccessfuly set.\n"); return true; } static HGLRC init_ogl_context_ex(HDC dc, bool fc, int major, int minor) { HWND testwnd = NULL; HDC testdc = NULL; HGLRC testrc = NULL; HGLRC old_rc = NULL; HDC old_dc = NULL; HGLRC glrc = NULL; testwnd = _al_win_create_hidden_window(); if (!testwnd) return NULL; old_rc = wglGetCurrentContext(); old_dc = wglGetCurrentDC(); testdc = GetDC(testwnd); testrc = init_temp_context(testwnd); if (!testrc) goto bail; _ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB = (_ALLEGRO_wglGetExtensionsStringARB_t)wglGetProcAddress("wglGetExtensionsStringARB"); ALLEGRO_INFO("_wglGetExtensionsStringARB %p\n", _wglGetExtensionsStringARB); if (is_wgl_extension_supported(_wglGetExtensionsStringARB, "WGL_ARB_create_context", testdc)) { int attrib[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, major, WGL_CONTEXT_MINOR_VERSION_ARB, minor, WGL_CONTEXT_FLAGS_ARB, 0, 0}; if (fc) attrib[5] = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; if (!init_context_creation_extensions()) goto bail; /* TODO: we could use the context sharing feature */ glrc = _wglCreateContextAttribsARB(dc, 0, attrib); } else goto bail; bail: wglMakeCurrent(NULL, NULL); if (testrc) { wglDeleteContext(testrc); } wglMakeCurrent(old_dc, old_rc); _wglCreateContextAttribsARB = NULL; if (testwnd) { ReleaseDC(testwnd, testdc); DestroyWindow(testwnd); } return glrc; } static ALLEGRO_EXTRA_DISPLAY_SETTINGS** get_available_pixel_formats_ext(int *count) { HWND testwnd = NULL; HDC testdc = NULL; HGLRC testrc = NULL; HGLRC old_rc = NULL; HDC old_dc = NULL; ALLEGRO_EXTRA_DISPLAY_SETTINGS **eds_list = NULL; ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref; int maxindex; int i, j; *count = 0; ref = _al_get_new_display_settings(); /* We need to create a dummy window with a pixel format to get the * list of valid PFDs */ testwnd = _al_win_create_hidden_window(); if (!testwnd) return false; old_rc = wglGetCurrentContext(); old_dc = wglGetCurrentDC(); testdc = GetDC(testwnd); testrc = init_temp_context(testwnd); if (!testrc) goto bail; _ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB = (_ALLEGRO_wglGetExtensionsStringARB_t)wglGetProcAddress("wglGetExtensionsStringARB"); ALLEGRO_INFO("_wglGetExtensionsStringARB %p\n", _wglGetExtensionsStringARB); if (!is_wgl_extension_supported(_wglGetExtensionsStringARB, "WGL_ARB_pixel_format", testdc) && !is_wgl_extension_supported(_wglGetExtensionsStringARB, "WGL_EXT_pixel_format", testdc)) { ALLEGRO_ERROR("WGL_ARB/EXT_pf not supported.\n"); goto bail; } if (!init_pixel_format_extensions()) goto bail; maxindex = get_pixel_formats_count_ext(testdc); if (maxindex < 1) goto bail; ALLEGRO_INFO("Got %i visuals.\n", maxindex); eds_list = al_calloc(maxindex, sizeof(*eds_list)); if (!eds_list) goto bail; for (j = i = 0; i < maxindex; i++) { ALLEGRO_INFO("-- \n"); ALLEGRO_INFO("Decoding visual no. %i...\n", i+1); eds_list[j] = read_pixel_format_ext(_wglGetExtensionsStringARB, i, testdc); if (!eds_list[j]) continue; // Fill vsync setting here and enable/disable it after display creation eds_list[j]->settings[ALLEGRO_VSYNC] = ref->settings[ALLEGRO_VSYNC]; display_pixel_format(eds_list[j]); eds_list[j]->score = _al_score_display_settings(eds_list[j], ref); if (eds_list[j]->score == -1) { al_free(eds_list[j]); eds_list[j] = NULL; continue; } /* In WinAPI first index is 1 ::) */ eds_list[j]->index = i+1; j++; } ALLEGRO_INFO("%i visuals are good enough.\n", j); *count = j; bail: wglMakeCurrent(NULL, NULL); if (testrc) { wglDeleteContext(testrc); } wglMakeCurrent(old_dc, old_rc); _wglGetPixelFormatAttribivARB = NULL; _wglGetPixelFormatAttribivEXT = NULL; if (testwnd) { ReleaseDC(testwnd, testdc); DestroyWindow(testwnd); } return eds_list; } static ALLEGRO_EXTRA_DISPLAY_SETTINGS** get_available_pixel_formats_old(int *count, HDC dc) { ALLEGRO_EXTRA_DISPLAY_SETTINGS **eds_list = NULL; ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref; int maxindex; int i, j; *count = 0; ref = _al_get_new_display_settings(); maxindex = get_pixel_formats_count_old(dc); if (maxindex < 1) return NULL; ALLEGRO_INFO("Got %i visuals.\n", maxindex); eds_list = al_calloc(maxindex, sizeof(*eds_list)); if (!eds_list) return NULL; for (j = i = 0; i < maxindex; i++) { ALLEGRO_INFO("-- \n"); ALLEGRO_INFO("Decoding visual no. %i...\n", i+1); eds_list[j] = read_pixel_format_old(i, dc); if (!eds_list[j]) continue; #ifdef DEBUGMODE display_pixel_format(eds_list[j]); #endif eds_list[j]->score = _al_score_display_settings(eds_list[j], ref); if (eds_list[j]->score == -1) { al_free(eds_list[j]); eds_list[j] = NULL; continue; } /* In WinAPI first index is 1 ::) */ eds_list[j]->index = i+1; j++; } ALLEGRO_INFO("%i visuals are good enough.\n", j); *count = j; return eds_list; } static bool select_pixel_format(ALLEGRO_DISPLAY_WGL *d, HDC dc) { ALLEGRO_EXTRA_DISPLAY_SETTINGS **eds = NULL; ALLEGRO_CONFIG *sys_cfg = al_get_system_config(); int eds_count = 0; int i; bool force_old = false; const char *selection_mode; selection_mode = al_get_config_value(sys_cfg, "graphics", "config_selection"); if (selection_mode && selection_mode[0] != '\0') { if (!_al_stricmp(selection_mode, "old")) { ALLEGRO_INFO("Forcing OLD visual selection method.\n"); force_old = true; } else if (!_al_stricmp(selection_mode, "new")) force_old = false; } if (!force_old) eds = get_available_pixel_formats_ext(&eds_count); if (!eds) eds = get_available_pixel_formats_old(&eds_count, dc); if (!eds || !eds_count) { ALLEGRO_ERROR("Didn't find any suitable pixel format!\n"); return false; } qsort(eds, eds_count, sizeof(eds[0]), _al_display_settings_sorter); for (i = 0; i < eds_count ; i++) { if (SetPixelFormat(d->dc, eds[i]->index, NULL)) { ALLEGRO_INFO("Chose visual no. %i\n\n", eds[i]->index); display_pixel_format(eds[i]); break; } else { ALLEGRO_WARN("Unable to set pixel format! %s\n", _al_win_last_error()); ALLEGRO_WARN("Trying next one.\n"); } } if (i == eds_count) { ALLEGRO_ERROR("Unable to set any pixel format! %s\n", _al_win_last_error()); for (i = 0; i < eds_count; i++) al_free(eds[i]); al_free(eds); return false; } memcpy(&d->win_display.display.extra_settings, eds[i], sizeof(ALLEGRO_EXTRA_DISPLAY_SETTINGS)); for (i = 0; i < eds_count; i++) al_free(eds[i]); if (eds) al_free(eds); return true; } static bool create_display_internals(ALLEGRO_DISPLAY_WGL *wgl_disp) { ALLEGRO_DISPLAY *disp = (void*)wgl_disp; ALLEGRO_DISPLAY_WIN *win_disp = (void*)wgl_disp; WGL_DISPLAY_PARAMETERS ndp; int window_x, window_y; int major, minor; /* The window is created in a separate thread so we need to pass this * TLS on */ al_get_new_window_position(&window_x, &window_y); ndp.window_x = window_x; ndp.window_y = window_y; ndp.window_title = al_get_new_window_title(); /* _beginthread closes the handle automatically. */ ndp.display = wgl_disp; ndp.init_failed = true; ndp.AckEvent = CreateEvent(NULL, false, false, NULL); _beginthread(display_thread_proc, 0, &ndp); /* Wait some _finite_ time (10 secs or so) for display thread to init, and * give up if something horrible happened to it, unless we're in debug mode * and we may have intentionally stopped the execution to analyze the code. */ #ifdef DEBUGMODE WaitForSingleObject(ndp.AckEvent, INFINITE); #else WaitForSingleObject(ndp.AckEvent, 10*1000); #endif CloseHandle(ndp.AckEvent); if (ndp.init_failed) { ALLEGRO_ERROR("Failed to create display.\n"); return false; } /* WGL display lists cannot be shared with the API currently in use. */ disp->ogl_extras->is_shared = false; if (!select_pixel_format(wgl_disp, wgl_disp->dc)) { destroy_display_internals(wgl_disp); return false; } major = al_get_new_display_option(ALLEGRO_OPENGL_MAJOR_VERSION, 0); minor = al_get_new_display_option(ALLEGRO_OPENGL_MINOR_VERSION, 0); // TODO: request GLES context in GLES builds if ((disp->flags & ALLEGRO_OPENGL_3_0) || major != 0) { if (major == 0) major = 3; bool fc = (disp->flags & ALLEGRO_OPENGL_FORWARD_COMPATIBLE) != 0; wgl_disp->glrc = init_ogl_context_ex(wgl_disp->dc, fc, major, minor); } else { wgl_disp->glrc = wglCreateContext(wgl_disp->dc); } if (!wgl_disp->glrc) { ALLEGRO_ERROR("Unable to create a render context! %s\n", _al_win_last_error()); destroy_display_internals(wgl_disp); return false; } /* make the context the current one */ if (!wglMakeCurrent(wgl_disp->dc, wgl_disp->glrc)) { ALLEGRO_ERROR("Unable to make the context current! %s\n", _al_win_last_error()); destroy_display_internals(wgl_disp); return false; } _al_ogl_manage_extensions(disp); _al_ogl_set_extensions(disp->ogl_extras->extension_api); if (disp->ogl_extras->ogl_info.version < _ALLEGRO_OPENGL_VERSION_1_2) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = _al_get_new_display_settings(); if (eds->required & (1<extra_settings.settings[ALLEGRO_COMPATIBLE_DISPLAY] = 0; } /* Fill in the display settings for opengl major and minor versions...*/ const int v = disp->ogl_extras->ogl_info.version; disp->extra_settings.settings[ALLEGRO_OPENGL_MAJOR_VERSION] = (v >> 24) & 0xFF; disp->extra_settings.settings[ALLEGRO_OPENGL_MINOR_VERSION] = (v >> 16) & 0xFF; /* Try to enable or disable vsync as requested */ /* NOTE: my drivers claim I don't have WGL_EXT_swap_control * (according to al_have_opengl_extension), but wglSwapIntervalEXT * does get loaded, so just check for that. */ if (wglSwapIntervalEXT) { if (disp->extra_settings.settings[ALLEGRO_VSYNC] == 1) { wglSwapIntervalEXT(1); } else if (disp->extra_settings.settings[ALLEGRO_VSYNC] == 2) { wglSwapIntervalEXT(0); } } win_disp->mouse_selected_hcursor = 0; win_disp->mouse_cursor_shown = false; win_disp->hide_mouse_on_move = false; _al_win_grab_input(win_disp); if (disp->extra_settings.settings[ALLEGRO_COMPATIBLE_DISPLAY]) _al_ogl_setup_gl(disp); return true; } static ALLEGRO_DISPLAY* wgl_create_display(int w, int h) { ALLEGRO_SYSTEM_WIN *system = (ALLEGRO_SYSTEM_WIN *)al_get_system_driver(); ALLEGRO_DISPLAY_WGL **add; ALLEGRO_DISPLAY_WGL *wgl_display = al_calloc(1, sizeof *wgl_display); ALLEGRO_DISPLAY *ogl_display = (void*)wgl_display; ALLEGRO_DISPLAY *display = (void*)ogl_display; ALLEGRO_DISPLAY_WIN *win_disp = (ALLEGRO_DISPLAY_WIN *)display; win_disp->adapter = _al_win_determine_adapter(); display->w = w; display->h = h; display->refresh_rate = al_get_new_display_refresh_rate(); display->flags = al_get_new_display_flags(); #ifdef ALLEGRO_CFG_OPENGLES2 display->flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; #endif #ifdef ALLEGRO_CFG_OPENGLES display->flags |= ALLEGRO_OPENGL_ES_PROFILE; #endif display->vt = &vt; display->ogl_extras = al_calloc(1, sizeof(ALLEGRO_OGL_EXTRAS)); if (!create_display_internals(wgl_display)) { al_free(display->ogl_extras); al_free(display); return NULL; } /* Print out OpenGL version info */ ALLEGRO_INFO("OpenGL Version: %s\n", (const char*)glGetString(GL_VERSION)); ALLEGRO_INFO("Vendor: %s\n", (const char*)glGetString(GL_VENDOR)); ALLEGRO_INFO("Renderer: %s\n\n", (const char*)glGetString(GL_RENDERER)); /* Add ourself to the list of displays. */ add = _al_vector_alloc_back(&system->system.displays); *add = wgl_display; /* Each display is an event source. */ _al_event_source_init(&display->es); _al_win_set_system_mouse_cursor(display, ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW); _al_win_show_mouse_cursor(display); _al_win_post_create_window(display); return display; } static void destroy_display_internals(ALLEGRO_DISPLAY_WGL *wgl_disp) { ALLEGRO_DISPLAY *disp = (ALLEGRO_DISPLAY *)wgl_disp; ALLEGRO_DISPLAY_WIN *win_disp = (ALLEGRO_DISPLAY_WIN *)wgl_disp; /* We need to convert all our bitmaps to display independent (memory) * bitmaps because WGL driver doesn't support sharing of resources. */ while (disp->bitmaps._size > 0) { ALLEGRO_BITMAP **bptr = _al_vector_ref_back(&disp->bitmaps); ALLEGRO_BITMAP *bmp = *bptr; _al_convert_to_memory_bitmap(bmp); } if (disp->ogl_extras->backbuffer) _al_ogl_destroy_backbuffer(disp->ogl_extras->backbuffer); disp->ogl_extras->backbuffer = NULL; _al_ogl_unmanage_extensions(disp); PostMessage(win_disp->window, _al_win_msg_suicide, (WPARAM)win_disp, 0); while (!win_disp->thread_ended) al_rest(0.001); if (wgl_disp->glrc) { wglDeleteContext(wgl_disp->glrc); wgl_disp->glrc = NULL; } if (wgl_disp->dc) { ReleaseDC(win_disp->window, wgl_disp->dc); wgl_disp->dc = NULL; } if (disp->flags & ALLEGRO_FULLSCREEN && !_wgl_do_not_change_display_mode) { ChangeDisplaySettings(NULL, 0); } if (win_disp->window) { DestroyWindow(win_disp->window); win_disp->window = NULL; } } static void wgl_destroy_display(ALLEGRO_DISPLAY *disp) { ALLEGRO_SYSTEM_WIN *system = (ALLEGRO_SYSTEM_WIN *)al_get_system_driver(); ALLEGRO_DISPLAY_WGL *wgl_disp = (ALLEGRO_DISPLAY_WGL *)disp; ALLEGRO_DISPLAY *old_disp = al_get_current_display(); if (old_disp != disp) _al_set_current_display_only(disp); if (system->mouse_grab_display == disp) system->mouse_grab_display = NULL; _al_win_destroy_display_icons(disp); destroy_display_internals(wgl_disp); _al_event_source_free(&disp->es); _al_vector_find_and_delete(&system->system.displays, &disp); _al_vector_free(&disp->bitmaps); _al_vector_free(&((ALLEGRO_DISPLAY_WIN*) disp)->msg_callbacks); al_free(disp->ogl_extras); if (old_disp != disp) _al_set_current_display_only(old_disp); al_free(disp->vertex_cache); al_free(wgl_disp); } static bool wgl_set_current_display(ALLEGRO_DISPLAY *d) { ALLEGRO_DISPLAY_WGL *wgl_disp = (ALLEGRO_DISPLAY_WGL *)d; HGLRC current_glrc; current_glrc = wglGetCurrentContext(); if (!current_glrc || (current_glrc && current_glrc != wgl_disp->glrc)) { /* make the context the current one */ if (!wglMakeCurrent(wgl_disp->dc, wgl_disp->glrc)) { ALLEGRO_ERROR("Unable to make the context current! %s\n", _al_win_last_error()); return false; } _al_ogl_set_extensions(d->ogl_extras->extension_api); } _al_ogl_update_render_state(d); return true; } static void wgl_unset_current_display(ALLEGRO_DISPLAY *d) { (void)d; if (!wglMakeCurrent(NULL, NULL)) { ALLEGRO_ERROR("Unable unset the current context! %s\n", _al_win_last_error()); } } /* * The window must be created in the same thread that * runs the message loop. */ static void display_thread_proc(void *arg) { WGL_DISPLAY_PARAMETERS *ndp = arg; ALLEGRO_DISPLAY *disp = (ALLEGRO_DISPLAY*)ndp->display; ALLEGRO_DISPLAY_WGL *wgl_disp = (void*)disp; ALLEGRO_DISPLAY_WIN *win_disp = (void*)disp; MSG msg; /* So that we can call the functions using TLS from this thread. */ al_set_new_display_flags(disp->flags); al_set_new_window_position(ndp->window_x, ndp->window_y); al_set_new_window_title(ndp->window_title); if (disp->flags & ALLEGRO_FULLSCREEN) { if (!change_display_mode(disp)) { win_disp->thread_ended = true; destroy_display_internals(wgl_disp); SetEvent(ndp->AckEvent); return; } } else if (disp->flags & ALLEGRO_FULLSCREEN_WINDOW) { ALLEGRO_MONITOR_INFO mi; int adapter = win_disp->adapter; al_get_monitor_info(adapter, &mi); win_disp->toggle_w = disp->w; win_disp->toggle_h = disp->h; disp->w = mi.x2 - mi.x1; disp->h = mi.y2 - mi.y1; disp->refresh_rate = al_get_monitor_refresh_rate(adapter); } else { int adapter = win_disp->adapter; win_disp->toggle_w = disp->w; win_disp->toggle_h = disp->h; disp->refresh_rate = al_get_monitor_refresh_rate(adapter); } win_disp->window = _al_win_create_window(disp, disp->w, disp->h, disp->flags); if (!win_disp->window) { win_disp->thread_ended = true; destroy_display_internals(wgl_disp); SetEvent(ndp->AckEvent); return; } /* FIXME: can't _al_win_create_window() do this? */ if ((disp->flags & ALLEGRO_FULLSCREEN) || (disp->flags & ALLEGRO_FULLSCREEN_WINDOW)) { RECT rect; rect.left = 0; rect.right = disp->w; rect.top = 0; rect.bottom = disp->h; SetWindowPos(win_disp->window, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED); } if (disp->flags & ALLEGRO_FULLSCREEN_WINDOW) { _al_win_set_window_frameless(disp, win_disp->window, true); } { DWORD lock_time; HWND wnd = win_disp->window; if ((disp->flags & ALLEGRO_FULLSCREEN) == 0) { ShowWindow(wnd, SW_SHOWNORMAL); SetForegroundWindow(wnd); UpdateWindow(wnd); } else { /* Yep, the following is really needed sometimes. */ /* ... Or is it now that we have dumped DInput? */ /* Win98/2k/XP's window foreground rules don't let us * make our window the topmost window on launch. This causes issues on * full-screen apps, as DInput loses input focus on them. * We use this trick to force the window to be topmost, when switching * to full-screen only. Note that this only works for Win98 and greater. * Win95 will ignore our SystemParametersInfo() calls. * * See http://support.microsoft.com:80/support/kb/articles/Q97/9/25.asp * for details. */ #define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000 #define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001 SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)&lock_time, 0); SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE); ShowWindow(wnd, SW_SHOWNORMAL); SetForegroundWindow(wnd); /* In some rare cases, it doesn't seem to work without the loop. And we * absolutely need this to succeed, else we trap the user in a * fullscreen window without input. */ while (GetForegroundWindow() != wnd) { al_rest(0.1); SetForegroundWindow(wnd); } UpdateWindow(wnd); SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)&lock_time, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE); #undef SPI_GETFOREGROUNDLOCKTIMEOUT #undef SPI_SETFOREGROUNDLOCKTIMEOUT } } #if 0 if (disp->flags & ALLEGRO_FULLSCREEN && al_is_mouse_installed()) { RAWINPUTDEVICE rid[1]; rid[0].usUsagePage = 0x01; rid[0].usUsage = 0x02; rid[0].dwFlags = RIDEV_NOLEGACY; rid[0].hwndTarget = 0; if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == FALSE) { ALLEGRO_ERROR( "Failed to init mouse. %s\n", get_error_desc(GetLastError())); } } #endif /* get the device context of our window */ wgl_disp->dc = GetDC(win_disp->window); win_disp->thread_ended = false; win_disp->end_thread = false; ndp->init_failed = false; SetEvent(ndp->AckEvent); while (!win_disp->end_thread) { /* get a message from the queue */ if (GetMessage(&msg, NULL, 0, 0) != 0) DispatchMessage(&msg); else break; /* WM_QUIT received or error (GetMessage returned -1) */ } ALLEGRO_INFO("wgl display thread exits\n"); win_disp->thread_ended = true; } static void wgl_flip_display(ALLEGRO_DISPLAY *d) { ALLEGRO_DISPLAY_WGL* disp = (ALLEGRO_DISPLAY_WGL*)d; glFlush(); if (!d->extra_settings.settings[ALLEGRO_SINGLE_BUFFER]) SwapBuffers(disp->dc); } static void wgl_update_display_region(ALLEGRO_DISPLAY *d, int x, int y, int width, int height) { if (al_get_opengl_extension_list()->ALLEGRO_WGL_WIN_swap_hint) { /* FIXME: This is just a driver hint and there is no guarantee that the * contens of the front buffer outside the given rectangle will be preserved, * thus we should really return false here and do nothing. */ ALLEGRO_DISPLAY_WGL* disp = (ALLEGRO_DISPLAY_WGL*)d; wglAddSwapHintRectWIN(x, y, width, height); glFlush(); SwapBuffers(disp->dc); return; } wgl_flip_display(d); } static bool wgl_resize_helper(ALLEGRO_DISPLAY *d, int width, int height) { ALLEGRO_DISPLAY_WGL *wgl_disp = (ALLEGRO_DISPLAY_WGL *)d; ALLEGRO_DISPLAY_WIN *win_disp = (ALLEGRO_DISPLAY_WIN *)d; int full_w, full_h; ALLEGRO_MONITOR_INFO mi; int adapter = win_disp->adapter; al_get_monitor_info(adapter, &mi); full_w = mi.x2 - mi.x1; full_h = mi.y2 - mi.y1; if ((d->flags & ALLEGRO_FULLSCREEN_WINDOW) && (full_w != width || full_h != height)) { win_disp->toggle_w = width; win_disp->toggle_h = height; return true; } if (d->flags & ALLEGRO_FULLSCREEN) { ALLEGRO_BITMAP *target_bmp; _AL_VECTOR disp_bmps; bool was_backbuffer = false; size_t i; target_bmp = al_get_target_bitmap(); if (target_bmp && target_bmp->vt) { ALLEGRO_BITMAP_EXTRA_OPENGL *extra = target_bmp->parent ? target_bmp->parent->extra : target_bmp->extra; was_backbuffer = extra->is_backbuffer; } /* Remember display bitmaps. */ _al_vector_init(&disp_bmps, sizeof(ALLEGRO_BITMAP*)); for (i = 0; i < _al_vector_size(&d->bitmaps); i++) { ALLEGRO_BITMAP **dis = _al_vector_ref(&d->bitmaps, i); ALLEGRO_BITMAP **mem = _al_vector_alloc_back(&disp_bmps); *mem = *dis; } /* This flag prevents from switching to desktop resolution in between. */ _wgl_do_not_change_display_mode = true; destroy_display_internals(wgl_disp); _wgl_do_not_change_display_mode = false; d->w = width; d->h = height; if(!create_display_internals(wgl_disp)) return false; /* We have a new backbuffer now. */ if (was_backbuffer) al_set_target_bitmap(al_get_backbuffer(d)); /* Reupload bitmaps. */ while (_al_vector_is_nonempty(&disp_bmps)) { ALLEGRO_BITMAP **back = _al_vector_ref_back(&disp_bmps); _al_convert_to_display_bitmap(*back); _al_vector_delete_at(&disp_bmps, _al_vector_size(&disp_bmps) - 1); } } else { RECT win_size; WINDOWINFO wi; win_size.left = 0; win_size.top = 0; win_size.right = width; win_size.bottom = height; wi.cbSize = sizeof(WINDOWINFO); GetWindowInfo(win_disp->window, &wi); AdjustWindowRectEx(&win_size, wi.dwStyle, GetMenu(win_disp->window) ? TRUE : FALSE, wi.dwExStyle); if (!SetWindowPos(win_disp->window, HWND_TOP, 0, 0, win_size.right - win_size.left, win_size.bottom - win_size.top, SWP_NOMOVE|SWP_NOZORDER)) return false; d->w = width; d->h = height; if (!(d->flags & ALLEGRO_FULLSCREEN_WINDOW)) { win_disp->toggle_w = width; win_disp->toggle_h = height; } } return true; } static bool wgl_resize_display(ALLEGRO_DISPLAY *d, int width, int height) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)d; int orig_w = d->w; int orig_h = d->h; bool ret; win_display->ignore_resize = true; if (!wgl_resize_helper(d, width, height)) { wgl_resize_helper(d, orig_w, orig_h); ret = false; } else { ret = true; wgl_acknowledge_resize(d); } win_display->ignore_resize = false; return ret; } static bool wgl_acknowledge_resize(ALLEGRO_DISPLAY *d) { WINDOWINFO wi; ALLEGRO_DISPLAY_WIN *win_disp = (ALLEGRO_DISPLAY_WIN *)d; int w, h; ALLEGRO_STATE state; wi.cbSize = sizeof(WINDOWINFO); GetWindowInfo(win_disp->window, &wi); w = wi.rcClient.right - wi.rcClient.left; h = wi.rcClient.bottom - wi.rcClient.top; d->w = w; d->h = h; _al_ogl_setup_gl(d); _al_ogl_update_render_state(d); al_store_state(&state, ALLEGRO_STATE_DISPLAY | ALLEGRO_STATE_TARGET_BITMAP); al_set_target_backbuffer(d); al_set_clipping_rectangle(0, 0, w, h); al_restore_state(&state); return true; } static bool wgl_is_compatible_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { /* Note: WGL driver doesn't support sharing of resources between contexts, * thus all bitmaps are tied to the display which was current at the time * al_create_bitmap was called. */ return display == _al_get_bitmap_display(bitmap); } static void wgl_switch_in(ALLEGRO_DISPLAY *display) { (void)display; /* ALLEGRO_DISPLAY_WIN *win_disp = (ALLEGRO_DISPLAY_WIN *)display; if (al_is_mouse_installed()) al_set_mouse_range(win_disp->mouse_range_x1, win_disp->mouse_range_y1, win_disp->mouse_range_x2, win_disp->mouse_range_y2); */ } static void wgl_switch_out(ALLEGRO_DISPLAY *display) { (void)display; } static void wgl_set_window_position(ALLEGRO_DISPLAY *display, int x, int y) { _al_win_set_window_position(((ALLEGRO_DISPLAY_WIN *)display)->window, x, y); } static void wgl_get_window_position(ALLEGRO_DISPLAY *display, int *x, int *y) { _al_win_get_window_position(((ALLEGRO_DISPLAY_WIN *)display)->window, x, y); } /* Obtain a reference to this driver. */ ALLEGRO_DISPLAY_INTERFACE *_al_display_wgl_driver(void) { if (vt.create_display) return &vt; vt.create_display = wgl_create_display; vt.destroy_display = wgl_destroy_display; vt.resize_display = wgl_resize_display; vt.set_current_display = wgl_set_current_display; vt.unset_current_display = wgl_unset_current_display; vt.flip_display = wgl_flip_display; vt.update_display_region = wgl_update_display_region; vt.acknowledge_resize = wgl_acknowledge_resize; vt.create_bitmap = _al_ogl_create_bitmap; vt.get_backbuffer = _al_ogl_get_backbuffer; vt.set_target_bitmap = _al_ogl_set_target_bitmap; vt.is_compatible_bitmap = wgl_is_compatible_bitmap; vt.switch_in = wgl_switch_in; vt.switch_out = wgl_switch_out; vt.set_mouse_cursor = _al_win_set_mouse_cursor; vt.set_system_mouse_cursor = _al_win_set_system_mouse_cursor; vt.show_mouse_cursor = _al_win_show_mouse_cursor; vt.hide_mouse_cursor = _al_win_hide_mouse_cursor; vt.set_icons = _al_win_set_display_icons; vt.set_window_position = wgl_set_window_position; vt.get_window_position = wgl_get_window_position; vt.get_window_borders = _al_win_get_window_borders; vt.set_window_constraints = _al_win_set_window_constraints; vt.get_window_constraints = _al_win_get_window_constraints; vt.apply_window_constraints = _al_win_apply_window_constraints; vt.set_display_flag = _al_win_set_display_flag; vt.set_window_title = _al_win_set_window_title; vt.update_render_state = _al_ogl_update_render_state; _al_ogl_add_drawing_functions(&vt); _al_win_add_clipboard_functions(&vt); return &vt; } int _al_wgl_get_num_display_modes(int format, int refresh_rate, int flags) { DEVMODE dm; int count = 0; /* FIXME: Ignoring format. * To get a list of pixel formats we have to create a window with a valid DC, which * would even require to change the video mode in fullscreen cases and we really * don't want to do that. */ (void)format; (void)refresh_rate; (void)flags; memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(dm); while (EnumDisplaySettings(NULL, count, &dm) != false) { count++; } return count; } ALLEGRO_DISPLAY_MODE *_al_wgl_get_display_mode(int index, int format, int refresh_rate, int flags, ALLEGRO_DISPLAY_MODE *mode) { DEVMODE dm; /* * FIXME: see the comment in _al_wgl_get_num_display_modes */ (void)format; (void)refresh_rate; (void)flags; memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(dm); if (!EnumDisplaySettings(NULL, index, &dm)) return NULL; mode->width = dm.dmPelsWidth; mode->height = dm.dmPelsHeight; mode->refresh_rate = dm.dmDisplayFrequency; mode->format = format; switch (dm.dmBitsPerPel) { case 32: if (format == ALLEGRO_PIXEL_FORMAT_ANY) mode->format = ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA; else if (format == ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA) mode->format = ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA; break; case 24: mode->format = ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA; break; case 16: if (format == ALLEGRO_PIXEL_FORMAT_ANY) mode->format = ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA; else if(format == ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA) mode->format = ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA; break; default: break; } return mode; } /* vi: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/whapall.c000066400000000000000000000206471473414355200166510ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows wrapper haptic (force-feedback) device driver. * This wraps around the XInput and DirectInput drivers to support both. * By Beoran. * * See LICENSE.txt for copyright information. */ #define ALLEGRO_NO_COMPATIBILITY #define DIRECTINPUT_VERSION 0x0800 /* For waitable timers */ #define _WIN32_WINNT 0x0501 #include "allegro5/allegro.h" #include "allegro5/haptic.h" #include "allegro5/internal/aintern.h" #include "allegro5/platform/aintwin.h" #include "allegro5/internal/aintern_haptic.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_bitmap.h" #ifdef ALLEGRO_CFG_XINPUT /* Don't compile this lot if xinput and directinput isn't supported. */ #include "allegro5/internal/aintern_wjoyall.h" ALLEGRO_DEBUG_CHANNEL("haptic") /* forward declarations */ static bool hapall_init_haptic(void); static void hapall_exit_haptic(void); static bool hapall_is_mouse_haptic(ALLEGRO_MOUSE *dev); static bool hapall_is_joystick_haptic(ALLEGRO_JOYSTICK *); static bool hapall_is_keyboard_haptic(ALLEGRO_KEYBOARD *dev); static bool hapall_is_display_haptic(ALLEGRO_DISPLAY *dev); static bool hapall_is_touch_input_haptic(ALLEGRO_TOUCH_INPUT *dev); static ALLEGRO_HAPTIC *hapall_get_from_mouse(ALLEGRO_MOUSE *dev); static ALLEGRO_HAPTIC *hapall_get_from_joystick(ALLEGRO_JOYSTICK *dev); static ALLEGRO_HAPTIC *hapall_get_from_keyboard(ALLEGRO_KEYBOARD *dev); static ALLEGRO_HAPTIC *hapall_get_from_display(ALLEGRO_DISPLAY *dev); static ALLEGRO_HAPTIC *hapall_get_from_touch_input(ALLEGRO_TOUCH_INPUT *dev); static bool hapall_release(ALLEGRO_HAPTIC *haptic); static bool hapall_get_active(ALLEGRO_HAPTIC *hap); static int hapall_get_capabilities(ALLEGRO_HAPTIC *dev); static double hapall_get_gain(ALLEGRO_HAPTIC *dev); static bool hapall_set_gain(ALLEGRO_HAPTIC *dev, double); static int hapall_get_max_effects(ALLEGRO_HAPTIC *dev); static bool hapall_is_effect_ok(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *eff); static bool hapall_upload_effect(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *eff, ALLEGRO_HAPTIC_EFFECT_ID *id); static bool hapall_play_effect(ALLEGRO_HAPTIC_EFFECT_ID *id, int loop); static bool hapall_stop_effect(ALLEGRO_HAPTIC_EFFECT_ID *id); static bool hapall_is_effect_playing(ALLEGRO_HAPTIC_EFFECT_ID *id); static bool hapall_release_effect(ALLEGRO_HAPTIC_EFFECT_ID *id); static double hapall_get_autocenter(ALLEGRO_HAPTIC *dev); static bool hapall_set_autocenter(ALLEGRO_HAPTIC *dev, double); ALLEGRO_HAPTIC_DRIVER _al_hapdrv_windows_all = { AL_HAPTIC_TYPE_WINDOWS_ALL, "", "", "Windows haptic(s)", hapall_init_haptic, hapall_exit_haptic, hapall_is_mouse_haptic, hapall_is_joystick_haptic, hapall_is_keyboard_haptic, hapall_is_display_haptic, hapall_is_touch_input_haptic, hapall_get_from_mouse, hapall_get_from_joystick, hapall_get_from_keyboard, hapall_get_from_display, hapall_get_from_touch_input, hapall_get_active, hapall_get_capabilities, hapall_get_gain, hapall_set_gain, hapall_get_max_effects, hapall_is_effect_ok, hapall_upload_effect, hapall_play_effect, hapall_stop_effect, hapall_is_effect_playing, hapall_release_effect, hapall_release, hapall_get_autocenter, hapall_set_autocenter }; /* Mutex for thread protection. */ static ALLEGRO_MUTEX *hapall_mutex = NULL; /* Initializes the combined haptic system. */ static bool hapall_init_haptic(void) { bool xi_ok, di_ok; ASSERT(hapall_mutex == NULL); /* Create the mutex. */ hapall_mutex = al_create_mutex_recursive(); if (!hapall_mutex) return false; al_lock_mutex(hapall_mutex); xi_ok = _al_hapdrv_xinput.init_haptic(); di_ok = _al_hapdrv_directx.init_haptic(); al_unlock_mutex(hapall_mutex); return xi_ok || di_ok; } static void hapall_exit_haptic(void) { ASSERT(hapall_mutex); al_destroy_mutex(hapall_mutex); hapall_mutex = NULL; } static bool hapall_get_active(ALLEGRO_HAPTIC *haptic) { return haptic->driver->get_active(haptic); } static bool hapall_is_mouse_haptic(ALLEGRO_MOUSE *mouse) { (void)mouse; return false; } static bool hapall_is_joystick_haptic(ALLEGRO_JOYSTICK *joy) { bool dx_ok = false, xi_ok = false; ASSERT(joy->driver); if (joy->driver == &_al_joydrv_xinput) { dx_ok = _al_hapdrv_xinput.is_joystick_haptic(joy); } else if (joy->driver == &_al_joydrv_directx) { xi_ok = _al_hapdrv_directx.is_joystick_haptic(joy); } return dx_ok || xi_ok; } static bool hapall_is_display_haptic(ALLEGRO_DISPLAY *dev) { (void)dev; return false; } static bool hapall_is_keyboard_haptic(ALLEGRO_KEYBOARD *dev) { (void)dev; return false; } static bool hapall_is_touch_input_haptic(ALLEGRO_TOUCH_INPUT *dev) { (void)dev; return false; } static ALLEGRO_HAPTIC *hapall_get_from_mouse(ALLEGRO_MOUSE *mouse) { (void)mouse; return NULL; } static ALLEGRO_HAPTIC *hapall_get_from_joystick(ALLEGRO_JOYSTICK *joy) { ALLEGRO_HAPTIC *haptic = NULL; if (!al_is_joystick_haptic(joy)) return NULL; al_lock_mutex(hapall_mutex); if (joy->driver == &_al_joydrv_xinput) { haptic = _al_hapdrv_xinput.get_from_joystick(joy); if (haptic) { haptic->driver = &_al_hapdrv_xinput; } } else if (joy->driver == &_al_joydrv_directx) { haptic = _al_hapdrv_directx.get_from_joystick(joy); if (haptic) { haptic->driver = &_al_hapdrv_directx; } } al_unlock_mutex(hapall_mutex); return haptic; } static ALLEGRO_HAPTIC *hapall_get_from_display(ALLEGRO_DISPLAY *dev) { (void)dev; return NULL; } static ALLEGRO_HAPTIC *hapall_get_from_keyboard(ALLEGRO_KEYBOARD *dev) { (void)dev; return NULL; } static ALLEGRO_HAPTIC *hapall_get_from_touch_input(ALLEGRO_TOUCH_INPUT *dev) { (void)dev; return NULL; } static int hapall_get_capabilities(ALLEGRO_HAPTIC *dev) { return dev->driver->get_capabilities(dev); } static double hapall_get_gain(ALLEGRO_HAPTIC *dev) { return dev->driver->get_gain(dev); } static bool hapall_set_gain(ALLEGRO_HAPTIC *dev, double gain) { return dev->driver->set_gain(dev, gain); } double hapall_get_autocenter(ALLEGRO_HAPTIC *dev) { return dev->driver->get_autocenter(dev); } static bool hapall_set_autocenter(ALLEGRO_HAPTIC *dev, double intensity) { return dev->driver->set_autocenter(dev, intensity); } static int hapall_get_max_effects(ALLEGRO_HAPTIC *dev) { return dev->driver->get_max_effects(dev); } static bool hapall_is_effect_ok(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *effect) { return dev->driver->is_effect_ok(dev, effect); } static bool hapall_upload_effect(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *effect, ALLEGRO_HAPTIC_EFFECT_ID *id) { /* store the driver we'll need it later. */ id->driver = dev->driver; return dev->driver->upload_effect(dev, effect, id); } static bool hapall_play_effect(ALLEGRO_HAPTIC_EFFECT_ID *id, int loops) { ALLEGRO_HAPTIC_DRIVER *driver = id->driver; /* Use the stored driver to perform the operation. */ return driver->play_effect(id, loops); } static bool hapall_stop_effect(ALLEGRO_HAPTIC_EFFECT_ID *id) { ALLEGRO_HAPTIC_DRIVER *driver = id->driver; /* Use the stored driver to perform the operation. */ return driver->stop_effect(id); } static bool hapall_is_effect_playing(ALLEGRO_HAPTIC_EFFECT_ID *id) { ALLEGRO_HAPTIC_DRIVER *driver = id->driver; /* Use the stored driver to perform the operation. */ return driver->is_effect_playing(id); } static bool hapall_release_effect(ALLEGRO_HAPTIC_EFFECT_ID *id) { ALLEGRO_HAPTIC_DRIVER *driver = id->driver; /* Use the stored driver to perform the operation. */ return driver->release_effect(id); } static bool hapall_release(ALLEGRO_HAPTIC *haptic) { if (!haptic) return false; return haptic->driver->release(haptic); } #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/whapdrv.c000066400000000000000000000020011473414355200166540ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * List of Windows joystick drivers, kept in a seperate file so that * they can be overriden by user programs. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_haptic.h" #ifndef ALLEGRO_WINDOWS #error something is wrong with the makefile #endif /* Construct the DirectInput haptics driver list */ _AL_BEGIN_HAPTIC_DRIVER_LIST _AL_HAPTIC_DRIVER_DIRECTX _AL_END_HAPTIC_DRIVER_LIST allegro5-5.2.10.1/src/win/whaptic.cpp000066400000000000000000001223101473414355200172060ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows haptic (force-feedback) device driver. * * By Beoran. * * See LICENSE.txt for copyright information. */ #define ALLEGRO_NO_COMPATIBILITY #define DIRECTINPUT_VERSION 0x0800 /* For waitable timers */ #define _WIN32_WINNT 0x0501 #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/platform/aintwin.h" #include "allegro5/internal/aintern_haptic.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_bitmap.h" #ifndef ALLEGRO_WINDOWS #error something is wrong with the makefile #endif #ifdef ALLEGRO_MINGW32 #undef MAKEFOURCC #endif #include #include #include #include #include #include /* #include */ #include "allegro5/internal/aintern_wjoydxnu.h" ALLEGRO_DEBUG_CHANNEL("whaptic") /* Support at most 32 haptic devices. */ #define HAPTICS_MAX 32 /* Support at most 16 effects per device. */ #define HAPTICS_EFFECTS_MAX 16 /* Support at most 3 axes per device. */ #define HAPTICS_AXES_MAX 3 /** This union is needed to avoid dynamical memory allocation. */ typedef union { DICONSTANTFORCE constant; DIRAMPFORCE ramp; DIPERIODIC periodic; DICONDITION condition; DICUSTOMFORCE custom; } ALLEGRO_HAPTIC_PARAMETER_WINDOWS; /* * Haptic effect system data. */ struct ALLEGRO_HAPTIC_EFFECT_WINDOWS { int id; bool active; DIEFFECT effect; DIENVELOPE envelope; LPDIRECTINPUTEFFECT ref; DWORD axes[HAPTICS_AXES_MAX]; LONG directions[HAPTICS_AXES_MAX]; ALLEGRO_HAPTIC_PARAMETER_WINDOWS parameter; const GUID* guid; }; struct ALLEGRO_HAPTIC_WINDOWS { struct ALLEGRO_HAPTIC parent; /* must be first */ bool active; LPDIRECTINPUTDEVICE2 device; GUID guid; DIDEVICEINSTANCE instance; DIDEVCAPS capabilities; LPDIRECTINPUTDEVICE8 device8; ALLEGRO_DISPLAY_WIN* display; int flags; ALLEGRO_HAPTIC_EFFECT_WINDOWS effects[HAPTICS_EFFECTS_MAX]; DWORD axes[HAPTICS_AXES_MAX]; int naxes; }; #define LONG_BITS (sizeof(long) * 8) #define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS) /* Tests if a bit in an array of longs is set. */ #define TEST_BIT(nr, addr) \ ((1UL << ((nr) % LONG_BITS)) & (addr)[(nr) / LONG_BITS]) /* forward declarations */ static bool whap_init_haptic(void); static void whap_exit_haptic(void); static bool whap_is_mouse_haptic(ALLEGRO_MOUSE *dev); static bool whap_is_joystick_haptic(ALLEGRO_JOYSTICK *); static bool whap_is_keyboard_haptic(ALLEGRO_KEYBOARD *dev); static bool whap_is_display_haptic(ALLEGRO_DISPLAY *dev); static bool whap_is_touch_input_haptic(ALLEGRO_TOUCH_INPUT *dev); static ALLEGRO_HAPTIC *whap_get_from_mouse(ALLEGRO_MOUSE *dev); static ALLEGRO_HAPTIC *whap_get_from_joystick(ALLEGRO_JOYSTICK *dev); static ALLEGRO_HAPTIC *whap_get_from_keyboard(ALLEGRO_KEYBOARD *dev); static ALLEGRO_HAPTIC *whap_get_from_display(ALLEGRO_DISPLAY *dev); static ALLEGRO_HAPTIC *whap_get_from_touch_input(ALLEGRO_TOUCH_INPUT *dev); static bool whap_release(ALLEGRO_HAPTIC *haptic); static bool whap_get_active(ALLEGRO_HAPTIC *hap); static int whap_get_capabilities(ALLEGRO_HAPTIC *dev); static double whap_get_gain(ALLEGRO_HAPTIC *dev); static bool whap_set_gain(ALLEGRO_HAPTIC *dev, double); static int whap_get_max_effects(ALLEGRO_HAPTIC *dev); static bool whap_is_effect_ok(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *eff); static bool whap_upload_effect(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *eff, ALLEGRO_HAPTIC_EFFECT_ID *id); static bool whap_play_effect(ALLEGRO_HAPTIC_EFFECT_ID *id, int loop); static bool whap_stop_effect(ALLEGRO_HAPTIC_EFFECT_ID *id); static bool whap_is_effect_playing(ALLEGRO_HAPTIC_EFFECT_ID *id); static bool whap_release_effect(ALLEGRO_HAPTIC_EFFECT_ID *id); static double whap_get_autocenter(ALLEGRO_HAPTIC *dev); static bool whap_set_autocenter(ALLEGRO_HAPTIC *dev, double); ALLEGRO_HAPTIC_DRIVER _al_hapdrv_directx = { AL_HAPTIC_TYPE_DIRECTX, "", "", "Windows haptic(s)", whap_init_haptic, whap_exit_haptic, whap_is_mouse_haptic, whap_is_joystick_haptic, whap_is_keyboard_haptic, whap_is_display_haptic, whap_is_touch_input_haptic, whap_get_from_mouse, whap_get_from_joystick, whap_get_from_keyboard, whap_get_from_display, whap_get_from_touch_input, whap_get_active, whap_get_capabilities, whap_get_gain, whap_set_gain, whap_get_max_effects, whap_is_effect_ok, whap_upload_effect, whap_play_effect, whap_stop_effect, whap_is_effect_playing, whap_release_effect, whap_release, whap_get_autocenter, whap_set_autocenter }; static ALLEGRO_HAPTIC_WINDOWS haptics[HAPTICS_MAX]; static ALLEGRO_MUTEX *haptic_mutex = NULL; /* Capability map between directinput effects and allegro effect types. */ struct CAP_MAP { GUID guid; int allegro_bit; }; /* GUID values are borrowed from Wine */ #define DEFINE_PRIVATE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ static const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } DEFINE_PRIVATE_GUID(_al_GUID_None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); static const struct CAP_MAP cap_map[] = { { GUID_ConstantForce, ALLEGRO_HAPTIC_CONSTANT }, { GUID_Spring, ALLEGRO_HAPTIC_SPRING }, { GUID_Spring, ALLEGRO_HAPTIC_FRICTION }, { GUID_Damper, ALLEGRO_HAPTIC_DAMPER }, { GUID_Inertia, ALLEGRO_HAPTIC_INERTIA }, { GUID_RampForce, ALLEGRO_HAPTIC_RAMP }, { GUID_Square, ALLEGRO_HAPTIC_SQUARE }, { GUID_Triangle, ALLEGRO_HAPTIC_TRIANGLE }, { GUID_Sine, ALLEGRO_HAPTIC_SINE }, { GUID_SawtoothUp, ALLEGRO_HAPTIC_SAW_UP }, { GUID_SawtoothDown, ALLEGRO_HAPTIC_SAW_DOWN }, { GUID_CustomForce, ALLEGRO_HAPTIC_CUSTOM }, /*{ { _al_GUID_None }, -1 } */ }; static bool whap_init_haptic(void) { int i; ASSERT(haptic_mutex == NULL); haptic_mutex = al_create_mutex(); if (!haptic_mutex) return false; for (i = 0; i < HAPTICS_MAX; i++) { haptics[i].active = false; } return true; } static ALLEGRO_HAPTIC_WINDOWS *whap_get_available_haptic(void) { int i; for (i = 0; i < HAPTICS_MAX; i++) { if (!haptics[i].active) { haptics[i].active = true; return &haptics[i]; } } return NULL; } /* Look for a free haptic effect slot for a device and return it, * or NULL if exhausted. Also initializes the effect * reference to NULL. */ static ALLEGRO_HAPTIC_EFFECT_WINDOWS *whap_get_available_effect(ALLEGRO_HAPTIC_WINDOWS *whap) { ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff; int i; for (i = 0; i < al_get_max_haptic_effects(&whap->parent); i++) { if (!whap->effects[i].active) { weff = whap->effects + i; weff->id = i; weff->active = true; weff->ref = NULL; return weff; } } return NULL; } /* Releases a windows haptics effect and unloads it from the device. */ static bool whap_release_effect_windows(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff) { bool result = true; if (!weff) return false; /* make it easy to handle all cases later on. */ if (!weff->active) return false; /* already not in use, bail out. */ /* Unload the effect from the device. */ if (weff->ref) { HRESULT ret; ret = IDirectInputEffect_Unload(weff->ref); if (FAILED(ret)) { ALLEGRO_WARN("Could not unload effect."); result = false; } } /* Custom force needs to clean up it's data. */ if (weff->guid == &GUID_CustomForce) { al_free(weff->parameter.custom.rglForceData); weff->parameter.custom.rglForceData = NULL; } weff->active = false; /* not in use */ weff->ref = NULL; /* No reference to effect anymore. */ return result; } /* Converts a generic haptic device to a Windows-specific one. */ static ALLEGRO_HAPTIC_WINDOWS *whap_from_al(ALLEGRO_HAPTIC *hap) { return (ALLEGRO_HAPTIC_WINDOWS *)hap; } static void whap_exit_haptic(void) { ASSERT(haptic_mutex); al_destroy_mutex(haptic_mutex); haptic_mutex = NULL; } /* Convert the type of the periodic allegro effect to the windows effect*/ static bool whap_periodictype2win(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_EFFECT *effect) { switch (effect->data.periodic.waveform) { case ALLEGRO_HAPTIC_SINE: weff->guid = &GUID_Sine; return true; case ALLEGRO_HAPTIC_SQUARE: weff->guid = &GUID_Square; return true; case ALLEGRO_HAPTIC_TRIANGLE: weff->guid = &GUID_Triangle; return true; case ALLEGRO_HAPTIC_SAW_UP: weff->guid = &GUID_SawtoothUp; return true; case ALLEGRO_HAPTIC_SAW_DOWN: weff->guid = &GUID_SawtoothDown; return true; case ALLEGRO_HAPTIC_CUSTOM: weff->guid = &GUID_CustomForce; return true; default: return false; } } /* Convert the type of the allegro effect to the windows effect*/ static bool whap_type2win(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_EFFECT *effect) { switch (effect->type) { case ALLEGRO_HAPTIC_RUMBLE: weff->guid = &GUID_Sine; return true; case ALLEGRO_HAPTIC_PERIODIC: return whap_periodictype2win(weff, effect); case ALLEGRO_HAPTIC_CONSTANT: weff->guid = &GUID_ConstantForce; return true; case ALLEGRO_HAPTIC_SPRING: weff->guid = &GUID_Spring; return true; case ALLEGRO_HAPTIC_FRICTION: weff->guid = &GUID_Friction; return true; case ALLEGRO_HAPTIC_DAMPER: weff->guid = &GUID_Damper; return true; case ALLEGRO_HAPTIC_INERTIA: weff->guid = &GUID_Inertia; return true; case ALLEGRO_HAPTIC_RAMP: weff->guid = &GUID_RampForce; return true; default: return NULL; } return true; } /* Convert the direction of the allegro effect to the windows effect*/ static bool whap_direction2win(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_EFFECT *effect, ALLEGRO_HAPTIC_WINDOWS *whap) { unsigned int index; double calc_x, calc_y; /* It seems that (at least for sine motions), 1 or 2 axes work, but 0 or 3 don't for my test joystick. Also, while polar or spherical coordinates are accepted, they don't cause any vibration for a periodic effect. All in all it seems that cartesian is the only well-supported axis system, at least for periodic effects. Need more tests with other joysticks to see their behavior. Annoyingly there seems to be no way to discover what kind of axis system is supported without trying to upload the effect... Hence, use a 1 or 2 axis cartesian system and hope for the best for non-periodic effects. */ /* Use CARTESIAN coordinates since those seem to be the only well suppported ones. */ weff->effect.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; /* Prepare axes. If whap naxes is > 2, use 2 because more than 2 axes isn't always supported. */ weff->effect.cAxes = whap->naxes; if (weff->effect.cAxes > 2) { weff->effect.cAxes = 2; } memset((void *)weff->axes, 0, sizeof(weff->axes)); for (index = 0; index < weff->effect.cAxes; index++) { weff->axes[index] = whap->axes[index]; } weff->effect.rgdwAxes = weff->axes; /* Set up directions as well.. */ memset((void *)weff->directions, 0, sizeof(weff->directions)); /* Calculate the X and Y coordinates of the effect based on the angle. That is map angular coordinates to cartesian ones. */ calc_x = sin(effect->direction.angle) * effect->direction.radius * DI_FFNOMINALMAX; calc_y = cos(effect->direction.angle) * effect->direction.radius * DI_FFNOMINALMAX; /* Set X if there is 1 axis and also y if there are more . */ if (weff->effect.cAxes > 1) { weff->directions[0] = (long)calc_x; } if (whap->naxes > 2) { weff->directions[1] = (long)calc_y; } weff->effect.rglDirection = weff->directions; return true; } /* Converts the time in seconds to a Windows-compatible time. * Return false if out of bounds. */ static bool whap_time2win(DWORD *res, double sec) { ASSERT(res); if (sec < 0.0 || sec >= 4294.967296) return false; (*res) = (DWORD)floor(sec * DI_SECONDS); return true; } /* Converts the level in range 0.0 to 1.0 to a Windows-compatible level. * Returns false if out of bounds. */ static bool whap_level2win(DWORD *res, double level) { ASSERT(res); if (level < 0.0 || level > 1.0) return false; *res = (DWORD)floor(level * DI_FFNOMINALMAX); return true; } /* Converts the level in range -1.0 to 1.0 to a Windows-compatible level. * Returns false if out of bounds. */ static bool whap_slevel2win(LONG *res, double level) { ASSERT(res); if (level < -1.0 || level > 1.0) return false; *res = (LONG)(level * DI_FFNOMINALMAX); return true; } /* Converts a phase in range 0.0 to 1.0 to a Windows-compatible level. * Returns false if out of bounds. */ static bool whap_phase2win(DWORD *res, double phase) { ASSERT(res); if (phase < 0.0 || phase > 1.0) return false; *res = (DWORD)(phase * 35999); return true; } /* Converts replay data to Widows-compatible data. */ static bool whap_replay2win(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_EFFECT *effect) { return whap_time2win(&weff->effect.dwStartDelay, effect->replay.delay) && whap_time2win(&weff->effect.dwDuration, effect->replay.length); } /* Converts an Allegro haptic effect envelope to DirectInput API. */ static bool whap_envelope2win(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_ENVELOPE *aenv) { /* Prepare envelope. */ DIENVELOPE *wenv = &weff->envelope; /* Do not set any envelope if all values are 0.0 */ if ((aenv->attack_length == 0.0) && (aenv->fade_length == 0.0) && (aenv->attack_level == 0.0) && (aenv->fade_level == 0.0)) { return true; } /* Prepare the envelope. */ memset((void *)wenv, 0, sizeof(DIENVELOPE)); weff->envelope.dwSize = sizeof(DIENVELOPE); weff->effect.lpEnvelope = wenv; /* Set the values. */ return whap_time2win(&wenv->dwAttackTime, aenv->attack_length) && whap_time2win(&wenv->dwFadeTime, aenv->fade_length) && whap_level2win(&wenv->dwAttackLevel, aenv->attack_level) && whap_level2win(&wenv->dwFadeLevel, aenv->fade_level); } /* Converts a constant effect to directinput API. */ static bool whap_constant2win(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_EFFECT *effect) { weff->effect.cbTypeSpecificParams = sizeof(weff->parameter.constant); weff->effect.lpvTypeSpecificParams = &weff->parameter.constant; return whap_envelope2win(weff, &effect->data.constant.envelope) && whap_slevel2win(&weff->parameter.constant.lMagnitude, effect->data.constant.level); } /* Converts a ramp effect to directinput input API. */ static bool whap_ramp2win(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_EFFECT *effect) { weff->effect.cbTypeSpecificParams = sizeof(weff->parameter.ramp); weff->effect.lpvTypeSpecificParams = &weff->parameter.ramp; return whap_envelope2win(weff, &effect->data.ramp.envelope) && whap_slevel2win(&weff->parameter.ramp.lStart, effect->data.ramp.start_level) && whap_slevel2win(&weff->parameter.ramp.lEnd, effect->data.ramp.end_level); } /* Converts a condition effect to directinput input API. */ static bool whap_condition2win(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_EFFECT *effect) { weff->effect.cbTypeSpecificParams = sizeof(weff->parameter.condition); weff->effect.lpvTypeSpecificParams = &weff->parameter.condition; /* XXX: no envelope here ??? */ return whap_level2win(&weff->parameter.condition.dwNegativeSaturation, effect->data.condition.left_saturation) && whap_level2win(&weff->parameter.condition.dwPositiveSaturation, effect->data.condition.right_saturation) && whap_slevel2win(&weff->parameter.condition.lNegativeCoefficient, effect->data.condition.left_coeff) && whap_slevel2win(&weff->parameter.condition.lPositiveCoefficient, effect->data.condition.right_coeff) && whap_slevel2win(&weff->parameter.condition.lDeadBand, effect->data.condition.deadband) && whap_slevel2win(&weff->parameter.condition.lOffset, effect->data.condition.center); } /* Converts a custom effect to directinput input API. */ static bool whap_custom2win(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_EFFECT *effect) { int index; weff->effect.cbTypeSpecificParams = sizeof(weff->parameter.custom); weff->effect.lpvTypeSpecificParams = &weff->parameter.custom; weff->parameter.custom.cChannels = 1; weff->parameter.custom.cSamples = effect->data.periodic.custom_len; /* Use al malloc only in this case since the custom_data can be arbitrarily long. */ weff->parameter.custom.rglForceData = (LONG *)al_malloc(sizeof(LONG) * effect->data.periodic.custom_len); if (!weff->parameter.custom.rglForceData) return false; /* Gotta copy this to long values, and scale them too... */ for (index = 0; index < effect->data.periodic.custom_len; index++) { weff->parameter.custom.rglForceData[index] = (LONG)(effect->data.periodic.custom_data[index] * ((double)(1 << 31))); } return true; } /* Converts a periodic effect to directinput input API. */ static bool whap_periodic2win(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_EFFECT *effect) { if (effect->data.periodic.waveform == ALLEGRO_HAPTIC_CUSTOM) { return whap_custom2win(weff, effect); } weff->effect.cbTypeSpecificParams = sizeof(weff->parameter.periodic); weff->effect.lpvTypeSpecificParams = &weff->parameter.periodic; return whap_envelope2win(weff, &effect->data.periodic.envelope) && whap_level2win(&weff->parameter.periodic.dwMagnitude, effect->data.periodic.magnitude) && whap_phase2win(&weff->parameter.periodic.dwPhase, effect->data.periodic.phase) && whap_time2win(&weff->parameter.periodic.dwPeriod, effect->data.periodic.period) && whap_slevel2win(&weff->parameter.periodic.lOffset, effect->data.periodic.offset); } /* Converts a periodic effect to directinput input API. */ static bool whap_rumble2win(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_EFFECT *effect) { weff->effect.cbTypeSpecificParams = sizeof(weff->parameter.periodic); weff->effect.lpvTypeSpecificParams = &weff->parameter.periodic; return whap_level2win(&weff->parameter.periodic.dwMagnitude, effect->data.rumble.strong_magnitude) && whap_phase2win(&weff->parameter.periodic.dwPhase, 0) && whap_time2win(&weff->parameter.periodic.dwPeriod, 0.01) && whap_slevel2win(&weff->parameter.periodic.lOffset, 0); } /* Converts Allegro haptic effect to dinput API. */ static bool whap_effect2win(ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_EFFECT *effect, ALLEGRO_HAPTIC_WINDOWS *whap) { /* Generic setup */ memset((void *)weff, 0, sizeof(*weff)); /* Set global stuff. */ weff->effect.dwSize = sizeof(DIEFFECT); weff->effect.dwGain = DI_FFNOMINALMAX; weff->effect.dwSamplePeriod = 0; weff->effect.dwFlags = DIEFF_OBJECTOFFSETS; weff->effect.lpEnvelope = NULL; /* Gain of the effect must be set to max, otherwise it won't be felt (enough) as the per effect gain multiplies with the per-device gain. */ weff->effect.dwGain = DI_FFNOMINALMAX; /* This effect is not mapped to a trigger, and must be played explicitly. */ weff->effect.dwTriggerButton = DIEB_NOTRIGGER; if (!whap_type2win(weff, effect)) { return false; } if (!whap_direction2win(weff, effect, whap)) { return false; } if (!whap_replay2win(weff, effect)) { return false; } switch (effect->type) { case ALLEGRO_HAPTIC_RUMBLE: return whap_rumble2win(weff, effect); case ALLEGRO_HAPTIC_PERIODIC: return whap_periodic2win(weff, effect); case ALLEGRO_HAPTIC_CONSTANT: return whap_constant2win(weff, effect); case ALLEGRO_HAPTIC_RAMP: return whap_ramp2win(weff, effect); case ALLEGRO_HAPTIC_SPRING: case ALLEGRO_HAPTIC_FRICTION: case ALLEGRO_HAPTIC_DAMPER: case ALLEGRO_HAPTIC_INERTIA: return whap_condition2win(weff, effect); default: return false; } } static bool whap_get_active(ALLEGRO_HAPTIC *haptic) { ALLEGRO_HAPTIC_WINDOWS *whap = whap_from_al(haptic); return whap->active; } static bool whap_is_dinput_device_haptic(LPDIRECTINPUTDEVICE2 device) { HRESULT ret; DIDEVCAPS dicaps; /* Get capabilities. */ ALLEGRO_DEBUG("IDirectInputDevice_GetCapabilities on %p\n", device); dicaps.dwSize = sizeof(dicaps); ret = IDirectInputDevice_GetCapabilities(device, &dicaps); if (FAILED(ret)) { ALLEGRO_ERROR("IDirectInputDevice_GetCapabilities failed on %p\n", device); return false; } /** Is it a haptic device? */ bool ishaptic = (dicaps.dwFlags & DIDC_FORCEFEEDBACK); ALLEGRO_DEBUG("dicaps.dwFlags: %lu, %d, %d\n", dicaps.dwFlags, DIDC_FORCEFEEDBACK, ishaptic); return(ishaptic); } static bool whap_is_mouse_haptic(ALLEGRO_MOUSE *mouse) { (void)mouse; return false; } static bool whap_is_joystick_haptic(ALLEGRO_JOYSTICK *joy) { ALLEGRO_JOYSTICK_DIRECTX *joydx = (ALLEGRO_JOYSTICK_DIRECTX *)joy; (void)joydx; if (!al_is_joystick_installed()) return false; if (!al_get_joystick_active(joy)) return false; ALLEGRO_DEBUG("Checking capabilities of joystick %s\n", joydx->name); return whap_is_dinput_device_haptic(joydx->device); } static bool whap_is_display_haptic(ALLEGRO_DISPLAY *dev) { (void)dev; return false; } static bool whap_is_keyboard_haptic(ALLEGRO_KEYBOARD *dev) { (void)dev; return false; } static bool whap_is_touch_input_haptic(ALLEGRO_TOUCH_INPUT *dev) { (void)dev; return false; } static ALLEGRO_HAPTIC *whap_get_from_mouse(ALLEGRO_MOUSE *mouse) { (void)mouse; return NULL; } /* Sets the force feedback gain on a directinput device. Returns true on success and false on failure. */ static bool whap_set_dinput_device_gain(LPDIRECTINPUTDEVICE2 device, double gain) { HRESULT ret; DIPROPDWORD dipdw; if (gain < 0.0) return false; if (gain > 1.0) return false; dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = gain * DI_FFNOMINALMAX; ret = IDirectInputDevice_SetProperty(device, DIPROP_FFGAIN, &dipdw.diph); return(!FAILED(ret)); } /* Sets the force feedback autocentering intensity on a directinput device. Returns true on success and false on failure. */ static bool whap_set_dinput_device_autocenter(LPDIRECTINPUTDEVICE2 device, double intensity) { HRESULT ret; DIPROPDWORD dipdw; if (intensity < 0.0) return false; if (intensity > 1.0) return false; dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; if (intensity < 0.5) { dipdw.dwData = DIPROPAUTOCENTER_OFF; } else { dipdw.dwData = DIPROPAUTOCENTER_ON; } /* Try to set the autocenter. */ ret = IDirectInputDevice_SetProperty(device, DIPROP_AUTOCENTER, &dipdw.diph); return(!FAILED(ret)); } /* Callback to check which effect types are supported. */ static BOOL CALLBACK whap_check_effect_callback(LPCDIEFFECTINFO info, LPVOID data) { ALLEGRO_HAPTIC *haptic = (ALLEGRO_HAPTIC *)data; ALLEGRO_HAPTIC_WINDOWS *whap = whap_from_al(haptic); const CAP_MAP *map; for (map = cap_map; map->allegro_bit != -1; map++) { if (GUID_EQUAL(info->guid, map->guid)) { whap->flags |= map->allegro_bit; } } /* Check for more supported effect types. */ return DIENUM_CONTINUE; } /* Callback to check which axes are supported. */ static BOOL CALLBACK whap_check_axes_callback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID data) { ALLEGRO_HAPTIC *haptic = (ALLEGRO_HAPTIC *)data; ALLEGRO_HAPTIC_WINDOWS *whap = whap_from_al(haptic); if ((dev->dwType & DIDFT_AXIS) && (dev->dwFlags & DIDOI_FFACTUATOR)) { whap->axes[whap->naxes] = dev->dwOfs; whap->naxes++; /* Stop if the axes limit is reached */ if (whap->naxes >= HAPTICS_AXES_MAX) { return DIENUM_STOP; } } return DIENUM_CONTINUE; } /* Acquires an exclusive lock on the device. */ static bool whap_acquire_lock(ALLEGRO_HAPTIC_WINDOWS *whap) { HRESULT ret; /* Release previous acquire lock on device if any */ ret = IDirectInputDevice_Unacquire(whap->device); if (FAILED(ret)) { ALLEGRO_WARN ("IDirectInputDevice_Unacquire failed for haptic device.\n"); return false; } /* Need a display to lock the cooperative level of the haptic device on */ whap->display = (ALLEGRO_DISPLAY_WIN *)al_get_current_display(); if (!whap->display) { ALLEGRO_WARN("No active window available to lock the haptic device on."); return false; } /* Must set the cooperative level to exclusive now to enable force feedback. */ ret = IDirectInputDevice_SetCooperativeLevel(whap->device, whap->display->window, DISCL_BACKGROUND | DISCL_EXCLUSIVE); if (FAILED(ret)) { ALLEGRO_WARN ("IDirectInputDevice_SetCooperativeLevel failed for haptic device.\n"); return false; } /* Get acquire lock on device */ ret = IDirectInputDevice_Acquire(whap->device); if (FAILED(ret)) { ALLEGRO_WARN("IDirectInputDevice_Acquire failed for haptic device.\n"); return false; } return true; } /* Initializes the haptic device for use with DirectInput */ static bool whap_initialize_dinput(ALLEGRO_HAPTIC_WINDOWS *whap) { HRESULT ret; ALLEGRO_HAPTIC *haptic = &whap->parent; /* Set number of axes to zero, and then ... */ whap->naxes = 0; /* ... get number of axes. */ ret = IDirectInputDevice_EnumObjects(whap->device, whap_check_axes_callback, haptic, DIDFT_AXIS); if (FAILED(ret)) { ALLEGRO_WARN("Could not get haptic device axes \n"); return false; } /* Support angle and radius if we have at least 2 axes. * Axis support on DirectInput is a big mess, so Azimuth is unlikely to be * supported. */ if (whap->naxes >= 1) { whap->flags |= ALLEGRO_HAPTIC_ANGLE; whap->flags |= ALLEGRO_HAPTIC_RADIUS; } if (!whap_acquire_lock(whap)) { ALLEGRO_WARN("Could not lock haptic device \n"); return false; } /* Reset all actuators in case some where active */ ret = IDirectInputDevice8_SendForceFeedbackCommand(whap->device, DISFFC_RESET); if (FAILED(ret)) { ALLEGRO_WARN("Could not reset haptic device \n"); } /* Enable all actuators. */ ret = IDirectInputDevice8_SendForceFeedbackCommand(whap->device, DISFFC_SETACTUATORSON); if (FAILED(ret)) { ALLEGRO_WARN("Could not enable haptic device actuators\n"); return false; } /* Get known supported effects. */ ret = IDirectInputDevice8_EnumEffects(whap->device, whap_check_effect_callback, haptic, DIEFT_ALL); if (FAILED(ret)) { ALLEGRO_WARN("Could not get haptic device supported effects\n"); return false; } /* Check if any periodic effects are supported. */ bool periodic_ok = al_is_haptic_capable(haptic, ALLEGRO_HAPTIC_SINE); periodic_ok |= al_is_haptic_capable(haptic, ALLEGRO_HAPTIC_SQUARE); periodic_ok |= al_is_haptic_capable(haptic, ALLEGRO_HAPTIC_TRIANGLE); periodic_ok |= al_is_haptic_capable(haptic, ALLEGRO_HAPTIC_SAW_DOWN); periodic_ok |= al_is_haptic_capable(haptic, ALLEGRO_HAPTIC_SAW_UP); if (periodic_ok) { /* If we have any of the effects above, we can use periodic and rumble effects. */ whap->flags |= (ALLEGRO_HAPTIC_PERIODIC | ALLEGRO_HAPTIC_RUMBLE); } if (whap_set_dinput_device_gain(whap->device, 1.0)) { whap->flags |= ALLEGRO_HAPTIC_GAIN; } /* Check autocenter and turn it off in one go. */ if (whap_set_dinput_device_autocenter(whap->device, 0.0)) { whap->flags |= ALLEGRO_HAPTIC_AUTOCENTER; } return true; } static ALLEGRO_HAPTIC *whap_get_from_joystick(ALLEGRO_JOYSTICK *joy) { ALLEGRO_JOYSTICK_DIRECTX *joydx = (ALLEGRO_JOYSTICK_DIRECTX *)joy; ALLEGRO_HAPTIC_WINDOWS *whap; int i; if (!al_is_joystick_haptic(joy)) return NULL; al_lock_mutex(haptic_mutex); whap = whap_get_available_haptic(); if (!whap) { al_unlock_mutex(haptic_mutex); return NULL; } whap->parent.driver = &_al_hapdrv_directx; whap->parent.device = joy; whap->parent.from = _AL_HAPTIC_FROM_JOYSTICK; whap->guid = joydx->guid; whap->device = joydx->device; whap->active = true; for (i = 0; i < HAPTICS_EFFECTS_MAX; i++) { whap->effects[i].active = false; /* not in use */ } whap->parent.gain = 1.0; whap->parent.autocenter = 0.0; /* result is ok if init functions returns true. */ if (!whap_initialize_dinput(whap)) { al_release_haptic(&whap->parent); al_unlock_mutex(haptic_mutex); return NULL; } al_unlock_mutex(haptic_mutex); return &whap->parent; } static ALLEGRO_HAPTIC *whap_get_from_display(ALLEGRO_DISPLAY *dev) { (void)dev; return NULL; } static ALLEGRO_HAPTIC *whap_get_from_keyboard(ALLEGRO_KEYBOARD *dev) { (void)dev; return NULL; } static ALLEGRO_HAPTIC *whap_get_from_touch_input(ALLEGRO_TOUCH_INPUT *dev) { (void)dev; return NULL; } static int whap_get_capabilities(ALLEGRO_HAPTIC *dev) { ALLEGRO_HAPTIC_WINDOWS *whap = whap_from_al(dev); return whap->flags; } static double whap_get_gain(ALLEGRO_HAPTIC *dev) { ALLEGRO_HAPTIC_WINDOWS *whap = whap_from_al(dev); /* Just return the stored gain, it's easier than querying. */ return whap->parent.gain; } static bool whap_set_gain(ALLEGRO_HAPTIC *dev, double gain) { ALLEGRO_HAPTIC_WINDOWS *whap = whap_from_al(dev); bool ok = whap_set_dinput_device_gain(whap->device, gain); if (ok) { whap->parent.gain = gain; } else { whap->parent.gain = 1.0; } return ok; } double whap_get_autocenter(ALLEGRO_HAPTIC *dev) { ALLEGRO_HAPTIC_WINDOWS *whap = whap_from_al(dev); /* Return the stored autocenter value. It's easiest like that. */ return whap->parent.autocenter; } static bool whap_set_autocenter(ALLEGRO_HAPTIC *dev, double intensity) { ALLEGRO_HAPTIC_WINDOWS *whap = whap_from_al(dev); bool ok = whap_set_dinput_device_autocenter(whap->device, intensity); if (ok) { whap->parent.autocenter = intensity; } else { whap->parent.autocenter = 0.0; } return ok; } static int whap_get_max_effects(ALLEGRO_HAPTIC *dev) { ALLEGRO_HAPTIC_WINDOWS *whap = whap_from_al(dev); int n_effects; (void)n_effects, (void)whap; return HAPTICS_EFFECTS_MAX; } static bool whap_is_effect_ok(ALLEGRO_HAPTIC *haptic, ALLEGRO_HAPTIC_EFFECT *effect) { int caps; caps = al_get_haptic_capabilities(haptic); if (caps & effect->type) { return true; } /* XXX: should do more checking here? */ return false; } struct dinput_error_pair { HRESULT error; const char *text; }; #define DIMKEP(ERROR) { ((HRESULT)ERROR), # ERROR } struct dinput_error_pair dinput_errors[] = { DIMKEP(DI_BUFFEROVERFLOW), DIMKEP(DI_DOWNLOADSKIPPED), DIMKEP(DI_EFFECTRESTARTED), DIMKEP(DI_NOEFFECT), DIMKEP(DI_NOTATTACHED), DIMKEP(DI_OK), DIMKEP(DI_POLLEDDEVICE), DIMKEP(DI_PROPNOEFFECT), DIMKEP(DI_SETTINGSNOTSAVED), DIMKEP(DI_TRUNCATED), DIMKEP(DI_TRUNCATEDANDRESTARTED), DIMKEP(DI_WRITEPROTECT), DIMKEP(DIERR_ACQUIRED), DIMKEP(DIERR_ALREADYINITIALIZED), DIMKEP(DIERR_BADDRIVERVER), DIMKEP(DIERR_BETADIRECTINPUTVERSION), DIMKEP(DIERR_DEVICEFULL), DIMKEP(DIERR_DEVICENOTREG), DIMKEP(DIERR_EFFECTPLAYING), DIMKEP(DIERR_GENERIC), DIMKEP(DIERR_HANDLEEXISTS), DIMKEP(DIERR_HASEFFECTS), DIMKEP(DIERR_INCOMPLETEEFFECT), DIMKEP(DIERR_INPUTLOST), DIMKEP(DIERR_INVALIDPARAM), DIMKEP(DIERR_MAPFILEFAIL), DIMKEP(DIERR_MOREDATA), DIMKEP(DIERR_NOAGGREGATION), DIMKEP(DIERR_NOINTERFACE), DIMKEP(DIERR_NOTACQUIRED), DIMKEP(DIERR_NOTBUFFERED), DIMKEP(DIERR_NOTDOWNLOADED), DIMKEP(DIERR_NOTEXCLUSIVEACQUIRED), DIMKEP(DIERR_NOTFOUND), DIMKEP(DIERR_NOTINITIALIZED), DIMKEP(DIERR_OBJECTNOTFOUND), DIMKEP(DIERR_OLDDIRECTINPUTVERSION), DIMKEP(DIERR_OTHERAPPHASPRIO), DIMKEP(DIERR_OUTOFMEMORY), DIMKEP(DIERR_READONLY), DIMKEP(DIERR_REPORTFULL), DIMKEP(DIERR_UNPLUGGED), DIMKEP(DIERR_UNSUPPORTED), DIMKEP(E_HANDLE), DIMKEP(E_PENDING), DIMKEP(E_POINTER), { 0, NULL } }; static void warn_on_error(HRESULT hr) { struct dinput_error_pair *pair = dinput_errors; while (pair->text) { if (hr == pair->error) { ALLEGRO_WARN("HRESULT error: %s\n", pair->text); } pair++; } ALLEGRO_WARN("Unknown HRESULT error: %u\n", (unsigned int)hr); } static bool whap_upload_effect_helper (ALLEGRO_HAPTIC_WINDOWS *whap, ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff, ALLEGRO_HAPTIC_EFFECT *effect) { HRESULT ret; if (!whap_effect2win(weff, effect, whap)) { ALLEGRO_WARN("Could not convert haptic effect.\n"); return false; } /* Create the effect. */ ret = IDirectInputDevice8_CreateEffect(whap->device, (*weff->guid), &weff->effect, &weff->ref, NULL); /* XXX Need to re-lock since the joystick driver steals my thunder * by calling Unacquire on the device. * The better way would be to fix this in that driver somehow. */ if (!whap_acquire_lock(whap)) { ALLEGRO_WARN("Could not lock haptic device.\n"); return false; } /* Create the effect. */ ret = IDirectInputDevice8_CreateEffect(whap->device, (*weff->guid), &weff->effect, &weff->ref, NULL); if (FAILED(ret)) { ALLEGRO_WARN("Could not create haptic effect.\n"); warn_on_error(ret); return false; } /* Upload the effect to the device. */ ret = IDirectInputEffect_Download(weff->ref); if (FAILED(ret)) { ALLEGRO_WARN("Could not upload haptic effect.\n"); warn_on_error(ret); return false; } return true; } static bool whap_upload_effect(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *effect, ALLEGRO_HAPTIC_EFFECT_ID *id) { bool ok = FALSE; ALLEGRO_HAPTIC_WINDOWS *whap = whap_from_al(dev); ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff = NULL; ASSERT(dev); ASSERT(id); ASSERT(effect); /* Set id's values to indicate failure beforehand. */ id->_haptic = NULL; id->_id = -1; id->_pointer = NULL; id->_playing = false; id->_effect_duration = 0.0; id->_start_time = 0.0; id->_end_time = 0.0; al_lock_mutex(haptic_mutex); /* Look for a free haptic effect slot. */ weff = whap_get_available_effect(whap); /* Returns NULL if there is no more space for an effect. */ if (weff) { if (whap_upload_effect_helper(whap, weff, effect)) { /* set ID handle to signify success */ id->_haptic = dev; id->_pointer = weff; id->_id = weff->id; id->_effect_duration = al_get_haptic_effect_duration(effect); ok = true; } else { ALLEGRO_WARN("Could not upload effect."); } } else { ALLEGRO_WARN("No free effect slot."); } al_unlock_mutex(haptic_mutex); return ok; } static bool whap_play_effect(ALLEGRO_HAPTIC_EFFECT_ID *id, int loops) { HRESULT res; ALLEGRO_HAPTIC_WINDOWS *whap = (ALLEGRO_HAPTIC_WINDOWS *)id->_haptic; ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff; if ((!whap) || (id->_id < 0)) return false; weff = whap->effects + id->_id; /* Need to re-lock since the joystick driver steals the haptics' thunder * by calling Unacquire on the device. * The better way would be to fix this in that driver somehow. */ if (!whap_acquire_lock(whap)) { ALLEGRO_WARN("Could not lock haptic device \n"); return false; } res = IDirectInputEffect_Start(weff->ref, loops, 0); if (FAILED(res)) { ALLEGRO_WARN("Failed to play an effect."); warn_on_error(res); return false; } id->_playing = true; id->_start_time = al_get_time(); id->_end_time = id->_start_time; id->_end_time += id->_effect_duration * (double)loops; return true; } static bool whap_stop_effect(ALLEGRO_HAPTIC_EFFECT_ID *id) { HRESULT res; ALLEGRO_HAPTIC_WINDOWS *whap = (ALLEGRO_HAPTIC_WINDOWS *)id->_haptic; ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff; if ((!whap) || (id->_id < 0)) return false; weff = whap->effects + id->_id; res = IDirectInputEffect_Stop(weff->ref); if (FAILED(res)) { ALLEGRO_WARN("Failed to play an effect."); return false; } id->_playing = false; return true; } static bool whap_is_effect_playing(ALLEGRO_HAPTIC_EFFECT_ID *id) { ASSERT(id); HRESULT res; DWORD flags = 0; ALLEGRO_HAPTIC_WINDOWS *whap = (ALLEGRO_HAPTIC_WINDOWS *)id->_haptic; ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff; if ((!whap) || (id->_id < 0) || (!id->_playing)) return false; weff = whap->effects + id->_id; res = IDirectInputEffect_GetEffectStatus(weff->ref, &flags); if (FAILED(res)) { ALLEGRO_WARN("Failed to get the status of effect."); /* If we get here, then use the play time in stead to * see if the effect should still be playing. * Do this because in case GeteffectStatus fails, we can't * assume the sample isn't playing. In fact, if the play command * was successful, it should still be playing as long as the play * time has not passed. */ return(al_get_time() < id->_end_time); } if (flags & DIEGES_PLAYING) return true; /* WINE is bugged here, it doesn't set flags, but it also * just returns DI_OK. Thats why here, don't believe the API * when it the playing flag isn't set if the effect's duration * has not passed. On real Windows it should probably always be the * case that the effect will have played completely when * the play time has ended. */ return(al_get_time() < id->_end_time); } static bool whap_release_effect(ALLEGRO_HAPTIC_EFFECT_ID *id) { ALLEGRO_HAPTIC_WINDOWS *whap = (ALLEGRO_HAPTIC_WINDOWS *)id->_haptic; ALLEGRO_HAPTIC_EFFECT_WINDOWS *weff; if ((!whap) || (id->_id < 0)) return false; whap_stop_effect(id); weff = whap->effects + id->_id; return whap_release_effect_windows(weff); } static bool whap_release(ALLEGRO_HAPTIC *haptic) { ALLEGRO_HAPTIC_WINDOWS *whap = whap_from_al(haptic); int index; HRESULT res; ASSERT(haptic); if (!whap->active) return false; /* Release all effects for this device. */ for (index = 0; index < HAPTICS_EFFECTS_MAX; index++) { whap_release_effect_windows(whap->effects + index); } /* Release the acquire lock on the device */ IDirectInputDevice_Unacquire(whap->device); /* Reset the cooperative level to nonexclusive. */ res = IDirectInputDevice_SetCooperativeLevel(whap->device, whap->display->window, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); if (FAILED(res)) { ALLEGRO_WARN ("IDirectInputDevice8_SetCooperativeLevel NONEXCLUSIVE failed for haptic device.\n"); } whap->display = NULL; whap->active = false; whap->device = NULL; return true; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/whapxi.c000066400000000000000000000562631473414355200165240ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows haptic (force-feedback) device driver. * * By Beoran. * * See LICENSE.txt for copyright information. */ #define ALLEGRO_NO_COMPATIBILITY #define DIRECTINPUT_VERSION 0x0800 /* For waitable timers */ #define _WIN32_WINNT 0x0501 #include "allegro5/allegro.h" #include "allegro5/haptic.h" #include "allegro5/internal/aintern.h" #include "allegro5/platform/aintwin.h" #include "allegro5/internal/aintern_haptic.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_bitmap.h" #ifdef ALLEGRO_CFG_XINPUT /* Don't compile this lot if xinput isn't supported. */ #ifndef ALLEGRO_WINDOWS #error something is wrong with the makefile #endif #ifndef ALLEGRO_XINPUT_POLL_DELAY #define ALLEGRO_XINPUT_POLL_DELAY 0.1 #endif #ifdef ALLEGRO_MINGW32 #undef MAKEFOURCC #endif #include #include #include #include #include /* The official DirectX xinput.h uses SAL annotations. * Need the sal.h header to get rid of them. On some other platforms * such as MinGW on Linux this header is lacking because it is not needed there. * So, simply try to include sal.h IF we have it , and if not, hope * for the best. * This does no harm on msys2 either, they have a sal.h header. */ #ifdef ALLEGRO_HAVE_SAL_H #include #endif #include #include "allegro5/internal/aintern_wjoyxi.h" ALLEGRO_DEBUG_CHANNEL("haptic") /* Support at most 4 haptic devices. */ #define HAPTICS_MAX 4 /* Support at most 1 rumble effect per device, because * XInput doesn't really support uploading the effects. */ #define HAPTIC_EFFECTS_MAX 1 /* Enum for the state of a haptic effect. The playback is managed by a small * finite state machine. */ typedef enum ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE { ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_INACTIVE = 0, ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_READY = 1, ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_STARTING = 2, ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_PLAYING = 3, ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_DELAYED = 4, ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_STOPPING = 5, } ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE; /* Allowed state transitions: * from inactive to ready, * from ready to starting * from starting to delayed or playing * from delayed to playing * from playing to delayed (for loops) or stopping * from stopping to ready * from ready to inactive */ typedef struct ALLEGRO_HAPTIC_EFFECT_XINPUT { ALLEGRO_HAPTIC_EFFECT effect; XINPUT_VIBRATION vibration; int id; double start_time; double loop_start; double stop_time; int repeats; int delay_repeated; int play_repeated; ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE state; } ALLEGRO_HAPTIC_EFFECT_XINPUT; typedef struct ALLEGRO_HAPTIC_XINPUT { /* Important, parent must be first. */ ALLEGRO_HAPTIC parent; ALLEGRO_JOYSTICK_XINPUT *xjoy; bool active; ALLEGRO_HAPTIC_EFFECT_XINPUT effect; int flags; /* Only one effect is supported since the XInput API allows only one pair of vibration speeds to be set to the device. */ } ALLEGRO_HAPTIC_XINPUT; /* forward declarations */ static bool hapxi_init_haptic(void); static void hapxi_exit_haptic(void); static bool hapxi_is_mouse_haptic(ALLEGRO_MOUSE *dev); static bool hapxi_is_joystick_haptic(ALLEGRO_JOYSTICK *); static bool hapxi_is_keyboard_haptic(ALLEGRO_KEYBOARD *dev); static bool hapxi_is_display_haptic(ALLEGRO_DISPLAY *dev); static bool hapxi_is_touch_input_haptic(ALLEGRO_TOUCH_INPUT *dev); static ALLEGRO_HAPTIC *hapxi_get_from_mouse(ALLEGRO_MOUSE *dev); static ALLEGRO_HAPTIC *hapxi_get_from_joystick(ALLEGRO_JOYSTICK *dev); static ALLEGRO_HAPTIC *hapxi_get_from_keyboard(ALLEGRO_KEYBOARD *dev); static ALLEGRO_HAPTIC *hapxi_get_from_display(ALLEGRO_DISPLAY *dev); static ALLEGRO_HAPTIC *hapxi_get_from_touch_input(ALLEGRO_TOUCH_INPUT *dev); static bool hapxi_release(ALLEGRO_HAPTIC *haptic); static bool hapxi_get_active(ALLEGRO_HAPTIC *hap); static int hapxi_get_capabilities(ALLEGRO_HAPTIC *dev); static double hapxi_get_gain(ALLEGRO_HAPTIC *dev); static bool hapxi_set_gain(ALLEGRO_HAPTIC *dev, double); static int hapxi_get_max_effects(ALLEGRO_HAPTIC *dev); static bool hapxi_is_effect_ok(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *eff); static bool hapxi_upload_effect(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *eff, ALLEGRO_HAPTIC_EFFECT_ID *id); static bool hapxi_play_effect(ALLEGRO_HAPTIC_EFFECT_ID *id, int loop); static bool hapxi_stop_effect(ALLEGRO_HAPTIC_EFFECT_ID *id); static bool hapxi_is_effect_playing(ALLEGRO_HAPTIC_EFFECT_ID *id); static bool hapxi_release_effect(ALLEGRO_HAPTIC_EFFECT_ID *id); static double hapxi_get_autocenter(ALLEGRO_HAPTIC *dev); static bool hapxi_set_autocenter(ALLEGRO_HAPTIC *dev, double); static void *hapxi_poll_thread(ALLEGRO_THREAD *thread, void *arg); ALLEGRO_HAPTIC_DRIVER _al_hapdrv_xinput = { AL_HAPTIC_TYPE_XINPUT, "", "", "Windows XInput haptic(s)", hapxi_init_haptic, hapxi_exit_haptic, hapxi_is_mouse_haptic, hapxi_is_joystick_haptic, hapxi_is_keyboard_haptic, hapxi_is_display_haptic, hapxi_is_touch_input_haptic, hapxi_get_from_mouse, hapxi_get_from_joystick, hapxi_get_from_keyboard, hapxi_get_from_display, hapxi_get_from_touch_input, hapxi_get_active, hapxi_get_capabilities, hapxi_get_gain, hapxi_set_gain, hapxi_get_max_effects, hapxi_is_effect_ok, hapxi_upload_effect, hapxi_play_effect, hapxi_stop_effect, hapxi_is_effect_playing, hapxi_release_effect, hapxi_release, hapxi_get_autocenter, hapxi_set_autocenter }; static ALLEGRO_HAPTIC_XINPUT haptics[HAPTICS_MAX]; /* For the background thread */ static ALLEGRO_THREAD *hapxi_thread = NULL; static ALLEGRO_MUTEX *hapxi_mutex = NULL; /* Use a condition variable to put the thread to sleep and prevent too frequent polling. */ static ALLEGRO_COND *hapxi_cond = NULL; typedef DWORD(WINAPI *XInputSetStatePROC)(DWORD, XINPUT_VIBRATION*); extern XInputSetStatePROC _al_imp_XInputSetState; /* Forces vibration to stop immediately. */ static bool hapxi_force_stop(ALLEGRO_HAPTIC_XINPUT *hapxi, ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi) { XINPUT_VIBRATION no_vibration = { 0, 0 }; ALLEGRO_DEBUG("XInput haptic effect stopped.\n"); _al_imp_XInputSetState(hapxi->xjoy->index, &no_vibration); effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_READY; return true; } /* starts vibration immediately. If successfully also sets playing */ static bool hapxi_force_play(ALLEGRO_HAPTIC_XINPUT *hapxi, ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi) { DWORD res; res = _al_imp_XInputSetState(hapxi->xjoy->index, &effxi->vibration); ALLEGRO_DEBUG("Starting to play back haptic effect: %d.\n", (int)(res)); if (res == ERROR_SUCCESS) { effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_PLAYING; return true; } else { effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_READY; return false; } } static bool hapxi_poll_haptic_effect_ready(ALLEGRO_HAPTIC_XINPUT *hapxi, ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi) { (void)hapxi; (void)effxi; /* when ready do nothing */ return true; } static bool hapxi_poll_haptic_effect_starting(ALLEGRO_HAPTIC_XINPUT *hapxi, ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi) { /* when starting switch to delayed mode or play mode */ double now = al_get_time(); if ((now - effxi->start_time) < effxi->effect.replay.delay) { effxi->loop_start = al_get_time(); effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_DELAYED; } else { hapxi_force_play(hapxi, effxi); } ALLEGRO_DEBUG("Polling XInput haptic effect. Really Starting: %d!\n", effxi->state); return true; } static bool hapxi_poll_haptic_effect_playing(ALLEGRO_HAPTIC_XINPUT *hapxi, ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi) { double now = al_get_time(); double stop = effxi->loop_start + effxi->effect.replay.delay + effxi->effect.replay.length; (void)hapxi; if (now > stop) { /* may need to repeat play because of "loop" in playback. */ effxi->play_repeated++; if (effxi->play_repeated < effxi->repeats) { /* need to play another loop. Stop playing now. */ hapxi_force_stop(hapxi, effxi); effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_DELAYED; effxi->loop_start = al_get_time(); } else { effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_STOPPING; } return true; } return false; } static bool hapxi_poll_haptic_effect_delayed(ALLEGRO_HAPTIC_XINPUT *hapxi, ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi) { double now = al_get_time(); if (now > (effxi->loop_start + effxi->effect.replay.delay)) { return hapxi_force_play(hapxi, effxi); } return false; } static bool hapxi_poll_haptic_effect_stopping(ALLEGRO_HAPTIC_XINPUT *hapxi, ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi) { /* when stopping, force stop and go to ready state (hapxi_force_stop does this)*/ return hapxi_force_stop(hapxi, effxi); } /* Polls the xinput API for a single haptic device and effect. */ static bool hapxi_poll_haptic_effect(ALLEGRO_HAPTIC_XINPUT *hapxi, ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi) { /* Check the state of the effect. */ switch (effxi->state) { case ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_INACTIVE: return false; case ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_READY: return hapxi_poll_haptic_effect_ready(hapxi, effxi); case ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_STARTING: return hapxi_poll_haptic_effect_starting(hapxi, effxi); case ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_PLAYING: return hapxi_poll_haptic_effect_playing(hapxi, effxi); case ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_DELAYED: return hapxi_poll_haptic_effect_delayed(hapxi, effxi); case ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_STOPPING: return hapxi_poll_haptic_effect_stopping(hapxi, effxi); default: ALLEGRO_DEBUG("XInput haptic effect state not valid :%d.\n", effxi->state); return false; } } /* Polls the xinput API for a single haptic device. */ static void hapxi_poll_haptic(ALLEGRO_HAPTIC_XINPUT *hapxi) { hapxi_poll_haptic_effect(hapxi, &hapxi->effect); } /* Polls the xinput API for hapxi effect and starts * or stops playback when needed. */ static void hapxi_poll_haptics(void) { int i; for (i = 0; i < HAPTICS_MAX; i++) { if (haptics[i].active) { hapxi_poll_haptic(haptics + i); } } } /* Function for the haptics polling thread. */ static void *hapxi_poll_thread(ALLEGRO_THREAD *thread, void *arg) { ALLEGRO_TIMEOUT timeout; al_lock_mutex(hapxi_mutex); while (!al_get_thread_should_stop(thread)) { /* Poll once every 10 milliseconds. XXX: Should this be configurable? */ al_init_timeout(&timeout, ALLEGRO_XINPUT_POLL_DELAY); /* Wait for the condition to allow the polling thread to be awoken when needed. */ al_wait_cond_until(hapxi_cond, hapxi_mutex, &timeout); /* If we get here poll joystick for new input or connection * and dispatch events. */ hapxi_poll_haptics(); } al_unlock_mutex(hapxi_mutex); return arg; } /* Initializes the XInput haptic system. */ static bool hapxi_init_haptic(void) { int i; ASSERT(hapxi_mutex == NULL); ASSERT(hapxi_thread == NULL); ASSERT(hapxi_cond == NULL); /* Create the mutex and a condition vaiable. */ hapxi_mutex = al_create_mutex_recursive(); if (!hapxi_mutex) return false; hapxi_cond = al_create_cond(); if (!hapxi_cond) return false; al_lock_mutex(hapxi_mutex); for (i = 0; i < HAPTICS_MAX; i++) { haptics[i].active = false; } /* Now start a polling background thread, since XInput is a polled API, and also to make it possible for effects to stop running when their duration has passed. */ hapxi_thread = al_create_thread(hapxi_poll_thread, NULL); al_unlock_mutex(hapxi_mutex); if (hapxi_thread) al_start_thread(hapxi_thread); return(hapxi_thread != NULL); } /* Converts a generic haptic device to a Windows-specific one. */ static ALLEGRO_HAPTIC_XINPUT *hapxi_from_al(ALLEGRO_HAPTIC *hap) { return (ALLEGRO_HAPTIC_XINPUT *)hap; } static void hapxi_exit_haptic(void) { void *ret_value; ASSERT(hapxi_thread); ASSERT(hapxi_mutex); ASSERT(hapxi_cond); /* Request the event thread to shut down, signal the condition, then join the thread. */ al_set_thread_should_stop(hapxi_thread); al_signal_cond(hapxi_cond); al_join_thread(hapxi_thread, &ret_value); /* clean it all up. */ al_destroy_thread(hapxi_thread); al_destroy_cond(hapxi_cond); al_destroy_mutex(hapxi_mutex); hapxi_mutex = NULL; } /* Converts a float to a unsigned WORD range */ static bool hapxi_magnitude2win(WORD *word, double value) { if (!word) return false; (*word) = (WORD)(65535 * value); return true; } /* Converts Allegro haptic effect to xinput API. */ static bool hapxi_effect2win( ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi, ALLEGRO_HAPTIC_EFFECT *effect, ALLEGRO_HAPTIC_XINPUT *hapxi) { (void)hapxi; /* Generic setup */ if (effect->type != ALLEGRO_HAPTIC_RUMBLE) return false; /* Right motor is "weaker" than left one, That is, right produces a less violent vibration than left. */ return hapxi_magnitude2win(&effxi->vibration.wRightMotorSpeed, effect->data.rumble.weak_magnitude) && hapxi_magnitude2win(&effxi->vibration.wLeftMotorSpeed, effect->data.rumble.strong_magnitude); } static bool hapxi_get_active(ALLEGRO_HAPTIC *haptic) { ALLEGRO_HAPTIC_XINPUT *hapxi = hapxi_from_al(haptic); return hapxi->active; } static bool hapxi_is_mouse_haptic(ALLEGRO_MOUSE *mouse) { (void)mouse; return false; } static bool hapxi_is_joystick_haptic(ALLEGRO_JOYSTICK *joy) { ALLEGRO_JOYSTICK_XINPUT *joyxi = (ALLEGRO_JOYSTICK_XINPUT *)joy; if (!al_is_joystick_installed()) return false; if (!al_get_joystick_active(joy)) return false; /* IF this flag is not supported, then it means we're compiling against an older XInput library. In this case, the Flags are inoperable, and force feedback must be assumed to be always available. */ #ifndef XINPUT_CAPS_FFB_SUPPORTED (void)joyxi; ALLEGRO_DEBUG("Compiled against older XInput library, assuming force feedback support is available.\n"); return true; #else ALLEGRO_DEBUG("joyxi->capabilities.Flags: %d <-> %d\n", joyxi->capabilities.Flags, XINPUT_CAPS_FFB_SUPPORTED); return(joyxi->capabilities.Flags & XINPUT_CAPS_FFB_SUPPORTED); #endif } static bool hapxi_is_display_haptic(ALLEGRO_DISPLAY *dev) { (void)dev; return false; } static bool hapxi_is_keyboard_haptic(ALLEGRO_KEYBOARD *dev) { (void)dev; return false; } static bool hapxi_is_touch_input_haptic(ALLEGRO_TOUCH_INPUT *dev) { (void)dev; return false; } static ALLEGRO_HAPTIC *hapxi_get_from_mouse(ALLEGRO_MOUSE *mouse) { (void)mouse; return NULL; } static ALLEGRO_HAPTIC *hapxi_get_from_joystick(ALLEGRO_JOYSTICK *joy) { ALLEGRO_JOYSTICK_XINPUT *joyxi = (ALLEGRO_JOYSTICK_XINPUT *)joy; ALLEGRO_HAPTIC_XINPUT *hapxi; if (!al_is_joystick_haptic(joy)) return NULL; al_lock_mutex(hapxi_mutex); hapxi = haptics + joyxi->index; hapxi->parent.driver = &_al_hapdrv_xinput; hapxi->parent.device = joyxi; hapxi->parent.from = _AL_HAPTIC_FROM_JOYSTICK; hapxi->active = true; hapxi->effect.state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_INACTIVE; /* not in use */ hapxi->parent.gain = 1.0; hapxi->parent.autocenter = 0.0; hapxi->flags = ALLEGRO_HAPTIC_RUMBLE; hapxi->xjoy = joyxi; al_unlock_mutex(hapxi_mutex); return &hapxi->parent; } static ALLEGRO_HAPTIC *hapxi_get_from_display(ALLEGRO_DISPLAY *dev) { (void)dev; return NULL; } static ALLEGRO_HAPTIC *hapxi_get_from_keyboard(ALLEGRO_KEYBOARD *dev) { (void)dev; return NULL; } static ALLEGRO_HAPTIC *hapxi_get_from_touch_input(ALLEGRO_TOUCH_INPUT *dev) { (void)dev; return NULL; } static int hapxi_get_capabilities(ALLEGRO_HAPTIC *dev) { ALLEGRO_HAPTIC_XINPUT *hapxi = hapxi_from_al(dev); return hapxi->flags; } static double hapxi_get_gain(ALLEGRO_HAPTIC *dev) { (void)dev; /* Just return the 1.0, gain isn't supported */ return 1.0; } static bool hapxi_set_gain(ALLEGRO_HAPTIC *dev, double gain) { (void)dev; (void)gain; /* Gain not supported*/ return false; } double hapxi_get_autocenter(ALLEGRO_HAPTIC *dev) { (void)dev; /* Autocenter not supported so return 0.0. */ return 0.0; } static bool hapxi_set_autocenter(ALLEGRO_HAPTIC *dev, double intensity) { (void)dev; (void)intensity; /* Autocenter not supported*/ return false; } static int hapxi_get_max_effects(ALLEGRO_HAPTIC *dev) { (void)dev; /* Support only one effect */ return 1; } static bool hapxi_is_effect_ok(ALLEGRO_HAPTIC *haptic, ALLEGRO_HAPTIC_EFFECT *effect) { int caps; caps = al_get_haptic_capabilities(haptic); if (caps & effect->type) { return true; } return false; } /* Gets an available haptic effect slot from the device or NULL if not * available. */ static ALLEGRO_HAPTIC_EFFECT_XINPUT * hapxi_get_available_effect(ALLEGRO_HAPTIC_XINPUT *hapxi) { if (hapxi->effect.state == ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_INACTIVE) { /* Set up ID here. */ hapxi->effect.id = 0; return &hapxi->effect; } return NULL; } static bool hapxi_release_effect_windows(ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi) { effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_INACTIVE; return true; } static bool hapxi_upload_effect(ALLEGRO_HAPTIC *dev, ALLEGRO_HAPTIC_EFFECT *effect, ALLEGRO_HAPTIC_EFFECT_ID *id) { ALLEGRO_HAPTIC_XINPUT *hapxi = hapxi_from_al(dev); ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi = NULL; ASSERT(dev); ASSERT(id); ASSERT(effect); /* Set id's values to indicate failure beforehand. */ id->_haptic = NULL; id->_id = -1; id->_pointer = NULL; id->_playing = false; id->_effect_duration = 0.0; id->_start_time = 0.0; id->_end_time = 0.0; if (!al_is_haptic_effect_ok(dev, effect)) return false; al_lock_mutex(hapxi_mutex); /* Is a haptic effect slot available? */ effxi = hapxi_get_available_effect(hapxi); /* No more space for an effect. */ if (!effxi) { ALLEGRO_WARN("No free effect slot."); al_unlock_mutex(hapxi_mutex); return false; } if (!hapxi_effect2win(effxi, effect, hapxi)) { ALLEGRO_WARN("Cannot convert haptic effect to XINPUT effect.\n"); al_unlock_mutex(hapxi_mutex); return false; } effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_READY; effxi->effect = (*effect); /* set ID handle to signify success */ id->_haptic = dev; id->_pointer = effxi; id->_id = effxi->id; id->_effect_duration = al_get_haptic_effect_duration(effect); al_unlock_mutex(hapxi_mutex); return true; } static ALLEGRO_HAPTIC_XINPUT * hapxi_device_for_id(ALLEGRO_HAPTIC_EFFECT_ID *id) { return (ALLEGRO_HAPTIC_XINPUT *)id->_haptic; } static ALLEGRO_HAPTIC_EFFECT_XINPUT * hapxi_effect_for_id(ALLEGRO_HAPTIC_EFFECT_ID *id) { return (ALLEGRO_HAPTIC_EFFECT_XINPUT *)id->_pointer; } static bool hapxi_play_effect(ALLEGRO_HAPTIC_EFFECT_ID *id, int loops) { ALLEGRO_HAPTIC_XINPUT *hapxi = hapxi_device_for_id(id); ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi = hapxi_effect_for_id(id); if ((!hapxi) || (id->_id < 0) || (!effxi) || (loops < 1)) return false; al_lock_mutex(hapxi_mutex); /* Simply set some flags. The polling thread will see this and start playing. after the effect's delay has passed. */ effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_STARTING; effxi->start_time = al_get_time(); effxi->stop_time = effxi->start_time + al_get_haptic_effect_duration(&effxi->effect) * loops; effxi->repeats = loops; effxi->play_repeated = 0; effxi->loop_start = effxi->start_time; id->_playing = true; id->_start_time = al_get_time(); id->_start_time = effxi->start_time; id->_end_time = effxi->stop_time; al_unlock_mutex(hapxi_mutex); al_signal_cond(hapxi_cond); return true; } static bool hapxi_stop_effect(ALLEGRO_HAPTIC_EFFECT_ID *id) { ALLEGRO_HAPTIC_XINPUT *hapxi = hapxi_device_for_id(id); ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi = hapxi_effect_for_id(id); if ((!hapxi) || (id->_id < 0)) return false; /* Simply set some flags. The polling thread will see this and stop playing.*/ effxi = (ALLEGRO_HAPTIC_EFFECT_XINPUT *)id->_pointer; if (effxi->state <= ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_READY) return false; al_lock_mutex(hapxi_mutex); effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_STOPPING; id->_playing = false; al_unlock_mutex(hapxi_mutex); al_signal_cond(hapxi_cond); return true; } static bool hapxi_is_effect_playing(ALLEGRO_HAPTIC_EFFECT_ID *id) { ALLEGRO_HAPTIC_XINPUT *hapxi; ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi; bool result; ASSERT(id); hapxi = hapxi_device_for_id(id); effxi = hapxi_effect_for_id(id); if ((!hapxi) || (id->_id < 0) || (!id->_playing)) return false; al_lock_mutex(hapxi_mutex); ALLEGRO_DEBUG("Playing effect state: %d %p %lf %lf\n", effxi->state, effxi, al_get_time(), id->_end_time); result = (effxi->state > ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_READY); al_unlock_mutex(hapxi_mutex); al_signal_cond(hapxi_cond); return result; } static bool hapxi_release_effect(ALLEGRO_HAPTIC_EFFECT_ID *id) { ALLEGRO_HAPTIC_XINPUT *hapxi = hapxi_device_for_id(id); ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi = hapxi_effect_for_id(id); bool result; if ((!hapxi) || (!effxi)) return false; al_lock_mutex(hapxi_mutex); /* Forcefully stop since a normal stop may not be instant. */ hapxi_force_stop(hapxi, effxi); effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_INACTIVE; result = hapxi_release_effect_windows(effxi); al_unlock_mutex(hapxi_mutex); return result; } static bool hapxi_release(ALLEGRO_HAPTIC *haptic) { ALLEGRO_HAPTIC_XINPUT *hapxi = hapxi_from_al(haptic); ASSERT(haptic); if (!hapxi->active) return false; al_lock_mutex(hapxi_mutex); /* Release the effect for this device. */ /* Forcefully stop since a normal stop may not be instant. */ hapxi_force_stop(hapxi, &hapxi->effect); hapxi_release_effect_windows(&hapxi->effect); hapxi->active = false; hapxi->parent.device = NULL; al_unlock_mutex(hapxi_mutex); return true; } #endif /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/wjoyall.c000066400000000000000000000155111473414355200166740ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows wrap-all joystick driver. * By Beoran. * See readme.txt for copyright information. * * This driver exists because on Windows, DirectInput and XInput are two * different joystick input APIs which bith need to be supported simultaneously. * * Although DirectInput is deprecated, it is a far more capable API in terms * of joystick layout and force feedback effects. XInput is a much simpler * API but it only supports joysticks that have a layout similar to that of an * XBOX controller. XInput also has very limited force feedback effects, * it only supportd rubmble style vibrations. * * Older joystics or input devices such as steering wheels that do not map * cleanly to an XBOX controller tend to have DirectInput drivers available, * while more recent joypads tend to have a XInput driver available. In theory * XInput devices also support DirectInput, and some devices even have a switch * that lets the user select the API. But XInput devices only partially support * DirectInput. In particular, XInput devices do not support force feedback when * using DirectInput to access them. * * For all these reasons, both directinput and xinput drivers should be * supported on Windows to allow greates comfort to end users. * The wjoyall.c and whapall.c drivers are wrapper drivers that combine * the Allegro XInput and DirectInput drivers into a single driver. * For this reason, the same joystick ormay show up twice * in the joystick list. However, XInput devices will appear before DirectInput * devices in the list, so when in doubt, use the joystick with the lowest ID. * */ #define ALLEGRO_NO_COMPATIBILITY /* For waitable timers */ #define _WIN32_WINNT 0x0501 #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/platform/aintwin.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_bitmap.h" #ifdef ALLEGRO_CFG_XINPUT /* Don't compile this lot if xinput isn't supported. */ #ifndef ALLEGRO_WINDOWS #error something is wrong with the makefile #endif #ifdef ALLEGRO_MINGW32 #undef MAKEFOURCC #endif #include ALLEGRO_DEBUG_CHANNEL("wjoyall") #include "allegro5/joystick.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_wjoyall.h" /* forward declarations */ static bool joyall_init_joystick(void); static void joyall_exit_joystick(void); static bool joyall_reconfigure_joysticks(void); static int joyall_get_num_joysticks(void); static ALLEGRO_JOYSTICK *joyall_get_joystick(int num); static void joyall_release_joystick(ALLEGRO_JOYSTICK *joy); static void joyall_get_joystick_state(ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state); static const char *joyall_get_name(ALLEGRO_JOYSTICK *joy); static bool joyall_get_active(ALLEGRO_JOYSTICK *joy); /* the driver vtable */ ALLEGRO_JOYSTICK_DRIVER _al_joydrv_windows_all = { AL_JOY_TYPE_WINDOWS_ALL, "", "", "Windows Joystick", joyall_init_joystick, joyall_exit_joystick, joyall_reconfigure_joysticks, joyall_get_num_joysticks, joyall_get_joystick, joyall_release_joystick, joyall_get_joystick_state, joyall_get_name, joyall_get_active }; /* Mutex to protect state access. XXX is this needed? */ static ALLEGRO_MUTEX *joyall_mutex = NULL; static bool ok_xi = false; static bool ok_di = false; /* Sets up all joysticks from the two wrapped apis. */ static void joyall_setup_joysticks(void) { int index; int num_xinput = 0; int num_dinput = 0; if (ok_di) num_dinput = _al_joydrv_directx.num_joysticks(); if (ok_xi) num_xinput = _al_joydrv_xinput.num_joysticks(); for (index = 0; index < num_xinput; index++) { ALLEGRO_JOYSTICK *joystick = _al_joydrv_xinput.get_joystick(index); joystick->driver = &_al_joydrv_xinput; } for (index = 0; index < num_dinput; index++) { ALLEGRO_JOYSTICK *joystick = _al_joydrv_directx.get_joystick(index); joystick->driver = &_al_joydrv_directx; } } /* Initialization API function. */ static bool joyall_init_joystick(void) { /* Create the mutex and a condition vaiable. */ joyall_mutex = al_create_mutex_recursive(); if (!joyall_mutex) return false; al_lock_mutex(joyall_mutex); ok_xi = _al_joydrv_xinput.init_joystick(); ok_di = _al_joydrv_directx.init_joystick(); joyall_setup_joysticks(); al_unlock_mutex(joyall_mutex); return ok_xi || ok_di; } static void joyall_exit_joystick(void) { al_lock_mutex(joyall_mutex); _al_joydrv_xinput.exit_joystick(); _al_joydrv_directx.exit_joystick(); al_unlock_mutex(joyall_mutex); al_destroy_mutex(joyall_mutex); } static bool joyall_reconfigure_joysticks(void) { al_lock_mutex(joyall_mutex); if (ok_xi) _al_joydrv_xinput.reconfigure_joysticks(); if (ok_di) _al_joydrv_directx.reconfigure_joysticks(); joyall_setup_joysticks(); al_unlock_mutex(joyall_mutex); return true; } static int joyall_get_num_joysticks(void) { int ret = 0; if (ok_xi) ret += _al_joydrv_xinput.num_joysticks(); if (ok_di) ret += _al_joydrv_directx.num_joysticks(); return ret; } static ALLEGRO_JOYSTICK *joyall_get_joystick(int num) { int num_xinput = 0; int num_dinput = 0; if (ok_di) num_dinput = _al_joydrv_directx.num_joysticks(); if (ok_xi) num_xinput = _al_joydrv_xinput.num_joysticks(); if (num < 0) return NULL; /* Shift the joystick number to fit the range of each of the subdrivers */ if (num < num_xinput) { return _al_joydrv_xinput.get_joystick(num); } else if (num < (num_xinput + num_dinput)) { return _al_joydrv_directx.get_joystick(num - num_xinput); } return NULL; } static void joyall_release_joystick(ALLEGRO_JOYSTICK *joy) { /* Forward to the driver's function. Here it's OK to use joy * since the get_joystick function returns a * pointer to the real underlying driver-specific joystick data. */ if (joy) { joy->driver->release_joystick(joy); } } static void joyall_get_joystick_state(ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state) { joy->driver->get_joystick_state(joy, ret_state); } static const char *joyall_get_name(ALLEGRO_JOYSTICK *joy) { return joy->driver->get_name(joy); } static bool joyall_get_active(ALLEGRO_JOYSTICK *joy) { return joy->driver->get_active(joy); } #endif /* #ifdef ALLEGRO_CFG_XINPUT */ allegro5-5.2.10.1/src/win/wjoydrv.c000066400000000000000000000020671473414355200167210ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * List of Windows joystick drivers, kept in a seperate file so that * they can be overriden by user programs. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_joystick.h" #ifndef ALLEGRO_WINDOWS #error something is wrong with the makefile #endif _AL_BEGIN_JOYSTICK_DRIVER_LIST _AL_JOYSTICK_DRIVER_DIRECTX #ifdef ALLEGRO_CFG_XINPUT _AL_JOYSTICK_DRIVER_XINPUT _AL_JOYSTICK_DRIVER_WINDOWS_ALL #endif _AL_END_JOYSTICK_DRIVER_LIST allegro5-5.2.10.1/src/win/wjoydxnu.cpp000066400000000000000000001510201473414355200174360ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows DirectInput joystick driver. * * By Eric Botcazou. * * Omar Cornut fixed it to handle a weird peculiarity of * the DirectInput joystick API. * * Modified extensively for the new joystick API by Peter Wang. * * See readme.txt for copyright information. */ /* * Driver operation: * * 1. When the driver is initialised all the joysticks on the system * are enumerated. For each joystick, an ALLEGRO_JOYSTICK_DIRECTX structure * is created. A win32 Event is also created for each joystick and DirectInput * is told to set that event whenever the joystick state changes. For some * devices this is not possible -- they must be polled. In that case, a * Waitable Timer object is used instead of a win32 Event. Once all the * joysticks are set up, a dedicated background thread is started. * * 2. When al_get_joystick() is called the address of one of the * ALLEGRO_JOYSTICK_DIRECTX structures is returned to the user. * * 3. The background thread waits upon the win32 Events/Waitable Timer * objects. When one of them is triggered, the thread wakes up and * reads in buffered joystick events. An internal ALLEGRO_JOYSTICK_STATE * structure (part of ALLEGRO_JOYSTICK_DIRECTX) is updated accordingly. * Also, any Allegro events are generated if necessary. * * 4. When the user calls al_get_joystick_state() the contents of the * internal ALLEGRO_JOYSTICK_STATE structure are copied to a user * ALLEGRO_JOYSTICK_STATE structure. * * 5. Every second or so, all the joysticks on the system are enumerated again. * We compare the GUIDs of the enumerated joysticks with the existing * ALLEGRO_JOYSTICK structures to tell if any new joysticks have been connected, * or old ones disconnected. */ #define ALLEGRO_NO_COMPATIBILITY #define DIRECTINPUT_VERSION 0x0800 /* For waitable timers */ #define _WIN32_WINNT 0x0501 #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/platform/aintwin.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_bitmap.h" #ifndef ALLEGRO_WINDOWS #error something is wrong with the makefile #endif #ifdef ALLEGRO_MINGW32 #undef MAKEFOURCC #endif #include #include #include #include /* We need XInput detection if we actually compile the XInput driver in. */ #ifdef ALLEGRO_CFG_XINPUT /* Windows XP is required. If you still use older Windows, XInput won't work anyway. */ #undef WIN32_LEAN_AND_MEAN #include #include #define ALLEGRO_DINPUT_FILTER_XINPUT #endif ALLEGRO_DEBUG_CHANNEL("dinput") #include "allegro5/joystick.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_wjoydxnu.h" #include "allegro5/internal/aintern_wunicode.h" /* forward declarations */ static bool joydx_init_joystick(void); static void joydx_exit_joystick(void); static bool joydx_reconfigure_joysticks(void); static int joydx_get_num_joysticks(void); static ALLEGRO_JOYSTICK *joydx_get_joystick(int num); static void joydx_release_joystick(ALLEGRO_JOYSTICK *joy); static void joydx_get_joystick_state(ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state); static const char *joydx_get_name(ALLEGRO_JOYSTICK *joy); static bool joydx_get_active(ALLEGRO_JOYSTICK *joy); static void joydx_inactivate_joy(ALLEGRO_JOYSTICK_DIRECTX *joy); static unsigned __stdcall joydx_thread_proc(LPVOID unused); static void update_joystick(ALLEGRO_JOYSTICK_DIRECTX *joy); static void handle_axis_event(ALLEGRO_JOYSTICK_DIRECTX *joy, const AXIS_MAPPING *axis_mapping, DWORD value); static void handle_pov_event(ALLEGRO_JOYSTICK_DIRECTX *joy, int stick, DWORD value); static void handle_button_event(ALLEGRO_JOYSTICK_DIRECTX *joy, int button, bool down); static void generate_axis_event(ALLEGRO_JOYSTICK_DIRECTX *joy, int stick, int axis, float pos); static void generate_button_event(ALLEGRO_JOYSTICK_DIRECTX *joy, int button, ALLEGRO_EVENT_TYPE event_type); /* the driver vtable */ ALLEGRO_JOYSTICK_DRIVER _al_joydrv_directx = { AL_JOY_TYPE_DIRECTX, "", "", "DirectInput joystick", joydx_init_joystick, joydx_exit_joystick, joydx_reconfigure_joysticks, joydx_get_num_joysticks, joydx_get_joystick, joydx_release_joystick, joydx_get_joystick_state, joydx_get_name, joydx_get_active }; /* GUID values are borrowed from Wine */ #define DEFINE_PRIVATE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ static const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } DEFINE_PRIVATE_GUID(__al_GUID_XAxis, 0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); DEFINE_PRIVATE_GUID(__al_GUID_YAxis, 0xA36D02E1,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); DEFINE_PRIVATE_GUID(__al_GUID_ZAxis, 0xA36D02E2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); DEFINE_PRIVATE_GUID(__al_GUID_RxAxis,0xA36D02F4,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); DEFINE_PRIVATE_GUID(__al_GUID_RyAxis,0xA36D02F5,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); DEFINE_PRIVATE_GUID(__al_GUID_RzAxis,0xA36D02E3,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); DEFINE_PRIVATE_GUID(__al_GUID_Slider,0xA36D02E4,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); DEFINE_PRIVATE_GUID(__al_GUID_Button,0xA36D02F0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); DEFINE_PRIVATE_GUID(__al_GUID_POV, 0xA36D02F2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); DEFINE_PRIVATE_GUID(__al_IID_IDirectInput8W, 0xBF798031,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00); DEFINE_PRIVATE_GUID(__al_IID_IDirectInput8A, 0xBF798030,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00); DEFINE_PRIVATE_GUID(__al_IID_IDirectInputDevice8A,0x54D41080,0xDC15,0x4833,0xA4,0x1B,0x74,0x8F,0x73,0xA3,0x81,0x79); DEFINE_PRIVATE_GUID(__al_IID_IDirectInputDevice8W,0x54D41081,0xDC15,0x4833,0xA4,0x1B,0x74,0x8F,0x73,0xA3,0x81,0x79); #ifdef UNICODE #define __al_IID_IDirectInput8 __al_IID_IDirectInput8W #define __al_IID_IDirectInputDevice8 __al_IID_IDirectInputDevice8W #else #define __al_IID_IDirectInput __al_IID_IDirectInput8A #define __al_IID_IDirectInputDevice __al_IID_IDirectInputDevice8A #endif /* definition of DirectInput Joystick was borrowed from Wine implementation */ #define DIDFT_AXIS 0x00000003 #define DIDFT_ANYINSTANCE 0x00FFFF00 #define DIDFT_OPTIONAL 0x80000000 static const DIOBJECTDATAFORMAT __al_dfDIJoystick[] = { { &__al_GUID_XAxis, DIJOFS_X, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0}, { &__al_GUID_YAxis, DIJOFS_Y, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0}, { &__al_GUID_ZAxis, DIJOFS_Z, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0}, { &__al_GUID_RxAxis, DIJOFS_RX, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0}, { &__al_GUID_RyAxis, DIJOFS_RY, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0}, { &__al_GUID_RzAxis, DIJOFS_RZ, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0}, { &__al_GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0}, { &__al_GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0}, { &__al_GUID_POV, DIJOFS_POV(0), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0}, { &__al_GUID_POV, DIJOFS_POV(1), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0}, { &__al_GUID_POV, DIJOFS_POV(2), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0}, { &__al_GUID_POV, DIJOFS_POV(3), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(0), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(1), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(2), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(3), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(4), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(5), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(6), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(7), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(8), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(9), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(10), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(11), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(12), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(13), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(14), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(15), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(16), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(17), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(18), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(19), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(20), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(21), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(22), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(23), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(24), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(25), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(26), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(27), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(28), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(29), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(30), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, { NULL, DIJOFS_BUTTON(31), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0}, }; static const DIDATAFORMAT __al_c_dfDIJoystick = { sizeof(DIDATAFORMAT), sizeof(DIOBJECTDATAFORMAT), DIDF_ABSAXIS, sizeof(DIJOYSTATE), sizeof(__al_dfDIJoystick) / sizeof(*__al_dfDIJoystick), (LPDIOBJECTDATAFORMAT)__al_dfDIJoystick }; /* end of Wine code */ /* DirectInput creation prototype */ typedef HRESULT (WINAPI *DIRECTINPUT8CREATEPROC)(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID * ppvOut, LPUNKNOWN punkOuter); /* DirectInput module name */ static const char* _al_dinput_module_name = "dinput8.dll"; /* DirecInput module handle */ static HMODULE _al_dinput_module = NULL; /* DirectInput creation procedure */ static DIRECTINPUT8CREATEPROC _al_dinput_create = (DIRECTINPUT8CREATEPROC)NULL; /* a handle to the DirectInput interface */ static LPDIRECTINPUT joystick_dinput = NULL; /* last display which acquired the devices */ static ALLEGRO_DISPLAY_WIN *win_disp; /* number of joysticks visible to user */ static int joydx_num_joysticks; /* the joystick structures */ static ALLEGRO_JOYSTICK_DIRECTX joydx_joystick[MAX_JOYSTICKS]; /* for the background thread */ static HANDLE joydx_thread = NULL; static CRITICAL_SECTION joydx_thread_cs; /* whether the DirectInput devices need to be enumerated again */ static bool need_device_enumeration = false; /* whether the user should call al_reconfigure_joysticks */ static bool config_needs_merging = false; /* An array of objects that are to wake the background thread when * something interesting happens. The first handle is for thread * termination. The rest point to joydx_joystick[i].waker_event values, * for each active joystick. joydx_joystick[i].waker_event is NOT * necessarily at JOYSTICK_WAKER(i). */ static HANDLE joydx_thread_wakers[1+MAX_JOYSTICKS]; #define STOP_EVENT (joydx_thread_wakers[0]) #define JOYSTICK_WAKER(n) (joydx_thread_wakers[1+(n)]) /* names for things in case DirectInput doesn't provide them */ static char default_name_x[] = "X"; static char default_name_y[] = "Y"; static char default_name_z[] = "Z"; static char default_name_rx[] = "RX"; static char default_name_ry[] = "RY"; static char default_name_rz[] = "RZ"; static char default_name_stick[] = "stick"; static char default_name_slider[] = "slider"; static char default_name_hat[] = "hat"; static const char *default_name_button[MAX_BUTTONS] = { "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "B10", "B11", "B12", "B13", "B14", "B15", "B16", "B17", "B18", "B19", "B20", "B21", "B22", "B23", "B24", "B25", "B26", "B27", "B28", "B29", "B30", "B31", "B32" }; #define JOY_POVFORWARD_WRAP 36000 /* Returns a pointer to a static buffer, for debugging. */ static char *guid_to_string(const GUID * guid) { static char buf[200]; sprintf(buf, "%lx-%x-%x-%x%x%x%x%x%x%x%x", guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] ); return buf; } /* Returns a pointer to a static buffer, for debugging. */ static char *joydx_guid_string(ALLEGRO_JOYSTICK_DIRECTX *joy) { return guid_to_string((const GUID *)&joy->guid); } /* dinput_err_str: * Returns a DirectInput error string. */ #ifdef DEBUGMODE static char* dinput_err_str(long err) { static char err_str[64]; switch (err) { case DIERR_ACQUIRED: _al_sane_strncpy(err_str, "the device is acquired", sizeof(err_str)); break; case DIERR_NOTACQUIRED: _al_sane_strncpy(err_str, "the device is not acquired", sizeof(err_str)); break; case DIERR_INPUTLOST: _al_sane_strncpy(err_str, "access to the device was not granted", sizeof(err_str)); break; case DIERR_INVALIDPARAM: _al_sane_strncpy(err_str, "the device does not have a selected data format", sizeof(err_str)); break; case DIERR_OTHERAPPHASPRIO: _al_sane_strncpy(err_str, "can't acquire the device in background", sizeof(err_str)); break; default: _al_sane_strncpy(err_str, "unknown error", sizeof(err_str)); } return err_str; } #else #define dinput_err_str(hr) "\0" #endif /* _al_win_joystick_dinput_acquire: [window thread] * Acquires the joystick devices. */ static void joystick_dinput_acquire(void) { HRESULT hr; int i; if (!joystick_dinput) return; for (i=0; i < MAX_JOYSTICKS; i++) { if (joydx_joystick[i].device) { hr = IDirectInputDevice8_Acquire(joydx_joystick[i].device); if (FAILED(hr)) ALLEGRO_ERROR("acquire joystick %d failed: %s\n", i, dinput_err_str(hr)); } } } /* _al_win_joystick_dinput_trigger_enumeration: [window thread] * Let joydx_thread_proc() know to reenumerate joysticks. */ void _al_win_joystick_dinput_trigger_enumeration(void) { if (!joystick_dinput) return; EnterCriticalSection(&joydx_thread_cs); need_device_enumeration = true; LeaveCriticalSection(&joydx_thread_cs); } /* _al_win_joystick_dinput_unacquire: [window thread] * Unacquires the joystick devices. */ void _al_win_joystick_dinput_unacquire(void *unused) { int i; (void)unused; if (joystick_dinput && win_disp) { for (i=0; i < MAX_JOYSTICKS; i++) { if (joydx_joystick[i].device) { ALLEGRO_DEBUG("Unacquiring joystick device at slot %d\n", i); IDirectInputDevice8_Unacquire(joydx_joystick[i].device); } } } } /* _al_win_joystick_dinput_grab: [window thread] * Grabs the joystick devices. */ void _al_win_joystick_dinput_grab(void *param) { int i; if (!joystick_dinput) return; /* Release the input from the previous window just in case, otherwise set cooperative level will fail. */ if (win_disp) { _al_win_wnd_call_proc(win_disp->window, _al_win_joystick_dinput_unacquire, NULL); } win_disp = (ALLEGRO_DISPLAY_WIN *)param; /* set cooperative level */ for (i = 0; i < MAX_JOYSTICKS; i++) { HRESULT hr; if (!joydx_joystick[i].device) continue; hr = IDirectInputDevice8_SetCooperativeLevel(joydx_joystick[i].device, win_disp->window, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); if (FAILED(hr)) { ALLEGRO_ERROR("IDirectInputDevice8_SetCooperativeLevel failed.\n"); return; } } joystick_dinput_acquire(); } static ALLEGRO_JOYSTICK_DIRECTX *joydx_by_guid(const GUID guid, const GUID product_guid) { unsigned i; for (i = 0; i < MAX_JOYSTICKS; i++) { if ( GUID_EQUAL(joydx_joystick[i].guid, guid) && GUID_EQUAL(joydx_joystick[i].product_guid, product_guid) /* && joydx_joystick[i].config_state == STATE_ALIVE */ ) return &joydx_joystick[i]; } return NULL; } static ALLEGRO_JOYSTICK_DIRECTX *joydx_allocate_structure(int *num) { int i; for (i = 0; i < MAX_JOYSTICKS; i++) { if (joydx_joystick[i].config_state == STATE_UNUSED) { *num = i; return &joydx_joystick[i]; } } *num = -1; return NULL; } /* object_enum_callback: [primary thread] * Helper function to find out what objects we have on the device. */ static BOOL CALLBACK object_enum_callback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) { #define GUIDTYPE_EQ(x) GUID_EQUAL(lpddoi->guidType, x) CAPS_AND_NAMES *can = (CAPS_AND_NAMES *)pvRef; if (GUIDTYPE_EQ(__al_GUID_XAxis)) { can->have_x = true; _tcsncpy(can->name_x, lpddoi->tszName, NAME_LEN); } else if (GUIDTYPE_EQ(__al_GUID_YAxis)) { can->have_y = true; _tcsncpy(can->name_y, lpddoi->tszName, NAME_LEN); } else if (GUIDTYPE_EQ(__al_GUID_ZAxis)) { can->have_z = true; _tcsncpy(can->name_z, lpddoi->tszName, NAME_LEN); } else if (GUIDTYPE_EQ(__al_GUID_RxAxis)) { can->have_rx = true; _tcsncpy(can->name_rx, lpddoi->tszName, NAME_LEN); } else if (GUIDTYPE_EQ(__al_GUID_RyAxis)) { can->have_ry = true; _tcsncpy(can->name_ry, lpddoi->tszName, NAME_LEN); } else if (GUIDTYPE_EQ(__al_GUID_RzAxis)) { can->have_rz = true; _tcsncpy(can->name_rz, lpddoi->tszName, NAME_LEN); } else if (GUIDTYPE_EQ(__al_GUID_Slider)) { if (can->num_sliders < MAX_SLIDERS) { _tcsncpy(can->name_slider[can->num_sliders], lpddoi->tszName, NAME_LEN); can->num_sliders++; } } else if (GUIDTYPE_EQ(__al_GUID_POV)) { if (can->num_povs < MAX_POVS) { _tcsncpy(can->name_pov[can->num_povs], lpddoi->tszName, NAME_LEN); can->num_povs++; } } else if (GUIDTYPE_EQ(__al_GUID_Button)) { if (can->num_buttons < MAX_BUTTONS) { _tcsncpy(can->name_button[can->num_buttons], lpddoi->tszName, NAME_LEN); can->num_buttons++; } } return DIENUM_CONTINUE; #undef GUIDTYPE_EQ } static char *add_string(char *buf, const TCHAR *src, int *pos, int bufsize, const char* dfl) { char *dest; dest = buf + *pos; if (*pos >= bufsize - 1) { /* Out of space. */ ALLEGRO_ASSERT(dest[0] == '\0'); return dest; } if (*pos > 0) { /* Skip over NUL separator. */ dest++; (*pos)++; } if (src) { dest = _twin_copy_tchar_to_utf8(dest, src, bufsize - *pos); } else { dest = _al_sane_strncpy(dest, dfl, bufsize - *pos); } ALLEGRO_ASSERT(dest != 0); if (dest) { (*pos) += strlen(dest); ALLEGRO_ASSERT(*pos < bufsize); } return dest; } /* fill_joystick_info_using_caps_and_names: [primary thread] * Helper to fill in the contents of the joystick structure using the * information painstakingly stored into the caps_and_names substructure. */ static void fill_joystick_info_using_caps_and_names(ALLEGRO_JOYSTICK_DIRECTX *joy, const CAPS_AND_NAMES *can) { _AL_JOYSTICK_INFO *info = &joy->parent.info; int pos = 0; int i; #define N_STICK (info->num_sticks) #define N_AXIS (info->stick[N_STICK].num_axes) #define ADD_STRING(A, dfl) \ (add_string(joy->all_names, (A), &pos, \ sizeof(joy->all_names), (dfl))) /* the X, Y, Z axes make up the first stick */ if (can->have_x || can->have_y || can->have_z) { if (can->have_x) { info->stick[N_STICK].flags = ALLEGRO_JOYFLAG_DIGITAL | ALLEGRO_JOYFLAG_ANALOGUE; info->stick[N_STICK].axis[N_AXIS].name = ADD_STRING(can->name_x, default_name_x); joy->x_mapping.stick = N_STICK; joy->x_mapping.axis = N_AXIS; N_AXIS++; } if (can->have_y) { info->stick[N_STICK].flags = ALLEGRO_JOYFLAG_DIGITAL | ALLEGRO_JOYFLAG_ANALOGUE; info->stick[N_STICK].axis[N_AXIS].name = ADD_STRING(can->name_y, default_name_y); joy->y_mapping.stick = N_STICK; joy->y_mapping.axis = N_AXIS; N_AXIS++; } if (can->have_z) { info->stick[N_STICK].flags = ALLEGRO_JOYFLAG_DIGITAL | ALLEGRO_JOYFLAG_ANALOGUE; info->stick[N_STICK].axis[N_AXIS].name = ADD_STRING(can->name_z, default_name_z); joy->z_mapping.stick = N_STICK; joy->z_mapping.axis = N_AXIS; N_AXIS++; } info->stick[N_STICK].name = ADD_STRING(NULL, default_name_stick); N_STICK++; } /* the Rx, Ry, Rz axes make up the next stick */ if (can->have_rx || can->have_ry || can->have_rz) { if (can->have_rx) { info->stick[N_STICK].flags = ALLEGRO_JOYFLAG_DIGITAL | ALLEGRO_JOYFLAG_ANALOGUE; info->stick[N_STICK].axis[N_AXIS].name = ADD_STRING(can->name_rx, default_name_rx); joy->rx_mapping.stick = N_STICK; joy->rx_mapping.axis = N_AXIS; N_AXIS++; } if (can->have_ry) { info->stick[N_STICK].flags = ALLEGRO_JOYFLAG_DIGITAL | ALLEGRO_JOYFLAG_ANALOGUE; info->stick[N_STICK].axis[N_AXIS].name = ADD_STRING(can->name_ry, default_name_ry); joy->ry_mapping.stick = N_STICK; joy->ry_mapping.axis = N_AXIS; N_AXIS++; } if (can->have_rz) { info->stick[N_STICK].flags = ALLEGRO_JOYFLAG_DIGITAL | ALLEGRO_JOYFLAG_ANALOGUE; info->stick[N_STICK].axis[N_AXIS].name = ADD_STRING(can->name_rz, default_name_rz); joy->rz_mapping.stick = N_STICK; joy->rz_mapping.axis = N_AXIS; N_AXIS++; } info->stick[N_STICK].name = ADD_STRING(NULL, default_name_stick); N_STICK++; } /* sliders are assigned to one stick each */ for (i = 0; i < can->num_sliders; i++) { info->stick[N_STICK].flags = ALLEGRO_JOYFLAG_DIGITAL | ALLEGRO_JOYFLAG_ANALOGUE; info->stick[N_STICK].num_axes = 1; info->stick[N_STICK].axis[0].name = ADD_STRING(NULL, "axis"); info->stick[N_STICK].name = ADD_STRING(can->name_slider[i], default_name_slider); joy->slider_mapping[i].stick = N_STICK; joy->slider_mapping[i].axis = 0; N_STICK++; } /* POV devices are assigned to one stick each */ for (i = 0; i < can->num_povs; i++) { info->stick[N_STICK].flags = ALLEGRO_JOYFLAG_DIGITAL; info->stick[N_STICK].num_axes = 2; info->stick[N_STICK].axis[0].name = ADD_STRING(NULL, "left/right"); info->stick[N_STICK].axis[1].name = ADD_STRING(NULL, "up/down"); info->stick[N_STICK].name = ADD_STRING(can->name_pov[i], default_name_hat); joy->pov_mapping_stick[i] = N_STICK; N_STICK++; } /* buttons */ for (i = 0; i < can->num_buttons; i++) { info->button[i].name = ADD_STRING(can->name_button[i], default_name_button[i]); } info->num_buttons = can->num_buttons; /* correct buggy MP-8866 Dual USB Joypad info received from DirectInput */ if (strstr(joy->name, "MP-8866")) { /* axes were mapped weird; remap as expected */ /* really R-stick X axis */ joy->z_mapping.stick = 1; joy->z_mapping.axis = 0; /* really R-stick Y axis */ joy->rz_mapping.stick = 1; joy->rz_mapping.axis = 1; info->stick[0].num_axes = 2; info->stick[1].num_axes = 2; /* reuse the axis names from the first stick */ info->stick[2].axis[0].name = info->stick[1].axis[0].name = info->stick[0].axis[0].name; info->stick[2].axis[1].name = info->stick[1].axis[1].name = info->stick[0].axis[1].name; /* first four button names contained junk; replace with valid strings */ info->button[ 0].name = ADD_STRING(NULL, "Triangle"); info->button[ 1].name = ADD_STRING(NULL, "Circle"); info->button[ 2].name = ADD_STRING(NULL, "X"); info->button[ 3].name = ADD_STRING(NULL, "Square"); /* while we're at it, give these controls more sensible names, too */ info->stick[0].name = ADD_STRING(NULL, "[L-stick] or D-pad"); info->stick[1].name = ADD_STRING(NULL, "[R-stick]"); info->stick[2].name = ADD_STRING(NULL, "[D-pad]"); } #undef N_AXIS #undef N_STICK #undef ADD_STRING } #ifdef ALLEGRO_DINPUT_FILTER_XINPUT /* A better Xinput detection method inspired by from SDL. * The method proposed by Microsoft on their web site is problematic because it * requires non standard compiler extensions and hard to get headers. * This method only needs Windows XP and user32.dll. */ static bool dinput_is_device_xinput(const GUID *guid) { PRAWINPUTDEVICELIST device_list = NULL; UINT amount = 0; UINT i; bool result = false; bool found = false; /* Go through RAWINPUT (WinXP and later) to find HID devices. */ if ((GetRawInputDeviceList(NULL, &amount, sizeof (RAWINPUTDEVICELIST)) != 0)) { ALLEGRO_ERROR("Could not get amount of raw input devices.\n"); return false; /* drat... */ } if (amount < 1) { ALLEGRO_ERROR("Could not get any of raw input devices.\n"); return false; /* drat again... */ } device_list = (PRAWINPUTDEVICELIST) al_malloc(sizeof(RAWINPUTDEVICELIST) * amount); if (!device_list) { ALLEGRO_ERROR("Could allocate memory for raw input devices.\n"); return false; /* No luck. */ } if (GetRawInputDeviceList(device_list, &amount, sizeof(RAWINPUTDEVICELIST)) == ((UINT)-1)) { ALLEGRO_ERROR("Could not retrieve %d raw input devices.\n", amount); al_free((void *)device_list); return false; } for (i = 0; i < amount; i++) { PRAWINPUTDEVICELIST device = device_list + i; RID_DEVICE_INFO rdi; char device_name[128]; UINT rdi_size = sizeof (rdi); UINT name_size = 127; rdi.cbSize = sizeof (rdi); /* Get device info. */ if (GetRawInputDeviceInfoA(device->hDevice, RIDI_DEVICEINFO, &rdi, &rdi_size) == ((UINT)-1)) { ALLEGRO_ERROR("Could not get raw device info for list index %d.\n", i); continue; } /* See if vendor and product id match. */ if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != ((LONG)guid->Data1)) continue; found = true; /* Get device name */ memset(device_name, 0, 128); if(GetRawInputDeviceInfoA(device->hDevice, RIDI_DEVICENAME, device_name, &name_size) == ((UINT)-1)) { ALLEGRO_ERROR("Could not get raw device name for list index %d.\n", i); continue; } /* See if there is IG_ in the name, if it is , it's an XInput device. */ ALLEGRO_DEBUG("Checking for XInput : %s\n", device_name); if (strstr(device_name, "IG_") != NULL) { ALLEGRO_DEBUG("Device %s is an XInput device.\n", device_name); result = true; break; } } if (!found) { ALLEGRO_ERROR("Could not find device %s in the raw device list.\n", guid_to_string(guid)); result = true; /* Ignore "mystery" devices. Testing shows that on MinGW these are never valid DirectInput devices. Real ones should show up in the raw device list. */ } al_free((void *)device_list); return result; } #endif /* joystick_enum_callback: [primary thread] * Helper function to find out how many joysticks we have and set them up. * At the end joydx_num_joysticks and joydx_joystick[] will be initialised. */ static BOOL CALLBACK joystick_enum_callback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) { DIPROPRANGE property_range = { /* the header */ { sizeof(DIPROPRANGE), // diph.dwSize sizeof(DIPROPHEADER), // diph.dwHeaderSize 0, // diph.dwObj DIPH_DEVICE, // diph.dwHow }, /* the data */ -32767, // lMin +32767 // lMax }; DIPROPDWORD property_deadzone = { /* the header */ { sizeof(DIPROPDWORD), // diph.dwSize sizeof(DIPROPHEADER), // diph.dwHeaderSize 0, // diph.dwObj DIPH_DEVICE, // diph.dwHow }, /* the data */ 0, // dwData }; DIPROPDWORD property_buffersize = { /* the header */ { sizeof(DIPROPDWORD), // diph.dwSize sizeof(DIPROPHEADER), // diph.dwHeaderSize 0, // diph.dwObj DIPH_DEVICE, // diph.dwHow }, /* the data */ DEVICE_BUFFER_SIZE // number of data items }; LPDIRECTINPUTDEVICE _dinput_device1; LPDIRECTINPUTDEVICE2 dinput_device = NULL; HRESULT hr; LPVOID temp; CAPS_AND_NAMES caps_and_names; ALLEGRO_JOYSTICK_DIRECTX *joy = NULL; int num; (void)pvRef; /* check if the joystick already existed before * Aslo have to check the product GUID because devices like the Logitech * F710 have a backside switch that will change the product GUID, * but not the instance guid. */ joy = joydx_by_guid(lpddi->guidInstance, lpddi->guidProduct); if (joy) { ALLEGRO_DEBUG("Device %s still exists\n", joydx_guid_string(joy)); joy->marked = true; return DIENUM_CONTINUE; } /* If we are compiling the XInput driver, ignore XInput devices, those can go though the XInput driver, unless if the DirectInput driver was set explicitly in the configuration. */ #ifdef ALLEGRO_DINPUT_FILTER_XINPUT if (dinput_is_device_xinput(&lpddi->guidProduct)) { ALLEGRO_DEBUG("Filtered out XInput device %s\n", guid_to_string(&lpddi->guidInstance)); goto Error; } #endif /* create the DirectInput joystick device */ hr = IDirectInput8_CreateDevice(joystick_dinput, lpddi->guidInstance, &_dinput_device1, NULL); if (FAILED(hr)) goto Error; /* query the DirectInputDevice2 interface needed for the poll() method */ hr = IDirectInputDevice8_QueryInterface(_dinput_device1, __al_IID_IDirectInputDevice8, &temp); IDirectInputDevice8_Release(_dinput_device1); if (FAILED(hr)) goto Error; dinput_device = (LPDIRECTINPUTDEVICE2)temp; /* enumerate objects available on the device */ memset(&caps_and_names, 0, sizeof(caps_and_names)); hr = IDirectInputDevice8_EnumObjects(dinput_device, object_enum_callback, &caps_and_names, DIDFT_PSHBUTTON | DIDFT_AXIS | DIDFT_POV); if (FAILED(hr)) goto Error; /* set data format */ hr = IDirectInputDevice8_SetDataFormat(dinput_device, &__al_c_dfDIJoystick); if (FAILED(hr)) goto Error; /* set the range of axes */ hr = IDirectInputDevice8_SetProperty(dinput_device, DIPROP_RANGE, &property_range.diph); if (FAILED(hr)) goto Error; /* set the dead zone of axes */ hr = IDirectInputDevice8_SetProperty(dinput_device, DIPROP_DEADZONE, &property_deadzone.diph); if (FAILED(hr)) goto Error; /* set the buffer size */ hr = IDirectInputDevice8_SetProperty(dinput_device, DIPROP_BUFFERSIZE, &property_buffersize.diph); if (FAILED(hr)) goto Error; /* set up the joystick structure */ joy = joydx_allocate_structure(&num); if (!joy) { ALLEGRO_ERROR("Joystick array full\n"); goto Error; } joy->config_state = STATE_BORN; joy->marked = true; joy->device = dinput_device; memcpy(&joy->guid, &lpddi->guidInstance, sizeof(GUID)); memcpy(&joy->product_guid, &lpddi->guidProduct, sizeof(GUID)); _twin_copy_tchar_to_utf8(joy->name, lpddi->tszInstanceName, sizeof(joy->name)); /* fill in the joystick structure */ fill_joystick_info_using_caps_and_names(joy, &caps_and_names); /* create a thread event for this joystick, unless it was already created */ joy->waker_event = CreateEvent(NULL, false, false, NULL); /* tell the joystick background thread to wake up when this joystick * device's state changes */ hr = IDirectInputDevice8_SetEventNotification(joy->device, joy->waker_event); if (FAILED(hr)) { ALLEGRO_ERROR("SetEventNotification failed for joystick %d: %s\n", num, dinput_err_str(hr)); goto Error; } if (hr == DI_POLLEDDEVICE) { /* This joystick device must be polled -- replace the Event with * a Waitable Timer object. * * Theoretically all polled devices could share a single * waitable timer object. But, really, how many such devices * are there going to be on a system? */ CloseHandle(joy->waker_event); joy->waker_event = CreateWaitableTimer(NULL, false, NULL); if (joy->waker_event == NULL) { ALLEGRO_ERROR("CreateWaitableTimer failed for polled device.\n"); goto Error; } { LARGE_INTEGER due_time = { 0 }; due_time.QuadPart = -1; /* Start ASAP... */ SetWaitableTimer(joy->waker_event, &due_time, 15, /* ... then periodic, every 15ms*/ NULL, NULL, false); } } ALLEGRO_INFO("Joystick %d initialized, GUID: %s\n", num, joydx_guid_string(joy)); config_needs_merging = true; return DIENUM_CONTINUE; Error: if (dinput_device) IDirectInputDevice8_Release(dinput_device); if (joy) { joy->device = NULL; joydx_inactivate_joy(joy); } return DIENUM_CONTINUE; } static void joydx_inactivate_joy(ALLEGRO_JOYSTICK_DIRECTX *joy) { if (joy->config_state == STATE_UNUSED) return; joy->config_state = STATE_UNUSED; joy->marked = false; if (joy->device) { IDirectInputDevice8_SetEventNotification(joy->device, NULL); IDirectInputDevice8_Release(joy->device); joy->device = NULL; } memset(&joy->guid, 0, sizeof(GUID)); if (joy->waker_event) { CloseHandle(joy->waker_event); joy->waker_event = NULL; } memset(&joy->parent.info, 0, sizeof(joy->parent.info)); /* XXX the joystick name really belongs in joy->parent.info too */ joy->name[0] = '\0'; memset(&joy->joystate, 0, sizeof(joy->joystate)); /* Don't forget to wipe the guids as well! */ memset(&joy->guid, 0, sizeof(joy->guid)); memset(&joy->product_guid, 0, sizeof(joy->product_guid)); } static void joydx_generate_configure_event(void) { ALLEGRO_EVENT event; event.joystick.type = ALLEGRO_EVENT_JOYSTICK_CONFIGURATION; event.joystick.timestamp = al_get_time(); _al_generate_joystick_event(&event); } static bool joydx_scan(bool configure) { HRESULT hr; unsigned i; /* Clear mark bits. */ for (i = 0; i < MAX_JOYSTICKS; i++) joydx_joystick[i].marked = false; /* enumerate the joysticks attached to the system */ hr = IDirectInput8_EnumDevices(joystick_dinput, DI8DEVCLASS_GAMECTRL, joystick_enum_callback, NULL, DIEDFL_ATTACHEDONLY); if (FAILED(hr)) { /* XXX will this ruin everything? */ IDirectInput8_Release(joystick_dinput); joystick_dinput = NULL; return false; } /* Schedule unmarked structures to be inactivated. */ for (i = 0; i < MAX_JOYSTICKS; i++) { ALLEGRO_JOYSTICK_DIRECTX *joy = &joydx_joystick[i]; if (joy->config_state == STATE_ALIVE && !joy->marked) { ALLEGRO_DEBUG("Joystick %s to be inactivated\n", joydx_guid_string(joy)); joy->config_state = STATE_DYING; config_needs_merging = true; } } if (config_needs_merging && configure) joydx_generate_configure_event(); return config_needs_merging; } static void joydx_merge(void) { unsigned i; HRESULT hr; config_needs_merging = false; joydx_num_joysticks = 0; for (i = 0; i < MAX_JOYSTICKS; i++) { ALLEGRO_JOYSTICK_DIRECTX *joy = &joydx_joystick[i]; switch (joy->config_state) { case STATE_UNUSED: break; case STATE_BORN: hr = IDirectInputDevice8_Acquire(joy->device); if (FAILED(hr)) { ALLEGRO_ERROR("acquire joystick %d failed: %s\n", i, dinput_err_str(hr)); } joy->config_state = STATE_ALIVE; /* fall through */ case STATE_ALIVE: JOYSTICK_WAKER(joydx_num_joysticks) = joy->waker_event; joydx_num_joysticks++; break; case STATE_DYING: joydx_inactivate_joy(joy); break; } } ALLEGRO_INFO("Merged, num joysticks=%d\n", joydx_num_joysticks); joystick_dinput_acquire(); } /* joydx_init_joystick: [primary thread] * * Initialises the DirectInput joystick devices. * * To avoid enumerating the the joysticks over and over, this does * the enumeration once and does almost all the setting up required * of the devices. joydx_get_joystick() is left with very little work * to do. */ static bool joydx_init_joystick(void) { HRESULT hr; ALLEGRO_SYSTEM *system; size_t i; MAKE_UNION(&joystick_dinput, LPDIRECTINPUT *); ALLEGRO_ASSERT(!joystick_dinput); ALLEGRO_ASSERT(!joydx_num_joysticks); ALLEGRO_ASSERT(!joydx_thread); ALLEGRO_ASSERT(!STOP_EVENT); /* load DirectInput module */ _al_dinput_module = _al_win_safe_load_library(_al_dinput_module_name); if (_al_dinput_module == NULL) { ALLEGRO_ERROR("Failed to open '%s' library\n", _al_dinput_module_name); joystick_dinput = NULL; return false; } /* import DirectInput create proc */ _al_dinput_create = (DIRECTINPUT8CREATEPROC)GetProcAddress(_al_dinput_module, "DirectInput8Create"); if (_al_dinput_create == NULL) { ALLEGRO_ERROR("DirectInput8Create not in %s\n", _al_dinput_module_name); FreeLibrary(_al_dinput_module); joystick_dinput = NULL; return false; } /* get the DirectInput interface */ hr = _al_dinput_create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, __al_IID_IDirectInput8, u.v, NULL); if (FAILED(hr)) { ALLEGRO_ERROR("Failed to create DirectInput interface\n"); FreeLibrary(_al_dinput_module); joystick_dinput = NULL; return false; } /* initialise the lock for the background thread */ InitializeCriticalSection(&joydx_thread_cs); // This initializes present joystick state joydx_scan(false); // This copies present state to user state joydx_merge(); /* create the dedicated thread stopping event */ STOP_EVENT = CreateEvent(NULL, false, false, NULL); /* If one of our windows is the foreground window make it grab the input. */ system = al_get_system_driver(); for (i = 0; i < _al_vector_size(&system->displays); i++) { ALLEGRO_DISPLAY_WIN **pwin_disp = (ALLEGRO_DISPLAY_WIN **)_al_vector_ref(&system->displays, i); ALLEGRO_DISPLAY_WIN *win_disp = *pwin_disp; if (win_disp->window == GetForegroundWindow()) { _al_win_wnd_call_proc(win_disp->window, _al_win_joystick_dinput_grab, win_disp); } } /* start the background thread */ joydx_thread = (HANDLE) _beginthreadex(NULL, 0, joydx_thread_proc, NULL, 0, NULL); return true; } /* joydx_exit_joystick: [primary thread] * Shuts down the DirectInput joystick devices. */ static void joydx_exit_joystick(void) { int i; ALLEGRO_SYSTEM *system; size_t j; ALLEGRO_DEBUG("Entering joydx_exit_joystick\n"); ALLEGRO_ASSERT(joydx_thread); /* stop the thread */ SetEvent(STOP_EVENT); WaitForSingleObject(joydx_thread, INFINITE); CloseHandle(joydx_thread); joydx_thread = NULL; /* free thread resources */ CloseHandle(STOP_EVENT); STOP_EVENT = NULL; DeleteCriticalSection(&joydx_thread_cs); /* The toplevel display is assumed to have the input acquired. Release it. */ system = al_get_system_driver(); for (j = 0; j < _al_vector_size(&system->displays); j++) { ALLEGRO_DISPLAY_WIN **pwin_disp = (ALLEGRO_DISPLAY_WIN **)_al_vector_ref(&system->displays, j); ALLEGRO_DISPLAY_WIN *win_disp = *pwin_disp; if (win_disp->window == GetForegroundWindow()) { ALLEGRO_DEBUG("Requesting window unacquire joystick devices\n"); _al_win_wnd_call_proc(win_disp->window, _al_win_joystick_dinput_unacquire, win_disp); } } /* destroy the devices */ for (i = 0; i < MAX_JOYSTICKS; i++) { joydx_inactivate_joy(&joydx_joystick[i]); } joydx_num_joysticks = 0; for (i = 0; i < MAX_JOYSTICKS; i++) { JOYSTICK_WAKER(i) = NULL; } /* destroy the DirectInput interface */ IDirectInput8_Release(joystick_dinput); joystick_dinput = NULL; /* release module handle */ FreeLibrary(_al_dinput_module); _al_dinput_module = NULL; ALLEGRO_DEBUG("Leaving joydx_exit_joystick\n"); } /* joydx_reconfigure_joysticks: [primary thread] */ static bool joydx_reconfigure_joysticks(void) { bool ret = false; EnterCriticalSection(&joydx_thread_cs); if (config_needs_merging) { joydx_merge(); ret = true; } LeaveCriticalSection(&joydx_thread_cs); return ret; } /* joydx_get_num_joysticks: [primary thread] * Return the number of joysticks available on the system. */ static int joydx_get_num_joysticks(void) { return joydx_num_joysticks; } /* joydx_get_joystick: [primary thread] * * Returns the address of a ALLEGRO_JOYSTICK structure for the device * number NUM. */ static ALLEGRO_JOYSTICK *joydx_get_joystick(int num) { ALLEGRO_JOYSTICK *ret = NULL; unsigned i; ALLEGRO_ASSERT(num >= 0); EnterCriticalSection(&joydx_thread_cs); for (i = 0; i < MAX_JOYSTICKS; i++) { ALLEGRO_JOYSTICK_DIRECTX *joy = &joydx_joystick[i]; if (ACTIVE_STATE(joy->config_state)) { if (num == 0) { ret = (ALLEGRO_JOYSTICK *)joy; break; } num--; } } /* Must set the driver of the joystick for the wrapper driver */ ret->driver = &_al_joydrv_directx; LeaveCriticalSection(&joydx_thread_cs); #if 0 /* is this needed? */ if (ret) { ALLEGRO_DISPLAY *display = al_get_current_display(); if (display) _al_win_joystick_dinput_grab(display); } #endif return ret; } /* joydx_release_joystick: [primary thread] * Releases a previously gotten joystick. */ static void joydx_release_joystick(ALLEGRO_JOYSTICK *joy) { (void)joy; } /* joydx_get_joystick_state: [primary thread] * Copy the internal joystick state to a user-provided structure. */ static void joydx_get_joystick_state(ALLEGRO_JOYSTICK *joy_, ALLEGRO_JOYSTICK_STATE *ret_state) { ALLEGRO_JOYSTICK_DIRECTX *joy = (ALLEGRO_JOYSTICK_DIRECTX *)joy_; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); _al_event_source_lock(es); { *ret_state = joy->joystate; } _al_event_source_unlock(es); } static const char *joydx_get_name(ALLEGRO_JOYSTICK *joy_) { ALLEGRO_JOYSTICK_DIRECTX *joy = (ALLEGRO_JOYSTICK_DIRECTX *)joy_; return joy->name; } static bool joydx_get_active(ALLEGRO_JOYSTICK *joy) { ALLEGRO_JOYSTICK_DIRECTX *joydx = (ALLEGRO_JOYSTICK_DIRECTX *)joy; return ACTIVE_STATE(joydx->config_state); } /* joydx_thread_proc: [joystick thread] * Thread loop function for the joystick thread. */ static unsigned __stdcall joydx_thread_proc(LPVOID unused) { double last_update = al_get_time(); /* XXX is this needed? */ _al_win_thread_init(); while (true) { DWORD result; result = WaitForMultipleObjects(joydx_num_joysticks + 1, /* +1 for STOP_EVENT */ joydx_thread_wakers, false, /* wait for any */ 1000); /* 1 second wait */ if (result == WAIT_OBJECT_0) break; /* STOP_EVENT */ EnterCriticalSection(&joydx_thread_cs); { /* handle hot plugging */ if (al_get_time() > last_update+1 || result == WAIT_TIMEOUT) { if (need_device_enumeration) { joydx_scan(true); need_device_enumeration = false; } last_update = al_get_time(); } if (result != WAIT_TIMEOUT) { int waker_num = result - WAIT_OBJECT_0 - 1; /* -1 for STOP_EVENT */ HANDLE waker = JOYSTICK_WAKER(waker_num); unsigned i; for (i = 0; i < MAX_JOYSTICKS; i++) { if (waker == joydx_joystick[i].waker_event) { update_joystick(&joydx_joystick[i]); break; } } if (i == MAX_JOYSTICKS) { ALLEGRO_WARN("unable to match event to joystick\n"); } } } LeaveCriticalSection(&joydx_thread_cs); } _al_win_thread_exit(); (void)unused; return 0; } /* update_joystick: [joystick thread] * Reads in data for a single DirectInput joystick device, updates * the internal ALLEGRO_JOYSTICK_STATE structure, and generates any Allegro * events required. */ static void update_joystick(ALLEGRO_JOYSTICK_DIRECTX *joy) { DIDEVICEOBJECTDATA buffer[DEVICE_BUFFER_SIZE]; DWORD num_items = DEVICE_BUFFER_SIZE; HRESULT hr; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); /* some devices require polling */ IDirectInputDevice8_Poll(joy->device); /* get device data into buffer */ hr = IDirectInputDevice8_GetDeviceData(joy->device, sizeof(DIDEVICEOBJECTDATA), buffer, &num_items, 0); if (hr != DI_OK && hr != DI_BUFFEROVERFLOW) { if ((hr == DIERR_NOTACQUIRED) || (hr == DIERR_INPUTLOST)) { ALLEGRO_WARN("joystick device not acquired or lost\n"); } else { ALLEGRO_ERROR("unexpected error while polling the joystick\n"); } return; } /* don't bother locking the event source if there's no work to do */ /* this happens a lot for polled devices */ if (num_items == 0) return; _al_event_source_lock(es); { unsigned int i; for (i = 0; i < num_items; i++) { const DIDEVICEOBJECTDATA *item = &buffer[i]; const int dwOfs = item->dwOfs; const DWORD dwData = item->dwData; if (dwOfs == DIJOFS_X) handle_axis_event(joy, &joy->x_mapping, dwData); else if (dwOfs == DIJOFS_Y) handle_axis_event(joy, &joy->y_mapping, dwData); else if (dwOfs == DIJOFS_Z) handle_axis_event(joy, &joy->z_mapping, dwData); else if (dwOfs == DIJOFS_RX) handle_axis_event(joy, &joy->rx_mapping, dwData); else if (dwOfs == DIJOFS_RY) handle_axis_event(joy, &joy->ry_mapping, dwData); else if (dwOfs == DIJOFS_RZ) handle_axis_event(joy, &joy->rz_mapping, dwData); else if ((unsigned int)dwOfs == DIJOFS_SLIDER(0)) handle_axis_event(joy, &joy->slider_mapping[0], dwData); else if ((unsigned int)dwOfs == DIJOFS_SLIDER(1)) handle_axis_event(joy, &joy->slider_mapping[1], dwData); else if ((unsigned int)dwOfs == DIJOFS_POV(0)) handle_pov_event(joy, joy->pov_mapping_stick[0], dwData); else if ((unsigned int)dwOfs == DIJOFS_POV(1)) handle_pov_event(joy, joy->pov_mapping_stick[1], dwData); else if ((unsigned int)dwOfs == DIJOFS_POV(2)) handle_pov_event(joy, joy->pov_mapping_stick[2], dwData); else if ((unsigned int)dwOfs == DIJOFS_POV(3)) handle_pov_event(joy, joy->pov_mapping_stick[3], dwData); else { /* buttons */ if ((dwOfs >= DIJOFS_BUTTON0) && (dwOfs < DIJOFS_BUTTON(joy->parent.info.num_buttons))) { int num = (dwOfs - DIJOFS_BUTTON0) / (DIJOFS_BUTTON1 - DIJOFS_BUTTON0); handle_button_event(joy, num, (dwData & 0x80)); } } } } _al_event_source_unlock(es); } /* handle_axis_event: [joystick thread] * Helper function to handle a state change in a non-POV axis. * The joystick must be locked BEFORE entering this function. */ static void handle_axis_event(ALLEGRO_JOYSTICK_DIRECTX *joy, const AXIS_MAPPING *axis_mapping, DWORD value) { const int stick = axis_mapping->stick; const int axis = axis_mapping->axis; float pos; if (stick < 0 || stick >= joy->parent.info.num_sticks) return; if (axis < 0 || axis >= joy->parent.info.stick[stick].num_axes) return; pos = (int)value / 32767.0; joy->joystate.stick[stick].axis[axis] = pos; generate_axis_event(joy, stick, axis, pos); } /* handle_pov_event: [joystick thread] * Helper function to handle a state change in a POV device. * The joystick must be locked BEFORE entering this function. */ static void handle_pov_event(ALLEGRO_JOYSTICK_DIRECTX *joy, int stick, DWORD _value) { int value = _value; float old_p0, old_p1; float p0, p1; if (stick < 0 || stick >= joy->parent.info.num_sticks) return; old_p0 = joy->joystate.stick[stick].axis[0]; old_p1 = joy->joystate.stick[stick].axis[1]; /* left */ if ((value > JOY_POVBACKWARD) && (value < JOY_POVFORWARD_WRAP)) joy->joystate.stick[stick].axis[0] = p0 = -1.0; /* right */ else if ((value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD)) joy->joystate.stick[stick].axis[0] = p0 = +1.0; else joy->joystate.stick[stick].axis[0] = p0 = 0.0; /* forward */ if (((value > JOY_POVLEFT) && (value <= JOY_POVFORWARD_WRAP)) || ((value >= JOY_POVFORWARD) && (value < JOY_POVRIGHT))) joy->joystate.stick[stick].axis[1] = p1 = -1.0; /* backward */ else if ((value > JOY_POVRIGHT) && (value < JOY_POVLEFT)) joy->joystate.stick[stick].axis[1] = p1 = +1.0; else joy->joystate.stick[stick].axis[1] = p1 = 0.0; if (old_p0 != p0) { generate_axis_event(joy, stick, 0, p0); } if (old_p1 != p1) { generate_axis_event(joy, stick, 1, p1); } } /* handle_button_event: [joystick thread] * Helper function to handle a state change in a button. * The joystick must be locked BEFORE entering this function. */ static void handle_button_event(ALLEGRO_JOYSTICK_DIRECTX *joy, int button, bool down) { if (button < 0 && button >= joy->parent.info.num_buttons) return; if (down) { joy->joystate.button[button] = 32767; generate_button_event(joy, button, ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN); } else { joy->joystate.button[button] = 0; generate_button_event(joy, button, ALLEGRO_EVENT_JOYSTICK_BUTTON_UP); } } /* generate_axis_event: [joystick thread] * Helper to generate an event after an axis is moved. * The joystick must be locked BEFORE entering this function. */ static void generate_axis_event(ALLEGRO_JOYSTICK_DIRECTX *joy, int stick, int axis, float pos) { ALLEGRO_EVENT event; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); if (!_al_event_source_needs_to_generate_event(es)) return; event.joystick.type = ALLEGRO_EVENT_JOYSTICK_AXIS; event.joystick.timestamp = al_get_time(); event.joystick.id = (ALLEGRO_JOYSTICK *)joy; event.joystick.stick = stick; event.joystick.axis = axis; event.joystick.pos = pos; event.joystick.button = 0; _al_event_source_emit_event(es, &event); } /* generate_button_event: [joystick thread] * Helper to generate an event after a button is pressed or released. * The joystick must be locked BEFORE entering this function. */ static void generate_button_event(ALLEGRO_JOYSTICK_DIRECTX *joy, int button, ALLEGRO_EVENT_TYPE event_type) { ALLEGRO_EVENT event; ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source(); if (!_al_event_source_needs_to_generate_event(es)) return; event.joystick.type = event_type; event.joystick.timestamp = al_get_time(); event.joystick.id = (ALLEGRO_JOYSTICK *)joy; event.joystick.stick = 0; event.joystick.axis = 0; event.joystick.pos = 0.0; event.joystick.button = button; _al_event_source_emit_event(es, &event); } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/wjoyxi.c000066400000000000000000000635111473414355200165470ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows XInput joystick driver. * * By Beoran. * * * See readme.txt for copyright information. */ #define ALLEGRO_NO_COMPATIBILITY /* For waitable timers */ #define _WIN32_WINNT 0x0501 #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/platform/aintwin.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_bitmap.h" #ifdef ALLEGRO_CFG_XINPUT /* Don't compile this lot if xinput isn't supported. */ #ifndef ALLEGRO_WINDOWS #error something is wrong with the makefile #endif #ifdef ALLEGRO_MINGW32 #undef MAKEFOURCC #endif /* Poll connected joysticks frequently and non-connected ones infrequently. */ #ifndef ALLEGRO_XINPUT_POLL_DELAY #define ALLEGRO_XINPUT_POLL_DELAY 0.01 #endif #ifndef ALLEGRO_XINPUT_DISCONNECTED_POLL_DELAY #define ALLEGRO_XINPUT_DISCONNECTED_POLL_DELAY 1.50 #endif #include #include #include #include /* The official DirectX xinput.h uses SAL annotations. * Need the sal.h header to get rid of them. On some other platforms * such as MinGW on Linux this header is lacking because it is not needed there. * So, simply try to include sal.h IF we have it , and if not, hope * for the best. * This does no harm on msys2 either, they have a sal.h header. */ #ifdef ALLEGRO_HAVE_SAL_H #include #endif #include ALLEGRO_DEBUG_CHANNEL("xinput") #include "allegro5/joystick.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_wjoyxi.h" /* forward declarations */ static bool joyxi_init_joystick(void); static void joyxi_exit_joystick(void); static bool joyxi_reconfigure_joysticks(void); static int joyxi_get_num_joysticks(void); static ALLEGRO_JOYSTICK *joyxi_get_joystick(int num); static void joyxi_release_joystick(ALLEGRO_JOYSTICK *joy); static void joyxi_get_joystick_state(ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state); static const char *joyxi_get_name(ALLEGRO_JOYSTICK *joy); static bool joyxi_get_active(ALLEGRO_JOYSTICK *joy); /* the driver vtable */ ALLEGRO_JOYSTICK_DRIVER _al_joydrv_xinput = { AL_JOY_TYPE_XINPUT, "", "", "XInput Joystick", joyxi_init_joystick, joyxi_exit_joystick, joyxi_reconfigure_joysticks, joyxi_get_num_joysticks, joyxi_get_joystick, joyxi_release_joystick, joyxi_get_joystick_state, joyxi_get_name, joyxi_get_active }; #define XINPUT_MIN_VERSION 3 #define XINPUT_MAX_VERSION 4 #ifndef ALLEGRO_CFG_HAVE_XINPUT_CAPABILITIES_EX typedef struct _XINPUT_CAPABILITIES_EX { XINPUT_CAPABILITIES Capabilities; WORD VendorId; WORD ProductId; WORD VersionNumber; WORD unk1; DWORD unk2; } XINPUT_CAPABILITIES_EX, * PXINPUT_CAPABILITIES_EX; #endif typedef void (WINAPI *XInputEnablePROC)(BOOL); typedef DWORD (WINAPI *XInputSetStatePROC)(DWORD, XINPUT_VIBRATION*); typedef DWORD (WINAPI *XInputGetStatePROC)(DWORD, XINPUT_STATE*); typedef DWORD (WINAPI *XInputGetCapabilitiesPROC)(DWORD, DWORD, XINPUT_CAPABILITIES*); typedef DWORD (WINAPI *XInputGetCapabilitiesExPROC)(DWORD, DWORD, DWORD, XINPUT_CAPABILITIES_EX*); static HMODULE _imp_xinput_module = 0; static XInputEnablePROC _imp_XInputEnable = NULL; static XInputGetStatePROC _imp_XInputGetState = NULL; static XInputGetCapabilitiesPROC _imp_XInputGetCapabilities = NULL; static XInputGetCapabilitiesExPROC _imp_XInputGetCapabilitiesEx = NULL; XInputSetStatePROC _al_imp_XInputSetState = NULL; /* the joystick structures */ static ALLEGRO_JOYSTICK_XINPUT joyxi_joysticks[MAX_JOYSTICKS]; /* For the background threads. */ static ALLEGRO_THREAD *joyxi_thread = NULL; static ALLEGRO_THREAD *joyxi_disconnected_thread = NULL; static ALLEGRO_MUTEX *joyxi_mutex = NULL; /* Use condition variables to put the thread to sleep and prevent too frequent polling*/ static ALLEGRO_COND *joyxi_cond = NULL; static ALLEGRO_COND *joyxi_disconnected_cond = NULL; /* Names for things in because XInput doesn't provide them. */ /* Names of the sticks.*/ static char *const joyxi_stick_names[MAX_STICKS] = { "Left Thumbstick", "Right Thumbstick", "Left Trigger", "Right Trigger", }; /* Names of the axis */ static char *const joyxi_axis_names[MAX_STICKS][MAX_AXES] = { { "X", "Y" }, { "X", "Y" }, { "Ramp", "Error" }, { "Ramp", "Error" }, }; /* Sticks per axis */ static const int joyxi_axis_per_stick[MAX_STICKS] = { 2, 2, 1, 1, }; /* Struct to help mapping. */ struct _AL_XINPUT_BUTTON_MAPPING { int flags; int button; const char *name; }; /* The data in this array helps to map from XINPUT button input to ALLEGRO's. */ static const struct _AL_XINPUT_BUTTON_MAPPING joyxi_button_mapping[MAX_BUTTONS] = { { XINPUT_GAMEPAD_A, 0, "A" }, { XINPUT_GAMEPAD_B, 1, "B" }, { XINPUT_GAMEPAD_X, 2, "X" }, { XINPUT_GAMEPAD_Y, 3, "Y" }, { XINPUT_GAMEPAD_RIGHT_SHOULDER, 4, "RB" }, { XINPUT_GAMEPAD_LEFT_SHOULDER, 5, "LB" }, { XINPUT_GAMEPAD_RIGHT_THUMB, 6, "RT" }, { XINPUT_GAMEPAD_LEFT_THUMB, 7, "LT" }, { XINPUT_GAMEPAD_BACK, 8, "BACK" }, { XINPUT_GAMEPAD_START, 9, "START" }, { XINPUT_GAMEPAD_DPAD_RIGHT, 10, "RIGHT DPAD" }, { XINPUT_GAMEPAD_DPAD_LEFT, 11, "LEFT DPAD" }, { XINPUT_GAMEPAD_DPAD_DOWN, 12, "DOWN DPAD" }, { XINPUT_GAMEPAD_DPAD_UP, 13, "UP DPAD" }, }; static void unload_xinput_module(void) { FreeLibrary(_imp_xinput_module); _imp_xinput_module = NULL; } static bool _imp_load_xinput_module_version(int version) { char module_name[16]; sprintf(module_name, "xinput1_%d.dll", version); _imp_xinput_module = _al_win_safe_load_library(module_name); if (NULL == _imp_xinput_module) return false; _imp_XInputEnable = (XInputEnablePROC)GetProcAddress(_imp_xinput_module, "XInputEnable"); if (NULL == _imp_XInputEnable) { FreeLibrary(_imp_xinput_module); _imp_xinput_module = NULL; return false; } _imp_XInputGetState = (XInputGetStatePROC)GetProcAddress(_imp_xinput_module, "XInputGetState"); _imp_XInputGetCapabilities = (XInputGetCapabilitiesPROC)GetProcAddress(_imp_xinput_module, "XInputGetCapabilities"); if (version == 4) _imp_XInputGetCapabilitiesEx = (XInputGetCapabilitiesExPROC)GetProcAddress(_imp_xinput_module, (char*)108); _al_imp_XInputSetState = (XInputSetStatePROC)GetProcAddress(_imp_xinput_module, "XInputSetState"); ALLEGRO_INFO("Module \"%s\" loaded.\n", module_name); return true; } static bool load_xinput_module(void) { long version; char const *value; if (_imp_xinput_module) { return true; } value = al_get_config_value(al_get_system_config(), "joystick", "force_xinput_version"); if (value) { errno = 0; version = strtol(value, NULL, 10); if (errno) { ALLEGRO_ERROR("Failed to override XInput version. \"%s\" is not valid integer number.", value); return false; } else return _imp_load_xinput_module_version((int)version); } // Iterate over all valid versions. for (version = XINPUT_MAX_VERSION; version >= XINPUT_MIN_VERSION; version--) if (_imp_load_xinput_module_version((int)version)) return true; ALLEGRO_ERROR("Failed to load XInput library. Library is not installed."); return false; } /* generate_axis_event: [joystick thread] * Helper to generate an event when reconfiguration is needed. * The joystick must be locked BEFORE entering this function. */ static void joyxi_generate_reconfigure_event(void) { ALLEGRO_EVENT_SOURCE *source; ALLEGRO_EVENT event; /* There is a potential race condition with all of the generate functions * in this source file where al_get_joystick_event_source is returning NULL * because the joystick driver init functions haven't finished and * therefore new_joystick_driver in joynu.c isn't set yet. So we check that * the driver has fully installed before proceeding. */ if (!al_is_joystick_installed()) return; source = al_get_joystick_event_source(); if (!_al_event_source_needs_to_generate_event(source)) return; event.type = ALLEGRO_EVENT_JOYSTICK_CONFIGURATION; event.any.timestamp = al_get_time(); event.any.source = source; _al_event_source_emit_event(source, &event); } /* Helper to generate an event after an axis is moved. * The joystick must be locked BEFORE entering this function. */ static void joyxi_generate_axis_event(ALLEGRO_JOYSTICK_XINPUT *joy, int stick, int axis, float pos) { ALLEGRO_EVENT event; ALLEGRO_EVENT_SOURCE *es; if (!al_is_joystick_installed()) return; es = al_get_joystick_event_source(); if (!_al_event_source_needs_to_generate_event(es)) return; event.joystick.type = ALLEGRO_EVENT_JOYSTICK_AXIS; event.joystick.timestamp = al_get_time(); event.joystick.id = (ALLEGRO_JOYSTICK *)&joy->parent; event.joystick.stick = stick; event.joystick.axis = axis; event.joystick.pos = pos; event.joystick.button = 0; ALLEGRO_DEBUG("Generating an axis event on stick %d axis %d value %f:\n", stick, axis, pos); _al_event_source_emit_event(es, &event); } /* Helper to generate an event after a button is pressed or released. * The joystick must be locked BEFORE entering this function. */ static void joyxi_generate_button_event(ALLEGRO_JOYSTICK_XINPUT *joy, int button, ALLEGRO_EVENT_TYPE event_type) { ALLEGRO_EVENT event; ALLEGRO_EVENT_SOURCE *es; if (!al_is_joystick_installed()) return; es = al_get_joystick_event_source(); if (!_al_event_source_needs_to_generate_event(es)) return; event.joystick.type = event_type; event.joystick.timestamp = al_get_time(); event.joystick.id = (ALLEGRO_JOYSTICK *)joy; event.joystick.stick = 0; event.joystick.axis = 0; event.joystick.pos = 0.0; event.joystick.button = button; ALLEGRO_DEBUG("Generating an button event on button %d type %d:\n", button, event_type); _al_event_source_emit_event(es, &event); } /* Converts an XINPUT axis value to one suitable for Allegro's axes.*/ static float joyxi_convert_axis(SHORT value) { if (value >= 0) return(((float)value) / 32767.0); return(((float)value) / 32768.0); } /* Converts an XINPUT trigger value to one suitable for Allegro's axes.*/ static float joyxi_convert_trigger(BYTE value) { return(((float)value) / 255.0); } /* Converts an XInput state to an Allegro joystick state. */ static void joyxi_convert_state(ALLEGRO_JOYSTICK_STATE *alstate, XINPUT_STATE *xistate) { int index; /* Wipe the allegro state clean. */ memset(alstate, 0, sizeof(*alstate)); /* Map the buttons. Make good use of the mapping data. */ for (index = 0; index < MAX_BUTTONS; index++) { const struct _AL_XINPUT_BUTTON_MAPPING *mapping = joyxi_button_mapping + index; if (xistate->Gamepad.wButtons & mapping->flags) { alstate->button[mapping->button] = 32767; } else { alstate->button[mapping->button] = 0; } } /* Map the x and y axes of both sticks. */ alstate->stick[0].axis[0] = joyxi_convert_axis(xistate->Gamepad.sThumbLX); alstate->stick[0].axis[1] = -joyxi_convert_axis(xistate->Gamepad.sThumbLY); alstate->stick[1].axis[0] = joyxi_convert_axis(xistate->Gamepad.sThumbRX); alstate->stick[1].axis[1] = -joyxi_convert_axis(xistate->Gamepad.sThumbRY); /* Map the triggers as two individual sticks and axes each . */ alstate->stick[2].axis[0] = joyxi_convert_trigger(xistate->Gamepad.bLeftTrigger); alstate->stick[3].axis[0] = joyxi_convert_trigger(xistate->Gamepad.bRightTrigger); return; } /* Emits joystick events for the difference between the new and old joystick state. */ static void joyxi_emit_events( ALLEGRO_JOYSTICK_XINPUT *xjoy, ALLEGRO_JOYSTICK_STATE *newstate, ALLEGRO_JOYSTICK_STATE *oldstate) { int index, subdex; /* Send events for buttons. */ for (index = 0; index < MAX_BUTTONS; index++) { int newbutton = newstate->button[index]; int oldbutton = oldstate->button[index]; if (newbutton != oldbutton) { int type = (oldbutton > newbutton ? ALLEGRO_EVENT_JOYSTICK_BUTTON_UP : ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN); joyxi_generate_button_event(xjoy, index, type); } } /* Send events for the thumb pad axes and triggers . */ for (index = 0; index < MAX_STICKS; index++) { for (subdex = 0; subdex < joyxi_axis_per_stick[index]; subdex++) { float oldaxis = oldstate->stick[index].axis[subdex]; float newaxis = newstate->stick[index].axis[subdex]; if (oldaxis != newaxis) { joyxi_generate_axis_event(xjoy, index, subdex, newaxis); } } } } /* Polling function for a joystick that is currently active. */ static void joyxi_poll_connected_joystick(ALLEGRO_JOYSTICK_XINPUT *xjoy) { XINPUT_STATE xistate; ALLEGRO_JOYSTICK_STATE alstate; DWORD res = _imp_XInputGetState(xjoy->index, &xistate); if (res != ERROR_SUCCESS) { /* Assume joystick was disconnected, need to reconfigure. */ joyxi_generate_reconfigure_event(); return; } /* Check if the sequence is different. If not, no state change so don't do anything. */ if (xistate.dwPacketNumber == xjoy->state.dwPacketNumber) return; ALLEGRO_DEBUG("XInput joystick state change detected.\n"); /* If we get here translate the state and send the needed events. */ joyxi_convert_state(&alstate, &xistate); joyxi_emit_events(xjoy, &alstate, &xjoy->joystate); /* Finally copy over the states. */ xjoy->state = xistate; xjoy->joystate = alstate; } /* Polling function for a joystick that is currently not active. Care is taken to do this infrequently so performance doesn't suffer too much. */ static void joyxi_poll_disconnected_joystick(ALLEGRO_JOYSTICK_XINPUT *xjoy) { XINPUT_CAPABILITIES xicapas; DWORD res; res = _imp_XInputGetCapabilities(xjoy->index, 0, &xicapas); if (res == ERROR_SUCCESS) { /* Got capabilities, joystick was connected, need to reconfigure. */ joyxi_generate_reconfigure_event(); return; } /* Nothing to do if we get here. */ } /** Polls all connected joysticks. */ static void joyxi_poll_connected_joysticks(void) { int index; for (index = 0; index < MAX_JOYSTICKS; index++) { if ((joyxi_joysticks + index)->active) { joyxi_poll_connected_joystick(joyxi_joysticks + index); } } } /** Polls all disconnected joysticks. */ static void joyxi_poll_disconnected_joysticks(void) { int index; for (index = 0; index < MAX_JOYSTICKS; index++) { if (!((joyxi_joysticks + index)->active)) { joyxi_poll_disconnected_joystick(joyxi_joysticks + index); } } } /** Thread function that polls the active xinput joysticks. */ static void *joyxi_poll_thread(ALLEGRO_THREAD *thread, void *arg) { ALLEGRO_TIMEOUT timeout; al_lock_mutex(joyxi_mutex); /* Poll once every so much time, 10ms by default. */ while (!al_get_thread_should_stop(thread)) { al_init_timeout(&timeout, ALLEGRO_XINPUT_POLL_DELAY); /* Wait for the condition for the polling time in stead of using al_rest to allows the polling thread to be awoken when needed. */ al_wait_cond_until(joyxi_cond, joyxi_mutex, &timeout); /* If we get here poll joystick for new input or connection * and dispatch events. The mutexhas always been locked * so this should be OK. */ joyxi_poll_connected_joysticks(); } al_unlock_mutex(joyxi_mutex); return arg; } /** Thread function that polls the disconnected joysticks. */ static void *joyxi_poll_disconnected_thread(ALLEGRO_THREAD *thread, void *arg) { ALLEGRO_TIMEOUT timeout; al_lock_mutex(joyxi_mutex); /* Poll once every so much time, 10ms by default. */ while (!al_get_thread_should_stop(thread)) { al_init_timeout(&timeout, ALLEGRO_XINPUT_DISCONNECTED_POLL_DELAY); /* Wait for the condition for the polling time in stead of using al_rest to allows the polling thread to be awoken when needed. */ al_wait_cond_until(joyxi_disconnected_cond, joyxi_mutex, &timeout); /* If we get here poll joystick for new input or connection * and dispatch events. The mutex has always been locked * so this should be OK. */ joyxi_poll_disconnected_joysticks(); } al_unlock_mutex(joyxi_mutex); return arg; } /* Initializes the info part of the joystick. */ static void joyxi_init_joystick_info(ALLEGRO_JOYSTICK_XINPUT *xjoy) { int index, subdex; _AL_JOYSTICK_INFO *info = &xjoy->parent.info; /* Map xinput to 4 sticks: 2 thumb pads and 2 triggers. */ info->num_sticks = 4; /* Map xinput to 14 buttons */ info->num_buttons = MAX_BUTTONS; /* Map button names. */ for (index = 0; index < MAX_BUTTONS; index++) { info->button[index].name = joyxi_button_mapping[index].name; } /* Map stick and axis names. */ for (index = 0; index < MAX_STICKS; index++) { info->stick[index].name = joyxi_stick_names[index]; info->stick[index].num_axes = joyxi_axis_per_stick[index]; info->stick[index].flags = ALLEGRO_JOYFLAG_ANALOGUE; for (subdex = 0; subdex < joyxi_axis_per_stick[index]; subdex++) { info->stick[index].axis[subdex].name = joyxi_axis_names[index][subdex]; } } } /* Initialization API function. */ static bool joyxi_init_joystick(void) { int index; if (!load_xinput_module()) return false; /* Create the mutex and two condition variables. */ joyxi_mutex = al_create_mutex_recursive(); if (!joyxi_mutex) return false; joyxi_cond = al_create_cond(); if (!joyxi_cond) return false; joyxi_disconnected_cond = al_create_cond(); if (!joyxi_disconnected_cond) return false; al_lock_mutex(joyxi_mutex); /* Fill in the joystick structs */ for (index = 0; index < MAX_JOYSTICKS; index++) { joyxi_joysticks[index].active = false; joyxi_joysticks[index].index = (DWORD)index; joyxi_init_joystick_info(joyxi_joysticks + index); } /* Now, enable XInput*/ _imp_XInputEnable(TRUE); /* Now check which joysticks are enabled and poll them for the first time * but without sending any events. */ for (index = 0; index < MAX_JOYSTICKS; index++) { DWORD res = _imp_XInputGetCapabilities(joyxi_joysticks[index].index, 0, &joyxi_joysticks[index].capabilities); joyxi_joysticks[index].active = (res == ERROR_SUCCESS); if (joyxi_joysticks[index].active) { res = _imp_XInputGetState(joyxi_joysticks[index].index, &joyxi_joysticks[index].state); joyxi_joysticks[index].active = (res == ERROR_SUCCESS); } } /* Now start two polling background thread, since XInput is a polled API. * The first thread will poll the active joysticks frequently, the second * thread will poll the inactive joysticks infrequently. * This is done like this to preserve performance. */ joyxi_thread = al_create_thread(joyxi_poll_thread, NULL); joyxi_disconnected_thread = al_create_thread(joyxi_poll_disconnected_thread, NULL); al_unlock_mutex(joyxi_mutex); if (joyxi_thread) al_start_thread(joyxi_thread); if (joyxi_disconnected_thread) al_start_thread(joyxi_disconnected_thread); return (joyxi_thread != NULL) && (joyxi_disconnected_thread != NULL); } static void joyxi_exit_joystick(void) { int index; void *ret_value = NULL; if (!joyxi_mutex) return; if (!joyxi_cond) return; if (!joyxi_thread) return; /* Request the event thread to shut down, signal the condition, then join the thread. */ al_set_thread_should_stop(joyxi_thread); al_signal_cond(joyxi_cond); al_join_thread(joyxi_thread, &ret_value); al_set_thread_should_stop(joyxi_disconnected_thread); al_signal_cond(joyxi_disconnected_cond); al_join_thread(joyxi_disconnected_thread, &ret_value); /* clean it all up. */ al_destroy_thread(joyxi_disconnected_thread); al_destroy_cond(joyxi_disconnected_cond); al_destroy_thread(joyxi_thread); al_destroy_cond(joyxi_cond); al_lock_mutex(joyxi_mutex); /* Disable xinput */ _imp_XInputEnable(FALSE); /* Wipe the joystick structs */ for (index = 0; index < MAX_JOYSTICKS; index++) { joyxi_joysticks[index].active = false; } al_unlock_mutex(joyxi_mutex); al_destroy_mutex(joyxi_mutex); unload_xinput_module(); } static bool joyxi_reconfigure_joysticks(void) { int index; al_lock_mutex(joyxi_mutex); for (index = 0; index < MAX_JOYSTICKS; index++) { DWORD res = _imp_XInputGetCapabilities(joyxi_joysticks[index].index, 0, &joyxi_joysticks[index].capabilities); joyxi_joysticks[index].active = (res == ERROR_SUCCESS); if (joyxi_joysticks[index].active) { res = _imp_XInputGetState(joyxi_joysticks[index].index, &joyxi_joysticks[index].state); joyxi_joysticks[index].active = (res == ERROR_SUCCESS); } } al_unlock_mutex(joyxi_mutex); /** Signal the conditions so new events are sent immediately for the new joysticks. */ al_signal_cond(joyxi_cond); /** Signal the disconnected thread in case another joystick got connected. */ al_signal_cond(joyxi_disconnected_cond); return true; } static int joyxi_get_num_joysticks(void) { int result = 0, index; for (index = 0; index < MAX_JOYSTICKS; index++) { if (joyxi_joysticks[index].active) result++; } return result; } static ALLEGRO_JOYSTICK *joyxi_get_joystick(int num) { int al_number = 0, index; /* Use a linear scan, so the first active joystick ends up as the first * allegro joystick etc. */ for (index = 0; index < MAX_JOYSTICKS; index++) { if (joyxi_joysticks[index].active) { if (num == al_number) return &joyxi_joysticks[index].parent; else al_number++; } } return NULL; } static void joyxi_release_joystick(ALLEGRO_JOYSTICK *joy) { /* No need to do anything. */ (void)joy; } static void joyxi_get_joystick_state(ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state) { ALLEGRO_JOYSTICK_XINPUT *xjoy = (ALLEGRO_JOYSTICK_XINPUT *)joy; ASSERT(xjoy); ASSERT(ret_state); /* Copy the data with the mutex * locked to prevent changes during copying. */ al_lock_mutex(joyxi_mutex); (*ret_state) = xjoy->joystate; al_unlock_mutex(joyxi_mutex); } // Source: https://github.com/xan105/node-xinput-ffi/blob/master/lib/util/HardwareID.js static const char *joyxi_lookup_device_name(WORD vid, WORD pid) { if (vid == 0x045E) { switch (pid) { case 0x028E: return "Xbox360 Controller"; case 0x02A1: return "Xbox360 Controller"; case 0x028F: return "Xbox360 Wireless Controller"; case 0x02E0: return "Xbox One S Controller"; case 0x02FF: return "Xbox One Elite Controller"; case 0x0202: return "Xbox Controller"; case 0x0285: return "Xbox Controller S"; case 0x0289: return "Xbox Controller S"; case 0x02E3: return "Xbox One Elite Controller"; case 0x02EA: return "Xbox One S Controller"; case 0x02FD: return "Xbox One S Controller"; case 0x02D1: return "Xbox One Controller"; case 0x02DD: return "Xbox One Controller"; case 0x0B13: return "Xbox Series X/S controller"; } return "Microsoft Corp."; } if (vid == 0x054C) { switch (pid) { case 0x0268: return "DualShock 3 / Sixaxis"; case 0x05C4: return "DualShock 4"; case 0x09CC: return "DualShock 4 (v2)"; case 0x0BA0: return "DualShock 4 USB Wireless Adaptor"; case 0x0CE6: return "DualSense Wireless Controller"; //PS5 } return "Sony Corp."; } if (vid == 0x057E) { switch (pid) { case 0x0306: return "Wii Remote Controller"; case 0x0337: return "Wii U GameCube Controller Adapter"; case 0x2006: return "Joy-Con L"; case 0x2007: return "Joy-Con R"; case 0x2009: return "Switch Pro Controller"; case 0x200E: return "Joy-Con Charging Grip"; } return "Nintendo Co., Ltd"; } if (vid == 0x28DE) { switch (pid) { case 0x11FC: return "Steam Controller"; case 0x1102: return "Steam Controller"; case 0x1142: return "Wireless Steam Controller"; } return "Valve Corp."; } if (vid == 0x046D) { switch (pid) { case 0xC21D: return "Logitech Gamepad F310"; case 0xC21E: return "Logitech Gamepad F510"; case 0xC21F: return "Logitech Gamepad F710"; case 0xC242: return "Logitech Chillstream Controller"; } return "Logitech Inc."; } return ""; } static const char *joyxi_get_name(ALLEGRO_JOYSTICK *joy) { ALLEGRO_JOYSTICK_XINPUT *xjoy = (ALLEGRO_JOYSTICK_XINPUT *)joy; ASSERT(xjoy); if (xjoy->name[0] == '\0') { if (_imp_XInputGetCapabilitiesEx) { XINPUT_CAPABILITIES_EX xicapas; int res = _imp_XInputGetCapabilitiesEx(1, xjoy->index, 0, &xicapas); if (res == ERROR_SUCCESS) { const char *device_name = joyxi_lookup_device_name(xicapas.VendorId, xicapas.ProductId); if (device_name[0] != '\0') sprintf(xjoy->name, device_name); else sprintf(xjoy->name, "XInput Joystick vendor: %x product: %x", xicapas.VendorId, xicapas.ProductId); return xjoy->name; } } sprintf(xjoy->name, "XInput Joystick %d", xjoy->index); } return xjoy->name; } static bool joyxi_get_active(ALLEGRO_JOYSTICK *joy) { ALLEGRO_JOYSTICK_XINPUT *xjoy = (ALLEGRO_JOYSTICK_XINPUT *)joy; ASSERT(xjoy); return xjoy->active; } #endif /* #ifdef ALLEGRO_CFG_XINPUT */ allegro5-5.2.10.1/src/win/wkeyboard.c000066400000000000000000000443501473414355200172050ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows keyboard driver. * * By Milan Mimica. * * See readme.txt for copyright information. * */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_driver.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/platform/aintwin.h" /* Missing from MSVC 2005 headers. */ #ifndef MAPVK_VSC_TO_VK_EX #define MAPVK_VSC_TO_VK_EX 3 #endif static bool installed = false; static ALLEGRO_KEYBOARD the_keyboard; static ALLEGRO_KEYBOARD_STATE the_state; static int modifiers = 0; /* lookup table for converting virtualkey VK_* codes into Allegro ALLEGRO_KEY_* codes */ /* For handling of extended keys, extkey_to_keycode() takes priority over this. */ /* Last unknown key sequence: 39*/ static const unsigned char hw_to_mycode[256] = { /* 0x00 */ 0, ALLEGRO_KEY_UNKNOWN+0, ALLEGRO_KEY_UNKNOWN+1, ALLEGRO_KEY_UNKNOWN+2, /* 0x04 */ ALLEGRO_KEY_UNKNOWN+3, ALLEGRO_KEY_UNKNOWN+4, ALLEGRO_KEY_UNKNOWN+5, 0, /* 0x08 */ ALLEGRO_KEY_BACKSPACE, ALLEGRO_KEY_TAB, 0, 0, /* 0x0C */ ALLEGRO_KEY_PAD_5, ALLEGRO_KEY_ENTER, 0, 0, /* 0x10 */ 0/*L or R shift*/, ALLEGRO_KEY_LCTRL, ALLEGRO_KEY_ALT, ALLEGRO_KEY_PAUSE, /* 0x14 */ ALLEGRO_KEY_CAPSLOCK, ALLEGRO_KEY_KANA, 0, ALLEGRO_KEY_UNKNOWN+6, /* 0x18 */ ALLEGRO_KEY_UNKNOWN+7, ALLEGRO_KEY_KANJI, 0, ALLEGRO_KEY_ESCAPE, /* 0x1C */ ALLEGRO_KEY_CONVERT, ALLEGRO_KEY_NOCONVERT, ALLEGRO_KEY_UNKNOWN+8, ALLEGRO_KEY_UNKNOWN+9, /* 0x20 */ ALLEGRO_KEY_SPACE, ALLEGRO_KEY_PAD_9, ALLEGRO_KEY_PAD_3, ALLEGRO_KEY_PAD_1, /* 0x24 */ ALLEGRO_KEY_PAD_7, ALLEGRO_KEY_PAD_4, ALLEGRO_KEY_PAD_8, ALLEGRO_KEY_PAD_6, /* 0x28 */ ALLEGRO_KEY_PAD_2, ALLEGRO_KEY_UNKNOWN+10, ALLEGRO_KEY_UNKNOWN+11, ALLEGRO_KEY_UNKNOWN+12, /* 0x2C */ ALLEGRO_KEY_PRINTSCREEN, ALLEGRO_KEY_PAD_0, ALLEGRO_KEY_PAD_DELETE, ALLEGRO_KEY_UNKNOWN+13, /* 0x30 */ ALLEGRO_KEY_0, ALLEGRO_KEY_1, ALLEGRO_KEY_2, ALLEGRO_KEY_3, /* 0x34 */ ALLEGRO_KEY_4, ALLEGRO_KEY_5, ALLEGRO_KEY_6, ALLEGRO_KEY_7, /* 0x38 */ ALLEGRO_KEY_8, ALLEGRO_KEY_9, 0, 0, /* 0x3C */ 0, 0, 0, 0, /* 0x40 */ 0, ALLEGRO_KEY_A, ALLEGRO_KEY_B, ALLEGRO_KEY_C, /* 0x44 */ ALLEGRO_KEY_D, ALLEGRO_KEY_E, ALLEGRO_KEY_F, ALLEGRO_KEY_G, /* 0x48 */ ALLEGRO_KEY_H, ALLEGRO_KEY_I, ALLEGRO_KEY_J, ALLEGRO_KEY_K, /* 0x4C */ ALLEGRO_KEY_L, ALLEGRO_KEY_M, ALLEGRO_KEY_N, ALLEGRO_KEY_O, /* 0x50 */ ALLEGRO_KEY_P, ALLEGRO_KEY_Q, ALLEGRO_KEY_R, ALLEGRO_KEY_S, /* 0x54 */ ALLEGRO_KEY_T, ALLEGRO_KEY_U, ALLEGRO_KEY_V, ALLEGRO_KEY_W, /* 0x58 */ ALLEGRO_KEY_X, ALLEGRO_KEY_Y, ALLEGRO_KEY_Z, ALLEGRO_KEY_LWIN, /* 0x5C */ ALLEGRO_KEY_RWIN, ALLEGRO_KEY_MENU, 0, 0, /* 0x60 */ ALLEGRO_KEY_PAD_0, ALLEGRO_KEY_PAD_1, ALLEGRO_KEY_PAD_2, ALLEGRO_KEY_PAD_3, /* 0x64 */ ALLEGRO_KEY_PAD_4, ALLEGRO_KEY_PAD_5, ALLEGRO_KEY_PAD_6, ALLEGRO_KEY_PAD_7, /* 0x68 */ ALLEGRO_KEY_PAD_8, ALLEGRO_KEY_PAD_9, ALLEGRO_KEY_PAD_ASTERISK, ALLEGRO_KEY_PAD_PLUS, /* 0x6C */ ALLEGRO_KEY_UNKNOWN+15, ALLEGRO_KEY_PAD_MINUS, ALLEGRO_KEY_PAD_DELETE, ALLEGRO_KEY_PAD_SLASH, /* 0x70 */ ALLEGRO_KEY_F1, ALLEGRO_KEY_F2, ALLEGRO_KEY_F3, ALLEGRO_KEY_F4, /* 0x74 */ ALLEGRO_KEY_F5, ALLEGRO_KEY_F6, ALLEGRO_KEY_F7, ALLEGRO_KEY_F8, /* 0x78 */ ALLEGRO_KEY_F9, ALLEGRO_KEY_F10, ALLEGRO_KEY_F11, ALLEGRO_KEY_F12, /* 0x7C */ ALLEGRO_KEY_UNKNOWN+17, ALLEGRO_KEY_UNKNOWN+18, ALLEGRO_KEY_UNKNOWN+19, ALLEGRO_KEY_UNKNOWN+20, /* 0x80 */ ALLEGRO_KEY_UNKNOWN+21, ALLEGRO_KEY_UNKNOWN+22, ALLEGRO_KEY_UNKNOWN+23, ALLEGRO_KEY_UNKNOWN+24, /* 0x84 */ ALLEGRO_KEY_UNKNOWN+25, ALLEGRO_KEY_UNKNOWN+26, ALLEGRO_KEY_UNKNOWN+27, ALLEGRO_KEY_UNKNOWN+28, /* 0x88 */ 0, 0, 0, 0, /* 0x8C */ 0, 0, 0, 0, /* 0x90 */ ALLEGRO_KEY_NUMLOCK, ALLEGRO_KEY_SCROLLLOCK, 0, 0, /* 0x94 */ 0, 0, 0, 0, /* 0x98 */ 0, 0, 0, 0, /* 0x9C */ 0, 0, 0, 0, /* 0xA0 */ ALLEGRO_KEY_LSHIFT, ALLEGRO_KEY_RSHIFT, ALLEGRO_KEY_LCTRL, ALLEGRO_KEY_RCTRL, /* 0xA4 */ ALLEGRO_KEY_ALT, ALLEGRO_KEY_ALTGR, 0, 0, /* 0xA8 */ 0, 0, 0, 0, /* 0xAC */ 0, 0, 0, 0, /* 0xB0 */ 0, 0, 0, 0, /* 0xB4 */ 0, 0, 0, 0, /* 0xB8 */ 0, 0, ALLEGRO_KEY_SEMICOLON, ALLEGRO_KEY_EQUALS, /* 0xBC */ ALLEGRO_KEY_COMMA, ALLEGRO_KEY_MINUS, ALLEGRO_KEY_FULLSTOP, ALLEGRO_KEY_SLASH, /* 0xC0 */ ALLEGRO_KEY_TILDE, 0, 0, 0, /* 0xC4 */ 0, 0, 0, 0, /* 0xC8 */ 0, 0, 0, 0, /* 0xCC */ 0, 0, 0, 0, /* 0xD0 */ 0, 0, 0, 0, /* 0xD4 */ 0, 0, 0, 0, /* 0xD8 */ 0, 0, 0, ALLEGRO_KEY_OPENBRACE, /* 0xDC */ ALLEGRO_KEY_BACKSLASH, ALLEGRO_KEY_CLOSEBRACE, ALLEGRO_KEY_QUOTE, 0, /* 0xE0 */ 0, 0, ALLEGRO_KEY_BACKSLASH2, 0, /* 0xE4 */ 0, ALLEGRO_KEY_UNKNOWN+29, 0, 0, /* 0xE8 */ 0, 0, 0, 0, /* 0xEC */ 0, 0, 0, 0, /* 0xF0 */ 0, 0, 0, 0, /* 0xF4 */ 0, 0, ALLEGRO_KEY_UNKNOWN+30, ALLEGRO_KEY_UNKNOWN+31, /* 0xF8 */ ALLEGRO_KEY_UNKNOWN+32, ALLEGRO_KEY_UNKNOWN+33, ALLEGRO_KEY_UNKNOWN+34, ALLEGRO_KEY_UNKNOWN+35, /* 0xFC */ ALLEGRO_KEY_UNKNOWN+36, ALLEGRO_KEY_UNKNOWN+37, ALLEGRO_KEY_UNKNOWN+38, 0 }; /* forward declarations */ static bool init_keyboard(void); static void exit_keyboard(void); static void get_keyboard_state(ALLEGRO_KEYBOARD_STATE *ret_state); static void clear_keyboard_state(void); static ALLEGRO_KEYBOARD *get_keyboard(void); /* the driver vtable */ #define KEYBOARD_WINAPI AL_ID('W','A','P','I') static ALLEGRO_KEYBOARD_DRIVER keyboard_winapi = { KEYBOARD_WINAPI, 0, 0, "WinAPI keyboard", init_keyboard, exit_keyboard, get_keyboard, NULL, /* bool set_leds(int leds) */ NULL, /* const char* keycode_to_name(int keycode)*/ get_keyboard_state, clear_keyboard_state, }; /* list the available drivers */ _AL_DRIVER_INFO _al_keyboard_driver_list[] = { { KEYBOARD_WINAPI, &keyboard_winapi, true }, { 0, NULL, 0 } }; /* init_keyboard: * Initialise the keyboard driver. */ static bool init_keyboard(void) { memset(&the_keyboard, 0, sizeof the_keyboard); memset(&the_state, 0, sizeof the_state); modifiers = 0; /* Initialise the keyboard object for use as an event source. */ _al_event_source_init(&the_keyboard.es); installed = true; return true; } /* exit_keyboard: * Shut down the keyboard driver. */ static void exit_keyboard(void) { _al_event_source_free(&the_keyboard.es); /* This may help catch bugs in the user program, since the pointer * we return to the user is always the same. */ memset(&the_keyboard, 0, sizeof the_keyboard); installed = false; } /* _al_win_fix_modifiers: * Fix the modifiers. */ void _al_win_fix_modifiers(void) { modifiers = 0; } /* get_keyboard: * Returns the address of a ALLEGRO_KEYBOARD structure representing the keyboard. */ static ALLEGRO_KEYBOARD *get_keyboard(void) { return &the_keyboard; } /* get_keyboard_state: * Copy the current keyboard state into RET_STATE. */ static void get_keyboard_state(ALLEGRO_KEYBOARD_STATE *ret_state) { unsigned int i; ALLEGRO_DISPLAY *disp = NULL; ALLEGRO_SYSTEM *sys; sys = al_get_system_driver(); for (i = 0; i < sys->displays._size; i++) { ALLEGRO_DISPLAY_WIN **d = (void*)_al_vector_ref(&sys->displays, i); if ((*d)->window == GetForegroundWindow()) { disp = (void*)*d; break; } } the_state.display = disp; *ret_state = the_state; } /* clear_keyboard_state: * Clear the current keyboard state. */ static void clear_keyboard_state(void) { memset(&the_state, 0, sizeof(the_state)); } /* extkey_to_keycode: * Given a VK code, returns the Allegro keycode for the corresponding extended * key. If no code is found, returns zero. */ static int extkey_to_keycode(int vcode) { switch (vcode) { /* These are ordered by VK value, lowest first. */ case VK_CANCEL: return ALLEGRO_KEY_PAUSE; case VK_RETURN: return ALLEGRO_KEY_PAD_ENTER; case VK_CONTROL: return ALLEGRO_KEY_RCTRL; case VK_MENU: return ALLEGRO_KEY_ALTGR; case VK_PRIOR: return ALLEGRO_KEY_PGUP; case VK_NEXT: return ALLEGRO_KEY_PGDN; case VK_END: return ALLEGRO_KEY_END; case VK_HOME: return ALLEGRO_KEY_HOME; case VK_LEFT: return ALLEGRO_KEY_LEFT; case VK_UP: return ALLEGRO_KEY_UP; case VK_RIGHT: return ALLEGRO_KEY_RIGHT; case VK_DOWN: return ALLEGRO_KEY_DOWN; case VK_SNAPSHOT: return ALLEGRO_KEY_PRINTSCREEN; case VK_INSERT: return ALLEGRO_KEY_INSERT; case VK_DELETE: return ALLEGRO_KEY_DELETE; case VK_LWIN: return ALLEGRO_KEY_LWIN; case VK_RWIN: return ALLEGRO_KEY_RWIN; case VK_APPS: return ALLEGRO_KEY_MENU; case VK_DIVIDE: return ALLEGRO_KEY_PAD_SLASH; case VK_NUMLOCK: return ALLEGRO_KEY_NUMLOCK; default: return 0; } } static void update_modifiers(int code, bool pressed) { #define ON_OFF2(code) \ { \ if (!pressed) \ modifiers &= ~code; \ else \ modifiers |= code; \ break; \ } switch (code) { case ALLEGRO_KEY_LSHIFT: ON_OFF2(ALLEGRO_KEYMOD_SHIFT); case ALLEGRO_KEY_RSHIFT: ON_OFF2(ALLEGRO_KEYMOD_SHIFT); case ALLEGRO_KEY_RCTRL: ON_OFF2(ALLEGRO_KEYMOD_CTRL); case ALLEGRO_KEY_LCTRL: ON_OFF2(ALLEGRO_KEYMOD_CTRL); case ALLEGRO_KEY_ALT: ON_OFF2(ALLEGRO_KEYMOD_ALT); case ALLEGRO_KEY_ALTGR: ON_OFF2(ALLEGRO_KEYMOD_ALTGR); case ALLEGRO_KEY_LWIN: ON_OFF2(ALLEGRO_KEYMOD_LWIN); case ALLEGRO_KEY_RWIN: ON_OFF2(ALLEGRO_KEYMOD_RWIN); case ALLEGRO_KEY_MENU: ON_OFF2(ALLEGRO_KEYMOD_MENU); } #undef ON_OFF2 } /* update_toggle_modifiers: * Update the state of Num Lock, Caps Lock, and Scroll Lock. */ static void update_toggle_modifiers(void) { #define ON_OFF(code, on) \ { \ if (on) \ modifiers |= code; \ else \ modifiers &= ~code; \ } /* GetKeyState appears to be the only reliable way of doing this. GetKeyboardState * is updated a bit too late in some cases. Maybe it would work if WM_CHARs were * used, since they arrive after the WM_KEYDOWNs that trigger them. */ ON_OFF(ALLEGRO_KEYMOD_NUMLOCK, GetKeyState(VK_NUMLOCK) & 1); ON_OFF(ALLEGRO_KEYMOD_CAPSLOCK, GetKeyState(VK_CAPITAL) & 1); ON_OFF(ALLEGRO_KEYMOD_SCROLLLOCK, GetKeyState(VK_SCROLL) & 1); #undef ON_OFF } /* _al_win_kbd_handle_key_press: * Does stuff when a key is pressed. */ void _al_win_kbd_handle_key_press(int scode, int vcode, bool extended, bool repeated, ALLEGRO_DISPLAY_WIN *win_disp) { ALLEGRO_DISPLAY *display = (ALLEGRO_DISPLAY *)win_disp; ALLEGRO_EVENT event; int my_code; bool actual_repeat; int char_count; int event_count; int i; BYTE ks[256]; WCHAR buf[8] = { 0 }; if (!installed) return; /* Check for an extended key first. */ my_code = 0; if (extended) my_code = extkey_to_keycode(vcode); /* Map a non-extended key. This also works as a fallback in case the key was extended, but no extended mapping was found. */ if (my_code == 0) { if (vcode == VK_SHIFT) /* Left or right Shift key? */ vcode = MapVirtualKey(scode, MAPVK_VSC_TO_VK_EX); my_code = hw_to_mycode[vcode]; } update_modifiers(my_code, true); actual_repeat = repeated && _AL_KEYBOARD_STATE_KEY_DOWN(the_state, my_code); _AL_KEYBOARD_STATE_SET_KEY_DOWN(the_state, my_code); if (!_al_event_source_needs_to_generate_event(&the_keyboard.es)) return; event.keyboard.type = ALLEGRO_EVENT_KEY_DOWN; event.keyboard.timestamp = al_get_time(); event.keyboard.display = display; event.keyboard.keycode = my_code; event.keyboard.unichar = 0; update_toggle_modifiers(); event.keyboard.modifiers = modifiers; event.keyboard.repeat = false; _al_event_source_lock(&the_keyboard.es); if (my_code > 0 && !actual_repeat) { _al_event_source_emit_event(&the_keyboard.es, &event); } /* Send char events, but not for modifier keys or dead keys. */ if (my_code < ALLEGRO_KEY_MODIFIERS) { char_count = ToUnicode(vcode, scode, GetKeyboardState(ks) ? ks : NULL, buf, 8, 0); /* Send ASCII code 127 for both Del keys. */ if (char_count == 0 && vcode == VK_DELETE) { char_count = 1; buf[0] = 127; } if (char_count != -1) { /* -1 means it was a dead key. */ event_count = char_count ? char_count : 1; event.keyboard.type = ALLEGRO_EVENT_KEY_CHAR; update_toggle_modifiers(); event.keyboard.modifiers = modifiers; event.keyboard.repeat = actual_repeat; for (i = 0; i < event_count; i++) { event.keyboard.unichar = buf[i]; _al_event_source_emit_event(&the_keyboard.es, &event); } } } _al_event_source_unlock(&the_keyboard.es); /* Toggle mouse grab key. */ if (my_code && !repeated) { ALLEGRO_SYSTEM_WIN *system = (void *)al_get_system_driver(); if (system->toggle_mouse_grab_keycode && my_code == system->toggle_mouse_grab_keycode && (modifiers & system->toggle_mouse_grab_modifiers) == system->toggle_mouse_grab_modifiers) { if (system->mouse_grab_display == display) { al_ungrab_mouse(); } else { al_grab_mouse(display); } } } } /* _al_win_kbd_handle_key_release: * Does stuff when a key is released. */ void _al_win_kbd_handle_key_release(int scode, int vcode, bool extended, ALLEGRO_DISPLAY_WIN *win_disp) { ALLEGRO_EVENT event; int my_code; if (!installed) return; my_code = 0; if (extended) my_code = extkey_to_keycode(vcode); if (my_code == 0) { if (vcode == VK_SHIFT) vcode = MapVirtualKey(scode, MAPVK_VSC_TO_VK_EX); my_code = hw_to_mycode[vcode]; } update_modifiers(my_code, false); _AL_KEYBOARD_STATE_CLEAR_KEY_DOWN(the_state, my_code); /* Windows only sends a WM_KEYUP message for the Shift keys when both have been released. If one of the Shift keys is still reported as down, we need to release it as well. */ if (my_code == ALLEGRO_KEY_LSHIFT && _AL_KEYBOARD_STATE_KEY_DOWN(the_state, ALLEGRO_KEY_RSHIFT)) _al_win_kbd_handle_key_release(scode, VK_RSHIFT, extended, win_disp); else if (my_code == ALLEGRO_KEY_RSHIFT && _AL_KEYBOARD_STATE_KEY_DOWN(the_state, ALLEGRO_KEY_LSHIFT)) _al_win_kbd_handle_key_release(scode, VK_LSHIFT, extended, win_disp); if (!_al_event_source_needs_to_generate_event(&the_keyboard.es)) return; event.keyboard.type = ALLEGRO_EVENT_KEY_UP; event.keyboard.timestamp = al_get_time(); event.keyboard.display = (void*)win_disp; event.keyboard.keycode = my_code; event.keyboard.unichar = 0; update_toggle_modifiers(); event.keyboard.modifiers = modifiers; _al_event_source_lock(&the_keyboard.es); _al_event_source_emit_event(&the_keyboard.es, &event); _al_event_source_unlock(&the_keyboard.es); } /* * Local Variables: * c-basic-offset: 3 * indent-tabs-mode: nil * End: */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/wmcursor.c000066400000000000000000000327021473414355200170750ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows mouse cursors. * * By Evert Glebbeek. * * Adapted for Allegro 4.9 by Peter Wang. * * GDI code adapted from src/win/gdi.c. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/platform/aintwin.h" static void local_stretch_blit_to_hdc(ALLEGRO_BITMAP *bitmap, HDC dc, int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, int dest_w, int dest_h); static void local_draw_to_hdc(HDC dc, ALLEGRO_BITMAP *bitmap, int x, int y); HICON _al_win_create_icon(HWND wnd, ALLEGRO_BITMAP *sprite, int xfocus, int yfocus, bool is_cursor, bool resize) { int x, y; int sys_sm_cx, sys_sm_cy; HDC h_dc; HDC h_and_dc; HDC h_xor_dc; ICONINFO iconinfo; HBITMAP and_mask; HBITMAP xor_mask; HBITMAP hOldAndMaskBitmap; HBITMAP hOldXorMaskBitmap; HICON icon; bool was_locked; ALLEGRO_BITMAP *tmp = sprite; if (resize) { if (is_cursor) { /* Get allowed cursor size - Windows can't make cursors of arbitrary size */ sys_sm_cx = GetSystemMetrics(SM_CXCURSOR); sys_sm_cy = GetSystemMetrics(SM_CYCURSOR); } else { sys_sm_cx = GetSystemMetrics(SM_CXICON); sys_sm_cy = GetSystemMetrics(SM_CYICON); } if ((tmp->w > sys_sm_cx) || (tmp->h > sys_sm_cy)) { float ratio = tmp->w / (float)tmp->h; int w, h; ALLEGRO_STATE state; if (ratio > 1) { w = sys_sm_cx; h = sys_sm_cy / ratio; } else { w = sys_sm_cx * ratio; h = sys_sm_cy; } al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP | ALLEGRO_STATE_BLENDER); tmp = _al_create_bitmap_params(al_get_current_display(), w, h, al_get_bitmap_format(tmp), ALLEGRO_MEMORY_BITMAP, 0, 0); al_set_target_bitmap(tmp); al_clear_to_color(al_map_rgba_f(0, 0, 0, 0)); al_draw_scaled_bitmap( sprite, 0, 0, sprite->w, sprite->h, 0, 0, w, h, 0 ); al_restore_state(&state); } } else { sys_sm_cx = al_get_bitmap_width(tmp); sys_sm_cy = al_get_bitmap_height(tmp); } /* Create bitmap */ h_dc = GetDC(wnd); h_xor_dc = CreateCompatibleDC(h_dc); h_and_dc = CreateCompatibleDC(h_dc); /* Prepare AND (monochrome) and XOR (colour) mask */ and_mask = CreateBitmap(sys_sm_cx, sys_sm_cy, 1, 1, NULL); xor_mask = CreateCompatibleBitmap(h_dc, sys_sm_cx, sys_sm_cy); hOldAndMaskBitmap = (HBITMAP) SelectObject(h_and_dc, and_mask); hOldXorMaskBitmap = (HBITMAP) SelectObject(h_xor_dc, xor_mask); /* Create transparent cursor */ for (y = 0; y < sys_sm_cy; y++) { for (x = 0; x < sys_sm_cx; x++) { SetPixel(h_and_dc, x, y, WINDOWS_RGB(255, 255, 255)); SetPixel(h_xor_dc, x, y, WINDOWS_RGB(0, 0, 0)); } } /* Lock sprite to speed up repeated get pixel calls. */ was_locked = al_is_bitmap_locked(tmp); if (!was_locked) { al_lock_bitmap(tmp, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); } local_draw_to_hdc(h_xor_dc, tmp, 0, 0); /* Make cursor background transparent */ for (y = 0; y < tmp->h; y++) { for (x = 0; x < tmp->w; x++) { ALLEGRO_COLOR c; unsigned char r, g, b, a; c = al_get_pixel(tmp, x, y); al_unmap_rgba(c, &r, &g, &b, &a); if (a != 0) { /* Don't touch XOR value */ SetPixel(h_and_dc, x, y, 0); } else { /* No need to touch AND value */ SetPixel(h_xor_dc, x, y, WINDOWS_RGB(0, 0, 0)); } } } if (!was_locked) { al_unlock_bitmap(tmp); } SelectObject(h_and_dc, hOldAndMaskBitmap); SelectObject(h_xor_dc, hOldXorMaskBitmap); DeleteDC(h_and_dc); DeleteDC(h_xor_dc); ReleaseDC(wnd, h_dc); iconinfo.fIcon = is_cursor ? false : true; iconinfo.xHotspot = xfocus; iconinfo.yHotspot = yfocus; iconinfo.hbmMask = and_mask; iconinfo.hbmColor = xor_mask; icon = CreateIconIndirect(&iconinfo); DeleteObject(and_mask); DeleteObject(xor_mask); if (sprite != tmp) { al_destroy_bitmap(tmp); } return icon; } ALLEGRO_MOUSE_CURSOR *_al_win_create_mouse_cursor(ALLEGRO_BITMAP *sprite, int xfocus, int yfocus) { HWND wnd; HCURSOR hcursor; ALLEGRO_MOUSE_CURSOR_WIN *win_cursor; /* A null HWND retrieves the DC for the entire screen. */ wnd = NULL; hcursor = (HCURSOR)_al_win_create_icon(wnd, sprite, xfocus, yfocus, true, true); if (!hcursor) { return NULL; } win_cursor = al_malloc(sizeof *win_cursor); if (!win_cursor) { DestroyIcon(hcursor); return NULL; } win_cursor->hcursor = hcursor; return (ALLEGRO_MOUSE_CURSOR *)win_cursor; } void _al_win_destroy_mouse_cursor(ALLEGRO_MOUSE_CURSOR *cursor) { ALLEGRO_MOUSE_CURSOR_WIN *win_cursor = (ALLEGRO_MOUSE_CURSOR_WIN *) cursor; ALLEGRO_SYSTEM *sys = al_get_system_driver(); unsigned i; ASSERT(win_cursor); /* XXX not at all thread safe */ for (i = 0; i < _al_vector_size(&sys->displays); i++) { ALLEGRO_DISPLAY_WIN **slot = _al_vector_ref(&sys->displays, i); ALLEGRO_DISPLAY_WIN *win_display = *slot; if (win_cursor->hcursor == win_display->mouse_selected_hcursor) { _al_win_set_system_mouse_cursor((ALLEGRO_DISPLAY *)win_display, ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW); } } DestroyIcon(win_cursor->hcursor); al_free(win_cursor); } bool _al_win_set_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_MOUSE_CURSOR *cursor) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *) display; ALLEGRO_MOUSE_CURSOR_WIN *win_cursor = (ALLEGRO_MOUSE_CURSOR_WIN *) cursor; ASSERT(win_cursor); ASSERT(win_cursor->hcursor); win_display->mouse_selected_hcursor = win_cursor->hcursor; if (win_display->mouse_cursor_shown) { POINT p; SetCursor(win_cursor->hcursor); /* Windows is too stupid to actually display the mouse pointer when we * change it and waits until it is moved, so we have to generate a fake * mouse move to actually show the cursor. */ GetCursorPos(&p); SetCursorPos(p.x, p.y); } return true; } bool _al_win_show_mouse_cursor(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *) display; ALLEGRO_MOUSE_CURSOR_WIN tmp_cursor; ALLEGRO_MOUSE_CURSOR_WIN *tmp_cursor_ptr = &tmp_cursor; /* XXX do we need this? */ if (!win_display->mouse_selected_hcursor) { _al_win_set_system_mouse_cursor(display, ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW); } tmp_cursor.hcursor = win_display->mouse_selected_hcursor; win_display->mouse_cursor_shown = true; win_display->hide_mouse_on_move = false; _al_win_set_mouse_cursor(display, (ALLEGRO_MOUSE_CURSOR *)tmp_cursor_ptr); return true; } bool _al_win_hide_mouse_cursor(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *) display; win_display->mouse_cursor_shown = false; PostMessage(win_display->window, WM_SETCURSOR, 0, 0); return true; } static HCURSOR system_cursor_to_hcursor(ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id) { switch (cursor_id) { case ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT: case ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW: return LoadCursor(NULL, IDC_ARROW); case ALLEGRO_SYSTEM_MOUSE_CURSOR_BUSY: return LoadCursor(NULL, IDC_WAIT); case ALLEGRO_SYSTEM_MOUSE_CURSOR_QUESTION: return LoadCursor(NULL, IDC_HELP); case ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT: return LoadCursor(NULL, IDC_IBEAM); case ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE: return LoadCursor(NULL, IDC_SIZEALL); case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N: case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_S: return LoadCursor(NULL, IDC_SIZENS); case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E: case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_W: return LoadCursor(NULL, IDC_SIZEWE); case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE: case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_SW: return LoadCursor(NULL, IDC_SIZENESW); case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW: case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_SE: return LoadCursor(NULL, IDC_SIZENWSE); case ALLEGRO_SYSTEM_MOUSE_CURSOR_PROGRESS: return LoadCursor(NULL, IDC_APPSTARTING); case ALLEGRO_SYSTEM_MOUSE_CURSOR_PRECISION: return LoadCursor(NULL, IDC_CROSS); case ALLEGRO_SYSTEM_MOUSE_CURSOR_LINK: return LoadCursor(NULL, IDC_HAND); case ALLEGRO_SYSTEM_MOUSE_CURSOR_ALT_SELECT: return LoadCursor(NULL, IDC_UPARROW); case ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE: return LoadCursor(NULL, IDC_NO); default: return NULL; } } bool _al_win_set_system_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *) display; HCURSOR wc; wc = system_cursor_to_hcursor(cursor_id); if (!wc) { return false; } win_display->mouse_selected_hcursor = wc; if (win_display->mouse_cursor_shown) { /* MySetCursor(wc); PostMessage(wgl_display->window, WM_MOUSEMOVE, 0, 0); */ ALLEGRO_MOUSE_CURSOR_WIN tmp_cursor; ALLEGRO_MOUSE_CURSOR_WIN *tmp_cursor_ptr = &tmp_cursor; tmp_cursor.hcursor = wc; _al_win_set_mouse_cursor(display, (ALLEGRO_MOUSE_CURSOR *)tmp_cursor_ptr); } return true; } /* GDI stuff - this really belongs elsewhere */ /* get_bitmap_info: * Returns a BITMAPINFO structure suited to an ALLEGRO_BITMAP. * You have to free the memory allocated by this function. * * This version always returns a 32-bit BITMAPINFO. */ static BITMAPINFO *get_bitmap_info(ALLEGRO_BITMAP *bitmap) { BITMAPINFO *bi; int i; bi = (BITMAPINFO *) al_malloc(sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 256); ZeroMemory(&bi->bmiHeader, sizeof(BITMAPINFOHEADER)); bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi->bmiHeader.biBitCount = 32; bi->bmiHeader.biPlanes = 1; bi->bmiHeader.biWidth = al_get_bitmap_width(bitmap); bi->bmiHeader.biHeight = -al_get_bitmap_height(bitmap); bi->bmiHeader.biClrUsed = 256; bi->bmiHeader.biCompression = BI_RGB; for (i = 0; i < 256; i++) { bi->bmiColors[i].rgbRed = 0; bi->bmiColors[i].rgbGreen = 0; bi->bmiColors[i].rgbBlue = 0; bi->bmiColors[i].rgbReserved = 0; } return bi; } /* get_dib_from_bitmap_32: * Creates a Windows device-independent bitmap (DIB) from an Allegro BITMAP. * You have to free the memory allocated by this function. * * This version always creates a 32-bit DIB. */ static BYTE *get_dib_from_bitmap_32(ALLEGRO_BITMAP *bitmap) { int w, h; int x, y; int pitch; BYTE *pixels; BYTE *dst; w = al_get_bitmap_width(bitmap); h = al_get_bitmap_height(bitmap); pitch = w * 4; pixels = (BYTE *) al_malloc(h * pitch); if (!pixels) return NULL; for (y = 0; y < h; y++) { dst = pixels + y * pitch; for (x = 0; x < w; x++) { ALLEGRO_COLOR col; unsigned char r, g, b, a; col = al_get_pixel(bitmap, x, y); al_unmap_rgba(col, &r, &g, &b, &a); /* BGR */ dst[0] = b; dst[1] = g; dst[2] = r; dst[3] = a; dst += 4; } } return pixels; } /* draw_to_hdc: * Draws an entire Allegro BITMAP to a Windows DC. Has a syntax similar to * draw_sprite(). */ static void local_draw_to_hdc(HDC dc, ALLEGRO_BITMAP *bitmap, int x, int y) { int w = al_get_bitmap_width(bitmap); int h = al_get_bitmap_height(bitmap); local_stretch_blit_to_hdc(bitmap, dc, 0, 0, w, h, x, y, w, h); } /* stretch_blit_to_hdc: * Blits an Allegro BITMAP to a Windows DC. Has a syntax similar to * stretch_blit(). */ static void local_stretch_blit_to_hdc(ALLEGRO_BITMAP *bitmap, HDC dc, int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, int dest_w, int dest_h) { const int bitmap_h = al_get_bitmap_height(bitmap); const int bottom_up_src_y = bitmap_h - src_y - src_h; BYTE *pixels; BITMAPINFO *bi; bi = get_bitmap_info(bitmap); pixels = get_dib_from_bitmap_32(bitmap); /* Windows treats all source bitmaps as bottom-up when using StretchDIBits * unless the source (x,y) is (0,0). To work around this buggy behavior, we * can use negative heights to reverse the direction of the blits. * * See for a detailed explanation. */ if (bottom_up_src_y == 0 && src_x == 0 && src_h != bitmap_h) { StretchDIBits(dc, dest_x, dest_h+dest_y-1, dest_w, -dest_h, src_x, bitmap_h - src_y + 1, src_w, -src_h, pixels, bi, DIB_RGB_COLORS, SRCCOPY); } else { StretchDIBits(dc, dest_x, dest_y, dest_w, dest_h, src_x, bottom_up_src_y, src_w, src_h, pixels, bi, DIB_RGB_COLORS, SRCCOPY); } al_free(pixels); al_free(bi); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/wmouse.c000066400000000000000000000226361473414355200165400ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows mouse driver. * * By Milan Mimica. * * See readme.txt for copyright information. */ #if 0 /* Raw input */ #define _WIN32_WINNT 0x0501 #ifndef WINVER #define WINVER 0x0600 #endif #endif #include /* * Even the most recent MinGW at the moment of writing this is missing * this symbol. */ #ifndef SM_MOUSEHORIZONTALWHEELPRESENT #define SM_MOUSEHORIZONTALWHEELPRESENT 91 #endif #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_driver.h" #include "allegro5/internal/aintern_mouse.h" #include "allegro5/platform/aintwin.h" #include "allegro5/internal/aintern_display.h" static ALLEGRO_MOUSE_STATE mouse_state; static ALLEGRO_MOUSE the_mouse; static bool installed = false; // The raw versions of z/w in the mouse_state. They are related to them by a scaling constant. static int raw_mouse_z = 0; static int raw_mouse_w = 0; static bool init_mouse(void) { ALLEGRO_DISPLAY *display; if (installed) return false; /* If the display was created before the mouse is installed and the mouse * cursor is initially within the window, then the display field has correct * and useful info so don't clobber it. */ display = mouse_state.display; memset(&mouse_state, 0, sizeof(mouse_state)); mouse_state.display = display; _al_event_source_init(&the_mouse.es); #if 0 if (al_get_new_display_flags() & ALLEGRO_FULLSCREEN) { RAWINPUTDEVICE rid[1]; rid[0].usUsagePage = 0x01; rid[0].usUsage = 0x02; rid[0].dwFlags = RIDEV_NOLEGACY; rid[0].hwndTarget = 0; if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == FALSE) { return false; } } #endif installed = true; return true; } static void exit_mouse(void) { if (!installed) return; memset(&mouse_state, 0, sizeof(mouse_state)); _al_event_source_free(&the_mouse.es); installed = false; } static void generate_mouse_event(unsigned int type, int x, int y, int z, int w, float pressure, int dx, int dy, int dz, int dw, unsigned int button, ALLEGRO_DISPLAY *source) { ALLEGRO_EVENT event; if (!_al_event_source_needs_to_generate_event(&the_mouse.es)) return; _al_event_source_lock(&the_mouse.es); event.mouse.type = type; event.mouse.timestamp = al_get_time(); event.mouse.display = source; event.mouse.x = x; event.mouse.y = y; event.mouse.z = z; event.mouse.w = w; event.mouse.dx = dx; event.mouse.dy = dy; event.mouse.dz = dz; event.mouse.dw = dw; event.mouse.button = button; event.mouse.pressure = pressure; _al_event_source_emit_event(&the_mouse.es, &event); _al_event_source_unlock(&the_mouse.es); } static ALLEGRO_MOUSE* get_mouse(void) { return &the_mouse; } static unsigned int get_num_buttons(void) { return GetSystemMetrics(SM_CMOUSEBUTTONS); } static unsigned int get_num_axes(void) { bool x = GetSystemMetrics(SM_MOUSEHORIZONTALWHEELPRESENT); bool z = GetSystemMetrics(SM_MOUSEWHEELPRESENT); if (x && z) return 4; if (x || z) return 3; return 2; } static bool set_mouse_xy(ALLEGRO_DISPLAY *disp, int x, int y) { int dx, dy; POINT pt; ALLEGRO_DISPLAY_WIN *win_disp = (void*)disp; if (!installed) return false; dx = x - mouse_state.x; dy = y - mouse_state.y; if (dx || dy) { mouse_state.x = x; mouse_state.y = y; generate_mouse_event( ALLEGRO_EVENT_MOUSE_WARPED, mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure, dx, dy, 0, 0, 0, (void*)win_disp); } pt.x = x; pt.y = y; ClientToScreen(win_disp->window, &pt); SetCursorPos(pt.x, pt.y); return true; } static bool set_mouse_axis(int which, int val) { /* Vertical mouse wheel. */ if (which == 2) { int dz = (val - mouse_state.z); raw_mouse_z = WHEEL_DELTA * val / al_get_mouse_wheel_precision(); if (dz != 0) { mouse_state.z = val; generate_mouse_event( ALLEGRO_EVENT_MOUSE_AXES, mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure, 0, 0, dz, 0, 0, mouse_state.display); } return true; } /* Horizontal mouse wheel. */ if (which == 3) { int dw = (val - mouse_state.w); raw_mouse_w = WHEEL_DELTA * val / al_get_mouse_wheel_precision(); if (dw != 0) { mouse_state.w = val; generate_mouse_event( ALLEGRO_EVENT_MOUSE_AXES, mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure, 0, 0, 0, dw, 0, mouse_state.display); } return true; } return false; } static void get_mouse_state(ALLEGRO_MOUSE_STATE *ret_state) { _al_event_source_lock(&the_mouse.es); *ret_state = mouse_state; _al_event_source_unlock(&the_mouse.es); } /* the driver vtable */ #define MOUSE_WINAPI AL_ID('W','A','P','I') static ALLEGRO_MOUSE_DRIVER mousedrv_winapi = { MOUSE_WINAPI, "", "", "WinAPI mouse", init_mouse, exit_mouse, get_mouse, get_num_buttons, get_num_axes, set_mouse_xy, set_mouse_axis, get_mouse_state }; _AL_DRIVER_INFO _al_mouse_driver_list[] = { {MOUSE_WINAPI, &mousedrv_winapi, true}, {0, NULL, 0} }; void _al_win_mouse_handle_leave(ALLEGRO_DISPLAY_WIN *win_disp) { /* The state should be updated even if the mouse is not installed so that * it will be correct if the mouse is installed later. */ if (mouse_state.display == (void*)win_disp) mouse_state.display = NULL; if (!installed) return; generate_mouse_event(ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY, mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure, 0, 0, 0, 0, 0, (void*)win_disp); } void _al_win_mouse_handle_enter(ALLEGRO_DISPLAY_WIN *win_disp) { /* The state should be updated even if the mouse is not installed so that * it will be correct if the mouse is installed later. */ mouse_state.display = (void*)win_disp; if (!installed) return; generate_mouse_event(ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY, mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure, 0, 0, 0, 0, 0, (void*)win_disp); } void _al_win_mouse_handle_move(int x, int y, bool abs, ALLEGRO_DISPLAY_WIN *win_disp) { int dx, dy; int oldx, oldy; oldx = mouse_state.x; oldy = mouse_state.y; if (!installed) return; if (!abs) { mouse_state.x += x; mouse_state.y += y; dx = x; dy = y; } else { dx = x - mouse_state.x; dy = y - mouse_state.y; mouse_state.x = x; mouse_state.y = y; } if (oldx != mouse_state.x || oldy != mouse_state.y) { generate_mouse_event(ALLEGRO_EVENT_MOUSE_AXES, mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure, dx, dy, 0, 0, 0, (void*)win_disp); } } void _al_win_mouse_handle_wheel(int raw_dz, bool abs, ALLEGRO_DISPLAY_WIN *win_disp) { int d; int new_z; if (!installed) return; if (!abs) { raw_mouse_z += raw_dz; } else { raw_mouse_z = raw_dz; } new_z = al_get_mouse_wheel_precision() * raw_mouse_z / WHEEL_DELTA; d = new_z - mouse_state.z; mouse_state.z = new_z; generate_mouse_event(ALLEGRO_EVENT_MOUSE_AXES, mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure, 0, 0, d, 0, 0, (void*)win_disp); } void _al_win_mouse_handle_hwheel(int raw_dw, bool abs, ALLEGRO_DISPLAY_WIN *win_disp) { int d; int new_w; if (!installed) return; if (!abs) { raw_mouse_w += raw_dw; } else { raw_mouse_w = raw_dw; } new_w = al_get_mouse_wheel_precision() * raw_mouse_w / WHEEL_DELTA; d = new_w - mouse_state.w; mouse_state.w = new_w; generate_mouse_event(ALLEGRO_EVENT_MOUSE_AXES, mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure, 0, 0, 0, d, 0, (void*)win_disp); } void _al_win_mouse_handle_button(int button, bool down, int x, int y, bool abs, ALLEGRO_DISPLAY_WIN *win_disp) { int type = down ? ALLEGRO_EVENT_MOUSE_BUTTON_DOWN : ALLEGRO_EVENT_MOUSE_BUTTON_UP; if (!installed) return; if (!abs) { mouse_state.x += x; mouse_state.y += y; } else { mouse_state.x = x; mouse_state.y = y; } if (down) mouse_state.buttons |= (1 << (button-1)); else mouse_state.buttons &= ~(1 << (button-1)); mouse_state.pressure = mouse_state.buttons ? 1.0 : 0.0; /* TODO */ generate_mouse_event(type, mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure, 0, 0, 0, 0, button, (void*)win_disp); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/wsystem.c000066400000000000000000000647261473414355200167420ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * New Windows system driver * * Based on the X11 OpenGL driver by Elias Pschernig. * * Heavily modified by Trent Gamblin. */ #include #include #include #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_system.h" #include "allegro5/platform/aintwin.h" #include "allegro5/internal/aintern_wunicode.h" #if defined ALLEGRO_CFG_OPENGL #include "allegro5/allegro_opengl.h" #endif #include #include ALLEGRO_DEBUG_CHANNEL("system") /* FIXME: should we check for psapi _WIN32_IE and shlobj? { */ #include #if _WIN32_IE < 0x500 #undef _WIN32_IE #define _WIN32_IE 0x500 #endif #include #include /* } */ bool _al_win_disable_screensaver = false; static ALLEGRO_SYSTEM_INTERFACE *vt = 0; static bool using_higher_res_timer; static ALLEGRO_SYSTEM_WIN *_al_win_system; /* This is mostly here for _al_display_d3d_driver, which is stateful. */ static ALLEGRO_MUTEX* win_mutex; /* _WinMain: * Entry point for Windows GUI programs, hooked by a macro in alwin.h, * which makes it look as if the application can still have a normal * main() function. */ int _WinMain(void *_main, void *hInst, void *hPrev, char *Cmd, int nShow) { int (*mainfunc) (int argc, char *argv[]) = (int (*)(int, char *[]))_main; char *argbuf; char **argv; int argc; int argc_max; int i, q; (void)hInst; (void)hPrev; (void)Cmd; (void)nShow; /* can't use parameter because it doesn't include the executable name */ argbuf = _twin_tchar_to_utf8(GetCommandLine()); argc = 0; argc_max = 64; argv = al_malloc(sizeof(char *) * argc_max); if (!argv) { al_free(argbuf); return 1; } i = 0; /* parse commandline into argc/argv format */ while (argbuf[i]) { while ((argbuf[i]) && (isspace(argbuf[i]))) i++; if (argbuf[i]) { if ((argbuf[i] == '\'') || (argbuf[i] == '"')) { q = argbuf[i++]; if (!argbuf[i]) break; } else q = 0; argv[argc++] = &argbuf[i]; if (argc >= argc_max) { argc_max += 64; argv = al_realloc(argv, sizeof(char *) * argc_max); if (!argv) { al_free(argbuf); return 1; } } while ((argbuf[i]) && ((q) ? (argbuf[i] != q) : (!isspace(argbuf[i])))) i++; if (argbuf[i]) { argbuf[i] = 0; i++; } } } argv[argc] = NULL; /* call the application entry point */ i = mainfunc(argc, argv); al_free(argv); al_free(argbuf); return i; } static void set_dpi_awareness(void) { bool dpi_awareness_set = false; /* We load the shcore DLL and the APIs dynamically because these are * not often included in MinGW headers. */ HMODULE shcore_dll = _al_win_safe_load_library("shcore.dll"); if (shcore_dll) { typedef enum _AL_PROCESS_DPI_AWARENESS { AL_PROCESS_DPI_UNAWARE = 0, AL_PROCESS_SYSTEM_DPI_AWARE = 1, AL_PROCESS_PER_MONITOR_DPI_AWARE = 2 } AL_PROCESS_DPI_AWARENESS; typedef HRESULT (WINAPI *SetProcessDpiAwarenessPROC)(AL_PROCESS_DPI_AWARENESS); SetProcessDpiAwarenessPROC imp_SetProcessDpiAwareness = (SetProcessDpiAwarenessPROC)GetProcAddress(shcore_dll, "SetProcessDpiAwareness"); if (imp_SetProcessDpiAwareness) { /* Try setting the per-monitor awareness first. It might fail on Win 8.1. */ HRESULT ret = imp_SetProcessDpiAwareness(AL_PROCESS_PER_MONITOR_DPI_AWARE); if (ret == E_INVALIDARG) { ret = imp_SetProcessDpiAwareness(AL_PROCESS_SYSTEM_DPI_AWARE); } if (ret == S_OK) { dpi_awareness_set = true; } } FreeLibrary(shcore_dll); } /* SetProcessDPIAware is an older API that corresponds to system dpi * awareness above. This is the only option on pre-8.1 systems. */ if (!dpi_awareness_set) { HMODULE user32_dll = _al_win_safe_load_library("user32.dll"); if (user32_dll) { typedef BOOL (WINAPI *SetProcessDPIAwarePROC)(void); SetProcessDPIAwarePROC imp_SetProcessDPIAware = (SetProcessDPIAwarePROC)GetProcAddress(user32_dll, "SetProcessDPIAware"); if (imp_SetProcessDPIAware) { imp_SetProcessDPIAware(); } FreeLibrary(user32_dll); } } } /* Create a new system object. */ static ALLEGRO_SYSTEM *win_initialize(int flags) { (void)flags; set_dpi_awareness(); _al_win_system = al_calloc(1, sizeof *_al_win_system); // Request a 1ms resolution from our timer if (timeBeginPeriod(1) != TIMERR_NOCANDO) { using_higher_res_timer = true; } _al_win_init_time(); _al_win_init_window(); _al_vector_init(&_al_win_system->system.displays, sizeof (ALLEGRO_SYSTEM_WIN *)); _al_win_system->system.vt = vt; win_mutex = al_create_mutex(); return &_al_win_system->system; } static void win_shutdown(void) { ALLEGRO_SYSTEM *s; ASSERT(vt); /* Close all open displays. */ s = al_get_system_driver(); while (_al_vector_size(&s->displays) > 0) { ALLEGRO_DISPLAY **dptr = _al_vector_ref(&s->displays, 0); ALLEGRO_DISPLAY *d = *dptr; al_destroy_display(d); } _al_vector_free(&s->displays); #ifdef ALLEGRO_CFG_D3D _al_d3d_shutdown_display(); #endif _al_win_shutdown_window(); _al_win_shutdown_time(); if (using_higher_res_timer) { timeEndPeriod(1); } al_free(vt); vt = NULL; al_destroy_mutex(win_mutex); ASSERT(_al_win_system); al_free(_al_win_system); } static ALLEGRO_DISPLAY_INTERFACE *win_get_display_driver(void) { const int flags = al_get_new_display_flags(); ALLEGRO_SYSTEM *sys = al_get_system_driver(); ALLEGRO_CONFIG *sys_cfg = al_get_system_config(); ALLEGRO_SYSTEM_WIN *syswin = (ALLEGRO_SYSTEM_WIN *)sys; const char *s; /* Look up the toggle_mouse_grab_key binding. This isn't such a great place * to do it, but the config file is not available in win_initialize, * and this is neutral between the D3D and OpenGL display drivers. */ if (!syswin->toggle_mouse_grab_keycode) { const char *binding = al_get_config_value(sys_cfg, "keyboard", "toggle_mouse_grab_key"); if (binding) { syswin->toggle_mouse_grab_keycode = _al_parse_key_binding(binding, &syswin->toggle_mouse_grab_modifiers); if (syswin->toggle_mouse_grab_keycode) { ALLEGRO_DEBUG("Toggle mouse grab key: '%s'\n", binding); } else { ALLEGRO_WARN("Cannot parse key binding '%s'\n", binding); } } } /* Programmatic selection. */ #ifdef ALLEGRO_CFG_D3D if (flags & ALLEGRO_DIRECT3D_INTERNAL) { al_lock_mutex(win_mutex); ALLEGRO_DISPLAY_INTERFACE* iface = _al_display_d3d_driver(); al_unlock_mutex(win_mutex); if (iface == NULL) ALLEGRO_WARN("Direct3D graphics driver not available.\n"); return iface; } #endif #ifdef ALLEGRO_CFG_OPENGL if (flags & ALLEGRO_OPENGL) { return _al_display_wgl_driver(); } #endif /* Selection by configuration file. The configuration value is non-binding. * The user may unknowingly set a value which was configured out at compile * time. The value should have no effect instead of causing a failure. */ s = al_get_config_value(sys_cfg, "graphics", "driver"); if (s) { ALLEGRO_DEBUG("Configuration value graphics.driver = %s\n", s); if (0 == _al_stricmp(s, "DIRECT3D") || 0 == _al_stricmp(s, "D3D")) { #ifdef ALLEGRO_CFG_D3D al_lock_mutex(win_mutex); ALLEGRO_DISPLAY_INTERFACE* iface = _al_display_d3d_driver(); al_unlock_mutex(win_mutex); if (iface != NULL) { al_set_new_display_flags(flags | ALLEGRO_DIRECT3D_INTERNAL); return iface; } #endif } else if (0 == _al_stricmp(s, "OPENGL")) { #ifdef ALLEGRO_CFG_OPENGL al_set_new_display_flags(flags | ALLEGRO_OPENGL); return _al_display_wgl_driver(); #endif } else if (0 != _al_stricmp(s, "DEFAULT")) { ALLEGRO_WARN("Graphics driver selection unrecognised: %s\n", s); } } /* Automatic graphics driver selection. */ /* XXX is implicitly setting new_display_flags the desired behaviour? */ #ifdef ALLEGRO_CFG_D3D { al_lock_mutex(win_mutex); ALLEGRO_DISPLAY_INTERFACE* iface = _al_display_d3d_driver(); al_unlock_mutex(win_mutex); if (iface != NULL) { al_set_new_display_flags(flags | ALLEGRO_DIRECT3D_INTERNAL); return iface; } } #endif #ifdef ALLEGRO_CFG_OPENGL { al_set_new_display_flags(flags | ALLEGRO_OPENGL); return _al_display_wgl_driver(); } #endif ALLEGRO_WARN("No graphics driver available.\n"); return NULL; } /* FIXME: use the list */ static ALLEGRO_KEYBOARD_DRIVER *win_get_keyboard_driver(void) { return _al_keyboard_driver_list[0].driver; } /* Checks whether the configured joystick driver is of the given name. * Also returns false if the configuration entry was not set. */ static bool win_configured_joystick_driver_is(const char * name) { const char * driver; ALLEGRO_CONFIG * sysconf = al_get_system_config(); if (!sysconf) return false; driver = al_get_config_value(sysconf, "joystick", "driver"); if (!driver) return false; ALLEGRO_DEBUG("Configuration value joystick.driver = %s\n", driver); return (0 == _al_stricmp(driver, name)); } /* Checks whether xinput should be used or not not according * to configuration. */ static bool win_use_xinput(void) { return win_configured_joystick_driver_is("XINPUT"); } /* Checks whether directinput should be used or not not according * to configuration. */ static bool win_use_directinput(void) { return win_configured_joystick_driver_is("DIRECTINPUT"); } /* By default the combined xinput/directinput driver is used unless directinput * or xinput exclusive is set.*/ static ALLEGRO_JOYSTICK_DRIVER *win_get_joystick_driver(void) { if (win_use_directinput()) { ALLEGRO_DEBUG("Selected DirectInput joystick driver.\n"); return &_al_joydrv_directx; } if (win_use_xinput()) { #ifdef ALLEGRO_CFG_XINPUT ALLEGRO_DEBUG("Selected XInput joystick driver.\n"); return &_al_joydrv_xinput; #else ALLEGRO_WARN("XInput joystick driver not supported.\n"); #endif } #ifdef ALLEGRO_CFG_XINPUT ALLEGRO_DEBUG("Selected combined XInput/DirectInput joystick driver.\n"); return &_al_joydrv_windows_all; #else ALLEGRO_WARN("Combined XInput/DirectInput joystick driver not supported. Usign DirectInput in stead.\n"); return &_al_joydrv_directx; #endif } /* By default the combined haptic driver is used unless directinput or * xinput exclusive is set in the configuration.*/ static ALLEGRO_HAPTIC_DRIVER *win_get_haptic_driver(void) { if (win_use_directinput()) { ALLEGRO_DEBUG("Selected DirectInput haptic driver.\n"); return &_al_hapdrv_directx; } if (win_use_xinput()) { #ifdef ALLEGRO_CFG_XINPUT ALLEGRO_DEBUG("Selected XInput haptic driver.\n"); return &_al_hapdrv_xinput; #else ALLEGRO_WARN("XInput haptic driver not supported.\n"); #endif } #ifdef ALLEGRO_CFG_XINPUT ALLEGRO_DEBUG("Selected combined XInput/DirectInput haptic driver.\n"); return &_al_hapdrv_windows_all; #else ALLEGRO_WARN("Combined XInput/DirectInput haptic driver not supported. Using DirectInput in stead.\n"); return &_al_hapdrv_directx; #endif } static int win_get_num_display_modes(void) { int format = _al_deduce_color_format(_al_get_new_display_settings()); int refresh_rate = al_get_new_display_refresh_rate(); int flags = al_get_new_display_flags(); #if defined ALLEGRO_CFG_OPENGL if (flags & ALLEGRO_OPENGL) { return _al_wgl_get_num_display_modes(format, refresh_rate, flags); } #endif #if defined ALLEGRO_CFG_D3D return _al_d3d_get_num_display_modes(format, refresh_rate, flags); #endif return 0; } static ALLEGRO_DISPLAY_MODE *win_get_display_mode(int index, ALLEGRO_DISPLAY_MODE *mode) { int format = _al_deduce_color_format(_al_get_new_display_settings()); int refresh_rate = al_get_new_display_refresh_rate(); int flags = al_get_new_display_flags(); #if defined ALLEGRO_CFG_OPENGL if (flags & ALLEGRO_OPENGL) { return _al_wgl_get_display_mode(index, format, refresh_rate, flags, mode); } #endif #if defined ALLEGRO_CFG_D3D return _al_d3d_get_display_mode(index, format, refresh_rate, flags, mode); #endif return NULL; } static int win_get_num_video_adapters(void) { DISPLAY_DEVICE dd; int count = 0; int c = 0; memset(&dd, 0, sizeof(dd)); dd.cb = sizeof(dd); while (EnumDisplayDevices(NULL, count, &dd, 0) != false) { if (dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) c++; count++; } return c; } static int win_find_nth_adapter_with_desktop(DISPLAY_DEVICE* pdd, int adapter) { int count = 0; int c = 0; while (EnumDisplayDevices(NULL, count, pdd, 0)) { if (pdd->StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) { if (c == adapter) return true; c++; } count++; } return false; } static int win_get_monitor_refresh_rate(int adapter) { DISPLAY_DEVICE dd; DEVMODE dm; memset(&dd, 0, sizeof(dd)); dd.cb = sizeof(dd); if (!win_find_nth_adapter_with_desktop(&dd, adapter)) { return 0; } memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(dm); if (!EnumDisplaySettings(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { return 0; } return dm.dmDisplayFrequency; } static bool win_get_monitor_info(int adapter, ALLEGRO_MONITOR_INFO *info) { DISPLAY_DEVICE dd; DEVMODE dm; memset(&dd, 0, sizeof(dd)); dd.cb = sizeof(dd); if (!win_find_nth_adapter_with_desktop(&dd, adapter)) { return false; } memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(dm); if (!EnumDisplaySettings(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { return false; } ASSERT(dm.dmFields & DM_PELSHEIGHT); ASSERT(dm.dmFields & DM_PELSWIDTH); /* Disabled this assertion for now as it fails under Wine 1.2. */ /* ASSERT(dm.dmFields & DM_POSITION); */ info->x1 = dm.dmPosition.x; info->y1 = dm.dmPosition.y; info->x2 = info->x1 + dm.dmPelsWidth; info->y2 = info->y1 + dm.dmPelsHeight; return true; } static BOOL CALLBACK monitor_enum_proc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { HMONITOR *h_monitor = (HMONITOR *) dwData; (void)hdcMonitor; (void)lprcMonitor; if (hMonitor) { *h_monitor = hMonitor; return false; } return true; } static HMONITOR win_get_monitor(ALLEGRO_MONITOR_INFO *info) { HMONITOR h_monitor; RECT rect; rect.left = info->x1; rect.top = info->y1; rect.right = info->x2; rect.bottom = info->y2; EnumDisplayMonitors(NULL, &rect, monitor_enum_proc, (LPARAM) &h_monitor); return h_monitor; } static int win_get_monitor_dpi(int adapter) { ALLEGRO_MONITOR_INFO info; HMODULE shcore_dll = _al_win_safe_load_library("shcore.dll"); UINT dpi_hori; UINT dpi_vert; typedef enum _AL_MONITOR_DPI_TYPE { AL_MDT_EFFECTIVE_DPI = 0, AL_MDT_ANGULAR_DPI = 1, AL_MDT_RAW_DPI = 2, AL_MDT_DEFAULT = AL_MDT_EFFECTIVE_DPI } AL_MONITOR_DPI_TYPE; typedef HRESULT (WINAPI *GetDpiForMonitorPROC)(HMONITOR hmonitor, AL_MONITOR_DPI_TYPE dpiType, UINT *dpiX, UINT *dpiY); GetDpiForMonitorPROC imp_GetDpiForMonitor = (GetDpiForMonitorPROC) GetProcAddress(shcore_dll, "GetDpiForMonitor"); if (!shcore_dll) { FreeLibrary(shcore_dll); return 0; } if (!win_get_monitor_info(adapter, &info)) { FreeLibrary(shcore_dll); return 0; } imp_GetDpiForMonitor(win_get_monitor(&info), 0, &dpi_hori, &dpi_vert); FreeLibrary(shcore_dll); return sqrt(dpi_hori * dpi_vert); } static bool win_get_cursor_position(int *ret_x, int *ret_y) { POINT p; GetCursorPos(&p); *ret_x = p.x; *ret_y = p.y; return true; } static bool win_grab_mouse(ALLEGRO_DISPLAY *display) { ALLEGRO_SYSTEM_WIN *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_WIN *win_disp = (void *)display; RECT rect; GetWindowRect(win_disp->window, &rect); if (ClipCursor(&rect) != 0) { system->mouse_grab_display = display; return true; } return false; } static bool win_ungrab_mouse(void) { ALLEGRO_SYSTEM_WIN *system = (void *)al_get_system_driver(); ClipCursor(NULL); system->mouse_grab_display = NULL; return true; } static ALLEGRO_MOUSE_DRIVER *win_get_mouse_driver(void) { return _al_mouse_driver_list[0].driver; } static ALLEGRO_TOUCH_INPUT_DRIVER *win_get_touch_input_driver(void) { return _al_touch_input_driver_list[0].driver; } /* _al_win_get_path: * Returns full path to various system and user diretories */ ALLEGRO_PATH *_al_win_get_path(int id) { char path[MAX_PATH]; wchar_t pathw[MAX_PATH]; ALLEGRO_USTR *pathu; uint32_t csidl = 0; HRESULT ret = 0; ALLEGRO_PATH *cisdl_path = NULL; switch (id) { case ALLEGRO_TEMP_PATH: { /* Check: TMP, TMPDIR, TEMP or TEMPDIR */ DWORD ret = GetTempPathW(MAX_PATH, pathw); if (ret > MAX_PATH) { /* should this ever happen, windows is more broken than I ever thought */ return NULL; } pathu = al_ustr_new_from_utf16(pathw); al_ustr_to_buffer(pathu, path, sizeof path); al_ustr_free(pathu); return al_create_path_for_directory(path); } break; case ALLEGRO_RESOURCES_PATH: { /* where the program is in */ HANDLE process = GetCurrentProcess(); char *ptr; GetModuleFileNameExW(process, NULL, pathw, MAX_PATH); pathu = al_ustr_new_from_utf16(pathw); al_ustr_to_buffer(pathu, path, sizeof path); al_ustr_free(pathu); ptr = strrchr(path, '\\'); if (!ptr) { /* shouldn't happen */ return NULL; } /* chop off everything including and after the last slash */ /* should this not chop the slash? */ *ptr = '\0'; return al_create_path_for_directory(path); } break; case ALLEGRO_USER_DATA_PATH: /* CSIDL_APPDATA */ case ALLEGRO_USER_SETTINGS_PATH: csidl = CSIDL_APPDATA; break; case ALLEGRO_USER_HOME_PATH: /* CSIDL_PROFILE */ csidl = CSIDL_PROFILE; break; case ALLEGRO_USER_DOCUMENTS_PATH: /* CSIDL_PERSONAL */ csidl = CSIDL_PERSONAL; break; case ALLEGRO_EXENAME_PATH: { /* full path to the exe including its name */ HANDLE process = GetCurrentProcess(); GetModuleFileNameExW(process, NULL, pathw, MAX_PATH); pathu = al_ustr_new_from_utf16(pathw); al_ustr_to_buffer(pathu, path, sizeof path); al_ustr_free(pathu); return al_create_path(path); } break; default: return NULL; } ret = SHGetFolderPathW(NULL, csidl, NULL, SHGFP_TYPE_CURRENT, pathw); if (ret != S_OK) { return NULL; } pathu = al_ustr_new_from_utf16(pathw); al_ustr_to_buffer(pathu, path, sizeof path); al_ustr_free(pathu); cisdl_path = al_create_path_for_directory(path); if (!cisdl_path) return NULL; if (csidl == CSIDL_APPDATA) { const char *org_name = al_get_org_name(); const char *app_name = al_get_app_name(); if (!app_name || !app_name[0]) { /* this shouldn't ever happen. */ al_destroy_path(cisdl_path); return NULL; } if (org_name && org_name[0]) { al_append_path_component(cisdl_path, org_name); } al_append_path_component(cisdl_path, app_name); } return cisdl_path; } static bool win_inhibit_screensaver(bool inhibit) { _al_win_disable_screensaver = inhibit; return true; } static HMODULE load_library_at_path(const TCHAR *path_str) { HMODULE lib; /* * XXX LoadLibrary will search the current directory for any dependencies of * the library we are loading. Using LoadLibraryEx with the appropriate * flags would fix that, but when I tried it I was unable to load dsound.dll * on Vista. */ char* upath_str = _twin_tchar_to_utf8(path_str); ALLEGRO_DEBUG("Calling LoadLibrary %s\n", upath_str); lib = LoadLibrary(path_str); if (lib) { ALLEGRO_INFO("Loaded %s\n", upath_str); } else { DWORD error = GetLastError(); HRESULT hr = HRESULT_FROM_WIN32(error); /* XXX do something with it */ (void)hr; ALLEGRO_WARN("Failed to load %s (error: %ld)\n", upath_str, error); } al_free(upath_str); return lib; } static bool is_build_config_name(const char *s) { return s && ( 0 == strcmp(s, "Debug") || 0 == strcmp(s, "Release") || 0 == strcmp(s, "RelWithDebInfo") || 0 == strcmp(s, "Profile")); } static ALLEGRO_PATH *maybe_parent_dir(const ALLEGRO_PATH *path) { ALLEGRO_PATH *path2; if (!path) return NULL; if (!is_build_config_name(al_get_path_tail(path))) return NULL; path2 = al_clone_path(path); if (path2) { al_drop_path_tail(path2); al_set_path_filename(path2, NULL); ALLEGRO_DEBUG("Also searching %s\n", al_path_cstr(path2, '\\')); } return path2; } /* * Calling LoadLibrary with a relative file name is a security risk: * see e.g. Microsoft Security Advisory (2269637) * "Insecure Library Loading Could Allow Remote Code Execution" */ HMODULE _al_win_safe_load_library(const char *filename) { ALLEGRO_PATH *path1 = NULL; ALLEGRO_PATH *path2 = NULL; TCHAR buf[MAX_PATH]; const TCHAR *other_dirs[3]; HMODULE lib = NULL; bool msvc_only = false; TCHAR* tfilename; /* MSVC only: if the executable is in the build configuration directory, * which is also just under the current directory, then also try to load the * library from the current directory. This leads to less surprises when * running example programs. */ #if defined(ALLEGRO_MSVC) msvc_only = true; #endif /* Try to load the library from the directory containing the running * executable, the Windows system directories, or directories on the PATH. * Do NOT try to load the library from the current directory. */ if (al_is_system_installed()) { path1 = al_get_standard_path(ALLEGRO_RESOURCES_PATH); } else if (GetModuleFileName(NULL, buf, sizeof(buf)) < sizeof(buf)) { char* tmp = _twin_tchar_to_utf8(buf); path1 = al_create_path(tmp); al_free(tmp); } if (msvc_only) { path2 = maybe_parent_dir(path1); } other_dirs[0] = path1 ? _twin_ustr_to_tchar(al_path_ustr(path1, '\\')) : NULL; other_dirs[1] = path2 ? _twin_ustr_to_tchar(al_path_ustr(path2, '\\')) : NULL; other_dirs[2] = NULL; /* sentinel */ tfilename = _twin_utf8_to_tchar(filename); _tcsncpy(buf, tfilename, MAX_PATH); al_free(tfilename); if (PathFindOnPath(buf, other_dirs)) { char* tmp = _twin_tchar_to_utf8(buf); ALLEGRO_DEBUG("PathFindOnPath found: %s\n", tmp); al_free(tmp); lib = load_library_at_path(buf); } else { ALLEGRO_WARN("PathFindOnPath failed to find %s\n", filename); } al_free((void*) other_dirs[0]); al_free((void*) other_dirs[1]); al_destroy_path(path1); al_destroy_path(path2); return lib; } static void *win_open_library(const char *filename) { return _al_win_safe_load_library(filename); } static void *win_import_symbol(void *library, const char *symbol) { ASSERT(library); return GetProcAddress(library, symbol); } static void win_close_library(void *library) { ASSERT(library); FreeLibrary(library); } static ALLEGRO_SYSTEM_INTERFACE *_al_system_win_driver(void) { if (vt) return vt; vt = al_calloc(1, sizeof *vt); vt->id = ALLEGRO_SYSTEM_ID_WINDOWS; vt->initialize = win_initialize; vt->get_display_driver = win_get_display_driver; vt->get_keyboard_driver = win_get_keyboard_driver; vt->get_mouse_driver = win_get_mouse_driver; vt->get_touch_input_driver = win_get_touch_input_driver; vt->get_haptic_driver = win_get_haptic_driver; vt->get_joystick_driver = win_get_joystick_driver; vt->get_num_display_modes = win_get_num_display_modes; vt->get_display_mode = win_get_display_mode; vt->shutdown_system = win_shutdown; vt->get_num_video_adapters = win_get_num_video_adapters; vt->create_mouse_cursor = _al_win_create_mouse_cursor; vt->destroy_mouse_cursor = _al_win_destroy_mouse_cursor; vt->get_monitor_info = win_get_monitor_info; vt->get_monitor_dpi = win_get_monitor_dpi; vt->get_monitor_refresh_rate = win_get_monitor_refresh_rate; vt->get_cursor_position = win_get_cursor_position; vt->grab_mouse = win_grab_mouse; vt->ungrab_mouse = win_ungrab_mouse; vt->get_path = _al_win_get_path; vt->inhibit_screensaver = win_inhibit_screensaver; vt->open_library = win_open_library; vt->import_symbol = win_import_symbol; vt->close_library = win_close_library; vt->get_time = _al_win_get_time; vt->rest = _al_win_rest; vt->init_timeout = _al_win_init_timeout; return vt; } void _al_register_system_interfaces() { ALLEGRO_SYSTEM_INTERFACE **add; add = _al_vector_alloc_back(&_al_system_interfaces); *add = _al_system_win_driver(); } const char* _al_win_error(DWORD err) { LPTSTR msg = NULL; int len; static char buf[2048]; len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, err, 0, (LPTSTR)&msg, 0, NULL); if (len == 0) { _al_sane_strncpy(buf, "(Unable to decode the error code)", sizeof(buf)); } else { /* Truncate trailing CRLF if it has one */ if (len >= 2 && _tcscmp(msg + len - 2, TEXT("\r\n")) == 0) { msg[len - 2] = (TCHAR)0; } _twin_copy_tchar_to_utf8(buf, msg, sizeof(buf)); LocalFree(msg); } return buf; } const char* _al_win_last_error() { return _al_win_error(GetLastError()); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/wthread.c000066400000000000000000000043671473414355200166600ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Thread management. * * By Stefan Schimanski. * * Synchronization functions added by Eric Botcazou. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/platform/aintwin.h" #include #ifndef ALLEGRO_WINDOWS #error something is wrong with the makefile #endif ALLEGRO_DEBUG_CHANNEL("system") /* COINIT_MULTITHREADED is not defined in objbase.h for MSVC */ #define _COINIT_MULTITHREADED 0 typedef HRESULT(CALLBACK * _CoInitializeEx_ptr) (LPVOID, DWORD); static _CoInitializeEx_ptr _CoInitializeEx = NULL; static int first_call = 1; /* _al_win_thread_init: * Initializes COM interface for the calling thread. * Attempts to use Distributed COM if available (installed by default * on every 32-bit Windows starting with Win98 and Win NT4). */ void _al_win_thread_init(void) { HMODULE ole32 = NULL; if (first_call) { first_call = 0; ole32 = GetModuleHandle(TEXT("OLE32.DLL")); if (ole32 != NULL) { _CoInitializeEx = (_CoInitializeEx_ptr) GetProcAddress( ole32, "CoInitializeEx"); } else { ALLEGRO_WARN("OLE32.DLL can't be loaded.\n"); } if (_CoInitializeEx == NULL) { ALLEGRO_WARN("Microsoft Distributed COM is not installed on this system. If you have problems "); ALLEGRO_WARN("with this application, please install the DCOM update. You can find it on the "); ALLEGRO_WARN("Microsoft homepage\n"); } } if (_CoInitializeEx != NULL) _CoInitializeEx(NULL, _COINIT_MULTITHREADED); else CoInitialize(NULL); } /* _al_win_thread_exit: * Shuts down COM interface for the calling thread. */ void _al_win_thread_exit(void) { CoUninitialize(); } allegro5-5.2.10.1/src/win/wtime.c000066400000000000000000000062031473414355200163360ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows time module. * * By Peter Wang. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_thread.h" #include "allegro5/platform/aintwin.h" #include ALLEGRO_STATIC_ASSERT(wtime, sizeof(ALLEGRO_TIMEOUT_WIN) <= sizeof(ALLEGRO_TIMEOUT)); #define LARGE_INTEGER_TO_INT64(li) (((int64_t)li.HighPart << 32) | \ (int64_t)li.LowPart) static int64_t high_res_timer_freq; static int64_t _al_win_prev_time; static double _al_win_total_time; static double (*real_get_time_func)(void); static _AL_MUTEX time_mutex = _AL_MUTEX_UNINITED; static double low_res_current_time(void) { int64_t cur_time; double ellapsed_time; _al_mutex_lock(&time_mutex); cur_time = (int64_t) timeGetTime(); ellapsed_time = (double) (cur_time - _al_win_prev_time) / 1000; if (cur_time < _al_win_prev_time) { ellapsed_time += 4294967.295; } _al_win_total_time += ellapsed_time; _al_win_prev_time = cur_time; _al_mutex_unlock(&time_mutex); return _al_win_total_time; } static double high_res_current_time(void) { LARGE_INTEGER count; int64_t cur_time; double ellapsed_time; _al_mutex_lock(&time_mutex); QueryPerformanceCounter(&count); cur_time = LARGE_INTEGER_TO_INT64(count); ellapsed_time = (double)(cur_time - _al_win_prev_time) / (double)high_res_timer_freq; _al_win_total_time += ellapsed_time; _al_win_prev_time = cur_time; _al_mutex_unlock(&time_mutex); return _al_win_total_time; } double _al_win_get_time(void) { return (*real_get_time_func)(); } void _al_win_init_time(void) { LARGE_INTEGER tmp_freq; _al_win_total_time = 0; _al_mutex_init(&time_mutex); if (QueryPerformanceFrequency(&tmp_freq) == 0) { real_get_time_func = low_res_current_time; _al_win_prev_time = (int64_t) timeGetTime(); } else { LARGE_INTEGER count; high_res_timer_freq = LARGE_INTEGER_TO_INT64(tmp_freq); real_get_time_func = high_res_current_time; QueryPerformanceCounter(&count); _al_win_prev_time = LARGE_INTEGER_TO_INT64(count); } } void _al_win_shutdown_time(void) { _al_mutex_destroy(&time_mutex); } void _al_win_rest(double seconds) { if (seconds <= 0) return; Sleep((DWORD)(seconds * 1000.0)); } void _al_win_init_timeout(ALLEGRO_TIMEOUT *timeout, double seconds) { ALLEGRO_TIMEOUT_WIN *wt = (ALLEGRO_TIMEOUT_WIN *) timeout; ASSERT(wt); ASSERT(seconds <= INT_MAX/1000.0); if (seconds <= 0.0) { wt->abstime = timeGetTime(); } else { wt->abstime = timeGetTime() + (DWORD)(seconds * 1000.0); } } /* vim: set sts=3 sw=3 et */ allegro5-5.2.10.1/src/win/wtouch_input.c000066400000000000000000000313121473414355200177400ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows touch input driver. * * By Michał Cichoń. * * See readme.txt for copyright information. */ #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_driver.h" #include "allegro5/internal/aintern_touch_input.h" #include "allegro5/platform/aintwin.h" #include "allegro5/internal/aintern_display.h" ALLEGRO_DEBUG_CHANNEL("touch") static ALLEGRO_TOUCH_INPUT_STATE touch_input_state; static ALLEGRO_TOUCH_INPUT touch_input; static bool installed = false; static size_t initiali_time_stamp = ~0; /* WinAPI import related stuff. */ static int touch_input_api_reference_counter = 0; static void* user32_module = NULL; CLOSETOUCHINPUTHANDLEPROC _al_win_close_touch_input_handle = NULL; GETTOUCHINPUTINFOPROC _al_win_get_touch_input_info = NULL; ISTOUCHWINDOWPROC _al_win_is_touch_window = NULL; REGISTERTOUCHWINDOWPROC _al_win_register_touch_window = NULL; UNREGISTERTOUCHWINDOWPROC _al_win_unregister_touch_window = NULL; bool _al_win_init_touch_input_api(void) { /* Reference counter will be negative if we already tried to initialize the driver. * Lack of touch input API is persistent state, so do not test for it again. */ if (touch_input_api_reference_counter < 0) return false; /* Increase API reference counter if it is already initialized. */ if (touch_input_api_reference_counter > 0) { touch_input_api_reference_counter++; return true; } /* Open handle to user32.dll. This one should be always present. */ user32_module = _al_open_library("user32.dll"); if (NULL == user32_module) return false; _al_win_close_touch_input_handle = (CLOSETOUCHINPUTHANDLEPROC)_al_import_symbol(user32_module, "CloseTouchInputHandle"); _al_win_get_touch_input_info = (GETTOUCHINPUTINFOPROC) _al_import_symbol(user32_module, "GetTouchInputInfo"); _al_win_is_touch_window = (ISTOUCHWINDOWPROC) _al_import_symbol(user32_module, "IsTouchWindow"); _al_win_register_touch_window = (REGISTERTOUCHWINDOWPROC) _al_import_symbol(user32_module, "RegisterTouchWindow"); _al_win_unregister_touch_window = (UNREGISTERTOUCHWINDOWPROC)_al_import_symbol(user32_module, "UnregisterTouchWindow"); if (NULL == _al_win_close_touch_input_handle || NULL == _al_win_get_touch_input_info || NULL == _al_win_is_touch_window || NULL == _al_win_register_touch_window || NULL == _al_win_unregister_touch_window) { _al_close_library(user32_module); _al_win_close_touch_input_handle = NULL; _al_win_get_touch_input_info = NULL; _al_win_is_touch_window = NULL; _al_win_register_touch_window = NULL; _al_win_unregister_touch_window = NULL; /* Mark as 'do not try this again'. */ touch_input_api_reference_counter = -1; ALLEGRO_WARN("failed loading the touch input API\n"); return false; } /* Set initial reference count. */ touch_input_api_reference_counter = 1; ALLEGRO_INFO("touch input API installed successfully\n"); return true; } void _al_win_exit_touch_input_api(void) { if (touch_input_api_reference_counter > 1) { --touch_input_api_reference_counter; return; } if (touch_input_api_reference_counter != 1) return; _al_close_library(user32_module); _al_win_close_touch_input_handle = NULL; _al_win_get_touch_input_info = NULL; _al_win_is_touch_window = NULL; _al_win_register_touch_window = NULL; _al_win_unregister_touch_window = NULL; touch_input_api_reference_counter = 0; } /* Actual driver implementation. */ static void generate_touch_input_event(int type, double timestamp, int id, float x, float y, float dx, float dy, bool primary, ALLEGRO_DISPLAY_WIN *win_disp) { ALLEGRO_EVENT event; bool want_touch_event = _al_event_source_needs_to_generate_event(&touch_input.es); bool want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && primary && al_is_mouse_installed(); if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_NONE) want_mouse_emulation_event = false; else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_INCLUSIVE) want_touch_event = want_mouse_emulation_event ? (want_touch_event && !primary) : want_touch_event; else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_EXCLUSIVE) want_touch_event = want_mouse_emulation_event ? false : want_touch_event; if (!want_touch_event && !want_mouse_emulation_event) return; if (want_touch_event) { event.touch.type = type; event.touch.display = (ALLEGRO_DISPLAY*)win_disp; event.touch.timestamp = timestamp; event.touch.id = id; event.touch.x = x; event.touch.y = y; event.touch.dx = dx; event.touch.dy = dy; event.touch.primary = primary; _al_event_source_lock(&touch_input.es); _al_event_source_emit_event(&touch_input.es, &event); _al_event_source_unlock(&touch_input.es); } if (want_mouse_emulation_event) { ALLEGRO_MOUSE_STATE state; switch (type) { case ALLEGRO_EVENT_TOUCH_BEGIN: type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN; break; case ALLEGRO_EVENT_TOUCH_CANCEL: case ALLEGRO_EVENT_TOUCH_END: type = ALLEGRO_EVENT_MOUSE_BUTTON_UP; break; case ALLEGRO_EVENT_TOUCH_MOVE: type = ALLEGRO_EVENT_MOUSE_AXES; break; } al_get_mouse_state(&state); event.mouse.type = type; event.mouse.timestamp = timestamp; event.mouse.display = (ALLEGRO_DISPLAY*)win_disp; event.mouse.x = (int)x; event.mouse.y = (int)y; event.mouse.z = state.z; event.mouse.w = state.w; event.mouse.dx = (int)dx; event.mouse.dy = (int)dy; event.mouse.dz = 0; event.mouse.dw = 0; event.mouse.button = 1; event.mouse.pressure = state.pressure; al_set_mouse_xy(event.mouse.display, event.mouse.x, event.mouse.y); _al_event_source_lock(&touch_input.mouse_emulation_es); _al_event_source_emit_event(&touch_input.mouse_emulation_es, &event); _al_event_source_unlock(&touch_input.mouse_emulation_es); } } static bool init_touch_input(void) { unsigned i; ALLEGRO_SYSTEM* system; if (installed) return false; if (!_al_win_init_touch_input_api()) return false; memset(&touch_input_state, 0, sizeof(touch_input_state)); _al_event_source_init(&touch_input.es); _al_event_source_init(&touch_input.mouse_emulation_es); touch_input.mouse_emulation_mode = ALLEGRO_MOUSE_EMULATION_TRANSPARENT; installed = true; system = al_get_system_driver(); for (i = 0; i < _al_vector_size(&system->displays); ++i) { bool r; ALLEGRO_DISPLAY_WIN *win_display = *((ALLEGRO_DISPLAY_WIN**)_al_vector_ref(&system->displays, i)); r = _al_win_register_touch_window(win_display->window, 0); ALLEGRO_INFO("registering touch window %p: %d\n", win_display, r); if (!r) { ALLEGRO_ERROR("RegisterTouchWindow failed: %s\n", _al_win_last_error()); return false; } } return true; } static void exit_touch_input(void) { if (!installed) return; memset(&touch_input_state, 0, sizeof(touch_input_state)); _al_event_source_free(&touch_input.es); _al_event_source_free(&touch_input.mouse_emulation_es); _al_win_exit_touch_input_api(); installed = false; } static ALLEGRO_TOUCH_INPUT* get_touch_input(void) { return &touch_input; } static void get_touch_input_state(ALLEGRO_TOUCH_INPUT_STATE *ret_state) { _al_event_source_lock(&touch_input.es); *ret_state = touch_input_state; _al_event_source_unlock(&touch_input.es); } static void set_mouse_emulation_mode(int mode) { if (touch_input.mouse_emulation_mode != mode) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) { ALLEGRO_TOUCH_STATE* touch = touch_input_state.touches + i; if (touch->id > 0) { _al_win_touch_input_handle_cancel(touch->id, initiali_time_stamp, touch->x, touch->y, touch->primary, (ALLEGRO_DISPLAY_WIN*)touch->display); } } touch_input.mouse_emulation_mode = mode; } } static ALLEGRO_TOUCH_STATE* find_free_touch_state(void) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) if (touch_input_state.touches[i].id <= 0) return touch_input_state.touches + i; return NULL; } static ALLEGRO_TOUCH_STATE* find_touch_state_with_id(int id) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) if (touch_input_state.touches[i].id == id) return touch_input_state.touches + i; return NULL; } static double get_time_stamp(size_t timestamp) { return al_get_time() - ((timestamp - initiali_time_stamp) / 1000.0); } void _al_win_touch_input_set_time_stamp(size_t timestamp) { if (initiali_time_stamp != (size_t)~0) initiali_time_stamp = timestamp; } void _al_win_touch_input_handle_begin(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY_WIN *win_disp) { ALLEGRO_TOUCH_STATE* state = find_free_touch_state(); if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->id = id; state->x = x; state->y = y; state->dx = 0.0f; state->dy = 0.0f; state->primary = primary; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_BEGIN, get_time_stamp(timestamp), state->id, state->x, state->y, state->dx, state->dy, state->primary, win_disp); } void _al_win_touch_input_handle_end(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY_WIN *win_disp) { ALLEGRO_TOUCH_STATE* state; (void)primary; state = find_touch_state_with_id(id); if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_END, get_time_stamp(timestamp), state->id, state->x, state->y, state->dx, state->dy, state->primary, win_disp); _al_event_source_lock(&touch_input.es); memset(state, 0, sizeof(ALLEGRO_TOUCH_STATE)); _al_event_source_unlock(&touch_input.es); } void _al_win_touch_input_handle_move(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY_WIN *win_disp) { ALLEGRO_TOUCH_STATE* state; (void)primary; state = find_touch_state_with_id(id); if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_MOVE, get_time_stamp(timestamp), state->id, state->x, state->y, state->dx, state->dy, state->primary, win_disp); } void _al_win_touch_input_handle_cancel(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY_WIN *win_disp) { ALLEGRO_TOUCH_STATE* state; (void)primary; state = find_touch_state_with_id(id); if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_CANCEL, get_time_stamp(timestamp), state->id, state->x, state->y, state->dx, state->dy, state->primary, win_disp); _al_event_source_lock(&touch_input.es); memset(state, 0, sizeof(ALLEGRO_TOUCH_STATE)); _al_event_source_unlock(&touch_input.es); } /* the driver vtable */ #define TOUCH_INPUT_WINAPI AL_ID('W','T','I','D') static ALLEGRO_TOUCH_INPUT_DRIVER touch_input_driver = { TOUCH_INPUT_WINAPI, init_touch_input, exit_touch_input, get_touch_input, get_touch_input_state, set_mouse_emulation_mode, NULL }; _AL_DRIVER_INFO _al_touch_input_driver_list[] = { {TOUCH_INPUT_WINAPI, &touch_input_driver, true}, {0, NULL, 0} }; allegro5-5.2.10.1/src/win/wunicode.c000066400000000000000000000211641473414355200170310ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Windows "UNICODE" helper routines. * * See LICENSE.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern_wunicode.h" #include ALLEGRO_DEBUG_CHANNEL("wunicode") /* _al_win_ustr_to_utf16: * Convert ALLEGRO_USTR to newly-allocated UTF-16 buffer */ wchar_t *_al_win_ustr_to_utf16(const ALLEGRO_USTR *u) { int wslen; wchar_t *ws; const char* us = al_cstr(u); size_t uslen = al_ustr_size(u); if (uslen == 0) { ws = al_malloc(sizeof(wchar_t)); ws[0] = 0; return ws; } wslen = MultiByteToWideChar(CP_UTF8, 0, us, uslen, NULL, 0); if (wslen == 0) { ALLEGRO_ERROR("MultiByteToWideChar failed\n"); return NULL; } /* For the NUL at the end. */ wslen += 1; ws = al_malloc(sizeof(wchar_t) * wslen); if (!ws) { ALLEGRO_ERROR("Out of memory\n"); return NULL; } if (0 == MultiByteToWideChar(CP_UTF8, 0, us, uslen, ws, wslen)) { al_free(ws); ALLEGRO_ERROR("MultiByteToWideChar failed\n"); return NULL; } ws[wslen - 1] = 0; return ws; } /* _al_win_utf8_to_ansi: * Convert UTF-8 to newly-allocated ansi buffer */ char* _al_win_ustr_to_ansi(const ALLEGRO_USTR *u) { int wslen; wchar_t *ws; int slen; char *s; const char* us = al_cstr(u); size_t uslen = al_ustr_size(u); if (uslen == 0) { s = al_malloc(sizeof(char)); s[0] = 0; return s; } wslen = MultiByteToWideChar(CP_UTF8, 0, us, uslen, NULL, 0); if (wslen == 0) { ALLEGRO_ERROR("MultiByteToWideChar failed\n"); return NULL; } ws = al_malloc(sizeof(wchar_t) * wslen); if (!ws) { ALLEGRO_ERROR("Out of memory\n"); return NULL; } if (0 == MultiByteToWideChar(CP_UTF8, 0, us, uslen, ws, wslen)) { al_free(ws); ALLEGRO_ERROR("MultiByteToWideChar failed\n"); return NULL; } slen = WideCharToMultiByte(CP_ACP, 0, ws, wslen, NULL, 0, NULL, NULL); if (slen == 0) { ALLEGRO_ERROR("WideCharToMultiByte failed\n"); al_free(ws); return NULL; } /* For the NUL at the end. */ slen += 1; s = al_malloc(sizeof(char) * slen); if (!s) { ALLEGRO_ERROR("Out of memory\n"); al_free(ws); return NULL; } if (0 == WideCharToMultiByte(CP_ACP, 0, ws, wslen, s, slen, NULL, NULL)) { al_free(ws); al_free(s); ALLEGRO_ERROR("WideCharToMultiByte failed\n"); return NULL; } s[slen - 1] = 0; al_free(ws); return s; } /* _al_win_utf8_to_utf16: * Convert UTF-8 to newly-allocated UTF-16 buffer */ wchar_t *_al_win_utf8_to_utf16(const char *us) { int wslen; wchar_t *ws; if (us == NULL) { return NULL; } wslen = MultiByteToWideChar(CP_UTF8, 0, us, -1, NULL, 0); if (wslen == 0) { ALLEGRO_ERROR("MultiByteToWideChar failed\n"); return NULL; } ws = al_malloc(sizeof(wchar_t) * wslen); if (!ws) { ALLEGRO_ERROR("Out of memory\n"); return NULL; } if (0 == MultiByteToWideChar(CP_UTF8, 0, us, -1, ws, wslen)) { al_free(ws); ALLEGRO_ERROR("MultiByteToWideChar failed\n"); return NULL; } return ws; } /* _al_win_utf16_to_utf8: * Convert UTF-16 to newly-allocated UTF-8 buffer */ char *_al_win_utf16_to_utf8(const wchar_t *ws) { int uslen; char *us; if (ws == NULL) { return NULL; } uslen = WideCharToMultiByte(CP_UTF8, 0, ws, -1, NULL, 0, NULL, NULL); if (uslen == 0) { ALLEGRO_ERROR("WideCharToMultiByte failed\n"); return NULL; } us = al_malloc(sizeof(char) * uslen); if (!us) { ALLEGRO_ERROR("Out of memory\n"); return NULL; } if (0 == WideCharToMultiByte(CP_UTF8, 0, ws, -1, us, uslen, NULL, NULL)) { al_free(us); ALLEGRO_ERROR("WideCharToMultiByte failed\n"); return NULL; } return us; } /* _al_win_utf8_to_ansi: * Convert UTF-8 to newly-allocated ansi buffer */ char* _al_win_utf8_to_ansi(const char *us) { int wslen; wchar_t *ws; int slen; char *s; if (us == NULL) { return NULL; } wslen = MultiByteToWideChar(CP_UTF8, 0, us, -1, NULL, 0); if (wslen == 0) { ALLEGRO_ERROR("MultiByteToWideChar failed\n"); return NULL; } ws = al_malloc(sizeof(wchar_t) * wslen); if (!ws) { ALLEGRO_ERROR("Out of memory\n"); return NULL; } if (0 == MultiByteToWideChar(CP_UTF8, 0, us, -1, ws, wslen)) { al_free(ws); ALLEGRO_ERROR("MultiByteToWideChar failed\n"); return NULL; } slen = WideCharToMultiByte(CP_ACP, 0, ws, -1, NULL, 0, NULL, NULL); if (slen == 0) { ALLEGRO_ERROR("WideCharToMultiByte failed\n"); al_free(ws); return NULL; } s = al_malloc(sizeof(char) * slen); if (!s) { ALLEGRO_ERROR("Out of memory\n"); al_free(ws); return NULL; } if (0 == WideCharToMultiByte(CP_ACP, 0, ws, -1, s, slen, NULL, NULL)) { al_free(ws); al_free(s); ALLEGRO_ERROR("WideCharToMultiByte failed\n"); return NULL; } al_free(ws); return s; } /* _al_win_ansi_to_utf8: * Convert ansi to newly-allocated UTF-8 buffer */ char* _al_win_ansi_to_utf8(const char *s) { int wslen; wchar_t *ws; int uslen; char *us; if (s == NULL) { return NULL; } wslen = MultiByteToWideChar(CP_ACP, 0, s, -1, NULL, 0); if (wslen == 0) { ALLEGRO_ERROR("MultiByteToWideChar failed\n"); return NULL; } ws = al_malloc(sizeof(wchar_t) * wslen); if (!ws) { ALLEGRO_ERROR("Out of memory\n"); return NULL; } if (0 == MultiByteToWideChar(CP_ACP, 0, s, -1, ws, wslen)) { al_free(ws); ALLEGRO_ERROR("MultiByteToWideChar failed\n"); return NULL; } uslen = WideCharToMultiByte(CP_UTF8, 0, ws, -1, NULL, 0, NULL, NULL); if (uslen == 0) { ALLEGRO_ERROR("WideCharToMultiByte failed\n"); al_free(ws); return NULL; } us = al_malloc(sizeof(char) * uslen); if (!s) { ALLEGRO_ERROR("Out of memory\n"); al_free(ws); return NULL; } if (0 == WideCharToMultiByte(CP_UTF8, 0, ws, -1, us, uslen, NULL, NULL)) { al_free(ws); al_free(us); ALLEGRO_ERROR("WideCharToMultiByte failed\n"); return NULL; } al_free(ws); return us; } /* _al_win_copy_utf16_to_utf8: Copy string and convert to UTF-8. * This takes a string and copies a UTF-8 version of it to * a buffer of fixed size. * If successful, the string will be zero-terminated and is * the return value of the function. * If unsuccesful, NULL will be returned. * If the representation would overflow the buffer, nothing * is copied and the return value is NULL. */ char *_al_win_copy_utf16_to_utf8(char* us, const wchar_t *ws, size_t uslen) { int rc = WideCharToMultiByte(CP_UTF8, 0, ws, -1, us, uslen, NULL, NULL); if (rc == 0) { ALLEGRO_ERROR("WideCharToMultiByte failed\n"); return NULL; } return us; } char *_al_win_copy_utf8_to_ansi(char* s, const char *us, size_t slen) { int wslen = MultiByteToWideChar(CP_UTF8, 0, us, -1, NULL, 0); if (wslen == 0) { ALLEGRO_ERROR("MultiByteToWideChar failed\n"); return NULL; } wchar_t* ws = al_malloc(wslen * sizeof(wchar_t)); if (!ws) { ALLEGRO_ERROR("Out of memory\n"); return NULL; } MultiByteToWideChar(CP_UTF8, 0, us, -1, ws, wslen); int rc = WideCharToMultiByte(CP_ACP, 0, ws, wslen, s, slen, NULL, NULL); al_free(ws); if (rc == 0) { ALLEGRO_ERROR("WideCharToMultiByte failed\n"); return NULL; } return s; } char *_al_win_copy_ansi_to_utf8(char* us, const char *s, size_t uslen) { int wslen = MultiByteToWideChar(CP_ACP, 0, s, -1, NULL, 0); if (wslen == 0) { ALLEGRO_ERROR("MultiByteToWideChar failed\n"); return NULL; } wchar_t* ws = al_malloc(wslen * sizeof(wchar_t)); if (!ws) { ALLEGRO_ERROR("Out of memory\n"); return NULL; } MultiByteToWideChar(CP_ACP, 0, s, -1, ws, wslen); int rc = WideCharToMultiByte(CP_UTF8, 0, ws, wslen, us, uslen, NULL, NULL); al_free(ws); if (rc == 0) { ALLEGRO_ERROR("WideCharToMultiByte failed\n"); return NULL; } return us; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/wwindow.c000066400000000000000000001426321473414355200167160ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * New Windows window handling * * By Trent Gamblin. * */ /* Raw input */ #define _WIN32_WINNT 0x0501 #ifndef WINVER #define WINVER 0x0501 #endif #include #include #include #include #include /* Only used for Vista and up. */ #ifndef WM_MOUSEHWHEEL #define WM_MOUSEHWHEEL 0x020E #endif #include #include #include "allegro5/allegro_windows.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_vector.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_wunicode.h" #include "allegro5/internal/aintern_joystick.h" #include "allegro5/internal/aintern_wjoydxnu.h" #include "allegro5/platform/aintwin.h" ALLEGRO_DEBUG_CHANNEL("wwindow") static WNDCLASS window_class; static _AL_VECTOR resizing_displays; static ALLEGRO_MUTEX *resize_event_thread_mutex; static bool end_resize_event_thread; static bool resize_event_thread_ended; UINT _al_win_msg_call_proc = 0; UINT _al_win_msg_suicide = 0; #ifndef WM_DPICHANGED #define WM_DPICHANGED 0x02E0 #endif static void display_flags_to_window_styles(int flags, DWORD *style, DWORD *ex_style) { if (flags & ALLEGRO_FULLSCREEN) { *style = WS_POPUP; *ex_style = WS_EX_APPWINDOW; } else if (flags & ALLEGRO_MAXIMIZED) { *style = WS_OVERLAPPEDWINDOW; *ex_style = WS_EX_APPWINDOW; } else if (flags & ALLEGRO_RESIZABLE) { *style = WS_OVERLAPPEDWINDOW; *ex_style = WS_EX_APPWINDOW | WS_EX_OVERLAPPEDWINDOW; } else { *style = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; *ex_style = WS_EX_APPWINDOW; } } // Clears a window to black static void clear_window(HWND window, int w, int h) { PAINTSTRUCT ps; HDC hdc; hdc = BeginPaint(window, &ps); SelectObject(hdc, GetStockObject(DC_BRUSH)); SetDCBrushColor(hdc, RGB(0, 0, 0)); Rectangle(hdc, 0, 0, w, h); } HWND _al_win_create_hidden_window() { HWND window = CreateWindowEx(0, TEXT("ALEX"), TEXT("hidden"), WS_POPUP, -5000, -5000, 0, 0, NULL,NULL,window_class.hInstance,0); return window; } static void _al_win_get_window_center( ALLEGRO_DISPLAY_WIN *win_display, int width, int height, int *out_x, int *out_y) { int a = win_display->adapter; bool *is_fullscreen; ALLEGRO_MONITOR_INFO info; RECT win_size; ALLEGRO_SYSTEM *sys = al_get_system_driver(); unsigned int num; unsigned int i; unsigned int fullscreen_found = 0; num = al_get_num_video_adapters(); is_fullscreen = al_calloc(num, sizeof(bool)); for (i = 0; i < sys->displays._size; i++) { ALLEGRO_DISPLAY **dptr = _al_vector_ref(&sys->displays, i); ALLEGRO_DISPLAY *d = *dptr; if (d->flags & ALLEGRO_FULLSCREEN) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)d; is_fullscreen[win_display->adapter] = true; fullscreen_found++; } } if (fullscreen_found && fullscreen_found < num) { for (i = 0; i < num; i++) { if (is_fullscreen[i] == false) { a = i; break; } } } al_free(is_fullscreen); al_get_monitor_info(a, &info); win_size.left = info.x1 + (info.x2 - info.x1 - width) / 2; win_size.top = info.y1 + (info.y2 - info.y1 - height) / 2; *out_x = win_size.left; *out_y = win_size.top; } HWND _al_win_create_window(ALLEGRO_DISPLAY *display, int width, int height, int flags) { HWND my_window; DWORD style; DWORD ex_style; DEV_BROADCAST_DEVICEINTERFACE notification_filter; int pos_x, pos_y; bool center = false; ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)display; WINDOWINFO wi; int lsize, rsize, tsize, bsize; // left, right, top, bottom border sizes TCHAR* window_title; wi.cbSize = sizeof(WINDOWINFO); display_flags_to_window_styles(flags, &style, &ex_style); al_get_new_window_position(&pos_x, &pos_y); if ((flags & ALLEGRO_FULLSCREEN) || (flags & ALLEGRO_FULLSCREEN_WINDOW)) { pos_x = pos_y = 0; } else if (pos_x == INT_MAX) { pos_x = pos_y = 0; center = true; } if (center) { _al_win_get_window_center(win_display, width, height, &pos_x, &pos_y); } window_title = _twin_utf8_to_tchar(al_get_new_window_title()); my_window = CreateWindowEx(ex_style, TEXT("ALEX"), window_title, style, pos_x, pos_y, width, height, NULL,NULL,window_class.hInstance,0); al_free(window_title); if (_al_win_register_touch_window) _al_win_register_touch_window(my_window, 0); ZeroMemory(¬ification_filter, sizeof(notification_filter)); notification_filter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); notification_filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; RegisterDeviceNotification(my_window, ¬ification_filter, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); GetWindowInfo(my_window, &wi); lsize = (wi.rcClient.left - wi.rcWindow.left); tsize = (wi.rcClient.top - wi.rcWindow.top); rsize = (wi.rcWindow.right - wi.rcClient.right); bsize = (wi.rcWindow.bottom - wi.rcClient.bottom); SetWindowPos(my_window, 0, 0, 0, width+lsize+rsize, height+tsize+bsize, SWP_NOZORDER | SWP_NOMOVE); SetWindowPos(my_window, 0, pos_x-lsize, pos_y-tsize, 0, 0, SWP_NOZORDER | SWP_NOSIZE); if (flags & ALLEGRO_FRAMELESS) { SetWindowLong(my_window, GWL_STYLE, WS_VISIBLE); SetWindowLong(my_window, GWL_EXSTYLE, WS_EX_APPWINDOW); SetWindowPos(my_window, 0, pos_x, pos_y, width, height, SWP_NOZORDER | SWP_FRAMECHANGED); } ShowWindow(my_window, SW_SHOW); clear_window(my_window, width, height); if (!(flags & ALLEGRO_RESIZABLE) && !(flags & ALLEGRO_FULLSCREEN)) { /* Make the window non-resizable */ HMENU menu; menu = GetSystemMenu(my_window, false); DeleteMenu(menu, SC_SIZE, MF_BYCOMMAND); DeleteMenu(menu, SC_MAXIMIZE, MF_BYCOMMAND); DrawMenuBar(my_window); } _al_vector_init(&win_display->msg_callbacks, sizeof(ALLEGRO_DISPLAY_WIN_CALLBACK)); return my_window; } HWND _al_win_create_faux_fullscreen_window(LPCTSTR devname, ALLEGRO_DISPLAY *display, int x1, int y1, int width, int height, int refresh_rate, int flags) { HWND my_window; DWORD style; DWORD ex_style; DEVMODE mode; LONG temp; TCHAR* window_title; ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)display; (void)flags; _al_vector_init(&win_display->msg_callbacks, sizeof(ALLEGRO_DISPLAY_WIN_CALLBACK)); style = WS_VISIBLE; ex_style = WS_EX_TOPMOST; window_title = _twin_utf8_to_tchar(al_get_new_window_title()); my_window = CreateWindowEx(ex_style, TEXT("ALEX"), window_title, style, x1, y1, width, height, NULL,NULL,window_class.hInstance,0); al_free(window_title); if (_al_win_register_touch_window) _al_win_register_touch_window(my_window, 0); temp = GetWindowLong(my_window, GWL_STYLE); temp &= ~WS_CAPTION; SetWindowLong(my_window, GWL_STYLE, temp); SetWindowPos(my_window, HWND_TOP, 0, 0, width, height, SWP_NOMOVE | SWP_FRAMECHANGED); /* Go fullscreen */ memset(&mode, 0, sizeof(DEVMODE)); mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0; mode.dmBitsPerPel = al_get_new_display_option(ALLEGRO_COLOR_SIZE, NULL); mode.dmPelsWidth = width; mode.dmPelsHeight = height; mode.dmDisplayFlags = 0; mode.dmDisplayFrequency = refresh_rate; mode.dmPosition.x = x1; mode.dmPosition.y = y1; mode.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT|DM_DISPLAYFLAGS| DM_DISPLAYFREQUENCY|DM_POSITION; ChangeDisplaySettingsEx(devname, &mode, NULL, 0, NULL/*CDS_FULLSCREEN*/); clear_window(my_window, width, height); return my_window; } /* _al_win_grab_input: * Makes the passed display grab the input. All consequent input events will be * generated the this display's window. The display's window must the the * foreground window. */ void _al_win_grab_input(ALLEGRO_DISPLAY_WIN *win_disp) { _al_win_wnd_schedule_proc(win_disp->window, _al_win_joystick_dinput_grab, win_disp); } /* Generate a resize event if the size has changed. We cannot asynchronously * change the display size here yet, since the user will only know about a * changed size after receiving the resize event. Here we merely add the * event to the queue. */ static void win_generate_resize_event(ALLEGRO_DISPLAY_WIN *win_display) { ALLEGRO_DISPLAY *display = (ALLEGRO_DISPLAY *)win_display; ALLEGRO_EVENT_SOURCE *es = &display->es; WINDOWINFO wi; int x, y, w, h; if (win_display->ignore_resize || win_display->d3d_ignore_resize) { return; } wi.cbSize = sizeof(WINDOWINFO); GetWindowInfo(win_display->window, &wi); x = wi.rcClient.left; y = wi.rcClient.top; w = wi.rcClient.right - wi.rcClient.left; h = wi.rcClient.bottom - wi.rcClient.top; /* Don't generate events when restoring after minimise. */ if (w == 0 && h == 0 && x == -32000 && y == -32000) return; /* Always generate resize event when constraints are used. * This is needed because d3d_acknowledge_resize() updates d->w, d->h * before this function will be called. */ if (display->use_constraints || display->w != w || display->h != h) { _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_RESIZE; event.display.timestamp = al_get_time(); event.display.x = x; event.display.y = y; event.display.width = w; event.display.height = h; event.display.source = display; _al_event_source_emit_event(es, &event); /* Generate an expose event. */ /* This seems a bit redundant after a resize. */ if (win_display->display.flags & ALLEGRO_GENERATE_EXPOSE_EVENTS) { event.display.type = ALLEGRO_EVENT_DISPLAY_EXPOSE; _al_event_source_emit_event(es, &event); } } _al_event_source_unlock(es); } } static void handle_mouse_capture(bool down, HWND hWnd) { int i; bool any_button_down = false; ALLEGRO_MOUSE_STATE state; if (!al_is_mouse_installed()) return; al_get_mouse_state(&state); for (i = 1; i <= 5; i++) { any_button_down |= al_mouse_button_down(&state, i); } if (down && GetCapture() != hWnd) { SetCapture(hWnd); } else if (!any_button_down) { ReleaseCapture(); } } static void break_window_message_pump(ALLEGRO_DISPLAY_WIN *win_display, HWND hWnd) { /* Get the ID of the thread which created the HWND and is processing its messages */ DWORD wnd_thread_id = GetWindowThreadProcessId(hWnd, NULL); /* Set the "end_thread" flag to stop the message pump */ win_display->end_thread = true; /* Wake-up the message pump so the thread can read the new value of "end_thread" */ PostThreadMessage(wnd_thread_id, WM_NULL, 0, 0); } /* Windows Touch Input emulate WM_MOUSE* events. If we are using touch input explicitly, * we do not want to use this, because Allegro driver provide emulation already. This * way we can be consistent across platforms. */ static bool accept_mouse_event(void) { if (!al_is_touch_input_installed()) return true; return !((GetMessageExtraInfo() & _AL_MOUSEEVENTF_FROMTOUCH) == _AL_MOUSEEVENTF_FROMTOUCH); } /* We want to rate-limit the ALLEGRO_EVENT_DISPLAY_RESIZE events while * live-resizing via mouse. To this end, we detect start/end of this * via WM_ENTERSIZEMOVE/WM_EXITSIZEMOVE and then enable this code to * periodically send those events. */ static void resize_event_thread_proc(void *arg) { (void)arg; while (true) { al_lock_mutex(resize_event_thread_mutex); if (end_resize_event_thread) { al_unlock_mutex(resize_event_thread_mutex); break; } for (int j = 0; j < (int)_al_vector_size(&resizing_displays); j++) { ALLEGRO_DISPLAY_WIN **win_display = (ALLEGRO_DISPLAY_WIN **)_al_vector_ref(&resizing_displays, j); win_generate_resize_event(*win_display); } al_unlock_mutex(resize_event_thread_mutex); Sleep(50); } resize_event_thread_ended = true; } static LRESULT CALLBACK window_callback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { ALLEGRO_DISPLAY *d = NULL; ALLEGRO_DISPLAY_WIN *win_display = NULL; //WINDOWINFO wi; unsigned int i; ALLEGRO_EVENT_SOURCE *es = NULL; ALLEGRO_SYSTEM *system = al_get_system_driver(); //wi.cbSize = sizeof(WINDOWINFO); if (message == _al_win_msg_call_proc) { ((void (*)(void*))wParam) ((void*)lParam); return 0; } if (!system) { return DefWindowProc(hWnd,message,wParam,lParam); } if (message == _al_win_msg_suicide && wParam) { win_display = (ALLEGRO_DISPLAY_WIN*)wParam; break_window_message_pump(win_display, hWnd); if (_al_win_unregister_touch_window) _al_win_unregister_touch_window(hWnd); al_lock_mutex(resize_event_thread_mutex); _al_vector_find_and_delete(&resizing_displays, &win_display); al_unlock_mutex(resize_event_thread_mutex); DestroyWindow(hWnd); return 0; } for (i = 0; i < system->displays._size; i++) { ALLEGRO_DISPLAY **dptr = _al_vector_ref(&system->displays, i); d = *dptr; win_display = (void*)d; if (win_display->window == hWnd) { es = &d->es; break; } } if (i == system->displays._size) return DefWindowProc(hWnd,message,wParam,lParam); if (message == _al_win_msg_suicide) { break_window_message_pump(win_display, hWnd); if (_al_win_unregister_touch_window) _al_win_unregister_touch_window(hWnd); al_lock_mutex(resize_event_thread_mutex); _al_vector_find_and_delete(&resizing_displays, &win_display); al_unlock_mutex(resize_event_thread_mutex); DestroyWindow(hWnd); return 0; } for (i = 0; i < _al_vector_size(&win_display->msg_callbacks); ++i) { LRESULT result = TRUE; ALLEGRO_DISPLAY_WIN_CALLBACK *ptr = _al_vector_ref(&win_display->msg_callbacks, i); if ((ptr->proc)(d, message, wParam, lParam, &result, ptr->userdata)) return result; } switch (message) { case WM_INPUT: { /* RAW Input is currently unused. */ UINT dwSize; LPBYTE lpb; RAWINPUT* raw; /* We can't uninstall WM_INPUT mesages. */ if (!al_is_mouse_installed()) break; GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER)); lpb = al_malloc(sizeof(BYTE)*dwSize); if (lpb == NULL) break; GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)); raw = (RAWINPUT*)lpb; if (raw->header.dwType != RIM_TYPEMOUSE) { al_free(lpb); break; } { RAWMOUSE *rm = &raw->data.mouse; int x = raw->data.mouse.lLastX; int y = raw->data.mouse.lLastY; bool abs = (rm->usFlags & (MOUSE_MOVE_ABSOLUTE | MOUSE_VIRTUAL_DESKTOP)) != 0; if (abs || x || y) _al_win_mouse_handle_move(x, y, abs, win_display); if (rm->usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) _al_win_mouse_handle_button(1, true, x, y, abs, win_display); if (rm->usButtonFlags & RI_MOUSE_BUTTON_1_UP) _al_win_mouse_handle_button(1, false, x, y, abs, win_display); if (rm->usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) _al_win_mouse_handle_button(2, true, x, y, abs, win_display); if (rm->usButtonFlags & RI_MOUSE_BUTTON_2_UP) _al_win_mouse_handle_button(2, false, x, y, abs, win_display); if (rm->usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) _al_win_mouse_handle_button(3, true, x, y, abs, win_display); if (rm->usButtonFlags & RI_MOUSE_BUTTON_3_UP) _al_win_mouse_handle_button(3, false, x, y, abs, win_display); if (rm->usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) _al_win_mouse_handle_button(4, true, x, y, abs, win_display); if (rm->usButtonFlags & RI_MOUSE_BUTTON_4_UP) _al_win_mouse_handle_button(4, false, x, y, abs, win_display); if (rm->usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) _al_win_mouse_handle_button(5, true, x, y, abs, win_display); if (rm->usButtonFlags & RI_MOUSE_BUTTON_5_UP) _al_win_mouse_handle_button(5, false, x, y, abs, win_display); if (rm->usButtonFlags & RI_MOUSE_WHEEL) { SHORT z = (SHORT)rm->usButtonData; _al_win_mouse_handle_wheel(z, false, win_display); } } al_free(lpb); break; } case WM_LBUTTONDOWN: case WM_LBUTTONUP: { if (accept_mouse_event()) { int mx = GET_X_LPARAM(lParam); int my = GET_Y_LPARAM(lParam); bool down = (message == WM_LBUTTONDOWN); _al_win_mouse_handle_button(1, down, mx, my, true, win_display); handle_mouse_capture(down, hWnd); } break; } case WM_MBUTTONDOWN: case WM_MBUTTONUP: { if (accept_mouse_event()) { int mx = GET_X_LPARAM(lParam); int my = GET_Y_LPARAM(lParam); bool down = (message == WM_MBUTTONDOWN); _al_win_mouse_handle_button(3, down, mx, my, true, win_display); handle_mouse_capture(down, hWnd); } break; } case WM_RBUTTONDOWN: case WM_RBUTTONUP: { if (accept_mouse_event()) { int mx = GET_X_LPARAM(lParam); int my = GET_Y_LPARAM(lParam); bool down = (message == WM_RBUTTONDOWN); _al_win_mouse_handle_button(2, down, mx, my, true, win_display); handle_mouse_capture(down, hWnd); } break; } case WM_XBUTTONDOWN: case WM_XBUTTONUP: { if (accept_mouse_event()) { int mx = GET_X_LPARAM(lParam); int my = GET_Y_LPARAM(lParam); int button = HIWORD(wParam); bool down = (message == WM_XBUTTONDOWN); if (button == XBUTTON1) _al_win_mouse_handle_button(4, down, mx, my, true, win_display); else if (button == XBUTTON2) _al_win_mouse_handle_button(5, down, mx, my, true, win_display); handle_mouse_capture(down, hWnd); return TRUE; } break; } case WM_MOUSEWHEEL: { if (accept_mouse_event()) { int d = GET_WHEEL_DELTA_WPARAM(wParam); _al_win_mouse_handle_wheel(d, false, win_display); return TRUE; } break; } case WM_MOUSEHWHEEL: { if (accept_mouse_event()) { int d = GET_WHEEL_DELTA_WPARAM(wParam); _al_win_mouse_handle_hwheel(d, false, win_display); return TRUE; } break; } case WM_MOUSEMOVE: { if (accept_mouse_event()) { TRACKMOUSEEVENT tme; int mx = GET_X_LPARAM(lParam); int my = GET_Y_LPARAM(lParam); if (win_display->mouse_cursor_shown && win_display->hide_mouse_on_move) { win_display->hide_mouse_on_move = false; win_display->display.vt->hide_mouse_cursor((void*)win_display); } _al_win_mouse_handle_move(mx, my, true, win_display); if (mx >= 0 && my >= 0 && mx < d->w && my < d->h) { tme.cbSize = sizeof(tme); tme.dwFlags = TME_QUERY; if (TrackMouseEvent(&tme) && !tme.hwndTrack) { tme.dwFlags = TME_LEAVE; tme.hwndTrack = hWnd; tme.dwHoverTime = 0; TrackMouseEvent(&tme); _al_win_mouse_handle_enter(win_display); } } } /* WM_SETCURSOR messages are not received while the mouse is * captured. We call SetCursor here so that changing the mouse * cursor has an effect while the user is holding down the mouse * button. */ if (GetCapture() == hWnd && win_display->mouse_cursor_shown) { SetCursor(win_display->mouse_selected_hcursor); } break; } case WM_MOUSELEAVE: { if (accept_mouse_event()) { _al_win_mouse_handle_leave(win_display); } break; } case _AL_WM_TOUCH: { if (_al_win_get_touch_input_info && _al_win_close_touch_input_handle) { int number_of_touches = LOWORD(wParam); TOUCHINPUT* touches = al_malloc(number_of_touches * sizeof(TOUCHINPUT)); if (_al_win_get_touch_input_info((HANDLE)lParam, number_of_touches, touches, sizeof(TOUCHINPUT))) { if (al_is_touch_input_installed()) { int i; POINT origin = { 0, 0 }; ClientToScreen(hWnd, &origin); _al_win_touch_input_set_time_stamp((touches + number_of_touches - 1)->dwTime); for (i = 0; i < number_of_touches; ++i) { TOUCHINPUT* touch = touches + i; float x = touch->x / 100.0f - (float)origin.x; float y = touch->y / 100.0f - (float)origin.y; bool primary = touch->dwFlags & _AL_TOUCHEVENTF_PRIMARY ? true : false; if (touch->dwFlags & _AL_TOUCHEVENTF_DOWN) _al_win_touch_input_handle_begin((int)touch->dwID, (size_t)touch->dwTime, x, y, primary, win_display); else if (touch->dwFlags & _AL_TOUCHEVENTF_UP) _al_win_touch_input_handle_end((int)touch->dwID, (size_t)touch->dwTime, x, y, primary, win_display); else if (touch->dwFlags & _AL_TOUCHEVENTF_MOVE) _al_win_touch_input_handle_move((int)touch->dwID, (size_t)touch->dwTime, x, y, primary, win_display); } } _al_win_close_touch_input_handle((HANDLE)lParam); } al_free(touches); } break; } case WM_CAPTURECHANGED: { if (al_is_mouse_installed()) { int i; ALLEGRO_MOUSE_STATE state; if (!lParam || (HWND)lParam == hWnd) break; al_get_mouse_state(&state); for (i = 1; i <= 5; i++) { if (al_mouse_button_down(&state, i)) _al_win_mouse_handle_button(i, 0, 0, 0, true, win_display); } } break; } case WM_NCMOUSEMOVE: { if (!win_display->mouse_cursor_shown) { win_display->display.vt->show_mouse_cursor((void*)win_display); win_display->hide_mouse_on_move = true; } break; } case WM_SYSKEYDOWN: { int vcode = wParam; int scode = (lParam >> 16) & 0xff; bool extended = (lParam >> 24) & 0x1; bool repeated = (lParam >> 30) & 0x1; _al_win_kbd_handle_key_press(scode, vcode, extended, repeated, win_display); break; } case WM_KEYDOWN: { int vcode = wParam; int scode = (lParam >> 16) & 0xff; bool extended = (lParam >> 24) & 0x1; bool repeated = (lParam >> 30) & 0x1; /* We can't use TranslateMessage() because we don't know if it will produce a WM_CHAR or not. */ _al_win_kbd_handle_key_press(scode, vcode, extended, repeated, win_display); break; } case WM_SYSKEYUP: case WM_KEYUP: { int vcode = wParam; int scode = (lParam >> 16) & 0xff; bool extended = (lParam >> 24) & 0x1; bool previous = (lParam >> 30) & 0x1; /* The docs say that previous should always be 1, but it's not in practice. * The events with previous = 0 seem malformed? I can get them reliably by * pressing + holding Shift and then tapping Alt. */ if (previous) _al_win_kbd_handle_key_release(scode, vcode, extended, win_display); break; } case WM_SYSCOMMAND: { DWORD style; DWORD exstyle; if (_al_win_disable_screensaver && ((wParam & 0xfff0) == SC_MONITORPOWER || (wParam & 0xfff0) == SC_SCREENSAVE)) { return 0; } else if ((wParam & 0xfff0) == SC_KEYMENU) { /* Prevent Windows from intercepting the ALT key. (Disables opening menus via the ALT key.) */ return 0; } /* This is used by WM_GETMINMAXINFO to set constraints. */ else if ((wParam & 0xfff0) == SC_MAXIMIZE) { d->flags |= ALLEGRO_MAXIMIZED; display_flags_to_window_styles(d->flags, &style, &exstyle); SetWindowLong(hWnd, GWL_EXSTYLE, exstyle); } else if ((wParam & 0xfff0) == SC_RESTORE) { d->flags &= ~ALLEGRO_MAXIMIZED; display_flags_to_window_styles(d->flags, &style, &exstyle); SetWindowLong(hWnd, GWL_EXSTYLE, exstyle); } break; } case WM_PAINT: { if (win_display->display.flags & ALLEGRO_GENERATE_EXPOSE_EVENTS) { RECT r; HRGN hrgn; GetWindowRect(win_display->window, &r); hrgn = CreateRectRgn(r.left, r.top, r.right, r.bottom); if (GetUpdateRgn(win_display->window, hrgn, false) != ERROR) { PAINTSTRUCT ps; DWORD size; LPRGNDATA rgndata; int n; int i; RECT *rects; BeginPaint(win_display->window, &ps); size = GetRegionData(hrgn, 0, NULL); rgndata = al_malloc(size); GetRegionData(hrgn, size, rgndata); n = rgndata->rdh.nCount; rects = (RECT *)rgndata->Buffer; //GetWindowInfo(win_display->window, &wi); _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_EXPOSE; event.display.timestamp = al_get_time(); for (i = 0; i < n; i++) { event.display.x = rects[i].left; event.display.y = rects[i].top; event.display.width = rects[i].right - rects[i].left; event.display.height = rects[i].bottom - rects[i].top; _al_event_source_emit_event(es, &event); } } _al_event_source_unlock(es); al_free(rgndata); EndPaint(win_display->window, &ps); DeleteObject(hrgn); } return 0; } break; } case WM_SETCURSOR: switch (LOWORD(lParam)) { case HTLEFT: case HTRIGHT: SetCursor(LoadCursor(NULL, IDC_SIZEWE)); break; case HTBOTTOM: case HTTOP: SetCursor(LoadCursor(NULL, IDC_SIZENS)); break; case HTBOTTOMLEFT: case HTTOPRIGHT: SetCursor(LoadCursor(NULL, IDC_SIZENESW)); break; case HTBOTTOMRIGHT: case HTTOPLEFT: SetCursor(LoadCursor(NULL, IDC_SIZENWSE)); break; default: if (win_display->mouse_cursor_shown) { SetCursor(win_display->mouse_selected_hcursor); } else { SetCursor(NULL); } break; } return 1; case WM_ACTIVATE: if (HIWORD(wParam) && LOWORD(wParam) != WA_INACTIVE) break; if (HIWORD(wParam)) d->flags |= ALLEGRO_MINIMIZED; else d->flags &= ~ALLEGRO_MINIMIZED; if (LOWORD(wParam) != WA_INACTIVE) { if (d->vt->switch_in) d->vt->switch_in(d); _al_win_fix_modifiers(); _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; memset(&event, 0, sizeof(event)); event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_IN; event.display.timestamp = al_get_time(); _al_event_source_emit_event(es, &event); } _al_event_source_unlock(es); _al_win_grab_input(win_display); return 0; } else { if (d->flags & ALLEGRO_FULLSCREEN) { d->vt->switch_out(d); } _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; memset(&event, 0, sizeof(event)); event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_OUT; event.display.timestamp = al_get_time(); _al_event_source_emit_event(es, &event); } _al_event_source_unlock(es); return 0; } break; case WM_MENUCHAR : return (MNC_CLOSE << 16) | (wParam & 0xffff); case WM_CLOSE: _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; memset(&event, 0, sizeof(event)); event.display.type = ALLEGRO_EVENT_DISPLAY_CLOSE; event.display.timestamp = al_get_time(); _al_event_source_emit_event(es, &event); } _al_event_source_unlock(es); return 0; case WM_GETMINMAXINFO: /* Set window constraints only when needed. */ if (d->use_constraints) { LPMINMAXINFO p_info = (LPMINMAXINFO)lParam; RECT wRect; RECT cRect; int wWidth; int wHeight; int cWidth; int cHeight; GetWindowRect(hWnd, &wRect); GetClientRect(hWnd, &cRect); wWidth = wRect.right - wRect.left; wHeight = wRect.bottom - wRect.top; cWidth = cRect.right - cRect.left; cHeight = cRect.bottom - cRect.top; /* Client size is zero when the window is restored. */ if (cWidth != 0 && cHeight != 0) { int total_border_width = wWidth - cWidth; int total_border_height = wHeight - cHeight; POINT wmin, wmax; wmin.x = (d->min_w > 0) ? d->min_w + total_border_width : p_info->ptMinTrackSize.x; wmin.y = (d->min_h > 0) ? d->min_h + total_border_height : p_info->ptMinTrackSize.y; /* don't use max_w & max_h constraints when window maximized */ if (d->flags & ALLEGRO_MAXIMIZED) { wmax.x = p_info->ptMaxTrackSize.x; wmax.y = p_info->ptMaxTrackSize.y; } else { wmax.x = (d->max_w > 0) ? d->max_w + total_border_width : p_info->ptMaxTrackSize.x; wmax.y = (d->max_h > 0) ? d->max_h + total_border_height : p_info->ptMaxTrackSize.y; } p_info->ptMinTrackSize = wmin; p_info->ptMaxTrackSize = wmax; } } break; case WM_SIZE: { bool generate = false; if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED) { generate = true; d->flags &= ~ALLEGRO_MAXIMIZED; if (wParam == SIZE_MAXIMIZED) { d->flags |= ALLEGRO_MAXIMIZED; } } else if (d->use_constraints) { /* al_apply_window_constraints() resizes a window if the current * width & height do not fit in the constraint's range. * We have to create the resize event, so the application could * redraw its content. */ generate = true; } al_lock_mutex(resize_event_thread_mutex); if (_al_vector_contains(&resizing_displays, &win_display)) { generate = false; } al_unlock_mutex(resize_event_thread_mutex); if (generate) { win_generate_resize_event(win_display); } return 0; } case WM_ENTERSIZEMOVE: { al_lock_mutex(resize_event_thread_mutex); if (d->flags & ALLEGRO_DIRECT3D_INTERNAL) { win_display->d3d_ignore_resize = true; } ALLEGRO_DISPLAY_WIN **add = (ALLEGRO_DISPLAY_WIN **)_al_vector_alloc_back(&resizing_displays); *add = win_display; al_unlock_mutex(resize_event_thread_mutex); break; } case WM_EXITSIZEMOVE: al_lock_mutex(resize_event_thread_mutex); if (d->flags & ALLEGRO_DIRECT3D_INTERNAL) { win_display->d3d_ignore_resize = false; } _al_vector_find_and_delete(&resizing_displays, &win_display); al_unlock_mutex(resize_event_thread_mutex); win_generate_resize_event(win_display); break; case WM_DPICHANGED: if ((d->flags & ALLEGRO_RESIZABLE) && !(d->flags & ALLEGRO_FULLSCREEN)) { RECT* rect = (RECT*)lParam; // XXX: This doesn't seem to actually move the window... why? SetWindowPos( hWnd, 0, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, SWP_NOZORDER | SWP_NOACTIVATE); win_generate_resize_event(win_display); } break; case WM_DEVICECHANGE: _al_win_joystick_dinput_trigger_enumeration(); break; } return DefWindowProc(hWnd,message,wParam,lParam); } int _al_win_init_window(void) { // Create A Window Class Structure window_class.cbClsExtra = 0; window_class.cbWndExtra = 0; window_class.hbrBackground = NULL; window_class.hCursor = NULL; window_class.hIcon = NULL; window_class.hInstance = GetModuleHandle(NULL); window_class.lpfnWndProc = window_callback; window_class.lpszClassName = TEXT("ALEX"); window_class.lpszMenuName = NULL; window_class.style = CS_VREDRAW|CS_HREDRAW|CS_OWNDC; RegisterClass(&window_class); if (_al_win_msg_call_proc == 0 && _al_win_msg_suicide == 0) { _al_win_msg_call_proc = RegisterWindowMessage(TEXT("Allegro call proc")); _al_win_msg_suicide = RegisterWindowMessage(TEXT("Allegro window suicide")); } resize_event_thread_mutex = al_create_mutex(); _al_vector_init(&resizing_displays, sizeof(ALLEGRO_DISPLAY_WIN *)); _beginthread(resize_event_thread_proc, 0, 0); return true; } void _al_win_shutdown_window(void) { al_lock_mutex(resize_event_thread_mutex); end_resize_event_thread = true; al_unlock_mutex(resize_event_thread_mutex); while (true) { al_lock_mutex(resize_event_thread_mutex); if (resize_event_thread_ended) { al_unlock_mutex(resize_event_thread_mutex); break; } al_unlock_mutex(resize_event_thread_mutex); Sleep(10); } _al_vector_free(&resizing_displays); al_destroy_mutex(resize_event_thread_mutex); resize_event_thread_mutex = NULL; } static int win_choose_icon_bitmap(const int sys_w, const int sys_h, const int num_icons, ALLEGRO_BITMAP *bmps[]) { int best_i = 0; int best_score = INT_MAX; int i; for (i = 0; i < num_icons; i++) { int bmp_w = al_get_bitmap_width(bmps[i]); int bmp_h = al_get_bitmap_height(bmps[i]); int score; if (bmp_w == sys_w && bmp_h == sys_h) return i; /* We prefer to scale up smaller bitmaps to the desired size than to * scale down larger bitmaps. At these resolutions, scaled up bitmaps * look blocky, but scaled down bitmaps can look even worse due to to * dropping crucial pixels. */ if (bmp_w * bmp_h <= sys_w * sys_h) score = (sys_w * sys_h) - (bmp_w * bmp_h); else score = bmp_w * bmp_h; if (score < best_score) { best_score = score; best_i = i; } } return best_i; } static void win_set_display_icon(ALLEGRO_DISPLAY_WIN *win_display, const WPARAM icon_type, const int sys_w, const int sys_h, const int num_icons, ALLEGRO_BITMAP *bmps[]) { HICON icon; HICON old_icon; ALLEGRO_BITMAP *bmp; int bmp_w; int bmp_h; int i; i = win_choose_icon_bitmap(sys_w, sys_h, num_icons, bmps); bmp = bmps[i]; bmp_w = al_get_bitmap_width(bmp); bmp_h = al_get_bitmap_height(bmp); if (bmp_w == sys_w && bmp_h == sys_h) { icon = _al_win_create_icon(win_display->window, bmp, 0, 0, false, false); } else { ALLEGRO_BITMAP *tmp_bmp; ALLEGRO_STATE backup; tmp_bmp = al_create_bitmap(sys_w, sys_h); if (!tmp_bmp) return; al_store_state(&backup, ALLEGRO_STATE_BITMAP | ALLEGRO_STATE_BLENDER); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ARGB_8888); al_set_target_bitmap(tmp_bmp); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_draw_scaled_bitmap(bmp, 0, 0, bmp_w, bmp_h, 0, 0, sys_w, sys_h, 0); al_restore_state(&backup); icon = _al_win_create_icon(win_display->window, tmp_bmp, 0, 0, false, false); al_destroy_bitmap(tmp_bmp); } old_icon = (HICON)SendMessage(win_display->window, WM_SETICON, icon_type, (LPARAM)icon); if (old_icon) DestroyIcon(old_icon); } void _al_win_set_display_icons(ALLEGRO_DISPLAY *display, int num_icons, ALLEGRO_BITMAP *bmps[]) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)display; int sys_w; int sys_h; sys_w = GetSystemMetrics(SM_CXSMICON); sys_h = GetSystemMetrics(SM_CYSMICON); win_set_display_icon(win_display, ICON_SMALL, sys_w, sys_h, num_icons, bmps); sys_w = GetSystemMetrics(SM_CXICON); sys_h = GetSystemMetrics(SM_CYICON); win_set_display_icon(win_display, ICON_BIG, sys_w, sys_h, num_icons, bmps); } void _al_win_destroy_display_icons(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)display; HICON old_icon; old_icon = (HICON)SendMessage(win_display->window, WM_SETICON, ICON_SMALL, 0); if (old_icon) DestroyIcon(old_icon); old_icon = (HICON)SendMessage(win_display->window, WM_SETICON, ICON_BIG, 0); if (old_icon) DestroyIcon(old_icon); } static void get_top_left_border(HWND window, int *left, int *top) { WINDOWINFO wi; wi.cbSize = sizeof(WINDOWINFO); GetWindowInfo(window, &wi); *left = (wi.rcClient.left - wi.rcWindow.left); *top = (wi.rcClient.top - wi.rcWindow.top); } void _al_win_set_window_position(HWND window, int x, int y) { int left, top; get_top_left_border(window, &left, &top); SetWindowPos( window, HWND_TOP, x - left, y - top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } void _al_win_get_window_position(HWND window, int *x, int *y) { RECT r; int left, top; get_top_left_border(window, &left, &top); GetWindowRect(window, &r); if (x) { *x = r.left + left; } if (y) { *y = r.top + top; } } static void update_adapter(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_WIN *win_display = (void*)display; int adapter = al_get_display_adapter(display); if (adapter >= 0) win_display->adapter = adapter; else win_display->adapter = 0; } void _al_win_set_window_frameless(ALLEGRO_DISPLAY *display, HWND hWnd, bool frameless) { int w = display->w; int h = display->h; if (frameless) { SetWindowLong(hWnd, GWL_STYLE, WS_VISIBLE); SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW); SetWindowPos(hWnd, 0, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); } else { RECT r; DWORD style; DWORD exStyle; display_flags_to_window_styles(display->flags, &style, &exStyle); style |= WS_VISIBLE; GetWindowRect(hWnd, &r); AdjustWindowRectEx(&r, style, GetMenu(hWnd) ? TRUE : FALSE, exStyle); w = r.right - r.left; h = r.bottom - r.top; SetWindowLong(hWnd, GWL_STYLE, style); SetWindowLong(hWnd, GWL_EXSTYLE, exStyle); SetWindowPos(hWnd, 0, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); } } bool _al_win_set_display_flag(ALLEGRO_DISPLAY *display, int flag, bool onoff) { ALLEGRO_DISPLAY_WIN *win_display = (void*)display; //double timeout; ALLEGRO_MONITOR_INFO mi; memset(&mi, 0, sizeof(mi)); switch (flag) { case ALLEGRO_FRAMELESS: { if (onoff) { display->flags |= ALLEGRO_FRAMELESS; } else { display->flags &= ~ALLEGRO_FRAMELESS; } _al_win_set_window_frameless(display, win_display->window, (display->flags & ALLEGRO_FRAMELESS)); return true; } case ALLEGRO_FULLSCREEN_WINDOW: if ((display->flags & ALLEGRO_FULLSCREEN_WINDOW) && onoff) { ALLEGRO_DEBUG("Already a fullscreen window\n"); return true; } if (!(display->flags & ALLEGRO_FULLSCREEN_WINDOW) && !onoff) { ALLEGRO_DEBUG("Already a non-fullscreen window\n"); return true; } if (onoff) { /* Switch off frame in fullscreen window mode. */ _al_win_set_window_frameless(display, win_display->window, true); } else { /* Respect display flag in windowed mode. */ _al_win_set_window_frameless(display, win_display->window, (display->flags & ALLEGRO_FRAMELESS)); } if (onoff) { update_adapter(display); int adapter = win_display->adapter; al_get_monitor_info(adapter, &mi); display->flags |= ALLEGRO_FULLSCREEN_WINDOW; display->w = mi.x2 - mi.x1; display->h = mi.y2 - mi.y1; } else { display->flags &= ~ALLEGRO_FULLSCREEN_WINDOW; display->w = win_display->toggle_w; display->h = win_display->toggle_h; } ASSERT(!!(display->flags & ALLEGRO_FULLSCREEN_WINDOW) == onoff); // Hide the window temporarily SetWindowPos(win_display->window, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOZORDER | SWP_NOMOVE); al_resize_display(display, display->w, display->h); if (onoff) { // Move to position SetWindowPos(win_display->window, HWND_TOP, mi.x1, mi.y1, 0, 0, SWP_NOSIZE); } else { int pos_x = 0; int pos_y = 0; WINDOWINFO wi; int bw, bh; // Center the window _al_win_get_window_center(win_display, display->w, display->h, &pos_x, &pos_y); GetWindowInfo(win_display->window, &wi); bw = (wi.rcClient.left - wi.rcWindow.left) + (wi.rcWindow.right - wi.rcClient.right), bh = (wi.rcClient.top - wi.rcWindow.top) + (wi.rcWindow.bottom - wi.rcClient.bottom), SetWindowPos( win_display->window, HWND_TOP, 0, 0, display->w+bw, display->h+bh, SWP_NOMOVE ); SetWindowPos( win_display->window, HWND_TOP, pos_x-bw/2, pos_y-bh/2, 0, 0, SWP_NOSIZE ); } // Show the window again SetWindowPos(win_display->window, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOZORDER | SWP_NOMOVE); // Clear the window to black clear_window(win_display->window, display->w, display->h); ASSERT(!!(display->flags & ALLEGRO_FULLSCREEN_WINDOW) == onoff); return true; case ALLEGRO_MAXIMIZED: if ((!!(display->flags & ALLEGRO_MAXIMIZED)) == onoff) return true; if (onoff) { ShowWindow(win_display->window, SW_SHOWMAXIMIZED); } else { ShowWindow(win_display->window, SW_RESTORE); } return true; } return false; } void _al_win_set_window_title(ALLEGRO_DISPLAY *display, const char *title) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)display; TCHAR *ttitle = _twin_utf8_to_tchar(title); SetWindowText(win_display->window, ttitle); al_free(ttitle); } bool _al_win_set_window_constraints(ALLEGRO_DISPLAY *display, int min_w, int min_h, int max_w, int max_h) { display->min_w = min_w; display->min_h = min_h; display->max_w = max_w; display->max_h = max_h; return true; } void _al_win_apply_window_constraints(ALLEGRO_DISPLAY *display, bool onoff) { if (onoff) { if (!(display->flags & ALLEGRO_MAXIMIZED)) { al_resize_display(display, display->w, display->h); } } } void _al_win_post_create_window(ALLEGRO_DISPLAY *display) { /* Ideally the d3d/wgl window creation would already create the * window maximized - but that code looks too messy to me to touch * right now. */ if (display->flags & ALLEGRO_MAXIMIZED) { display->flags &= ~ALLEGRO_MAXIMIZED; al_set_display_flag(display, ALLEGRO_MAXIMIZED, true); } } bool _al_win_get_window_constraints(ALLEGRO_DISPLAY *display, int *min_w, int *min_h, int *max_w, int *max_h) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)display; *min_w = win_display->display.min_w; *min_h = win_display->display.min_h; *max_w = win_display->display.max_w; *max_h = win_display->display.max_h; return true; } /* _al_win_wnd_call_proc: * instructs the specifed window thread to call the specified procedure. Waits * until the procedure has returned. */ void _al_win_wnd_call_proc(HWND wnd, void (*proc) (void*), void* param) { ASSERT(_al_win_msg_call_proc); SendMessage(wnd, _al_win_msg_call_proc, (WPARAM)proc, (LPARAM)param); } /* _al_win_wnd_schedule_proc: * instructs the specifed window thread to call the specified procedure but * doesn't wait until the procedure has returned. */ void _al_win_wnd_schedule_proc(HWND wnd, void (*proc) (void*), void* param) { ASSERT(_al_win_msg_call_proc); if (!PostMessage(wnd, _al_win_msg_call_proc, (WPARAM)proc, (LPARAM)param)) { ALLEGRO_ERROR("_al_win_wnd_schedule_proc failed.\n"); } } /* Function: al_get_win_window_handle */ HWND al_get_win_window_handle(ALLEGRO_DISPLAY *display) { if (!display) return NULL; return ((ALLEGRO_DISPLAY_WIN *)display)->window; } int _al_win_determine_adapter(void) { int a = al_get_new_display_adapter(); if (a == -1) { int num_screens = al_get_num_video_adapters(); int cScreen = 0; ALLEGRO_MONITOR_INFO temp_info; for (cScreen = 0; cScreen < num_screens; cScreen++) { al_get_monitor_info(cScreen, &temp_info); if (temp_info.x1 == 0 && temp_info.y1 == 0) { // ..probably found primary display return cScreen; } } return 0; // safety measure, probably not necessary } return a; } bool _al_win_get_window_borders(ALLEGRO_DISPLAY *display, int *left, int *top, int *right, int *bottom) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)display; WINDOWINFO wi; wi.cbSize = sizeof(WINDOWINFO); GetWindowInfo(win_display->window, &wi); if (left) *left = (wi.rcClient.left - wi.rcWindow.left); if (top) *top = (wi.rcClient.top - wi.rcWindow.top); if (right) *right = (wi.rcWindow.right - wi.rcClient.right); if (bottom) *bottom = (wi.rcWindow.bottom - wi.rcClient.bottom); return true; } /* Function: al_win_add_window_callback */ bool al_win_add_window_callback(ALLEGRO_DISPLAY *display, bool (*callback)(ALLEGRO_DISPLAY *display, UINT message, WPARAM wparam, LPARAM lparam, LRESULT *result, void *userdata), void *userdata) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *) display; ALLEGRO_DISPLAY_WIN_CALLBACK *ptr; if (!display || !callback) { return false; } else { size_t i; for (i = 0; i < _al_vector_size(&win_display->msg_callbacks); ++i) { ALLEGRO_DISPLAY_WIN_CALLBACK *ptr = _al_vector_ref(&win_display->msg_callbacks, i); if (ptr->proc == callback && ptr->userdata == userdata) return false; } } if (!(ptr = _al_vector_alloc_back(&win_display->msg_callbacks))) return false; ptr->proc = callback; ptr->userdata = userdata; return true; } /* Function: al_win_remove_window_callback */ bool al_win_remove_window_callback(ALLEGRO_DISPLAY *display, bool (*callback)(ALLEGRO_DISPLAY *display, UINT message, WPARAM wparam, LPARAM lparam, LRESULT *result, void *userdata), void *userdata) { ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *) display; if (display && callback) { size_t i; for (i = 0; i < _al_vector_size(&win_display->msg_callbacks); ++i) { ALLEGRO_DISPLAY_WIN_CALLBACK *ptr = _al_vector_ref(&win_display->msg_callbacks, i); if (ptr->proc == callback && ptr->userdata == userdata) { _al_vector_delete_at(&win_display->msg_callbacks, i); return true; } } } return false; } /* vi: set ts=8 sts=3 sw=3 et: */ allegro5-5.2.10.1/src/win/wxthread.c000066400000000000000000000245521473414355200170460ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Internal cross-platform threading API for Windows. * * By Peter Wang. * * See readme.txt for copyright information. */ #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_thread.h" #include #include /* threads */ static unsigned __stdcall thread_proc_trampoline(void *data) { _AL_THREAD *thread = data; (*thread->proc)(thread, thread->arg); /* _endthreadex does not automatically close the thread handle, * unlike _endthread. We rely on this in al_join_thread(). */ _endthreadex(0); return 0; } void _al_thread_create(_AL_THREAD *thread, void (*proc)(_AL_THREAD*, void*), void *arg) { ASSERT(thread); ASSERT(proc); { InitializeCriticalSection(&thread->cs); thread->should_stop = false; thread->proc = proc; thread->arg = arg; thread->thread = (void *)_beginthreadex(NULL, 0, thread_proc_trampoline, thread, 0, NULL); } } void _al_thread_create_with_stacksize(_AL_THREAD* thread, void (*proc)(_AL_THREAD*, void*), void *arg, size_t stacksize) { ASSERT(thread); ASSERT(proc); { InitializeCriticalSection(&thread->cs); thread->should_stop = false; thread->proc = proc; thread->arg = arg; thread->thread = (void *)_beginthreadex(NULL, stacksize, thread_proc_trampoline, thread, 0, NULL); } } void _al_thread_set_should_stop(_AL_THREAD *thread) { ASSERT(thread); EnterCriticalSection(&thread->cs); { thread->should_stop = true; } LeaveCriticalSection(&thread->cs); } void _al_thread_join(_AL_THREAD *thread) { ASSERT(thread); _al_thread_set_should_stop(thread); WaitForSingleObject(thread->thread, INFINITE); CloseHandle(thread->thread); DeleteCriticalSection(&thread->cs); } void _al_thread_detach(_AL_THREAD *thread) { ASSERT(thread); CloseHandle(thread->thread); DeleteCriticalSection(&thread->cs); } /* mutexes */ void _al_mutex_init(_AL_MUTEX *mutex) { ASSERT(mutex); if (!mutex->cs) mutex->cs = al_malloc(sizeof *mutex->cs); ASSERT(mutex->cs); if (mutex->cs) InitializeCriticalSection(mutex->cs); else abort(); } void _al_mutex_init_recursive(_AL_MUTEX *mutex) { /* These are the same on Windows. */ _al_mutex_init(mutex); } void _al_mutex_destroy(_AL_MUTEX *mutex) { ASSERT(mutex); if (mutex->cs) { DeleteCriticalSection(mutex->cs); al_free(mutex->cs); mutex->cs = NULL; } } /* condition variables */ /* * The algorithm used was originally designed for the pthread-win32 * package. I translated the pseudo-code below line for line. * * --- From pthread-win32: --- * Algorithm: * The algorithm used in this implementation is that developed by * Alexander Terekhov in colaboration with Louis Thomas. The bulk * of the discussion is recorded in the file README.CV, which contains * several generations of both colaborators original algorithms. The final * algorithm used here is the one referred to as * * Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL * * presented below in pseudo-code as it appeared: * * [snip] * ------------------------------------------------------------- * * Algorithm 9 / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL * * presented below in pseudo-code; basically 8a... * ...BUT W/O "spurious wakes" prevention: * * * given: * semBlockLock - bin.semaphore * semBlockQueue - semaphore * mtxExternal - mutex or CS * mtxUnblockLock - mutex or CS * nWaitersGone - int * nWaitersBlocked - int * nWaitersToUnblock - int * * wait( timeout ) { * * [auto: register int result ] // error checking omitted * [auto: register int nSignalsWasLeft ] * * sem_wait( semBlockLock ); * ++nWaitersBlocked; * sem_post( semBlockLock ); * * unlock( mtxExternal ); * bTimedOut = sem_wait( semBlockQueue,timeout ); * * lock( mtxUnblockLock ); * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { * --nWaitersToUnblock; * } * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or * // spurious semaphore :-) * sem_wait( semBlockLock ); * nWaitersBlocked -= nWaitersGone; // something is going on here * // - test of timeouts? :-) * sem_post( semBlockLock ); * nWaitersGone = 0; * } * unlock( mtxUnblockLock ); * * if ( 1 == nSignalsWasLeft ) { * sem_post( semBlockLock ); // open the gate * } * * lock( mtxExternal ); * * return ( bTimedOut ) ? ETIMEOUT : 0; * } * * signal(bAll) { * * [auto: register int result ] * [auto: register int nSignalsToIssue] * * lock( mtxUnblockLock ); * * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! * if ( 0 == nWaitersBlocked ) { // NO-OP * return unlock( mtxUnblockLock ); * } * if (bAll) { * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked; * nWaitersBlocked = 0; * } * else { * nSignalsToIssue = 1; * ++nWaitersToUnblock; * --nWaitersBlocked; * } * } * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! * sem_wait( semBlockLock ); // close the gate * if ( 0 != nWaitersGone ) { * nWaitersBlocked -= nWaitersGone; * nWaitersGone = 0; * } * if (bAll) { * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked; * nWaitersBlocked = 0; * } * else { * nSignalsToIssue = nWaitersToUnblock = 1; * --nWaitersBlocked; * } * } * else { // NO-OP * return unlock( mtxUnblockLock ); * } * * unlock( mtxUnblockLock ); * sem_post( semBlockQueue,nSignalsToIssue ); * return result; * } * ------------------------------------------------------------- */ void _al_cond_init(_AL_COND *cond) { cond->nWaitersBlocked = 0; cond->nWaitersGone = 0; cond->nWaitersToUnblock = 0; cond->semBlockQueue = CreateSemaphore(NULL, 0, INT_MAX, NULL); InitializeCriticalSection(&cond->semBlockLock); InitializeCriticalSection(&cond->mtxUnblockLock); } void _al_cond_destroy(_AL_COND *cond) { DeleteCriticalSection(&cond->mtxUnblockLock); DeleteCriticalSection(&cond->semBlockLock); CloseHandle(cond->semBlockQueue); } /* returns -1 on timeout */ static int cond_wait(_AL_COND *cond, _AL_MUTEX *mtxExternal, DWORD timeout) { int nSignalsWasLeft; bool bTimedOut; DWORD dwWaitResult; EnterCriticalSection(&cond->semBlockLock); ++cond->nWaitersBlocked; LeaveCriticalSection(&cond->semBlockLock); _al_mutex_unlock(mtxExternal); dwWaitResult = WaitForSingleObject(cond->semBlockQueue, timeout); if (dwWaitResult == WAIT_TIMEOUT) bTimedOut = true; else if (dwWaitResult == WAIT_OBJECT_0) bTimedOut = false; else { /* bad! what to do? */ _al_mutex_lock(mtxExternal); ASSERT(false); return 0; } EnterCriticalSection(&cond->mtxUnblockLock); if (0 != (nSignalsWasLeft = cond->nWaitersToUnblock)) { --(cond->nWaitersToUnblock); } else if (INT_MAX/2 == ++(cond->nWaitersGone)) { /* timeout/canceled or spurious semaphore :-) */ EnterCriticalSection(&cond->semBlockLock); cond->nWaitersBlocked -= cond->nWaitersGone; /* something is going on here - test of timeouts? :-) */ LeaveCriticalSection(&cond->semBlockLock); cond->nWaitersGone = 0; } LeaveCriticalSection(&cond->mtxUnblockLock); if (1 == nSignalsWasLeft) { LeaveCriticalSection(&cond->semBlockLock); /* open the gate */ } _al_mutex_lock(mtxExternal); return bTimedOut ? -1 : 0; } void _al_cond_wait(_AL_COND *cond, _AL_MUTEX *mtxExternal) { int result; ASSERT(cond); ASSERT(mtxExternal); result = cond_wait(cond, mtxExternal, INFINITE); ASSERT(result != -1); (void)result; } int _al_cond_timedwait(_AL_COND *cond, _AL_MUTEX *mtxExternal, const ALLEGRO_TIMEOUT *timeout) { ALLEGRO_TIMEOUT_WIN *win_timeout = (ALLEGRO_TIMEOUT_WIN *) timeout; DWORD now; DWORD rel_msecs; ASSERT(cond); ASSERT(mtxExternal); now = timeGetTime(); rel_msecs = win_timeout->abstime - now; if (rel_msecs > INT_MAX) { rel_msecs = 0; } return cond_wait(cond, mtxExternal, rel_msecs); } static void cond_signal(_AL_COND *cond, bool bAll) { int nSignalsToIssue; EnterCriticalSection(&cond->mtxUnblockLock); if (0 != cond->nWaitersToUnblock) { /* the gate is closed!!! */ if (0 == cond->nWaitersBlocked) { /* NO-OP */ LeaveCriticalSection(&cond->mtxUnblockLock); return; } if (bAll) { cond->nWaitersToUnblock += (nSignalsToIssue = cond->nWaitersBlocked); cond->nWaitersBlocked = 0; } else { nSignalsToIssue = 1; ++cond->nWaitersToUnblock; --cond->nWaitersBlocked; } } else if (cond->nWaitersBlocked > cond->nWaitersGone) { /* HARMLESS RACE CONDITION! */ EnterCriticalSection(&cond->semBlockLock); /* close the gate */ if (0 != cond->nWaitersGone) { cond->nWaitersBlocked -= cond->nWaitersGone; cond->nWaitersGone = 0; } if (bAll) { nSignalsToIssue = (cond->nWaitersToUnblock = cond->nWaitersBlocked); cond->nWaitersBlocked = 0; } else { nSignalsToIssue = cond->nWaitersToUnblock = 1; --cond->nWaitersBlocked; } } else { /* NO-OP */ LeaveCriticalSection(&cond->mtxUnblockLock); return; } LeaveCriticalSection(&cond->mtxUnblockLock); ReleaseSemaphore(cond->semBlockQueue, nSignalsToIssue, NULL); return; } void _al_cond_broadcast(_AL_COND *cond) { cond_signal(cond, true); } void _al_cond_signal(_AL_COND *cond) { cond_signal(cond, false); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/x/000077500000000000000000000000001473414355200145165ustar00rootroot00000000000000allegro5-5.2.10.1/src/x/icon.inc000066400000000000000000000616421473414355200161520ustar00rootroot00000000000000/* Generated using make_icon.py */ #define ICON_WIDTH 48 #define ICON_HEIGHT 48 static uint32_t icon_data[] = { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0xfcfcfcff,0xfcfcfcff,0xfcfcfcff,0xfcfcfcff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x080808ff,0xfcfcfcff,0xfcfcfcff,0xfcfcfcff,0xfcfcfcff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0xfcfcfcff,0xfcfcfcff,0xfcfcfcff,0xfcfcfcff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x080808ff,0xfcfcfcff,0xfcfcfcff,0xfcfcfcff,0xfcfcfcff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0xfcfcfcff,0xfcfcfcff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0xfcfcfcff,0xfcfcfcff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0xfcfcfcff,0xfcfcfcff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0xfcfcfcff,0xfcfcfcff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x080808ff,0x080808ff,0x486028ff,0x486028ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x486028ff,0x486028ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x080808ff,0x080808ff,0x486028ff,0x486028ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x486028ff,0x486028ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x486028ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x486028ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x486028ff,0x486028ff,0x080808ff, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x486028ff,0x486028ff,0x080808ff, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0xa4c47cff,0xa4c47cff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x486028ff,0x486028ff,0x080808ff, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0xa4c47cff,0xa4c47cff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x486028ff,0x486028ff,0x080808ff, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0xa4c47cff,0xa4c47cff,0x080808ff, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0xa4c47cff,0xa4c47cff,0x080808ff,0x080808ff,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0xa4c47cff,0xa4c47cff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0xa4c47cff,0xa4c47cff,0x080808ff,0x080808ff,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0xa4c47cff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x587834ff,0x486028ff,0x486028ff,0x587834ff,0x587834ff,0x587834ff,0x080808ff,0x080808ff,0x486028ff,0x486028ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x080808ff,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000 }; allegro5-5.2.10.1/src/x/xclipboard.c000066400000000000000000000164741473414355200170250ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_//_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * X11 clipboard handling. * * By Beoran. * * See readme.txt for copyright information. */ #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xclipboard.h" #include "allegro5/internal/aintern_xcursor.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xsystem.h" #ifdef ALLEGRO_RASPBERRYPI #include "allegro5/internal/aintern_raspberrypi.h" #define ALLEGRO_SYSTEM_XGLX ALLEGRO_SYSTEM_RASPBERRYPI #define ALLEGRO_DISPLAY_XGLX ALLEGRO_DISPLAY_RASPBERRYPI #endif ALLEGRO_DEBUG_CHANNEL("clipboard") void _al_xwin_display_selection_notify(ALLEGRO_DISPLAY *display, XSelectionEvent *xselection) { (void) display; (void) xselection; } void _al_xwin_display_selection_request(ALLEGRO_DISPLAY *display, XSelectionRequestEvent *xselectionrequest) { (void) display; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); Display *xdisplay = system->x11display; XSelectionRequestEvent *req; XEvent sevent = { 0 }; int seln_format; unsigned long nbytes; unsigned long overflow; unsigned char *seln_data; req = xselectionrequest; ALLEGRO_DEBUG("window %p: SelectionRequest (requestor = %ld, target = %ld)\n", xdisplay, req->requestor, req->target); memset(&sevent, 0, sizeof(sevent)); sevent.xany.type = SelectionNotify; sevent.xselection.selection = req->selection; sevent.xselection.target = None; sevent.xselection.property = None; sevent.xselection.requestor = req->requestor; sevent.xselection.time = req->time; if (XGetWindowProperty(xdisplay, DefaultRootWindow(xdisplay), XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target, &sevent.xselection.target, &seln_format, &nbytes, &overflow, &seln_data) == Success) { Atom XA_TARGETS = XInternAtom(xdisplay, "TARGETS", 0); if (sevent.xselection.target == req->target) { XChangeProperty(xdisplay, req->requestor, req->property, sevent.xselection.target, seln_format, PropModeReplace, seln_data, nbytes); sevent.xselection.property = req->property; } else if (XA_TARGETS == req->target) { Atom SupportedFormats[] = { sevent.xselection.target, XA_TARGETS }; XChangeProperty(xdisplay, req->requestor, req->property, XA_ATOM, 32, PropModeReplace, (unsigned char *)SupportedFormats, sizeof(SupportedFormats)/sizeof(*SupportedFormats)); sevent.xselection.property = req->property; } XFree(seln_data); } XSendEvent(xdisplay, req->requestor, False, 0, &sevent); XSync(xdisplay, False); } /* Waits for a selection (copy/paste or DND event) */ static bool _al_display_xglx_await_selection_event(ALLEGRO_DISPLAY *d) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)d; ALLEGRO_TIMEOUT timeout; ALLEGRO_DEBUG("Awaiting selection event\n"); XSync(system->x11display, False); /* Wait until the selection event is notified. * Don't wait forever if an event never comes. */ al_init_timeout(&timeout, 1.0); if (_al_cond_timedwait(&glx->selectioned, &system->lock, &timeout) == -1) { ALLEGRO_ERROR("Timeout while waiting for selection event.\n"); return false; } return true; } static bool xdpy_set_clipboard_text(ALLEGRO_DISPLAY *display, const char *text) { ALLEGRO_DISPLAY_XGLX *glx = (void *)display; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); Display *xdisplay = system->x11display; Window xwindow = glx->window; Atom format; Atom XA_CLIPBOARD = XInternAtom(xdisplay, "CLIPBOARD", 0); /* Get the window that will own the selection */ if (xwindow == None) { ALLEGRO_DEBUG("Couldn't find a window to own the selection"); return false; } /* Save the selection on the root window */ /* If you don't support UTF-8, you might use XA_STRING here */ format = XInternAtom(xdisplay, "UTF8_STRING", False); XChangeProperty(xdisplay, DefaultRootWindow(xdisplay), XA_CUT_BUFFER0, format, 8, PropModeReplace, (const unsigned char *)text, strlen(text)); if (XA_CLIPBOARD != None && XGetSelectionOwner(xdisplay, XA_CLIPBOARD) != xwindow) { XSetSelectionOwner(xdisplay, XA_CLIPBOARD, xwindow, CurrentTime); } if (XGetSelectionOwner(xdisplay, XA_PRIMARY) != xwindow) { XSetSelectionOwner(xdisplay, XA_PRIMARY, xwindow, CurrentTime); } return true; } static char *xdpy_get_clipboard_text(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_XGLX *glx = (void *)display; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); Display *xdisplay = system->x11display; Window xwindow = glx->window; Atom format; Window owner; Atom selection; Atom seln_type; int seln_format; unsigned long nbytes; unsigned long overflow; unsigned char *src; char *text = NULL; Atom XA_CLIPBOARD = XInternAtom(xdisplay, "CLIPBOARD", 0); if (XA_CLIPBOARD == None) { ALLEGRO_DEBUG("Couldn't access X clipboard"); return NULL; } /* Get the window that holds the selection */ format = XInternAtom(xdisplay, "UTF8_STRING", 0); owner = XGetSelectionOwner(xdisplay, XA_CLIPBOARD); if ((owner == None) || (owner == xwindow)) { owner = DefaultRootWindow(xdisplay); selection = XA_CUT_BUFFER0; } else { /* Request that the selection owner copy the data to our window. */ owner = xwindow; selection = XInternAtom(xdisplay, "ALLEGRO_SELECTION", False); XConvertSelection(xdisplay, XA_CLIPBOARD, format, selection, owner, CurrentTime); glx->is_selectioned = false; if (!_al_display_xglx_await_selection_event(display)) return NULL; } if (XGetWindowProperty(xdisplay, owner, selection, 0, INT_MAX/4, False, format, &seln_type, &seln_format, &nbytes, &overflow, &src) == Success) { if (seln_type == format) { text = (char *)al_malloc(nbytes+1); if (text) { memcpy(text, src, nbytes); text[nbytes] = '\0'; } } } XFree(src); return text; } static bool xdpy_has_clipboard_text(ALLEGRO_DISPLAY *display) { char *text = xdpy_get_clipboard_text(display); if (!text) { return false; } al_free(text); return true; } void _al_xwin_add_clipboard_functions(ALLEGRO_DISPLAY_INTERFACE *vt) { vt->set_clipboard_text = xdpy_set_clipboard_text; vt->get_clipboard_text = xdpy_get_clipboard_text; vt->has_clipboard_text = xdpy_has_clipboard_text; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/x/xcursor.c000066400000000000000000000201501473414355200163650ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xcursor.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xsystem.h" #ifdef ALLEGRO_RASPBERRYPI #include "allegro5/internal/aintern_raspberrypi.h" #define ALLEGRO_SYSTEM_XGLX ALLEGRO_SYSTEM_RASPBERRYPI #define ALLEGRO_DISPLAY_XGLX ALLEGRO_DISPLAY_RASPBERRYPI #endif #include #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR #include #else /* This requirement could be lifted for compatibility with older systems at the * expense of functionality, but it's probably not worthwhile. */ #error This file requires Xcursor. #endif ALLEGRO_MOUSE_CURSOR *_al_xwin_create_mouse_cursor(ALLEGRO_BITMAP *bmp, int x_focus, int y_focus) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); Display *xdisplay = system->x11display; int bmp_w; int bmp_h; ALLEGRO_MOUSE_CURSOR_XWIN *xcursor; XcursorImage *image; int c, ix, iy; bool was_locked; bmp_w = al_get_bitmap_width(bmp); bmp_h = al_get_bitmap_height(bmp); xcursor = al_malloc(sizeof *xcursor); if (!xcursor) { return NULL; } image = XcursorImageCreate(bmp->w, bmp->h); if (image == None) { al_free(xcursor); return NULL; } was_locked = al_is_bitmap_locked(bmp); if (!was_locked) { al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); } c = 0; for (iy = 0; iy < bmp_h; iy++) { for (ix = 0; ix < bmp_w; ix++) { ALLEGRO_COLOR col; unsigned char r, g, b, a; col = al_get_pixel(bmp, ix, iy); al_unmap_rgba(col, &r, &g, &b, &a); image->pixels[c++] = (a<<24) | (r<<16) | (g<<8) | (b); } } if (!was_locked) { al_unlock_bitmap(bmp); } image->xhot = x_focus; image->yhot = y_focus; _al_mutex_lock(&system->lock); xcursor->cursor = XcursorImageLoadCursor(xdisplay, image); _al_mutex_unlock(&system->lock); XcursorImageDestroy(image); return (ALLEGRO_MOUSE_CURSOR *)xcursor; } void _al_xwin_destroy_mouse_cursor(ALLEGRO_MOUSE_CURSOR *cursor) { ALLEGRO_MOUSE_CURSOR_XWIN *xcursor = (ALLEGRO_MOUSE_CURSOR_XWIN *)cursor; ALLEGRO_SYSTEM *sys = al_get_system_driver(); ALLEGRO_SYSTEM_XGLX *sysx = (ALLEGRO_SYSTEM_XGLX *)sys; unsigned i; _al_mutex_lock(&sysx->lock); for (i = 0; i < _al_vector_size(&sys->displays); i++) { ALLEGRO_DISPLAY_XGLX **slot = _al_vector_ref(&sys->displays, i); ALLEGRO_DISPLAY_XGLX *glx = *slot; if (glx->current_cursor == xcursor->cursor) { if (!glx->cursor_hidden) XUndefineCursor(sysx->x11display, glx->window); glx->current_cursor = None; } } XFreeCursor(sysx->x11display, xcursor->cursor); al_free(xcursor); _al_mutex_unlock(&sysx->lock); } static bool xdpy_set_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_MOUSE_CURSOR *cursor) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; ALLEGRO_MOUSE_CURSOR_XWIN *xcursor = (ALLEGRO_MOUSE_CURSOR_XWIN *)cursor; ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); Display *xdisplay = system->x11display; Window xwindow = glx->window; glx->current_cursor = xcursor->cursor; if (!glx->cursor_hidden) { _al_mutex_lock(&system->lock); XDefineCursor(xdisplay, xwindow, glx->current_cursor); _al_mutex_unlock(&system->lock); } return true; } static bool xdpy_set_system_mouse_cursor(ALLEGRO_DISPLAY *display, ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); Display *xdisplay = system->x11display; Window xwindow = glx->window; unsigned int cursor_shape; switch (cursor_id) { case ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT: case ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW: case ALLEGRO_SYSTEM_MOUSE_CURSOR_PROGRESS: cursor_shape = XC_left_ptr; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_BUSY: cursor_shape = XC_watch; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_QUESTION: cursor_shape = XC_question_arrow; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT: cursor_shape = XC_xterm; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE: cursor_shape = XC_fleur; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N: cursor_shape = XC_top_side; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_S: cursor_shape = XC_bottom_side; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E: cursor_shape = XC_right_side; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_W: cursor_shape = XC_left_side; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE: cursor_shape = XC_top_right_corner; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_SW: cursor_shape = XC_bottom_left_corner; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW: cursor_shape = XC_top_left_corner; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_SE: cursor_shape = XC_bottom_right_corner; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_PRECISION: cursor_shape = XC_crosshair; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_LINK: cursor_shape = XC_hand2; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_ALT_SELECT: cursor_shape = XC_hand1; break; case ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE: cursor_shape = XC_X_cursor; break; default: return false; } _al_mutex_lock(&system->lock); glx->current_cursor = XCreateFontCursor(xdisplay, cursor_shape); /* XXX: leak? */ if (!glx->cursor_hidden) { XDefineCursor(xdisplay, xwindow, glx->current_cursor); } _al_mutex_unlock(&system->lock); return true; } /* Show the system mouse cursor. */ static bool xdpy_show_mouse_cursor(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_XGLX *glx = (void *)display; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); Display *xdisplay = system->x11display; Window xwindow = glx->window; if (!glx->cursor_hidden) return true; _al_mutex_lock(&system->lock); XDefineCursor(xdisplay, xwindow, glx->current_cursor); glx->cursor_hidden = false; _al_mutex_unlock(&system->lock); return true; } /* Hide the system mouse cursor. */ static bool xdpy_hide_mouse_cursor(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_XGLX *glx = (void *)display; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); Display *xdisplay = system->x11display; Window xwindow = glx->window; if (glx->cursor_hidden) return true; _al_mutex_lock(&system->lock); if (glx->invisible_cursor == None) { unsigned long gcmask; XGCValues gcvalues; Pixmap pixmap = XCreatePixmap(xdisplay, xwindow, 1, 1, 1); GC temp_gc; XColor color; gcmask = GCFunction | GCForeground | GCBackground; gcvalues.function = GXcopy; gcvalues.foreground = 0; gcvalues.background = 0; temp_gc = XCreateGC(xdisplay, pixmap, gcmask, &gcvalues); XDrawPoint(xdisplay, pixmap, temp_gc, 0, 0); XFreeGC(xdisplay, temp_gc); color.pixel = 0; color.red = color.green = color.blue = 0; color.flags = DoRed | DoGreen | DoBlue; glx->invisible_cursor = XCreatePixmapCursor(xdisplay, pixmap, pixmap, &color, &color, 0, 0); XFreePixmap(xdisplay, pixmap); } XDefineCursor(xdisplay, xwindow, glx->invisible_cursor); glx->cursor_hidden = true; _al_mutex_unlock(&system->lock); return true; } void _al_xwin_add_cursor_functions(ALLEGRO_DISPLAY_INTERFACE *vt) { vt->set_mouse_cursor = xdpy_set_mouse_cursor; vt->set_system_mouse_cursor = xdpy_set_system_mouse_cursor; vt->show_mouse_cursor = xdpy_show_mouse_cursor; vt->hide_mouse_cursor = xdpy_hide_mouse_cursor; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/x/xdisplay.c000066400000000000000000001351121473414355200165220ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xcursor.h" #include "allegro5/internal/aintern_xclipboard.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xfullscreen.h" #include "allegro5/internal/aintern_xglx_config.h" #include "allegro5/internal/aintern_xsystem.h" #include "allegro5/internal/aintern_xtouch.h" #include "allegro5/internal/aintern_xwindow.h" #include "allegro5/internal/aintern_xdnd.h" #include "allegro5/platform/aintxglx.h" #include #ifdef ALLEGRO_XWINDOWS_WITH_XINPUT2 #include #endif #include "xicon.h" #include "icon.inc" ALLEGRO_DEBUG_CHANNEL("display") static ALLEGRO_DISPLAY_INTERFACE xdpy_vt; static const ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE default_overridable_vt; static const ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE *gtk_override_vt = NULL; static void xdpy_destroy_display(ALLEGRO_DISPLAY *d); static bool xdpy_acknowledge_resize(ALLEGRO_DISPLAY *d); /* XXX where does this belong? */ static void _al_xglx_use_adapter(ALLEGRO_SYSTEM_XGLX *s, int adapter) { ALLEGRO_DEBUG("use adapter %i\n", adapter); s->adapter_use_count++; s->adapter_map[adapter]++; } static void _al_xglx_unuse_adapter(ALLEGRO_SYSTEM_XGLX *s, int adapter) { ALLEGRO_DEBUG("unuse adapter %i\n", adapter); s->adapter_use_count--; s->adapter_map[adapter]--; } static bool check_adapter_use_count(ALLEGRO_SYSTEM_XGLX *system) { /* If we're in multi-head X mode, bail out if we try to use more than one * display as there are bugs in X/glX that cause us to hang in X if we try * to use more than one. * If we're in real xinerama mode, also bail out, X makes mouse use evil. */ bool true_xinerama_active = false; #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA bool xrandr_active = false; #ifdef ALLEGRO_XWINDOWS_WITH_XRANDR xrandr_active = system->xrandr_available; #endif true_xinerama_active = !xrandr_active && system->xinerama_available; #endif if ((true_xinerama_active || ScreenCount(system->x11display) > 1) && system->adapter_use_count > 0) { int i, adapter_use_count = 0; /* XXX magic constant */ for (i = 0; i < 32; i++) { if (system->adapter_map[i]) adapter_use_count++; } if (adapter_use_count > 1) { ALLEGRO_ERROR("Use of more than one adapter at once in " "multi-head X or X with true Xinerama active is not possible.\n"); return false; } } return true; } static int query_glx_version(ALLEGRO_SYSTEM_XGLX *system) { int major, minor; int version; glXQueryVersion(system->x11display, &major, &minor); version = major * 100 + minor * 10; ALLEGRO_INFO("GLX %.1f.\n", version / 100.f); return version; } static int xdpy_swap_control(ALLEGRO_DISPLAY *display, int vsync_setting) { /* We set the swap interval to 0 if vsync is forced off, and to 1 * if it is forced on. * http://www.opengl.org/registry/specs/SGI/swap_control.txt * If the option is set to 0, we simply use the system default. The * above extension specifies vsync on as default though, so in the * end with GLX we can't force vsync on, just off. */ ALLEGRO_DEBUG("requested vsync=%d.\n", vsync_setting); if (vsync_setting) { if (display->ogl_extras->extension_list->ALLEGRO_GLX_SGI_swap_control) { int x = (vsync_setting == 2) ? 0 : 1; if (glXSwapIntervalSGI(x)) { ALLEGRO_WARN("glXSwapIntervalSGI(%d) failed.\n", x); } } else { ALLEGRO_WARN("no vsync, GLX_SGI_swap_control missing.\n"); /* According to the specification that means it's on, but * the driver might have disabled it. So we do not know. */ vsync_setting = 0; } } return vsync_setting; } static bool should_bypass_compositor(int flags) { const char* value = al_get_config_value(al_get_system_config(), "x11", "bypass_compositor"); if (value && strcmp(value, "always") == 0) { return true; } if (value && strcmp(value, "never") == 0) { return false; } // default to "fullscreen_only" return (flags & ALLEGRO_FULLSCREEN) || (flags & ALLEGRO_FULLSCREEN_WINDOW); } static void set_compositor_bypass_flag(ALLEGRO_DISPLAY *display) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; const long _NET_WM_BYPASS_COMPOSITOR_HINT_ON = should_bypass_compositor(display->flags); Atom _NET_WM_BYPASS_COMPOSITOR; _NET_WM_BYPASS_COMPOSITOR = XInternAtom(system->x11display, "_NET_WM_BYPASS_COMPOSITOR", False); XChangeProperty(system->x11display, glx->window, _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&_NET_WM_BYPASS_COMPOSITOR_HINT_ON, 1); } static bool xdpy_create_display_window(ALLEGRO_SYSTEM_XGLX *system, ALLEGRO_DISPLAY_XGLX *d, int w, int h, int adapter) { ALLEGRO_DISPLAY *display = (ALLEGRO_DISPLAY *)d; /* Create a colormap. */ Colormap cmap = XCreateColormap(system->x11display, RootWindow(system->x11display, d->xvinfo->screen), d->xvinfo->visual, AllocNone); /* Create an X11 window */ XSetWindowAttributes swa; int mask = CWBorderPixel | CWColormap | CWEventMask; swa.colormap = cmap; swa.border_pixel = 0; swa.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask | ExposureMask | PropertyChangeMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask; /* We handle these events via GTK-sent XEmbed events. */ if (!(display->flags & ALLEGRO_GTK_TOPLEVEL_INTERNAL)) { swa.event_mask |= FocusChangeMask; } /* For a non-compositing window manager, a black background can look * less broken if the application doesn't react to expose events fast * enough. However in some cases like resizing, the black background * causes horrible flicker. */ if (!(display->flags & ALLEGRO_RESIZABLE)) { mask |= CWBackPixel; swa.background_pixel = BlackPixel(system->x11display, d->xvinfo->screen); } int x_off = INT_MAX; int y_off = INT_MAX; if (display->flags & ALLEGRO_FULLSCREEN) { _al_xglx_get_display_offset(system, d->adapter, &x_off, &y_off); } else { /* We want new_display_adapter's offset to add to the * new_window_position. */ int xscr_x = 0; int xscr_y = 0; al_get_new_window_position(&x_off, &y_off); if (x_off != INT_MAX && y_off != INT_MAX) { d->need_initial_position_adjust = true; ALLEGRO_DEBUG("Will adjust window position later to %d/%d\n", x_off, y_off); } if (adapter >= 0) { /* Non default adapter. I'm assuming this means the user wants the * window to be placed on the adapter offset by new display pos. */ _al_xglx_get_display_offset(system, d->adapter, &xscr_x, &xscr_y); if (x_off != INT_MAX) x_off += xscr_x; if (y_off != INT_MAX) y_off += xscr_y; } } d->window = XCreateWindow(system->x11display, RootWindow(system->x11display, d->xvinfo->screen), x_off != INT_MAX ? x_off : 0, y_off != INT_MAX ? y_off : 0, w, h, 0, d->xvinfo->depth, InputOutput, d->xvinfo->visual, mask, &swa); ALLEGRO_DEBUG("Window ID: %ld\n", (long)d->window); /* Try to set full screen mode if requested, fail if we can't. */ if (display->flags & ALLEGRO_FULLSCREEN) { /* According to the spec, the window manager is supposed to disable * window decorations when _NET_WM_STATE_FULLSCREEN is in effect. * However, some WMs may not be fully compliant, e.g. Fluxbox. */ _al_xwin_set_frame(display, false); _al_xwin_set_above(display, 1); if (!_al_xglx_fullscreen_set_mode(system, d, w, h, 0, display->refresh_rate)) { ALLEGRO_DEBUG("xdpy: failed to set fullscreen mode.\n"); return false; } } ALLEGRO_DEBUG("X11 window created.\n"); /* Set the PID related to the window. */ Atom _NET_WM_PID = XInternAtom(system->x11display, "_NET_WM_PID", False); int pid = getpid(); XChangeProperty(system->x11display, d->window, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1); _al_xwin_set_size_hints(display, x_off, y_off); /* Let the window manager know we're a "normal" window */ Atom _NET_WM_WINDOW_TYPE; Atom _NET_WM_WINDOW_TYPE_NORMAL; _NET_WM_WINDOW_TYPE = XInternAtom(system->x11display, "_NET_WM_WINDOW_TYPE", False); _NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(system->x11display, "_NET_WM_WINDOW_TYPE_NORMAL", False); XChangeProperty(system->x11display, d->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *)&_NET_WM_WINDOW_TYPE_NORMAL, 1); /* This seems like a good idea */ set_compositor_bypass_flag(display); #ifdef ALLEGRO_XWINDOWS_WITH_XINPUT2 /* listen for touchscreen events */ XIEventMask event_mask; event_mask.deviceid = XIAllMasterDevices; event_mask.mask_len = XIMaskLen(XI_TouchEnd); event_mask.mask = (unsigned char*)al_calloc(3, sizeof(char)); XISetMask(event_mask.mask, XI_TouchBegin); XISetMask(event_mask.mask, XI_TouchUpdate); XISetMask(event_mask.mask, XI_TouchEnd); XISelectEvents(system->x11display, d->window, &event_mask, 1); al_free(event_mask.mask); #endif return true; } static ALLEGRO_DISPLAY_XGLX *xdpy_create_display_locked( ALLEGRO_SYSTEM_XGLX *system, int flags, int w, int h, int adapter) { ALLEGRO_DISPLAY_XGLX *d = al_calloc(1, sizeof *d); ALLEGRO_DISPLAY *display = (ALLEGRO_DISPLAY *)d; ALLEGRO_OGL_EXTRAS *ogl = al_calloc(1, sizeof *ogl); display->ogl_extras = ogl; d->glx_version = query_glx_version(system); display->w = w; display->h = h; display->vt = _al_display_xglx_driver(); display->refresh_rate = al_get_new_display_refresh_rate(); display->flags = flags; // FIXME: default? Is this the right place to set this? display->flags |= ALLEGRO_OPENGL; #ifdef ALLEGRO_CFG_OPENGLES2 display->flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; #endif #ifdef ALLEGRO_CFG_OPENGLES display->flags |= ALLEGRO_OPENGL_ES_PROFILE; #endif /* Store our initial virtual adapter, used by fullscreen and positioning * code. */ ALLEGRO_DEBUG("selected adapter %i\n", adapter); if (adapter < 0) d->adapter = _al_xglx_get_default_adapter(system); else d->adapter = adapter; ALLEGRO_DEBUG("xdpy: selected adapter %i\n", d->adapter); _al_xglx_use_adapter(system, d->adapter); if (!check_adapter_use_count(system)) { goto EarlyError; } /* Store our initial X Screen, used by window creation, fullscreen, and glx * visual code. */ d->xscreen = _al_xglx_get_xscreen(system, d->adapter); ALLEGRO_DEBUG("xdpy: selected xscreen %i\n", d->xscreen); d->wm_delete_window_atom = None; d->is_mapped = false; _al_cond_init(&d->mapped); d->is_selectioned = false; _al_cond_init(&d->selectioned); d->resize_count = 0; d->programmatic_resize = false; _al_xglx_config_select_visual(d); if (!d->xvinfo) { ALLEGRO_ERROR("FIXME: Need better visual selection.\n"); ALLEGRO_ERROR("No matching visual found.\n"); goto EarlyError; } ALLEGRO_INFO("Selected X11 visual %lu.\n", d->xvinfo->visualid); /* Add ourself to the list of displays. */ ALLEGRO_DISPLAY_XGLX **add; add = _al_vector_alloc_back(&system->system.displays); *add = d; /* Each display is an event source. */ _al_event_source_init(&display->es); if (!xdpy_create_display_window(system, d, w, h, adapter)) { goto LateError; } /* Send any pending requests to the X server. * This is necessary to make the window ID immediately valid * for a GtkSocket. */ XSync(system->x11display, False); if (display->flags & ALLEGRO_GTK_TOPLEVEL_INTERNAL) { ASSERT(gtk_override_vt); if (!gtk_override_vt->create_display_hook(display, w, h)) { goto LateError; } } else { default_overridable_vt.set_window_title(display, al_get_new_window_title()); if (!default_overridable_vt.create_display_hook(display, w, h)) { goto LateError; } } /* overridable_vt should be set by the create_display_hook. */ ASSERT(d->overridable_vt); /* Send any pending requests to the X server. */ XSync(system->x11display, False); /* To avoid race conditions where some X11 functions fail before the window * is mapped, we wait here until it is mapped. Note that the thread is * locked, so the event could not possibly have been processed yet in the * events thread. So as long as no other map events occur, the condition * should only be signalled when our window gets mapped. */ while (!d->is_mapped) { _al_cond_wait(&d->mapped, &system->lock); } /* In tiling WMs, we might get resize events pretty much immediately after * Window creation. This location seems to catch them reliably, tested with * dwm, awesome, xmonad and i3. */ if ((display->flags & ALLEGRO_RESIZABLE) && d->resize_count > 0) { xdpy_acknowledge_resize(display); } /* We can do this at any time, but if we already have a mapped * window when switching to fullscreen it will use the same * monitor (with the MetaCity version I'm using here right now). */ if ((display->flags & ALLEGRO_FULLSCREEN_WINDOW)) { ALLEGRO_INFO("Toggling fullscreen flag for %d x %d window.\n", display->w, display->h); _al_xwin_reset_size_hints(display); _al_xwin_set_fullscreen_window(display, 2); _al_xwin_set_size_hints(display, INT_MAX, INT_MAX); XWindowAttributes xwa; XGetWindowAttributes(system->x11display, d->window, &xwa); display->w = xwa.width; display->h = xwa.height; ALLEGRO_INFO("Using ALLEGRO_FULLSCREEN_WINDOW of %d x %d\n", display->w, display->h); } if (display->flags & ALLEGRO_FULLSCREEN) { /* kwin wants these here */ /* metacity wants these here too */ /* XXX compiz is quiky, can't seem to find a combination of hints that * make sure we are layerd over panels, and are positioned properly */ //_al_xwin_set_fullscreen_window(display, 1); _al_xwin_set_above(display, 1); _al_xglx_fullscreen_to_display(system, d); /* Grab mouse if we only have one display, ungrab it if we have more than * one. */ if (_al_vector_size(&system->system.displays) == 1) { al_grab_mouse(display); } else if (_al_vector_size(&system->system.displays) > 1) { al_ungrab_mouse(); } } if (display->flags & ALLEGRO_FRAMELESS) { /* set_display_flag works by comparing to current flag value, so we need * to start with an unset state. */ display->flags &= ~ALLEGRO_FRAMELESS; /* Call the vt directly to bypass system lock. */ d->overridable_vt->set_display_flag(display, ALLEGRO_FRAMELESS, true); } if (display->flags & ALLEGRO_DRAG_AND_DROP) { _al_xwin_accept_drag_and_drop(display, true); } if (flags & ALLEGRO_MAXIMIZED) { /* set_display_flag works by comparing to current flag value, so we need * to start with an unset state. */ display->flags &= ~ALLEGRO_MAXIMIZED; /* Call the vt directly to bypass system lock. */ d->overridable_vt->set_display_flag(display, ALLEGRO_MAXIMIZED, true); } if (!_al_xglx_config_create_context(d)) { goto LateError; } /* Make our GLX context current for reading and writing in the current * thread. */ if (d->fbc) { if (!glXMakeContextCurrent(system->gfxdisplay, d->glxwindow, d->glxwindow, d->context)) { ALLEGRO_ERROR("glXMakeContextCurrent failed\n"); } } else { if (!glXMakeCurrent(system->gfxdisplay, d->glxwindow, d->context)) { ALLEGRO_ERROR("glXMakeCurrent failed\n"); } } _al_ogl_manage_extensions(display); _al_ogl_set_extensions(ogl->extension_api); /* Print out OpenGL version info */ ALLEGRO_INFO("OpenGL Version: %s\n", (const char*)glGetString(GL_VERSION)); ALLEGRO_INFO("Vendor: %s\n", (const char*)glGetString(GL_VENDOR)); ALLEGRO_INFO("Renderer: %s\n", (const char*)glGetString(GL_RENDERER)); /* Fill in opengl version */ const int v = display->ogl_extras->ogl_info.version; display->extra_settings.settings[ALLEGRO_OPENGL_MAJOR_VERSION] = (v >> 24) & 0xFF; display->extra_settings.settings[ALLEGRO_OPENGL_MINOR_VERSION] = (v >> 16) & 0xFF; if (display->ogl_extras->ogl_info.version < _ALLEGRO_OPENGL_VERSION_1_2) { ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = _al_get_new_display_settings(); if (eds->required & (1<extra_settings.settings[ALLEGRO_COMPATIBLE_DISPLAY] = 0; } if (display->extra_settings.settings[ALLEGRO_COMPATIBLE_DISPLAY]) _al_ogl_setup_gl(display); /* vsync */ int vsync_setting = _al_get_new_display_settings()->settings[ALLEGRO_VSYNC]; vsync_setting = xdpy_swap_control(display, vsync_setting); display->extra_settings.settings[ALLEGRO_VSYNC] = vsync_setting; d->invisible_cursor = None; /* Will be created on demand. */ d->current_cursor = None; /* Initially, we use the root cursor. */ d->cursor_hidden = false; d->icon = None; d->icon_mask = None; return d; EarlyError: al_free(d); al_free(ogl); return NULL; LateError: xdpy_destroy_display(display); return NULL; } static bool xdpy_create_display_hook_default(ALLEGRO_DISPLAY *display, int w, int h) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *d = (ALLEGRO_DISPLAY_XGLX *)display; (void)w; (void)h; if (_al_xwin_initial_icon) { ALLEGRO_BITMAP *bitmaps[] = {_al_xwin_initial_icon}; _al_xwin_set_icons(display, 1, bitmaps); } else { ALLEGRO_STATE state; al_store_state(&state, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); ALLEGRO_BITMAP *bitmap = al_create_bitmap(ICON_WIDTH, ICON_HEIGHT); al_restore_state(&state); ALLEGRO_LOCKED_REGION *lr = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_RGBA_8888, ALLEGRO_LOCK_WRITEONLY); for (int y = 0; y < ICON_HEIGHT; y++) { memcpy((char*)lr->data + lr->pitch * y, &icon_data[ICON_WIDTH * y], ICON_WIDTH * 4); } al_unlock_bitmap(bitmap); ALLEGRO_BITMAP *bitmaps[] = {bitmap}; _al_xwin_set_icons(display, 1, bitmaps); al_destroy_bitmap(bitmap); } XLockDisplay(system->x11display); XMapWindow(system->x11display, d->window); ALLEGRO_DEBUG("X11 window mapped.\n"); d->wm_delete_window_atom = XInternAtom(system->x11display, "WM_DELETE_WINDOW", False); XSetWMProtocols(system->x11display, d->window, &d->wm_delete_window_atom, 1); XUnlockDisplay(system->x11display); d->overridable_vt = &default_overridable_vt; return true; } /* Create a new X11 display, which maps directly to a GLX window. */ static ALLEGRO_DISPLAY *xdpy_create_display(int w, int h) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *display; int flags; int adapter; if (system->x11display == NULL) { ALLEGRO_WARN("Not connected to X server.\n"); return NULL; } if (w <= 0 || h <= 0) { ALLEGRO_ERROR("Invalid window size %dx%d\n", w, h); return NULL; } flags = al_get_new_display_flags(); if (flags & ALLEGRO_GTK_TOPLEVEL_INTERNAL) { if (gtk_override_vt == NULL) { ALLEGRO_ERROR("GTK requested but unavailable\n"); return NULL; } if (flags & ALLEGRO_FULLSCREEN) { ALLEGRO_ERROR("GTK incompatible with fullscreen\n"); return NULL; } } _al_mutex_lock(&system->lock); adapter = al_get_new_display_adapter(); display = xdpy_create_display_locked(system, flags, w, h, adapter); _al_mutex_unlock(&system->lock); return (ALLEGRO_DISPLAY *)display; } static void convert_display_bitmaps_to_memory_bitmap(ALLEGRO_DISPLAY *d) { ALLEGRO_DEBUG("converting display bitmaps to memory bitmaps.\n"); while (d->bitmaps._size > 0) { ALLEGRO_BITMAP **bptr = _al_vector_ref_back(&d->bitmaps); ALLEGRO_BITMAP *b = *bptr; _al_convert_to_memory_bitmap(b); } } static void transfer_display_bitmaps_to_any_other_display( ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY *d) { size_t i; ALLEGRO_DISPLAY *living = NULL; ASSERT(s->system.displays._size > 1); for (i = 0; i < s->system.displays._size; i++) { ALLEGRO_DISPLAY **slot = _al_vector_ref(&s->system.displays, i); living = *slot; if (living != d) break; } ALLEGRO_DEBUG("transferring display bitmaps to other display.\n"); for (i = 0; i < d->bitmaps._size; i++) { ALLEGRO_BITMAP **add = _al_vector_alloc_back(&(living->bitmaps)); ALLEGRO_BITMAP **ref = _al_vector_ref(&d->bitmaps, i); *add = *ref; (*add)->_display = living; } } static void restore_mode_if_last_fullscreen_display(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d) { bool last_fullscreen = true; size_t i; /* If any other fullscreen display is still active on the same adapter, * we must not touch the video mode. */ for (i = 0; i < s->system.displays._size; i++) { ALLEGRO_DISPLAY_XGLX **slot = _al_vector_ref(&s->system.displays, i); ALLEGRO_DISPLAY_XGLX *living = *slot; if (living == d) continue; /* Check for fullscreen displays on the same adapter. */ if (living->adapter == d->adapter && (living->display.flags & ALLEGRO_FULLSCREEN)) { last_fullscreen = false; } } if (last_fullscreen) { ALLEGRO_DEBUG("restore mode.\n"); _al_xglx_restore_video_mode(s, d->adapter); } else { ALLEGRO_DEBUG("*not* restoring mode.\n"); } } static void xdpy_destroy_display_hook_default(ALLEGRO_DISPLAY *d, bool is_last) { ALLEGRO_SYSTEM_XGLX *s = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)d; (void)is_last; if (glx->context) { glXDestroyContext(s->gfxdisplay, glx->context); glx->context = NULL; ALLEGRO_DEBUG("destroy context.\n"); } if (glx->fbc) { al_free(glx->fbc); glx->fbc = NULL; XFree(glx->xvinfo); glx->xvinfo = NULL; } else if (glx->xvinfo) { al_free(glx->xvinfo); glx->xvinfo = NULL; } if ((glx->glxwindow) && (glx->glxwindow != glx->window)) { glXDestroyWindow(s->x11display, glx->glxwindow); glx->glxwindow = 0; ALLEGRO_DEBUG("destroy glx window\n"); } _al_cond_destroy(&glx->mapped); _al_cond_destroy(&glx->selectioned); ALLEGRO_DEBUG("destroy window.\n"); XDestroyWindow(s->x11display, glx->window); _al_xglx_unuse_adapter(s, glx->adapter); if (d->flags & ALLEGRO_FULLSCREEN) { restore_mode_if_last_fullscreen_display(s, glx); } } static void xdpy_destroy_display(ALLEGRO_DISPLAY *d) { ALLEGRO_SYSTEM_XGLX *s = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)d; ALLEGRO_OGL_EXTRAS *ogl = d->ogl_extras; bool is_last; ALLEGRO_DEBUG("destroying display.\n"); /* If we're the last display, convert all bitmaps to display independent * (memory) bitmaps. Otherwise, pass all bitmaps to any other living * display. We assume all displays are compatible.) */ is_last = (s->system.displays._size == 1); if (is_last) convert_display_bitmaps_to_memory_bitmap(d); else transfer_display_bitmaps_to_any_other_display(s, d); _al_ogl_unmanage_extensions(d); ALLEGRO_DEBUG("unmanaged extensions.\n"); _al_mutex_lock(&s->lock); _al_vector_find_and_delete(&s->system.displays, &d); if (ogl->backbuffer) { _al_ogl_destroy_backbuffer(ogl->backbuffer); ogl->backbuffer = NULL; ALLEGRO_DEBUG("destroy backbuffer.\n"); } if (glx->overridable_vt) { glx->overridable_vt->destroy_display_hook(d, is_last); } if (s->mouse_grab_display == d) { s->mouse_grab_display = NULL; } _al_vector_free(&d->bitmaps); _al_event_source_free(&d->es); al_free(d->ogl_extras); al_free(d->vertex_cache); al_free(d); _al_mutex_unlock(&s->lock); ALLEGRO_DEBUG("destroy display finished.\n"); } static bool xdpy_make_current(ALLEGRO_DISPLAY *d) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)d; /* Make our GLX context current for reading and writing in the current * thread. */ if (glx->fbc) { return glXMakeContextCurrent(system->gfxdisplay, glx->glxwindow, glx->glxwindow, glx->context); } else { return glXMakeCurrent(system->gfxdisplay, glx->glxwindow, glx->context); } } static bool xdpy_set_current_display(ALLEGRO_DISPLAY *d) { bool rc; rc = xdpy_make_current(d); if (rc) { ALLEGRO_OGL_EXTRAS *ogl = d->ogl_extras; _al_ogl_set_extensions(ogl->extension_api); _al_ogl_update_render_state(d); } return rc; } static void xdpy_unset_current_display(ALLEGRO_DISPLAY *d) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); glXMakeContextCurrent(system->gfxdisplay, None, None, NULL); (void)d; } static void xdpy_flip_display(ALLEGRO_DISPLAY *d) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)d; int e = glGetError(); if (e) { ALLEGRO_ERROR("OpenGL error was not 0: %s\n", _al_gl_error_string(e)); } if (d->extra_settings.settings[ALLEGRO_SINGLE_BUFFER]) glFlush(); else glXSwapBuffers(system->gfxdisplay, glx->glxwindow); } static void xdpy_update_display_region(ALLEGRO_DISPLAY *d, int x, int y, int w, int h) { (void)x; (void)y; (void)w; (void)h; xdpy_flip_display(d); } static bool xdpy_acknowledge_resize(ALLEGRO_DISPLAY *d) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)d; XWindowAttributes xwa; unsigned int w, h; _al_mutex_lock(&system->lock); /* glXQueryDrawable is GLX 1.3+. */ /* glXQueryDrawable(system->x11display, glx->glxwindow, GLX_WIDTH, &w); glXQueryDrawable(system->x11display, glx->glxwindow, GLX_HEIGHT, &h); */ XGetWindowAttributes(system->x11display, glx->window, &xwa); w = xwa.width; h = xwa.height; if ((int)w != d->w || (int)h != d->h) { d->w = w; d->h = h; ALLEGRO_DEBUG("xdpy: acknowledge_resize (%d, %d)\n", d->w, d->h); /* No context yet means this is a stray call happening during * initialization. */ if (glx->context) { _al_ogl_setup_gl(d); } glx->overridable_vt->check_maximized(d); } _al_mutex_unlock(&system->lock); return true; } /* Note: The system mutex must be locked (exactly once) so when we * wait for the condition variable it gets auto-unlocked. For a * nested lock that would not be the case. */ void _al_display_xglx_await_resize(ALLEGRO_DISPLAY *d, int old_resize_count, bool delay_hack) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)d; ALLEGRO_TIMEOUT timeout; ALLEGRO_DEBUG("Awaiting resize event\n"); XSync(system->x11display, False); /* Wait until we are actually resized. * Don't wait forever if an event never comes. */ al_init_timeout(&timeout, 1.0); while (old_resize_count == glx->resize_count) { if (_al_cond_timedwait(&system->resized, &system->lock, &timeout) == -1) { ALLEGRO_ERROR("Timeout while waiting for resize event.\n"); return; } } /* XXX: This hack helps when toggling between fullscreen windows and not, * on various window managers. */ if (delay_hack) { al_rest(0.2); } xdpy_acknowledge_resize(d); } static bool xdpy_resize_display_default(ALLEGRO_DISPLAY *d, int w, int h) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)d; XWindowAttributes xwa; int attempts; bool ret = false; _al_mutex_lock(&system->lock); /* It seems some X servers will treat the resize as a no-op if the window is * already the right size, so check for it to avoid a deadlock later. */ XGetWindowAttributes(system->x11display, glx->window, &xwa); if (xwa.width == w && xwa.height == h) { _al_mutex_unlock(&system->lock); return false; } if (d->flags & ALLEGRO_FULLSCREEN) { _al_xwin_set_fullscreen_window(d, 0); if (!_al_xglx_fullscreen_set_mode(system, glx, w, h, 0, 0)) { ret = false; goto skip_resize; } attempts = 3; } else { attempts = 1; } /* Hack: try multiple times to resize the window, with delays. KDE reacts * slowly to the video mode change, and won't resize our window until a * while after. It would be better to wait for some sort of event rather * than just waiting some amount of time, but I didn't manage to find that * event. --pw */ for (; attempts >= 0; attempts--) { const int old_resize_count = glx->resize_count; ALLEGRO_DEBUG("calling XResizeWindow, attempts=%d\n", attempts); _al_xwin_reset_size_hints(d); glx->programmatic_resize = true; XResizeWindow(system->x11display, glx->window, w, h); _al_display_xglx_await_resize(d, old_resize_count, (d->flags & ALLEGRO_FULLSCREEN)); glx->programmatic_resize = false; _al_xwin_set_size_hints(d, INT_MAX, INT_MAX); if (d->w == w && d->h == h) { ret = true; break; } /* Wait before trying again. */ al_rest(0.333); } if (attempts == 0) { ALLEGRO_ERROR("XResizeWindow didn't work; giving up\n"); } skip_resize: if (d->flags & ALLEGRO_FULLSCREEN) { _al_xwin_set_fullscreen_window(d, 1); _al_xwin_set_above(d, 1); _al_xglx_fullscreen_to_display(system, glx); ALLEGRO_DEBUG("xdpy: resize fullscreen?\n"); } _al_mutex_unlock(&system->lock); return ret; } static bool xdpy_resize_display(ALLEGRO_DISPLAY *d, int w, int h) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)d; /* A fullscreen-window can't be resized. */ if (d->flags & ALLEGRO_FULLSCREEN_WINDOW) return false; return glx->overridable_vt->resize_display(d, w, h); } void _al_xglx_display_configure(ALLEGRO_DISPLAY *d, int x, int y, int width, int height, bool setglxy) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)d; ALLEGRO_EVENT_SOURCE *es = &glx->display.es; _al_event_source_lock(es); _al_xwin_get_borders(d); /* Generate a resize event if the size has changed non-programmatically. * We cannot asynchronously change the display size here yet, since the user * will only know about a changed size after receiving the resize event. * Here we merely add the event to the queue. */ if (!glx->programmatic_resize && (d->w != width || d->h != height)) { if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_RESIZE; event.display.timestamp = al_get_time(); event.display.x = x; event.display.y = y; event.display.width = width; event.display.height = height; _al_event_source_emit_event(es, &event); } } if (setglxy) { // Note: XConfigure events will have our inner window position // which is what we are using for al_set/get_window_position glx->x = x; glx->y = y; if (glx->need_initial_position_adjust && glx->borders_known) { glx->need_initial_position_adjust = false; // Unfortunately there doesn't seem to be a good way to know the // border size before mapping the window, so we have to adjust // the position slightly now, after the window is mapped. // The scenario is this: // 1. We create the window, passing the user position to X11, which // is interpreted as outer coordinates. Since borders are // not known yet d->x/d->y are also set to that position. // 2. The window is mapped and X11 sends us the inner coordinates // in XConfigure which we store in d->x/d->y. // 3. Now d->x/d->y is in sync with the real position, but if // we wanted a specific position it is off by the border size // and so we adjust it below. ALLEGRO_DEBUG("Adjusting initial position: %d/%d", glx->x - glx->border_left, glx->y - glx->border_top); al_set_window_position(d, glx->x - glx->border_left, glx->y - glx->border_top); } } ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX*)al_get_system_driver(); ALLEGRO_MONITOR_INFO mi; int center_x = (glx->x + (glx->x + width)) / 2; int center_y = (glx->y + (glx->y + height)) / 2; _al_xglx_get_monitor_info(system, glx->adapter, &mi); ALLEGRO_DEBUG("xconfigure event! %ix%i\n", x, y); /* check if we're no longer inside the stored adapter */ if ((center_x < mi.x1 && center_x > mi.x2) || (center_y < mi.y1 && center_y > mi.x2)) { int new_adapter = _al_xglx_get_adapter(system, glx, true); if (new_adapter != glx->adapter) { ALLEGRO_DEBUG("xdpy: adapter change!\n"); _al_xglx_unuse_adapter(system, glx->adapter); if (d->flags & ALLEGRO_FULLSCREEN) _al_xglx_restore_video_mode(system, glx->adapter); glx->adapter = new_adapter; _al_xglx_use_adapter(system, glx->adapter); } } glx->overridable_vt->check_maximized(d); _al_event_source_unlock(es); } /* Handle an X11 configure event. [X11 thread] * Only called from the event handler with the system locked. */ void _al_xglx_display_configure_event(ALLEGRO_DISPLAY *d, XEvent *xevent) { /* We receive two configure events when toggling the window frame. * We ignore the first one as it has bogus coordinates. * The only way to tell them apart seems to be the send_event field. * Unfortunately, we also end up ignoring the only event we receive in * response to a XMoveWindow request so we have to compensate for that. */ bool setglxy = (xevent->xconfigure.send_event); _al_xglx_display_configure(d, xevent->xconfigure.x, xevent->xconfigure.y, xevent->xconfigure.width, xevent->xconfigure.height, setglxy); } /* Handle X11 switch event. [X11 thread] */ void _al_xwin_display_switch_handler(ALLEGRO_DISPLAY *display, XFocusChangeEvent *xevent) { /* Mouse click in/out tend to set NotifyNormal events. For Alt-Tab, * there are also accompanying NotifyGrab/NotifyUngrab events which we don't * care about. At this point, some WMs either send NotifyNormal (KDE) or * NotifyWhileGrabbed (GNOME). */ if (xevent->mode == NotifyNormal || xevent->mode == NotifyWhileGrabbed) _al_xwin_display_switch_handler_inner(display, (xevent->type == FocusIn)); } /* Handle X11 switch event. [X11 thread] */ void _al_xwin_display_switch_handler_inner(ALLEGRO_DISPLAY *display, bool focus_in) { ALLEGRO_EVENT_SOURCE *es = &display->es; _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; if (focus_in) event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_IN; else event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_OUT; event.display.timestamp = al_get_time(); _al_event_source_emit_event(es, &event); } _al_event_source_unlock(es); } void _al_xwin_display_expose(ALLEGRO_DISPLAY *display, XExposeEvent *xevent) { ALLEGRO_EVENT_SOURCE *es = &display->es; _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_EXPOSE; event.display.timestamp = al_get_time(); event.display.x = xevent->x; event.display.y = xevent->y; event.display.width = xevent->width; event.display.height = xevent->height; _al_event_source_emit_event(es, &event); } _al_event_source_unlock(es); } static bool xdpy_is_compatible_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { /* All GLX bitmaps are compatible. */ (void)display; (void)bitmap; return true; } static void xdpy_set_window_title_default(ALLEGRO_DISPLAY *display, const char *title) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; { Atom WM_NAME = XInternAtom(system->x11display, "WM_NAME", False); Atom _NET_WM_NAME = XInternAtom(system->x11display, "_NET_WM_NAME", False); char *list[1] = { (char *) title }; XTextProperty property; Xutf8TextListToTextProperty(system->x11display, list, 1, XUTF8StringStyle, &property); XSetTextProperty(system->x11display, glx->window, &property, WM_NAME); XSetTextProperty(system->x11display, glx->window, &property, _NET_WM_NAME); XSetTextProperty(system->x11display, glx->window, &property, XA_WM_NAME); XFree(property.value); } { XClassHint *hint = XAllocClassHint(); if (hint) { ALLEGRO_PATH *exepath = al_get_standard_path(ALLEGRO_EXENAME_PATH); // hint doesn't use a const char*, so we use strdup to create a non const string hint->res_name = strdup(al_get_path_basename(exepath)); hint->res_class = strdup(al_get_path_basename(exepath)); XSetClassHint(system->x11display, glx->window, hint); free(hint->res_name); free(hint->res_class); XFree(hint); al_destroy_path(exepath); } } } static void xdpy_set_window_title(ALLEGRO_DISPLAY *display, const char *title) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; _al_mutex_lock(&system->lock); glx->overridable_vt->set_window_title(display, title); _al_mutex_unlock(&system->lock); } // Note: we assume x/y to be the inner window position (that is drawing // to 0/0 in Allegro's drawing area will draw to x/y on the desktop) static void xdpy_set_window_position_default(ALLEGRO_DISPLAY *display, int x, int y) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); _al_mutex_lock(&system->lock); // Note: a previous version of this function tried to translate the // coordinates with XTranslateCoordinates (assuming a parent window // offset by exactly the border) - but that didn't quite work in any // of the window managers I tried. // XMoveWindow expects outer coordinates so we offset by the border // size. XMoveWindow(system->x11display, glx->window, x - glx->border_left, y - glx->border_top); XFlush(system->x11display); /* We have to store these immediately, as we will ignore the XConfigureEvent * that we receive in response. See comments in _al_xglx_display_configure(). */ glx->x = x; glx->y = y; _al_mutex_unlock(&system->lock); } static void xdpy_set_window_position(ALLEGRO_DISPLAY *display, int x, int y) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; glx->overridable_vt->set_window_position(display, x, y); } static void xdpy_get_window_position(ALLEGRO_DISPLAY *display, int *x, int *y) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; /* We could also query the X11 server, but it just would take longer, and * would not be synchronized to our events. The latter can be an advantage * or disadvantage. */ *x = glx->x; *y = glx->y; } static bool xdpy_get_window_borders(ALLEGRO_DISPLAY *display, int *left, int *top, int *right, int *bottom) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; if (!glx->borders_known) return false; if (left) *left = glx->border_left; if (right) *right = glx->border_right; if (top) *top = glx->border_top; if (bottom) *bottom = glx->border_bottom; return true; } static bool xdpy_set_window_constraints_default(ALLEGRO_DISPLAY *display, int min_w, int min_h, int max_w, int max_h) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; glx->display.min_w = min_w; glx->display.min_h = min_h; glx->display.max_w = max_w; glx->display.max_h = max_h; return true; } static bool xdpy_set_window_constraints(ALLEGRO_DISPLAY *display, int min_w, int min_h, int max_w, int max_h) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; return glx->overridable_vt->set_window_constraints(display, min_w, min_h, max_w, max_h); } static bool xdpy_get_window_constraints(ALLEGRO_DISPLAY *display, int *min_w, int *min_h, int *max_w, int * max_h) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; *min_w = glx->display.min_w; *min_h = glx->display.min_h; *max_w = glx->display.max_w; *max_h = glx->display.max_h; return true; } static void xdpy_apply_window_constraints(ALLEGRO_DISPLAY *display, bool onoff) { int posX; int posY; ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); _al_mutex_lock(&system->lock); if (onoff) { al_get_window_position(display, &posX, &posY); _al_xwin_set_size_hints(display, posX, posY); } else { _al_xwin_reset_size_hints(display); } _al_mutex_unlock(&system->lock); al_resize_display(display, display->w, display->h); } static void xdpy_set_fullscreen_window_default(ALLEGRO_DISPLAY *display, bool onoff) { if (onoff == !(display->flags & ALLEGRO_FULLSCREEN_WINDOW)) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); _al_mutex_lock(&system->lock); _al_xwin_reset_size_hints(display); _al_xwin_set_fullscreen_window(display, 2); /* XXX Technically, the user may fiddle with the _NET_WM_STATE_FULLSCREEN * property outside of Allegro so this flag may not be in sync with * reality. */ display->flags ^= ALLEGRO_FULLSCREEN_WINDOW; _al_xwin_set_size_hints(display, INT_MAX, INT_MAX); set_compositor_bypass_flag(display); _al_mutex_unlock(&system->lock); } } static bool xdpy_set_display_flag_default(ALLEGRO_DISPLAY *display, int flag, bool flag_onoff) { switch (flag) { case ALLEGRO_FRAMELESS: { /* The ALLEGRO_FRAMELESS flag is backwards. */ _al_xwin_set_frame(display, !flag_onoff); return true; } case ALLEGRO_FULLSCREEN_WINDOW: { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; glx->overridable_vt->set_fullscreen_window(display, flag_onoff); return true; } case ALLEGRO_MAXIMIZED: { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); _al_mutex_lock(&system->lock); _al_xwin_maximize(display, flag_onoff); _al_mutex_unlock(&system->lock); return true; } } return false; } static bool xdpy_set_display_flag(ALLEGRO_DISPLAY *display, int flag, bool onoff) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; return glx->overridable_vt->set_display_flag(display, flag, onoff); } static bool xdpy_wait_for_vsync(ALLEGRO_DISPLAY *display) { (void) display; if (al_get_opengl_extension_list()->ALLEGRO_GLX_SGI_video_sync) { unsigned int count; glXGetVideoSyncSGI(&count); glXWaitVideoSyncSGI(2, (count+1) & 1, &count); return true; } return false; } /* Obtain a reference to this driver. */ ALLEGRO_DISPLAY_INTERFACE *_al_display_xglx_driver(void) { if (xdpy_vt.create_display) return &xdpy_vt; xdpy_vt.create_display = xdpy_create_display; xdpy_vt.destroy_display = xdpy_destroy_display; xdpy_vt.set_current_display = xdpy_set_current_display; xdpy_vt.unset_current_display = xdpy_unset_current_display; xdpy_vt.flip_display = xdpy_flip_display; xdpy_vt.update_display_region = xdpy_update_display_region; xdpy_vt.acknowledge_resize = xdpy_acknowledge_resize; xdpy_vt.create_bitmap = _al_ogl_create_bitmap; xdpy_vt.get_backbuffer = _al_ogl_get_backbuffer; xdpy_vt.set_target_bitmap = _al_ogl_set_target_bitmap; xdpy_vt.is_compatible_bitmap = xdpy_is_compatible_bitmap; xdpy_vt.resize_display = xdpy_resize_display; xdpy_vt.set_icons = _al_xwin_set_icons; xdpy_vt.set_window_title = xdpy_set_window_title; xdpy_vt.set_window_position = xdpy_set_window_position; xdpy_vt.get_window_position = xdpy_get_window_position; xdpy_vt.get_window_borders = xdpy_get_window_borders; xdpy_vt.set_window_constraints = xdpy_set_window_constraints; xdpy_vt.get_window_constraints = xdpy_get_window_constraints; xdpy_vt.apply_window_constraints = xdpy_apply_window_constraints; xdpy_vt.set_display_flag = xdpy_set_display_flag; xdpy_vt.wait_for_vsync = xdpy_wait_for_vsync; xdpy_vt.update_render_state = _al_ogl_update_render_state; _al_xwin_add_cursor_functions(&xdpy_vt); _al_xwin_add_clipboard_functions(&xdpy_vt); _al_ogl_add_drawing_functions(&xdpy_vt); return &xdpy_vt; } static const ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE default_overridable_vt = { xdpy_create_display_hook_default, xdpy_destroy_display_hook_default, xdpy_resize_display_default, xdpy_set_window_title_default, xdpy_set_fullscreen_window_default, xdpy_set_window_position_default, xdpy_set_window_constraints_default, xdpy_set_display_flag_default, _al_xwin_check_maximized, }; bool _al_xwin_set_gtk_display_overridable_interface(uint32_t check_version, const ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE *vt) { /* The version of the native dialogs addon must exactly match the core * library version. */ if (vt && check_version == ALLEGRO_VERSION_INT) { ALLEGRO_DEBUG("GTK vtable made available\n"); gtk_override_vt = vt; return true; } ALLEGRO_DEBUG("GTK vtable reset\n"); gtk_override_vt = NULL; return (vt == NULL); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/x/xdnd.c000066400000000000000000000262751473414355200156330ustar00rootroot00000000000000// Note: adapted from SDL2 #include #include #include #include "allegro5/allegro.h" #include "allegro5/platform/aintunix.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xevents.h" #include "allegro5/internal/aintern_xsystem.h" #include "allegro5/internal/aintern_xdnd.h" ALLEGRO_DEBUG_CHANNEL("xdnd") typedef struct { unsigned char *data; int format, count; Atom type; } Property; static int last_drop_x, last_drop_y; void _al_display_xglx_init_dnd_atoms(ALLEGRO_SYSTEM_XGLX *s) { #define GET_ATOM(name) s->dnd_info.name = XInternAtom(s->x11display, #name, False) GET_ATOM(XdndEnter); GET_ATOM(XdndPosition); GET_ATOM(XdndStatus); GET_ATOM(XdndTypeList); GET_ATOM(XdndActionCopy); GET_ATOM(XdndDrop); GET_ATOM(XdndFinished); GET_ATOM(XdndSelection); GET_ATOM(XdndLeave); GET_ATOM(PRIMARY); } /* Read property * Must call X11_XFree on results */ static void read_property(Property *p, Display *disp, Window w, Atom prop) { unsigned char *ret = NULL; Atom type; int fmt; unsigned long count; unsigned long bytes_left; int bytes_fetch = 0; do { if (ret != 0) XFree(ret); XGetWindowProperty(disp, w, prop, 0, bytes_fetch, false, AnyPropertyType, &type, &fmt, &count, &bytes_left, &ret); bytes_fetch += bytes_left; } while (bytes_left != 0); p->data = ret; p->format = fmt; p->count = count; p->type = type; } /* Find text-uri-list in a list of targets and return it's atom * if available, else return None */ static Atom pick_target(Display *disp, Atom list[], int list_count) { Atom request = None; char *name; int i; for (i = 0; i < list_count && request == None; i++) { name = XGetAtomName(disp, list[i]); if ((strcmp("text/uri-list", name) == 0) || (strcmp("text/plain", name) == 0)) { request = list[i]; } XFree(name); } return request; } /* Wrapper for pick_target for a maximum of three targets, a special * case in the Xdnd protocol */ static Atom pick_target_from_atoms(Display *disp, Atom a0, Atom a1, Atom a2) { int count = 0; Atom atom[3]; if (a0 != None) atom[count++] = a0; if (a1 != None) atom[count++] = a1; if (a2 != None) atom[count++] = a2; return pick_target(disp, atom, count); } static void x11_reply(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *allegro_display, Window window, Atom message_type) { XClientMessageEvent m; memset(&m, 0, sizeof(XClientMessageEvent)); m.type = ClientMessage; m.display = s->x11display; m.window = window; m.message_type = message_type; m.format = 32; m.data.l[0] = allegro_display->window; if (message_type == s->dnd_info.XdndStatus) { /* See https://freedesktop.org/wiki/Specifications/XDND/ * * data.l[0] contains the XID of the target window. * data.l[1]: * Bit 0 is set if the current target will accept the drop. * data.l[2,3] contains a rectangle in root coordinates that * means "don't send another XdndPosition message until the mouse * moves out of here". * data.l[4] contains the action accepted by the target */ m.data.l[1] = s->dnd_info.xdnd_req != None ? 3 : 0; m.data.l[4] = s->dnd_info.XdndActionCopy; } if (message_type == s->dnd_info.XdndFinished) { /* See https://freedesktop.org/wiki/Specifications/XDND/ * * data.l[0] contains the XID of the target window. * data.l[1]: * Bit 0 is set if the current target accepted the drop * data.l[2] contains the action performed by the target. */ m.data.l[1] = s->dnd_info.xdnd_req != None; m.data.l[2] = s->dnd_info.xdnd_req != None ? s->dnd_info.XdndActionCopy : None; } XSendEvent(s->x11display, window, false, NoEventMask, (XEvent*)&m); XSync(s->x11display, 0); } static void _send_event(ALLEGRO_DISPLAY_XGLX *allegro_display, char *text, bool is_file, int row, bool is_complete) { ALLEGRO_EVENT_SOURCE *es = &allegro_display->display.es; _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; event.drop.type = ALLEGRO_EVENT_DROP; event.drop.timestamp = al_get_time(); event.drop.x = last_drop_x; event.drop.y = last_drop_y; event.drop.text = text; event.drop.is_file = is_file; event.drop.row = row; event.drop.is_complete = is_complete; _al_event_source_emit_event(es, &event); } _al_event_source_unlock(es); } /* Return true if the event is handled as a DND related event else * false. */ bool _al_display_xglx_handle_drag_and_drop(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *allegro_display, XEvent *xevent) { if (!(allegro_display->display.flags & ALLEGRO_DRAG_AND_DROP)) return false; if (xevent->xclient.message_type == s->dnd_info.XdndEnter) { ALLEGRO_DEBUG("Xdnd entered\n"); bool use_list = xevent->xclient.data.l[1] & 1; s->dnd_info.xdnd_source = xevent->xclient.data.l[0]; if (use_list) { Property p; read_property(&p, s->x11display, s->dnd_info.xdnd_source, s->dnd_info.XdndTypeList); s->dnd_info.xdnd_req = pick_target(s->x11display, (Atom*)p.data, p.count); XFree(p.data); } else { s->dnd_info.xdnd_req = pick_target_from_atoms(s->x11display, xevent->xclient.data.l[2], xevent->xclient.data.l[3], xevent->xclient.data.l[4]); } if (s->dnd_info.xdnd_req == None) { ALLEGRO_WARN("Xdnd action unsupported\n"); } return true; } else if (xevent->xclient.message_type == s->dnd_info.XdndPosition) { int root_x, root_y, window_x, window_y; Window ChildReturn; root_x = xevent->xclient.data.l[2] >> 16; root_y = xevent->xclient.data.l[2] & 0xffff; XTranslateCoordinates(s->x11display, DefaultRootWindow(s->x11display), allegro_display->window, root_x, root_y, &window_x, &window_y, &ChildReturn); // we don't send the text yet to avoid all the string allocations last_drop_x = window_x; last_drop_y = window_y; _send_event(allegro_display, NULL, false, 0, false); x11_reply(s, allegro_display, xevent->xclient.data.l[0], s->dnd_info.XdndStatus); return true; } else if (xevent->xclient.message_type == s->dnd_info.XdndDrop) { if (s->dnd_info.xdnd_req == None) { x11_reply(s, allegro_display, xevent->xclient.data.l[0], s->dnd_info.XdndFinished); _send_event(allegro_display, NULL, false, 0, true); ALLEGRO_DEBUG("Xdnd aborted\n"); } else { ALLEGRO_DEBUG("Xdnd received, converting to selection\n"); int xdnd_version = xevent->xclient.data.l[1] >> 24; if(xdnd_version >= 1) { XConvertSelection(s->x11display, s->dnd_info.XdndSelection, s->dnd_info.xdnd_req, s->dnd_info.PRIMARY, allegro_display->window, xevent->xclient.data.l[2]); } else { XConvertSelection(s->x11display, s->dnd_info.XdndSelection, s->dnd_info.xdnd_req, s->dnd_info.PRIMARY, allegro_display->window, CurrentTime); } } return true; } else if (xevent->xclient.message_type == s->dnd_info.XdndLeave) { _send_event(allegro_display, NULL, false, 0, true); ALLEGRO_DEBUG("Xdnd cancelled\n"); } return false; } // Replaces "%xx" with the hex character and "+" with a space. static void _urldecode(char *url) { char const *src = url; char *dst = url; char a, b; while (*src) { if ((*src == '%') && ((a = src[1]) && (b = src[2])) && (isxdigit(a) && isxdigit(b))) { if (a >= 'a') a = a - 'a' + 'A'; if (a >= 'A') a = a - 'A' + 10; else a -= '0'; if (b >= 'a') b = b - 'a' + 'A'; if (b >= 'A') b = b - 'A' + 10; else b -= '0'; *dst++ = 16 * a + b; src += 3; } else if (*src == '+') { *dst++ = ' '; src++; } else { *dst++ = *src++; } } *dst++ = '\0'; } // in any of these cases: // - /path // - file:/path // - file:///path // - file://hostname/path // we will return just /path static char *_uri_to_filename(char *uri) { char *uri2 = uri; if (memcmp(uri, "file://", 7) == 0) { uri2 = strstr(uri + 7, "/"); } else if (memcmp(uri, "file:/", 6) == 0) { uri2 += 5; } else if (strstr(uri, ":/") != NULL) { return NULL; } memmove(uri, uri2, strlen(uri2) + 1); _urldecode(uri); return uri; } bool _al_display_xglx_handle_drag_and_drop_selection(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *allegro_display, XEvent *xevent) { if (!(allegro_display->display.flags & ALLEGRO_DRAG_AND_DROP)) return false; Atom target = xevent->xselection.target; if (target == s->dnd_info.xdnd_req) { Property p; read_property(&p, s->x11display, allegro_display->window, s->dnd_info.PRIMARY); if (p.format == 8) { ALLEGRO_USTR *text = al_ustr_new((char *)p.data); char *name = XGetAtomName(s->x11display, target); if (name) { ALLEGRO_INFO("Xdnd data received, format '%s'\n", name); int pos = 0; int row = 0; bool complete = false; while (!complete) { int pos2 = al_ustr_find_set_cstr(text, pos, "\r\n"); if (pos2 == -1) pos2 = al_ustr_size(text); ALLEGRO_USTR *token = al_ustr_dup_substr(text, pos, pos2); if (al_ustr_get(text, pos2) == '\r') al_ustr_next(text, &pos2); if (al_ustr_get(text, pos2) == '\n') al_ustr_next(text, &pos2); if (al_ustr_get(text, pos2) == -1) complete = true; pos = pos2; if (strcmp(name, "text/plain") == 0) { _send_event(allegro_display, al_cstr_dup(token), false, row, complete); } else if (strcmp(name, "text/uri-list") == 0) { char *filename = _uri_to_filename(al_cstr_dup(token)); _send_event(allegro_display, filename, true, row, complete); } else { ALLEGRO_WARN("Attempt to drop unknown format '%s'\n", name); } al_ustr_free(token); row++; } XFree(name); } al_ustr_free(text); } else { s->dnd_info.xdnd_req = None; } if (p.data) XFree(p.data); x11_reply(s, allegro_display, s->dnd_info.xdnd_source, s->dnd_info.XdndFinished); ALLEGRO_DEBUG("Xdnd completed\n"); return true; } return false; } void _al_xwin_accept_drag_and_drop(ALLEGRO_DISPLAY *display, bool accept) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; Atom XdndAware = XInternAtom(system->x11display, "XdndAware", False); if (accept) { Atom xdnd_version = 5; XChangeProperty(system->x11display, glx->window, XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*)&xdnd_version, 1); } else { XDeleteProperty(system->x11display, glx->window, XdndAware); } } allegro5-5.2.10.1/src/x/xevents.c000066400000000000000000000212671473414355200163660ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "allegro5/platform/aintunix.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xclipboard.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xembed.h" #include "allegro5/internal/aintern_xevents.h" #include "allegro5/internal/aintern_xfullscreen.h" #include "allegro5/internal/aintern_xkeyboard.h" #include "allegro5/internal/aintern_xmouse.h" #include "allegro5/internal/aintern_xsystem.h" #include "allegro5/internal/aintern_xtouch.h" #include "allegro5/internal/aintern_xdnd.h" #ifdef ALLEGRO_RASPBERRYPI #include "allegro5/internal/aintern_raspberrypi.h" #define ALLEGRO_SYSTEM_XGLX ALLEGRO_SYSTEM_RASPBERRYPI #define ALLEGRO_DISPLAY_XGLX ALLEGRO_DISPLAY_RASPBERRYPI #endif ALLEGRO_DEBUG_CHANNEL("xevents") /* Handle an X11 close button event. [X11 thread] * Only called from the event handler with the system locked. */ void _al_display_xglx_closebutton(ALLEGRO_DISPLAY *d, XEvent *xevent) { ALLEGRO_EVENT_SOURCE *es = &d->es; (void)xevent; _al_event_source_lock(es); if (_al_event_source_needs_to_generate_event(es)) { ALLEGRO_EVENT event; event.display.type = ALLEGRO_EVENT_DISPLAY_CLOSE; event.display.timestamp = al_get_time(); _al_event_source_emit_event(es, &event); } _al_event_source_unlock(es); } static void process_x11_event(ALLEGRO_SYSTEM_XGLX *s, XEvent event) { unsigned int i; ALLEGRO_DISPLAY_XGLX *d = NULL; /* With many windows, it's bad to loop through them all, but typically * we have one or at most two or so. */ for (i = 0; i < _al_vector_size(&s->system.displays); i++) { ALLEGRO_DISPLAY_XGLX **dptr = _al_vector_ref(&s->system.displays, i); d = *dptr; if (d->window == event.xany.window) { break; } } if (!d) { /* The display was probably destroyed already. */ return; } switch (event.type) { case KeyPress: _al_xwin_keyboard_handler(&event.xkey, &d->display); break; case KeyRelease: _al_xwin_keyboard_handler(&event.xkey, &d->display); break; case MotionNotify: _al_xwin_mouse_motion_notify_handler( event.xmotion.x, event.xmotion.y, &d->display); break; case ButtonPress: _al_xwin_mouse_button_press_handler(event.xbutton.button, &d->display); break; case ButtonRelease: _al_xwin_mouse_button_release_handler(event.xbutton.button, &d->display); break; case ClientMessage: if (event.xclient.message_type == s->AllegroAtom) { d->mouse_warp = true; break; } if (d->wm_delete_window_atom != None && (Atom)event.xclient.data.l[0] == d->wm_delete_window_atom) { _al_display_xglx_closebutton(&d->display, &event); break; } if (_al_display_xglx_handle_drag_and_drop(s, d, &event)) { break; } #ifndef ALLEGRO_RASPBERRYPI if (event.xclient.message_type == s->XEmbedAtom) { const long xtime = event.xclient.data.l[0]; const long major = event.xclient.data.l[1]; const long detail = event.xclient.data.l[2]; const long data1 = event.xclient.data.l[3]; const long data2 = event.xclient.data.l[4]; (void)xtime; (void)detail; (void)data2; switch (major) { case XEMBED_EMBEDDED_NOTIFY: d->embedder_window = data1; ALLEGRO_INFO("XEmbed begin: embedder window = %ld\n", data1); break; case XEMBED_FOCUS_IN: ALLEGRO_DEBUG("XEmbed focus in\n"); _al_xwin_display_switch_handler_inner(&d->display, true); _al_xwin_keyboard_switch_handler(&d->display, true); break; case XEMBED_FOCUS_OUT: ALLEGRO_DEBUG("XEmbed focus out\n"); _al_xwin_display_switch_handler_inner(&d->display, false); _al_xwin_keyboard_switch_handler(&d->display, false); break; } break; } break; case EnterNotify: _al_xwin_mouse_switch_handler(&d->display, &event.xcrossing); break; case LeaveNotify: _al_xwin_mouse_switch_handler(&d->display, &event.xcrossing); break; case FocusIn: _al_xwin_display_switch_handler(&d->display, &event.xfocus); _al_xwin_keyboard_switch_handler(&d->display, true); break; case FocusOut: _al_xwin_display_switch_handler(&d->display, &event.xfocus); _al_xwin_keyboard_switch_handler(&d->display, false); break; case ConfigureNotify: _al_xglx_display_configure_event(&d->display, &event); d->resize_count++; _al_cond_signal(&s->resized); break; case MapNotify: d->display.flags &= ~ALLEGRO_MINIMIZED; d->is_mapped = true; _al_cond_signal(&d->mapped); break; case UnmapNotify: d->display.flags |= ALLEGRO_MINIMIZED; break; case Expose: if (d->display.flags & ALLEGRO_GENERATE_EXPOSE_EVENTS) { _al_xwin_display_expose(&d->display, &event.xexpose); } break; case ReparentNotify: if (event.xreparent.parent == RootWindow(s->x11display, d->xscreen)) { ALLEGRO_INFO("XEmbed protocol finished.\n"); d->embedder_window = None; } break; case SelectionNotify: if (_al_display_xglx_handle_drag_and_drop_selection(s, d, &event)) break; _al_xwin_display_selection_notify(&d->display, &event.xselection); d->is_selectioned = true; _al_cond_signal(&d->selectioned); break; case SelectionRequest: _al_xwin_display_selection_request(&d->display, &event.xselectionrequest); break; default: _al_x_handle_touch_event(s, d, &event); _al_xglx_handle_mmon_event(s, d, &event); break; #endif } } void _al_xwin_background_thread(_AL_THREAD *self, void *arg) { ALLEGRO_SYSTEM_XGLX *s = arg; XEvent event; double last_reset_screensaver_time = 0.0; while (!_al_get_thread_should_stop(self)) { /* Note: * Most older X11 implementations are not thread-safe no matter what, so * we simply cannot sit inside a blocking XNextEvent from another thread * if another thread also uses X11 functions. * * The usual use of XNextEvent is to only call it from the main thread. We * could of course do this for A5, just needs some slight adjustments to * the events system (polling for an Allegro event would call a function * of the system driver). * * As an alternative, we can use locking. This however can never fully * work, as for example OpenGL implementations also will access X11, in a * way we cannot know and cannot control (and we can't require users to * only call graphics functions inside a lock). * * However, most X11 implementations are somewhat thread safe, and do * use locking quite a bit themselves, so locking mostly does work. * * (Yet another alternative might be to use a separate X11 display * connection for graphics output.) * */ _al_mutex_lock(&s->lock); while (XEventsQueued(s->x11display, QueuedAfterFlush)) { XNextEvent(s->x11display, &event); process_x11_event(s, event); } /* The Xlib manual is particularly useless about the XResetScreenSaver() * function. Nevertheless, this does seem to work to inhibit the native * screensaver facility. Probably it won't do anything for other * systems, though. */ if (!s->screen_saver_query_available && s->inhibit_screensaver) { double now = al_get_time(); if (now - last_reset_screensaver_time > 10.0) { XResetScreenSaver(s->x11display); last_reset_screensaver_time = now; } } _al_mutex_unlock(&s->lock); /* If no X11 events are there, unlock so other threads can run. We use * a select call to wake up when as soon as anything is available on * the X11 connection - and just for safety also wake up 10 times * a second regardless. */ int x11_fd = ConnectionNumber(s->x11display); fd_set fdset; FD_ZERO(&fdset); FD_SET(x11_fd, &fdset); struct timeval small_time = {0, 100000}; /* 10 times a second */ select(x11_fd + 1, &fdset, NULL, NULL, &small_time); } } allegro5-5.2.10.1/src/x/xfullscreen.c000066400000000000000000000715311473414355200172230ustar00rootroot00000000000000#include #include "allegro5/allegro.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xfullscreen.h" #include "allegro5/internal/aintern_xsystem.h" ALLEGRO_DEBUG_CHANNEL("display") /* globals - this might be better in ALLEGRO_SYSTEM_XGLX */ _ALLEGRO_XGLX_MMON_INTERFACE _al_xglx_mmon_interface; /* generic multi-head x */ int _al_xsys_mheadx_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s) { int i; ALLEGRO_DEBUG("mhead get default adapter\n"); if (ScreenCount(s->x11display) == 1) return 0; _al_mutex_lock(&s->lock); Window focus; int revert_to = 0; XWindowAttributes attr; Screen *focus_screen; if (!XGetInputFocus(s->x11display, &focus, &revert_to)) { ALLEGRO_ERROR("XGetInputFocus failed!"); _al_mutex_unlock(&s->lock); return 0; } if (focus == None) { ALLEGRO_ERROR("XGetInputFocus returned None!\n"); _al_mutex_unlock(&s->lock); return 0; } else if (focus == PointerRoot) { ALLEGRO_DEBUG("XGetInputFocus returned PointerRoot.\n"); /* XXX TEST THIS >:( */ Window root, child; int root_x, root_y; int win_x, win_y; unsigned int mask; if (XQueryPointer(s->x11display, focus, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask) == False) { ALLEGRO_ERROR("XQueryPointer failed :("); _al_mutex_unlock(&s->lock); return 0; } focus = root; } else { ALLEGRO_DEBUG("XGetInputFocus returned %i!\n", (int)focus); } XGetWindowAttributes(s->x11display, focus, &attr); focus_screen = attr.screen; int ret = 0; for (i = 0; i < ScreenCount(s->x11display); i++) { if (ScreenOfDisplay(s->x11display, i) == focus_screen) { _al_mutex_unlock(&s->lock); ret = i; break; } } _al_mutex_unlock(&s->lock); return ret; } /* in pure multi-head mode, allegro's virtual adapters map directly to X Screens. */ int _al_xsys_mheadx_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter) { (void)s; ALLEGRO_DEBUG("mhead get screen %i\n", adapter); return adapter; } /* Returns the parent window of "window" (i.e. the ancestor of window that is a direct child of the root, or window itself if it is a direct child). If window is the root window, returns window. */ static Window get_toplevel_parent(ALLEGRO_SYSTEM_XGLX *s, Window window) { Window parent; Window root; Window * children; unsigned int num_children; while (1) { /* XXX enlightenment shows some very strange errors here, * for some reason 'window' isn't valid when the mouse happens * to be over the windeco when this is called.. */ if (0 == XQueryTree(s->x11display, window, &root, &parent, &children, &num_children)) { ALLEGRO_ERROR("XQueryTree error\n"); return None; } if (children) { /* must test for NULL */ XFree(children); } if (window == root || parent == root) { return window; } else { window = parent; } } return None; } /* used for xinerama and pure xrandr modes */ void _al_xsys_get_active_window_center(ALLEGRO_SYSTEM_XGLX *s, int *x, int *y) { Window focus; int revert_to = 0; _al_mutex_lock(&s->lock); if (!XGetInputFocus(s->x11display, &focus, &revert_to)) { ALLEGRO_ERROR("XGetInputFocus failed!\n"); _al_mutex_unlock(&s->lock); return; } if (focus == None || focus == PointerRoot) { ALLEGRO_DEBUG("XGetInputFocus returned special window, selecting default root!\n"); focus = DefaultRootWindow(s->x11display); } else { /* this horribleness is due to toolkits like GTK (and probably Qt) creating * a 1x1 window under the window you're looking at that actually accepts * all input, so we need to grab the top level parent window rather than * whatever happens to have focus */ focus = get_toplevel_parent(s, focus); } ALLEGRO_DEBUG("XGetInputFocus returned %i\n", (int)focus); XWindowAttributes attr; if (XGetWindowAttributes(s->x11display, focus, &attr) == 0) { ALLEGRO_ERROR("XGetWindowAttributes failed :(\n"); _al_mutex_unlock(&s->lock); return; } _al_mutex_unlock(&s->lock); /* check the center of the window with focus * might be a bit more useful than just checking the top left */ ALLEGRO_DEBUG("focus geom: %ix%i %ix%i\n", attr.x, attr.y, attr.width, attr.height); *x = (attr.x + (attr.x + attr.width)) / 2; *y = (attr.y + (attr.y + attr.height)) / 2; } /*--------------------------------------------------------------------------- * * Xinerama * */ #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA static void xinerama_init(ALLEGRO_SYSTEM_XGLX *s) { int event_base = 0; int error_base = 0; /* init xinerama info to defaults */ s->xinerama_available = 0; s->xinerama_screen_count = 0; s->xinerama_screen_info = NULL; _al_mutex_lock(&s->lock); if (XineramaQueryExtension(s->x11display, &event_base, &error_base)) { int minor_version = 0, major_version = 0; int status = XineramaQueryVersion(s->x11display, &major_version, &minor_version); ALLEGRO_INFO("Xinerama version: %i.%i\n", major_version, minor_version); if (status && !XineramaIsActive(s->x11display)) { ALLEGRO_WARN("Xinerama is not active\n"); } else { s->xinerama_screen_info = XineramaQueryScreens(s->x11display, &s->xinerama_screen_count); if (!s->xinerama_screen_info) { ALLEGRO_ERROR("Xinerama failed to query screens.\n"); } else { s->xinerama_available = 1; ALLEGRO_INFO("Xinerama is active\n"); } } } if (!s->xinerama_available) { ALLEGRO_WARN("Xinerama extension is not available.\n"); } _al_mutex_unlock(&s->lock); } static void xinerama_exit(ALLEGRO_SYSTEM_XGLX *s) { if (!s->xinerama_available) return; ALLEGRO_DEBUG("xfullscreen: xinerama exit.\n"); if (s->xinerama_screen_info) XFree(s->xinerama_screen_info); s->xinerama_available = 0; s->xinerama_screen_count = 0; s->xinerama_screen_info = NULL; } #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE static void xinerama_get_display_offset(ALLEGRO_SYSTEM_XGLX *s, int adapter, int *x, int *y) { ALLEGRO_ASSERT(adapter >= 0 && adapter < s->xinerama_screen_count); *x = s->xinerama_screen_info[adapter].x_org; *y = s->xinerama_screen_info[adapter].y_org; ALLEGRO_DEBUG("xinerama dpy off %ix%i\n", *x, *y); } static bool xinerama_get_monitor_info(ALLEGRO_SYSTEM_XGLX *s, int adapter, ALLEGRO_MONITOR_INFO *mi) { if (adapter < 0 || adapter >= s->xinerama_screen_count) return false; mi->x1 = s->xinerama_screen_info[adapter].x_org; mi->y1 = s->xinerama_screen_info[adapter].y_org; mi->x2 = mi->x1 + s->xinerama_screen_info[adapter].width; mi->y2 = mi->y1 + s->xinerama_screen_info[adapter].height; return true; } static ALLEGRO_DISPLAY_MODE *xinerama_get_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int i, ALLEGRO_DISPLAY_MODE *mode) { if (adapter < 0 || adapter >= s->xinerama_screen_count) return NULL; if (i != 0) return NULL; mode->width = s->xinerama_screen_info[adapter].width; mode->height = s->xinerama_screen_info[adapter].height; mode->format = 0; mode->refresh_rate = 0; return mode; } static int xinerama_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s) { int center_x = 0, center_y = 0; ALLEGRO_DEBUG("xinerama get default adapter\n"); _al_xsys_get_active_window_center(s, ¢er_x, ¢er_y); ALLEGRO_DEBUG("xinerama got active center: %ix%i\n", center_x, center_y); int i; for (i = 0; i < s->xinerama_screen_count; i++) { if (center_x >= s->xinerama_screen_info[i].x_org && center_x <= s->xinerama_screen_info[i].x_org + s->xinerama_screen_info[i].width && center_y >= s->xinerama_screen_info[i].y_org && center_y <= s->xinerama_screen_info[i].y_org + s->xinerama_screen_info[i].height) { ALLEGRO_DEBUG("center is inside (%i) %ix%i %ix%i\n", i, s->xinerama_screen_info[i].x_org, s->xinerama_screen_info[i].y_org, s->xinerama_screen_info[i].width, s->xinerama_screen_info[i].height); return i; } } ALLEGRO_DEBUG("xinerama returning default 0\n"); return 0; } /* similar to multi-head x, but theres only one X Screen, so we return 0 always */ static int xinerama_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter) { (void)s; (void)adapter; return 0; } #endif /* ALLEGRO_XWINDOWS_WITH_XF86VIDMODE */ #endif /* ALLEGRO_XWINDOWS_WITH_XINERAMA */ /*--------------------------------------------------------------------------- * * XF86VidMode * */ #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE // XXX retest under multi-head! static int xfvm_get_num_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter) { #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA if (s->xinerama_available && s->xinerama_screen_count != s->xfvm_screen_count) { if (adapter < 0 || adapter > s->xinerama_screen_count) return 0; /* due to braindeadedness of the NVidia binary driver we can't know what an individual * monitor's modes are, as the NVidia binary driver only reports combined "BigDesktop" * or "TwinView" modes to user-space. There is no way to set modes on individual screens. * As such, we can only do one thing here and report one single mode, * which will end up being the xinerama size for the requested adapter */ return 1; } #endif if (adapter < 0 || adapter > s->xfvm_screen_count) return 0; return s->xfvm_screen[adapter].mode_count; } static ALLEGRO_DISPLAY_MODE *xfvm_get_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int i, ALLEGRO_DISPLAY_MODE *mode) { int denom; #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA /* TwinView gives us one large screen via xfvm, and no way to * properly change modes on individual monitors, so we want to query * xinerama for the lone mode. */ if (s->xinerama_available && s->xfvm_screen_count != s->xinerama_screen_count) { return xinerama_get_mode(s, adapter, i, mode); } #endif if (adapter < 0 || adapter > s->xfvm_screen_count) return NULL; if (i < 0 || i > s->xfvm_screen[adapter].mode_count) return NULL; mode->width = s->xfvm_screen[adapter].modes[i]->hdisplay; mode->height = s->xfvm_screen[adapter].modes[i]->vdisplay; mode->format = 0; denom = s->xfvm_screen[adapter].modes[i]->htotal * s->xfvm_screen[adapter].modes[i]->vtotal; if (denom > 0) mode->refresh_rate = s->xfvm_screen[adapter].modes[i]->dotclock * 1000L / denom; else mode->refresh_rate = 0; return mode; } static bool xfvm_set_mode(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, int w, int h, int format, int refresh_rate) { int mode_idx = -1; int adapter = _al_xglx_get_adapter(s, d, false); #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA /* TwinView workarounds, nothing to do here, since we can't really change or restore modes */ if (s->xinerama_available && s->xinerama_screen_count != s->xfvm_screen_count) { /* at least pretend we set a mode if its the current mode */ if (s->xinerama_screen_info[adapter].width != w || s->xinerama_screen_info[adapter].height != h) return false; return true; } #endif mode_idx = _al_xglx_fullscreen_select_mode(s, adapter, w, h, format, refresh_rate); if (mode_idx == -1) return false; if (!XF86VidModeSwitchToMode(s->x11display, adapter, s->xfvm_screen[adapter].modes[mode_idx])) { ALLEGRO_ERROR("xfullscreen: XF86VidModeSwitchToMode failed\n"); return false; } return true; } static void xfvm_store_video_mode(ALLEGRO_SYSTEM_XGLX *s) { int n; ALLEGRO_DEBUG("xfullscreen: xfvm_store_video_mode\n"); #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA /* TwinView workarounds, nothing to do here, since we can't really change or restore modes */ if (s->xinerama_available && s->xinerama_screen_count != s->xfvm_screen_count) { return; } #endif // save all original modes int i; for (i = 0; i < s->xfvm_screen_count; i++) { n = xfvm_get_num_modes(s, i); if (n == 0) { /* XXX what to do here? */ continue; } s->xfvm_screen[i].original_mode = s->xfvm_screen[i].modes[0]; int j; for (j = 0; j < s->xfvm_screen[i].mode_count; j++) { ALLEGRO_DEBUG("xfvm: screen[%d] mode[%d] = (%d, %d)\n", i, j, s->xfvm_screen[i].modes[j]->hdisplay, s->xfvm_screen[i].modes[j]->vdisplay); } ALLEGRO_INFO("xfvm: screen[%d] original mode = (%d, %d)\n", i, s->xfvm_screen[i].original_mode->hdisplay, s->xfvm_screen[i].original_mode->vdisplay); } } static void xfvm_restore_video_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter) { Bool ok; #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA /* TwinView workarounds, nothing to do here, since we can't really change or restore modes */ if (s->xinerama_available && s->xinerama_screen_count != s->xfvm_screen_count) { return; } #endif if (adapter < 0 || adapter > s->xfvm_screen_count) return; ASSERT(s->xfvm_screen[adapter].original_mode); ALLEGRO_DEBUG("xfullscreen: xfvm_restore_video_mode (%d, %d)\n", s->xfvm_screen[adapter].original_mode->hdisplay, s->xfvm_screen[adapter].original_mode->vdisplay); ok = XF86VidModeSwitchToMode(s->x11display, adapter, s->xfvm_screen[adapter].original_mode); if (!ok) { ALLEGRO_ERROR("xfullscreen: XF86VidModeSwitchToMode failed\n"); } if (s->mouse_grab_display) { XUngrabPointer(s->gfxdisplay, CurrentTime); s->mouse_grab_display = NULL; } /* This is needed, at least on my machine, or the program may terminate * before the screen mode is actually reset. --pw */ /* can we move this into shutdown_system? It could speed up mode restores -TF */ XFlush(s->gfxdisplay); } static void xfvm_get_display_offset(ALLEGRO_SYSTEM_XGLX *s, int adapter, int *x, int *y) { int tmp_x = 0, tmp_y = 0; #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA if (s->xinerama_available) { xinerama_get_display_offset(s, adapter, &tmp_x, &tmp_y); } //else #else (void)s; (void)adapter; #endif /* don't set the output params if function fails */ /* XXX I don't think this part makes sense at all. * in multi-head mode, the origin is always 0x0 * in Xinerama, its caught by xinerama, and xfvm is NEVER * used when xrandr is active -TF */ //if (!XF86VidModeGetViewPort(s->x11display, adapter, &tmp_x, &tmp_y)) // return; *x = tmp_x; *y = tmp_y; ALLEGRO_DEBUG("xfvm dpy off %ix%i\n", *x, *y); } static int xfvm_get_num_adapters(ALLEGRO_SYSTEM_XGLX *s) { #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA if (s->xinerama_available) { return s->xinerama_screen_count; } #endif return s->xfvm_screen_count; } static bool xfvm_get_monitor_info(ALLEGRO_SYSTEM_XGLX *s, int adapter, ALLEGRO_MONITOR_INFO *mi) { #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA if (s->xinerama_available) { return xinerama_get_monitor_info(s, adapter, mi); } #endif if (adapter < 0 || adapter > s->xfvm_screen_count) return false; XWindowAttributes xwa; Window root; _al_mutex_lock(&s->lock); root = RootWindow(s->x11display, adapter); XGetWindowAttributes(s->x11display, root, &xwa); _al_mutex_unlock(&s->lock); /* under plain X, each screen has its own origin, and theres no way to figure out orientation or relative position */ mi->x1 = 0; mi->y1 = 0; mi->x2 = xwa.width; mi->y2 = xwa.height; return true; } static int xfvm_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s) { ALLEGRO_DEBUG("xfvm get default adapter\n"); #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA if (s->xinerama_available) { return xinerama_get_default_adapter(s); } #endif return _al_xsys_mheadx_get_default_adapter(s); } static int xfvm_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter) { ALLEGRO_DEBUG("xfvm get xscreen for adapter %i\n", adapter); #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA if (s->xinerama_available) { return xinerama_get_xscreen(s, adapter); } #endif return _al_xsys_mheadx_get_xscreen(s, adapter); } static void xfvm_post_setup(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d) { int x = 0, y = 0; XWindowAttributes xwa; #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA /* TwinView workarounds, nothing to do here, since we can't really change or restore modes */ if (s->xinerama_available && s->xinerama_screen_count != s->xfvm_screen_count) { return; } #endif int adapter = _al_xglx_get_adapter(s, d, false); XGetWindowAttributes(s->x11display, d->window, &xwa); xfvm_get_display_offset(s, adapter, &x, &y); /* some window managers like to move our window even if we explicitly tell it not to * so we need to get the correct offset here */ x = xwa.x - x; y = xwa.y - y; ALLEGRO_DEBUG("xfvm set view port: %ix%i\n", x, y); XF86VidModeSetViewPort(s->x11display, adapter, x, y); } static void xfvm_init(ALLEGRO_SYSTEM_XGLX *s) { int event_base = 0; int error_base = 0; /* init xfvm info to defaults */ s->xfvm_available = 0; s->xfvm_screen_count = 0; s->xfvm_screen = NULL; _al_mutex_lock(&s->lock); if (XF86VidModeQueryExtension(s->x11display, &event_base, &error_base)) { int minor_version = 0, major_version = 0; int status = XF86VidModeQueryVersion(s->x11display, &major_version, &minor_version); ALLEGRO_INFO("XF86VidMode version: %i.%i\n", major_version, minor_version); if (!status) { ALLEGRO_WARN("XF86VidMode not available, XF86VidModeQueryVersion failed.\n"); } else { // I don't actually know what versions are required here, just going to assume any is ok for now. ALLEGRO_INFO("XF86VidMode %i.%i is active\n", major_version, minor_version); s->xfvm_available = 1; } } else { ALLEGRO_WARN("XF86VidMode extension is not available.\n"); } if (s->xfvm_available) { int num_screens; #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA /* This is some fun stuff right here, if XRANDR is available, we can't use the xinerama screen count * and we really want the xrandr init in xglx_initialize to come last so it overrides xf86vm if available * and I really don't want to add more XRRQuery* or #ifdefs here. * I don't think XRandR can be disabled once its loaded, * so just seeing if its in the extension list should be fine. */ /* interesting thing to note is if XRandR is available, that means we have TwinView, * and not multi-head Xinerama mode, as True Xinerama disables XRandR on my NVidia. * which means all of those xfvm_screen_count != xinerama_screen_count tests * only apply to TwinView. As this code below sets xfvm_screen_count to xinerama_screen_count * making all those compares fail, and make us fall back to the normal xfvm multi-head code. */ /* second note, if FakeXinerama is disabled on TwinView setups, we will end up using * XRandR, as there is no other way to detect TwinView outside of libNVCtrl */ int ext_op, ext_evt, ext_err; Bool ext_ret = XQueryExtension(s->x11display, "RANDR", &ext_op, &ext_evt, &ext_err); if (s->xinerama_available && ext_ret == False) { num_screens = s->xinerama_screen_count; } else #endif { num_screens = ScreenCount(s->x11display); } ALLEGRO_DEBUG("XF86VidMode Got %d screens.\n", num_screens); s->xfvm_screen_count = num_screens; s->xfvm_screen = al_calloc(num_screens, sizeof(*s->xfvm_screen)); if (!s->xfvm_screen) { ALLEGRO_ERROR("XF86VidMode: failed to allocate screen array.\n"); s->xfvm_available = 0; } else { int i; for (i = 0; i < num_screens; i++) { ALLEGRO_DEBUG("XF86VidMode GetAllModeLines on screen %d.\n", i); if (!XF86VidModeGetAllModeLines(s->x11display, i, &(s->xfvm_screen[i].mode_count), &(s->xfvm_screen[i].modes))) { /* XXX what to do here? */ } } _al_xglx_mmon_interface.get_num_display_modes = xfvm_get_num_modes; _al_xglx_mmon_interface.get_display_mode = xfvm_get_mode; _al_xglx_mmon_interface.set_mode = xfvm_set_mode; _al_xglx_mmon_interface.store_mode = xfvm_store_video_mode; _al_xglx_mmon_interface.restore_mode = xfvm_restore_video_mode; _al_xglx_mmon_interface.get_display_offset = xfvm_get_display_offset; _al_xglx_mmon_interface.get_num_adapters = xfvm_get_num_adapters; _al_xglx_mmon_interface.get_monitor_info = xfvm_get_monitor_info; _al_xglx_mmon_interface.get_default_adapter = xfvm_get_default_adapter; _al_xglx_mmon_interface.get_xscreen = xfvm_get_xscreen; _al_xglx_mmon_interface.post_setup = xfvm_post_setup; } } _al_mutex_unlock(&s->lock); } static void xfvm_exit(ALLEGRO_SYSTEM_XGLX *s) { int adapter; ALLEGRO_DEBUG("xfullscreen: XFVM exit\n"); for (adapter = 0; adapter < s->xfvm_screen_count; adapter++) { if (s->xfvm_screen[adapter].mode_count > 0) { int i; for (i = 0; i < s->xfvm_screen[adapter].mode_count; i++) { if (s->xfvm_screen[adapter].modes[i]->privsize > 0) { //XFree(s->xfvm_screen[adapter].modes[i]->private); } } //XFree(s->xfvm_screen[adapter].modes); } s->xfvm_screen[adapter].mode_count = 0; s->xfvm_screen[adapter].modes = NULL; s->xfvm_screen[adapter].original_mode = NULL; ALLEGRO_DEBUG("xfullscreen: XFVM freed adapter %d.\n", adapter); } al_free(s->xfvm_screen); s->xfvm_screen = NULL; } #endif /* ALLEGRO_XWINDOWS_WITH_XF86VIDMODE */ /*--------------------------------------------------------------------------- * * Generic multi-monitor interface * */ static bool init_mmon_interface(ALLEGRO_SYSTEM_XGLX *s) { if (s->x11display == NULL) { ALLEGRO_WARN("Not connected to X server.\n"); return false; } if (s->mmon_interface_inited) return true; /* Shouldn't we avoid initing any more of these than we need? */ /* nope, no way to tell which is going to be used on any given system * this way, xrandr always overrides everything else should it succeed. * And when xfvm is chosen, it needs xinerama inited, * incase there are multiple screens. */ #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA xinerama_init(s); #endif #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE xfvm_init(s); #endif #ifdef ALLEGRO_XWINDOWS_WITH_XRANDR _al_xsys_xrandr_init(s); #endif if (_al_xglx_mmon_interface.store_mode) _al_xglx_mmon_interface.store_mode(s); s->mmon_interface_inited = true; return true; } void _al_xsys_mmon_exit(ALLEGRO_SYSTEM_XGLX *s) { if (!s->mmon_interface_inited) return; #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA xinerama_exit(s); #endif #ifdef ALLEGRO_XWINDOWS_WITH_XF86VIDMODE xfvm_exit(s); #endif #ifdef ALLEGRO_XWINDOWS_WITH_XRANDR _al_xsys_xrandr_exit(s); #endif s->mmon_interface_inited = false; } int _al_xglx_get_num_display_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter) { if (!init_mmon_interface(s)) return 0; if (adapter < 0) adapter = _al_xglx_get_default_adapter(s); if (!_al_xglx_mmon_interface.get_num_display_modes) { if (adapter != 0) return 0; return 1; } return _al_xglx_mmon_interface.get_num_display_modes(s, adapter); } ALLEGRO_DISPLAY_MODE *_al_xglx_get_display_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int index, ALLEGRO_DISPLAY_MODE *mode) { if (!init_mmon_interface(s)) return NULL; if (adapter < 0) adapter = _al_xglx_get_default_adapter(s); if (!_al_xglx_mmon_interface.get_display_mode) { mode->width = DisplayWidth(s->x11display, DefaultScreen(s->x11display)); mode->height = DisplayHeight(s->x11display, DefaultScreen(s->x11display)); mode->format = 0; mode->refresh_rate = 0; return NULL; } return _al_xglx_mmon_interface.get_display_mode(s, adapter, index, mode); } int _al_xglx_fullscreen_select_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int w, int h, int format, int refresh_rate) { int i; int n; if (!init_mmon_interface(s)) return -1; if (adapter < 0) adapter = _al_xglx_get_default_adapter(s); n = _al_xglx_get_num_display_modes(s, adapter); if (!n) return -1; /* Find all modes with correct parameters. */ ALLEGRO_DISPLAY_MODE mode = {0, 0, 0, 0}; int possible_modes[n]; int possible_count = 0; for (i = 0; i < n; i++) { if (!_al_xglx_get_display_mode(s, adapter, i, &mode)) { continue; } if (mode.width == w && mode.height == h && (format == 0 || mode.format == format) && (refresh_rate == 0 || mode.refresh_rate == refresh_rate)) { possible_modes[possible_count++] = i; } } if (!possible_count) return -1; /* Choose mode with highest refresh rate. */ int best_mode = possible_modes[0]; _al_xglx_get_display_mode(s, adapter, best_mode, &mode); for (i = 1; i < possible_count; i++) { ALLEGRO_DISPLAY_MODE mode2; if (!_al_xglx_get_display_mode(s, adapter, possible_modes[i], &mode2)) { continue; } if (mode2.refresh_rate > mode.refresh_rate) { mode = mode2; best_mode = possible_modes[i]; } } ALLEGRO_INFO("best mode [%d] = (%d, %d)\n", best_mode, mode.width, mode.height); return best_mode; } bool _al_xglx_fullscreen_set_mode(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, int w, int h, int format, int refresh_rate) { if (!init_mmon_interface(s)) return false; if (!_al_xglx_mmon_interface.set_mode) return false; return _al_xglx_mmon_interface.set_mode(s, d, w, h, format, refresh_rate); } void _al_xglx_fullscreen_to_display(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d) { if (!init_mmon_interface(s)) return; if (!_al_xglx_mmon_interface.post_setup) return; _al_xglx_mmon_interface.post_setup(s, d); } void _al_xglx_store_video_mode(ALLEGRO_SYSTEM_XGLX *s) { if (!init_mmon_interface(s)) return; if (!_al_xglx_mmon_interface.store_mode) return; _al_xglx_mmon_interface.store_mode(s); } void _al_xglx_restore_video_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter) { if (!init_mmon_interface(s)) return; if (!_al_xglx_mmon_interface.restore_mode) return; _al_xglx_mmon_interface.restore_mode(s, adapter); } void _al_xglx_get_display_offset(ALLEGRO_SYSTEM_XGLX *s, int adapter, int *x, int *y) { if (!init_mmon_interface(s)) return; if (!_al_xglx_mmon_interface.get_display_offset) return; _al_xglx_mmon_interface.get_display_offset(s, adapter, x, y); } bool _al_xglx_get_monitor_info(ALLEGRO_SYSTEM_XGLX *s, int adapter, ALLEGRO_MONITOR_INFO *info) { if (!init_mmon_interface(s)) return false; if (!_al_xglx_mmon_interface.get_monitor_info) { _al_mutex_lock(&s->lock); info->x1 = 0; info->y1 = 0; info->x2 = DisplayWidth(s->x11display, DefaultScreen(s->x11display)); info->y2 = DisplayHeight(s->x11display, DefaultScreen(s->x11display)); _al_mutex_unlock(&s->lock); return true; } return _al_xglx_mmon_interface.get_monitor_info(s, adapter, info); } int _al_xglx_get_num_video_adapters(ALLEGRO_SYSTEM_XGLX *s) { if (!init_mmon_interface(s)) return 0; if (!_al_xglx_mmon_interface.get_num_adapters) return 1; return _al_xglx_mmon_interface.get_num_adapters(s); } int _al_xglx_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s) { ALLEGRO_DEBUG("get default adapter\n"); if (!init_mmon_interface(s)) return 0; if (!_al_xglx_mmon_interface.get_default_adapter) return 0; return _al_xglx_mmon_interface.get_default_adapter(s); } int _al_xglx_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter) { ALLEGRO_DEBUG("get xscreen\n"); if (!init_mmon_interface(s)) return 0; if (!_al_xglx_mmon_interface.get_xscreen) return 0; return _al_xglx_mmon_interface.get_xscreen(s, adapter); } int _al_xglx_get_adapter(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, bool recalc) { if (!init_mmon_interface(s)) return 0; if (d->adapter >= 0 && !recalc) return d->adapter; if (!_al_xglx_mmon_interface.get_adapter) return 0; return _al_xglx_mmon_interface.get_adapter(s, d); } void _al_xglx_handle_mmon_event(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, XEvent *e) { ALLEGRO_DEBUG("got event %i\n", e->type); // if we haven't setup the mmon interface, just bail if (!s->mmon_interface_inited) return; // bail if the current mmon interface doesn't implement the handle_xevent method if (!_al_xglx_mmon_interface.handle_xevent) return; _al_xglx_mmon_interface.handle_xevent(s, d, e); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/x/xglx_config.c000066400000000000000000000477261473414355200172110ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/allegro_opengl.h" #include "allegro5/opengl/gl_ext.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_display.h" #include "allegro5/internal/aintern_opengl.h" #include "allegro5/internal/aintern_pixels.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xglx_config.h" #include "allegro5/internal/aintern_xsystem.h" ALLEGRO_DEBUG_CHANNEL("xglx_config") #ifdef DEBUGMODE static void display_pixel_format(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds) { ALLEGRO_DEBUG("Single-buffer: %s\n", eds->settings[ALLEGRO_SINGLE_BUFFER] ? "yes" : "no"); if (eds->settings[ALLEGRO_SWAP_METHOD] > 0) ALLEGRO_DEBUG("Swap method: %s\n", eds->settings[ALLEGRO_SWAP_METHOD] == 2 ? "flip" : "copy"); else ALLEGRO_DEBUG("Swap method: undefined\n"); ALLEGRO_DEBUG("Color format: r%i g%i b%i a%i, %i bit\n", eds->settings[ALLEGRO_RED_SIZE], eds->settings[ALLEGRO_GREEN_SIZE], eds->settings[ALLEGRO_BLUE_SIZE], eds->settings[ALLEGRO_ALPHA_SIZE], eds->settings[ALLEGRO_COLOR_SIZE]); ALLEGRO_DEBUG("Depth buffer: %i bits\n", eds->settings[ALLEGRO_DEPTH_SIZE]); ALLEGRO_DEBUG("Sample buffers: %s\n", eds->settings[ALLEGRO_SAMPLE_BUFFERS] ? "yes" : "no"); ALLEGRO_DEBUG("Samples: %i\n", eds->settings[ALLEGRO_SAMPLES]); } #endif static int get_shift(int mask) { int i = 0, j = 1; if (!mask) return -1; while (!(j & mask)) { i++; j <<= 1; } return i; } static void figure_out_colors(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds, XVisualInfo *v) { eds->settings[ALLEGRO_RED_SHIFT] = get_shift(v->red_mask); eds->settings[ALLEGRO_GREEN_SHIFT] = get_shift(v->green_mask); eds->settings[ALLEGRO_BLUE_SHIFT] = get_shift(v->blue_mask); eds->settings[ALLEGRO_ALPHA_SHIFT] = 0; eds->settings[ALLEGRO_COLOR_SIZE] = 0; if (eds->settings[ALLEGRO_RED_SIZE] == 3 && eds->settings[ALLEGRO_GREEN_SIZE] == 3 && eds->settings[ALLEGRO_BLUE_SIZE] == 2) { eds->settings[ALLEGRO_COLOR_SIZE] = 8; } if (eds->settings[ALLEGRO_RED_SIZE] == 5 && eds->settings[ALLEGRO_BLUE_SIZE] == 5) { if (eds->settings[ALLEGRO_GREEN_SIZE] == 5) { eds->settings[ALLEGRO_COLOR_SIZE] = 15; } if (eds->settings[ALLEGRO_GREEN_SIZE] == 6) { eds->settings[ALLEGRO_COLOR_SIZE] = 16; } } if (eds->settings[ALLEGRO_RED_SIZE] == 8 && eds->settings[ALLEGRO_GREEN_SIZE] == 8 && eds->settings[ALLEGRO_BLUE_SIZE] == 8) { if (eds->settings[ALLEGRO_ALPHA_SIZE] == 0) { eds->settings[ALLEGRO_COLOR_SIZE] = 24; } if (eds->settings[ALLEGRO_ALPHA_SIZE] == 8) { eds->settings[ALLEGRO_COLOR_SIZE] = 32; /* small hack that tries to guess alpha shifting */ eds->settings[ALLEGRO_ALPHA_SHIFT] = 48 - eds->settings[ALLEGRO_RED_SHIFT] - eds->settings[ALLEGRO_GREEN_SHIFT] - eds->settings[ALLEGRO_BLUE_SHIFT]; } } } static ALLEGRO_EXTRA_DISPLAY_SETTINGS* read_fbconfig(Display *dpy, GLXFBConfig fbc) { int render_type, visual_type, buffer_size, sbuffers, samples; int drawable_type, renderable, swap_method, double_buffer; ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds; XVisualInfo *v; eds = al_calloc(1, sizeof(ALLEGRO_EXTRA_DISPLAY_SETTINGS)); eds->settings[ALLEGRO_RENDER_METHOD] = 2; if (glXGetFBConfigAttrib (dpy, fbc, GLX_RENDER_TYPE, &render_type) || glXGetFBConfigAttrib (dpy, fbc, GLX_X_RENDERABLE, &renderable) || glXGetFBConfigAttrib (dpy, fbc, GLX_DRAWABLE_TYPE, &drawable_type) || glXGetFBConfigAttrib (dpy, fbc, GLX_X_VISUAL_TYPE, &visual_type) || glXGetFBConfigAttrib (dpy, fbc, GLX_BUFFER_SIZE, &buffer_size) || glXGetFBConfigAttrib (dpy, fbc, GLX_DEPTH_SIZE, &eds->settings[ALLEGRO_DEPTH_SIZE]) || glXGetFBConfigAttrib (dpy, fbc, GLX_STEREO, &eds->settings[ALLEGRO_STEREO]) || glXGetFBConfigAttrib (dpy, fbc, GLX_RED_SIZE, &eds->settings[ALLEGRO_RED_SIZE]) || glXGetFBConfigAttrib (dpy, fbc, GLX_GREEN_SIZE, &eds->settings[ALLEGRO_GREEN_SIZE]) || glXGetFBConfigAttrib (dpy, fbc, GLX_BLUE_SIZE, &eds->settings[ALLEGRO_BLUE_SIZE]) || glXGetFBConfigAttrib (dpy, fbc, GLX_ALPHA_SIZE, &eds->settings[ALLEGRO_ALPHA_SIZE]) || glXGetFBConfigAttrib (dpy, fbc, GLX_DOUBLEBUFFER, &double_buffer) || glXGetFBConfigAttrib (dpy, fbc, GLX_AUX_BUFFERS, &eds->settings[ALLEGRO_AUX_BUFFERS]) || glXGetFBConfigAttrib (dpy, fbc, GLX_STENCIL_SIZE, &eds->settings[ALLEGRO_STENCIL_SIZE]) || glXGetFBConfigAttrib (dpy, fbc, GLX_ACCUM_RED_SIZE, &eds->settings[ALLEGRO_ACC_RED_SIZE]) || glXGetFBConfigAttrib (dpy, fbc, GLX_ACCUM_GREEN_SIZE, &eds->settings[ALLEGRO_ACC_GREEN_SIZE]) || glXGetFBConfigAttrib (dpy, fbc, GLX_ACCUM_BLUE_SIZE, &eds->settings[ALLEGRO_ACC_BLUE_SIZE]) || glXGetFBConfigAttrib (dpy, fbc, GLX_ACCUM_ALPHA_SIZE, &eds->settings[ALLEGRO_ACC_ALPHA_SIZE])) { ALLEGRO_DEBUG("Incomplete glX mode ...\n"); al_free(eds); return NULL; } eds->settings[ALLEGRO_SINGLE_BUFFER] = !double_buffer; if (!(render_type & GLX_RGBA_BIT) && !(render_type & GLX_RGBA_FLOAT_BIT_ARB)) { ALLEGRO_DEBUG("Not RGBA mode\n"); al_free(eds); return NULL; } if (!(drawable_type & GLX_WINDOW_BIT)) { ALLEGRO_DEBUG("Cannot render to a window.\n"); al_free(eds); return NULL; } if (renderable == False) { ALLEGRO_DEBUG("GLX windows not supported.\n"); al_free(eds); return NULL; } if (visual_type != GLX_TRUE_COLOR && visual_type != GLX_DIRECT_COLOR) { ALLEGRO_DEBUG("visual type other than TrueColor and " "DirectColor.\n"); al_free(eds); return NULL; } /* Floating-point depth is not supported as glx extension (yet). */ eds->settings[ALLEGRO_FLOAT_DEPTH] = 0; eds->settings[ALLEGRO_FLOAT_COLOR] = (render_type & GLX_RGBA_FLOAT_BIT_ARB); v = glXGetVisualFromFBConfig(dpy, fbc); if (!v) { ALLEGRO_DEBUG("Cannot get associated visual for the FBConfig.\n"); al_free(eds); return NULL; } figure_out_colors(eds, v); if (glXGetConfig(dpy, v, GLX_SAMPLE_BUFFERS, &sbuffers)) { /* Multisample extension is not supported */ eds->settings[ALLEGRO_SAMPLE_BUFFERS] = 0; } else { eds->settings[ALLEGRO_SAMPLE_BUFFERS] = sbuffers; } if (glXGetConfig(dpy, v, GLX_SAMPLES, &samples)) { /* Multisample extension is not supported */ eds->settings[ALLEGRO_SAMPLES] = 0; } else { eds->settings[ALLEGRO_SAMPLES] = samples; } if (glXGetFBConfigAttrib(dpy, fbc, GLX_SWAP_METHOD_OML, &swap_method) == GLX_BAD_ATTRIBUTE) { /* GLX_OML_swap_method extension is not supported */ eds->settings[ALLEGRO_SWAP_METHOD] = 0; } else { eds->settings[ALLEGRO_SWAP_METHOD] = swap_method; } /* We can only guarantee vsync is off. */ eds->settings[ALLEGRO_VSYNC] = 2; eds->settings[ALLEGRO_COMPATIBLE_DISPLAY] = (_al_deduce_color_format(eds) != ALLEGRO_PIXEL_FORMAT_ANY); XFree(v); return eds; } static ALLEGRO_EXTRA_DISPLAY_SETTINGS** get_visuals_new(ALLEGRO_DISPLAY_XGLX *glx, int *eds_count) { int num_fbconfigs, i, j; GLXFBConfig *fbconfig; ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref; ALLEGRO_EXTRA_DISPLAY_SETTINGS **eds = NULL; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ref = _al_get_new_display_settings(); fbconfig = glXGetFBConfigs(system->gfxdisplay, glx->xscreen, &num_fbconfigs); if (!fbconfig || !num_fbconfigs) { if (fbconfig) { XFree(fbconfig); } ALLEGRO_DEBUG("glXGetFBConfigs(xscreen=%d) returned NULL.\n", glx->xscreen); return NULL; } eds = al_malloc(num_fbconfigs * sizeof(*eds)); ALLEGRO_INFO("%i formats.\n", num_fbconfigs); for (i = j = 0; i < num_fbconfigs; i++) { ALLEGRO_DEBUG("-- \n"); ALLEGRO_DEBUG("Decoding visual no. %i...\n", i); eds[j] = read_fbconfig(system->gfxdisplay, fbconfig[i]); if (!eds[j]) continue; #ifdef DEBUGMODE display_pixel_format(eds[j]); #endif eds[j]->score = _al_score_display_settings(eds[j], ref); if (eds[j]->score == -1) { al_free(eds[j]); continue; } eds[j]->index = i; eds[j]->info = al_malloc(sizeof(GLXFBConfig)); memcpy(eds[j]->info, &fbconfig[i], sizeof(GLXFBConfig)); j++; } *eds_count = j; ALLEGRO_INFO("%i visuals are good enough.\n", j); if (j == 0) { al_free(eds); eds = NULL; } XFree(fbconfig); return eds; } static ALLEGRO_EXTRA_DISPLAY_SETTINGS* read_xvisual(Display *dpy, XVisualInfo *v) { int rgba, buffer_size, use_gl, sbuffers, samples, double_buffer; ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds; /* We can only support TrueColor and DirectColor visuals -- * we only support RGBA mode */ if (v->class != TrueColor && v->class != DirectColor) return NULL; eds = al_calloc(1, sizeof(ALLEGRO_EXTRA_DISPLAY_SETTINGS)); eds->settings[ALLEGRO_RENDER_METHOD] = 2; if (glXGetConfig (dpy, v, GLX_RGBA, &rgba) || glXGetConfig (dpy, v, GLX_USE_GL, &use_gl) || glXGetConfig (dpy, v, GLX_BUFFER_SIZE, &buffer_size) || glXGetConfig (dpy, v, GLX_RED_SIZE, &eds->settings[ALLEGRO_RED_SIZE]) || glXGetConfig (dpy, v, GLX_GREEN_SIZE, &eds->settings[ALLEGRO_GREEN_SIZE]) || glXGetConfig (dpy, v, GLX_BLUE_SIZE, &eds->settings[ALLEGRO_BLUE_SIZE]) || glXGetConfig (dpy, v, GLX_ALPHA_SIZE, &eds->settings[ALLEGRO_ALPHA_SIZE]) || glXGetConfig (dpy, v, GLX_DOUBLEBUFFER, &double_buffer) || glXGetConfig (dpy, v, GLX_STEREO, &eds->settings[ALLEGRO_STEREO]) || glXGetConfig (dpy, v, GLX_AUX_BUFFERS, &eds->settings[ALLEGRO_AUX_BUFFERS]) || glXGetConfig (dpy, v, GLX_DEPTH_SIZE, &eds->settings[ALLEGRO_DEPTH_SIZE]) || glXGetConfig (dpy, v, GLX_STENCIL_SIZE, &eds->settings[ALLEGRO_STENCIL_SIZE]) || glXGetConfig (dpy, v, GLX_ACCUM_RED_SIZE, &eds->settings[ALLEGRO_ACC_RED_SIZE]) || glXGetConfig (dpy, v, GLX_ACCUM_GREEN_SIZE, &eds->settings[ALLEGRO_ACC_GREEN_SIZE]) || glXGetConfig (dpy, v, GLX_ACCUM_BLUE_SIZE, &eds->settings[ALLEGRO_ACC_BLUE_SIZE]) || glXGetConfig (dpy, v, GLX_ACCUM_ALPHA_SIZE, &eds->settings[ALLEGRO_ACC_ALPHA_SIZE])) { ALLEGRO_DEBUG("Incomplete glX mode ...\n"); al_free(eds); return NULL; } eds->settings[ALLEGRO_SINGLE_BUFFER] = !double_buffer; if (!rgba) { ALLEGRO_DEBUG("Not RGBA mode\n"); al_free(eds); return NULL; } if (!use_gl) { ALLEGRO_DEBUG("OpenGL Unsupported\n"); al_free(eds); return NULL; } eds->settings[ALLEGRO_COLOR_SIZE] = 0; figure_out_colors(eds, v); eds->settings[ALLEGRO_FLOAT_COLOR] = 0; eds->settings[ALLEGRO_FLOAT_DEPTH] = 0; if (glXGetConfig(dpy, v, GLX_SAMPLE_BUFFERS, &sbuffers) == GLX_BAD_ATTRIBUTE) { /* Multisample extension is not supported */ eds->settings[ALLEGRO_SAMPLE_BUFFERS] = 0; } else { eds->settings[ALLEGRO_SAMPLE_BUFFERS] = sbuffers; } if (glXGetConfig(dpy, v, GLX_SAMPLES, &samples) == GLX_BAD_ATTRIBUTE) { /* Multisample extension is not supported */ eds->settings[ALLEGRO_SAMPLES] = 0; } else { eds->settings[ALLEGRO_SAMPLES] = samples; } eds->settings[ALLEGRO_SWAP_METHOD] = 0; eds->settings[ALLEGRO_COMPATIBLE_DISPLAY] = (_al_deduce_color_format(eds) != ALLEGRO_PIXEL_FORMAT_ANY); return eds; } static ALLEGRO_EXTRA_DISPLAY_SETTINGS** get_visuals_old(int *eds_count) { int i, j, num_visuals; XVisualInfo *xv; ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref; ALLEGRO_EXTRA_DISPLAY_SETTINGS **eds; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ref = _al_get_new_display_settings(); xv = XGetVisualInfo(system->gfxdisplay, 0, NULL, &num_visuals); if (!xv || !num_visuals) return NULL; eds = al_malloc(num_visuals * sizeof(*eds)); ALLEGRO_INFO("%i formats.\n", num_visuals); for (i = j = 0; i < num_visuals; i++) { ALLEGRO_DEBUG("-- \n"); ALLEGRO_DEBUG("Decoding visual no. %i...\n", i); eds[j] = read_xvisual(system->gfxdisplay, xv + i); if (!eds[j]) continue; #ifdef DEBUGMODE display_pixel_format(eds[j]); #endif eds[j]->score = _al_score_display_settings(eds[j], ref); if (eds[j]->score == -1) { al_free(eds[j]); continue; } eds[j]->index = i; /* Seems that XVinfo is static. */ eds[j]->info = al_malloc(sizeof(XVisualInfo)); memcpy(eds[j]->info, xv + i, sizeof(XVisualInfo)); j++; } *eds_count = j; ALLEGRO_INFO("%i visuals are good enough.\n", j); if (j == 0) { al_free(eds); eds = NULL; } XFree(xv); return eds; } static void select_best_visual(ALLEGRO_DISPLAY_XGLX *glx, ALLEGRO_EXTRA_DISPLAY_SETTINGS* *eds, int eds_count, bool using_fbc) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); qsort(eds, eds_count, sizeof(*eds), _al_display_settings_sorter); ASSERT(eds_count > 0); ASSERT(eds[0] != NULL); if (!eds[0]->info) { ALLEGRO_ERROR("No matching displays found.\n"); glx->xvinfo = NULL; return; } ALLEGRO_INFO("Chose visual no. %i\n", eds[0]->index); #ifdef DEBUGMODE display_pixel_format(eds[0]); #endif if (using_fbc) { glx->fbc = al_malloc(sizeof(GLXFBConfig)); memcpy(glx->fbc, eds[0]->info, sizeof(GLXFBConfig)); glx->xvinfo = glXGetVisualFromFBConfig(system->gfxdisplay, *glx->fbc); } else { glx->xvinfo = al_malloc(sizeof(XVisualInfo)); memcpy(glx->xvinfo, eds[0]->info, sizeof(XVisualInfo)); } ALLEGRO_INFO("Corresponding X11 visual id: %lu\n", glx->xvinfo->visualid); memcpy(&glx->display.extra_settings, eds[0], sizeof(ALLEGRO_EXTRA_DISPLAY_SETTINGS)); } void _al_xglx_config_select_visual(ALLEGRO_DISPLAY_XGLX *glx) { ALLEGRO_EXTRA_DISPLAY_SETTINGS **eds; int eds_count, i; bool force_old = false; bool using_fbc; const char *selection_mode; selection_mode = al_get_config_value(al_get_system_config(), "graphics", "config_selection"); if (selection_mode && selection_mode[0] != '\0') { if (!_al_stricmp(selection_mode, "old")) { ALLEGRO_WARN("Forcing OLD visual selection method.\n"); force_old = true; } else if (!_al_stricmp(selection_mode, "new")) force_old = false; } if (glx->glx_version >= 130 && !force_old) eds = get_visuals_new(glx, &eds_count); else eds = NULL; if (!eds) { eds = get_visuals_old(&eds_count); using_fbc = false; } else using_fbc = true; if (!eds) { ALLEGRO_ERROR("Failed to get any visual info.\n"); return; } select_best_visual(glx, eds, eds_count, using_fbc); for (i = 0; i < eds_count; i++) { if (eds[i]) { al_free(eds[i]->info); al_free(eds[i]); } } al_free(eds); } static GLXContext create_context_new(int ver, Display *dpy, GLXFBConfig fb, GLXContext ctx, bool forward_compat, bool want_es, bool core_profile, int major, int minor) { typedef GLXContext (*GCCA_PROC) (Display*, GLXFBConfig, GLXContext, Bool, const int*); GCCA_PROC _xglx_glXCreateContextAttribsARB = NULL; if (ver >= 140) { /* GLX 1.4 should have this, if it's defined, use it directly. */ /* OTOH it *could* be there but only available through dynamic loading. */ /* In that case, fallback to calling glxXGetProcAddress. */ #ifdef glXCreateContextAttribsARB _xglx_glXCreateContextAttribsARB = glXCreateContextAttribsARB; #endif // glXCreateContextAttribsARB } if (!_xglx_glXCreateContextAttribsARB) { /* Load the extension manually. */ _xglx_glXCreateContextAttribsARB = (GCCA_PROC)glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB"); } if (!_xglx_glXCreateContextAttribsARB) { ALLEGRO_ERROR("GLX_ARB_create_context not supported and needed for OpenGL 3\n"); return NULL; } int attrib[] = {GLX_CONTEXT_MAJOR_VERSION_ARB, major, GLX_CONTEXT_MINOR_VERSION_ARB, minor, GLX_CONTEXT_FLAGS_ARB, 0, 0, 0, 0}; if (forward_compat) attrib[5] = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; if (want_es) { attrib[6] = GLX_CONTEXT_PROFILE_MASK_ARB; attrib[7] = GLX_CONTEXT_ES_PROFILE_BIT_EXT; } else if (core_profile) { attrib[6] = GLX_CONTEXT_PROFILE_MASK_ARB; attrib[7] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; } return _xglx_glXCreateContextAttribsARB(dpy, fb, ctx, True, attrib); } bool _al_xglx_config_create_context(ALLEGRO_DISPLAY_XGLX *glx) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY *disp = (void*)glx; GLXContext existing_ctx = NULL; /* Find an existing context with which to share display lists. */ if (_al_vector_size(&system->system.displays) > 1) { ALLEGRO_DISPLAY_XGLX **existing_dpy; existing_dpy = _al_vector_ref_front(&system->system.displays); if (*existing_dpy != glx) existing_ctx = (*existing_dpy)->context; } int major = al_get_new_display_option(ALLEGRO_OPENGL_MAJOR_VERSION, 0); int minor = al_get_new_display_option(ALLEGRO_OPENGL_MINOR_VERSION, 0); if (glx->fbc) { bool forward_compat = (disp->flags & ALLEGRO_OPENGL_FORWARD_COMPATIBLE) != 0; bool core_profile = (disp->flags & ALLEGRO_OPENGL_CORE_PROFILE) != 0; /* Create a GLX context from FBC. */ if (disp->flags & ALLEGRO_OPENGL_ES_PROFILE) { if (major == 0) major = 2; glx->context = create_context_new(glx->glx_version, system->gfxdisplay, *glx->fbc, existing_ctx, forward_compat, true, core_profile, major, minor); } else if ((disp->flags & ALLEGRO_OPENGL_3_0) || major != 0 || core_profile) { if (major == 0) major = 3; if (core_profile && major == 3 && minor < 2) // core profile requires at least 3.2 minor = 2; glx->context = create_context_new(glx->glx_version, system->gfxdisplay, *glx->fbc, existing_ctx, forward_compat, false, core_profile, major, minor); /* TODO: Right now Allegro's own OpenGL driver only works with a 3.0+ * context when using the programmable pipeline, for some reason. All * that's missing is probably a default shader though. */ disp->extra_settings.settings[ALLEGRO_COMPATIBLE_DISPLAY] = 1; if (forward_compat && !(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) disp->extra_settings.settings[ALLEGRO_COMPATIBLE_DISPLAY] = 0; } else { glx->context = glXCreateNewContext(system->gfxdisplay, *glx->fbc, GLX_RGBA_TYPE, existing_ctx, True); } /* Create a GLX subwindow inside our window. */ glx->glxwindow = glXCreateWindow(system->gfxdisplay, *glx->fbc, glx->window, 0); } else { /* Create a GLX context from visual info. */ glx->context = glXCreateContext(system->gfxdisplay, glx->xvinfo, existing_ctx, True); glx->glxwindow = glx->window; } if (!glx->context || !glx->glxwindow) { ALLEGRO_ERROR("Failed to create GLX context.\n"); return false; } disp->ogl_extras->is_shared = true; ALLEGRO_DEBUG("Got GLX context.\n"); return true; } allegro5-5.2.10.1/src/x/xicon.h000066400000000000000000000001421473414355200160040ustar00rootroot00000000000000#ifndef XICON_H #define XICON_H extern ALLEGRO_BITMAP *_al_xwin_initial_icon; #endif // XICON_H allegro5-5.2.10.1/src/x/xkeyboard.c000066400000000000000000001007501473414355200166550ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * X keyboard driver. * * By Elias Pschernig. * * Modified for the new keyboard API by Peter Wang. * * See readme.txt for copyright information. */ #define ALLEGRO_NO_COMPATIBILITY #include #include #include #include #include #include #include #include #include #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_events.h" #include "allegro5/internal/aintern_keyboard.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xkeyboard.h" #include "allegro5/internal/aintern_xsystem.h" #ifdef ALLEGRO_RASPBERRYPI #include "allegro5/internal/aintern_raspberrypi.h" #define ALLEGRO_SYSTEM_XGLX ALLEGRO_SYSTEM_RASPBERRYPI #endif ALLEGRO_DEBUG_CHANNEL("keyboard") /*----------------------------------------------------------------------*/ static void handle_key_press(int mycode, int unichar, int filtered, unsigned int modifiers, ALLEGRO_DISPLAY *display); static void handle_key_release(int mycode, unsigned int modifiers, ALLEGRO_DISPLAY *display); static int _key_shifts; /*----------------------------------------------------------------------*/ typedef struct ALLEGRO_KEYBOARD_XWIN { ALLEGRO_KEYBOARD parent; ALLEGRO_KEYBOARD_STATE state; // Quit if Ctrl-Alt-Del is pressed. bool three_finger_flag; } ALLEGRO_KEYBOARD_XWIN; typedef struct ALLEGRO_KEY_REPEAT_DATA { XKeyEvent *event; bool found; } ALLEGRO_KEY_REPEAT_DATA; /* the one and only keyboard object */ static ALLEGRO_KEYBOARD_XWIN the_keyboard; static int last_press_code = -1; #ifdef ALLEGRO_XWINDOWS_WITH_XIM static XIM xim = NULL; static XIC xic = NULL; #endif static XModifierKeymap *xmodmap = NULL; static int xkeyboard_installed = 0; static int used[ALLEGRO_KEY_MAX]; static int sym_per_key; static int min_keycode, max_keycode; static KeySym *keysyms = NULL; static int main_pid; /* The pid to kill with ctrl-alt-del. */ static int pause_key = 0; /* Allegro's special pause key state. */ static int keycode_to_scancode[256]; /* This table can be ammended to provide more reasonable defaults for * mappings other than US/UK. They are used to map X11 KeySyms as found in * X11/keysym.h to Allegro's ALLEGRO_KEY_* codes. This will only work well on US/UK * keyboards since Allegro simply doesn't have ALLEGRO_KEY_* codes for non US/UK * keyboards. So with other mappings, the unmapped keys will be distributed * arbitrarily to the remaining ALLEGRO_KEY_* codes. * * Double mappings should be avoided, else they can lead to different keys * producing the same ALLEGRO_KEY_* code on some mappings. * * In cases where there is no other way to detect a key, since we have no * ASCII applied to it, like ALLEGRO_KEY_LEFT or ALLEGRO_KEY_PAUSE, multiple mappings should * be ok though. This table will never be able to be 100% perfect, so just * try to make it work for as many as possible, using additional hacks in * some cases. There is also still the possibility to override keys with * the [xkeyboard] config section, so users can always re-map keys. (E.g. * to play an Allegro game which hard-coded ALLEGRO_KEY_Y and ALLEGRO_KEY_X for left and * right.) */ static struct { KeySym keysym; int allegro_key; } translation_table[] = { {XK_a, ALLEGRO_KEY_A}, {XK_b, ALLEGRO_KEY_B}, {XK_c, ALLEGRO_KEY_C}, {XK_d, ALLEGRO_KEY_D}, {XK_e, ALLEGRO_KEY_E}, {XK_f, ALLEGRO_KEY_F}, {XK_g, ALLEGRO_KEY_G}, {XK_h, ALLEGRO_KEY_H}, {XK_i, ALLEGRO_KEY_I}, {XK_j, ALLEGRO_KEY_J}, {XK_k, ALLEGRO_KEY_K}, {XK_l, ALLEGRO_KEY_L}, {XK_m, ALLEGRO_KEY_M}, {XK_n, ALLEGRO_KEY_N}, {XK_o, ALLEGRO_KEY_O}, {XK_p, ALLEGRO_KEY_P}, {XK_q, ALLEGRO_KEY_Q}, {XK_r, ALLEGRO_KEY_R}, {XK_s, ALLEGRO_KEY_S}, {XK_t, ALLEGRO_KEY_T}, {XK_u, ALLEGRO_KEY_U}, {XK_v, ALLEGRO_KEY_V}, {XK_w, ALLEGRO_KEY_W}, {XK_x, ALLEGRO_KEY_X}, {XK_y, ALLEGRO_KEY_Y}, {XK_z, ALLEGRO_KEY_Z}, {XK_0, ALLEGRO_KEY_0}, {XK_1, ALLEGRO_KEY_1}, {XK_2, ALLEGRO_KEY_2}, {XK_3, ALLEGRO_KEY_3}, {XK_4, ALLEGRO_KEY_4}, {XK_5, ALLEGRO_KEY_5}, {XK_6, ALLEGRO_KEY_6}, {XK_7, ALLEGRO_KEY_7}, {XK_8, ALLEGRO_KEY_8}, {XK_9, ALLEGRO_KEY_9}, /* Double mappings for numeric keyboard. * If an X server actually uses both at the same time, Allegro will * detect them as the same. But normally, an X server just reports it as * either of them, and therefore we always get the keys as ALLEGRO_KEY_PAD_*. */ {XK_KP_0, ALLEGRO_KEY_PAD_0}, {XK_KP_Insert, ALLEGRO_KEY_PAD_0}, {XK_KP_1, ALLEGRO_KEY_PAD_1}, {XK_KP_End, ALLEGRO_KEY_PAD_1}, {XK_KP_2, ALLEGRO_KEY_PAD_2}, {XK_KP_Down, ALLEGRO_KEY_PAD_2}, {XK_KP_3, ALLEGRO_KEY_PAD_3}, {XK_KP_Page_Down, ALLEGRO_KEY_PAD_3}, {XK_KP_4, ALLEGRO_KEY_PAD_4}, {XK_KP_Left, ALLEGRO_KEY_PAD_4}, {XK_KP_5, ALLEGRO_KEY_PAD_5}, {XK_KP_Begin, ALLEGRO_KEY_PAD_5}, {XK_KP_6, ALLEGRO_KEY_PAD_6}, {XK_KP_Right, ALLEGRO_KEY_PAD_6}, {XK_KP_7, ALLEGRO_KEY_PAD_7}, {XK_KP_Home, ALLEGRO_KEY_PAD_7}, {XK_KP_8, ALLEGRO_KEY_PAD_8}, {XK_KP_Up, ALLEGRO_KEY_PAD_8}, {XK_KP_9, ALLEGRO_KEY_PAD_9}, {XK_KP_Page_Up, ALLEGRO_KEY_PAD_9}, {XK_KP_Delete, ALLEGRO_KEY_PAD_DELETE}, {XK_KP_Decimal, ALLEGRO_KEY_PAD_DELETE}, /* Double mapping! * Same as above - but normally, the X server just reports one or the * other for the Pause key, and the other is not reported for any key. */ {XK_Pause, ALLEGRO_KEY_PAUSE}, {XK_Break, ALLEGRO_KEY_PAUSE}, {XK_F1, ALLEGRO_KEY_F1}, {XK_F2, ALLEGRO_KEY_F2}, {XK_F3, ALLEGRO_KEY_F3}, {XK_F4, ALLEGRO_KEY_F4}, {XK_F5, ALLEGRO_KEY_F5}, {XK_F6, ALLEGRO_KEY_F6}, {XK_F7, ALLEGRO_KEY_F7}, {XK_F8, ALLEGRO_KEY_F8}, {XK_F9, ALLEGRO_KEY_F9}, {XK_F10, ALLEGRO_KEY_F10}, {XK_F11, ALLEGRO_KEY_F11}, {XK_F12, ALLEGRO_KEY_F12}, {XK_Escape, ALLEGRO_KEY_ESCAPE}, {XK_grave, ALLEGRO_KEY_TILDE}, /* US left of 1 */ {XK_minus, ALLEGRO_KEY_MINUS}, /* US right of 0 */ {XK_equal, ALLEGRO_KEY_EQUALS}, /* US 2 right of 0 */ {XK_BackSpace, ALLEGRO_KEY_BACKSPACE}, {XK_Tab, ALLEGRO_KEY_TAB}, {XK_bracketleft, ALLEGRO_KEY_OPENBRACE}, /* US right of P */ {XK_bracketright, ALLEGRO_KEY_CLOSEBRACE}, /* US 2 right of P */ {XK_Return, ALLEGRO_KEY_ENTER}, {XK_semicolon, ALLEGRO_KEY_SEMICOLON}, /* US right of L */ {XK_apostrophe, ALLEGRO_KEY_QUOTE}, /* US 2 right of L */ {XK_backslash, ALLEGRO_KEY_BACKSLASH}, /* US 3 right of L */ {XK_less, ALLEGRO_KEY_BACKSLASH2}, /* US left of Y */ {XK_comma, ALLEGRO_KEY_COMMA}, /* US right of M */ {XK_period, ALLEGRO_KEY_FULLSTOP}, /* US 2 right of M */ {XK_slash, ALLEGRO_KEY_SLASH}, /* US 3 right of M */ {XK_space, ALLEGRO_KEY_SPACE}, {XK_Insert, ALLEGRO_KEY_INSERT}, {XK_Delete, ALLEGRO_KEY_DELETE}, {XK_Home, ALLEGRO_KEY_HOME}, {XK_End, ALLEGRO_KEY_END}, {XK_Page_Up, ALLEGRO_KEY_PGUP}, {XK_Page_Down, ALLEGRO_KEY_PGDN}, {XK_Left, ALLEGRO_KEY_LEFT}, {XK_Right, ALLEGRO_KEY_RIGHT}, {XK_Up, ALLEGRO_KEY_UP}, {XK_Down, ALLEGRO_KEY_DOWN}, {XK_KP_Divide, ALLEGRO_KEY_PAD_SLASH}, {XK_KP_Multiply, ALLEGRO_KEY_PAD_ASTERISK}, {XK_KP_Subtract, ALLEGRO_KEY_PAD_MINUS}, {XK_KP_Add, ALLEGRO_KEY_PAD_PLUS}, {XK_KP_Enter, ALLEGRO_KEY_PAD_ENTER}, {XK_Print, ALLEGRO_KEY_PRINTSCREEN}, //{, ALLEGRO_KEY_ABNT_C1}, //{, ALLEGRO_KEY_YEN}, //{, ALLEGRO_KEY_KANA}, //{, ALLEGRO_KEY_CONVERT}, //{, ALLEGRO_KEY_NOCONVERT}, //{, ALLEGRO_KEY_AT}, //{, ALLEGRO_KEY_CIRCUMFLEX}, //{, ALLEGRO_KEY_COLON2}, //{, ALLEGRO_KEY_KANJI}, {XK_KP_Equal, ALLEGRO_KEY_PAD_EQUALS}, /* MacOS X */ //{, ALLEGRO_KEY_BACKQUOTE}, /* MacOS X */ //{, ALLEGRO_KEY_SEMICOLON}, /* MacOS X */ //{, ALLEGRO_KEY_COMMAND}, /* MacOS X */ {XK_Shift_L, ALLEGRO_KEY_LSHIFT}, {XK_Shift_R, ALLEGRO_KEY_RSHIFT}, {XK_Control_L, ALLEGRO_KEY_LCTRL}, {XK_Control_R, ALLEGRO_KEY_RCTRL}, {XK_Alt_L, ALLEGRO_KEY_ALT}, /* Double mappings. This is a bit of a problem, since you can configure * X11 differently to what report for those keys. */ {XK_Alt_R, ALLEGRO_KEY_ALTGR}, {XK_ISO_Level3_Shift, ALLEGRO_KEY_ALTGR}, {XK_Meta_L, ALLEGRO_KEY_LWIN}, {XK_Super_L, ALLEGRO_KEY_LWIN}, {XK_Meta_R, ALLEGRO_KEY_RWIN}, {XK_Super_R, ALLEGRO_KEY_RWIN}, {XK_Menu, ALLEGRO_KEY_MENU}, {XK_Scroll_Lock, ALLEGRO_KEY_SCROLLLOCK}, {XK_Num_Lock, ALLEGRO_KEY_NUMLOCK}, {XK_Caps_Lock, ALLEGRO_KEY_CAPSLOCK} }; /* Table of: Allegro's modifier flag, associated X11 flag, toggle method. */ static int modifier_flags[8][3] = { {ALLEGRO_KEYMOD_SHIFT, ShiftMask, 0}, {ALLEGRO_KEYMOD_CAPSLOCK, LockMask, 1}, {ALLEGRO_KEYMOD_CTRL, ControlMask, 0}, {ALLEGRO_KEYMOD_ALT, Mod1Mask, 0}, {ALLEGRO_KEYMOD_NUMLOCK, Mod2Mask, 1}, {ALLEGRO_KEYMOD_SCROLLLOCK, Mod3Mask, 1}, {ALLEGRO_KEYMOD_LWIN | ALLEGRO_KEYMOD_RWIN, Mod4Mask, 0}, /* Should we use only one? */ {ALLEGRO_KEYMOD_ALTGR, Mod5Mask, 0} /* AltGr */ }; /* Table of key names. */ static char const *key_names[ALLEGRO_KEY_MAX]; /* update_shifts * Update Allegro's key_shifts variable, directly from the corresponding * X11 modifiers state. */ static void update_shifts(XKeyEvent *event) { int mask = 0; int i; for (i = 0; i < 8; i++) { int j; /* This is the state of the modifiers just before the key * press/release. */ if (event->state & modifier_flags[i][1]) mask |= modifier_flags[i][0]; /* In case a modifier key itself was pressed, we now need to update * the above state for Allegro, which wants the state after the * press, not before as reported by X. */ for (j = 0; j < xmodmap->max_keypermod; j++) { if (event->keycode && event->keycode == xmodmap->modifiermap[i * xmodmap->max_keypermod + j]) { if (event->type == KeyPress) { /* Modifier key pressed - toggle or set flag. */ if (modifier_flags[i][2]) mask ^= modifier_flags[i][0]; else mask |= modifier_flags[i][0]; } else if (event->type == KeyRelease) { /* Modifier key of non-toggle key released - remove flag. */ if (!modifier_flags[i][2]) mask &= ~modifier_flags[i][0]; } } } } _key_shifts = mask; } /* find_unknown_key_assignment * In some cases, X11 doesn't report any KeySym for a key - so the earliest * time we can map it to an Allegro key is when it is first pressed. */ static int find_unknown_key_assignment(int i) { int j; for (j = 1; j < ALLEGRO_KEY_MAX; j++) { if (!used[j]) { const char *str; keycode_to_scancode[i] = j; str = XKeysymToString(keysyms[sym_per_key * (i - min_keycode)]); if (str) key_names[j] = str; else { key_names[j] = _al_keyboard_common_names[j]; } used[j] = 1; break; } } if (j == ALLEGRO_KEY_MAX) { ALLEGRO_ERROR("You have more keys reported by X than Allegro's " "maximum of %i keys. Please send a bug report.\n", ALLEGRO_KEY_MAX); keycode_to_scancode[i] = 0; } char str[1024]; sprintf(str, "Key %i missing:", i); for (j = 0; j < sym_per_key; j++) { char *sym_str = XKeysymToString(keysyms[sym_per_key * (i - min_keycode) + j]); sprintf(str + strlen(str), " %s", sym_str ? sym_str : "NULL"); } ALLEGRO_DEBUG("%s assigned to %i.\n", str, keycode_to_scancode[i]); return keycode_to_scancode[i]; } /* XCheckIfAny predicate that checks if this event may be a key repeat event */ static Bool check_for_repeat(Display *display, XEvent *event, XPointer arg) { ALLEGRO_KEY_REPEAT_DATA *d = (ALLEGRO_KEY_REPEAT_DATA *)arg; (void)display; if (event->type == KeyPress && event->xkey.keycode == d->event->keycode && (event->xkey.time - d->event->time) < 4) { d->found = true; } return False; } /* _al_xwin_keyboard_handler: * Keyboard "interrupt" handler. */ void _al_xwin_keyboard_handler(XKeyEvent *event, ALLEGRO_DISPLAY *display) { int keycode; if (!xkeyboard_installed) return; keycode = keycode_to_scancode[event->keycode]; if (keycode == -1) keycode = find_unknown_key_assignment(event->keycode); update_shifts(event); /* Special case the pause key. */ if (keycode == ALLEGRO_KEY_PAUSE) { /* Allegro ignore's releasing of the pause key. */ if (event->type == KeyRelease) return; if (pause_key) { event->type = KeyRelease; pause_key = 0; } else { pause_key = 1; } } if (event->type == KeyPress) { /* Key pressed. */ int len; char buffer[16]; int unicode = 0; int filtered = 0; #if defined (ALLEGRO_XWINDOWS_WITH_XIM) && defined(X_HAVE_UTF8_STRING) if (xic) { len = Xutf8LookupString(xic, event, buffer, sizeof buffer, NULL, NULL); } else #endif { /* XLookupString is supposed to only use ASCII. */ len = XLookupString(event, buffer, sizeof buffer, NULL, NULL); } buffer[len] = '\0'; ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *ustr = al_ref_cstr(&info, buffer); unicode = al_ustr_get(ustr, 0); if (unicode < 0) unicode = 0; #ifdef ALLEGRO_XWINDOWS_WITH_XIM ALLEGRO_DISPLAY_XGLX *glx = (void *)display; filtered = XFilterEvent((XEvent *)event, glx->window); #endif if (keycode || unicode) { handle_key_press(keycode, unicode, filtered, _key_shifts, display); } } else { /* Key release. */ /* HACK: * Detect key repeat by looking forward to see if this release is * followed by a press event, in which case we assume that this release * event was generated in response to that key press event. Events are * simultaneous if they are separated by less than 4 ms (a value that * worked well on one machine where this hack was needed). * * This is unnecessary on systems where XkbSetDetectableAutorepeat works. */ if (XPending(event->display) > 0) { ALLEGRO_KEY_REPEAT_DATA d; XEvent dummy; d.event = event; d.found = false; XCheckIfEvent(event->display, &dummy, check_for_repeat, (XPointer)&d); if (d.found) { return; } } handle_key_release(keycode, _key_shifts, display); } } /* _al_xwin_keyboard_switch_handler: * Handle a focus switch event. */ void _al_xwin_keyboard_switch_handler(ALLEGRO_DISPLAY *display, bool focus_in) { _al_event_source_lock(&the_keyboard.parent.es); if (focus_in) { the_keyboard.state.display = display; #ifdef ALLEGRO_XWINDOWS_WITH_XIM if (xic) { ALLEGRO_DISPLAY_XGLX *display_glx = (void *)display; XSetICValues(xic, XNClientWindow, display_glx->window, NULL); } #endif } else { the_keyboard.state.display = NULL; } _al_event_source_unlock(&the_keyboard.parent.es); } /* find_allegro_key * Search the translation table for the Allegro key corresponding to the * given KeySym. */ static int find_allegro_key(KeySym sym) { int i; int n = sizeof translation_table / sizeof *translation_table; for (i = 0; i < n; i++) { if (translation_table[i].keysym == sym) return translation_table[i].allegro_key; } return 0; } /* scancode_to_name: * Converts the given scancode to a description of the key. */ static const char *x_scancode_to_name(int scancode) { ASSERT (scancode >= 0 && scancode < ALLEGRO_KEY_MAX); return key_names[scancode]; } /* _al_xwin_get_keyboard_mapping: * Generate a mapping from X11 keycodes to Allegro ALLEGRO_KEY_* codes. We have * two goals: Every keypress should be mapped to a distinct Allegro ALLEGRO_KEY_* * code. And we want the ALLEGRO_KEY_* codes to match the pressed * key to some extent. To do the latter, the X11 KeySyms produced by a key * are examined. If a match is found in the table above, the mapping is * added to the mapping table. If no known KeySym is found for a key (or * the same KeySym is found for more keys) - the remaining keys are * distributed arbitrarily to the remaining ALLEGRO_KEY_* codes. * * In a future version, this could be simplified by mapping *all* the X11 * KeySyms to ALLEGRO_KEY_* codes. */ static bool _al_xwin_get_keyboard_mapping(void) { int i; int count; int missing = 0; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); memset(used, 0, sizeof used); memset(keycode_to_scancode, 0, sizeof keycode_to_scancode); XDisplayKeycodes(system->x11display, &min_keycode, &max_keycode); count = 1 + max_keycode - min_keycode; if (keysyms) { XFree(keysyms); } keysyms = XGetKeyboardMapping(system->x11display, min_keycode, count, &sym_per_key); ALLEGRO_INFO("%i keys, %i symbols per key.\n", count, sym_per_key); if (sym_per_key <= 0) { return false; } missing = 0; for (i = min_keycode; i <= max_keycode; i++) { KeySym sym = keysyms[sym_per_key * (i - min_keycode)]; KeySym sym2 = keysyms[sym_per_key * (i - min_keycode) + 1]; char *sym_str, *sym2_str; int allegro_key = 0; char str[1024]; sym_str = XKeysymToString(sym); sym2_str = XKeysymToString(sym2); snprintf(str, sizeof str, "key [%i: %s %s]", i, sym_str ? sym_str : "NULL", sym2_str ? sym2_str : "NULL"); /* Hack for French keyboards, to correctly map ALLEGRO_KEY_0 to ALLEGRO_KEY_9. */ if (sym2 >= XK_0 && sym2 <= XK_9) { allegro_key = find_allegro_key(sym2); } if (!allegro_key) { if (sym != NoSymbol) { allegro_key = find_allegro_key(sym); if (allegro_key == 0) { missing++; ALLEGRO_DEBUG("%s defering.\n", str); } } else { /* No KeySym for this key - ignore it. */ keycode_to_scancode[i] = -1; ALLEGRO_DEBUG("%s not assigned.\n", str); } } if (allegro_key) { bool is_double = false; if (used[allegro_key]) { is_double = true; } keycode_to_scancode[i] = allegro_key; key_names[allegro_key] = XKeysymToString(keysyms[sym_per_key * (i - min_keycode)]); used[allegro_key] = 1; ALLEGRO_DEBUG("%s%s assigned to %i.\n", str, is_double ? " *double*" : "", allegro_key); } } if (missing) { /* The keys still not assigned are just assigned arbitrarily now. */ for (i = min_keycode; i <= max_keycode; i++) { if (keycode_to_scancode[i] == 0) { find_unknown_key_assignment(i); } } } if (xmodmap) XFreeModifiermap(xmodmap); xmodmap = XGetModifierMapping(system->x11display); for (i = 0; i < 8; i++) { int j; char str[1024]; sprintf(str, "Modifier %d:", i + 1); for (j = 0; j < xmodmap->max_keypermod; j++) { KeyCode keycode = xmodmap->modifiermap[i * xmodmap->max_keypermod + j]; // XKeycodeToKeysym is deprecated //KeySym sym = XKeycodeToKeysym(system->x11display, keycode, 0); KeySym sym = XkbKeycodeToKeysym(system->x11display, keycode, 0, 0); char *sym_str = XKeysymToString(sym); sprintf(str + strlen(str), " %s", sym_str ? sym_str : "NULL"); } ALLEGRO_DEBUG("%s\n", str); } /* The [xkeymap] section can be useful, e.g. if trying to play a * game which has X and Y hardcoded as ALLEGRO_KEY_X and ALLEGRO_KEY_Y to mean * left/right movement, but on the X11 keyboard X and Y are far apart. * For normal use, a user never should have to touch [xkeymap] anymore * though, and proper written programs will not hardcode such mappings. */ ALLEGRO_CONFIG *c = al_get_system_config(); char const *key; ALLEGRO_CONFIG_ENTRY *it; key = al_get_first_config_entry(c, "xkeymap", &it); while (key) { char const *val; val = al_get_config_value(c, "xkeymap", key); int keycode = strtol(key, NULL, 10); int scancode = strtol(val, NULL, 10); if (keycode > 0 && scancode > 0) { keycode_to_scancode[keycode] = scancode; ALLEGRO_WARN("User override: KeySym %i assigned to %i.\n", keycode, scancode); } key = al_get_next_config_entry(&it); } return true; } /* x_set_leds: * Update the keyboard LEDs. */ static void x_set_leds(int leds) { XKeyboardControl values; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ASSERT(xkeyboard_installed); _al_mutex_lock(&system->lock); values.led = 1; values.led_mode = leds & ALLEGRO_KEYMOD_NUMLOCK ? LedModeOn : LedModeOff; XChangeKeyboardControl(system->x11display, KBLed | KBLedMode, &values); values.led = 2; values.led_mode = leds & ALLEGRO_KEYMOD_CAPSLOCK ? LedModeOn : LedModeOff; XChangeKeyboardControl(system->x11display, KBLed | KBLedMode, &values); values.led = 3; values.led_mode = leds & ALLEGRO_KEYMOD_SCROLLLOCK ? LedModeOn : LedModeOff; XChangeKeyboardControl(system->x11display, KBLed | KBLedMode, &values); _al_mutex_unlock(&system->lock); } /* x_keyboard_init * Initialise the X11 keyboard driver. */ static int x_keyboard_init(void) { #ifdef ALLEGRO_XWINDOWS_WITH_XIM char *old_locale; XIMStyles *xim_styles; XIMStyle xim_style = 0; char *imvalret; int i; #endif ALLEGRO_SYSTEM_XGLX *s = (void *)al_get_system_driver(); if (xkeyboard_installed) return 0; if (s->x11display == NULL) return 0; main_pid = getpid(); memcpy(key_names, _al_keyboard_common_names, sizeof key_names); _al_mutex_lock(&s->lock); /* HACK: XkbSetDetectableAutoRepeat is broken in some versions of X.Org */ Bool supported; XkbSetDetectableAutoRepeat(s->x11display, True, &supported); if (!supported) { ALLEGRO_WARN("XkbSetDetectableAutoRepeat failed.\n"); } #ifdef ALLEGRO_XWINDOWS_WITH_XIM ALLEGRO_INFO("Using X Input Method.\n"); old_locale = setlocale(LC_CTYPE, NULL); ALLEGRO_DEBUG("Old locale: %s\n", old_locale ? old_locale : "(null)"); if (old_locale) { /* The return value of setlocale() may be clobbered by the next call * to setlocale() so we must copy it. */ old_locale = strdup(old_locale); } /* Otherwise we are restricted to ISO-8859-1 characters. */ if (setlocale(LC_CTYPE, "") == NULL) { ALLEGRO_WARN("Could not set default locale.\n"); } /* By default never use an input method as we are not prepared to * handle any of them. This is still enough to get composed keys. */ char const *modifiers = XSetLocaleModifiers("@im=none"); if (modifiers == NULL) { ALLEGRO_WARN("XSetLocaleModifiers failed.\n"); } xim = XOpenIM(s->x11display, NULL, NULL, NULL); if (xim == NULL) { ALLEGRO_WARN("XOpenIM failed.\n"); } if (old_locale) { ALLEGRO_DEBUG("Restoring old locale: %s\n", old_locale); setlocale(LC_CTYPE, old_locale); free(old_locale); } if (xim) { imvalret = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL); if (imvalret != NULL || xim_styles == NULL) { ALLEGRO_WARN("Input method doesn't support any styles.\n"); } if (xim_styles) { xim_style = 0; for (i = 0; i < xim_styles->count_styles; i++) { if (xim_styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) { xim_style = xim_styles->supported_styles[i]; break; } } if (xim_style == 0) { ALLEGRO_WARN("Input method doesn't support the style we support.\n"); } else { ALLEGRO_INFO("Input method style = %ld\n", xim_style); } XFree(xim_styles); } } if (xim && xim_style) { xic = XCreateIC(xim, XNInputStyle, xim_style, NULL); if (xic == NULL) { ALLEGRO_WARN("XCreateIC failed.\n"); } else { ALLEGRO_INFO("XCreateIC succeeded.\n"); } /* In case al_install_keyboard() is called when there already is * a display, we set it as client window. */ ALLEGRO_DISPLAY *display = al_get_current_display(); ALLEGRO_DISPLAY_XGLX *display_glx = (void *)display; if (display_glx && xic) XSetICValues(xic, XNClientWindow, display_glx->window, NULL); } #endif if (!_al_xwin_get_keyboard_mapping()) { return 1; } _al_mutex_unlock(&s->lock); xkeyboard_installed = 1; return 0; } /* x_keyboard_exit * Shut down the X11 keyboard driver. */ static void x_keyboard_exit(void) { if (!xkeyboard_installed) return; xkeyboard_installed = 0; ALLEGRO_SYSTEM_XGLX *s = (void *)al_get_system_driver(); _al_mutex_lock(&s->lock); #ifdef ALLEGRO_XWINDOWS_WITH_XIM if (xic) { XDestroyIC(xic); xic = NULL; } if (xim) { XCloseIM(xim); xim = NULL; } #endif if (xmodmap) { XFreeModifiermap(xmodmap); xmodmap = NULL; } if (keysyms) { XFree(keysyms); keysyms = NULL; } _al_mutex_unlock(&s->lock); } /*---------------------------------------------------------------------- * * Supports for new API. For now this code is kept separate from the * above to ease merging changes made in the trunk. * */ /* forward declarations */ static bool xkeybd_init_keyboard(void); static void xkeybd_exit_keyboard(void); static ALLEGRO_KEYBOARD *xkeybd_get_keyboard(void); static bool xkeybd_set_keyboard_leds(int leds); static const char *xkeybd_keycode_to_name(int keycode); static void xkeybd_get_keyboard_state(ALLEGRO_KEYBOARD_STATE *ret_state); static void xkeybd_clear_keyboard_state(void); /* the driver vtable */ #define KEYDRV_XWIN AL_ID('X','W','I','N') static ALLEGRO_KEYBOARD_DRIVER keydrv_xwin = { KEYDRV_XWIN, "", "", "X11 keyboard", xkeybd_init_keyboard, xkeybd_exit_keyboard, xkeybd_get_keyboard, xkeybd_set_keyboard_leds, xkeybd_keycode_to_name, xkeybd_get_keyboard_state, xkeybd_clear_keyboard_state }; ALLEGRO_KEYBOARD_DRIVER *_al_xwin_keyboard_driver(void) { return &keydrv_xwin; } /* xkeybd_init_keyboard: * Initialise the driver. */ static bool xkeybd_init_keyboard(void) { if (x_keyboard_init() != 0) return false; memset(&the_keyboard, 0, sizeof the_keyboard); _al_event_source_init(&the_keyboard.parent.es); the_keyboard.three_finger_flag = true; const char *value = al_get_config_value(al_get_system_config(), "keyboard", "enable_three_finger_exit"); if (value) { the_keyboard.three_finger_flag = !strncmp(value, "true", 4); } ALLEGRO_DEBUG("Three finger flag enabled: %s\n", the_keyboard.three_finger_flag ? "true" : "false"); //_xwin_keydrv_set_leds(_key_shifts); /* Get the pid, which we use for the three finger salute */ main_pid = getpid(); return true; } /* xkeybd_exit_keyboard: * Shut down the keyboard driver. */ static void xkeybd_exit_keyboard(void) { x_keyboard_exit(); _al_event_source_free(&the_keyboard.parent.es); } /* xkeybd_get_keyboard: * Returns the address of a ALLEGRO_KEYBOARD structure representing the keyboard. */ static ALLEGRO_KEYBOARD *xkeybd_get_keyboard(void) { return (ALLEGRO_KEYBOARD *)&the_keyboard; } /* xkeybd_set_keyboard_leds: * Updates the LED state. */ static bool xkeybd_set_keyboard_leds(int leds) { x_set_leds(leds); return true; } /* xkeybd_keycode_to_name: * Converts the given keycode to a description of the key. */ static const char *xkeybd_keycode_to_name(int keycode) { return x_scancode_to_name(keycode); } /* xkeybd_get_keyboard_state: * Copy the current keyboard state into RET_STATE, with any necessary locking. */ static void xkeybd_get_keyboard_state(ALLEGRO_KEYBOARD_STATE *ret_state) { _al_event_source_lock(&the_keyboard.parent.es); { *ret_state = the_keyboard.state; } _al_event_source_unlock(&the_keyboard.parent.es); } /* xkeybd_get_keyboard_state: * Clear the current keyboard state, with any necessary locking. */ static void xkeybd_clear_keyboard_state(void) { _al_event_source_lock(&the_keyboard.parent.es); { last_press_code = -1; memset(&the_keyboard.state, 0, sizeof(the_keyboard.state)); } _al_event_source_unlock(&the_keyboard.parent.es); } /* handle_key_press: [bgman thread] * Hook for the X event dispatcher to handle key presses. * The caller must lock the X-display. */ static void handle_key_press(int mycode, int unichar, int filtered, unsigned int modifiers, ALLEGRO_DISPLAY *display) { bool is_repeat; is_repeat = (last_press_code == mycode); if (mycode > 0) last_press_code = mycode; _al_event_source_lock(&the_keyboard.parent.es); { /* Update the key_down array. */ _AL_KEYBOARD_STATE_SET_KEY_DOWN(the_keyboard.state, mycode); /* Generate the events if necessary. */ if (_al_event_source_needs_to_generate_event(&the_keyboard.parent.es)) { ALLEGRO_EVENT event; event.keyboard.type = ALLEGRO_EVENT_KEY_DOWN; event.keyboard.timestamp = al_get_time(); event.keyboard.display = display; event.keyboard.keycode = last_press_code; event.keyboard.unichar = 0; event.keyboard.modifiers = modifiers; event.keyboard.repeat = false; /* Don't send KEY_DOWN for non-physical key events. */ if (mycode > 0 && !is_repeat) { _al_event_source_emit_event(&the_keyboard.parent.es, &event); } /* Don't send KEY_CHAR for events filtered by an input method, * nor modifier keys. */ if (!filtered && mycode < ALLEGRO_KEY_MODIFIERS) { event.keyboard.type = ALLEGRO_EVENT_KEY_CHAR; event.keyboard.unichar = unichar; event.keyboard.modifiers = modifiers; event.keyboard.repeat = is_repeat; _al_event_source_emit_event(&the_keyboard.parent.es, &event); } } } _al_event_source_unlock(&the_keyboard.parent.es); // FIXME? #ifndef ALLEGRO_RASPBERRYPI /* Toggle mouse grab key. The system driver should not be locked here. */ if (last_press_code && !is_repeat) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); if (system->toggle_mouse_grab_keycode && system->toggle_mouse_grab_keycode == mycode && (modifiers & system->toggle_mouse_grab_modifiers) == system->toggle_mouse_grab_modifiers) { if (system->mouse_grab_display == display) al_ungrab_mouse(); else al_grab_mouse(display); } } #endif /* Exit by Ctrl-Alt-End. */ if ((the_keyboard.three_finger_flag) && ((mycode == ALLEGRO_KEY_DELETE) || (mycode == ALLEGRO_KEY_END)) && (modifiers & ALLEGRO_KEYMOD_CTRL) && (modifiers & (ALLEGRO_KEYMOD_ALT | ALLEGRO_KEYMOD_ALTGR))) { ALLEGRO_WARN("Three finger combo detected. SIGTERMing " "pid %d\n", main_pid); kill(main_pid, SIGTERM); } } /* handle_key_release: [bgman thread] * Hook for the X event dispatcher to handle key releases. * The caller must lock the X-display. */ static void handle_key_release(int mycode, unsigned int modifiers, ALLEGRO_DISPLAY *display) { if (last_press_code == mycode) last_press_code = -1; _al_event_source_lock(&the_keyboard.parent.es); { /* Update the key_down array. */ _AL_KEYBOARD_STATE_CLEAR_KEY_DOWN(the_keyboard.state, mycode); /* Generate the release event if necessary. */ if (_al_event_source_needs_to_generate_event(&the_keyboard.parent.es)) { ALLEGRO_EVENT event; event.keyboard.type = ALLEGRO_EVENT_KEY_UP; event.keyboard.timestamp = al_get_time(); event.keyboard.display = display; event.keyboard.keycode = mycode; event.keyboard.unichar = 0; event.keyboard.modifiers = modifiers; _al_event_source_emit_event(&the_keyboard.parent.es, &event); } } _al_event_source_unlock(&the_keyboard.parent.es); } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/x/xmousenu.c000066400000000000000000000360011473414355200165450ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * X-Windows mouse module. * * By Peter Wang. * * Original by Michael Bukin. * * See readme.txt for copyright information. */ #define ALLEGRO_NO_COMPATIBILITY #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_mouse.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xmouse.h" #include "allegro5/internal/aintern_xsystem.h" #ifdef ALLEGRO_RASPBERRYPI #include "allegro5/internal/aintern_raspberrypi.h" #include "allegro5/internal/aintern_vector.h" #define ALLEGRO_SYSTEM_XGLX ALLEGRO_SYSTEM_RASPBERRYPI #define ALLEGRO_DISPLAY_XGLX ALLEGRO_DISPLAY_RASPBERRYPI #endif ALLEGRO_DEBUG_CHANNEL("mouse") typedef struct ALLEGRO_MOUSE_XWIN { ALLEGRO_MOUSE parent; ALLEGRO_MOUSE_STATE state; int min_x, min_y; int max_x, max_y; } ALLEGRO_MOUSE_XWIN; static bool xmouse_installed = false; /* the one and only mouse object */ static ALLEGRO_MOUSE_XWIN the_mouse; /* forward declarations */ static bool xmouse_init(void); static void xmouse_exit(void); static ALLEGRO_MOUSE *xmouse_get_mouse(void); static unsigned int xmouse_get_mouse_num_buttons(void); static unsigned int xmouse_get_mouse_num_axes(void); static bool xmouse_set_mouse_xy(ALLEGRO_DISPLAY *,int x, int y); static bool xmouse_set_mouse_axis(int which, int z); static void xmouse_get_state(ALLEGRO_MOUSE_STATE *ret_state); static void wheel_motion_handler(int x_button, ALLEGRO_DISPLAY *display); static unsigned int x_button_to_al_button(unsigned int x_button); static void generate_mouse_event(unsigned int type, int x, int y, int z, int w, float pressure, int dx, int dy, int dz, int dw, unsigned int button, ALLEGRO_DISPLAY *display); /* the driver vtable */ #define MOUSEDRV_XWIN AL_ID('X','W','I','N') static ALLEGRO_MOUSE_DRIVER mousedrv_xwin = { MOUSEDRV_XWIN, "", "", "X-Windows mouse", xmouse_init, xmouse_exit, xmouse_get_mouse, xmouse_get_mouse_num_buttons, xmouse_get_mouse_num_axes, xmouse_set_mouse_xy, xmouse_set_mouse_axis, xmouse_get_state }; ALLEGRO_MOUSE_DRIVER *_al_xwin_mouse_driver(void) { return &mousedrv_xwin; } /* xmouse_init: * Initialise the driver. */ static bool xmouse_init(void) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY *display; int x, y; if (system->x11display == NULL) return false; if (xmouse_installed) return false; /* Don't clobber mouse position in case the display was created before * the mouse is installed. */ display = the_mouse.state.display; x = the_mouse.state.x; y = the_mouse.state.y; memset(&the_mouse, 0, sizeof the_mouse); the_mouse.state.display = display; the_mouse.state.x = x; the_mouse.state.y = y; _al_event_source_init(&the_mouse.parent.es); xmouse_installed = true; return true; } /* xmouse_exit: * Shut down the mouse driver. */ static void xmouse_exit(void) { if (!xmouse_installed) return; xmouse_installed = false; _al_event_source_free(&the_mouse.parent.es); } /* xmouse_get_mouse: * Returns the address of a ALLEGRO_MOUSE structure representing the mouse. */ static ALLEGRO_MOUSE *xmouse_get_mouse(void) { ASSERT(xmouse_installed); return (ALLEGRO_MOUSE *)&the_mouse; } /* xmouse_get_mouse_num_buttons: * Return the number of buttons on the mouse. */ static unsigned int xmouse_get_mouse_num_buttons(void) { int num_buttons; unsigned char map[32]; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ASSERT(xmouse_installed); _al_mutex_lock(&system->lock); num_buttons = XGetPointerMapping(system->x11display, map, sizeof(map)); _al_mutex_unlock(&system->lock); if (num_buttons > (int)sizeof(map)) num_buttons = sizeof(map); #ifdef DEBUGMODE char debug[num_buttons * 4 + 1]; debug[0] = 0; int i; for (i = 0; i < num_buttons; i++) { sprintf(debug + strlen(debug), "%2d,", map[i]); } ALLEGRO_DEBUG("XGetPointerMapping: %s\n", debug); #endif if (num_buttons < 1) num_buttons = 1; return num_buttons; } /* xmouse_get_mouse_num_axes: * Return the number of axes on the mouse. */ static unsigned int xmouse_get_mouse_num_axes(void) { ASSERT(xmouse_installed); /* TODO: is there a way to detect whether z/w axis actually exist? */ return 4; } /* xmouse_set_mouse_xy: * Set the mouse position. Return true if successful. */ static bool xmouse_set_mouse_xy(ALLEGRO_DISPLAY *display, int x, int y) { if (!xmouse_installed) return false; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); Display *x11display = system->x11display; ALLEGRO_DISPLAY_XGLX *d = (void *)display; int window_width = al_get_display_width(display); int window_height = al_get_display_height(display); if (x < 0 || y < 0 || x >= window_width || y >= window_height) return false; the_mouse.state.x = x; the_mouse.state.y = y; #ifdef ALLEGRO_RASPBERRYPI float scale_x, scale_y; _al_raspberrypi_get_mouse_scale_ratios(&scale_x, &scale_y); x /= scale_x; y /= scale_y; #endif _al_mutex_lock(&system->lock); /* We prepend the mouse motion event generated by XWarpPointer * with our own event to distinguish real and generated * events. */ XEvent event; memset(&event, 0, sizeof event); event.xclient.type = ClientMessage; event.xclient.serial = 0; event.xclient.send_event = True; event.xclient.display = x11display; event.xclient.window = d->window; event.xclient.message_type = system->AllegroAtom; event.xclient.format = 32; XSendEvent(x11display, d->window, False, NoEventMask, &event); XWarpPointer(x11display, None, d->window, 0, 0, 0, 0, x, y); _al_mutex_unlock(&system->lock); return true; } /* xmouse_set_mouse_axis: * Set the mouse wheel position. Return true if successful. */ static bool xmouse_set_mouse_axis(int which, int v) { ASSERT(xmouse_installed); if (which != 2 && which != 3) { return false; } _al_event_source_lock(&the_mouse.parent.es); { int z = which == 2 ? v : the_mouse.state.z; int w = which == 3 ? v : the_mouse.state.w; int dz = z - the_mouse.state.z; int dw = w - the_mouse.state.w; if (dz != 0 || dw != 0) { the_mouse.state.z = z; the_mouse.state.w = w; generate_mouse_event( ALLEGRO_EVENT_MOUSE_AXES, the_mouse.state.x, the_mouse.state.y, the_mouse.state.z, the_mouse.state.w, the_mouse.state.pressure, 0, 0, dz, dw, 0, the_mouse.state.display); } } _al_event_source_unlock(&the_mouse.parent.es); return true; } /* xmouse_get_state: * Copy the current mouse state into RET_STATE, with any necessary locking. */ static void xmouse_get_state(ALLEGRO_MOUSE_STATE *ret_state) { ASSERT(xmouse_installed); _al_event_source_lock(&the_mouse.parent.es); { *ret_state = the_mouse.state; } _al_event_source_unlock(&the_mouse.parent.es); } /* _al_xwin_mouse_button_press_handler: [bgman thread] * Called by _xwin_process_event() for ButtonPress events received from the X * server. */ void _al_xwin_mouse_button_press_handler(int x_button, ALLEGRO_DISPLAY *display) { unsigned int al_button; if (!xmouse_installed) return; wheel_motion_handler(x_button, display); /* Is this button supported by the Allegro API? */ al_button = x_button_to_al_button(x_button); if (al_button == 0) return; _al_event_source_lock(&the_mouse.parent.es); { the_mouse.state.buttons |= (1 << (al_button - 1)); the_mouse.state.pressure = the_mouse.state.buttons ? 1.0 : 0.0; /* TODO */ generate_mouse_event( ALLEGRO_EVENT_MOUSE_BUTTON_DOWN, the_mouse.state.x, the_mouse.state.y, the_mouse.state.z, the_mouse.state.w, the_mouse.state.pressure, 0, 0, 0, 0, al_button, display); } _al_event_source_unlock(&the_mouse.parent.es); } /* wheel_motion_handler: [bgman thread] * Called by _al_xwin_mouse_button_press_handler() if the ButtonPress event * received from the X server is actually for a mouse wheel movement. */ static void wheel_motion_handler(int x_button, ALLEGRO_DISPLAY *display) { int dz = 0, dw = 0; if (x_button == Button4) dz = 1; if (x_button == Button5) dz = -1; if (x_button == 6) dw = -1; if (x_button == 7) dw = 1; if (dz == 0 && dw == 0) return; dz *= al_get_mouse_wheel_precision(); dw *= al_get_mouse_wheel_precision(); _al_event_source_lock(&the_mouse.parent.es); { the_mouse.state.z += dz; the_mouse.state.w += dw; generate_mouse_event( ALLEGRO_EVENT_MOUSE_AXES, the_mouse.state.x, the_mouse.state.y, the_mouse.state.z, the_mouse.state.w, the_mouse.state.pressure, 0, 0, dz, dw, 0, display); } _al_event_source_unlock(&the_mouse.parent.es); } /* _al_xwin_mouse_button_release_handler: [bgman thread] * Called by _xwin_process_event() for ButtonRelease events received from the * X server. */ void _al_xwin_mouse_button_release_handler(int x_button, ALLEGRO_DISPLAY *display) { int al_button; if (!xmouse_installed) return; al_button = x_button_to_al_button(x_button); if (al_button == 0) return; _al_event_source_lock(&the_mouse.parent.es); { the_mouse.state.buttons &=~ (1 << (al_button - 1)); the_mouse.state.pressure = the_mouse.state.buttons ? 1.0 : 0.0; /* TODO */ generate_mouse_event( ALLEGRO_EVENT_MOUSE_BUTTON_UP, the_mouse.state.x, the_mouse.state.y, the_mouse.state.z, the_mouse.state.w, the_mouse.state.pressure, 0, 0, 0, 0, al_button, display); } _al_event_source_unlock(&the_mouse.parent.es); } /* _al_xwin_mouse_motion_notify_handler: [bgman thread] * Called by _xwin_process_event() for MotionNotify events received from the X * server. */ void _al_xwin_mouse_motion_notify_handler(int x, int y, ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_XGLX *glx = (void *)display; int event_type = ALLEGRO_EVENT_MOUSE_AXES; if (!xmouse_installed) return; /* Is this an event generated in response to al_set_mouse_xy? */ if (glx->mouse_warp) { glx->mouse_warp = false; event_type = ALLEGRO_EVENT_MOUSE_WARPED; } _al_event_source_lock(&the_mouse.parent.es); #ifdef ALLEGRO_RASPBERRYPI float scale_x, scale_y; _al_raspberrypi_get_mouse_scale_ratios(&scale_x, &scale_y); x *= scale_x; y *= scale_y; #endif int dx = x - the_mouse.state.x; int dy = y - the_mouse.state.y; the_mouse.state.x = x; the_mouse.state.y = y; the_mouse.state.display = display; generate_mouse_event( event_type, the_mouse.state.x, the_mouse.state.y, the_mouse.state.z, the_mouse.state.w, the_mouse.state.pressure, dx, dy, 0, 0, 0, display); _al_event_source_unlock(&the_mouse.parent.es); } /* x_button_to_al_button: [bgman thread] * Map a X button number to an Allegro button number. */ static unsigned int x_button_to_al_button(unsigned int x_button) { switch (x_button) { case Button1: return 1; case Button2: return 3; case Button3: return 2; case Button4: case Button5: case 6: case 7: // hardcoded for z and w wheel return 0; default: if (x_button >= 8 && x_button <= 36) { return 4 + x_button - 8; } return 0; } } /* generate_mouse_event: [bgman thread] * Helper to generate a mouse event. */ static void generate_mouse_event(unsigned int type, int x, int y, int z, int w, float pressure, int dx, int dy, int dz, int dw, unsigned int button, ALLEGRO_DISPLAY *display) { ALLEGRO_EVENT event; if (!_al_event_source_needs_to_generate_event(&the_mouse.parent.es)) return; event.mouse.type = type; event.mouse.timestamp = al_get_time(); event.mouse.display = display; event.mouse.x = x; event.mouse.y = y; event.mouse.z = z; event.mouse.w = w; event.mouse.dx = dx; event.mouse.dy = dy; event.mouse.dz = dz; event.mouse.dw = dw; event.mouse.button = button; event.mouse.pressure = pressure; _al_event_source_emit_event(&the_mouse.parent.es, &event); } /* _al_xwin_mouse_switch_handler: * Handle a focus switch event. */ void _al_xwin_mouse_switch_handler(ALLEGRO_DISPLAY *display, const XCrossingEvent *event) { int event_type; /* Ignore events where any of the buttons are held down. */ if (event->state & (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask)) { return; } _al_event_source_lock(&the_mouse.parent.es); switch (event->type) { case EnterNotify: the_mouse.state.display = display; the_mouse.state.x = event->x; the_mouse.state.y = event->y; event_type = ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY; break; case LeaveNotify: the_mouse.state.display = NULL; the_mouse.state.x = event->x; the_mouse.state.y = event->y; event_type = ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY; break; default: ASSERT(false); event_type = 0; break; } generate_mouse_event( event_type, the_mouse.state.x, the_mouse.state.y, the_mouse.state.z, the_mouse.state.pressure, the_mouse.state.w, 0, 0, 0, 0, 0, display); _al_event_source_unlock(&the_mouse.parent.es); } bool _al_xwin_grab_mouse(ALLEGRO_DISPLAY *display) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; int grab; bool ret; _al_mutex_lock(&system->lock); grab = XGrabPointer(system->x11display, glx->window, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, glx->window, None, CurrentTime); if (grab == GrabSuccess) { system->mouse_grab_display = display; ret = true; } else { ret = false; } _al_mutex_unlock(&system->lock); return ret; } bool _al_xwin_ungrab_mouse(void) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); _al_mutex_lock(&system->lock); XUngrabPointer(system->x11display, CurrentTime); system->mouse_grab_display = NULL; _al_mutex_unlock(&system->lock); return true; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/x/xrandr.c000066400000000000000000000714721473414355200161730ustar00rootroot00000000000000#include "allegro5/allegro.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xfullscreen.h" #include "allegro5/internal/aintern_xsystem.h" #ifdef ALLEGRO_XWINDOWS_WITH_XRANDR ALLEGRO_DEBUG_CHANNEL("xrandr") typedef struct xrandr_screen xrandr_screen; typedef struct xrandr_crtc xrandr_crtc; typedef struct xrandr_output xrandr_output; typedef struct xrandr_mode xrandr_mode; struct xrandr_screen { int id; Time timestamp; Time configTimestamp; _AL_VECTOR crtcs; // xrandr_crtc _AL_VECTOR outputs; // xrandr_output _AL_VECTOR modes; // xrandr_mode XRRScreenResources *res; }; enum xrandr_crtc_position { CRTC_POS_NONE = 0, CRTC_POS_ABOVE, CRTC_POS_LEFTOF, CRTC_POS_BELOW, CRTC_POS_RIGHTOF }; struct xrandr_crtc { RRCrtc id; Time timestamp; int x, y; unsigned int width, height; RRMode mode; Rotation rotation; _AL_VECTOR connected; _AL_VECTOR possible; RRMode original_mode; int original_xoff; int original_yoff; RRCrtc align_to; int align; }; struct xrandr_output { RROutput id; Time timestamp; RRCrtc crtc; char *name; int namelen; unsigned long mm_width; unsigned long mm_height; Connection connection; SubpixelOrder subpixel_order; _AL_VECTOR crtcs; // RRCrtc _AL_VECTOR clones; // RROutput RRMode prefered_mode; _AL_VECTOR modes; // RRMode }; struct xrandr_mode { RRMode id; unsigned int width; unsigned int height; unsigned int refresh; }; struct xrandr_rect { int x1; int y1; int x2; int y2; }; static void xrandr_copy_mode(xrandr_mode *mode, XRRModeInfo *rrmode) { mode->id = rrmode->id; mode->width = rrmode->width; mode->height = rrmode->height; if (rrmode->hTotal && rrmode->vTotal) { mode->refresh = ((float) rrmode->dotClock / ((float) rrmode->hTotal * (float) rrmode->vTotal)); } else { mode->refresh = 0; } } static void xrandr_clear_fake_refresh_rates(xrandr_mode *modes, int nmode) { int i; if (nmode < 2) return; /* The Nvidia proprietary driver may return fake refresh rates when * DynamicTwinView is enabled, so that all modes are unique. The user has * no use for that wrong information so zero it out if we detect it. */ for (i = 1; i < nmode; i++) { if (modes[i].refresh != modes[i-1].refresh + 1) { return; } } ALLEGRO_WARN("Zeroing out fake refresh rates from nvidia proprietary driver.\n"); ALLEGRO_WARN("Disable the DynamicTwinView driver option to avoid this.\n"); for (i = 0; i < nmode; i++) { modes[i].refresh = 0; } } static void xrandr_copy_output(xrandr_output *output, RROutput id, XRROutputInfo *rroutput) { output->id = id; output->timestamp = rroutput->timestamp; output->crtc = rroutput->crtc; output->name = strdup(rroutput->name); output->namelen = rroutput->nameLen; output->mm_width = rroutput->mm_width; output->mm_height = rroutput->mm_height; output->connection = rroutput->connection; output->subpixel_order = rroutput->subpixel_order; ALLEGRO_DEBUG("output[%s] %s on crtc %i.\n", output->name, output->connection == RR_Connected ? "Connected" : "Not Connected", (int)output->crtc); _al_vector_init(&output->crtcs, sizeof(RRCrtc)); if(rroutput->ncrtc) { _al_vector_append_array(&output->crtcs, rroutput->ncrtc, rroutput->crtcs); } _al_vector_init(&output->clones, sizeof(RROutput)); if(rroutput->nclone) { _al_vector_append_array(&output->clones, rroutput->nclone, rroutput->clones); } _al_vector_init(&output->modes, sizeof(RRMode)); if(rroutput->nmode) { _al_vector_append_array(&output->modes, rroutput->nmode, rroutput->modes); } /* npreferred isn't the prefered mode index, it's the number of prefered modes * starting from 0. So just load up the first prefered mode. * We don't actually use it yet anyway, so it's not really important. */ if(rroutput->npreferred) { output->prefered_mode = rroutput->modes[0]; } } static void xrandr_copy_crtc(xrandr_crtc *crtc, RRCrtc id, XRRCrtcInfo *rrcrtc) { crtc->id = id; crtc->timestamp = rrcrtc->timestamp; crtc->x = rrcrtc->x; crtc->y = rrcrtc->y; crtc->width = rrcrtc->width; crtc->height = rrcrtc->height; crtc->mode = rrcrtc->mode; crtc->rotation = rrcrtc->rotation; _al_vector_init(&crtc->connected, sizeof(RROutput)); if(rrcrtc->noutput) { _al_vector_append_array(&crtc->connected, rrcrtc->noutput, rrcrtc->outputs); } ALLEGRO_DEBUG("found %i outputs.\n", rrcrtc->noutput); _al_vector_init(&crtc->possible, sizeof(RROutput)); if(rrcrtc->npossible) { _al_vector_append_array(&crtc->possible, rrcrtc->npossible, rrcrtc->possible); int i; for(i = 0; i < rrcrtc->npossible; i++) { ALLEGRO_DEBUG("output[%i] %i.\n", i, (int)rrcrtc->possible[i]); } } crtc->original_mode = crtc->mode; crtc->original_xoff = crtc->x; crtc->original_yoff = crtc->y; crtc->align_to = 0; crtc->align = CRTC_POS_NONE; } static void xrandr_copy_screen(ALLEGRO_SYSTEM_XGLX *s, xrandr_screen *screen, XRRScreenResources *res) { int j; _al_vector_init(&screen->modes, sizeof(xrandr_mode)); if(res->nmode) { for(j = 0; j < res->nmode; j++) { xrandr_mode *mode = _al_vector_alloc_back(&screen->modes); xrandr_copy_mode(mode, &res->modes[j]); } xrandr_clear_fake_refresh_rates(_al_vector_ref_front(&screen->modes), res->nmode); } _al_vector_init(&screen->crtcs, sizeof(xrandr_crtc)); if(res->ncrtc) { ALLEGRO_DEBUG("found %i crtcs.\n", res->ncrtc); for(j = 0; j < res->ncrtc; j++) { ALLEGRO_DEBUG("crtc[%i] %i.\n", j, (int)res->crtcs[j]); xrandr_crtc *crtc = _al_vector_alloc_back(&screen->crtcs); XRRCrtcInfo *rrcrtc = XRRGetCrtcInfo(s->x11display, res, res->crtcs[j]); xrandr_copy_crtc(crtc, res->crtcs[j], rrcrtc); XRRFreeCrtcInfo(rrcrtc); } } _al_vector_init(&screen->outputs, sizeof(xrandr_output)); if(res->noutput) { ALLEGRO_DEBUG("found %i outputs.\n", res->noutput); for(j = 0; j < res->noutput; j++) { ALLEGRO_DEBUG("output[%i] %i.\n", j, (int)res->outputs[j]); xrandr_output *output = _al_vector_alloc_back(&screen->outputs); XRROutputInfo *rroutput = XRRGetOutputInfo(s->x11display, res, res->outputs[j]); xrandr_copy_output(output, res->outputs[j], rroutput); XRRFreeOutputInfo(rroutput); XSync(s->x11display, False); } } } static xrandr_crtc *xrandr_fetch_crtc(ALLEGRO_SYSTEM_XGLX *s, int sid, RRCrtc id) { unsigned int i; xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, sid); for(i = 0; i < _al_vector_size(&screen->crtcs); i++) { xrandr_crtc *crtc = _al_vector_ref(&screen->crtcs, i); if(crtc->id == id) return crtc; } return NULL; } static xrandr_output *xrandr_fetch_output(ALLEGRO_SYSTEM_XGLX *s, int sid, RROutput id) { unsigned int i; xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, sid); for(i = 0; i < _al_vector_size(&screen->outputs); i++) { xrandr_output *output = _al_vector_ref(&screen->outputs, i); if(output->id == id) return output; } return NULL; } static xrandr_mode *xrandr_fetch_mode(ALLEGRO_SYSTEM_XGLX *s, int sid, RRMode id) { unsigned int i; xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, sid); for(i = 0; i < _al_vector_size(&screen->modes); i++) { xrandr_mode *mode = _al_vector_ref(&screen->modes, i); if(mode->id == id) return mode; } return NULL; } static inline xrandr_crtc *xrandr_map_to_crtc(ALLEGRO_SYSTEM_XGLX *s, int sid, int adapter) { return xrandr_fetch_crtc(s, sid, *(RRCrtc*)_al_vector_ref(&s->xrandr_adaptermap, adapter)); } static inline xrandr_output *xrandr_map_adapter(ALLEGRO_SYSTEM_XGLX *s, int sid, int adapter) { xrandr_crtc *crtc = xrandr_map_to_crtc(s, sid, adapter); return xrandr_fetch_output(s, sid, *(RROutput*)_al_vector_ref(&crtc->connected, 0)); } static void xrandr_combine_output_rect(struct xrandr_rect *rect, xrandr_crtc *crtc) { if(rect->x1 > crtc->x) rect->x1 = crtc->x; if(rect->y1 > crtc->y) rect->y1 = crtc->y; if(crtc->x + (int)crtc->width > rect->x2) rect->x2 = crtc->x + crtc->width; if(crtc->y + (int)crtc->height > rect->y2) rect->y2 = crtc->y + crtc->height; } /* begin vtable methods */ static int xrandr_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter); static bool xrandr_query(ALLEGRO_SYSTEM_XGLX *s) { int screen_count = ScreenCount(s->x11display); int i; bool ret = true; _al_vector_init(&s->xrandr_screens, sizeof(xrandr_screen)); _al_vector_init(&s->xrandr_adaptermap, sizeof(RROutput)); for(i = 0; i < screen_count; i++) { xrandr_screen *screen = _al_vector_alloc_back(&s->xrandr_screens); XRRScreenResources *res = XRRGetScreenResources(s->x11display, XRootWindow(s->x11display, i)); if(!res) { ALLEGRO_DEBUG("failed to get screen resources for screen %i\n", i); continue; } if(!res->noutput) { ALLEGRO_DEBUG("screen %i doesn't have any outputs.\n", i); continue; } xrandr_copy_screen(s, screen, res); screen->res = res; /* Detect clones */ int j; for(j = 0; j < (int)_al_vector_size(&screen->crtcs); j++) { xrandr_crtc *crtc = _al_vector_ref(&screen->crtcs, j); /* Skip crtc with no connected outputs. */ if(_al_vector_size(&crtc->connected) < 1) continue; // XXX it might be nessesary to do something more clever about detecting clones // XXX for now I'm going with a plain origin test, it aught to work for most cases. // the other alternative is to check the crtc's connected outputs's clone's list... // sounds like pain to me. int k; bool not_clone = true; for(k = 0; k < j; k++) { xrandr_crtc *crtc_k = _al_vector_ref(&screen->crtcs, k); /* Skip crtc with no connected outputs. */ if(_al_vector_size(&crtc_k->connected) < 1) continue; if(crtc->x == crtc_k->x && crtc->y == crtc_k->y) not_clone = false; } if(not_clone) { RRCrtc *crtc_ptr = _al_vector_alloc_back(&s->xrandr_adaptermap); ALLEGRO_DEBUG("Map Allegro Adadpter %i to RandR CRTC %i.\n", (int)(_al_vector_size(&s->xrandr_adaptermap)-1), (int)crtc->id); *crtc_ptr = crtc->id; } else { ALLEGRO_DEBUG("RandR CRTC %i is a clone, ignoring.\n", (int)crtc->id); } } int mask = RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RROutputPropertyNotifyMask; XRRSelectInput( s->x11display, RootWindow(s->x11display, i), 0); XRRSelectInput( s->x11display, RootWindow(s->x11display, i), mask); } /* map out crtc positions and alignments */ /* this code makes Adapter 0 the root display, everything will hang off it */ for(i = 1; i < (int)_al_vector_size(&s->xrandr_adaptermap); i++) { int xscreen = xrandr_get_xscreen(s, i); xrandr_crtc *crtc = xrandr_fetch_crtc(s, xscreen, *(RRCrtc*)_al_vector_ref(&s->xrandr_adaptermap, i)); int j; for(j = 0; j < (int)_al_vector_size(&s->xrandr_adaptermap); j++) { int xscreen_j = xrandr_get_xscreen(s, j); xrandr_crtc *crtc_j = xrandr_fetch_crtc(s, xscreen_j, *(RRCrtc*)_al_vector_ref(&s->xrandr_adaptermap, j)); if(crtc->x == crtc_j->x + (int)crtc_j->width) { crtc->align_to = crtc_j->id; crtc->align = CRTC_POS_RIGHTOF; ALLEGRO_DEBUG("Adapter %i is RightOf Adapter %i.\n", i, j); } else if(crtc->x + (int)crtc->width == crtc_j->x) { crtc->align_to = crtc_j->id; crtc->align = CRTC_POS_LEFTOF; ALLEGRO_DEBUG("Adapter %i is LeftOf Adapter %i.\n", i, j); } else if(crtc->y == crtc_j->y + (int)crtc_j->height) { crtc->align_to = crtc_j->id; crtc->align = CRTC_POS_BELOW; ALLEGRO_DEBUG("Adapter %i is Below Adapter %i.\n", i, j); } else if(crtc->y + (int)crtc->height == crtc_j->y) { crtc->align_to = crtc_j->id; crtc->align = CRTC_POS_ABOVE; ALLEGRO_DEBUG("Adapter %i is Above Adapter %i.\n", i, j); } } } #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA if (s->xinerama_available && s->xinerama_screen_count != (int)_al_vector_size(&s->xrandr_adaptermap)) { ALLEGRO_WARN("XRandR and Xinerama seem to disagree on how many screens there are (%i vs %i), going to ignore XRandR.\n", (int)_al_vector_size(&s->xrandr_adaptermap), s->xinerama_screen_count); // only actually going to ignore the output count, and setting of modes on the extra xinerama screens. ret = false; } #endif return ret; } static int xrandr_get_num_modes(ALLEGRO_SYSTEM_XGLX *s, int adapter) { if(adapter < 0 || adapter >= (int)_al_vector_size(&s->xrandr_adaptermap)) return 0; int xscreen = _al_xglx_get_xscreen(s, adapter); xrandr_output *output = xrandr_map_adapter(s, xscreen, adapter); return _al_vector_size(&output->modes); } static ALLEGRO_DISPLAY_MODE *xrandr_get_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter, int id, ALLEGRO_DISPLAY_MODE *amode) { int xscreen = _al_xglx_get_xscreen(s, adapter); xrandr_output *output = xrandr_map_adapter(s, xscreen, adapter); if(id < 0 || id > (int)_al_vector_size(&output->modes)) return NULL; xrandr_mode *mode = xrandr_fetch_mode(s, xscreen, *(RRMode*)_al_vector_ref(&output->modes, id)); amode->width = mode->width; amode->height = mode->height; amode->format = 0; amode->refresh_rate = mode->refresh; return amode; } static bool xrandr_realign_crtc_origin(ALLEGRO_SYSTEM_XGLX *s, int xscreen, xrandr_crtc *crtc, int new_w, int new_h, int *x, int *y) { bool ret; if(crtc->align_to == 0) return false; xrandr_crtc *align_to = xrandr_fetch_crtc(s, xscreen, crtc->align_to); switch(crtc->align) { case CRTC_POS_RIGHTOF: *x = align_to->x + align_to->width; *y = align_to->y; ret = true; break; case CRTC_POS_LEFTOF: *x = align_to->x - new_w; *y = align_to->y; ret = true; break; case CRTC_POS_BELOW: *x = align_to->x; *y = align_to->y + align_to->height; ret = true; break; case CRTC_POS_ABOVE: *x = align_to->x; *y = align_to->y - new_h; ret = true; break; default: ALLEGRO_WARN("unknown crtc alignment flag (%i)!", crtc->align); ret = false; break; } return ret; } static bool xrandr_set_mode(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, int w, int h, int format, int refresh) { int adapter = _al_xglx_get_adapter(s, d, false); int xscreen = _al_xglx_get_xscreen(s, adapter); xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, xscreen); xrandr_crtc *crtc = xrandr_map_to_crtc(s, xscreen, adapter); xrandr_mode *cur_mode = xrandr_fetch_mode(s, xscreen, crtc->mode); if((int)cur_mode->width == w && (int)cur_mode->height == h && (refresh == 0 || refresh == (int)cur_mode->refresh)) { ALLEGRO_DEBUG("mode already set, good to go\n"); return true; } else { ALLEGRO_DEBUG("new mode: %dx%d@%d old mode: %dx%d@%d.\n", w, h, refresh, cur_mode->width, cur_mode->height, cur_mode->refresh); } int mode_idx = _al_xglx_fullscreen_select_mode(s, adapter, w, h, format, refresh); if(mode_idx == -1) { ALLEGRO_DEBUG("mode %dx%d@%d not found\n", w, h, refresh); return false; } xrandr_output *output = xrandr_fetch_output(s, xscreen, *(RROutput*)_al_vector_ref(&crtc->connected, 0)); xrandr_mode *mode = xrandr_fetch_mode(s, xscreen, *(RRMode*)_al_vector_ref(&output->modes, mode_idx)); int new_x = crtc->x, new_y = crtc->y; xrandr_realign_crtc_origin(s, xscreen, crtc, w, h, &new_x, &new_y); ALLEGRO_DEBUG("xrandr: set mode %i+%i-%ix%i on adapter %i\n", new_x, new_y, w, h, adapter); _al_mutex_lock(&s->lock); int ok = XRRSetCrtcConfig( s->x11display, screen->res, crtc->id, crtc->timestamp, new_x, new_y, mode->id, crtc->rotation, _al_vector_ref_front(&crtc->connected), _al_vector_size(&crtc->connected) ); if (ok != RRSetConfigSuccess) { ALLEGRO_ERROR("XRandR failed to set mode.\n"); _al_mutex_unlock(&s->lock); return false; } /* make sure the virtual screen size is large enough after setting our mode */ int i; struct xrandr_rect rect = { 0, 0, 0, 0 }; for(i = 0; i < (int)_al_vector_size(&screen->crtcs); i++) { xrandr_crtc *c = _al_vector_ref(&screen->crtcs, i); if(_al_vector_size(&c->connected) > 0) { xrandr_combine_output_rect(&rect, crtc); } } int new_width = rect.x2 - rect.x1; int new_height = rect.y2 - rect.y1; if(new_width > DisplayWidth(s->x11display, xscreen) || new_height > DisplayHeight(s->x11display, xscreen)) { XRRSetScreenSize(s->x11display, RootWindow(s->x11display, xscreen), new_width, new_height, DisplayWidthMM(s->x11display, xscreen), DisplayHeightMM(s->x11display, xscreen)); } _al_mutex_unlock(&s->lock); return true; } static void xrandr_restore_mode(ALLEGRO_SYSTEM_XGLX *s, int adapter) { int xscreen = _al_xglx_get_xscreen(s, adapter); xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, xscreen); xrandr_crtc *crtc = xrandr_map_to_crtc(s, xscreen, adapter); if(crtc->mode == crtc->original_mode) { ALLEGRO_DEBUG("current crtc mode (%i) equals the original mode (%i), not restoring.\n", (int)crtc->mode, (int)crtc->original_mode); return; } xrandr_mode *orig_mode = xrandr_fetch_mode(s, xscreen, crtc->original_mode); ALLEGRO_DEBUG("restore mode %i+%i-%ix%i@%i on adapter %i\n", crtc->original_xoff, crtc->original_yoff, orig_mode->width, orig_mode->height, orig_mode->refresh, adapter); _al_mutex_lock(&s->lock); int ok = XRRSetCrtcConfig ( s->x11display, screen->res, crtc->id, crtc->timestamp, crtc->original_xoff, crtc->original_yoff, orig_mode->id, crtc->rotation, _al_vector_ref_front(&crtc->connected), _al_vector_size(&crtc->connected) ); if(ok != RRSetConfigSuccess) { ALLEGRO_ERROR("failed to restore mode.\n"); } // XSync(s->x11display, False); _al_mutex_unlock(&s->lock); } static void xrandr_get_display_offset(ALLEGRO_SYSTEM_XGLX *s, int adapter, int *x, int *y) { int xscreen = _al_xglx_get_xscreen(s, adapter); xrandr_crtc *crtc = xrandr_map_to_crtc(s, xscreen, adapter); // XXX Should we always return original_[xy]off here? // When does a user want to query the offset after the modes are set? *x = crtc->x; *y = crtc->y; ALLEGRO_DEBUG("display offset: %ix%i.\n", *x, *y); } static int xrandr_get_num_adapters(ALLEGRO_SYSTEM_XGLX *s) { return _al_vector_size(&s->xrandr_adaptermap); } static bool xrandr_get_monitor_info(ALLEGRO_SYSTEM_XGLX *s, int adapter, ALLEGRO_MONITOR_INFO *mi) { if(adapter < 0 || adapter >= (int)_al_vector_size(&s->xrandr_adaptermap)) return false; int xscreen = _al_xglx_get_xscreen(s, adapter); xrandr_output *output = xrandr_map_adapter(s, xscreen, adapter); xrandr_crtc *crtc = xrandr_fetch_crtc(s, xscreen, output->crtc); mi->x1 = crtc->x; mi->y1 = crtc->y; mi->x2 = crtc->x + crtc->width; mi->y2 = crtc->y + crtc->height; return true; } static int xrandr_get_default_adapter(ALLEGRO_SYSTEM_XGLX *s) { // if we have more than one xrandr_screen, we're in multi-head x mode if(_al_vector_size(&s->xrandr_screens) > 1) return _al_xsys_mheadx_get_default_adapter(s); int center_x = 0, center_y = 0; _al_xsys_get_active_window_center(s, ¢er_x, ¢er_y); int i, default_adapter = 0; for(i = 0; i < (int)_al_vector_size(&s->xrandr_adaptermap); i++) { xrandr_crtc *crtc = xrandr_map_to_crtc(s, 0, i); if(center_x >= (int)crtc->x && center_x <= (int)(crtc->x + crtc->width) && center_y >= (int)crtc->y && center_y <= (int)(crtc->y + crtc->height)) { default_adapter = i; break; } } ALLEGRO_DEBUG("selected default adapter: %i.\n", default_adapter); return default_adapter; } static int xrandr_get_xscreen(ALLEGRO_SYSTEM_XGLX *s, int adapter) { // more than one screen means we have multi-head x mode if(_al_vector_size(&s->xrandr_screens) > 1) return _al_xsys_mheadx_get_xscreen(s, adapter); // Normal XRandR will normally give us one X screen, so return 0 always. return 0; } static void xrandr_handle_xevent(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, XEvent *e) { if(e->type == s->xrandr_event_base + RRNotify) { XRRNotifyEvent *rre = (XRRNotifyEvent*)e; if(rre->subtype == RRNotify_CrtcChange) { XRRCrtcChangeNotifyEvent *rrce = (XRRCrtcChangeNotifyEvent*)rre; ALLEGRO_DEBUG("RRNotify_CrtcChange!\n"); xrandr_crtc *crtc = xrandr_fetch_crtc(s, d->xscreen, rrce->crtc); if(!crtc) { ALLEGRO_DEBUG("invalid RRCrtc(%i).\n", (int)rrce->crtc); return; } if(rrce->mode != crtc->mode) { ALLEGRO_DEBUG("mode changed from %i to %i.\n", (int)crtc->mode, (int)rrce->mode); crtc->mode = rrce->mode; } if(rrce->rotation != crtc->rotation) { ALLEGRO_DEBUG("rotation changed from %i to %i.\n", crtc->rotation, rrce->rotation); crtc->rotation = rrce->rotation; } if(rrce->x != crtc->x || rrce->y != crtc->y) { ALLEGRO_DEBUG("origin changed from %i+%i to %i+%i.\n", crtc->x, crtc->y, rrce->x, rrce->y); crtc->x = rrce->x; crtc->y = rrce->y; } if(rrce->width != crtc->width || rrce->height != crtc->height) { ALLEGRO_DEBUG("size changed from %ix%i to %ix%i.\n", crtc->width, crtc->height, rrce->width, rrce->height); crtc->width = rrce->width; crtc->height = rrce->height; } xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, d->xscreen); crtc->timestamp = screen->timestamp; } else if(rre->subtype == RRNotify_OutputChange) { XRROutputChangeNotifyEvent *rroe = (XRROutputChangeNotifyEvent*)rre; xrandr_output *output = xrandr_fetch_output(s, d->xscreen, rroe->output); if(!output) { ALLEGRO_DEBUG("invalid RROutput(%i).\n", (int)rroe->output); return; } ALLEGRO_DEBUG("xrandr: RRNotify_OutputChange %s!\n", output->name); if(rroe->crtc != output->crtc) { ALLEGRO_DEBUG("crtc changed from %i to %i.\n", (int)output->crtc, (int)rroe->crtc); output->crtc = rroe->crtc; } // XXX I'm not sure how monitor connections are handled here, // that is, what happens when a monitor is connected, and disconnected... // IE: CHECK! if(rroe->connection != output->connection) { ALLEGRO_DEBUG("connection changed from %i to %i.\n", output->connection, rroe->connection); output->connection = rroe->connection; } xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, d->xscreen); output->timestamp = screen->timestamp; } else if(rre->subtype == RRNotify_OutputProperty) { ALLEGRO_DEBUG("xrandr: RRNotify_OutputProperty!\n"); } else { ALLEGRO_DEBUG("xrandr: RRNotify_Unknown(%i)!\n", rre->subtype); } } else if(e->type == s->xrandr_event_base + RRScreenChangeNotify) { XRRScreenChangeNotifyEvent *rre = (XRRScreenChangeNotifyEvent*)e; XRRUpdateConfiguration( e ); ALLEGRO_DEBUG("RRScreenChangeNotify!\n"); /* XXX I don't think we need to actually handle this event fully, * it only really deals with the virtual screen as a whole it seems * The interesting changes get sent with the RRNotify event. */ /* update the timestamps */ xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, d->xscreen); screen->timestamp = rre->timestamp; screen->configTimestamp = rre->config_timestamp; } } /* begin "public" ctor/dtor methods */ void _al_xsys_xrandr_init(ALLEGRO_SYSTEM_XGLX *s) { int error_base = 0; _al_mutex_lock(&s->lock); if (XRRQueryExtension(s->x11display, &s->xrandr_event_base, &error_base)) { int minor_version = 0, major_version = 0; int status = XRRQueryVersion(s->x11display, &major_version, &minor_version); ALLEGRO_INFO("XRandR version: %i.%i\n", major_version, minor_version); if (!status) { ALLEGRO_WARN("XRandR not available, XRRQueryVersion failed.\n"); } else if (major_version == 1 && minor_version < 2) { /* this is unlikely to happen, unless the user has an ancient Xorg, Xorg will just emulate the latest version and return that instead of what the driver actually supports, stupid. */ ALLEGRO_WARN("XRandR not available, unsupported version: %i.%i\n", major_version, minor_version); } else { bool ret = xrandr_query(s); if (ret) { ALLEGRO_INFO("XRandR is active\n"); s->xrandr_available = 1; } else { ALLEGRO_INFO("XRandR is not active\n"); } } } else { ALLEGRO_WARN("XRandR extension is not available.\n"); } if (s->xrandr_available) { memset(&_al_xglx_mmon_interface, 0, sizeof(_al_xglx_mmon_interface)); _al_xglx_mmon_interface.get_num_display_modes = xrandr_get_num_modes; _al_xglx_mmon_interface.get_display_mode = xrandr_get_mode; _al_xglx_mmon_interface.set_mode = xrandr_set_mode; _al_xglx_mmon_interface.restore_mode = xrandr_restore_mode; _al_xglx_mmon_interface.get_display_offset = xrandr_get_display_offset; _al_xglx_mmon_interface.get_num_adapters = xrandr_get_num_adapters; _al_xglx_mmon_interface.get_monitor_info = xrandr_get_monitor_info; _al_xglx_mmon_interface.get_default_adapter = xrandr_get_default_adapter; _al_xglx_mmon_interface.get_xscreen = xrandr_get_xscreen; _al_xglx_mmon_interface.handle_xevent = xrandr_handle_xevent; } _al_mutex_unlock(&s->lock); } void _al_xsys_xrandr_exit(ALLEGRO_SYSTEM_XGLX *s) { #if 0 // int i; ALLEGRO_DEBUG("XRandR exiting.\n"); // for (i = 0; i < s->xrandr_output_count; i++) { // XRRFreeOutputInfo(s->xrandr_outputs[i]); // } // for (i = 0; i < s->xrandr_res_count; i++) { // XRRFreeScreenResources(s->xrandr_res[i]); // } ALLEGRO_DEBUG("XRRFreeScreenResources\n"); //if (s->xrandr_res) // XRRFreeScreenResources(s->xrandr_res); al_free(s->xrandr_outputs); al_free(s->xrandr_res); s->xrandr_available = 0; s->xrandr_res_count = 0; s->xrandr_res = NULL; s->xrandr_output_count = 0; s->xrandr_outputs = NULL; ALLEGRO_DEBUG("XRandR exit finished.\n"); #endif /* 0 */ int i; for(i = 0; i < (int)_al_vector_size(&s->xrandr_screens); i++) { xrandr_screen *screen = _al_vector_ref(&s->xrandr_screens, i); int j; for (j = 0; j < (int)_al_vector_size(&screen->crtcs); j++) { xrandr_crtc *crtc = _al_vector_ref(&screen->crtcs, j); _al_vector_free(&crtc->connected); _al_vector_free(&crtc->possible); } for(j = 0; j < (int)_al_vector_size(&screen->outputs); j++) { xrandr_output *output = _al_vector_ref(&screen->outputs, j); free(output->name); _al_vector_free(&output->crtcs); _al_vector_free(&output->clones); _al_vector_free(&output->modes); } _al_vector_free(&screen->crtcs); _al_vector_free(&screen->outputs); _al_vector_free(&screen->modes); XRRFreeScreenResources(screen->res); screen->res = NULL; } _al_vector_free(&s->xrandr_screens); _al_vector_free(&s->xrandr_adaptermap); } #endif /* ALLEGRO_XWINDOWS_WITH_XRANDR */ /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/x/xsystem.c000066400000000000000000000237721473414355200164110ustar00rootroot00000000000000#ifdef DEBUG_X11 extern int _Xdebug; /* part of Xlib */ #endif #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_bitmap.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xcursor.h" #include "allegro5/internal/aintern_xembed.h" #include "allegro5/internal/aintern_xevents.h" #include "allegro5/internal/aintern_xfullscreen.h" #include "allegro5/internal/aintern_xkeyboard.h" #include "allegro5/internal/aintern_xmouse.h" #include "allegro5/internal/aintern_xsystem.h" #include "allegro5/internal/aintern_xdnd.h" #include "allegro5/platform/aintunix.h" #include "allegro5/platform/aintxglx.h" #include "allegro5/allegro_x.h" #include "xicon.h" ALLEGRO_DEBUG_CHANNEL("system") static ALLEGRO_SYSTEM_INTERFACE *xglx_vt; ALLEGRO_BITMAP *_al_xwin_initial_icon = NULL; static bool xglx_inhibit_screensaver(bool inhibit); /* Function: al_x_set_initial_icon */ bool al_x_set_initial_icon(ALLEGRO_BITMAP *bitmap) { ALLEGRO_STATE state; al_store_state(&state, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); al_destroy_bitmap(_al_xwin_initial_icon); _al_xwin_initial_icon = al_clone_bitmap(bitmap); al_restore_state(&state); return true; } static ALLEGRO_SYSTEM *xglx_initialize(int flags) { Display *x11display; Display *gfxdisplay; ALLEGRO_SYSTEM_XGLX *s; (void)flags; #ifdef DEBUG_X11 _Xdebug = 1; #endif XInitThreads(); /* Get an X11 display handle. */ x11display = XOpenDisplay(0); if (x11display) { /* Never ask. */ gfxdisplay = XOpenDisplay(0); if (!gfxdisplay) { ALLEGRO_ERROR("XOpenDisplay failed second time.\n"); XCloseDisplay(x11display); return NULL; } } else { ALLEGRO_INFO("XOpenDisplay failed; assuming headless mode.\n"); gfxdisplay = NULL; } _al_unix_init_time(); s = al_calloc(1, sizeof *s); _al_mutex_init_recursive(&s->lock); _al_cond_init(&s->resized); s->inhibit_screensaver = false; s->screen_saver_query_available = false; _al_vector_init(&s->system.displays, sizeof (ALLEGRO_DISPLAY_XGLX *)); s->system.vt = xglx_vt; s->gfxdisplay = gfxdisplay; s->x11display = x11display; if (s->x11display) { ALLEGRO_INFO("XGLX driver connected to X11 (%s %d).\n", ServerVendor(s->x11display), VendorRelease(s->x11display)); ALLEGRO_INFO("X11 protocol version %d.%d.\n", ProtocolVersion(s->x11display), ProtocolRevision(s->x11display)); /* We need to put *some* atom into the ClientMessage we send for * faking mouse movements with al_set_mouse_xy - so let's ask X11 * for one here. */ s->AllegroAtom = XInternAtom(x11display, "AllegroAtom", False); /* Message type for XEmbed protocol. */ s->XEmbedAtom = XInternAtom(x11display, "_XEMBED", False); _al_display_xglx_init_dnd_atoms(s); _al_thread_create(&s->xevents_thread, _al_xwin_background_thread, s); s->have_xevents_thread = true; ALLEGRO_INFO("events thread spawned.\n"); } const char *binding = al_get_config_value(al_get_system_config(), "keyboard", "toggle_mouse_grab_key"); if (binding) { s->toggle_mouse_grab_keycode = _al_parse_key_binding(binding, &s->toggle_mouse_grab_modifiers); if (s->toggle_mouse_grab_keycode) { ALLEGRO_DEBUG("Toggle mouse grab key: '%s'\n", binding); } else { ALLEGRO_WARN("Cannot parse key binding '%s'\n", binding); } } return &s->system; } static void xglx_shutdown_system(void) { ALLEGRO_SYSTEM *s = al_get_system_driver(); ALLEGRO_SYSTEM_XGLX *sx = (void *)s; ALLEGRO_INFO("shutting down.\n"); if (sx->have_xevents_thread) { _al_thread_join(&sx->xevents_thread); sx->have_xevents_thread = false; } /* Close all open displays. */ while (_al_vector_size(&s->displays) > 0) { ALLEGRO_DISPLAY **dptr = _al_vector_ref(&s->displays, 0); ALLEGRO_DISPLAY *d = *dptr; al_destroy_display(d); } _al_vector_free(&s->displays); if (sx->inhibit_screensaver) { xglx_inhibit_screensaver(false); } // Makes sure we wait for any commands sent to the X server when destroying the displays. // Should make sure we don't shutdown before modes are restored. if (sx->x11display) { XSync(sx->x11display, False); } _al_xsys_mmon_exit(sx); if (sx->x11display) { XCloseDisplay(sx->x11display); sx->x11display = None; ALLEGRO_DEBUG("xsys: close x11display.\n"); } if (sx->gfxdisplay) { XCloseDisplay(sx->gfxdisplay); sx->gfxdisplay = None; } al_free(sx); } static ALLEGRO_DISPLAY_INTERFACE *xglx_get_display_driver(void) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); _al_mutex_lock(&system->lock); /* _al_display_xglx_driver has global state. */ ALLEGRO_DISPLAY_INTERFACE *driver = _al_display_xglx_driver(); _al_mutex_unlock(&system->lock); return driver; } static ALLEGRO_KEYBOARD_DRIVER *xglx_get_keyboard_driver(void) { return _al_xwin_keyboard_driver(); } static ALLEGRO_MOUSE_DRIVER *xglx_get_mouse_driver(void) { return _al_xwin_mouse_driver(); } static ALLEGRO_JOYSTICK_DRIVER *xglx_get_joystick_driver(void) { return _al_joystick_driver_list[0].driver; } static ALLEGRO_HAPTIC_DRIVER *xglx_get_haptic_driver(void) { return _al_haptic_driver_list[0].driver; } static ALLEGRO_TOUCH_INPUT_DRIVER *xglx_get_touch_driver(void) { return _al_touch_input_driver_list[0].driver; } static int xglx_get_num_video_adapters(void) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); return _al_xglx_get_num_video_adapters(system); } static bool xglx_get_monitor_info(int adapter, ALLEGRO_MONITOR_INFO *info) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); return _al_xglx_get_monitor_info(system, adapter, info); } static bool xglx_get_cursor_position(int *ret_x, int *ret_y) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); Window root = RootWindow(system->x11display, 0); Window child; int wx, wy; unsigned int mask; _al_mutex_lock(&system->lock); XQueryPointer(system->x11display, root, &root, &child, ret_x, ret_y, &wx, &wy, &mask); _al_mutex_unlock(&system->lock); return true; } static bool xglx_inhibit_screensaver(bool inhibit) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); int temp, version_min, version_max; #ifdef ALLEGRO_XWINDOWS_WITH_XSCREENSAVER if (!XScreenSaverQueryExtension(system->x11display, &temp, &temp) || !XScreenSaverQueryVersion(system->x11display, &version_max, &version_min) || version_max < 1 || (version_max == 1 && version_min < 1)) { system->screen_saver_query_available = false; } else { system->screen_saver_query_available = true; /* X11 maintains a counter on the number of identical calls to * XScreenSaverSuspend for a given display. So, only call it if 'inhibit' is * different to the previous invocation; otherwise we'd need to call it an * identical number of times with the negated value if there were a change. */ if (inhibit != system->inhibit_screensaver) { XScreenSaverSuspend(system->x11display, inhibit); } } #else (void)temp; (void)version_min; (void)version_max; #endif system->inhibit_screensaver = inhibit; return true; } static int xglx_get_num_display_modes(void) { int adapter = al_get_new_display_adapter(); ALLEGRO_SYSTEM_XGLX *s = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); return _al_xglx_get_num_display_modes(s, adapter); } static ALLEGRO_DISPLAY_MODE *xglx_get_display_mode(int mode, ALLEGRO_DISPLAY_MODE *dm) { int adapter = al_get_new_display_adapter(); ALLEGRO_SYSTEM_XGLX *s = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); return _al_xglx_get_display_mode(s, adapter, mode, dm); } static int xglx_get_monitor_dpi(int adapter) { ALLEGRO_MONITOR_INFO info; ALLEGRO_SYSTEM_XGLX *s = (void *)al_get_system_driver(); int x2_mm; int y2_mm; int dpi_hori; int dpi_vert; if(!_al_xglx_get_monitor_info(s, adapter, &info)) { return 0; } x2_mm = DisplayWidthMM(s->x11display, DefaultScreen(s->x11display)); y2_mm = DisplayHeightMM(s->x11display, DefaultScreen(s->x11display)); dpi_hori = (info.x2 - info.x1) / (_AL_INCHES_PER_MM * x2_mm); dpi_vert = (info.y2 - info.y1) / (_AL_INCHES_PER_MM * y2_mm); return sqrt(dpi_hori * dpi_vert); } /* Internal function to get a reference to this driver. */ ALLEGRO_SYSTEM_INTERFACE *_al_system_xglx_driver(void) { if (xglx_vt) return xglx_vt; xglx_vt = al_calloc(1, sizeof *xglx_vt); xglx_vt->id = ALLEGRO_SYSTEM_ID_XGLX; xglx_vt->initialize = xglx_initialize; xglx_vt->get_display_driver = xglx_get_display_driver; xglx_vt->get_keyboard_driver = xglx_get_keyboard_driver; xglx_vt->get_mouse_driver = xglx_get_mouse_driver; xglx_vt->get_joystick_driver = xglx_get_joystick_driver; xglx_vt->get_haptic_driver = xglx_get_haptic_driver; xglx_vt->get_touch_input_driver = xglx_get_touch_driver; xglx_vt->get_num_display_modes = xglx_get_num_display_modes; xglx_vt->get_display_mode = xglx_get_display_mode; xglx_vt->shutdown_system = xglx_shutdown_system; xglx_vt->get_num_video_adapters = xglx_get_num_video_adapters; xglx_vt->get_monitor_info = xglx_get_monitor_info; xglx_vt->get_monitor_dpi = xglx_get_monitor_dpi; xglx_vt->create_mouse_cursor = _al_xwin_create_mouse_cursor; xglx_vt->destroy_mouse_cursor = _al_xwin_destroy_mouse_cursor; xglx_vt->get_cursor_position = xglx_get_cursor_position; xglx_vt->grab_mouse = _al_xwin_grab_mouse; xglx_vt->ungrab_mouse = _al_xwin_ungrab_mouse; xglx_vt->get_path = _al_unix_get_path; xglx_vt->inhibit_screensaver = xglx_inhibit_screensaver; xglx_vt->get_time = _al_unix_get_time; xglx_vt->rest = _al_unix_rest; xglx_vt->init_timeout = _al_unix_init_timeout; return xglx_vt; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/src/x/xtouch.c000066400000000000000000000324161473414355200162020ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * X-Windows touch module. * * By Ryan Gumbs. * * See readme.txt for copyright information. */ #define ALLEGRO_NO_COMPATIBILITY #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_mouse.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xmouse.h" #include "allegro5/internal/aintern_xsystem.h" #include "allegro5/internal/aintern_xtouch.h" #ifdef ALLEGRO_XWINDOWS_WITH_XINPUT2 #include #include ALLEGRO_DEBUG_CHANNEL("touch") /* the one and only touch object */ static ALLEGRO_TOUCH_INPUT_STATE touch_input_state; static ALLEGRO_TOUCH_INPUT touch_input; static ALLEGRO_MOUSE_STATE mouse_state; static int touch_ids[ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT]; /* the XInput id for touches */ static int primary_touch_id = -1; static bool installed = false; static size_t initiali_time_stamp = ~0; static int opcode; static void reset_touch_input_state(void) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; i++) { touch_input_state.touches[i].id = -1; } } static void generate_touch_input_event(unsigned int type, double timestamp, int id, float x, float y, float dx, float dy, bool primary, ALLEGRO_DISPLAY *disp) { ALLEGRO_EVENT event; bool want_touch_event = _al_event_source_needs_to_generate_event(&touch_input.es); bool want_mouse_emulation_event; if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_5_0_x) { want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && al_is_mouse_installed(); } else { want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && primary && al_is_mouse_installed(); } if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_NONE) want_mouse_emulation_event = false; else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_INCLUSIVE) want_touch_event = al_is_mouse_installed() ? (want_touch_event && !primary) : want_touch_event; else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_EXCLUSIVE) want_touch_event = al_is_mouse_installed() ? false : want_touch_event; if (!want_touch_event && !want_mouse_emulation_event) return; if (want_touch_event) { event.touch.type = type; event.touch.display = (ALLEGRO_DISPLAY*)disp; event.touch.timestamp = timestamp; event.touch.id = id; event.touch.x = x; event.touch.y = y; event.touch.dx = dx; event.touch.dy = dy; event.touch.primary = primary; _al_event_source_lock(&touch_input.es); _al_event_source_emit_event(&touch_input.es, &event); _al_event_source_unlock(&touch_input.es); } if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_NONE) { mouse_state.x = (int)x; mouse_state.y = (int)y; if (type == ALLEGRO_EVENT_TOUCH_BEGIN) mouse_state.buttons++; else if (type == ALLEGRO_EVENT_TOUCH_END) mouse_state.buttons--; mouse_state.pressure = mouse_state.buttons ? 1.0 : 0.0; /* TODO */ _al_event_source_lock(&touch_input.mouse_emulation_es); if (want_mouse_emulation_event) { switch (type) { case ALLEGRO_EVENT_TOUCH_BEGIN: type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN; break; case ALLEGRO_EVENT_TOUCH_CANCEL: case ALLEGRO_EVENT_TOUCH_END: type = ALLEGRO_EVENT_MOUSE_BUTTON_UP; break; case ALLEGRO_EVENT_TOUCH_MOVE: type = ALLEGRO_EVENT_MOUSE_AXES; break; } event.mouse.type = type; event.mouse.timestamp = timestamp; event.mouse.display = (ALLEGRO_DISPLAY*)disp; event.mouse.x = (int)x; event.mouse.y = (int)y; event.mouse.dx = (int)dx; event.mouse.dy = (int)dy; event.mouse.dz = 0; event.mouse.dw = 0; if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) { event.mouse.button = 1; } else { event.mouse.button = id; } event.mouse.pressure = mouse_state.pressure; if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) { al_set_mouse_xy(event.mouse.display, event.mouse.x, event.mouse.y); } _al_event_source_emit_event(&touch_input.mouse_emulation_es, &event); } _al_event_source_unlock(&touch_input.mouse_emulation_es); } } static int find_free_touch_state_index(void) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; i++) if (touch_input_state.touches[i].id < 0) return i; return -1; } static int find_touch_state_index_with_id(int id) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; i++) if (touch_ids[i] == id) return i; return -1; } static void touch_input_handle_begin(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { int index= find_free_touch_state_index(); if (index < 0) return; ALLEGRO_TOUCH_STATE* state = touch_input_state.touches + index; (void)primary; if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->id = index; state->x = x; state->y = y; state->dx = 0.0f; state->dy = 0.0f; state->primary = primary; state->display = disp; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_BEGIN, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); touch_ids[index]= id; } static void touch_input_handle_end(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { int index= find_touch_state_index_with_id(id); if (index < 0) return; ALLEGRO_TOUCH_STATE* state = touch_input_state.touches + index; (void)primary; if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_END, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); _al_event_source_lock(&touch_input.es); state->id = -1; touch_ids[index]= -1; _al_event_source_unlock(&touch_input.es); } static void touch_input_handle_move(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { int index= find_touch_state_index_with_id(id); if (index < 0) return; ALLEGRO_TOUCH_STATE* state = touch_input_state.touches + index; (void)primary; if (NULL == state) return; if (x == state->x && y == state->y) return; /* coordinates haven't changed */ _al_event_source_lock(&touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_MOVE, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); } static void touch_input_handle_cancel(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) { int index= find_touch_state_index_with_id(id); if (index < 0) return; ALLEGRO_TOUCH_STATE* state = touch_input_state.touches + index; (void)primary; if (NULL == state) return; _al_event_source_lock(&touch_input.es); state->dx = x - state->x; state->dy = y - state->y; state->x = x; state->y = y; _al_event_source_unlock(&touch_input.es); generate_touch_input_event(ALLEGRO_EVENT_TOUCH_CANCEL, timestamp, state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); _al_event_source_lock(&touch_input.es); state->id = -1; _al_event_source_unlock(&touch_input.es); } static bool init_touch_input_api(void) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); Display *dpy = system->x11display; /* check XInput extension */ int ev; int err; if (!XQueryExtension(dpy, "XInputExtension", &opcode, &ev, &err)) { ALLEGRO_DEBUG("XInput extension not available. Touch input unavailable.\n"); return false; } /* check the version of XInput */ int major = 2; int minor = 2; int rc = XIQueryVersion(dpy, &major, &minor); if (rc != Success) { ALLEGRO_DEBUG("XInput version is too old (%d.%d): Needs 2.2. Touch input unavailable.\n", major, minor); return false; } /* select device */ int cnt; int i, j; int touch_devid; XIDeviceInfo *di = XIQueryDevice(dpy, XIAllDevices, &cnt); for (i = 0; i < cnt; i++) { XIDeviceInfo *dev = &di[i]; for (j = 0; j < dev->num_classes; j++) { XITouchClassInfo *class = (XITouchClassInfo*)(dev->classes[j]); if (class->type == XITouchClass) { touch_devid = dev->deviceid; ALLEGRO_DEBUG("Found touchscreen deviceid: %i\n", touch_devid); goto STOP_SEARCH_DEVICE; } } } STOP_SEARCH_DEVICE: XIFreeDeviceInfo(di); if (i >= cnt) { /* no device found */ ALLEGRO_DEBUG("No touchscreen device found.\n"); return false; } return true; } static bool xtouch_init(void) { if (installed) return false; if (!init_touch_input_api()) return false; ALLEGRO_DEBUG("XInput2 touch input initialized.\n"); memset(&touch_input, 0, sizeof(touch_input)); reset_touch_input_state(); /* Initialise the touch object for use as an event source. */ _al_event_source_init(&touch_input.es); _al_event_source_init(&touch_input.mouse_emulation_es); touch_input.mouse_emulation_mode = ALLEGRO_MOUSE_EMULATION_TRANSPARENT; initiali_time_stamp = al_get_time(); installed = true; return true; } static void xtouch_exit(void) { } static ALLEGRO_TOUCH_INPUT* get_touch_input(void) { return &touch_input; } static void get_touch_input_state(ALLEGRO_TOUCH_INPUT_STATE *ret_state) { _al_event_source_lock(&touch_input.es); *ret_state = touch_input_state; _al_event_source_unlock(&touch_input.es); } static void set_mouse_emulation_mode(int mode) { if (touch_input.mouse_emulation_mode != mode) { int i; for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; i++) { ALLEGRO_TOUCH_STATE* touch = touch_input_state.touches + i; if (touch->id > 0) { touch_input_handle_cancel(touch_ids[i], initiali_time_stamp, touch->x, touch->y, touch->primary, touch->display); } } touch_input.mouse_emulation_mode = mode; } } /* the driver vtable */ #define TOUCHDRV_XWIN AL_ID('X','W','I','N') static ALLEGRO_TOUCH_INPUT_DRIVER touchdrv_xwin = { TOUCHDRV_XWIN, xtouch_init, xtouch_exit, get_touch_input, get_touch_input_state, set_mouse_emulation_mode, NULL }; #endif _AL_DRIVER_INFO _al_touch_input_driver_list[] = { #ifdef ALLEGRO_XWINDOWS_WITH_XINPUT2 {TOUCHDRV_XWIN, &touchdrv_xwin, true}, #endif {0, NULL, 0} }; void _al_x_handle_touch_event(ALLEGRO_SYSTEM_XGLX *s, ALLEGRO_DISPLAY_XGLX *d, XEvent *e) { #ifdef ALLEGRO_XWINDOWS_WITH_XINPUT2 Display *x11display = s->x11display; XGenericEventCookie *cookie = &e->xcookie; if (!installed) return; /* extended event */ if (XGetEventData(x11display, cookie)) { /* check if this belongs to XInput */ if (cookie->type == GenericEvent && cookie->extension == opcode) { XIDeviceEvent *devev; devev = cookie->data; /* ignore events from a different display */ if (devev->display != x11display) return; switch (devev->evtype) { case XI_TouchBegin: /* the next new touch gets primary flag if it's not set */ if (primary_touch_id < 0) primary_touch_id= devev->detail; touch_input_handle_begin(devev->detail, al_get_time(), devev->event_x, devev->event_y, primary_touch_id == devev->detail, &d->display); break; case XI_TouchUpdate: touch_input_handle_move(devev->detail, al_get_time(), devev->event_x, devev->event_y, primary_touch_id == devev->detail, &d->display); break; case XI_TouchEnd: touch_input_handle_end(devev->detail, al_get_time(), devev->event_x, devev->event_y, primary_touch_id == devev->detail, &d->display); if (primary_touch_id == devev->detail) primary_touch_id = -1; break; } } } #else (void)s; (void)d; (void)e; #endif } allegro5-5.2.10.1/src/x/xwindow.c000066400000000000000000000327501473414355200163700ustar00rootroot00000000000000#include #include #include #include "allegro5/allegro.h" #include "allegro5/allegro_x.h" #include "allegro5/internal/aintern_x.h" #include "allegro5/internal/aintern_xdisplay.h" #include "allegro5/internal/aintern_xsystem.h" #include "allegro5/internal/aintern_xwindow.h" #ifdef ALLEGRO_RASPBERRYPI #include "allegro5/internal/aintern_raspberrypi.h" #define ALLEGRO_SYSTEM_XGLX ALLEGRO_SYSTEM_RASPBERRYPI #define ALLEGRO_DISPLAY_XGLX ALLEGRO_DISPLAY_RASPBERRYPI #endif ALLEGRO_DEBUG_CHANNEL("xwindow") #define X11_ATOM(x) XInternAtom(x11, #x, False); void _al_xwin_set_size_hints(ALLEGRO_DISPLAY *d, int x_off, int y_off) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (void *)d; XSizeHints *sizehints; XWMHints *wmhints; XClassHint *classhints; int w, h; sizehints = XAllocSizeHints(); sizehints->flags = 0; #ifdef ALLEGRO_RASPBERRYPI int x, y; _al_raspberrypi_get_screen_info(&x, &y, &w, &h); #else w = d->w; h = d->h; #endif /* Do not force the size of the window on resizeable or fullscreen windows */ /* on fullscreen windows, it confuses most X Window Managers */ if (!(d->flags & ALLEGRO_RESIZABLE) && !(d->flags & ALLEGRO_FULLSCREEN)) { sizehints->flags |= PMinSize | PMaxSize | PBaseSize; sizehints->min_width = sizehints->max_width = sizehints->base_width = w; sizehints->min_height = sizehints->max_height = sizehints->base_height = h; } /* Constrain the window if needed. */ if (d->use_constraints && (d->flags & ALLEGRO_RESIZABLE) && (d->min_w > 0 || d->min_h > 0 || d->max_w > 0 || d->max_h > 0)) { sizehints->flags |= PMinSize | PMaxSize | PBaseSize; sizehints->min_width = (d->min_w > 0) ? d->min_w : 0; sizehints->min_height = (d->min_h > 0) ? d->min_h : 0; sizehints->max_width = (d->max_w > 0) ? d->max_w : INT_MAX; sizehints->max_height = (d->max_h > 0) ? d->max_h : INT_MAX; sizehints->base_width = w; sizehints->base_height = h; } // Tell WMs to respect our chosen position, otherwise the x_off/y_off // positions passed to XCreateWindow will be ignored by most WMs. if (x_off != INT_MAX && y_off != INT_MAX) { ALLEGRO_DEBUG("Force window position to %d, %d.\n", x_off, y_off); sizehints->flags |= PPosition; sizehints->x = x_off; sizehints->y = y_off; } if (d->flags & ALLEGRO_FULLSCREEN) { /* kwin will improperly layer a panel over our window on a second display without this. * some other Size flags may cause glitches with various WMs, but this seems to be ok * with metacity and kwin. As noted in xdpy_create_display, compiz is just broken. */ sizehints->flags |= PBaseSize; sizehints->base_width = w; sizehints->base_height = h; } /* Setup the input hints so we get keyboard input */ wmhints = XAllocWMHints(); wmhints->input = True; wmhints->flags = InputHint; ALLEGRO_PATH *exepath = al_get_standard_path(ALLEGRO_EXENAME_PATH); /* Setup the class hints so we can get an icon (AfterStep) * We must use the executable filename here. */ classhints = XAllocClassHint(); classhints->res_name = strdup(al_get_path_basename(exepath)); classhints->res_class = strdup(al_get_path_basename(exepath)); /* Set the size, input and class hints, and define WM_CLIENT_MACHINE and WM_LOCALE_NAME */ XSetWMProperties(system->x11display, glx->window, NULL, NULL, NULL, 0, sizehints, wmhints, classhints); free(classhints->res_name); free(classhints->res_class); XFree(sizehints); XFree(wmhints); XFree(classhints); al_destroy_path(exepath); } void _al_xwin_reset_size_hints(ALLEGRO_DISPLAY *d) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (void *)d; XSizeHints *hints; hints = XAllocSizeHints(); hints->flags = PMinSize | PMaxSize; hints->min_width = 0; hints->min_height = 0; // FIXME: Is there a way to remove/reset max dimensions? hints->max_width = 32768; hints->max_height = 32768; XSetWMNormalHints(system->x11display, glx->window, hints); XFree(hints); } /* Note: The system mutex must be locked (exactly once) before * calling this as we call _al_display_xglx_await_resize. */ void _al_xwin_set_fullscreen_window(ALLEGRO_DISPLAY *display, int value) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; Display *x11 = system->x11display; #ifndef ALLEGRO_RASPBERRYPI int old_resize_count = glx->resize_count; #endif ALLEGRO_DEBUG("Toggling _NET_WM_STATE_FULLSCREEN hint: %d\n", value); XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.message_type = X11_ATOM(_NET_WM_STATE); xev.xclient.window = glx->window; xev.xclient.format = 32; // Note: It seems 0 is not reliable except when mapping a window - // 2 is all we need though. xev.xclient.data.l[0] = value; /* 0 = off, 1 = on, 2 = toggle */ xev.xclient.data.l[1] = X11_ATOM(_NET_WM_STATE_FULLSCREEN); xev.xclient.data.l[2] = 0; xev.xclient.data.l[3] = 1; /* 1 = normal application source */ xev.xclient.data.l[4] = 0; XSendEvent( x11, #if !defined ALLEGRO_RASPBERRYPI RootWindowOfScreen(ScreenOfDisplay(x11, glx->xscreen)), #else RootWindowOfScreen(ScreenOfDisplay(x11, DefaultScreen(x11))), #endif False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); #if !defined ALLEGRO_RASPBERRYPI if (value == 2) { /* Only wait for a resize if toggling. */ _al_display_xglx_await_resize(display, old_resize_count, true); } #endif } void _al_xwin_set_above(ALLEGRO_DISPLAY *display, int value) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; Display *x11 = system->x11display; ALLEGRO_DEBUG("Toggling _NET_WM_STATE_ABOVE hint: %d\n", value); XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.message_type = X11_ATOM(_NET_WM_STATE); xev.xclient.window = glx->window; xev.xclient.format = 32; // Note: It seems 0 is not reliable except when mapping a window - // 2 is all we need though. xev.xclient.data.l[0] = value; /* 0 = off, 1 = on, 2 = toggle */ xev.xclient.data.l[1] = X11_ATOM(_NET_WM_STATE_ABOVE); xev.xclient.data.l[2] = 0; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 1; XSendEvent(x11, DefaultRootWindow(x11), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } void _al_xwin_set_frame(ALLEGRO_DISPLAY *display, bool frame_on) { ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; Display *x11 = system->x11display; Atom hints; #if 1 /* This code is taken from the GDK sources. So it works perfectly in Gnome, * no idea if it will work anywhere else. X11 documentation itself only * describes a way how to make the window completely unmanaged, but that * would also require special care in the event handler. */ hints = XInternAtom(x11, "_MOTIF_WM_HINTS", True); if (hints) { struct { unsigned long flags; unsigned long functions; unsigned long decorations; long input_mode; unsigned long status; } motif = {2, 0, frame_on, 0, 0}; XChangeProperty(x11, glx->window, hints, hints, 32, PropModeReplace, (void *)&motif, sizeof motif / 4); if (frame_on) display->flags &= ~ALLEGRO_FRAMELESS; else display->flags |= ALLEGRO_FRAMELESS; } #endif } /* Helper to set a window icon. We use the _NET_WM_ICON property which is * supported by modern window managers. * * The old method is XSetWMHints but the (antiquated) ICCCM talks about 1-bit * pixmaps. For colour icons, perhaps you're supposed use the icon_window, * and draw the window yourself? */ static bool xdpy_set_icon_inner(Display *x11display, Window window, ALLEGRO_BITMAP *bitmap, int prop_mode) { int w, h; int data_size; unsigned long *data; /* Yes, unsigned long, even on 64-bit platforms! */ ALLEGRO_LOCKED_REGION *lr; bool ret; w = al_get_bitmap_width(bitmap); h = al_get_bitmap_height(bitmap); data_size = 2 + w * h; data = al_malloc(data_size * sizeof(data[0])); if (!data) return false; lr = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA, ALLEGRO_LOCK_READONLY); if (lr) { int x, y; ALLEGRO_COLOR c; unsigned char r, g, b, a; Atom _NET_WM_ICON; data[0] = w; data[1] = h; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { c = al_get_pixel(bitmap, x, y); al_unmap_rgba(c, &r, &g, &b, &a); data[2 + y*w + x] = ((unsigned long)a << 24) | ((unsigned long)r << 16) | ((unsigned long)g << 8) | (unsigned long)b; } } _NET_WM_ICON = XInternAtom(x11display, "_NET_WM_ICON", False); XChangeProperty(x11display, window, _NET_WM_ICON, XA_CARDINAL, 32, prop_mode, (unsigned char *)data, data_size); al_unlock_bitmap(bitmap); ret = true; } else { ret = false; } al_free(data); return ret; } void _al_xwin_set_icons(ALLEGRO_DISPLAY *d, int num_icons, ALLEGRO_BITMAP *bitmaps[]) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)d; int prop_mode = PropModeReplace; int i; _al_mutex_lock(&system->lock); for (i = 0; i < num_icons; i++) { if (xdpy_set_icon_inner(system->x11display, glx->window, bitmaps[i], prop_mode)) { prop_mode = PropModeAppend; } } _al_mutex_unlock(&system->lock); } /* Note: The system mutex must be locked (exactly once) before * calling this as we call _al_display_xglx_await_resize. */ void _al_xwin_maximize(ALLEGRO_DISPLAY *display, bool maximized) { #ifndef ALLEGRO_RASPBERRYPI if (!!(display->flags & ALLEGRO_MAXIMIZED) == maximized) return; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; Display *x11 = system->x11display; int old_resize_count = glx->resize_count; XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.message_type = X11_ATOM(_NET_WM_STATE); xev.xclient.window = glx->window; xev.xclient.format = 32; xev.xclient.data.l[0] = maximized ? 1 : 0; xev.xclient.data.l[1] = X11_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); xev.xclient.data.l[2] = X11_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); xev.xclient.data.l[3] = 0; XSendEvent( x11, RootWindowOfScreen(ScreenOfDisplay(x11, glx->xscreen)), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); _al_display_xglx_await_resize(display, old_resize_count, true); #endif } void _al_xwin_check_maximized(ALLEGRO_DISPLAY *display) { #ifndef ALLEGRO_RASPBERRYPI ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; Display *x11 = system->x11display; Atom type; Atom horz = X11_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); Atom vert = X11_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); Atom property = X11_ATOM(_NET_WM_STATE); int format; int maximized = 0; unsigned long n, remaining, i, *p32; unsigned char *p8 = NULL; if (XGetWindowProperty(x11, glx->window, property, 0, INT_MAX, False, AnyPropertyType, &type, &format, &n, &remaining, &p8) != Success) { return; } p32 = (unsigned long *)p8; for (i = 0; i < n; i++) { if (p32[i] == horz) maximized |= 1; if (p32[i] == vert) maximized |= 2; } XFree(p8); display->flags &= ~ALLEGRO_MAXIMIZED; if (maximized == 3) display->flags |= ALLEGRO_MAXIMIZED; #endif } /* Function: al_get_x_window_id */ XID al_get_x_window_id(ALLEGRO_DISPLAY *display) { ASSERT(display != NULL); return ((ALLEGRO_DISPLAY_XGLX*)display)->window; } // Note: this only seems to work after the window has been mapped void _al_xwin_get_borders(ALLEGRO_DISPLAY *display) { ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)display; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); Display *x11 = system->x11display; Atom type; int format; unsigned long nitems, bytes_after; unsigned char *property; Atom frame_extents = X11_ATOM(_NET_FRAME_EXTENTS); if (XGetWindowProperty(x11, glx->window, frame_extents, 0, 16, 0, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &property) == Success) { if (type != None && nitems == 4) { glx->border_left = (int)((long *)property)[0]; glx->border_right = (int)((long *)property)[1]; glx->border_top = (int)((long *)property)[2]; glx->border_bottom = (int)((long *)property)[3]; glx->borders_known = true; ALLEGRO_DEBUG("_NET_FRAME_EXTENTS: %d %d %d %d\n", glx->border_left, glx->border_top, glx->border_right, glx->border_bottom); } else { ALLEGRO_DEBUG("Unexpected _NET_FRAME_EXTENTS format: nitems=%lu\n", nitems); } XFree(property); } else { ALLEGRO_DEBUG("Could not read _NET_FRAME_EXTENTS\n"); } } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/tests/000077500000000000000000000000001473414355200146225ustar00rootroot00000000000000allegro5-5.2.10.1/tests/CMakeLists.txt000066400000000000000000000066601473414355200173720ustar00rootroot00000000000000if(NOT ALLEGRO_LINK_WITH OR NOT ALLEGRO_MAIN_LINK_WITH OR NOT IMAGE_LINK_WITH OR NOT COLOR_LINK_WITH OR NOT FONT_LINK_WITH OR NOT TTF_LINK_WITH OR NOT PRIMITIVES_LINK_WITH) message(STATUS "Not building tests due to missing library. " "Have: ${ALLEGRO_LINK_WITH} ${ALLEGRO_MAIN_LINK_WITH} " "${IMAGE_LINK_WITH} ${COLOR_LINK_WITH} " "${FONT_LINK_WITH} ${TTF_LINK_WITH} " "${PRIMITIVES_LINK_WITH}") return() endif() include_directories( ../addons/acodec ../addons/audio ../addons/color ../addons/font ../addons/image ../addons/main ../addons/memfile ../addons/native_dialog ../addons/physfs ../addons/primitives ../addons/shader ../addons/ttf ) if(MSVC) set(EXECUTABLE_TYPE) endif(MSVC) if(WANT_MONOLITH) set(LINK_WITH ${ALLEGRO_MONOLITH_LINK_WITH}) else() set(LINK_WITH ${ALLEGRO_LINK_WITH} ${ALLEGRO_MAIN_LINK_WITH} ${IMAGE_LINK_WITH} ${COLOR_LINK_WITH} ${FONT_LINK_WITH} ${TTF_LINK_WITH} ${PRIMITIVES_LINK_WITH} ${SHADER_LINK_WITH}) endif() #-----------------------------------------------------------------------------# # # Main test driver # #-----------------------------------------------------------------------------# add_our_executable( test_driver LIBS ${LINK_WITH} ) set(test_files ${CMAKE_CURRENT_SOURCE_DIR}/test_bitmaps.ini ${CMAKE_CURRENT_SOURCE_DIR}/test_bitmaps2.ini ${CMAKE_CURRENT_SOURCE_DIR}/test_blend.ini ${CMAKE_CURRENT_SOURCE_DIR}/test_locking.ini ${CMAKE_CURRENT_SOURCE_DIR}/test_locking2.ini ${CMAKE_CURRENT_SOURCE_DIR}/test_backbuffer.ini ${CMAKE_CURRENT_SOURCE_DIR}/test_image.ini ${CMAKE_CURRENT_SOURCE_DIR}/test_fonts.ini ${CMAKE_CURRENT_SOURCE_DIR}/test_prim.ini ${CMAKE_CURRENT_SOURCE_DIR}/test_prim2.ini ${CMAKE_CURRENT_SOURCE_DIR}/test_convert.ini ${CMAKE_CURRENT_SOURCE_DIR}/test_ciede2000.ini ) add_dependencies(test_driver copy_example_data) #-----------------------------------------------------------------------------# # # Standalone tests # #-----------------------------------------------------------------------------# add_our_executable( test_list LIBS ${LINK_WITH} ) #-----------------------------------------------------------------------------# # # Commands # #-----------------------------------------------------------------------------# add_custom_target(run_standalone_tests DEPENDS test_list COMMAND test_list ) add_custom_target(run_tests DEPENDS test_driver COMMAND test_driver ${test_files} ) add_custom_target(run_tests_gl DEPENDS test_driver COMMAND test_driver --force-opengl ${test_files} ) add_custom_target(run_tests_gl12 DEPENDS test_driver COMMAND test_driver --force-opengl-1.2 ${test_files} ) add_custom_target(run_tests_gl20 DEPENDS test_driver COMMAND test_driver --force-opengl-2.0 ${test_files} ) add_custom_target(run_tests_d3d DEPENDS test_driver COMMAND test_driver --force-d3d ${test_files} ) add_custom_target(run_tests_wine DEPENDS test_driver COMMAND wine test_driver ${test_files} ) add_custom_target(run_tests_wine_gl DEPENDS test_driver COMMAND wine test_driver --force-opengl ${test_files} ) add_custom_target(run_tests_shaders DEPENDS test_driver COMMAND test_driver --use-shaders ${test_files} ) # vim: set sts=4 sw=4 et: allegro5-5.2.10.1/tests/grab_bitmap_suites.sh000066400000000000000000000012511473414355200210200ustar00rootroot00000000000000# bmp suite 1 wget -N https://download.tuxfamily.org/allegro/files/bmpsuite/bmpsuite.zip unzip -u -d bmpsuite bmpsuite.zip # bmp suite 2 wget -N https://download.tuxfamily.org/allegro/files/bmpsuite/bmptestsuite-0.9.zip unzip -u bmptestsuite-0.9.zip # bmp suite 3 wget -N -P wvnet https://download.tuxfamily.org/allegro/files/bmpsuite/wvnet/test32bfv4.bmp wget -N -P wvnet https://download.tuxfamily.org/allegro/files/bmpsuite/wvnet/test32v5.bmp wget -N -P wvnet https://download.tuxfamily.org/allegro/files/bmpsuite/wvnet/trans.bmp # bmp suite 4 wget -N https://download.tuxfamily.org/allegro/files/bmpsuite/bmpsuite-2.4.zip unzip -u bmpsuite-2.4.zip mv bmpsuite-2.4 bmpsuite2 allegro5-5.2.10.1/tests/manual_bmpsuite1.ini000066400000000000000000000054061473414355200205760ustar00rootroot00000000000000# Test BMP loader with images from this source: # http://entropymine.com/jason/bmpsuite/ [bitmaps] g01bg =bmpsuite/g01bg.bmp g01bw =bmpsuite/g01bw.bmp g01p1 =bmpsuite/g01p1.bmp g01wb =bmpsuite/g01wb.bmp g04 =bmpsuite/g04.bmp g04p4 =bmpsuite/g04p4.bmp g04rle =bmpsuite/g04rle.bmp g08 =bmpsuite/g08.bmp g08offs =bmpsuite/g08offs.bmp g08os2 =bmpsuite/g08os2.bmp g08p64 =bmpsuite/g08p64.bmp g08p256 =bmpsuite/g08p256.bmp g08pi64 =bmpsuite/g08pi64.bmp g08pi256 =bmpsuite/g08pi256.bmp g08res11 =bmpsuite/g08res11.bmp g08res21 =bmpsuite/g08res21.bmp g08res22 =bmpsuite/g08res22.bmp g08rle =bmpsuite/g08rle.bmp g08s0 =bmpsuite/g08s0.bmp g08w124 =bmpsuite/g08w124.bmp g08w125 =bmpsuite/g08w125.bmp g08w126 =bmpsuite/g08w126.bmp g16bf555 =bmpsuite/g16bf555.bmp g16bf565 =bmpsuite/g16bf565.bmp g16def555=bmpsuite/g16def555.bmp g24 =bmpsuite/g24.bmp g32bf =bmpsuite/g32bf.bmp g32def =bmpsuite/g32def.bmp [template] op0=al_draw_bitmap(bmp, 0, 0, 0) [test bmpsuite g01bg] extend=template bmp=g01bg hash=9846dc91 [test bmpsuite g01bw] extend=template bmp=g01bw hash=e20721a5 [test bmpsuite g01p1] extend=template bmp=g01p1 hash=87931dc5 [test bmpsuite g01wb] extend=template bmp=g01wb hash=e20721a5 [test bmpsuite g04] extend=template bmp=g04 hash=3ba8f12f [test bmpsuite g04p4] extend=template bmp=g04p4 hash=ab1a2d4d [test bmpsuite g04rle] extend=template bmp=g04rle hash=3ba8f12f [test bmpsuite g08] extend=template bmp=g08 hash=7d8eb943 [test bmpsuite g08offs] extend=template bmp=g08offs hash=7d8eb943 [test bmpsuite g08os2] extend=template bmp=g08os2 hash=7d8eb943 [test bmpsuite g08p64] extend=template bmp=g08p64 hash=7b1f9739 [test bmpsuite g08p256] extend=template bmp=g08p256 hash=7d8eb943 [test bmpsuite g08pi64] extend=template bmp=g08pi64 hash=7d8eb943 [test bmpsuite g08pi256] extend=template bmp=g08pi256 hash=7d8eb943 [test bmpsuite g08res11] extend=template bmp=g08res11 hash=7d8eb943 [test bmpsuite g08res21] extend=template bmp=g08res21 hash=7d8eb943 [test bmpsuite g08res22] extend=template bmp=g08res22 hash=7d8eb943 [test bmpsuite g08rle] extend=template bmp=g08rle hash=7d8eb943 [test bmpsuite g08s0] extend=template bmp=g08s0 hash=7d8eb943 [test bmpsuite g08w124] extend=template bmp=g08w124 hash=a18fef34 [test bmpsuite g08w125] extend=template bmp=g08w125 hash=a25db914 [test bmpsuite g08w126] extend=template bmp=g08w126 hash=dde9c6c4 [test bmpsuite g16bf555] extend=template bmp=g16bf555 hash=096251dc [test bmpsuite g16bf565] extend=template bmp=g16bf565 hash=09f60795 [test bmpsuite g16def555] extend=template bmp=g16def555 hash=096251dc [test bmpsuite g24] extend=template bmp=g24 hash=f5bdf572 [test bmpsuite g32bf] extend=template bmp=g32bf hash=f5bdf572 [test bmpsuite g32def] extend=template bmp=g32def hash=f5bdf572 allegro5-5.2.10.1/tests/manual_bmpsuite2.ini000066400000000000000000000261371473414355200206030ustar00rootroot00000000000000# Test BMP loader with images from this source: # http://bmptestsuite.sourceforge.net/ [bitmaps] 1bpp-1x1 =bmptestsuite-0.9/valid/1bpp-1x1.bmp 1bpp-320x240 =bmptestsuite-0.9/valid/1bpp-320x240.bmp 1bpp-320x240-color =bmptestsuite-0.9/valid/1bpp-320x240-color.bmp 1bpp-320x240-overlappingcolor =bmptestsuite-0.9/valid/1bpp-320x240-overlappingcolor.bmp 1bpp-321x240 =bmptestsuite-0.9/valid/1bpp-321x240.bmp 1bpp-322x240 =bmptestsuite-0.9/valid/1bpp-322x240.bmp 1bpp-323x240 =bmptestsuite-0.9/valid/1bpp-323x240.bmp 1bpp-324x240 =bmptestsuite-0.9/valid/1bpp-324x240.bmp 1bpp-325x240 =bmptestsuite-0.9/valid/1bpp-325x240.bmp 1bpp-326x240 =bmptestsuite-0.9/valid/1bpp-326x240.bmp 1bpp-327x240 =bmptestsuite-0.9/valid/1bpp-327x240.bmp 1bpp-328x240 =bmptestsuite-0.9/valid/1bpp-328x240.bmp 1bpp-329x240 =bmptestsuite-0.9/valid/1bpp-329x240.bmp 1bpp-330x240 =bmptestsuite-0.9/valid/1bpp-330x240.bmp 1bpp-331x240 =bmptestsuite-0.9/valid/1bpp-331x240.bmp 1bpp-332x240 =bmptestsuite-0.9/valid/1bpp-332x240.bmp 1bpp-333x240 =bmptestsuite-0.9/valid/1bpp-333x240.bmp 1bpp-334x240 =bmptestsuite-0.9/valid/1bpp-334x240.bmp 1bpp-335x240 =bmptestsuite-0.9/valid/1bpp-335x240.bmp 1bpp-topdown-320x240 =bmptestsuite-0.9/valid/1bpp-topdown-320x240.bmp 4bpp-1x1 =bmptestsuite-0.9/valid/4bpp-1x1.bmp 4bpp-320x240 =bmptestsuite-0.9/valid/4bpp-320x240.bmp 4bpp-321x240 =bmptestsuite-0.9/valid/4bpp-321x240.bmp 4bpp-322x240 =bmptestsuite-0.9/valid/4bpp-322x240.bmp 4bpp-323x240 =bmptestsuite-0.9/valid/4bpp-323x240.bmp 4bpp-324x240 =bmptestsuite-0.9/valid/4bpp-324x240.bmp 4bpp-325x240 =bmptestsuite-0.9/valid/4bpp-325x240.bmp 4bpp-326x240 =bmptestsuite-0.9/valid/4bpp-326x240.bmp 4bpp-327x240 =bmptestsuite-0.9/valid/4bpp-327x240.bmp 4bpp-topdown-320x240 =bmptestsuite-0.9/valid/4bpp-topdown-320x240.bmp 8bpp-1x1 =bmptestsuite-0.9/valid/8bpp-1x1.bmp # 8bpp-1x64000 =bmptestsuite-0.9/valid/8bpp-1x64000.bmp # due to hardware limitation 8bpp-320x240 =bmptestsuite-0.9/valid/8bpp-320x240.bmp 8bpp-321x240 =bmptestsuite-0.9/valid/8bpp-321x240.bmp 8bpp-322x240 =bmptestsuite-0.9/valid/8bpp-322x240.bmp 8bpp-323x240 =bmptestsuite-0.9/valid/8bpp-323x240.bmp 8bpp-colorsimportant-two =bmptestsuite-0.9/valid/8bpp-colorsimportant-two.bmp 8bpp-colorsused-zero =bmptestsuite-0.9/valid/8bpp-colorsused-zero.bmp 8bpp-topdown-320x240 =bmptestsuite-0.9/valid/8bpp-topdown-320x240.bmp 24bpp-1x1 =bmptestsuite-0.9/valid/24bpp-1x1.bmp 24bpp-320x240 =bmptestsuite-0.9/valid/24bpp-320x240.bmp 24bpp-321x240 =bmptestsuite-0.9/valid/24bpp-321x240.bmp 24bpp-322x240 =bmptestsuite-0.9/valid/24bpp-322x240.bmp 24bpp-323x240 =bmptestsuite-0.9/valid/24bpp-323x240.bmp 24bpp-imagesize-zero =bmptestsuite-0.9/valid/24bpp-imagesize-zero.bmp 24bpp-topdown-320x240 =bmptestsuite-0.9/valid/24bpp-topdown-320x240.bmp 32bpp-1x1 =bmptestsuite-0.9/valid/32bpp-1x1.bmp 32bpp-320x240 =bmptestsuite-0.9/valid/32bpp-320x240.bmp 32bpp-888-optimalpalette-320x240=bmptestsuite-0.9/valid/32bpp-888-optimalpalette-320x240.bmp 32bpp-101110-320x240 =bmptestsuite-0.9/valid/32bpp-101110-320x240.bmp 32bpp-optimalpalette-320x240 =bmptestsuite-0.9/valid/32bpp-optimalpalette-320x240.bmp 32bpp-topdown-320x240 =bmptestsuite-0.9/valid/32bpp-topdown-320x240.bmp 555-1x1 =bmptestsuite-0.9/valid/555-1x1.bmp 555-320x240 =bmptestsuite-0.9/valid/555-320x240.bmp 555-321x240 =bmptestsuite-0.9/valid/555-321x240.bmp 565-1x1 =bmptestsuite-0.9/valid/565-1x1.bmp 565-320x240 =bmptestsuite-0.9/valid/565-320x240.bmp 565-320x240-topdown =bmptestsuite-0.9/valid/565-320x240-topdown.bmp 565-321x240 =bmptestsuite-0.9/valid/565-321x240.bmp 565-321x240-topdown =bmptestsuite-0.9/valid/565-321x240-topdown.bmp 565-322x240 =bmptestsuite-0.9/valid/565-322x240.bmp 565-322x240-topdown =bmptestsuite-0.9/valid/565-322x240-topdown.bmp rle4-absolute-320x240 =bmptestsuite-0.9/valid/rle4-absolute-320x240.bmp rle4-alternate-320x240 =bmptestsuite-0.9/valid/rle4-alternate-320x240.bmp rle4-delta-320x240 =bmptestsuite-0.9/valid/rle4-delta-320x240.bmp rle4-encoded-320x240 =bmptestsuite-0.9/valid/rle4-encoded-320x240.bmp # rle8-64000x1 =bmptestsuite-0.9/valid/rle8-64000x1.bmp # due to hardware limitation rle8-absolute-320x240 =bmptestsuite-0.9/valid/rle8-absolute-320x240.bmp rle8-blank-160x120 =bmptestsuite-0.9/valid/rle8-blank-160x120.bmp rle8-delta-320x240 =bmptestsuite-0.9/valid/rle8-delta-320x240.bmp rle8-encoded-320x240 =bmptestsuite-0.9/valid/rle8-encoded-320x240.bmp [template] op0=buf = al_create_bitmap(640, 480) op1=al_set_target_bitmap(buf) op2=al_clear_to_color(#ff00ff) op3=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op4=al_draw_bitmap(bmp, 0, 0, 0) op5=al_set_target_bitmap(target) op6=al_draw_bitmap(buf, 0, 0, 0) [test bmpsuite 1bpp-1x1] extend=template bmp=1bpp-1x1 hash=c6c3a3fd [test bmpsuite 1bpp-320x240] extend=template bmp=1bpp-320x240 hash=6050ef7d [test bmpsuite 1bpp-320x240-color] extend=template bmp=1bpp-320x240-color hash=9a3e4ae9 [test bmpsuite 1bpp-320x240-overlappingcolor] extend=template bmp=1bpp-320x240-overlappingcolor hash=9ebc16c5 [test bmpsuite 1bpp-323x240] extend=template bmp=1bpp-323x240 hash=a9d171bd [test bmpsuite 1bpp-324x240] extend=template bmp=1bpp-324x240 hash=c83ad13d [test bmpsuite 1bpp-325x240] extend=template bmp=1bpp-325x240 hash=d20c6b6d [test bmpsuite 1bpp-326x240] extend=template bmp=1bpp-326x240 hash=9cfd0a6d [test bmpsuite 1bpp-327x240] extend=template bmp=1bpp-327x240 hash=2c50ba1d [test bmpsuite 1bpp-328x240] extend=template bmp=1bpp-328x240 hash=c8ba84ed [test bmpsuite 1bpp-329x240] extend=template bmp=1bpp-329x240 hash=5763db1d [test bmpsuite 1bpp-330x240] extend=template bmp=1bpp-330x240 hash=6ab7842d [test bmpsuite 1bpp-331x240] extend=template bmp=1bpp-331x240 hash=adbad50d [test bmpsuite 1bpp-332x240] extend=template bmp=1bpp-332x240 hash=c6ae5b5d [test bmpsuite 1bpp-333x240] extend=template bmp=1bpp-333x240 hash=cd269f7d [test bmpsuite 1bpp-334x240] extend=template bmp=1bpp-334x240 hash=76d2f81d [test bmpsuite 1bpp-335x240] extend=template bmp=1bpp-335x240 hash=74e8607d [test bmpsuite 1bpp-topdown-320x240] extend=template bmp=1bpp-topdown-320x240 hash=6050ef7d [test bmpsuite 4bpp-1x1] extend=template bmp=4bpp-1x1 hash=5413ad0c [test bmpsuite 4bpp-320x240] extend=template bmp=4bpp-320x240 hash=14e6fb1d [test bmpsuite 4bpp-321x240] extend=template bmp=4bpp-321x240 hash=05a7bc6d [test bmpsuite 4bpp-322x240] extend=template bmp=4bpp-322x240 hash=4d583135 [test bmpsuite 4bpp-323x240] extend=template bmp=4bpp-323x240 hash=69d41ddd [test bmpsuite 4bpp-324x240] extend=template bmp=4bpp-324x240 hash=97b402cd [test bmpsuite 4bpp-325x240] extend=template bmp=4bpp-325x240 hash=e54ba235 [test bmpsuite 4bpp-326x240] extend=template bmp=4bpp-326x240 hash=f0ca000d [test bmpsuite 4bpp-327x240] extend=template bmp=4bpp-327x240 hash=c7c5e10d [test bmpsuite 4bpp-topdown-320x240] extend=template bmp=4bpp-topdown-320x240 hash=14e6fb1d [test bmpsuite 8bpp-1x1] extend=template bmp=8bpp-1x1 hash=5413ad0c [test bmpsuite 8bpp-320x240] extend=template bmp=8bpp-320x240 hash=14e6fb1d [test bmpsuite 8bpp-321x240] extend=template bmp=8bpp-321x240 hash=05a7bc6d [test bmpsuite 8bpp-322x240] extend=template bmp=8bpp-322x240 hash=4d583135 [test bmpsuite 8bpp-323x240] extend=template bmp=8bpp-323x240 hash=69d41ddd [test bmpsuite 8bpp-colorsimportant-two] extend=template bmp=8bpp-colorsimportant-two hash=14e6fb1d [test bmpsuite 8bpp-colorsused-zero] extend=template bmp=8bpp-colorsused-zero hash=14e6fb1d [test bmpsuite 8bpp-topdown-320x240] extend=template bmp=8bpp-topdown-320x240 hash=14e6fb1d [test bmpsuite 24bpp-1x1] extend=template bmp=24bpp-1x1 hash=5413ad0c [test bmpsuite 24bpp-320x240] extend=template bmp=24bpp-320x240 hash=14e6fb1d [test bmpsuite 24bpp-321x240] extend=template bmp=24bpp-321x240 hash=05a7bc6d [test bmpsuite 24bpp-322x240] extend=template bmp=24bpp-322x240 hash=4d583135 [test bmpsuite 24bpp-323x240] extend=template bmp=24bpp-323x240 hash=69d41ddd [test bmpsuite 24bpp-imagesize-zero] extend=template bmp=24bpp-imagesize-zero hash=14e6fb1d [test bmpsuite 24bpp-topdown-320x240] extend=template bmp=24bpp-topdown-320x240 hash=14e6fb1d [test bmpsuite 32bpp-1x1] extend=template bmp=32bpp-1x1 hash=5413ad0c [test bmpsuite 32bpp-320x240] extend=template bmp=32bpp-320x240 hash=14e6fb1d [test bmpsuite 32bpp-888-optimalpalette-320x240] extend=template bmp=32bpp-888-optimalpalette-320x240 hash=14e6fb1d [test bmpsuite 32bpp-101110-320x240] extend=template bmp=32bpp-101110-320x240 hash=14e6fb1d [test bmpsuite 32bpp-optimalpalette-320x240] extend=template bmp=32bpp-optimalpalette-320x240 hash=14e6fb1d [test bmpsuite 32bpp-topdown-320x240] extend=template bmp=32bpp-topdown-320x240 hash=14e6fb1d [test bmpsuite 555-1x1] extend=template bmp=555-1x1 hash=5413ad0c [test bmpsuite 555-320x240] extend=template bmp=555-320x240 hash=14e6fb1d [test bmpsuite 555-321x240] extend=template bmp=555-321x240 hash=05a7bc6d [test bmpsuite 565-1x1] extend=template bmp=565-1x1 hash=5413ad0c [test bmpsuite 565-320x240] extend=template bmp=565-320x240 hash=14e6fb1d [test bmpsuite 565-320x240-topdown] extend=template bmp=565-320x240-topdown hash=14e6fb1d [test bmpsuite 565-321x240] extend=template bmp=565-321x240 hash=05a7bc6d [test bmpsuite 565-321x240-topdown] extend=template bmp=565-321x240-topdown hash=05a7bc6d [test bmpsuite 565-322x240] extend=template bmp=565-322x240 hash=4d583135 [test bmpsuite 565-322x240-topdown] extend=template bmp=565-322x240-topdown hash=4d583135 [test bmpsuite rle4-absolute-320x240] extend=template bmp=rle4-absolute-320x240 hash=14e6fb1d [test bmpsuite rle4-alternate-320x240] extend=template bmp=rle4-alternate-320x240 hash=bcf6e8cd [test bmpsuite rle4-delta-320x240] extend=template bmp=rle4-delta-320x240 hash=ef879d9d [test bmpsuite rle4-encoded-320x240] extend=template bmp=rle4-encoded-320x240 hash=14e6fb1d [test bmpsuite rle8-absolute-320x240] extend=template bmp=rle8-absolute-320x240 hash=14e6fb1d [test bmpsuite rle8-blank-160x120] extend=template bmp=rle8-blank-160x120 hash=6a451dc5 [test bmpsuite rle8-delta-320x240] extend=template bmp=rle8-delta-320x240 hash=ef879d9d [test bmpsuite rle8-encoded-320x240] extend=template bmp=rle8-encoded-320x240 hash=14e6fb1d allegro5-5.2.10.1/tests/manual_bmpsuite3.ini000066400000000000000000000015311473414355200205730ustar00rootroot00000000000000# Test BMP loader with images from this source: # http://wvnvms.wvnet.edu/vmswww/bmp.html (dead link) # http://pxd.me/dompdf/www/test/image_bmp.html [bitmaps] test32bfv4 = wvnet/test32bfv4.bmp test32v5 = wvnet/test32v5.bmp # test4os2v2= wvnet/test4os2v2.bmp # OS/2 v2 headers not supported trans = wvnet/trans.bmp [template] op0=buf = al_create_bitmap(640, 480) op1=al_set_target_bitmap(buf) op2=al_clear_to_color(#ff00ff) op3=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op4=al_draw_bitmap(bmp, 0, 0, 0) op5=al_set_target_bitmap(target) op6=al_draw_bitmap(buf, 0, 0, 0) [test bmpsuite test32bfv4] extend=template bmp=test32bfv4 # This image really *is* fully transparent. hash=6a451dc5 [test bmpsuite test32v5] extend=template bmp=test32v5 hash=f5c38217 [test bmpsuite trans] extend=template bmp=trans hash=da824687 allegro5-5.2.10.1/tests/manual_bmpsuite4.ini000066400000000000000000000173161473414355200206040ustar00rootroot00000000000000# Test BMP loader with images from this source: # http://entropymine.com/jason/bmpsuite/ (version 2) [bitmaps] # --- Common ("good") bmp files gpal1bg = bmpsuite2/g/pal1bg.bmp gpal1 = bmpsuite2/g/pal1.bmp gpal1wb = bmpsuite2/g/pal1wb.bmp gpal4 = bmpsuite2/g/pal4.bmp gpal4gs = bmpsuite2/g/pal4gs.bmp gpal4rle = bmpsuite2/g/pal4rle.bmp gpal8-0 = bmpsuite2/g/pal8-0.bmp gpal8 = bmpsuite2/g/pal8.bmp gpal8gs = bmpsuite2/g/pal8gs.bmp gpal8nonsquare = bmpsuite2/g/pal8nonsquare.bmp gpal8os2 = bmpsuite2/g/pal8os2.bmp gpal8rle = bmpsuite2/g/pal8rle.bmp gpal8topdown = bmpsuite2/g/pal8topdown.bmp gpal8v4 = bmpsuite2/g/pal8v4.bmp gpal8v5 = bmpsuite2/g/pal8v5.bmp gpal8w124 = bmpsuite2/g/pal8w124.bmp gpal8w125 = bmpsuite2/g/pal8w125.bmp gpal8w126 = bmpsuite2/g/pal8w126.bmp grgb16-565 = bmpsuite2/g/rgb16-565.bmp grgb16-565pal = bmpsuite2/g/rgb16-565pal.bmp grgb16 = bmpsuite2/g/rgb16.bmp grgb24 = bmpsuite2/g/rgb24.bmp grgb24pal = bmpsuite2/g/rgb24pal.bmp grgb32 = bmpsuite2/g/rgb32.bmp grgb32bf = bmpsuite2/g/rgb32bf.bmp # --- Obscure ("questionable") bmp files qpal1p1 = bmpsuite2/q/pal1p1.bmp qpal2 = bmpsuite2/q/pal2.bmp qpal2color = bmpsuite2/q/pal2color.bmp qpal8os2-sz = bmpsuite2/q/pal8os2-sz.bmp qpal8os2v2-40sz = bmpsuite2/q/pal8os2v2-40sz.bmp qrgb24lprof = bmpsuite2/q/rgb24lprof.bmp qrgb24prof = bmpsuite2/q/rgb24prof.bmp qrgb24largepal = bmpsuite2/q/rgb24largepal.bmp qpal8oversizepal = bmpsuite2/q/pal8oversizepal.bmp qpal8os2sp = bmpsuite2/q/pal8os2sp.bmp qrgb16-231 = bmpsuite2/q/rgb16-231.bmp qrgb16-3103 = bmpsuite2/q/rgb16-3103.bmp qrgb32-111110 = bmpsuite2/q/rgb32-111110.bmp qrgb32-7187 = bmpsuite2/q/rgb32-7187.bmp qrgba16-1924 = bmpsuite2/q/rgba16-1924.bmp qrgba16-4444 = bmpsuite2/q/rgba16-4444.bmp qrgba32-61754 = bmpsuite2/q/rgba32-61754.bmp qrgba32-81284 = bmpsuite2/q/rgba32-81284.bmp qrgba32 = bmpsuite2/q/rgba32.bmp # activates the alpha channel detection hack # output is not "correct", but it is what we want qrgb32fakealpha = bmpsuite2/q/rgb32fakealpha.bmp # multiple "correct" outputs, we choose palette 0 to fill empty spaces # note: output of the "rlecut" variants is intended to have purple lines qpal4rletrns = bmpsuite2/q/pal4rletrns.bmp qpal8rletrns = bmpsuite2/q/pal8rletrns.bmp qpal4rlecut = bmpsuite2/q/pal4rlecut.bmp qpal8rlecut = bmpsuite2/q/pal8rlecut.bmp # allegro bails on unrecognized header sizes #qrgb32h52 = bmpsuite2/q/rgb32h52.bmp #qrgba32h56 = bmpsuite2/q/rgba32h56.bmp # OS2v2 format not supported #qpal8os2v2-16 = bmpsuite2/q/pal8os2v2-16.bmp #qpal8os2v2 = bmpsuite2/q/pal8os2v2.bmp #qpal8os2v2-sz = bmpsuite2/q/pal8os2v2-sz.bmp # BI_ALHPABITFIELDS not supported #qrgba32abf = bmpsuite2/q/rgba32abf.bmp # JPEG/PNG compression not supported #qrgb24jpeg = bmpsuite2/q/rgb24jpeg.bmp #qrgb24png = bmpsuite2/q/rgb24png.bmp # --- Invalid ("bad") bmp files # Ensure empty palette entries are consistently colored bpal8badindex = bmpsuite2/b/pal8badindex.bmp # Ensure unspecified pixels are consistently colored bshortfile = bmpsuite2/b/shortfile.bmp # Ensure zero-length bitfields are consistently handled brgb16-880 = bmpsuite2/b/rgb16-880.bmp # Ensure RLE top-down images remain working brletopdown = bmpsuite2/b/rletopdown.bmp [template] op0=al_draw_bitmap(bmp, 0, 0, 0) [template_premul] op0=bmp = al_load_bitmap(filename) op1=al_draw_bitmap(bmp, 0, 0, 0) [test bmpsuite2 gpal1bg] extend=template bmp=gpal1bg hash=0d098169 [test bmpsuite2 gpal1] extend=template bmp=gpal1 hash=0a1884dd [test bmpsuite2 gpal1wb] extend=template bmp=gpal1wb hash=0a1884dd [test bmpsuite2 gpal4] extend=template bmp=gpal4 hash=a1f65579 [test bmpsuite2 gpal4gs] extend=template bmp=gpal4gs hash=c17d0e68 [test bmpsuite2 gpal4rle] extend=template bmp=gpal4rle hash=a1f65579 [test bmpsuite2 gpal8-0] extend=template bmp=gpal8-0 hash=3f98d122 [test bmpsuite2 gpal8] extend=template bmp=gpal8 hash=3f98d122 [test bmpsuite2 gpal8gs] extend=template bmp=gpal8gs hash=644b7fcb [test bmpsuite2 gpal8nonsquare] extend=template bmp=gpal8nonsquare hash=92123f8e [test bmpsuite2 gpal8os2] extend=template bmp=gpal8os2 hash=3f98d122 [test bmpsuite2 gpal8rle] extend=template bmp=gpal8rle hash=3f98d122 [test bmpsuite2 gpal8topdown] extend=template bmp=gpal8topdown hash=3f98d122 [test bmpsuite2 gpal8v4] extend=template bmp=gpal8v4 hash=3f98d122 [test bmpsuite2 gpal8v5] extend=template bmp=gpal8v5 hash=3f98d122 [test bmpsuite2 gpal8w124] extend=template bmp=gpal8w124 hash=0a409ae9 [test bmpsuite2 gpal8w125] extend=template bmp=gpal8w125 hash=57e4822b [test bmpsuite2 gpal8w126] extend=template bmp=gpal8w126 hash=226f73e5 [test bmpsuite2 grgb16-565] extend=template bmp=grgb16-565 hash=250c9fae [test bmpsuite2 grgb16-565pal] extend=template bmp=grgb16-565pal hash=250c9fae [test bmpsuite2 grgb16] extend=template bmp=grgb16 hash=7af81b6e [test bmpsuite2 grgb24] extend=template bmp=grgb24 hash=68c13e2b [test bmpsuite2 grgb24pal] extend=template bmp=grgb24pal hash=68c13e2b [test bmpsuite2 grgb32] extend=template bmp=grgb32 hash=68c13e2b [test bmpsuite2 grgb32bf] extend=template bmp=grgb32bf hash=68c13e2b [test bmpsuite2 qpal1p1] extend=template bmp=qpal1p1 hash=87931dc5 [test bmpsuite2 qpal2] extend=template bmp=qpal2 hash=e9f2003f [test bmpsuite2 qpal2color] extend=template bmp=qpal2color hash=441e2930 [test bmpsuite2 qpal8os2-sz] extend=template bmp=qpal8os2-sz hash=3f98d122 [test bmpsuite2 qpal8os2v2-40sz] extend=template bmp=qpal8os2v2-40sz hash=3f98d122 [test bmpsuite2 qrgb24lprof] extend=template bmp=qrgb24lprof hash=68c13e2b [test bmpsuite2 qrgb24prof] extend=template bmp=qrgb24prof hash=68c13e2b [test bmpsuite2 qrgb24largepal] extend=template bmp=qrgb24largepal hash=68c13e2b [test bmpsuite2 qpal8oversizepal] extend=template bmp=qpal8oversizepal hash=3f98d122 [test bmpsuite2 qpal8os2sp] extend=template bmp=qpal8os2sp hash=3f98d122 [test bmpsuite2 qrgb16-231] extend=template bmp=qrgb16-231 hash=ac77a449 [test bmpsuite2 qrgb16-3103] extend=template bmp=qrgb16-3103 hash=6c258348 [test bmpsuite2 qrgb32-111110] extend=template bmp=qrgb32-111110 hash=84580522 [test bmpsuite2 qrgb32-7187] extend=template bmp=qrgb32-7187 hash=dc097ec5 [test bmpsuite2 qrgba16-1924] extend=template bmp=qrgba16-1924 hash=1e8da1d6 [test bmpsuite2 qrgba16-4444] extend=template bmp=qrgba16-4444 hash=e76fc7c2 [test bmpsuite2 qrgba32-61754] extend=template bmp=qrgba32-61754 hash=26e36575 [test bmpsuite2 qrgba32-81284] extend=template bmp=qrgba32-81284 hash=d90b3b69 [test bmpsuite2 qrgba32] extend=template bmp=qrgba32 hash=8a20727d [test bmpsuite2 qrgb32fakealpha] extend=template bmp=qrgb32fakealpha hash=f645af5b [test bmpsuite2 qpal4rletrns] extend=template bmp=qpal4rletrns hash=a52bd5f5 [test bmpsuite2 qpal8rletrns] extend=template bmp=qpal8rletrns hash=66933b5a [test bmpsuite2 qpal4rlecut] extend=template bmp=qpal4rlecut hash=f6a25391 [test bmpsuite2 qpal8rlecut] extend=template bmp=qpal8rlecut hash=828ee98c [test bmpsuite2 bpal8badindex] extend=template bmp=bpal8badindex hash=eb1512c3 [test bmpsuite2 bshortfile] extend=template bmp=bshortfile hash=76ba6cd6 [test bmpsuite2 brgb16-880] extend=template bmp=brgb16-880 hash=db0c5b9c [test bmpsuite2 brletopdown] extend=template bmp=brletopdown hash=3f98d122 [test bmpsuite2 qrgba16-1924_premul] extend=template_premul filename=bmpsuite2/q/rgba16-1924.bmp hash=e2f9488d [test bmpsuite2 qrgba16-4444_premul] extend=template_premul filename=bmpsuite2/q/rgba16-4444.bmp hash=463e4ca9 [test bmpsuite2 qrgba32-61754_premul] extend=template_premul filename=bmpsuite2/q/rgba32-61754.bmp hash=d7e0e0e2 [test bmpsuite2 qrgba32-81284_premul] extend=template_premul filename=bmpsuite2/q/rgba32-81284.bmp hash=cd6f937e [test bmpsuite2 qrgba32_premul] extend=template_premul filename=bmpsuite2/q/rgba32.bmp hash=b4aca763 [test bmpsuite2 qrgb32fakealpha_premul] extend=template_premul filename=bmpsuite2/q/rgb32fakealpha.bmp hash=5cf7f0d4 allegro5-5.2.10.1/tests/test_backbuffer.ini000066400000000000000000000046411473414355200204610ustar00rootroot00000000000000[bitmaps] allegro=../examples/data/allegro.pcx mysha=../examples/data/mysha.pcx # Test backbuffer to backbuffer. # Self-blitting support is not scheduled for 5.0.0. #[test bb2bb] #op0=al_draw_bitmap(allegro, 0, 0, 0) #op1=al_draw_bitmap_region(target, 0, 0, 320, 200, 100, 100, flags) #flags=0 #hash=BROKEN #[test bb2bb hflip] #extend=test bb2bb #flags=ALLEGRO_FLIP_HORIZONTAL #hash=BROKEN #[test bb2bb vflip] #extend=test bb2bb #flags=ALLEGRO_FLIP_VERTICAL #hash=BROKEN #[test bb2bb vhflip] #extend=test bb2bb #flags=ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL #hash=BROKEN # Test drawing backbuffer to non-backbuffer bitmaps. [test bbsrc] op0=al_draw_bitmap(mysha, 0, 0, 0) op1=bmp = al_create_bitmap(400, 300) op2=al_set_target_bitmap(bmp) op3=al_clear_to_color(yellow) op4=al_draw_bitmap(target, 0, 0, flags) op5=al_set_target_bitmap(target) op6=al_draw_bitmap(bmp, 200, 150, 0) flags=0 hash=a22aae19 [test bbsrc translate] extend=test bbsrc op4=al_draw_bitmap(target, 160, 100, flags) hash=9cf6fa5d [test bbsrc outside] extend=test bbsrc op4=al_draw_bitmap(target, -160, -100, flags) hash=882edf64 # In Allegro 5.0.0, tinting as well as blending is ignored when the # source bitmap is the screen (and locking is not used). [test bbsrc tint] skip_on_xvfb=true extend=test bbsrc op4=al_draw_tinted_bitmap(target, #008000, 0, 0, flags) hash=a47a96d4 hash_hw=a22aae19 # Support for transforming the back-buffer is not on the feature list # for 5.0.0. #[test bbsrc hflip] #extend=test bbsrc #flags=ALLEGRO_FLIP_HORIZONTAL #[test bbsrc vflip] #extend=test bbsrc #flags=ALLEGRO_FLIP_VERTICAL #[test bbsrc vhflip] #extend=test bbsrc #flags=ALLEGRO_FLIP_HORIZONTAL|ALLEGRO_FLIP_VERTICAL #[test bbsrc scale] #extend=test bbsrc #op4=al_draw_scaled_bitmap(target, 0, 0, 320, 200, 0, 0, 640, 480, flags) #[test bbsrc scale hflip] #extend=test bbsrc scale #flags=ALLEGRO_FLIP_HORIZONTAL #[test bbsrc scale vflip] #extend=test bbsrc scale #flags=ALLEGRO_FLIP_VERTICAL #[test bbsrc scale vhflip] #extend=test bbsrc scale #flags=ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL #[test bbsrc rotate] #extend=test bbsrc #op4=al_draw_rotated_bitmap(target, 0, 0, 0, 0, 0.2, flags) #[test bbsrc rotate hflip] #extend=test bbsrc rotate #flags=ALLEGRO_FLIP_HORIZONTAL #[test bbsrc rotate vflip] #extend=test bbsrc rotate #flags=ALLEGRO_FLIP_VERTICAL #[test bbsrc rotate vhflip] #extend=test bbsrc rotate #flags=ALLEGRO_FLIP_HORIZONTAL|ALLEGRO_FLIP_VERTICAL allegro5-5.2.10.1/tests/test_bitmaps.ini000066400000000000000000000306361473414355200200310ustar00rootroot00000000000000[bitmaps] mysha=../examples/data/mysha.pcx allegro=../examples/data/allegro.pcx [test blit] op0=al_clear_to_color(red) op1=al_draw_bitmap(mysha, 37, 47, flags) flags=0 hash=dabe9c74 [test blit vflip] extend=test blit flags=ALLEGRO_FLIP_VERTICAL hash=ee8c112c [test blit hflip] extend=test blit flags=ALLEGRO_FLIP_HORIZONTAL hash=7e343e90 [test blit vhflip] extend=test blit flags=ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL hash=72d59a18 [test region] op0=al_clear_to_color(red) op1=al_draw_bitmap(mysha, 37, 47, flags) op2=al_draw_bitmap_region(mysha, 111, 51, 77, 99, 37, 47, flags) flags=0 hash=8e5335ae [test region hflip] extend=test region flags=ALLEGRO_FLIP_HORIZONTAL hash=569472fc [test region vflip] extend=test region flags=ALLEGRO_FLIP_VERTICAL hash=f479bb0d [test region vhflip] extend=test region flags=ALLEGRO_FLIP_HORIZONTAL|ALLEGRO_FLIP_VERTICAL hash=cadc1987 [test scale min] op0=al_clear_to_color(red) op1=al_draw_scaled_bitmap(mysha, 0, 0, 320, 200, 11, 17, 77, 99, flags) flags=0 hash=ae4b4301 [test scale min vflip] extend=test scale min flags=ALLEGRO_FLIP_VERTICAL hash=973bd6bd sig=DLLLLLLLLELLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL [test scale min hflip] extend=test scale min flags=ALLEGRO_FLIP_HORIZONTAL hash=807e7ae5 [test scale min vhflip] extend=test scale min flags=ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL hash=5c2b54ad [test scale max] op0=al_clear_to_color(blue) op1=al_draw_scaled_bitmap(mysha, 0, 0, 320, 200, 11, 17, 611, 415, flags) flags=0 hash=1ede4355 sig=EEEEEEDDCEFGPGEEDDFKjsebEDDGwvsVaEEDHvcgQPKDDHogTKMFEE4EaNLN9DE22254I222DDDDDDDDD [test scale max hflip] extend=test scale max flags=ALLEGRO_FLIP_HORIZONTAL hash=99b05f69 sig=CDEEEEEEECDEMFRFFECDEairgGFDEIZburwFDEMOTlrvGDECLLUeqGDD2HMNaA3222385222DDDDDDDDD [test scale max vflip] extend=test scale max flags=ALLEGRO_FLIP_VERTICAL hash=d9f0a6ea sig=22221222222VM2K222GmePLLDEEJrmeRQJEDHuuoTUHDDFlovXaEDDEFPsgVEDCEEEEEEEDCIIIIIIHHH [test scale max2] op0=al_clear_to_color(aqua) op1=al_draw_scaled_bitmap(mysha, 0, 0, 320, 200, 320, 240, dw, dh, flags) dw=600 dh=600 flags=0 hash=edba302f sig=ggggggggggggggggggggggggggggggggggggggggXPQQQggggQEEEEggggQEEFFggggQFOtsggggQFomt [test scale max2 vflip] extend=test scale max2 flags=ALLEGRO_FLIP_VERTICAL hash=e6bc6d52 sig=ggggggggggggggggggggggggggggggggggggggggTJJJJggggJ222BggggJ22LGggggJ1baOggggVIkgP [test scale max2 negy hflip] extend=test scale max2 dh=-600 flags=ALLEGRO_FLIP_HORIZONTAL hash=e6bc6d52 sig=ggggPDEEYggggPCDEXggggPDDEDggggOCDDEggggYTTUUgggggggggggggggggggggggggggggggggggg [test scale max2 negy vhflip] extend=test scale max2 dh=-600 flags=ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL hash=cf1b15e6 sig=ggggQEEDMggggQDE7HggggJ1211ggggJ2222ggggWPPPPgggggggggggggggggggggggggggggggggggg [test scale max2 negx vflip] extend=test scale max2 dw=-600 flags=ALLEGRO_FLIP_VERTICAL hash=635d9cf1 sig=ggggggggggggggggggggggggggggggggggggJJJJWgggg9222PggggHK22PggggOab1PggggQgkIYgggg [test scale max2 negx negy] extend=test scale max2 dw=-600 dh=-600 sig=tmnFUggggrrIFUggggFFEEUggggEEEEUggggUUUTbgggggggggggggggggggggggggggggggggggggggg [test scale max2 negx negy hflip] extend=test scale max2 negx negy flags=ALLEGRO_FLIP_HORIZONTAL sig=ZEEDTggggXEDCTggggDEDCTggggEDDCTggggUTTTagggggggggggggggggggggggggggggggggggggggg [test scale max2 negx negy vflip] extend=test scale max2 negx negy flags=ALLEGRO_FLIP_VERTICAL sig=QgkHYggggOaZ2PggggHH22Pgggg9222PggggPPPPZgggggggggggggggggggggggggggggggggggggggg [test scale max2 negx negy vhflip] extend=test scale max2 negx negy flags=ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL sig=MCEEUggggG7EDUgggg1121Pgggg2222PggggPPPPZgggggggggggggggggggggggggggggggggggggggg [test rotate] op0=al_clear_to_color(purple) op1=al_draw_rotated_bitmap(allegro, 50, 50, 320, 240, theta, flags) op2=al_draw_pixel(320, 240, cyan) theta=0 flags=0 hash=435c5d10 [test rotate 0.5] extend=test rotate theta=0.5 hash=f03d3240 sig=LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLULLLLLLLLRKLLLLLLLQaaTLLLLOKSOkRLLLLGQXTLLLLLLINOL [test rotate 1.0] extend=test rotate theta=1.0 hash=78bf9ff5 sig=LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLkLLLLLLLIRLLLLLLOLcLLLLLLLOQkLLLLLLGaXeLLLLLLSinLL [test rotate 1.0 vflip] extend=test rotate 1.0 flags=ALLEGRO_FLIP_VERTICAL hash=5b75eca4 sig=LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLSNLLLLLLYTPHLLLLLLeVNLLLLLLL+WMLLLLLLhgNLL [test rotate -1.0] extend=test rotate theta=-1.0 hash=d86fa86f sig=LLLLLVmMLLLLLLYhNNLLLLKlUOLLLLLUdbHLLLLLTOLLLLLLLbLMLLLLLLLNLLLLLLLLLLLLLLLLLLLLL [test rotate -2.0] extend=test rotate theta=-2.0 hash=1b5ff6da sig=LLifZHLLLLLLgUJLLLLLLaYKLLLLLLKfOILLLLLLTJLLLLLLLkLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL [test rotate -2.0 hflip] extend=test rotate -2.0 flags=ALLEGRO_FLIP_HORIZONTAL hash=0a4986c3 sig=LLVSMGLLLLLLYSKLLLLLLabULLLLLLPTNMLLLLLLlNLLLLLLLiLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL [test rotate -2.0 vhflip] extend=test rotate -2.0 flags=ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL hash=4ddeb3e3 sig=LLJPcKLLLLLLJcZLLLLLLKWgLLLLLLIYUjLLLLLLNBLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL [test scaled rotate] op0=al_clear_to_color(firebrick) op1=al_draw_scaled_rotated_bitmap(allegro, 50, 50, 320, 240, xscale, yscale, theta, flags) op2=al_draw_pixel(320, 240, cyan) xscale=0.25 yscale=0.25 theta=0.7854 flags=0 hash=dc4ad82d sig=KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKdKKKKKKKKIKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK [test scaled rotate 2] extend=test scaled rotate xscale=0.777 yscale=0.777 hash=8fc7ecf8 sig=KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKXKKKKKKKKTKKKKKKKNehKKKKKKHSsgKKKKKKHTgKKKKKKKMKKK [test scaled rotate 2 neg] extend=test scaled rotate xscale=-0.777 yscale=-0.777 hash=96153b14 sig=KKKLKKKKKKKbTHKKKKKKhxSHKKKKKKheNKKKKKKKVKKKKKKKKXKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK [test scaled rotate 3] extend=test scaled rotate xscale=1.777 yscale=1.777 hash=1d003c91 sig=KKKKKKKKKKKKKKKKKKKKKKXKKKKKKKllQKKKKKJYQYKKKKKJRTjKKKKNNQYdnKKKOKKQUnZRKKLMYWjgf [test scaled rotate 4] extend=test scaled rotate xscale=3.0 yscale=3.0 theta=-2.5 hash=31a17741 sig=nhjTTOLOOlgdgSOJMMNnORRVNKLKOngKDEHKKKTnQYYKKKKMfnifKKKKKThiKKKKKKKWkKKKKKKKKKKKK [test scaled rotate 4 vflip] extend=test scaled rotate 4 flags=ALLEGRO_FLIP_VERTICAL hash=055000e8 sig=NSTPVQYDjMHQMTVWYnGKJKOJPXVFHOOQJKNKKGMONQMKKKKKSOPMKKKKKINNKKKKKKKONKKKKKKKKKKKK [test scaled rotate 4 hflip] extend=test scaled rotate 4 flags=ALLEGRO_FLIP_HORIZONTAL hash=59ba09c8 sig=mbfcaSMKOieel/TMNNQihgcHMONOYfi//DNKLbgclyqKKKLdhcnmKKKKKiflKKKKKKLlhKKKKKKKLKKKK [test scaled rotate 4 vhflip] extend=test scaled rotate 4 flags=ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL hash=e3236edd sig=NVTZGmClnNRYXVf/ClGPUTPRsDhGJQSLMNlKKKMKNLOKKKKMLNNNKKKKKLLNKKKKKKKNNKKKKKKKKKKKK [test scaled rotate 5] extend=test scaled rotate xscale=200 yscale=3.0 theta=-2 # It is known that the sw version is slightly offset from the hw version. hash=e941f051 sig=LXnQfPMOMKTkQXUGJLKRjmYGKJOKKXnUfQKNKKTkQXVJJKKRjnYCHJKKKYneaQLKKKTkQXWJKKKQimYDN [test sub src] op0=al_clear_to_color(teal) op1=b = al_create_sub_bitmap(allegro, 3, 40, 310, 70) op2=al_draw_bitmap(b, 50, 50, flags) op3=al_draw_rectangle(49.5, 49.5, 360.5, 120.5, black, 1) flags=0 hash=ec890555 [test sub src hflip] extend=test sub src flags=ALLEGRO_FLIP_HORIZONTAL hash=8862d735 sig=QNOQQLLLLDGbSVLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL [test sub src outside] op0=al_clear_to_color(teal) op1=al_draw_rectangle(9.5, 9.5, 380.5, 260.5, black, 1) op2=b = al_create_sub_bitmap(allegro, -50, -50, 370, 250) op3=al_draw_bitmap(b, 10, 10, flags) flags=0 hash=208f7025 [test sub src outside hflip] extend=test sub src outside flags=ALLEGRO_FLIP_HORIZONTAL hash=c72f2d45 [test sub src outside vflip] extend=test sub src outside flags=ALLEGRO_FLIP_VERTICAL hash=287e0fbd [test sub src outside vhflip] extend=test sub src outside flags=ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL hash=4696783d [test sub src outside scale] op0=al_clear_to_color(teal) op1=b = al_create_sub_bitmap(allegro, -50, -50, 370, 250) op2=al_draw_rectangle(9.5, 9.5, 610.5, 410.5, black, 1) op3=al_draw_scaled_bitmap(b, 0, 0, 370, 250, 10, 10, 600, 400, flags) flags=0 hash=ac298a45 sig=LLLLLLLLLLTNKKNXbkLmnkkffVhLnNOhcv/zLKZPaepcOLKNKZYYNOLMNMMOSOOLONIHHKLNLLLLLLLLL [test sub src outside scale hflip] extend=test sub src outside scale flags=ALLEGRO_FLIP_HORIZONTAL hash=898f5e8d sig=LLLLLLLLLjcRKKKRWLYYheknnjLW/P+UWYkLQ/qgPaRRLLQWZXQJKLNRQOKONQLLMIFGOKNLLLLLLLLLL [test sub src outside scale vflip] extend=test sub src outside scale flags=ALLEGRO_FLIP_VERTICAL hash=762b67d5 sig=LMPLHHMLMLQMHJSWNNLLPMZXYSNLMdMjbdLDLcbOmfgkmLjhTQReegLLLLLLLLLLLLLLLLLLLLLLLLLLL [test sub src outside scale vhflip] extend=test sub src outside scale flags=ALLEGRO_FLIP_HORIZONTAL|ALLEGRO_FLIP_VERTICAL hash=7c95685d sig=LNJGGONOLNNVMMGKPLMUfdWRKJLh/hcUaYVLmkekXhYjLfeYVPYjkLLLLLLLLLLLLLLLLLLLLLLLLLLLL [test sub dest] op0=b = al_create_sub_bitmap(target, 35, 37, 103, 104) op1=al_set_target_bitmap(b) op2=al_draw_bitmap(allegro, 0, 0, 0) hash=1127286c [test sub dest pixel] op0=b = al_create_sub_bitmap(target, 35, 37, 103, 104) op1=al_set_target_bitmap(b) op2=al_draw_pixel(0.5, 0.5, red) op3=al_put_pixel(1, 0, limegreen) op4=al_draw_pixel(14.5, 17.5, red) op5=al_put_pixel(15, 17, limegreen) op6=al_draw_pixel(24.5, 27.5, red) op7=al_put_pixel(25, 27, limegreen) hash=b4d84cb9 hash_hw=663b41cf sig_hw=000000000000000000000000000000000000000000000000000000000000000000000000000000000 [test subsub dest] op0=al_clear_to_color(tan) op1=b1 = al_create_sub_bitmap(target, 70, 90, 200, 200) op2=al_set_target_bitmap(b1) op3=al_clear_to_color(seagreen) op4=b2 = al_create_sub_bitmap(b1, -50, -50, 200, 200) op5=al_set_target_bitmap(b2) op6=al_clear_to_color(royalblue) op7=al_draw_bitmap(allegro, 10, 10, 0) hash=066a6e10 [test sub transform] op0=al_clear_to_color(teal) op1=b = al_create_sub_bitmap(mysha, 160, 0, 160, 200) op2=al_translate_transform(Tt, -80, 0) op3=al_use_transform(Tt) op4=al_draw_bitmap(b, 320, 10, flags) op5=al_use_transform(Ti) op6=al_draw_line(320.5, 0, 320.5, 480, #ffffff, 1) flags=0 hash=945d520b sig=LLLZLCLLLLLLPLDLLLLLLMLDLLLLLL2A2LLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLL [test sub transform hflip] extend=test sub transform flags=ALLEGRO_FLIP_HORIZONTAL hash=ee8a23a0 sig=LLLCLZLLLLLLDLPLLLLLLDLMLLLLLL2A2LLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLL [test sub transform vflip] extend=test sub transform flags=ALLEGRO_FLIP_VERTICAL hash=9290db87 sig=LLL2B1LLLLLLKLDLLLLLLVLCLLLLLLEKCLLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLL [test sub transform vhflip] extend=test sub transform flags=ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL hash=d43a7e7c sig=LLL1A2LLLLLLDLLLLLLLLCLVLLLLLLCKELLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLL [test region transform] op0=al_clear_to_color(teal) op1=al_translate_transform(Tt, -80, 0) op2=al_use_transform(Tt) op3=al_draw_bitmap_region(mysha, 160, 0, 160, 200, 320, 10, flags) op4=al_use_transform(Ti) op5=al_draw_line(320.5, 0, 320.5, 480, #ffffff, 1) flags=0 hash=945d520b sig=LLLZLCLLLLLLPLDLLLLLLMLDLLLLLL2A2LLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLL [test region transform hflip] extend=test region transform flags=ALLEGRO_FLIP_HORIZONTAL hash=ee8a23a0 sig=LLLCLZLLLLLLDLPLLLLLLDLMLLLLLL2A2LLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLL [test region transform vflip] extend=test region transform flags=ALLEGRO_FLIP_VERTICAL hash=9290db87 sig=LLL2B1LLLLLLKLDLLLLLLVLCLLLLLLEKCLLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLL [test region transform vhflip] extend=test region transform flags=ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL hash=d43a7e7c sig=LLL1A2LLLLLLDLLLLLLLLCLVLLLLLLCKELLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLLLLLLRLLLL [test transform compose] op0=al_translate_transform(Tt, 200, 50) op1=al_use_transform(Tt) op2=al_draw_bitmap(allegro, 0, 0, 0) op3=al_rotate_transform(Tr, 0.5) op4=al_use_transform(Tr) op5=al_draw_bitmap(mysha, 0, 0, 0) op6=al_scale_transform(T, 1.5, 0.7) op7=al_compose_transform(T, Tr) op8=al_compose_transform(T, Tt) op9=al_use_transform(T) op10=al_draw_bitmap(allegro, 0, 0, 0) hash=e1c88814 sig=E0075AAD0wElcvfjm0pYKUlWto0LLKKZnPM02CEHKZNe002100JZPl000000MNV000000000000000000 [test transform per bitmap] op0=al_clear_to_color(gray) op1=al_build_transform(T1, 200, 50, 1, 1, -0.333) op2=al_use_transform(T1) op3=sub = al_create_sub_bitmap(target, 30, 150, 400, 300) op4=al_set_target_bitmap(sub) op5=al_clear_to_color(azure) op6=al_build_transform(Tsub, 0, 0, 1.5, 1.5, 0.5) op7=al_use_transform(Tsub) op8=al_draw_bitmap(mysha, 0, 0, 0) op9=al_set_target_bitmap(target) op10=al_draw_bitmap(allegro, 0, 0, 0) hash=341b718b sig=WWWVngLbWWWWBUUaNWWWWJNKLLWE++POGWWWFEP+++WWWmtEE++WWWqvlFD+WWWjaPQECWWWVLKPDCWWW allegro5-5.2.10.1/tests/test_bitmaps2.ini000066400000000000000000000073521473414355200201120ustar00rootroot00000000000000# Test al_draw_tinted_bitmap et al. [bitmaps] mysha=../examples/data/mysha.pcx allegro=../examples/data/allegro.pcx [test tint blit] op0=al_clear_to_color(red) op1=al_draw_tinted_bitmap(mysha, #ccaa44, 37, 47, flags) flags=0 hash=706d8440 sig=BBBBALLLL8LS77LLLL9UID7LLLL9MB37LLLL11211LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL [test tint region] op0=al_clear_to_color(red) op1=al_draw_tinted_bitmap_region(mysha, #ccaa44, 111, 51, 77, 99, 37, 47, flags) flags=0 hash=1faa6d4d sig=SLLLLLLLLBLLLLLLLLFLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL [test tint scale min] op0=al_clear_to_color(red) op1=al_draw_tinted_scaled_bitmap(mysha, #ccaa44, 0, 0, 320, 200, 11, 17, 77, 99, flags) flags=0 hash=742e9335 sig=8LLLLLLLL1LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL [test tint scale max] op0=al_clear_to_color(blue) op1=al_draw_tinted_scaled_bitmap(mysha, #ccaa44, 0, 0, 320, 200, 11, 17, 611, 415, flags) flags=0 hash=c09b38b8 sig=777777776789D977778BQVNL7779XWUHL8779WLOEEB779SOGBC87728KDBD57711122A111CCCCCCCCC [test tint rotate] op0=al_clear_to_color(purple) op1=al_draw_tinted_rotated_bitmap(allegro, #88aa44, 50, 50, 320, 240, theta, flags) op2=al_draw_pixel(320, 240, cyan) theta=-1.0 hash=da5afb88 sig=LLLLLJNALLLLLLHLBBLLLLGNHDLLLLLEKL8LLLLKGDALLLLLLHABLLLLLLLCLLLLLLLLLLLLLLLLLLLLL [test tint scaled rotate] op0=al_clear_to_color(firebrick) op1=al_draw_tinted_scaled_rotated_bitmap(allegro, #88aa44, 50, 50, 320, 240, xscale, yscale, theta, flags) op2=al_draw_pixel(320, 240, cyan) xscale=0.25 yscale=0.25 theta=0.7854 flags=0 hash=3f12b882 sig=KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK8KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK [test tint transform compose] op0=al_translate_transform(Tt, 200, 50) op1=al_use_transform(Tt) op2=al_draw_tinted_bitmap(allegro, #aa0000, 0, 0, 0) op3=al_rotate_transform(Tr, 0.5) op4=al_use_transform(Tr) op5=al_draw_tinted_bitmap(mysha, #00aa00, 0, 0, 0) op6=al_scale_transform(T, 1.5, 0.7) op7=al_compose_transform(T, Tr) op8=al_compose_transform(T, Tt) op9=al_use_transform(T) op10=al_draw_tinted_bitmap(allegro, #0000aa, 0, 0, 0) hash=68ba872b sig=200112220C2A9DCCB0B642AAEB044433A53002234006000000300A000000557000000000000000000 [test al_draw_tinted_scaled_rotated_bitmap_region] op0=al_draw_tinted_scaled_rotated_bitmap_region(mysha, 80, 50, 160, 100, #8080ff, 0, 0, 320, 240, 1.41, 1.41, -0.78, 0) op1=al_draw_tinted_scaled_rotated_bitmap_region(mysha, 80, 50, 160, 100, #8080ff, 60, 0, 320, 240, 1.41, 1.41, 0.78, 0) hash=7669c5a4 sig=000000000000000000000000PF0000R0YIE0000dPcMD000ROMYD00000EH90000000A0000000090000 [test horizontal shear] op0=al_horizontal_shear_transform(T1, -0.5) op1=al_use_transform(T1) op2=al_draw_scaled_bitmap(mysha, 0, 0, 320, 200, 0, 0, 64, 128, 0) op3=al_translate_transform(T2, 64, 0) op4=al_horizontal_shear_transform(T2, -0.5) op5=al_use_transform(T2) op6=al_draw_scaled_bitmap(mysha, 0, 0, 320, 200, 0, 0, 64, 64, 0) op7=al_translate_transform(T3, 64, 64) op8=al_horizontal_shear_transform(T3, -0.5) op9=al_use_transform(T3) op10=al_draw_scaled_bitmap(mysha, 0, 0, 320, 200, 0, 0, 64, 64, 0) hash=380bb87f sig=YF0000000Rt0000000000000000000000000000000000000000000000000000000000000000000000 [test vertical shear] op0=al_vertical_shear_transform(T1, 0.5) op1=al_use_transform(T1) op2=al_draw_scaled_bitmap(mysha, 0, 0, 320, 200, 0, 0, 64, 128, 0) op3=al_translate_transform(T2, 64, 0) op4=al_vertical_shear_transform(T2, 0.5) op5=al_use_transform(T2) op6=al_draw_scaled_bitmap(mysha, 0, 0, 320, 200, 0, 0, 64, 64, 0) op7=al_translate_transform(T3, 64, 64) op8=al_vertical_shear_transform(T3, 0.5) op9=al_use_transform(T3) op10=al_draw_scaled_bitmap(mysha, 0, 0, 320, 200, 0, 0, 64, 64, 0) hash=2af248da sig=D00000000750000000F50000000000000000000000000000000000000000000000000000000000000 allegro5-5.2.10.1/tests/test_blend.ini000066400000000000000000000560101473414355200174500ustar00rootroot00000000000000[bitmaps] allegro=../examples/data/allegro.pcx green=../examples/data/green.png bkg=../examples/data/bkg.png # We can't assume that a backbuffer with alpha is available, so draw # to a temporary bitmap. [template] op0=b = al_create_bitmap(640, 480) op1=al_set_target_bitmap(b) op2=al_draw_tinted_scaled_bitmap(allegro, #aaaaaa80, 0, 0, 320, 200, 0, 0, 640, 480, 0) op3=al_set_blender(mode, src, dst1) op4=al_set_blend_color(#abcdeffe) op5=al_draw_bitmap(green, x, 5, 0) op6=al_set_blender(mode, src, dst2) op7=al_draw_bitmap(green, x, 125, 0) op8=al_set_blender(mode, src, dst3) op9=al_draw_bitmap(green, x, 245, 0) op10=al_set_blender(mode, src, dst4) op11=al_draw_bitmap(green, x, 365, 0) op12=al_set_target_bitmap(target) op13=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO) op14=al_draw_bitmap(bkg, 0, 0, 0) op15=al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ZERO, ALLEGRO_ONE) op16=al_draw_bitmap(b, 0, 0, 0) x=140 [template dst=1,0,a,ia] extend=template dst1=ALLEGRO_ONE dst2=ALLEGRO_ZERO dst3=ALLEGRO_ALPHA dst4=ALLEGRO_INVERSE_ALPHA [template dst=sc,dc,isc,idc] extend=template dst1=ALLEGRO_SRC_COLOR dst2=ALLEGRO_DEST_COLOR dst3=ALLEGRO_INVERSE_SRC_COLOR dst4=ALLEGRO_INVERSE_DEST_COLOR [template dst=cc,icc] extend=template dst1=ALLEGRO_SRC_COLOR dst2=ALLEGRO_DEST_COLOR dst3=ALLEGRO_SRC_COLOR dst4=ALLEGRO_DEST_COLOR #-----------------------------------------------------------------------------# [template mode=ADD dst=1,0,a,ia] extend=template dst=1,0,a,ia mode=ALLEGRO_ADD [test blend mode=ADD src=1 dst=1,0,a,ia] extend=template mode=ADD dst=1,0,a,ia src=ALLEGRO_ONE hash=7bc85f46 sig=GDD9PNGlHJJqJIHHHHEDL3566KLCCH78T6QCBCCBDFHCF9A76MM5bBCAZ66676BBAP7B8ALAABJ8CUBQA [test blend mode=ADD src=0 dst=1,0,a,ia] extend=template mode=ADD dst=1,0,a,ia src=ALLEGRO_ZERO hash=441baf02 sig=GDA9BAGHHJJJJIHHHHED665767LCC676766CBCCBDFHCF9A66A95ABCA866676BBA77A7A6AAB6886B5A [test blend mode=ADD src=a dst=1,0,a,ia] extend=template mode=ADD dst=1,0,a,ia src=ALLEGRO_ALPHA hash=a8d416f9 sig=GDB9NMGlHJJoJIHHHHEDJ5576KLCCH76T6PCBCCBDFHCF9A66LL5bBCAY66676BBAM7A9ALAABI89TBPA [test blend mode=ADD src=ia dst=1,0,a,ia] extend=template mode=ADD dst=1,0,a,ia src=ALLEGRO_INVERSE_ALPHA hash=16223282 sig=GDB9DCGIHJJMJIHHHHED655566LCC676666CBCCBDFHCF9A76BB5ABCA966676BBA87B7A6AAB6896B5A [test blend mode=ADD src=sc dst=1,0,a,ia] extend=template mode=ADD dst=1,0,a,ia src=ALLEGRO_SRC_COLOR hash=f926f4cd sig=GDA9KJGeHJJhJIHHHHEDF5556ELCCB76L6ICBCCBDFHCF9A66II5TBCAR66676BBAH7A7AFAABC89LBIA [test blend mode=ADD src=dc dst=1,0,a,ia] extend=template mode=ADD dst=1,0,a,ia src=ALLEGRO_DEST_COLOR hash=b2630b89 sig=GDA9HGGeHJJjJIHHHHED855568LCC776D68CBCCBDFHCF9A66IH5MBCAE66676BBA87A6A6AAB6885B6A [test blend mode=ADD src=isc dst=1,0,a,ia] extend=template mode=ADD dst=1,0,a,ia src=ALLEGRO_INVERSE_SRC_COLOR hash=1e52eaf0 sig=GDC9FEGLHJJQJIHHHHED655566LCC676766CBCCBDFHCF9A76DC5EBCAC66676BBA97B7A7AAB6896B6A [test blend mode=ADD src=idc dst=1,0,a,ia] extend=template mode=ADD dst=1,0,a,ia src=ALLEGRO_INVERSE_DEST_COLOR hash=fe52c382 sig=GDC9LKGgHJJiJIHHHHED955568LCC87686ACBCCBDFHCF9A76JI5YBCAW66676BBAD7A7ABAABB8AFBCA [test blend mode=ADD src=cc dst=1,0,a,ia] extend=template mode=ADD dst=1,0,a,ia src=ALLEGRO_CONST_COLOR hash=4ee1eaca sig=GDC9OMGkHJJoJIHHHHEDH3556GLCCE77N6KCBCCBDFHCF9A76LL5ZBCAW66676BBAK7B8AHAABG8BOBLA [test blend mode=ADD src=icc dst=1,0,a,ia] extend=template mode=ADD dst=1,0,a,ia src=ALLEGRO_INVERSE_CONST_COLOR hash=83ed9c53 sig=GDA9CBGJHJJMJIHHHHED665767LCC676766CBCCBDFHCF9A66BA5DBCAA66676BBA87A7A7AAB6886B5A #-----------------------------------------------------------------------------# [template mode=ADD dst=sc,dc,isc,idc] extend=template dst=sc,dc,isc,idc mode=ALLEGRO_ADD [test blend mode=ADD src=1 dst=sc,dc,isc,idc] extend=template mode=ADD dst=sc,dc,isc,idc src=ALLEGRO_ONE hash=0ce01bb8 sig=GD76AA6VHJJZ66676HEDV6AG7YLCCT6Dn8ZCBCCBDFIDF9ACCPPDYBCAXCCEFABBAU98E7TAABR7Ca8YA [test blend mode=ADD src=0 dst=sc,dc,isc,idc] extend=template mode=ADD dst=sc,dc,isc,idc src=ALLEGRO_ZERO hash=90e041ac sig=GD664468HJJA66676HED869879LCC867C88CBCCBDFIDF9AAC88D5BCA6CCEFABBA878878AAB777787A [test blend mode=ADD src=a dst=sc,dc,isc,idc] extend=template mode=ADD dst=sc,dc,isc,idc src=ALLEGRO_ALPHA hash=a2c1dee3 sig=GD66BA6VHJJY66676HEDS69F7XLCCR6An8ZCBCCBDFIDF9AACMMDXBCAUCCEFABBAS88D7SAABQ79a8YA [test blend mode=ADD src=ia dst=sc,dc,isc,idc] extend=template mode=ADD dst=sc,dc,isc,idc src=ALLEGRO_INVERSE_ALPHA hash=597e5032 sig=GD763369HJJC66676HED96A97ALCC969D88CBCCBDFIDF9ABCAAD6BCA7CCEFABBA988978AAB878787A [test blend mode=ADD src=sc dst=sc,dc,isc,idc] extend=template mode=ADD dst=sc,dc,isc,idc src=ALLEGRO_SRC_COLOR hash=901f4244 sig=GD66776NHJJR66676HEDN69D7RLCCM69f8RCBCCBDFIDF9AACJJDQBCAOCCEFABBAN88C7MAABK78S8QA [test blend mode=ADD src=dc dst=sc,dc,isc,idc] extend=template mode=ADD dst=sc,dc,isc,idc src=ALLEGRO_DEST_COLOR hash=b80bdb24 sig=GD66556OHJJS66676HEDI6AC7LLCCH69a8JCBCCBDFIDF9AACEEDBBCA8CCEFABBAE88A7DAABC77B8EA [test blend mode=ADD src=isc dst=sc,dc,isc,idc] extend=template mode=ADD dst=sc,dc,isc,idc src=ALLEGRO_INVERSE_SRC_COLOR hash=020d43da sig=GD76556CHJJF66676HEDB6AA7CLCCB69F8ACBCCBDFIDF9ABCBBD6BCA8CCEFABBAB8897AAABA79989A [test blend mode=ADD src=idc dst=sc,dc,isc,idc] extend=template mode=ADD dst=sc,dc,isc,idc src=ALLEGRO_INVERSE_DEST_COLOR hash=2349d015 sig=GD76996QHJJS66676HEDI6AC7LLCCH6AU8MCBCCBDFIDF9ABCFEDGBCAICCEFABBAL88B7KAABJ79Q8OA [test blend mode=ADD src=cc dst=sc,dc,isc,idc] extend=template mode=ADD dst=sc,dc,isc,idc src=ALLEGRO_CONST_COLOR hash=d2c79eaa sig=GD76996THJJX66676HEDT6AF7WLCCR6Cl8XCBCCBDFIDF9ACCNNDTBCASCCEFABBAS98E7RAABP7BX8WA [test blend mode=ADD src=icc dst=sc,dc,isc,idc] extend=template mode=ADD dst=sc,dc,isc,idc src=ALLEGRO_INVERSE_CONST_COLOR hash=5f617039 sig=GD66556BHJJD66676HED96987ALCC967E89CBCCBDFIDF9AAC88D6BCA7CCEFABBA978879AAB877888A #-----------------------------------------------------------------------------# [template mode=ADD dst=cc,icc] extend=template dst=cc,icc mode=ALLEGRO_ADD [test blend mode=ADD src=1 dst=cc,icc] extend=template mode=ADD dst=cc,icc src=ALLEGRO_ONE hash=65dca8dc sig=GD76AA6VHJJZ66676HEDV6AG7YLCCT6Dn8ZCBCCBDFIDF9A76BB5TBCAV66676BBAP4685NAABL59V6SA [test blend mode=ADD src=0 dst=cc,icc] extend=template mode=ADD dst=cc,icc src=ALLEGRO_ZERO hash=182efe77 sig=GD664468HJJA66676HED869879LCC867C88CBCCBDFIDF9A665556BCA666676BBA656656AAB555565A [test blend mode=ADD src=a dst=cc,icc] extend=template mode=ADD dst=cc,icc src=ALLEGRO_ALPHA hash=8272bd59 sig=GD66BA6VHJJY66676HEDS69F7XLCCR6An8ZCBCCBDFIDF9A66BB5TBCAT66676BBAO5685NAABK57V6SA [test blend mode=ADD src=ia dst=cc,icc] extend=template mode=ADD dst=cc,icc src=ALLEGRO_INVERSE_ALPHA hash=6202d315 sig=GD763369HJJC66676HED96A97ALCC969D88CBCCBDFIDF9A764456BCA666676BBA746556AAB556565A [test blend mode=ADD src=sc dst=cc,icc] extend=template mode=ADD dst=cc,icc src=ALLEGRO_SRC_COLOR hash=0a7aa6df sig=GD66776NHJJR66676HEDN69D7RLCCM69f8RCBCCBDFIDF9A66885LBCAN66676BBAI5665GAABE56N6KA [test blend mode=ADD src=dc dst=cc,icc] extend=template mode=ADD dst=cc,icc src=ALLEGRO_DEST_COLOR hash=a314996a sig=GD66556OHJJS66676HEDI6AC7LLCCH69a8JCBCCBDFIDF9A66885EBCAA66676BBA956658AAB755668A [test blend mode=ADD src=isc dst=cc,icc] extend=template mode=ADD dst=cc,icc src=ALLEGRO_INVERSE_SRC_COLOR hash=81205c32 sig=GD76556CHJJF66676HEDB6AA7CLCCB69F8ACBCCBDFIDF9A76665ABCAA66676BBA846657AAB756767A [test blend mode=ADD src=idc dst=cc,icc] extend=template mode=ADD dst=cc,icc src=ALLEGRO_INVERSE_DEST_COLOR hash=3c6243b3 sig=GD76996QHJJS66676HEDI6AC7LLCCH6AU8MCBCCBDFIDF9A76995QBCAR66676BBAG5675FAABE57L6IA [test blend mode=ADD src=cc dst=cc,icc] extend=template mode=ADD dst=cc,icc src=ALLEGRO_CONST_COLOR hash=15e071c8 sig=GD76996THJJX66676HEDT6AF7WLCCR6Cl8XCBCCBDFIDF9A76AA5RBCAS66676BBAM4675KAABH58Q6OA [test blend mode=ADD src=icc dst=cc,icc] extend=template mode=ADD dst=cc,icc src=ALLEGRO_INVERSE_CONST_COLOR hash=de752105 sig=GD66556BHJJD66676HED96987ALCC967E89CBCCBDFIDF9A666659BCA866676BBA756657AAB655666A #-----------------------------------------------------------------------------# [template mode=DEST_MINUS_SRC dst=1,0,a,ia] extend=template dst=1,0,a,ia mode=ALLEGRO_DEST_MINUS_SRC [test blend mode=DEST_MINUS_SRC src=1 dst=1,0,a,ia] extend=template mode=DEST_MINUS_SRC dst=1,0,a,ia src=ALLEGRO_ONE hash=2e819fcc sig=GD9966G6HJJ7JIHHHHED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA76A7A7AAB6886B6A [test blend mode=DEST_MINUS_SRC src=0 dst=1,0,a,ia] extend=template mode=DEST_MINUS_SRC dst=1,0,a,ia src=ALLEGRO_ZERO hash=441baf02 sig=GDA9BAGHHJJJJIHHHHED665767LCC676766CBCCBDFHCF9A66A95ABCA866676BBA77A7A6AAB6886B5A [test blend mode=DEST_MINUS_SRC src=a dst=1,0,a,ia] extend=template mode=DEST_MINUS_SRC dst=1,0,a,ia src=ALLEGRO_ALPHA hash=6fcd619c sig=GD9977G6HJJ7JIHHHHED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA86A7A7AAB6886B6A [test blend mode=DEST_MINUS_SRC src=ia dst=1,0,a,ia] extend=template mode=DEST_MINUS_SRC dst=1,0,a,ia src=ALLEGRO_INVERSE_ALPHA hash=77192dfe sig=GD9998GGHJJHJIHHHHED665767LCC676766CBCCBDFHCF9A66985ABCA766676BBA76A7A7AAB6886B6A [test blend mode=DEST_MINUS_SRC src=sc dst=1,0,a,ia] extend=template mode=DEST_MINUS_SRC dst=1,0,a,ia src=ALLEGRO_SRC_COLOR hash=2dc73562 sig=GD9977G6HJJ7JIHHHHED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA86A7A7AAB6886B6A [test blend mode=DEST_MINUS_SRC src=dc dst=1,0,a,ia] extend=template mode=DEST_MINUS_SRC dst=1,0,a,ia src=ALLEGRO_DEST_COLOR hash=683a8d24 sig=GD9977G6HJJ7JIHHHHED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA86A7A7AAB6886B6A [test blend mode=DEST_MINUS_SRC src=isc dst=1,0,a,ia] extend=template mode=DEST_MINUS_SRC dst=1,0,a,ia src=ALLEGRO_INVERSE_SRC_COLOR hash=c590b4b7 sig=GD9977GCHJJEJIHHHHED665767LCC676766CBCCBDFHCF9A668756BCA566676BBA76A7A7AAB6886B6A [test blend mode=DEST_MINUS_SRC src=idc dst=1,0,a,ia] extend=template mode=DEST_MINUS_SRC dst=1,0,a,ia src=ALLEGRO_INVERSE_DEST_COLOR hash=c0986966 sig=GD9977G6HJJ7JIHHHHED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA76A7A7AAB6886B6A [test blend mode=DEST_MINUS_SRC src=cc dst=1,0,a,ia] extend=template mode=DEST_MINUS_SRC dst=1,0,a,ia src=ALLEGRO_CONST_COLOR hash=38f39dec sig=GD9966G6HJJ7JIHHHHED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA86A7A7AAB6886B6A [test blend mode=DEST_MINUS_SRC src=icc dst=1,0,a,ia] extend=template mode=DEST_MINUS_SRC dst=1,0,a,ia src=ALLEGRO_INVERSE_CONST_COLOR hash=6eb30b02 sig=GDA9A9GEHJJGJIHHHHED665767LCC676766CBCCBDFHCF9A669957BCA566676BBA77A7A7AAB6886B6A #-----------------------------------------------------------------------------# [template mode=DEST_MINUS_SRC dst=sc,dc,isc,idc] extend=template dst=sc,dc,isc,idc mode=ALLEGRO_DEST_MINUS_SRC [test blend mode=DEST_MINUS_SRC src=1 dst=sc,dc,isc,idc] extend=template mode=DEST_MINUS_SRC dst=sc,dc,isc,idc src=ALLEGRO_ONE hash=8b11d273 sig=GD666666HJJ666676HED669777LCC667786CBCCBDFIDF9AAC65D6BCA6CCEFABBA768777AAB677686A [test blend mode=DEST_MINUS_SRC src=0 dst=sc,dc,isc,idc] extend=template mode=DEST_MINUS_SRC dst=sc,dc,isc,idc src=ALLEGRO_ZERO hash=90e041ac sig=GD664468HJJA66676HED869879LCC867C88CBCCBDFIDF9AAC88D5BCA6CCEFABBA878878AAB777787A [test blend mode=DEST_MINUS_SRC src=a dst=sc,dc,isc,idc] extend=template mode=DEST_MINUS_SRC dst=sc,dc,isc,idc src=ALLEGRO_ALPHA hash=b4a2ce11 sig=GD666666HJJ666676HED669777LCC667786CBCCBDFIDF9AAC55D6BCA6CCEFABBA768777AAB677686A [test blend mode=DEST_MINUS_SRC src=ia dst=sc,dc,isc,idc] extend=template mode=DEST_MINUS_SRC dst=sc,dc,isc,idc src=ALLEGRO_INVERSE_ALPHA hash=59fcf94a sig=GD665568HJJA66676HED769778LCC767B88CBCCBDFIDF9AAC55D6BCA6CCEFABBA768777AAB777686A [test blend mode=DEST_MINUS_SRC src=sc dst=sc,dc,isc,idc] extend=template mode=DEST_MINUS_SRC dst=sc,dc,isc,idc src=ALLEGRO_SRC_COLOR hash=861e7e3e sig=GD666666HJJ666676HED669777LCC667786CBCCBDFIDF9AAC55D6BCA6CCEFABBA768777AAB677686A [test blend mode=DEST_MINUS_SRC src=dc dst=sc,dc,isc,idc] extend=template mode=DEST_MINUS_SRC dst=sc,dc,isc,idc src=ALLEGRO_DEST_COLOR hash=d0317d02 sig=GD666666HJJ666676HED669777LCC667786CBCCBDFIDF9AAC55D6BCA6CCEFABBA768777AAB677686A [test blend mode=DEST_MINUS_SRC src=isc dst=sc,dc,isc,idc] extend=template mode=DEST_MINUS_SRC dst=sc,dc,isc,idc src=ALLEGRO_INVERSE_SRC_COLOR hash=6d493d98 sig=GD664466HJJ866676HED669777LCC667A87CBCCBDFIDF9AAC55D6BCA6CCEFABBA668776AAB677585A [test blend mode=DEST_MINUS_SRC src=idc dst=sc,dc,isc,idc] extend=template mode=DEST_MINUS_SRC dst=sc,dc,isc,idc src=ALLEGRO_INVERSE_DEST_COLOR hash=18079776 sig=GD666666HJJ666676HED669777LCC667786CBCCBDFIDF9AAC55D6BCA6CCEFABBA768777AAB677686A [test blend mode=DEST_MINUS_SRC src=cc dst=sc,dc,isc,idc] extend=template mode=DEST_MINUS_SRC dst=sc,dc,isc,idc src=ALLEGRO_CONST_COLOR hash=ed43510b sig=GD666666HJJ666676HED669777LCC667786CBCCBDFIDF9AAC65D6BCA6CCEFABBA768777AAB677686A [test blend mode=DEST_MINUS_SRC src=icc dst=sc,dc,isc,idc] extend=template mode=DEST_MINUS_SRC dst=sc,dc,isc,idc src=ALLEGRO_INVERSE_CONST_COLOR hash=c347651f sig=GD663366HJJ866676HED769878LCC767A86CBCCBDFIDF9AAC88D6BCA6CCEFABBA778877AAB676585A #-----------------------------------------------------------------------------# [template mode=DEST_MINUS_SRC dst=cc,icc] extend=template dst=cc,icc mode=ALLEGRO_DEST_MINUS_SRC [test blend mode=DEST_MINUS_SRC src=1 dst=cc,icc] extend=template mode=DEST_MINUS_SRC dst=cc,icc src=ALLEGRO_ONE hash=d68bdd68 sig=GD666666HJJ666676HED669777LCC667786CBCCBDFIDF9A666556BCA666676BBA766757AAB655666A [test blend mode=DEST_MINUS_SRC src=0 dst=cc,icc] extend=template mode=DEST_MINUS_SRC dst=cc,icc src=ALLEGRO_ZERO hash=182efe77 sig=GD664468HJJA66676HED869879LCC867C88CBCCBDFIDF9A665556BCA666676BBA656656AAB555565A [test blend mode=DEST_MINUS_SRC src=a dst=cc,icc] extend=template mode=DEST_MINUS_SRC dst=cc,icc src=ALLEGRO_ALPHA hash=cb2229b3 sig=GD666666HJJ666676HED669777LCC667786CBCCBDFIDF9A666556BCA666676BBA766757AAB655666A [test blend mode=DEST_MINUS_SRC src=ia dst=cc,icc] extend=template mode=DEST_MINUS_SRC dst=cc,icc src=ALLEGRO_INVERSE_ALPHA hash=cbb32185 sig=GD665568HJJA66676HED769778LCC767B88CBCCBDFIDF9A666656BCA566676BBA666756AAB655565A [test blend mode=DEST_MINUS_SRC src=sc dst=cc,icc] extend=template mode=DEST_MINUS_SRC dst=cc,icc src=ALLEGRO_SRC_COLOR hash=128074a2 sig=GD666666HJJ666676HED669777LCC667786CBCCBDFIDF9A666556BCA666676BBA766757AAB655666A [test blend mode=DEST_MINUS_SRC src=dc dst=cc,icc] extend=template mode=DEST_MINUS_SRC dst=cc,icc src=ALLEGRO_DEST_COLOR hash=07b128cd sig=GD666666HJJ666676HED669777LCC667786CBCCBDFIDF9A666556BCA666676BBA766757AAB655666A [test blend mode=DEST_MINUS_SRC src=isc dst=cc,icc] extend=template mode=DEST_MINUS_SRC dst=cc,icc src=ALLEGRO_INVERSE_SRC_COLOR hash=3704cd4c sig=GD664466HJJ866676HED669777LCC667A87CBCCBDFIDF9A665555BCA566676BBA666756AAB555564A [test blend mode=DEST_MINUS_SRC src=idc dst=cc,icc] extend=template mode=DEST_MINUS_SRC dst=cc,icc src=ALLEGRO_INVERSE_DEST_COLOR hash=6df57d07 sig=GD666666HJJ666676HED669777LCC667786CBCCBDFIDF9A666556BCA666676BBA766757AAB655666A [test blend mode=DEST_MINUS_SRC src=cc dst=cc,icc] extend=template mode=DEST_MINUS_SRC dst=cc,icc src=ALLEGRO_CONST_COLOR hash=66a06ce3 sig=GD666666HJJ666676HED669777LCC667786CBCCBDFIDF9A666556BCA666676BBA766757AAB655666A [test blend mode=DEST_MINUS_SRC src=icc dst=cc,icc] extend=template mode=DEST_MINUS_SRC dst=cc,icc src=ALLEGRO_INVERSE_CONST_COLOR hash=1222ba8b sig=GD663366HJJ866676HED769878LCC767A86CBCCBDFIDF9A664454BCA466676BBA556655AAB555464A #-----------------------------------------------------------------------------# [template mode=SRC_MINUS_DEST dst=1,0,a,ia] extend=template dst=1,0,a,ia mode=ALLEGRO_SRC_MINUS_DEST [test blend mode=SRC_MINUS_DEST src=1 dst=1,0,a,ia] extend=template mode=SRC_MINUS_DEST dst=1,0,a,ia src=ALLEGRO_ONE hash=2a79c7ac sig=GD666667HJJ766676HEDL3566KLCCH78T6QCBCCBDFHCF9A665559BCAC66676BBAL5775KAABH67T7PA [test blend mode=SRC_MINUS_DEST src=0 dst=1,0,a,ia] extend=template mode=SRC_MINUS_DEST dst=1,0,a,ia src=ALLEGRO_ZERO hash=82bce5d4 sig=GD666666HJJ666676HED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA767757AAB666676A [test blend mode=SRC_MINUS_DEST src=a dst=1,0,a,ia] extend=template mode=SRC_MINUS_DEST dst=1,0,a,ia src=ALLEGRO_ALPHA hash=98761b88 sig=GD666667HJJ766676HEDJ5576KLCCH76T6PCBCCBDFHCF9A666659BCAB66676BBAJ6785KAABG67S7PA [test blend mode=SRC_MINUS_DEST src=ia dst=1,0,a,ia] extend=template mode=SRC_MINUS_DEST dst=1,0,a,ia src=ALLEGRO_INVERSE_ALPHA hash=5bc32bdb sig=GD666666HJJ666676HED655566LCC676666CBCCBDFHCF9A666556BCA666676BBA767757AAB666676A [test blend mode=SRC_MINUS_DEST src=sc dst=1,0,a,ia] extend=template mode=SRC_MINUS_DEST dst=1,0,a,ia src=ALLEGRO_SRC_COLOR hash=bebf46ff sig=GD666667HJJ766676HEDF5556ELCCB76L6ICBCCBDFHCF9A665558BCAA66676BBAF6765EAABB66L7IA [test blend mode=SRC_MINUS_DEST src=dc dst=1,0,a,ia] extend=template mode=SRC_MINUS_DEST dst=1,0,a,ia src=ALLEGRO_DEST_COLOR hash=721318ba sig=GD666666HJJ666676HED855568LCC776D68CBCCBDFHCF9A666556BCA666676BBA767656AAB666576A [test blend mode=SRC_MINUS_DEST src=isc dst=1,0,a,ia] extend=template mode=SRC_MINUS_DEST dst=1,0,a,ia src=ALLEGRO_INVERSE_SRC_COLOR hash=b3cf8aac sig=GD666666HJJ666676HED655566LCC676766CBCCBDFHCF9A666556BCA666676BBA767757AAB666676A [test blend mode=SRC_MINUS_DEST src=idc dst=1,0,a,ia] extend=template mode=SRC_MINUS_DEST dst=1,0,a,ia src=ALLEGRO_INVERSE_DEST_COLOR hash=0793889c sig=GD666666HJJ666676HED955568LCC87686ACBCCBDFHCF9A666556BCA666676BBAB6775BAABA67F7CA [test blend mode=SRC_MINUS_DEST src=cc dst=1,0,a,ia] extend=template mode=SRC_MINUS_DEST dst=1,0,a,ia src=ALLEGRO_CONST_COLOR hash=8d0c7f68 sig=GD665565HJJ666676HEDH3556GLCCE77N6KCBCCBDFHCF9A665457BCAA66676BBAH5765GAABD67N7KA [test blend mode=SRC_MINUS_DEST src=icc dst=1,0,a,ia] extend=template mode=SRC_MINUS_DEST dst=1,0,a,ia src=ALLEGRO_INVERSE_CONST_COLOR hash=82bce5d4 sig=GD666666HJJ666676HED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA767757AAB666676A #-----------------------------------------------------------------------------# [template mode=SRC_MINUS_DEST dst=sc,dc,isc,idc] extend=template dst=sc,dc,isc,idc mode=ALLEGRO_SRC_MINUS_DEST [test blend mode=SRC_MINUS_DEST src=1 dst=sc,dc,isc,idc] extend=template mode=SRC_MINUS_DEST dst=sc,dc,isc,idc src=ALLEGRO_ONE hash=a5bc2ba0 sig=GD666669HJJA66676HEDB55569LCC97696ECBCCBDFHCF9A66885IBCAM66676BBAC5755BAAB967H7DA [test blend mode=SRC_MINUS_DEST src=0 dst=sc,dc,isc,idc] extend=template mode=SRC_MINUS_DEST dst=sc,dc,isc,idc src=ALLEGRO_ZERO hash=82bce5d4 sig=GD666666HJJ666676HED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA767757AAB666676A [test blend mode=SRC_MINUS_DEST src=a dst=sc,dc,isc,idc] extend=template mode=SRC_MINUS_DEST dst=sc,dc,isc,idc src=ALLEGRO_ALPHA hash=eda1ec1b sig=GD667769HJJ966676HEDA65769LCC97696ECBCCBDFHCF9A66985IBCAL66676BBAB6765BAAB966G7DA [test blend mode=SRC_MINUS_DEST src=ia dst=sc,dc,isc,idc] extend=template mode=SRC_MINUS_DEST dst=sc,dc,isc,idc src=ALLEGRO_INVERSE_ALPHA hash=33a0483e sig=GD666666HJJ666676HED665767LCC676766CBCCBDFHCF9A665555BCA666676BBA767757AAB666676A [test blend mode=SRC_MINUS_DEST src=sc dst=sc,dc,isc,idc] extend=template mode=SRC_MINUS_DEST dst=sc,dc,isc,idc src=ALLEGRO_SRC_COLOR hash=fb2978c6 sig=GD666667HJJ766676HED965669LCC77696BCBCCBDFHCF9A66775FBCAG66676BBAA67659AAB866D7BA [test blend mode=SRC_MINUS_DEST src=dc dst=sc,dc,isc,idc] extend=template mode=SRC_MINUS_DEST dst=sc,dc,isc,idc src=ALLEGRO_DEST_COLOR hash=5a1c8feb sig=GD666666HJJ666676HED665666LCC675666CBCCBDFHCF9A665555BCA566676BBA667655AAB566574A [test blend mode=SRC_MINUS_DEST src=isc dst=sc,dc,isc,idc] extend=template mode=SRC_MINUS_DEST dst=sc,dc,isc,idc src=ALLEGRO_INVERSE_SRC_COLOR hash=612ad8c8 sig=GD666666HJJ666676HED665767LCC676766CBCCBDFHCF9A665555BCA666676BBA767757AAB666676A [test blend mode=SRC_MINUS_DEST src=idc dst=sc,dc,isc,idc] extend=template mode=SRC_MINUS_DEST dst=sc,dc,isc,idc src=ALLEGRO_INVERSE_DEST_COLOR hash=77b28a0b sig=GD666666HJJ666676HED665666LCC676567CBCCBDFHCF9A666659BCAC66676BBA767757AAB766876A [test blend mode=SRC_MINUS_DEST src=cc dst=sc,dc,isc,idc] extend=template mode=SRC_MINUS_DEST dst=sc,dc,isc,idc src=ALLEGRO_CONST_COLOR hash=70d42cc2 sig=GD665667HJJ766676HED955567LCC77666BCBCCBDFHCF9A66775FBCAH66676BBA957558AAB766D79A [test blend mode=SRC_MINUS_DEST src=icc dst=sc,dc,isc,idc] extend=template mode=SRC_MINUS_DEST dst=sc,dc,isc,idc src=ALLEGRO_INVERSE_CONST_COLOR hash=82bce5d4 sig=GD666666HJJ666676HED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA767757AAB666676A #-----------------------------------------------------------------------------# [template mode=SRC_MINUS_DEST dst=cc,icc] extend=template dst=cc,icc mode=ALLEGRO_SRC_MINUS_DEST [test blend mode=SRC_MINUS_DEST src=1 dst=cc,icc] extend=template mode=SRC_MINUS_DEST dst=cc,icc src=ALLEGRO_ONE hash=ec7a13cf sig=GD666669HJJA66676HEDB55569LCC97696ECBCCBDFHCF9A66665CBCAE66676BBAF5765FAABD67M7IA [test blend mode=SRC_MINUS_DEST src=0 dst=cc,icc] extend=template mode=SRC_MINUS_DEST dst=cc,icc src=ALLEGRO_ZERO hash=82bce5d4 sig=GD666666HJJ666676HED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA767757AAB666676A [test blend mode=SRC_MINUS_DEST src=a dst=cc,icc] extend=template mode=SRC_MINUS_DEST dst=cc,icc src=ALLEGRO_ALPHA hash=4176dbb1 sig=GD667769HJJ966676HEDA65769LCC97696ECBCCBDFHCF9A66665CBCAD66676BBAF6775FAABC67L7IA [test blend mode=SRC_MINUS_DEST src=ia dst=cc,icc] extend=template mode=SRC_MINUS_DEST dst=cc,icc src=ALLEGRO_INVERSE_ALPHA hash=8db00872 sig=GD666666HJJ666676HED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA767757AAB666676A [test blend mode=SRC_MINUS_DEST src=sc dst=cc,icc] extend=template mode=SRC_MINUS_DEST dst=cc,icc src=ALLEGRO_SRC_COLOR hash=1bd139f8 sig=GD666667HJJ766676HED965669LCC77696BCBCCBDFHCF9A665558BCAA66676BBAB6765BAAB966G7DA [test blend mode=SRC_MINUS_DEST src=dc dst=cc,icc] extend=template mode=SRC_MINUS_DEST dst=cc,icc src=ALLEGRO_DEST_COLOR hash=ac5b10cc sig=GD666666HJJ666676HED665666LCC675666CBCCBDFHCF9A666556BCA666676BBA667656AAB666575A [test blend mode=SRC_MINUS_DEST src=isc dst=cc,icc] extend=template mode=SRC_MINUS_DEST dst=cc,icc src=ALLEGRO_INVERSE_SRC_COLOR hash=e2a893a6 sig=GD666666HJJ666676HED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA767757AAB666676A [test blend mode=SRC_MINUS_DEST src=idc dst=cc,icc] extend=template mode=SRC_MINUS_DEST dst=cc,icc src=ALLEGRO_INVERSE_DEST_COLOR hash=c7613016 sig=GD666666HJJ666676HED665666LCC676567CBCCBDFHCF9A666556BCA666676BBA867758AAB766A78A [test blend mode=SRC_MINUS_DEST src=cc dst=cc,icc] extend=template mode=SRC_MINUS_DEST dst=cc,icc src=ALLEGRO_CONST_COLOR hash=abe19282 sig=GD665667HJJ766676HED955567LCC77666BCBCCBDFHCF9A665559BCAC66676BBAD5755CAABA67I7EA [test blend mode=SRC_MINUS_DEST src=icc dst=cc,icc] extend=template mode=SRC_MINUS_DEST dst=cc,icc src=ALLEGRO_INVERSE_CONST_COLOR hash=82bce5d4 sig=GD666666HJJ666676HED665767LCC676766CBCCBDFHCF9A666556BCA666676BBA767757AAB666676A #-----------------------------------------------------------------------------# #-----------------------------------------------------------------------------# [test blend bullet] op0=image = al_create_bitmap(180, 160) op1=al_set_target_bitmap(image) op2=al_clear_to_color(#ffffff) op3=al_set_target_bitmap(target) op4=al_clear_to_color(#808080) op5=al_draw_line(10, 10, 190, 10, white, 2) op6=al_set_blender(ALLEGRO_DEST_MINUS_SRC, ALLEGRO_ALPHA, ALLEGRO_ONE) op7=al_draw_bitmap(image, 10, 20, 0) op8=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op9=al_draw_line(10, 190, 190, 190, white, 2) hash=610f2805 allegro5-5.2.10.1/tests/test_blend_target.ini000066400000000000000000000022521473414355200210150ustar00rootroot00000000000000[bitmaps] mysha=../examples/data/mysha.pcx [test basic] op0=t1 = al_create_sub_bitmap(target, 0, 0, 300, 200) op1=t2 = al_create_sub_bitmap(target, 300, 0, 300, 200) op2=al_set_target_bitmap(t1) op3=al_set_bitmap_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO) op4=al_set_target_bitmap(t2) op5=al_set_bitmap_blender(ALLEGRO_ADD, ALLEGRO_SRC_COLOR, ALLEGRO_ZERO) op6=al_set_target_bitmap(target) op7=al_set_target_bitmap(t1) op8=al_draw_bitmap(mysha, 0, 0, 0) op9=al_draw_pixel(116.5, 116.5, #ffffcc) op10=al_put_blended_pixel(132, 132, #ffffcc) op11=al_draw_rectangle(100, 100, 8, 8, #ffffcc, 2) op12=al_set_target_bitmap(t2) op13=al_draw_bitmap(mysha, 0, 0, 0) op14=al_draw_pixel(116.5, 116.5, #ffffcc) op15=al_put_blended_pixel(132, 132, #ffffcc) op16=al_draw_rectangle(100, 100, 8, 8, #ffffcc, 2) hash=252ba460 sig=FtZD39g32vmREBdCA3jLLEIP813222200100000000000000000000000000000000000000000000000 [test reset] op0=al_set_bitmap_blender(ALLEGRO_ADD, ALLEGRO_SRC_COLOR, ALLEGRO_ZERO) op1=al_draw_bitmap(mysha, 0, 0, 0) op2=al_reset_bitmap_blender(mysha) op3=al_draw_bitmap(mysha, 100, 0, 0) hash=f2a787d7 sig=3EanED000oIsWOD000WGfK7E000022422000000000000000000000000000000000000000000000000 allegro5-5.2.10.1/tests/test_ciede2000.ini000066400000000000000000000114061473414355200177370ustar00rootroot00000000000000# test data taken from http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf [fonts] builtin=al_create_builtin_font() [ciede2000] op0=c1 = al_color_lab(l1, a1, b1) op1=c2 = al_color_lab(l2, a2, b2) op2=d = al_color_distance_ciede2000(c1, c2) op3=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA) op4=x=fdif(d, d2000) # we only test if the result is within one percent because we are not # very numerically stable op5=x=fmul(x, 100) op6=x=round(x) op7=al_draw_text(builtin, white, 0, 0, ALLEGRO_ALIGN_LEFT, x); hash=fd053345 sw_only=true [test ciede2000 1] extend=ciede2000 l1=0.500000 a1=0.026772 b1=-0.797751 l2=0.500000 a2=0.000000 b2=-0.827485 d2000=0.020425 [test ciede2000 2] extend=ciede2000 l1=0.500000 a1=0.031571 b1=-0.772803 l2=0.500000 a2=0.000000 b2=-0.827485 d2000=0.028615 [test ciede2000 3] extend=ciede2000 l1=0.500000 a1=0.028361 b1=-0.740200 l2=0.500000 a2=0.000000 b2=-0.827485 d2000=0.034412 [test ciede2000 4] extend=ciede2000 l1=0.500000 a1=-0.013802 b1=-0.842814 l2=0.500000 a2=0.000000 b2=-0.827485 d2000=0.010000 [test ciede2000 5] extend=ciede2000 l1=0.500000 a1=-0.011848 b1=-0.848006 l2=0.500000 a2=0.000000 b2=-0.827485 d2000=0.010000 [test ciede2000 6] extend=ciede2000 l1=0.500000 a1=-0.009009 b1=-0.855211 l2=0.500000 a2=0.000000 b2=-0.827485 d2000=0.010000 [test ciede2000 7] extend=ciede2000 l1=0.500000 a1=0.000000 b1=0.000000 l2=0.500000 a2=-0.010000 b2=0.020000 d2000=0.023669 [test ciede2000 8] extend=ciede2000 l1=0.500000 a1=-0.010000 b1=0.020000 l2=0.500000 a2=0.000000 b2=0.000000 d2000=0.023669 [test ciede2000 9] extend=ciede2000 l1=0.500000 a1=0.024900 b1=-0.000010 l2=0.500000 a2=-0.024900 b2=0.000009 d2000=0.071792 [test ciede2000 10] extend=ciede2000 l1=0.500000 a1=0.024900 b1=-0.000010 l2=0.500000 a2=-0.024900 b2=0.000010 d2000=0.071792 [test ciede2000 11] extend=ciede2000 l1=0.500000 a1=0.024900 b1=-0.000010 l2=0.500000 a2=-0.024900 b2=0.000011 d2000=0.072195 [test ciede2000 12] extend=ciede2000 l1=0.500000 a1=0.024900 b1=-0.000010 l2=0.500000 a2=-0.024900 b2=0.000012 d2000=0.072195 [test ciede2000 13] extend=ciede2000 l1=0.500000 a1=-0.000010 b1=0.024900 l2=0.500000 a2=0.000009 b2=-0.024900 d2000=0.048045 [test ciede2000 14] extend=ciede2000 l1=0.500000 a1=-0.000010 b1=0.024900 l2=0.500000 a2=0.000010 b2=-0.024900 d2000=0.048045 [test ciede2000 15] extend=ciede2000 l1=0.500000 a1=-0.000010 b1=0.024900 l2=0.500000 a2=0.000011 b2=-0.024900 d2000=0.047461 [test ciede2000 16] extend=ciede2000 l1=0.500000 a1=0.025000 b1=0.000000 l2=0.500000 a2=0.000000 b2=-0.025000 d2000=0.043065 [test ciede2000 17] extend=ciede2000 l1=0.500000 a1=0.025000 b1=0.000000 l2=0.730000 a2=0.250000 b2=-0.180000 d2000=0.271492 [test ciede2000 18] extend=ciede2000 l1=0.500000 a1=0.025000 b1=0.000000 l2=0.610000 a2=-0.050000 b2=0.290000 d2000=0.228977 [test ciede2000 19] extend=ciede2000 l1=0.500000 a1=0.025000 b1=0.000000 l2=0.560000 a2=-0.270000 b2=-0.030000 d2000=0.319030 [test ciede2000 20] extend=ciede2000 l1=0.500000 a1=0.025000 b1=0.000000 l2=0.580000 a2=0.240000 b2=0.150000 d2000=0.194535 [test ciede2000 21] extend=ciede2000 l1=0.500000 a1=0.025000 b1=0.000000 l2=0.500000 a2=0.031736 b2=0.005854 d2000=0.010000 [test ciede2000 22] extend=ciede2000 l1=0.500000 a1=0.025000 b1=0.000000 l2=0.500000 a2=0.032972 b2=0.000000 d2000=0.010000 [test ciede2000 23] extend=ciede2000 l1=0.500000 a1=0.025000 b1=0.000000 l2=0.500000 a2=0.018634 b2=0.005757 d2000=0.010000 [test ciede2000 24] extend=ciede2000 l1=0.500000 a1=0.025000 b1=0.000000 l2=0.500000 a2=0.032592 b2=0.003350 d2000=0.010000 [test ciede2000 25] extend=ciede2000 l1=0.602574 a1=-0.340099 b1=0.362677 l2=0.604626 a2=-0.341751 b2=0.394387 d2000=0.012644 [test ciede2000 26] extend=ciede2000 l1=0.630109 a1=-0.310961 b1=-0.058663 l2=0.628187 a2=-0.297946 b2=-0.040864 d2000=0.012630 [test ciede2000 27] extend=ciede2000 l1=0.612901 a1=0.037196 b1=-0.053901 l2=0.614292 a2=0.022480 b2=-0.049620 d2000=0.018731 [test ciede2000 28] extend=ciede2000 l1=0.350831 a1=-0.441164 b1=0.037933 l2=0.350232 a2=-0.400716 b2=0.015901 d2000=0.018645 [test ciede2000 29] extend=ciede2000 l1=0.227233 a1=0.200904 b1=-0.466940 l2=0.230331 a2=0.149730 b2=-0.425619 d2000=0.020373 [test ciede2000 30] extend=ciede2000 l1=0.364612 a1=0.478580 b1=0.183852 l2=0.362715 a2=0.505065 b2=0.212231 d2000=0.014146 [test ciede2000 31] extend=ciede2000 l1=0.908027 a1=-0.020831 b1=0.014410 l2=0.911528 a2=-0.016435 b2=0.000447 d2000=0.014441 [test ciede2000 32] extend=ciede2000 l1=0.909257 a1=-0.005406 b1=-0.009208 l2=0.886381 a2=-0.008985 b2=-0.007239 d2000=0.015381 [test ciede2000 33] extend=ciede2000 l1=0.067747 a1=-0.002908 b1=-0.024247 l2=0.058714 a2=-0.000985 b2=-0.022286 d2000=0.006377 [test ciede2000 34] extend=ciede2000 l1=0.020776 a1=0.000795 b1=-0.011350 l2=0.009033 a2=-0.000636 b2=-0.005514 d2000=0.009082 allegro5-5.2.10.1/tests/test_compressed.ini000066400000000000000000000123771473414355200205400ustar00rootroot00000000000000# All of these are hardware only as compressed bitmaps are a video-bitmap only feature. [loading] hw_only = true op0=b = al_load_bitmap(filename) op1=al_draw_bitmap(b, 0, 0, 0) [test loading dxt1] extend=loading filename = ../examples/data/mysha_dxt1.dds sig=ftZD50000um0050000jLL050000222200000000000000000000000000000000000000000000000000 [test loading dxt3] extend=loading filename = ../examples/data/mysha_dxt3.dds sig=ftZE50000um0050000jLL050000222200000000000000000000000000000000000000000000000000 [test loading dxt5] extend=loading filename = ../examples/data/mysha_dxt5.dds sig=ftZE50000um0050000jLL050000222200000000000000000000000000000000000000000000000000 [dest rw] hw_only = true op0=b = al_load_bitmap(filename) op1=al_set_target_bitmap(b) # Need to lock, otherwise the triangles of the rectangle will lock separately and result in diagonal artifacts op2=al_lock_bitmap_region(b, 7, 7, 166, 126, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READWRITE) op3=al_draw_filled_rectangle(8, 8, 164, 124, #ff00ff) op4=al_unlock_bitmap(b) op5=al_set_target_bitmap(target) op6=al_draw_bitmap(b, 0, 0, 0) [test dest rw dxt1] extend=dest rw filename = ../examples/data/mysha_dxt1.dds sig=ggZD50000gg0050000jLL050000222200000000000000000000000000000000000000000000000000 [test dest rw dxt3] extend=dest rw filename = ../examples/data/mysha_dxt3.dds sig=ggZE50000gg0050000jLL050000222200000000000000000000000000000000000000000000000000 [test dest rw dxt5] extend=dest rw filename = ../examples/data/mysha_dxt5.dds sig=ggZE50000gg0050000jLL050000222200000000000000000000000000000000000000000000000000 [dest wo] hw_only = true filename2 = ../examples/data/blue_box.png op0=b = al_load_bitmap(filename) op1=b2 = al_load_bitmap(filename2) op2=al_set_target_bitmap(b) op3=al_draw_bitmap(b2, 16, 16, 0) op4=al_set_target_bitmap(target) op5=al_draw_bitmap(b, 0, 0, 0) [test dest wo dxt1] extend=dest wo filename = ../examples/data/mysha_dxt1.dds sig=OOZD50000OO0050000aML050000222200000000000000000000000000000000000000000000000000 [test dest wo dxt3] extend=dest wo filename = ../examples/data/mysha_dxt3.dds sig=OOZD50000OO0050000aML050000222200000000000000000000000000000000000000000000000000 [test dest wo dxt5] extend=dest wo filename = ../examples/data/mysha_dxt5.dds sig=OOZD50000OO0050000aML050000222200000000000000000000000000000000000000000000000000 [src] hw_only = true filename2 = ../examples/data/fakeamp.bmp op0=b = al_load_bitmap(filename) op1=b2 = al_load_bitmap(filename2) op2=al_set_target_bitmap(b2) op3=al_draw_bitmap_region(b, 16, 16, 128, 128, 16, 16, 0) op4=al_set_target_bitmap(target) op5=al_draw_bitmap(b2, 0, 0, 0) [test src dxt1] extend=src filename = ../examples/data/mysha_dxt1.dds sig=ftwu00000um0w00000QB0r00000vrnv00000000000000000000000000000000000000000000000000 [test src dxt3] extend=src filename = ../examples/data/mysha_dxt3.dds sig=ftwu00000um0w00000QB0r00000vrnv00000000000000000000000000000000000000000000000000 [test src dxt5] extend=src filename = ../examples/data/mysha_dxt5.dds sig=ftwu00000um0w00000QB0r00000vrnv00000000000000000000000000000000000000000000000000 [dest sub] hw_only = true op0=b = al_load_bitmap(filename) op1=b2 = al_create_sub_bitmap(b, 16, 16, 128, 128); op2=al_set_target_bitmap(b2) op3=al_clear_to_color(#00ff00) op4=al_set_target_bitmap(target) op5=al_draw_bitmap(b, 0, 0, 0) [test dest sub dxt1] extend=dest sub filename = ../examples/data/mysha_dxt1.dds sig=LLZD50000LL0050000ZLL050000222200000000000000000000000000000000000000000000000000 [test dest sub dxt3] extend=dest sub filename = ../examples/data/mysha_dxt3.dds sig=LLZD50000LL0050000ZLL050000222200000000000000000000000000000000000000000000000000 [test dest sub dxt5] extend=dest sub filename = ../examples/data/mysha_dxt5.dds sig=LLZD50000LL0050000ZLL050000222200000000000000000000000000000000000000000000000000 [convert from] hw_only = true op0=b = al_load_bitmap(filename) op1=al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_RGB_565) op2=al_convert_bitmap(b) op3=al_draw_bitmap(b, 0, 0, 0) [test convert from dxt1] extend=convert from filename = ../examples/data/mysha_dxt1.dds sig=ftZD50000um0050000jLL050000222200000000000000000000000000000000000000000000000000 [test convert from dxt3] extend=convert from filename = ../examples/data/mysha_dxt3.dds sig=ftZD50000um0050000jLL050000222200000000000000000000000000000000000000000000000000 [test convert from dxt5] extend=convert from filename = ../examples/data/mysha_dxt5.dds sig=ftZD50000um0050000jLL050000222200000000000000000000000000000000000000000000000000 [convert to] hw_only = true filename = ../examples/data/blue_box.png op0=al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_RGB_565) op1=b = al_load_bitmap(filename) op3=al_convert_bitmap(b) op4=al_draw_bitmap(b, 0, 0, 0) [test convert to dxt1] extend=convert to op2=al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1) sig=OA0000000OA0000000000000000000000000000000000000000000000000000000000000000000000 [test convert to dxt3] extend=convert to op2=al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3) sig=OA0000000OA0000000000000000000000000000000000000000000000000000000000000000000000 [test convert to dxt5] extend=convert to op2=al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5) sig=OA0000000OA0000000000000000000000000000000000000000000000000000000000000000000000 allegro5-5.2.10.1/tests/test_convert.ini000066400000000000000000000015641473414355200200500ustar00rootroot00000000000000[test convert] # This test relies on needing a video bitmap. hw_only = true skip_on_xvfb = true op0= al_clear_to_color(#554321) op1= al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP) op2= al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_RGB_565) op3= bmp = al_create_bitmap(360, 120) op4= al_set_target_bitmap(bmp) op5= al_clear_to_color(#00000000) op6= al_draw_filled_rectangle(0, 0, 120, 120, red) op7= al_draw_filled_rectangle(120, 0, 240, 120, green) op8= al_draw_filled_rectangle(240, 0, 360, 120, blue) op9= al_set_target_bitmap(target) op10=al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP) op11=al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_RGBA_8888) op12=al_convert_bitmap(bmp) op13=al_draw_bitmap(bmp, 0, 0, 0) hash=955d3cc5 [test convert back] extend=test convert op1=al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP) op10=al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP) hash=77b58ac5 allegro5-5.2.10.1/tests/test_driver.c000066400000000000000000001564751473414355200173420ustar00rootroot00000000000000/* * Automated testing driver program for Allegro. * * By Peter Wang. */ #define ALLEGRO_UNSTABLE #include #include #include #include #include #include #include #include #include #include #define MAX_BITMAPS 128 #define MAX_TRANS 8 #define MAX_FONTS 16 #define MAX_VERTICES 100 #define MAX_POLYGONS 8 typedef struct { ALLEGRO_USTR *name; ALLEGRO_BITMAP *bitmap[2]; } Bitmap; typedef enum { SW = 0, HW = 1 } BmpType; typedef struct { ALLEGRO_USTR *name; ALLEGRO_TRANSFORM transform; } Transform; typedef struct { int x; int y; int w; int h; ALLEGRO_LOCKED_REGION *lr; } LockRegion; typedef struct { ALLEGRO_USTR *name; ALLEGRO_FONT *font; } NamedFont; int argc; char **argv; ALLEGRO_DISPLAY *display; ALLEGRO_BITMAP *membuf; Bitmap bitmaps[MAX_BITMAPS]; LockRegion lock_region; Transform transforms[MAX_TRANS]; NamedFont fonts[MAX_FONTS]; ALLEGRO_VERTEX vertices[MAX_VERTICES]; float simple_vertices[2 * MAX_VERTICES]; int num_simple_vertices; int vertex_counts[MAX_POLYGONS]; int num_global_bitmaps; float delay = 0.0; bool save_outputs = false; bool save_on_failure = false; bool quiet = false; bool want_display = true; bool on_xvfb = true; int verbose = 0; int total_tests = 0; int passed_tests = 0; int failed_tests = 0; int skipped_tests = 0; #define streq(a, b) (0 == strcmp((a), (b))) /* Helper macros for scanning statements. */ #define PAT " %79[A-Za-z0-9_.$|#-] " #define PAT1 PAT #define PAT2 PAT1 "," PAT1 #define PAT3 PAT2 "," PAT1 #define PAT4 PAT3 "," PAT1 #define PAT5 PAT4 "," PAT1 #define PAT6 PAT5 "," PAT1 #define PAT7 PAT6 "," PAT1 #define PAT8 PAT7 "," PAT1 #define PAT9 PAT8 "," PAT1 #define PAT10 PAT9 "," PAT1 #define PAT11 PAT10 "," PAT1 #define PAT12 PAT11 "," PAT1 #define PAT13 PAT12 "," PAT1 #define PAT14 PAT13 "," PAT1 #define ARGS1 arg[0] #define ARGS2 ARGS1, arg[1] #define ARGS3 ARGS2, arg[2] #define ARGS4 ARGS3, arg[3] #define ARGS5 ARGS4, arg[4] #define ARGS6 ARGS5, arg[5] #define ARGS7 ARGS6, arg[6] #define ARGS8 ARGS7, arg[7] #define ARGS9 ARGS8, arg[8] #define ARGS10 ARGS9, arg[9] #define ARGS11 ARGS10, arg[10] #define ARGS12 ARGS11, arg[11] #define ARGS13 ARGS12, arg[12] #define ARGS14 ARGS13, arg[13] #define V(a) resolve_var(cfg, section, arg[(a)]) #define I(a) atoi(V(a)) #define F(a) atof(V(a)) #define C(a) get_color(V(a)) #define B(a) get_bitmap(V(a), bmp_type, target) #define SCAN0(fn) \ (sscanf(stmt, fn " %79[(]" " )", ARGS1) == 1) #define SCAN(fn, arity) \ (sscanf(stmt, fn " (" PAT##arity " )", ARGS##arity) == arity) #define SCANLVAL(fn, arity) \ (sscanf(stmt, PAT " = " fn " (" PAT##arity " )", lval, ARGS##arity) \ == 1 + arity) static void fatal_error(char const *msg, ...) { va_list ap; va_start(ap, msg); fprintf(stderr, "test_driver: "); vfprintf(stderr, msg, ap); fprintf(stderr, "\n"); va_end(ap); exit(EXIT_FAILURE); } static char const *bmp_type_to_string(BmpType bmp_type) { switch (bmp_type) { case SW: return "sw"; case HW: return "hw"; } return "error"; } static ALLEGRO_BITMAP *create_fallback_bitmap(void) { ALLEGRO_BITMAP *bmp = al_create_bitmap(256, 256); ALLEGRO_FONT *builtin_font = al_create_builtin_font(); ALLEGRO_STATE state; if (!bmp) { fatal_error("couldn't create a backup bitmap"); } if (!builtin_font) { fatal_error("couldn't create a builtin font"); } al_store_state(&state, ALLEGRO_STATE_BITMAP); al_set_target_bitmap(bmp); al_clear_to_color(al_map_rgb_f(0.5, 0, 0)); al_draw_text(builtin_font, al_map_rgb_f(1, 1, 1), 0, 0, 0, "fallback"); al_restore_state(&state); al_destroy_font(builtin_font); return bmp; } static ALLEGRO_BITMAP *load_relative_bitmap(char const *filename, int flags) { ALLEGRO_BITMAP *bmp; bmp = al_load_bitmap_flags(filename, flags); if (!bmp) { fprintf(stderr, "test_driver: failed to load %s\n", filename); bmp = create_fallback_bitmap(); } return bmp; } static void load_bitmaps(ALLEGRO_CONFIG const *cfg, const char *section, BmpType bmp_type, int flags) { int i = 0; ALLEGRO_CONFIG_ENTRY *iter; char const *key; char const *value; key = al_get_first_config_entry(cfg, section, &iter); while (key && i < MAX_BITMAPS) { value = al_get_config_value(cfg, section, key); bitmaps[i].name = al_ustr_new(key); bitmaps[i].bitmap[bmp_type] = load_relative_bitmap(value, flags); key = al_get_next_config_entry(&iter); i++; } if (i == MAX_BITMAPS) fatal_error("bitmap limit reached"); num_global_bitmaps = i; } static ALLEGRO_BITMAP **reserve_local_bitmap(const char *name, BmpType bmp_type) { int i; for (i = num_global_bitmaps; i < MAX_BITMAPS; i++) { if (!bitmaps[i].name) { bitmaps[i].name = al_ustr_new(name); return &bitmaps[i].bitmap[bmp_type]; } } fatal_error("bitmap limit reached"); return NULL; } static void unload_data(void) { int i; for (i = 0; i < MAX_BITMAPS; i++) { al_ustr_free(bitmaps[i].name); al_destroy_bitmap(bitmaps[i].bitmap[0]); al_destroy_bitmap(bitmaps[i].bitmap[1]); } memset(bitmaps, 0, sizeof(bitmaps)); for (i = 0; i < MAX_FONTS; i++) { al_ustr_free(fonts[i].name); al_destroy_font(fonts[i].font); } memset(fonts, 0, sizeof(fonts)); num_global_bitmaps = 0; } static void set_target_reset(ALLEGRO_BITMAP *target) { ALLEGRO_TRANSFORM ident; al_set_target_bitmap(target); al_clear_to_color(al_map_rgb(0, 0, 0)); al_reset_clipping_rectangle(); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO); al_identity_transform(&ident); al_use_transform(&ident); al_orthographic_transform(&ident, 0, 0, -1, al_get_bitmap_width(target), al_get_bitmap_height(target), 1); al_use_projection_transform(&ident); } static char const *resolve_var(ALLEGRO_CONFIG const *cfg, char const *section, char const *v) { char const *vv = al_get_config_value(cfg, section, v); return (vv) ? vv : v; } static bool get_bool(char const *value) { return streq(value, "true") ? true : streq(value, "false") ? false : atoi(value); } static ALLEGRO_COLOR get_color(char const *value) { int r, g, b, a; float rf, gf, bf; if (sscanf(value, "#%02x%02x%02x%02x", &r, &g, &b, &a) == 4) return al_map_rgba(r, g, b, a); if (sscanf(value, "#%02x%02x%02x", &r, &g, &b) == 3) return al_map_rgb(r, g, b); if (sscanf(value, "%f/%f/%f", &rf, &gf, &bf) == 3) return al_map_rgb_f(rf, gf, bf); return al_color_name(value); } static ALLEGRO_BITMAP *get_bitmap(char const *value, BmpType bmp_type, ALLEGRO_BITMAP *target) { int i; for (i = 0; i < MAX_BITMAPS; i++) { if (bitmaps[i].name && streq(al_cstr(bitmaps[i].name), value)) return bitmaps[i].bitmap[bmp_type]; } if (streq(value, "target")) return target; if (streq(value, "0") || streq(value, "NULL")) return NULL; fatal_error("undefined bitmap: %s", value); return NULL; } static int get_load_bitmap_flag(char const *value) { if (streq(value, "ALLEGRO_NO_PREMULTIPLIED_ALPHA")) return ALLEGRO_NO_PREMULTIPLIED_ALPHA; if (streq(value, "ALLEGRO_KEEP_INDEX")) return ALLEGRO_KEEP_INDEX; return atoi(value); } static int get_draw_bitmap_flag(char const *value) { if (streq(value, "ALLEGRO_FLIP_HORIZONTAL")) return ALLEGRO_FLIP_HORIZONTAL; if (streq(value, "ALLEGRO_FLIP_VERTICAL")) return ALLEGRO_FLIP_VERTICAL; if (streq(value, "ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL")) return ALLEGRO_FLIP_VERTICAL|ALLEGRO_FLIP_HORIZONTAL; if (streq(value, "ALLEGRO_FLIP_HORIZONTAL|ALLEGRO_FLIP_VERTICAL")) return ALLEGRO_FLIP_HORIZONTAL|ALLEGRO_FLIP_VERTICAL; return atoi(value); } static int get_blender_op(char const *value) { return streq(value, "ALLEGRO_ADD") ? ALLEGRO_ADD : streq(value, "ALLEGRO_DEST_MINUS_SRC") ? ALLEGRO_DEST_MINUS_SRC : streq(value, "ALLEGRO_SRC_MINUS_DEST") ? ALLEGRO_SRC_MINUS_DEST : atoi(value); } static int get_blend_factor(char const *value) { return streq(value, "ALLEGRO_ZERO") ? ALLEGRO_ZERO : streq(value, "ALLEGRO_ONE") ? ALLEGRO_ONE : streq(value, "ALLEGRO_ALPHA") ? ALLEGRO_ALPHA : streq(value, "ALLEGRO_INVERSE_ALPHA") ? ALLEGRO_INVERSE_ALPHA : streq(value, "ALLEGRO_SRC_COLOR") ? ALLEGRO_SRC_COLOR : streq(value, "ALLEGRO_DEST_COLOR") ? ALLEGRO_DEST_COLOR : streq(value, "ALLEGRO_INVERSE_SRC_COLOR") ? ALLEGRO_INVERSE_SRC_COLOR : streq(value, "ALLEGRO_INVERSE_DEST_COLOR") ? ALLEGRO_INVERSE_DEST_COLOR : streq(value, "ALLEGRO_CONST_COLOR") ? ALLEGRO_CONST_COLOR : streq(value, "ALLEGRO_INVERSE_CONST_COLOR") ? ALLEGRO_INVERSE_CONST_COLOR : atoi(value); } static ALLEGRO_TRANSFORM *get_transform(const char *name) { int i; for (i = 0; i < MAX_TRANS; i++) { if (!transforms[i].name) { transforms[i].name = al_ustr_new(name); al_identity_transform(&transforms[i].transform); return &transforms[i].transform; } if (transforms[i].name && streq(al_cstr(transforms[i].name), name)) return &transforms[i].transform; } fatal_error("transforms limit reached"); return NULL; } static int get_pixel_format(char const *v) { int format = streq(v, "ALLEGRO_PIXEL_FORMAT_ANY") ? ALLEGRO_PIXEL_FORMAT_ANY : streq(v, "ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA") ? ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA : streq(v, "ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA") ? ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA : streq(v, "ALLEGRO_PIXEL_FORMAT_ANY_15_NO_ALPHA") ? ALLEGRO_PIXEL_FORMAT_ANY_15_NO_ALPHA : streq(v, "ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA") ? ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA : streq(v, "ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA") ? ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA : streq(v, "ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA") ? ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA : streq(v, "ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA") ? ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA : streq(v, "ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA") ? ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA : streq(v, "ALLEGRO_PIXEL_FORMAT_ARGB_8888") ? ALLEGRO_PIXEL_FORMAT_ARGB_8888 : streq(v, "ALLEGRO_PIXEL_FORMAT_RGBA_8888") ? ALLEGRO_PIXEL_FORMAT_RGBA_8888 : streq(v, "ALLEGRO_PIXEL_FORMAT_ARGB_4444") ? ALLEGRO_PIXEL_FORMAT_ARGB_4444 : streq(v, "ALLEGRO_PIXEL_FORMAT_RGB_888") ? ALLEGRO_PIXEL_FORMAT_RGB_888 : streq(v, "ALLEGRO_PIXEL_FORMAT_RGB_565") ? ALLEGRO_PIXEL_FORMAT_RGB_565 : streq(v, "ALLEGRO_PIXEL_FORMAT_RGB_555") ? ALLEGRO_PIXEL_FORMAT_RGB_555 : streq(v, "ALLEGRO_PIXEL_FORMAT_RGBA_5551") ? ALLEGRO_PIXEL_FORMAT_RGBA_5551 : streq(v, "ALLEGRO_PIXEL_FORMAT_ARGB_1555") ? ALLEGRO_PIXEL_FORMAT_ARGB_1555 : streq(v, "ALLEGRO_PIXEL_FORMAT_ABGR_8888") ? ALLEGRO_PIXEL_FORMAT_ABGR_8888 : streq(v, "ALLEGRO_PIXEL_FORMAT_XBGR_8888") ? ALLEGRO_PIXEL_FORMAT_XBGR_8888 : streq(v, "ALLEGRO_PIXEL_FORMAT_BGR_888") ? ALLEGRO_PIXEL_FORMAT_BGR_888 : streq(v, "ALLEGRO_PIXEL_FORMAT_BGR_565") ? ALLEGRO_PIXEL_FORMAT_BGR_565 : streq(v, "ALLEGRO_PIXEL_FORMAT_BGR_555") ? ALLEGRO_PIXEL_FORMAT_BGR_555 : streq(v, "ALLEGRO_PIXEL_FORMAT_RGBX_8888") ? ALLEGRO_PIXEL_FORMAT_RGBX_8888 : streq(v, "ALLEGRO_PIXEL_FORMAT_XRGB_8888") ? ALLEGRO_PIXEL_FORMAT_XRGB_8888 : streq(v, "ALLEGRO_PIXEL_FORMAT_ABGR_F32") ? ALLEGRO_PIXEL_FORMAT_ABGR_F32 : streq(v, "ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE") ? ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE : streq(v, "ALLEGRO_PIXEL_FORMAT_RGBA_4444") ? ALLEGRO_PIXEL_FORMAT_RGBA_4444 : streq(v, "ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1") ? ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT1 : streq(v, "ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3") ? ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT3 : streq(v, "ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5") ? ALLEGRO_PIXEL_FORMAT_COMPRESSED_RGBA_DXT5 : -1; if (format == -1) fatal_error("invalid format: %s", v); return format; } static int get_lock_bitmap_flags(char const *v) { return streq(v, "ALLEGRO_LOCK_READWRITE") ? ALLEGRO_LOCK_READWRITE : streq(v, "ALLEGRO_LOCK_READONLY") ? ALLEGRO_LOCK_READONLY : streq(v, "ALLEGRO_LOCK_WRITEONLY") ? ALLEGRO_LOCK_WRITEONLY : atoi(v); } static int get_bitmap_flags(char const *v) { return streq(v, "ALLEGRO_MEMORY_BITMAP") ? ALLEGRO_MEMORY_BITMAP : streq(v, "ALLEGRO_VIDEO_BITMAP") ? ALLEGRO_VIDEO_BITMAP : atoi(v); } static void fill_lock_region(LockRegion *lr, float alphafactor, bool blended) { int x, y; float r, g, b, a; ALLEGRO_COLOR c; for (y = 0; y < lr->h; y++) { for (x = 0; x < lr->w; x++) { /* -1 to make the last pixel use the full color, allows easier * manual inspection of the test results as we have a fixed * color on each side. */ r = (float)x / (lr->w - 1); b = (float)y / (lr->h - 1); g = r*b; a = r * alphafactor; c = al_map_rgba_f(r, g, b, a); if (blended) al_put_blended_pixel(lr->x + x, lr->y + y, c); else al_put_pixel(lr->x + x, lr->y + y, c); } } } static int get_load_font_flags(char const *v) { return streq(v, "ALLEGRO_NO_PREMULTIPLIED_ALPHA") ? ALLEGRO_NO_PREMULTIPLIED_ALPHA : streq(v, "ALLEGRO_TTF_NO_KERNING") ? ALLEGRO_TTF_NO_KERNING : streq(v, "ALLEGRO_TTF_MONOCHROME") ? ALLEGRO_TTF_MONOCHROME : atoi(v); } static void load_fonts(ALLEGRO_CONFIG const *cfg, const char *section) { #define MAXBUF 80 int i = 0; ALLEGRO_CONFIG_ENTRY *iter; char const *key; char arg[14][MAXBUF]; key = al_get_first_config_entry(cfg, section, &iter); while (key && i < MAX_FONTS) { char const *stmt = al_get_config_value(cfg, section, key); ALLEGRO_FONT *font = NULL; bool load_stmt = false; if (SCAN("al_load_font", 3)) { font = al_load_font(V(0), I(1), get_load_font_flags(V(2))); load_stmt = true; } else if (SCAN("al_load_ttf_font", 3)) { font = al_load_ttf_font(V(0), I(1), get_load_font_flags(V(2))); load_stmt = true; } else if (SCAN("al_load_ttf_font_stretch", 4)) { font = al_load_ttf_font_stretch(V(0), I(1), I(2), get_load_font_flags(V(3))); load_stmt = true; } else if (SCAN0("al_create_builtin_font")) { font = al_create_builtin_font(); load_stmt = true; } if (load_stmt) { if (!font) { fatal_error("failed to load font: %s", key); } fonts[i].name = al_ustr_new(key); fonts[i].font = font; i++; } key = al_get_next_config_entry(&iter); } if (i == MAX_FONTS) fatal_error("font limit reached"); #undef MAXBUF } static ALLEGRO_FONT *get_font(char const *name) { int i; if (streq(name, "NULL")) return NULL; for (i = 0; i < MAX_FONTS; i++) { if (fonts[i].name && streq(al_cstr(fonts[i].name), name)) return fonts[i].font; } fatal_error("undefined font: %s", name); return NULL; } static int get_font_align(char const *value) { return streq(value, "ALLEGRO_ALIGN_LEFT") ? ALLEGRO_ALIGN_LEFT : streq(value, "ALLEGRO_ALIGN_CENTRE") ? ALLEGRO_ALIGN_CENTRE : streq(value, "ALLEGRO_ALIGN_RIGHT") ? ALLEGRO_ALIGN_RIGHT : streq(value, "ALLEGRO_ALIGN_INTEGER") ? ALLEGRO_ALIGN_INTEGER : streq(value, "ALLEGRO_ALIGN_LEFT|ALLEGRO_ALIGN_INTEGER") ? ALLEGRO_ALIGN_LEFT | ALLEGRO_ALIGN_INTEGER : streq(value, "ALLEGRO_ALIGN_RIGHT|ALLEGRO_ALIGN_INTEGER") ? ALLEGRO_ALIGN_RIGHT | ALLEGRO_ALIGN_INTEGER : streq(value, "ALLEGRO_ALIGN_CENTRE|ALLEGRO_ALIGN_INTEGER") ? ALLEGRO_ALIGN_CENTRE | ALLEGRO_ALIGN_INTEGER : atoi(value); } static void set_config_int(ALLEGRO_CONFIG *cfg, char const *section, char const *var, int value) { char buf[40]; sprintf(buf, "%d", value); al_set_config_value(cfg, section, var, buf); } static void set_config_float(ALLEGRO_CONFIG *cfg, char const *section, char const *var, float value) { char buf[40]; sprintf(buf, "%f", value); al_set_config_value(cfg, section, var, buf); } static void fill_vertices(ALLEGRO_CONFIG const *cfg, char const *name) { #define MAXBUF 80 char const *value; char buf[MAXBUF]; float x, y, z; float u, v; int i; memset(vertices, 0, sizeof(vertices)); for (i = 0; i < MAX_VERTICES; i++) { sprintf(buf, "v%d", i); value = al_get_config_value(cfg, name, buf); if (!value) return; if (sscanf(value, " %f , %f , %f ; %f , %f ; %s", &x, &y, &z, &u, &v, buf) == 6) { vertices[i].x = x; vertices[i].y = y; vertices[i].z = z; vertices[i].u = u; vertices[i].v = v; vertices[i].color = get_color(buf); } } #undef MAXBUF } static void fill_simple_vertices(ALLEGRO_CONFIG const *cfg, char const *name) { #define MAXBUF 80 char const *value; char buf[MAXBUF]; float x, y; int i; memset(simple_vertices, 0, sizeof(simple_vertices)); for (i = 0; i < MAX_VERTICES; i++) { sprintf(buf, "v%d", i); value = al_get_config_value(cfg, name, buf); if (!value) break; if (sscanf(value, " %f , %f", &x, &y) == 2) { simple_vertices[2*i + 0] = x; simple_vertices[2*i + 1] = y; } } num_simple_vertices = i; #undef MAXBUF } static void fill_vertex_counts(ALLEGRO_CONFIG const *cfg, char const *name) { #define MAXBUF 80 char const *value; char buf[MAXBUF]; int count; int i; memset(vertex_counts, 0, sizeof(vertex_counts)); for (i = 0; i < MAX_POLYGONS; i++) { sprintf(buf, "p%d", i); value = al_get_config_value(cfg, name, buf); if (!value) break; if (sscanf(value, " %d ", &count) == 1) { vertex_counts[i] = count; } } #undef MAXBUF } static int get_prim_type(char const *value) { return streq(value, "ALLEGRO_PRIM_POINT_LIST") ? ALLEGRO_PRIM_POINT_LIST : streq(value, "ALLEGRO_PRIM_LINE_LIST") ? ALLEGRO_PRIM_LINE_LIST : streq(value, "ALLEGRO_PRIM_LINE_STRIP") ? ALLEGRO_PRIM_LINE_STRIP : streq(value, "ALLEGRO_PRIM_LINE_LOOP") ? ALLEGRO_PRIM_LINE_LOOP : streq(value, "ALLEGRO_PRIM_TRIANGLE_LIST") ? ALLEGRO_PRIM_TRIANGLE_LIST : streq(value, "ALLEGRO_PRIM_TRIANGLE_STRIP") ? ALLEGRO_PRIM_TRIANGLE_STRIP : streq(value, "ALLEGRO_PRIM_TRIANGLE_FAN") ? ALLEGRO_PRIM_TRIANGLE_FAN : atoi(value); } static int get_line_join(char const *value) { return streq(value, "ALLEGRO_LINE_JOIN_NONE") ? ALLEGRO_LINE_JOIN_NONE : streq(value, "ALLEGRO_LINE_JOIN_BEVEL") ? ALLEGRO_LINE_JOIN_BEVEL : streq(value, "ALLEGRO_LINE_JOIN_ROUND") ? ALLEGRO_LINE_JOIN_ROUND : streq(value, "ALLEGRO_LINE_JOIN_MITER") ? ALLEGRO_LINE_JOIN_MITER : atoi(value); } static int get_line_cap(char const *value) { return streq(value, "ALLEGRO_LINE_CAP_NONE") ? ALLEGRO_LINE_CAP_NONE : streq(value, "ALLEGRO_LINE_CAP_SQUARE") ? ALLEGRO_LINE_CAP_SQUARE : streq(value, "ALLEGRO_LINE_CAP_ROUND") ? ALLEGRO_LINE_CAP_ROUND : streq(value, "ALLEGRO_LINE_CAP_TRIANGLE") ? ALLEGRO_LINE_CAP_TRIANGLE : streq(value, "ALLEGRO_LINE_CAP_CLOSED") ? ALLEGRO_LINE_CAP_CLOSED : atoi(value); } /* FNV-1a algorithm, parameters from: * http://www.isthe.com/chongo/tech/comp/fnv/index.html */ #define FNV_OFFSET_BASIS 2166136261UL #define FNV_PRIME 16777619 static uint32_t hash_bitmap(ALLEGRO_BITMAP *bmp) { ALLEGRO_LOCKED_REGION *lr; int x, y, w, h; uint32_t hash; w = al_get_bitmap_width(bmp); h = al_get_bitmap_height(bmp); hash = FNV_OFFSET_BASIS; lr = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_READONLY); for (y = 0; y < h; y++) { /* Oops, I unintentially committed the first version of this with signed * chars and computing in BGRA order, so leave it like that so we don't * have to update a bunch of old hashes. */ signed char const *data = ((signed char const *)lr->data) + y*lr->pitch; for (x = 0; x < w; x++) { hash ^= data[x*4 + 3]; hash *= FNV_PRIME; hash ^= data[x*4 + 2]; hash *= FNV_PRIME; hash ^= data[x*4 + 1]; hash *= FNV_PRIME; hash ^= data[x*4 + 0]; hash *= FNV_PRIME; } } al_unlock_bitmap(bmp); return hash; } /* Image "signature" I just made up: * We take the average intensity of 7x7 patches centred at 9x9 grid points on * the image. Each of these values is reduced down to 6 bits so it can be * represented by one printable character in base64 encoding. This gives a * reasonable signature length. */ #define SIG_GRID 9 #define SIG_LEN (SIG_GRID * SIG_GRID) #define SIG_LENZ (SIG_LEN + 1) static int patch_intensity(ALLEGRO_BITMAP *bmp, int cx, int cy) { float sum = 0.0; int x, y; for (y = -3; y <= 3; y++) { for (x = -3; x <= 3; x++) { ALLEGRO_COLOR c = al_get_pixel(bmp, cx + x, cy + y); sum += c.r + c.g + c.b; } } return 255 * sum/(7*7*3); } static char const base64[64] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; static int base64_decode(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'Z') return 10 + (c - 'A'); if (c >= 'a' && c <= 'z') return 36 + (c - 'a'); if (c == '+') return 62; if (c == '/') return 63; fatal_error("invalid base64 character: %c", c); return -1; } static void compute_signature(ALLEGRO_BITMAP *bmp, char sig[SIG_LENZ]) { int w = al_get_bitmap_width(bmp); int h = al_get_bitmap_height(bmp); int x, y; int n = 0; al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); for (y = 0; y < SIG_GRID; y++) { for (x = 0; x < SIG_GRID; x++) { int cx = (1 + x) * w/(1 + SIG_GRID); int cy = (1 + y) * h/(1 + SIG_GRID); int level = patch_intensity(bmp, cx, cy); sig[n] = base64[level >> 2]; n++; } } sig[n] = '\0'; al_unlock_bitmap(bmp); } static bool similar_signatures(char const sig1[SIG_LEN], char const sig2[SIG_LEN]) { int correct = 0; int i; for (i = 0; i < SIG_LEN; i++) { int q1 = base64_decode(sig1[i]); int q2 = base64_decode(sig2[i]); /* A difference of one quantisation level could be because two values * which were originally close by straddled a quantisation boundary. * A difference of two quantisation levels is a significant deviation. */ if (abs(q1 - q2) > 1) return false; correct++; } return ((float)correct / SIG_LEN) > 0.95; } static bool check_hash(ALLEGRO_CONFIG const *cfg, char const *testname, ALLEGRO_BITMAP *bmp, BmpType bmp_type) { char const *bt = bmp_type_to_string(bmp_type); char hash[16]; char sig[SIG_LENZ]; char const *exp; char const *sigexp; exp = al_get_config_value(cfg, testname, "hash"); sigexp = al_get_config_value(cfg, testname, "sig"); if (exp && streq(exp, "off")) { printf("OK %s [%s] - hash check off\n", testname, bt); passed_tests++; return true; } sprintf(hash, "%08x", hash_bitmap(bmp)); compute_signature(bmp, sig); if (verbose) { printf("hash=%s\n", hash); printf("sig=%s\n", sig); } if (!exp && !sigexp) { printf("NEW %s [%s]\n\thash=%s\n\tsig=%s\n", testname, bt, hash, sig); return true; } if (exp && streq(hash, exp)) { printf("OK %s [%s]\n", testname, bt); passed_tests++; return true; } if (sigexp && strlen(sigexp) != SIG_LEN) { printf("WARNING: ignoring bad signature: %s\n", sigexp); sigexp = NULL; } if (sigexp && similar_signatures(sig, sigexp)) { printf("OK %s [%s] - by signature\n", testname, bt); passed_tests++; return true; } printf("FAIL %s [%s] - hash=%s\n", testname, bt, hash); failed_tests++; return false; } static double bitmap_dissimilarity(ALLEGRO_BITMAP *bmp1, ALLEGRO_BITMAP *bmp2) { ALLEGRO_LOCKED_REGION *lr1; ALLEGRO_LOCKED_REGION *lr2; int x, y, w, h; double sqerr = 0.0; lr1 = al_lock_bitmap(bmp1, ALLEGRO_PIXEL_FORMAT_RGBA_8888, ALLEGRO_LOCK_READONLY); lr2 = al_lock_bitmap(bmp2, ALLEGRO_PIXEL_FORMAT_RGBA_8888, ALLEGRO_LOCK_READONLY); w = al_get_bitmap_width(bmp1); h = al_get_bitmap_height(bmp1); for (y = 0; y < h; y++) { char const *data1 = ((char const *)lr1->data) + y*lr1->pitch; char const *data2 = ((char const *)lr2->data) + y*lr2->pitch; for (x = 0; x < w*4; x++) { double err = (double)data1[x] - (double)data2[x]; sqerr += err*err; } } al_unlock_bitmap(bmp1); al_unlock_bitmap(bmp2); return sqrt(sqerr / (w*h*4.0)); } static bool check_similarity(ALLEGRO_CONFIG const *cfg, char const *testname, ALLEGRO_BITMAP *bmp1, ALLEGRO_BITMAP *bmp2, BmpType bmp_type, bool reliable) { char const *bt = bmp_type_to_string(bmp_type); double rms = bitmap_dissimilarity(bmp1, bmp2); double tolerance; char const *value; if (bmp_type == HW) { char const *exp = al_get_config_value(cfg, testname, "hash_hw"); char const *sigexp = al_get_config_value(cfg, testname, "sig_hw"); char hash[16]; char sig[SIG_LENZ]; sprintf(hash, "%08x", hash_bitmap(bmp1)); if (exp && streq(hash, exp)) { printf("OK %s [%s]\n", testname, bt); passed_tests++; return true; } if (sigexp && strlen(sigexp) != SIG_LEN) { printf("WARNING: ignoring bad signature: %s\n", sigexp); sigexp = NULL; } compute_signature(bmp1, sig); if (sigexp && similar_signatures(sig, sigexp)) { printf("OK %s [%s] - by signature\n", testname, bt); passed_tests++; return true; } } /* The default cutoff is "empirically determined" only. */ if ((value = al_get_config_value(cfg, testname, "tolerance"))) tolerance = atof(value); else tolerance = 17.5; if (rms <= tolerance) { if (reliable) printf("OK %s [%s]\n", testname, bt); else printf("OK? %s [%s]\n", testname, bt); passed_tests++; return true; } else { char const *exp = al_get_config_value(cfg, testname, "hash"); char hash[16]; char sig[SIG_LENZ]; sprintf(hash, "%08x", hash_bitmap(bmp1)); if (exp && streq(hash, exp)) { printf("OK %s [%s]\n", testname, bt); passed_tests++; return true; } printf("FAIL %s [%s] - RMS error is %g\n", testname, bt, rms); printf("hash_hw=%s\n", hash); compute_signature(bmp1, sig); printf("sig_hw=%s\n", sig); failed_tests++; return false; } } static bool do_test(ALLEGRO_CONFIG *cfg, char const *testname, ALLEGRO_BITMAP *target, int bmp_type, bool reliable, bool do_check_hash) { #define MAXBUF 80 const char *section = testname; int op; char const *stmt; char buf[MAXBUF]; char arg[14][MAXBUF]; char lval[MAXBUF]; int i; if (verbose) { /* So in case it segfaults, we know which test to re-run. */ printf("\nRunning %s [%s].\n", testname, bmp_type_to_string(bmp_type)); fflush(stdout); } set_target_reset(target); for (op = 0; ; op++) { sprintf(buf, "op%d", op); stmt = al_get_config_value(cfg, testname, buf); if (!stmt) { /* Check for a common mistake. */ sprintf(buf, "op%d", op+1); stmt = al_get_config_value(cfg, testname, buf); if (!stmt) break; printf("WARNING: op%d skipped, continuing at op%d\n", op, op+1); op++; } if (verbose > 1) printf("# %s\n", stmt); if (streq(stmt, "")) continue; if (SCAN("al_set_target_bitmap", 1)) { al_set_target_bitmap(B(0)); continue; } if (SCAN("al_set_clipping_rectangle", 4)) { al_set_clipping_rectangle(I(0), I(1), I(2), I(3)); continue; } if (SCAN("al_set_blender", 3)) { al_set_blender( get_blender_op(V(0)), get_blend_factor(V(1)), get_blend_factor(V(2))); continue; } if (SCAN("al_set_separate_blender", 6)) { al_set_separate_blender( get_blender_op(V(0)), get_blend_factor(V(1)), get_blend_factor(V(2)), get_blender_op(V(3)), get_blend_factor(V(4)), get_blend_factor(V(5))); continue; } if (SCAN("al_set_bitmap_blender", 3)) { al_set_bitmap_blender( get_blender_op(V(0)), get_blend_factor(V(1)), get_blend_factor(V(2))); continue; } if (SCAN0("al_reset_bitmap_blender")) { al_reset_bitmap_blender(); continue; } if (SCAN("al_set_new_bitmap_flags", 1)) { al_set_new_bitmap_flags(get_bitmap_flags(V(0))); continue; } if (SCAN("al_set_new_bitmap_format", 1)) { al_set_new_bitmap_format(get_pixel_format(V(0))); continue; } if (SCAN("al_clear_to_color", 1)) { al_clear_to_color(C(0)); continue; } if (SCANLVAL("al_clone_bitmap", 1)) { ALLEGRO_BITMAP **bmp = reserve_local_bitmap(lval, bmp_type); (*bmp) = al_clone_bitmap(B(0)); continue; } if (SCAN("al_draw_bitmap", 4)) { al_draw_bitmap(B(0), F(1), F(2), get_draw_bitmap_flag(V(3))); continue; } if (SCAN("al_draw_tinted_bitmap", 5)) { al_draw_tinted_bitmap(B(0), C(1), F(2), F(3), get_draw_bitmap_flag(V(4))); continue; } if (SCAN("al_draw_bitmap_region", 8)) { al_draw_bitmap_region(B(0), F(1), F(2), F(3), F(4), F(5), F(6), get_draw_bitmap_flag(V(7))); continue; } if (SCAN("al_draw_tinted_bitmap_region", 9)) { al_draw_tinted_bitmap_region(B(0), C(1), F(2), F(3), F(4), F(5), F(6), F(7), get_draw_bitmap_flag(V(8))); continue; } if (SCAN("al_draw_rotated_bitmap", 7)) { al_draw_rotated_bitmap(B(0), F(1), F(2), F(3), F(4), F(5), get_draw_bitmap_flag(V(6))); continue; } if (SCAN("al_draw_tinted_rotated_bitmap", 8)) { al_draw_tinted_rotated_bitmap(B(0), C(1), F(2), F(3), F(4), F(5), F(6), get_draw_bitmap_flag(V(7))); continue; } if (SCAN("al_draw_scaled_bitmap", 10)) { al_draw_scaled_bitmap(B(0), F(1), F(2), F(3), F(4), F(5), F(6), F(7), F(8), get_draw_bitmap_flag(V(9))); continue; } if (SCAN("al_draw_tinted_scaled_bitmap", 11)) { al_draw_tinted_scaled_bitmap(B(0), C(1), F(2), F(3), F(4), F(5), F(6), F(7), F(8), F(9), get_draw_bitmap_flag(V(10))); continue; } if (SCAN("al_draw_scaled_rotated_bitmap", 9)) { al_draw_scaled_rotated_bitmap(B(0), F(1), F(2), F(3), F(4), F(5), F(6), F(7), get_draw_bitmap_flag(V(8))); continue; } if (SCAN("al_draw_tinted_scaled_rotated_bitmap", 10)) { al_draw_tinted_scaled_rotated_bitmap(B(0), C(1), F(2), F(3), F(4), F(5), F(6), F(7), F(8), get_draw_bitmap_flag(V(9))); continue; } if (SCAN("al_draw_tinted_scaled_rotated_bitmap_region", 14)) { al_draw_tinted_scaled_rotated_bitmap_region(B(0), F(1), F(2), F(3), F(4), C(5), F(6), F(7), F(8), F(9), F(10), F(11), F(12), get_draw_bitmap_flag(V(13))); continue; } if (SCAN("al_draw_pixel", 3)) { al_draw_pixel(F(0), F(1), C(2)); continue; } if (SCAN("al_put_pixel", 3)) { al_put_pixel(I(0), I(1), C(2)); continue; } if (SCAN("al_put_blended_pixel", 3)) { al_put_blended_pixel(I(0), I(1), C(2)); continue; } if (SCANLVAL("al_create_bitmap", 2)) { ALLEGRO_BITMAP **bmp = reserve_local_bitmap(lval, bmp_type); (*bmp) = al_create_bitmap(I(0), I(1)); continue; } if (SCANLVAL("al_create_sub_bitmap", 5)) { ALLEGRO_BITMAP **bmp = reserve_local_bitmap(lval, bmp_type); (*bmp) = al_create_sub_bitmap(B(0), I(1), I(2), I(3), I(4)); continue; } if (SCANLVAL("al_load_bitmap", 1)) { ALLEGRO_BITMAP **bmp = reserve_local_bitmap(lval, bmp_type); (*bmp) = load_relative_bitmap(V(0), 0); continue; } if (SCANLVAL("al_load_bitmap_flags", 2)) { ALLEGRO_BITMAP **bmp = reserve_local_bitmap(lval, bmp_type); (*bmp) = load_relative_bitmap(V(0), get_load_bitmap_flag(V(1))); continue; } if (SCAN("al_save_bitmap", 2)) { if (!al_save_bitmap(V(0), B(1))) { fatal_error("failed to save %s", V(0)); } continue; } if (SCANLVAL("al_identify_bitmap", 1)) { char const *ext = al_identify_bitmap(V(0)); if (!ext) ext = "NULL"; al_set_config_value(cfg, testname, lval, ext); continue; } if (SCAN("al_hold_bitmap_drawing", 1)) { al_hold_bitmap_drawing(get_bool(V(0))); continue; } /* Transformations */ if (SCAN("al_copy_transform", 2)) { al_copy_transform(get_transform(V(0)), get_transform(V(1))); continue; } if (SCAN("al_use_transform", 1)) { al_use_transform(get_transform(V(0))); continue; } if (SCAN("al_build_transform", 6)) { al_build_transform(get_transform(V(0)), F(1), F(2), F(3), F(4), F(5)); continue; } if (SCAN("al_translate_transform", 3)) { al_translate_transform(get_transform(V(0)), F(1), F(2)); continue; } if (SCAN("al_scale_transform", 3)) { al_scale_transform(get_transform(V(0)), F(1), F(2)); continue; } if (SCAN("al_rotate_transform", 2)) { al_rotate_transform(get_transform(V(0)), F(1)); continue; } if (SCAN("al_compose_transform", 2)) { al_compose_transform(get_transform(V(0)), get_transform(V(1))); continue; } /* Conversion */ if (SCAN("al_convert_bitmap", 1)) { ALLEGRO_BITMAP *bmp = B(0); al_convert_bitmap(bmp); continue; } /* Locking */ if (SCAN("al_lock_bitmap", 3)) { ALLEGRO_BITMAP *bmp = B(0); lock_region.x = 0; lock_region.y = 0; lock_region.w = al_get_bitmap_width(bmp); lock_region.h = al_get_bitmap_height(bmp); lock_region.lr = al_lock_bitmap(bmp, get_pixel_format(V(1)), get_lock_bitmap_flags(V(2))); continue; } if (SCAN("al_lock_bitmap_region", 7)) { ALLEGRO_BITMAP *bmp = B(0); lock_region.x = I(1); lock_region.y = I(2); lock_region.w = I(3); lock_region.h = I(4); lock_region.lr = al_lock_bitmap_region(bmp, lock_region.x, lock_region.y, lock_region.w, lock_region.h, get_pixel_format(V(5)), get_lock_bitmap_flags(V(6))); continue; } if (SCAN("al_unlock_bitmap", 1)) { al_unlock_bitmap(B(0)); lock_region.lr = NULL; continue; } if (SCAN("fill_lock_region", 2)) { fill_lock_region(&lock_region, F(0), get_bool(V(1))); continue; } /* Fonts */ if (SCAN("al_draw_text", 6)) { al_draw_text(get_font(V(0)), C(1), F(2), F(3), get_font_align(V(4)), V(5)); continue; } if (SCAN("al_draw_justified_text", 8)) { al_draw_justified_text(get_font(V(0)), C(1), F(2), F(3), F(4), F(5), get_font_align(V(6)), V(7)); continue; } if (SCANLVAL("al_get_text_width", 2)) { int w = al_get_text_width(get_font(V(0)), V(1)); set_config_int(cfg, testname, lval, w); continue; } if (SCANLVAL("al_get_font_line_height", 1)) { int h = al_get_font_line_height(get_font(V(0))); set_config_int(cfg, testname, lval, h); continue; } if (SCANLVAL("al_get_font_ascent", 1)) { int as = al_get_font_ascent(get_font(V(0))); set_config_int(cfg, testname, lval, as); continue; } if (SCANLVAL("al_get_font_descent", 1)) { int de = al_get_font_descent(get_font(V(0))); set_config_int(cfg, testname, lval, de); continue; } if (SCAN("al_get_text_dimensions", 6)) { int bbx, bby, bbw, bbh; al_get_text_dimensions(get_font(V(0)), V(1), &bbx, &bby, &bbw, &bbh); set_config_int(cfg, testname, V(2), bbx); set_config_int(cfg, testname, V(3), bby); set_config_int(cfg, testname, V(4), bbw); set_config_int(cfg, testname, V(5), bbh); continue; } if (SCAN("al_set_fallback_font", 2)) { al_set_fallback_font(get_font(V(0)), get_font(V(1))); continue; } /* Primitives */ if (SCAN("al_draw_line", 6)) { al_draw_line(F(0), F(1), F(2), F(3), C(4), F(5)); continue; } if (SCAN("al_draw_triangle", 8)) { al_draw_triangle(F(0), F(1), F(2), F(3), F(4), F(5), C(6), F(7)); continue; } if (SCAN("al_draw_filled_triangle", 7)) { al_draw_filled_triangle(F(0), F(1), F(2), F(3), F(4), F(5), C(6)); continue; } if (SCAN("al_draw_rectangle", 6)) { al_draw_rectangle(F(0), F(1), F(2), F(3), C(4), F(5)); continue; } if (SCAN("al_draw_filled_rectangle", 5)) { al_draw_filled_rectangle(F(0), F(1), F(2), F(3), C(4)); continue; } if (SCAN("al_draw_rounded_rectangle", 8)) { al_draw_rounded_rectangle(F(0), F(1), F(2), F(3), F(4), F(5), C(6), F(7)); continue; } if (SCAN("al_draw_filled_rounded_rectangle", 7)) { al_draw_filled_rounded_rectangle(F(0), F(1), F(2), F(3), F(4), F(5), C(6)); continue; } if (SCAN("al_draw_pieslice", 7)) { al_draw_pieslice(F(0), F(1), F(2), F(3), F(4), C(5), F(6)); continue; } if (SCAN("al_draw_filled_pieslice", 6)) { al_draw_filled_pieslice(F(0), F(1), F(2), F(3), F(4), C(5)); continue; } if (SCAN("al_draw_ellipse", 6)) { al_draw_ellipse(F(0), F(1), F(2), F(3), C(4), F(5)); continue; } if (SCAN("al_draw_filled_ellipse", 5)) { al_draw_filled_ellipse(F(0), F(1), F(2), F(3), C(4)); continue; } if (SCAN("al_draw_circle", 5)) { al_draw_circle(F(0), F(1), F(2), C(3), F(4)); continue; } if (SCAN("al_draw_filled_circle", 4)) { al_draw_filled_circle(F(0), F(1), F(2), C(3)); continue; } if (SCAN("al_draw_arc", 7)) { al_draw_arc(F(0), F(1), F(2), F(3), F(4), C(5), F(6)); continue; } if (SCAN("al_draw_elliptical_arc", 8)) { al_draw_elliptical_arc(F(0), F(1), F(2), F(3), F(4), F(5), C(6), F(7)); continue; } if (SCAN("al_draw_spline", 3)) { float pt[8]; if (sscanf(V(0), "%f, %f, %f, %f, %f, %f, %f, %f", pt+0, pt+1, pt+2, pt+3, pt+4, pt+5, pt+6, pt+7) == 8) { al_draw_spline(pt, C(1), F(2)); continue; } } if (SCAN("al_draw_prim", 6)) { fill_vertices(cfg, V(0)); /* decl arg is ignored */ al_draw_prim(vertices, NULL, B(2), I(3), I(4), get_prim_type(V(5))); continue; } /* Keep 5.0 and 5.1 functions separate for easier merging. */ /* Primitives (5.1) */ if (SCAN("al_draw_polyline", 6)) { fill_simple_vertices(cfg, V(0)); al_draw_polyline(simple_vertices, 2 * sizeof(float), num_simple_vertices, get_line_join(V(1)), get_line_cap(V(2)), C(3), F(4), F(5)); continue; } if (SCAN("al_draw_polygon", 5)) { fill_simple_vertices(cfg, V(0)); al_draw_polygon(simple_vertices, num_simple_vertices, get_line_join(V(1)), C(2), F(3), F(4)); continue; } if (SCAN("al_draw_filled_polygon", 2)) { fill_simple_vertices(cfg, V(0)); al_draw_filled_polygon(simple_vertices, num_simple_vertices, C(1)); continue; } if (SCAN("al_draw_filled_polygon_with_holes", 3)) { fill_simple_vertices(cfg, V(0)); fill_vertex_counts(cfg, V(1)); al_draw_filled_polygon_with_holes(simple_vertices, vertex_counts, C(2)); continue; } /* Transformations (5.1) */ if (SCAN("al_horizontal_shear_transform", 2)) { al_horizontal_shear_transform(get_transform(V(0)), F(1)); continue; } if (SCAN("al_vertical_shear_transform", 2)) { al_vertical_shear_transform(get_transform(V(0)), F(1)); continue; } if (SCAN("al_orthographic_transform", 7)) { al_orthographic_transform(get_transform(V(0)), F(1), F(2), F(3), F(4), F(5), F(6)); continue; } if (SCAN("al_use_projection_transform", 1)) { al_use_projection_transform(get_transform(V(0))); continue; } if (SCAN("al_set_blend_color", 1)) { al_set_blend_color(C(0)); continue; } /* Simple arithmetic, generally useful. (5.1) */ if (SCANLVAL("isum", 2)) { int result = I(0) + I(1); set_config_int(cfg, testname, lval, result); continue; } if (SCANLVAL("idif", 2)) { int result = I(0) - I(1); set_config_int(cfg, testname, lval, result); continue; } if (SCANLVAL("imul", 2)) { int result = I(0) * I(1); set_config_int(cfg, testname, lval, result); continue; } if (SCANLVAL("idiv", 2)) { int result = I(0) / I(1); set_config_int(cfg, testname, lval, result); continue; } if (SCANLVAL("fsum", 2)) { float result = F(0) + F(1); set_config_float(cfg, testname, lval, result); continue; } if (SCANLVAL("fdif", 2)) { float result = F(0) - F(1); set_config_float(cfg, testname, lval, result); continue; } if (SCANLVAL("fmul", 2)) { float result = F(0) * F(1); set_config_float(cfg, testname, lval, result); continue; } if (SCANLVAL("fdiv", 2)) { float result = F(0) / F(1); set_config_float(cfg, testname, lval, result); continue; } if (SCANLVAL("round", 1)) { int result = round(F(0)); set_config_int(cfg, testname, lval, result); continue; } /* Dynamical variable initialisation, needed to properly initialize * variables (5.1)*/ if (SCANLVAL("int", 1)) { float result = F(0); set_config_float(cfg, testname, lval, result); continue; } if (SCANLVAL("float", 1)) { float result = F(0); set_config_float(cfg, testname, lval, result); continue; } /* Fonts: per glyph text handling (5.1) */ if (SCAN("al_draw_glyph", 5)) { al_draw_glyph(get_font(V(0)), C(1), F(2), F(3), I(4)); continue; } if (SCANLVAL("al_get_glyph_advance", 3)) { int kerning = al_get_glyph_advance(get_font(V(0)), I(1), I(2)); set_config_int(cfg, testname, lval, kerning); continue; } if (SCANLVAL("al_get_glyph_width", 2)) { int w = al_get_glyph_width(get_font(V(0)), I(1)); set_config_int(cfg, testname, lval, w); continue; } if (SCANLVAL("al_get_glyph_dimensions", 6)) { int bbx, bby, bbw, bbh; bool ok = al_get_glyph_dimensions(get_font(V(0)), I(1), &bbx, &bby, &bbw, &bbh); set_config_int(cfg, testname, V(2), bbx); set_config_int(cfg, testname, V(3), bby); set_config_int(cfg, testname, V(4), bbw); set_config_int(cfg, testname, V(5), bbh); set_config_int(cfg, testname, lval, ok); continue; } if (SCANLVAL("al_color_distance_ciede2000", 2)) { float d = al_color_distance_ciede2000(C(0), C(1)); set_config_float(cfg, testname, lval, d); continue; } if (SCANLVAL("al_color_lab", 3)) { ALLEGRO_COLOR rgb = al_color_lab(F(0), F(1), F(2)); char hex[100]; sprintf(hex, "%f/%f/%f", rgb.r, rgb.g, rgb.b); al_set_config_value(cfg, testname, lval, hex); continue; } fatal_error("statement didn't scan: %s", stmt); } al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA); bool good; if (do_check_hash) { good = check_hash(cfg, testname, target, bmp_type); } else { good = check_similarity(cfg, testname, target, membuf, bmp_type, reliable); } total_tests++; if (save_outputs && (!save_on_failure || !good)) { ALLEGRO_USTR *filename = al_ustr_newf("%s [%s].png", testname, bmp_type_to_string(bmp_type)); al_save_bitmap(al_cstr(filename), target); al_ustr_free(filename); } if (!quiet) { if (target != al_get_backbuffer(display)) { set_target_reset(al_get_backbuffer(display)); al_draw_bitmap(target, 0, 0, 0); } al_flip_display(); al_rest(delay); } /* Ensure we don't target a bitmap which is about to be destroyed. */ al_set_target_bitmap(display ? al_get_backbuffer(display) : NULL); /* Destroy local bitmaps. */ for (i = num_global_bitmaps; i < MAX_BITMAPS; i++) { if (bitmaps[i].name) { al_ustr_free(bitmaps[i].name); bitmaps[i].name = NULL; al_destroy_bitmap(bitmaps[i].bitmap[bmp_type]); bitmaps[i].bitmap[bmp_type] = NULL; } } /* Free transform names. */ for (i = 0; i < MAX_TRANS; i++) { al_ustr_free(transforms[i].name); transforms[i].name = NULL; } return good; #undef MAXBUF } static void sw_hw_test(ALLEGRO_CONFIG *cfg, char const *testname) { bool reliable = true; char const *hw_only_str = al_get_config_value(cfg, testname, "hw_only"); char const *sw_only_str = al_get_config_value(cfg, testname, "sw_only"); char const *skip_on_xvfb_str = al_get_config_value(cfg, testname, "skip_on_xvfb"); bool hw_only = hw_only_str && get_bool(hw_only_str); bool sw_only = sw_only_str && get_bool(sw_only_str); bool skip_on_xvfb = skip_on_xvfb_str && get_bool(skip_on_xvfb_str); if (skip_on_xvfb && on_xvfb) { skipped_tests++; return; } al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); if (!hw_only) { reliable = do_test(cfg, testname, membuf, SW, true, true); } if (sw_only) return; if (display) { al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP); do_test(cfg, testname, al_get_backbuffer(display), HW, reliable, hw_only); } else if (hw_only) { printf("WARNING: Skipping hardware-only test due to the --no-display flag: %s\n", testname); skipped_tests++; } } static bool section_exists(ALLEGRO_CONFIG const *cfg, char const *section) { ALLEGRO_CONFIG_ENTRY *iter; return al_get_first_config_entry(cfg, section, &iter) != NULL; } static void merge_config_sections( ALLEGRO_CONFIG *targ_cfg, char const *targ_section, ALLEGRO_CONFIG const *src_cfg, char const *src_section) { char const *key; char const *value; ALLEGRO_CONFIG_ENTRY *iter; value = al_get_config_value(src_cfg, src_section, "extend"); if (value) { if (streq(value, src_section)) { fatal_error("section cannot extend itself: %s " "(did you forget to rename a section?)", src_section); } merge_config_sections(targ_cfg, targ_section, src_cfg, value); } key = al_get_first_config_entry(src_cfg, src_section, &iter); if (!key) { fatal_error("missing section: %s", src_section); } for (; key != NULL; key = al_get_next_config_entry(&iter)) { value = al_get_config_value(src_cfg, src_section, key); al_set_config_value(targ_cfg, targ_section, key, value); } } static void run_test(ALLEGRO_CONFIG const *cfg, char const *section) { char const *extend; ALLEGRO_CONFIG *cfg2; if (!section_exists(cfg, section)) { fatal_error("section not found: %s", section); } cfg2 = al_create_config(); al_merge_config_into(cfg2, cfg); extend = al_get_config_value(cfg, section, "extend"); if (extend) { merge_config_sections(cfg2, section, cfg, section); } sw_hw_test(cfg2, section); al_destroy_config(cfg2); } static void run_matching_tests(ALLEGRO_CONFIG const *cfg, const char *prefix) { ALLEGRO_CONFIG_SECTION *iter; char const *section; for (section = al_get_first_config_section(cfg, &iter); section != NULL; section = al_get_next_config_section(&iter)) { if (0 == strncmp(section, prefix, strlen(prefix))) { run_test(cfg, section); } } } static void partial_tests(ALLEGRO_CONFIG const *cfg, int n) { ALLEGRO_USTR *name = al_ustr_new(""); while (n > 0) { /* Automatically prepend "test" for convenience. */ if (0 == strncmp(argv[0], "test ", 5)) { al_ustr_assign_cstr(name, argv[0]); } else { al_ustr_truncate(name, 0); al_ustr_appendf(name, "test %s", argv[0]); } /* Star suffix means run all matching tests. */ if (al_ustr_has_suffix_cstr(name, "*")) { al_ustr_truncate(name, al_ustr_size(name) - 1); run_matching_tests(cfg, al_cstr(name)); } else { run_test(cfg, al_cstr(name)); } argc--; argv++; n--; } al_ustr_free(name); } static bool has_suffix(char const *s, char const *suf) { return (strlen(s) >= strlen(suf)) && streq(s + strlen(s) - strlen(suf), suf); } static void process_ini_files(void) { ALLEGRO_CONFIG *cfg; int n; while (argc > 0) { if (!has_suffix(argv[0], ".ini")) fatal_error("expected .ini argument: %s\n", argv[0]); cfg = al_load_config_file(argv[0]); if (!cfg) fatal_error("failed to load config file %s", argv[0]); if (verbose) printf("Running %s\n", argv[0]); argc--; argv++; al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); load_bitmaps(cfg, "bitmaps", SW, ALLEGRO_NO_PREMULTIPLIED_ALPHA); if (display) { al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP); load_bitmaps(cfg, "bitmaps", HW, ALLEGRO_NO_PREMULTIPLIED_ALPHA); } load_fonts(cfg, "fonts"); for (n = 0; n < argc; n++) { if (has_suffix(argv[n], ".ini")) break; } if (n == 0) run_matching_tests(cfg, "test "); else partial_tests(cfg, n); unload_data(); al_destroy_config(cfg); } } const char* help_str = " [OPTION] CONFIG_FILE [TEST_NAME]... [CONFIG_FILE [TEST_NAME]...]...\n" "\n" "Run Allegro graphical output tests within one or more CONFIG_FILEs (each\n" "having an .ini extension). By default this program runs all the tests in a\n" "file, but individual TEST_NAMEs can be specified after each CONFIG_FILE.\n" "\n" "Options:\n" " -d, --delay duration (in sec) to wait between tests\n" " --force-d3d force using D3D (Windows only)\n" " --force-opengl-1.2 force using OpenGL 1.2\n" " --force-opengl-2.0 force using OpenGL 2.0\n" " --force-opengl force using OpenGL\n" " -f, --save_on_failure save the output of failred tests in the current directory\n" " -h, --help display this message\n" " -n, --no-display do not create a display (hardware drawing is disabled)\n" " -s, --save save the output of each test in the current directory\n" " --use-shaders use the programmable pipeline for drawing\n" " -v, --verbose show additional information after each test\n" " -q, --quiet do not draw test output to the display\n" " --xvfb indicates that we're running on XVFB, skipping tests if necessary\n"; int main(int _argc, char *_argv[]) { int display_flags = 0; argc = _argc; argv = _argv; if (argc == 1) { fatal_error("requires config file argument.\nSee --help for usage"); } argc--; argv++; if (!al_init()) { fatal_error("failed to initialise Allegro"); } al_init_image_addon(); al_init_font_addon(); al_init_ttf_addon(); al_init_primitives_addon(); for (; argc > 0; argc--, argv++) { char const *opt = argv[0]; if (streq(opt, "-d") || streq(opt, "--delay")) { delay = 1.0; } else if (streq(opt, "-s") || streq(opt, "--save")) { save_outputs = true; } else if (streq(opt, "-f") || streq(opt, "--save_on_failure")) { save_on_failure = true; save_outputs = true; } else if (streq(opt, "--xvfb")) { on_xvfb = true; } else if (streq(opt, "-q") || streq(opt, "--quiet")) { quiet = true; } else if (streq(opt, "-n") || streq(opt, "--no-display")) { want_display = false; quiet = true; } else if (streq(opt, "-v") || streq(opt, "--verbose")) { verbose++; } else if (streq(opt, "--force-opengl-1.2")) { ALLEGRO_CONFIG *cfg = al_get_system_config(); al_set_config_value(cfg, "opengl", "force_opengl_version", "1.2"); display_flags |= ALLEGRO_OPENGL; } else if (streq(opt, "--force-opengl-2.0")) { ALLEGRO_CONFIG *cfg = al_get_system_config(); al_set_config_value(cfg, "opengl", "force_opengl_version", "2.0"); display_flags |= ALLEGRO_OPENGL; } else if (streq(opt, "--force-opengl")) { display_flags |= ALLEGRO_OPENGL; } else if (streq(opt, "--force-d3d")) { /* Don't try this at home. */ display_flags |= ALLEGRO_DIRECT3D_INTERNAL; } else if (streq(opt, "--use-shaders")) { display_flags |= ALLEGRO_PROGRAMMABLE_PIPELINE; } else if (streq(opt, "-h") || streq(opt, "--help")) { printf("Usage:\n%s%s", _argv[0], help_str); return 0; } else { break; } } if (want_display) { al_set_new_display_flags(display_flags); display = al_create_display(640, 480); if (!display) { fatal_error("failed to create display"); } } al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); if (want_display) { membuf = al_create_bitmap( al_get_display_width(display), al_get_display_height(display)); } else { membuf = al_create_bitmap(640, 480); } process_ini_files(); printf("\n"); printf("total tests: %d\n", total_tests); printf("passed tests: %d\n", passed_tests); printf("failed tests: %d\n", failed_tests); printf("skipped tests: %d\n", skipped_tests); printf("\n"); return !!failed_tests; } /* vim: set sts=3 sw=3 et: */ allegro5-5.2.10.1/tests/test_driver.txt000066400000000000000000000071261473414355200177230ustar00rootroot00000000000000Usage ===== test_driver [OPTIONS] config1.ini [TESTS ...] [config2.ini [TESTS...]] ... where options are: -d, --delay delay between tests -s, --save save output images as .png -q, --quiet don't display graphical output -v, --verbose print extra output -v -v extra extra verbose --force-opengl select OpenGL driver --force-opengl-1.2 restrict Allegro to OpenGL 1.2 --force-opengl-2.0 restrict Allegro to OpenGL 2.0 --force-d3d select Direct3D driver If the list of tests is omitted then every test in the config file will be run. Otherwise each test named on the command line is run. For convenience, you may drop the "test " prefix on test names. If a test name ends with an asterisk, then all tests which match that prefix will be run, e.g. ./test_driver -d test_bitmaps.ini 'scaled rotate*' Every test is run with both memory and video bitmaps. The software rendered result is checked against an expected hash code. The hardware rendered result is checked for similarity with the software result. Config file format ================== Each [test ...] section defines a single test, containing one or more operations named by the keys op0, op1, ... opN. The value of each op key is a call to an Allegro function, or empty. Each argument of the call must be a literal of the correct type, or a variable name. A variable name is just another key in the section, whose value is taken as a _literal_ to be substituted in place of the variable. A test may inherit the keys of another section using the 'extend' key. Keys in the child section override keys in the parent. The [bitmaps] section defines a list of bitmaps to load, relative to the tests directory. Each key name is then a valid bitmap literal. The name 'target' refers to the default target bitmap. ALLEGRO_COLOR literals may be written as #rrggbb, #rrggbbaa or a named color (e.g. purple). Integer, float and enumeration literals are written as per C. (Note that "ALLEGRO_FLIP_HORIZONTAL|ALLEGRO_FLIP_VERTICAL" must be written without whitespace, because we don't have a proper parser.) String literals are not supported, but you can use a variable whose value is treated as the string contents (no quotes). Transformations are automatically created the first time they are mentioned, and set to the identity matrix. Each test section contains a key called 'hash', containing the hash code of the expected output for that test. When writing a test you should check (visually) that the output looks correct, then add the hash code computed hash code to the test section. Some tests produce slightly different (but still acceptable) output depending on the hardware, compiler or optimisation settings. As an alternative to 'hash', which will only pass if the result is exactly the same, you can use the 'sig' key. This will perform a loose comparison on "signatures" which are computed from the average intensity levels (greyscale) at 81 points on the image. Hopefully it is still strict enough to catch any major regressions. You can supply both 'hash' and 'sig' keys. Finally, 'hash=off' will disable hash checking entirely. For example, TTF rendering depends on the FreeType configuration, and the differences are big enough to show up even in the thumbnails. The hardware implementation is compared against the software implementation, with some tolerance. The tolerance is arbitrary but you can set it if necessary with the 'tolerance' key. In case the HW results is supposed to look different, a separate hash can be specifeid with 'hw_hash' instead of the similarity comparison. allegro5-5.2.10.1/tests/test_fonts.ini000066400000000000000000000201461473414355200175160ustar00rootroot00000000000000[fonts] bmpfont=al_load_font(bmp_filename, 24, flags) asciifont=al_load_font(ascii_filename, 24, flags) builtin=al_create_builtin_font() ttf=al_load_font(ttf_filename, 24, flags) ttf_tall=al_load_ttf_font_stretch(ttf_filename, 24, 48, flags) ttf_wide=al_load_ttf_font_stretch(ttf_filename, 48, 24, flags) ttf_px1=al_load_font(ttf_filename, -32, flags) ttf_px2=al_load_ttf_font_stretch(ttf_filename, 0, -32, flags) ttf_px3=al_load_ttf_font_stretch(ttf_filename, -24, -32, flags) # arguments bmp_filename=../examples/data/a4_font.tga ascii_filename=../examples/data/fixed_font.tga ttf_filename=../examples/data/DejaVuSans.ttf flags=ALLEGRO_NO_PREMULTIPLIED_ALPHA [text] en=Welcome to Allegro gr=Καλώς ήρθατε στο Allegro latin1=aábdðeéfghiíjkprstuúvxyýþæö missing=here -> á <- is unicode #00E1 [test font bmp] extend=text op0=al_clear_to_color(rosybrown) op1=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op2= op3=al_draw_text(font, darkred, 320, 100, ALLEGRO_ALIGN_LEFT, en) op4=al_draw_text(font, white, 320, 150, ALLEGRO_ALIGN_CENTRE, en) op5=al_draw_text(font, blue, 320, 200, ALLEGRO_ALIGN_RIGHT, en) op6= font=bmpfont hash=68f73534 [test font bmp hold] extend=test font bmp op2=al_hold_bitmap_drawing(true) op6=al_hold_bitmap_drawing(false) [test font builtin] extend=text op0=al_clear_to_color(rosybrown) op1=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op2=al_draw_text(font, darkred, 320, 100, ALLEGRO_ALIGN_LEFT, en) op3=al_draw_text(font, white, 320, 150, ALLEGRO_ALIGN_CENTRE, latin1) font=builtin hash=502aa12f [test font ttf] extend=test font bmp op6=al_draw_text(font, khaki, 320, 300, ALLEGRO_ALIGN_CENTRE, gr) font=ttf # Result changes with the FreeType configuration of the system. hash=off [test font ttf hold] extend=test font ttf op2=al_hold_bitmap_drawing(true) op7=al_hold_bitmap_drawing(false) [test font ttf tall] extend=test font ttf font=ttf_tall [test font ttf wide] extend=test font ttf font=ttf_wide [test font ttf pixelsize 1] extend=test font ttf font=ttf_px1 [test font ttf pixelsize 2] extend=test font ttf font=ttf_px2 [test font ttf pixelsize 3] extend=test font ttf font=ttf_px3 [test font bmp justify] extend=text op0=al_clear_to_color(#886655) op1=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op2=al_draw_justified_text(bmpfont, black, 100, 540, 100, 0, 0, en) op3=al_draw_justified_text(bmpfont, black, 100, 540, 150, 1000, 0, en) hash=6a402079 [test font ttf justify] extend=test font bmp justify op4=al_draw_justified_text(ttf, black, 100, 540, 300, 0, 0, gr) op5=al_draw_justified_text(ttf, black, 100, 540, 350, 1000, 0, gr) # Result changes with the FreeType configuration of the system. hash=off [test font complex] extend=text op0=al_clear_to_color(#665544) op1=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op2=al_build_transform(T, cx, cy, 2.0, 2.0, -0.3) op3=al_use_transform(T) op4=al_draw_text(ttf, #aabbcc80, 0, 0, ALLEGRO_ALIGN_CENTRE, en) op5=al_build_transform(T, cx, cy, 2.0, 2.0, 0.3) op6=al_use_transform(T) op7=al_draw_text(ttf, #eebbaa80, 0, 0, ALLEGRO_ALIGN_CENTRE, gr) op8=al_build_transform(T2, cx, 360, 20, 20, 0) op9=al_use_transform(T2) op10=al_draw_text(bmpfont, #88888855, 0, 0, ALLEGRO_ALIGN_CENTRE, yeah) cx=320 cy=200 yeah=yeah! # Result changes with the FreeType configuration of the system. hash=off [test font dimensions ttf en] op0= al_clear_to_color(#665544) op1= al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op2= al_translate_transform(T, 100, 100) op3= al_use_transform(T) op4= al_get_text_dimensions(font, str, bbx, bby, bbw, bbh) # We can't actually draw it without introducing arithmetic. #op5=al_draw_rectangle(bbx, bby, bbx+bbw, bby+bbh, black, 0) op5= op6= al_draw_text(font, #aabbcc80, 0, 0, ALLEGRO_ALIGN_LEFT, str) op7= op8= al_translate_transform(T, 0, 100) op9= al_use_transform(T) op10=w = al_get_text_width(font, str) op11=h = al_get_font_line_height(font) op12=as = al_get_font_ascent(font) op13=de = al_get_font_descent(font) # Note: the hw version blurs the lines because we can't add 0.5 offsets. op14=al_draw_rectangle(0, 0, w, h, black, 0) op15=al_draw_line(0, as, w, as, black, 0) op16=al_draw_line(0, de, w, de, black, 0) op17=al_draw_text(font, #aabbcc80, 0, 0, ALLEGRO_ALIGN_LEFT, str) font=ttf str=Welcome to Allegro hash=off [test font dimensions ttf gr] extend=test font dimensions ttf en str=Καλώς ήρθατε στο Allegro hash=off [test font dimensions bmp] extend=test font dimensions ttf en font=bmpfont hash=4284d74d # Not a font test but requires a font. [test d3d cache state bug] op0=image = al_create_bitmap(20, 20) op1=al_set_target_bitmap(image) op2=al_clear_to_color(white) op3=al_set_target_bitmap(target) op4=al_clear_to_color(#00000000) op5=al_draw_text(bmpfont, red, 0, 0, ALLEGRO_ALIGN_LEFT, str) op6=al_set_blender(ALLEGRO_DEST_MINUS_SRC, ALLEGRO_ALPHA, ALLEGRO_ONE) op7=al_draw_rectangle(45, 45, 75, 75, #ffffff40, 1) op8=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA) op9=al_draw_tinted_bitmap(image, #ffffffff, 50, 50, 0) str=Hello hash=249efe55 # Per glyph drawing [test font glyph simple builtin en] op0= al_clear_to_color(#665544) op1= al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op2= x = int(100) op3= y = int(100) op4= # al_hold_bitmap_drawing(1) op5= al_draw_glyph(font, glyph_color, x, y, glyph) # op6= al_hold_bitmap_drawing(0) font=builtin glyph=84 x=100 y=100 glyph_color=#00ff00ff hash=5a674455 [test font glyph simple bmp en] extend=test font glyph simple builtin en font=bmpfont hash=5a674455 [test font glyph simple ttf en] extend=test font glyph simple builtin en font=ttf hash=6ed595a5 sig=LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL [test font glyph simple ttf gr] extend=test font glyph simple builtin en font=ttf glyph=922 hash=f02da2af sig=LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL # Per glyph drawing [test font glyph match builtin en] op0= al_clear_to_color(#665544) op1= al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op2= x = int(100) op3= y = int(100) op4= # al_hold_bitmap_drawing(0) op5= al_draw_text(font, blue, x, y, ALLEGRO_ALIGN_LEFT, str) op6= al_draw_text(font, text_color, x, y, ALLEGRO_ALIGN_LEFT, str) op7= glyph_Tu_k = al_get_glyph_advance(font, glyph_T, glyph_u) op8= glyph_ul_k = al_get_glyph_advance(font, glyph_u, glyph_l) op9= glyph_li_k = al_get_glyph_advance(font, glyph_l, glyph_i) op10= glyph_ip_k = al_get_glyph_advance(font, glyph_i, glyph_p) op11= al_draw_glyph(font, glyph_color, x, y, glyph_T) op12= x = isum(x, glyph_Tu_k) op13= al_draw_glyph(font, glyph_color, x, y, glyph_u) op14= x = isum(x, glyph_ul_k) op15= al_draw_glyph(font, glyph_color, x, y, glyph_l) op16= x = isum(x, glyph_li_k) op17= al_draw_glyph(font, glyph_color, x, y, glyph_i) op18= x = isum(x, glyph_ip_k) op19= al_draw_glyph(font, glyph_color, x, y, glyph_p) op20= x = isum(x, glyph_p_w) op21= h = al_get_font_line_height(font) op22= x = int(100) op23= y = int(100) op24= # al_hold_bitmap_drawing(0) font=builtin str=Tulip glyph_T=84 glyph_u=117 glyph_l=108 glyph_i=105 glyph_p=112 glyph_Tu_k=0 glyph_ul_k=0 glyph_li_k=0 glyph_ip_k=0 x=100 y=100 text_color=#ff0000ff glyph_color=#00ff00ff hash=60affa5d [test font glyph match bmp en] extend=test font glyph match builtin en font=bmpfont str=Tulip hash=60affa5d [test font glyph match ttf en] extend=test font glyph match builtin en font=ttf hash=5857f828 sig=LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL [test font glyph match ttf gr] extend=test font glyph match ttf en glyph_T=922 glyph_u=945 glyph_l=955 glyph_i=974 glyph_p=962 str=Καλώς font=ttf hash=f0ff79f6 sig=LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL [test font fallback] extend=text op0=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op1=al_clear_to_color(black) op2=al_draw_text(asciifont, yellow, 100, 100, 0, missing) op3=al_set_fallback_font(asciifont, builtin) op4=al_draw_text(asciifont, yellow, 100, 120, 0, missing) op5=al_set_fallback_font(asciifont, NULL) op6=al_draw_text(builtin, yellow, 100, 140, 0, missing) hash=c4ee101f allegro5-5.2.10.1/tests/test_image.ini000066400000000000000000000075121473414355200174510ustar00rootroot00000000000000[bitmaps] allegro=../examples/data/allegro.pcx [fonts] builtin=al_create_builtin_font() # We can't assume that a backbuffer with alpha is available, so draw # to a temporary bitmap. [template] op0=temp = al_create_bitmap(640, 480) op1=al_set_target_bitmap(temp) op2=al_clear_to_color(brown) op3=b = al_load_bitmap_flags(filename, flags) op4=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA) op5=al_draw_bitmap(b, 0, 0, 0) op6=al_set_target_bitmap(target) op7=al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ZERO, ALLEGRO_ONE) op8=al_draw_bitmap(temp, 0, 0, 0) flags=ALLEGRO_NO_PREMULTIPLIED_ALPHA [test bmp] extend=template filename=../examples/data/fakeamp.bmp hash=62176b87 [test bmp 8bpp] extend=template filename=../examples/data/alexlogo.bmp hash=08b3a51d [test jpg] extend=template filename=../examples/data/obp.jpg hash=8e37f5f3 sig=lXWWYJaWKicWTKIXYKdecgPKaYKaeHLRLbYKhJSEFHbZKhJIHFJdYKn1IEFabVKPSQNPNNNKKKKKKKKKK [test pcx] extend=template filename=../examples/data/allegro.pcx hash=c44929e5 [test png] extend=template filename=../examples/data/mysha256x256.png hash=771a3491 [test png premul] extend=template filename=../examples/data/mysha256x256.png flags=0 hash=48965052 [test tga] extend=template filename=../examples/data/fixed_font.tga hash=64fa3221 [test webp] extend=template filename=../examples/data/mysha256x256.webp hash=771a3491 [test webp premul] extend=template filename=../examples/data/mysha256x256.webp flags=0 hash=48965052 # These indexed images may be displayed in shades of red (OpenGL >= 3) # or greyscale (OpenGL < 3). [test bmp indexed] extend=template filename=../examples/data/alexlogo.bmp flags=ALLEGRO_KEEP_INDEX hash=1d899e47 [test bmp indexed uncompressed] extend=template filename=../examples/data/gradient1.bmp flags=ALLEGRO_KEEP_INDEX hash=b5ba9d35 [test pcx indexed] extend=template filename=../examples/data/allegro.pcx flags=ALLEGRO_KEEP_INDEX hash=681b712d hash_hw=6fb8e2d5 [test png indexed] extend=template filename=../examples/data/alexlogo.png flags=ALLEGRO_KEEP_INDEX hash=1d899e47 [test png palette] extend=template filename=../examples/data/mysha_pal.png flags=0 # TODO: Figure out why this fails on 32 bits. sig=FlOKKKKKKugMKKKKKKjLKKKKKKK26FKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK [test png interlaced] extend=template filename=../examples/data/icon.png flags=0 hash=9e6b5342 [save template] op0=al_save_bitmap(filename, allegro) op1=b = al_load_bitmap_flags(filename, ALLEGRO_NO_PREMULTIPLIED_ALPHA) op2=al_clear_to_color(brown) op3=al_draw_bitmap(b, 0, 0, 0) [test save bmp] extend=save template filename=tmp.bmp hash=c44929e5 [test save jpg] extend=save template filename=tmp.jpg sig=jdelWKKKKaYmeXKKKKLNVNKKKKKHHHLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK [test save pcx] extend=save template filename=tmp.pcx hash=c44929e5 [test save png] extend=save template filename=tmp.png hash=c44929e5 [test save tga] extend=save template filename=tmp.tga hash=c44929e5 [test save webp] extend=save template filename=tmp.webp hash=c44929e5 [identify] op0=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA) op1=ext = al_identify_bitmap(filename) op2=al_draw_text(builtin, yellow, 0, 0, 0, ext) [test identify bmp] extend = identify filename=../examples/data/fakeamp.bmp hash=b5436ae7 [test identify png] extend = identify filename=../examples/data/alexlogo.png hash=05da299b [test identify jpg] extend = identify filename=../examples/data/obp.jpg hash=6e2b0f7d [test identify pcx] extend = identify filename=../examples/data/allegro.pcx hash=5d1d24db [test identify tga] extend = identify filename=../examples/data/fixed_font.tga hash=fca11c13 [test identify webp] extend = identify filename=../examples/data/mysha256x256.webp hash=30a6aae7 [test identify dds] extend = identify filename=../examples/data/mysha_dxt5.dds hash=84ab6fb5 allegro5-5.2.10.1/tests/test_list.c000066400000000000000000000056511473414355200170070ustar00rootroot00000000000000/* * Tests for Allegro's list function. */ #include #include #include "allegro5/allegro.h" #include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_list.h" static void test_basic_dynamic_usage(void) { int xs[4] = {1, 2, 3, 4}; _AL_LIST_ITEM* item; int i; _AL_LIST* list = _al_list_create(); assert(_al_list_is_empty(list)); assert(_al_list_front(list) == NULL); assert(_al_list_back(list) == NULL); assert(_al_list_size(list) == 0); _al_list_push_back(list, &xs[0]); assert(!_al_list_is_empty(list)); assert(_al_list_size(list) == 1); item = _al_list_front(list); i = 0; while (item) { assert(*(int*)_al_list_item_data(item) == xs[i]); item = _al_list_at(list, i); assert(*(int*)_al_list_item_data(item) == xs[i]); assert(_al_list_contains(list, &xs[i])); item = _al_list_next(list, item); i++; } item = _al_list_back(list); i = _al_list_size(list) - 1; while (item) { assert(*(int*)_al_list_item_data(item) == xs[i]); item = _al_list_previous(list, item); i--; } _al_list_push_back(list, &xs[1]); assert(_al_list_size(list) == 2); item = _al_list_front(list); i = 0; while (item) { assert(*(int*)_al_list_item_data(item) == xs[i]); item = _al_list_at(list, i); assert(*(int*)_al_list_item_data(item) == xs[i]); assert(_al_list_contains(list, &xs[i])); item = _al_list_next(list, item); i++; } item = _al_list_back(list); i = _al_list_size(list) - 1; while (item) { assert(*(int*)_al_list_item_data(item) == xs[i]); item = _al_list_previous(list, item); i--; } _al_list_push_back(list, &xs[2]); assert(_al_list_size(list) == 3); item = _al_list_front(list); i = 0; while (item) { assert(*(int*)_al_list_item_data(item) == xs[i]); item = _al_list_at(list, i); assert(*(int*)_al_list_item_data(item) == xs[i]); assert(_al_list_contains(list, &xs[i])); item = _al_list_next(list, item); i++; } item = _al_list_back(list); i = _al_list_size(list) - 1; while (item) { assert(*(int*)_al_list_item_data(item) == xs[i]); item = _al_list_previous(list, item); i--; } _al_list_push_back(list, &xs[3]); assert(_al_list_size(list) == 4); item = _al_list_front(list); i = 0; while (item) { assert(*(int*)_al_list_item_data(item) == xs[i]); item = _al_list_at(list, i); assert(*(int*)_al_list_item_data(item) == xs[i]); assert(_al_list_contains(list, &xs[i])); item = _al_list_next(list, item); i++; } item = _al_list_back(list); i = _al_list_size(list) - 1; while (item) { assert(*(int*)_al_list_item_data(item) == xs[i]); item = _al_list_previous(list, item); i--; } } int main(int argc, char *argv[]) { (void)argc; (void)argv; test_basic_dynamic_usage(); return 0; } allegro5-5.2.10.1/tests/test_locking.ini000066400000000000000000000067331473414355200200210ustar00rootroot00000000000000# Too many parameters to test... # target: memory, backbuffer, off-screen texture # mode: WRITEONLY, READWRITE, READONLY # all the pixel formats (24b especially problematic) # odd sizes especially problematic # lock region or entire bitmap # Locking an off-screen bitmap [texture] op0= al_clear_to_color(#554321) op1= op2= bmp = al_create_bitmap(640, 480) op3= al_set_target_bitmap(bmp) op4= al_clear_to_color(#00000000) op5= al_lock_bitmap_region(bmp, 133, 65, 381, 327, format, flags) op6= fill_lock_region(alphafactor, false) op7= al_unlock_bitmap(bmp) op8= op9= al_set_target_bitmap(target) op10=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op11=al_draw_bitmap(bmp, 0, 0, 0) flags=ALLEGRO_LOCK_WRITEONLY alphafactor=1.0 [test texture 32b ARGB_8888] extend=texture format=ALLEGRO_PIXEL_FORMAT_ARGB_8888 hash=25e01c26 sig=FFFFFFFFFFFDDEGKMFFFEEGJOQFFFEGINTVFFFFHLQYZFFFFINUcdFFFGKPXhiFFFHLSbmmFFFFFFFFFF [test texture 32b RGBA_8888] extend=texture format=ALLEGRO_PIXEL_FORMAT_RGBA_8888 hash=25e01c26 sig=FFFFFFFFFFFDDEGKMFFFEEGJOQFFFEGINTVFFFFHLQYZFFFFINUcdFFFGKPXhiFFFHLSbmmFFFFFFFFFF [test texture 16b ARGB_4444] extend=texture format=ALLEGRO_PIXEL_FORMAT_ARGB_4444 hash=94ba90ac sig=FFFFFFFFFFFDDDEIKFFFEEFIMOFFFEEHKQSFFFFGKOWXFFFFHMRabFFFGIOVffFFFGJQXkjFFFFFFFFFF [test texture 24b RGB_888] extend=texture format=ALLEGRO_PIXEL_FORMAT_RGB_888 hash=5a844e39 sig=FFFFFFFFFFF59DHLMFFF9DIMQQFFFCHMRWVFFFGLRWcZFFFJPWcieFFFNUahniFFFRYfmtnFFFFFFFFFF [test texture 16b RGB_565] extend=texture format=ALLEGRO_PIXEL_FORMAT_RGB_565 hash=7ee470cd [test texture 15b RGB_555] extend=texture format=ALLEGRO_PIXEL_FORMAT_RGB_555 hash=d8bcc9c6 [test texture 16b RGBA_5551] extend=texture format=ALLEGRO_PIXEL_FORMAT_RGBA_5551 alphafactor=2.0 hash=752a4074 [test texture 16b ARGB_1555] extend=texture format=ALLEGRO_PIXEL_FORMAT_ARGB_1555 alphafactor=2.0 hash=752a4074 [test texture 32b ABGR_8888] extend=texture format=ALLEGRO_PIXEL_FORMAT_ABGR_8888 hash=25e01c26 sig=FFFFFFFFFFFDDEGKMFFFEEGJOQFFFEGINTVFFFFHLQYZFFFFINUcdFFFGKPXhiFFFHLSbmmFFFFFFFFFF [test texture 32b XBGR_8888] extend=texture format=ALLEGRO_PIXEL_FORMAT_XBGR_8888 hash=5a844e39 sig=FFFFFFFFFFF59DHLMFFF9DIMQQFFFCHMRWVFFFGLRWcZFFFJPWcieFFFNUahniFFFRYfmtnFFFFFFFFFF [test texture 24b BGR_888] extend=texture format=ALLEGRO_PIXEL_FORMAT_BGR_888 hash=5a844e39 sig=FFFFFFFFFFF59DHLMFFF9DIMQQFFFCHMRWVFFFGLRWcZFFFJPWcieFFFNUahniFFFRYfmtnFFFFFFFFFF [test texture 16b BGR_565] extend=texture format=ALLEGRO_PIXEL_FORMAT_BGR_565 hash=7ee470cd [test texture 15b BGR_555] extend=texture format=ALLEGRO_PIXEL_FORMAT_BGR_555 hash=d8bcc9c6 [test texture 32b RGBX_8888] extend=texture format=ALLEGRO_PIXEL_FORMAT_RGBX_8888 hash=5a844e39 sig=FFFFFFFFFFF59DHLMFFF9DIMQQFFFCHMRWVFFFGLRWcZFFFJPWcieFFFNUahniFFFRYfmtnFFFFFFFFFF [test texture 32b XRGB_8888] extend=texture format=ALLEGRO_PIXEL_FORMAT_XRGB_8888 hash=5a844e39 sig=FFFFFFFFFFF59DHLMFFF9DIMQQFFFCHMRWVFFFGLRWcZFFFJPWcieFFFNUahniFFFRYfmtnFFFFFFFFFF [test texture f32 ABGR_F32] extend=texture format=ALLEGRO_PIXEL_FORMAT_ABGR_F32 hash=25e01c26 sig=FFFFFFFFFFFDDEGKMFFFEEGJOQFFFEGINTVFFFFHLQYZFFFFINUcdFFFGKPXhiFFFHLSbmmFFFFFFFFFF [test texture 32b ABGR_8888_LE] extend=texture format=ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE hash=25e01c26 sig=FFFFFFFFFFFDDEGKMFFFEEGJOQFFFEGINTVFFFFHLQYZFFFFINUcdFFFGKPXhiFFFHLSbmmFFFFFFFFFF [test texture 16b RGBA_4444] extend=texture format=ALLEGRO_PIXEL_FORMAT_RGBA_4444 hash=94ba90ac sig=FFFFFFFFFFFDDDEIKFFFEEFIMOFFFEEHKQSFFFFGKOWXFFFFHMRabFFFGIOVffFFFGJQXkjFFFFFFFFFF allegro5-5.2.10.1/tests/test_locking2.ini000066400000000000000000000060461473414355200201000ustar00rootroot00000000000000[texture rw] op0= al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op1= op2= bmp = al_create_bitmap(640, 480) op3= al_set_target_bitmap(bmp) op4= al_clear_to_color(#554321) op5= al_lock_bitmap_region(bmp, 133, 65, 381, 327, format, flags) op6= fill_lock_region(alphafactor, true) op7= al_unlock_bitmap(bmp) op8= op9= al_set_target_bitmap(target) op10=al_clear_to_color(#00ff00) # Don't assume the screen has an alpha channel, it may be 24 bit. op11=al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ZERO, ALLEGRO_ONE) op12=al_draw_bitmap(bmp, 0, 0, 0) flags=ALLEGRO_LOCK_READWRITE alphafactor=1.0 [test texture rw 32b ARGB_8888] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_ARGB_8888 hash=d4866407 sig=FFFFFFFFFFFEEFHKMFFFFFHKOQFFFFHJMSUFFFGILPWZFFFGJMSadFFFHKOUeiFFFHLQXimFFFFFFFFFF [test texture rw 32b RGBA_8888] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_RGBA_8888 hash=d4866407 sig=FFFFFFFFFFFEEFHKMFFFFFHKOQFFFFHJMSUFFFGILPWZFFFGJMSadFFFHKOUeiFFFHLQXimFFFFFFFFFF [test texture rw 16b ARGB_4444] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_ARGB_4444 hash=32b551c9 [test texture rw 24b RGB_888] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_RGB_888 hash=dc5525e2 [test texture rw 16b RGB_565] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_RGB_565 hash=a51f89f0 [test texture rw 15b RGB_555] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_RGB_555 hash=200647c4 [test texture rw 16b RGBA_5551] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_RGBA_5551 hash=c42fb611 # NOTE: the correct output for this is all green except for one pixel column # on the right. [test texture rw 16b ARGB_1555] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_ARGB_1555 hash=c42fb611 # NOTE: the correct output for this is all green except for one pixel column # on the right. [test texture rw 32b ABGR_8888] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_ABGR_8888 hash=d4866407 sig=FFFFFFFFFFFEEFHKMFFFFFHKOQFFFFHJMSUFFFGILPWZFFFGJMSadFFFHKOUeiFFFHLQXimFFFFFFFFFF [test texture rw 32b XBGR_8888] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_XBGR_8888 hash=dc5525e2 [test texture rw 24b BGR_888] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_BGR_888 hash=dc5525e2 [test texture rw 16b BGR_565] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_BGR_565 hash=a51f89f0 [test texture rw 15b BGR_555] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_BGR_555 hash=200647c4 [test texture rw 32b RGBX_8888] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_RGBX_8888 hash=dc5525e2 [test texture rw 32b XRGB_8888] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_XRGB_8888 hash=dc5525e2 [test texture rw f32 ABGR_F32] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_ABGR_F32 hash=d4866407 sig=FFFFFFFFFFFEEFHKMFFFFFHKOQFFFFHJMSUFFFGILPWZFFFGJMSadFFFHKOUeiFFFHLQXimFFFFFFFFFF [test texture rw 32b ABGR_8888_LE] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE hash=d4866407 sig=FFFFFFFFFFFEEFHKMFFFFFHKOQFFFFHJMSUFFFGILPWZFFFGJMSadFFFHKOUeiFFFHLQXimFFFFFFFFFF [test texture rw 16b RGBA_4444] extend=texture rw format=ALLEGRO_PIXEL_FORMAT_RGBA_4444 hash=32b551c9 allegro5-5.2.10.1/tests/test_prim.ini000066400000000000000000000431301473414355200173320ustar00rootroot00000000000000[bitmaps] bkg=../examples/data/bkg.png texture=../examples/data/texture.tga obp=../examples/data/obp.jpg [ll] op0= al_draw_bitmap(bkg, 0, 0, 0) op1= al_build_transform(trans, 320, 240, 1, 1, 1.0) op2= op3= al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE) op4= al_use_transform(trans) op5= al_draw_prim(verts, 0, tex, 0, 4, ALLEGRO_PRIM_LINE_LIST) op6= al_draw_prim(verts, 0, tex, 4, 9, ALLEGRO_PRIM_LINE_STRIP) op7= al_draw_prim(verts, 0, tex, 9, 13, ALLEGRO_PRIM_LINE_LOOP) verts=vtx_ll tex=0 [test ll notex blend] extend=ll hash=3e2bdb71 [test ll notex opaque] extend=ll op3=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO) hash=8e491071 [test ll tex blend] extend=ll tex=texture hash=002007ce [test ll tex blend white] extend=ll verts=vtx_ll_white tex=texture hash=cccd8111 [test ll tex opaque] extend=ll op3=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO) tex=texture hash=be2f916a [test ll tex opaque white] extend=ll op3=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO) verts=vtx_ll_white tex=texture hash=92099701 [hl] op0= al_draw_bitmap(bkg, 0, 0, 0) op1= al_build_transform(trans, 320, 240, 0.75, 0.75, theta) op2= op3= al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE) op4= al_use_transform(trans) op5= al_draw_line(-300, -200, 300, 200, #008080ff, thickness) op6= al_draw_triangle(-150, -250, 0, 250, 150, -250, #800080ff, thickness) op7= al_draw_rectangle(-300, -200, 300, 200, #800000ff, thickness) op8= al_draw_rounded_rectangle(-200, -125, 200, 125, 50, 100, #333300ff, thickness) op9= al_draw_ellipse(0, 0, 300, 150, #008080ff, thickness) op10=al_draw_arc(0, 0, 200, -1.5707, 3.1415, #803f00ff, thickness) op11= op12= op13=al_draw_spline(points, #193380ff, thickness) points=-300,-200, 700,200, -700,200, 300,-200 theta=0.5 thickness=1 [hl2] # hl2 is like hl but the spline is not rotated. # We received a report on i386 where the rotated spline is drawn with # a single pixel difference, but still acceptable. extend=hl op11=al_build_transform(trans, 320, 240, 0.75, 0.75, 0) op12=al_use_transform(trans) [test hl thick-0] extend=hl thickness=0 hash=d62736a8 sig=766666666769966A66656659677676767A66866697567669A6556766786676665767A876776666766 [test hl thick-1] extend=hl thickness=1 sig=766666666769966966656659677676767A66866697566669965567667866766657679876776666766 [test hl thick-2] extend=hl thickness=2 hash=639f3cad [test hl thick-10] extend=hl thickness=10 hash=019f07b9 [test hl2 thick-50] extend=hl2 thickness=50 hash=a0129b37 [test hl2 thick-50 clip] extend=test hl2 thick-50 op2=al_set_clipping_rectangle(220, 140, 420, 340) hash=9039ee00 [test hl2 thick-50 nolight] extend=test hl2 thick-50 op3= hash=dc66bfe1 [test hl2 thick-50 nolight clip] extend=test hl2 thick-50 clip op3= hash=2e3bd424 [test hl fill] op0= al_draw_bitmap(bkg, 0, 0, 0) op1= al_build_transform(trans, 320, 240, 0.75, 0.75, theta) op2= op3= al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE) op4= al_use_transform(trans) op5= op6= al_draw_filled_triangle(-100, -100, -150, 200, 100, 200, #80b24c) op7= al_draw_filled_rectangle(20, -50, 200, 50, #4c3399) op8= al_draw_filled_ellipse(-250, 0, 100, 150, #4c4c4c) op9= al_draw_filled_rounded_rectangle(50, -250, 350, -75, 50, 70, #333300) theta=0.5 hash=effa21ee sig=76N6666667PP6667666OP657EF76QPd67EFF7P6c6UDFE66cb6TS6F66cc66766657677576776666766 [test hl fill clip] extend=test hl fill op2=al_set_clipping_rectangle(220, 140, 420, 340) hash=923737a4 [test hl fill nolight] extend=test hl fill op3= hash=400eca07 [test hl fill subbmp dest] op0= subbmp = al_create_sub_bitmap(target, 60, 60, 540, 380) op1= al_set_target_bitmap(subbmp) op2= al_draw_bitmap(bkg, 0, 0, 0) op3= op4= al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE) op5= al_build_transform(trans, 320, 240, 0.75, 0.75, theta) op6= al_use_transform(trans) op7= al_draw_filled_triangle(-100, -100, -150, 200, 100, 200, #80b24c) op8= al_draw_filled_rectangle(20, -50, 200, 50, #4c3399) op9= al_draw_filled_ellipse(-250, 0, 100, 150, #4c4c4c) op10=al_draw_filled_rounded_rectangle(50, -250, 350, -75, 50, 70, #333300) theta=0.5 hash=457ddb11 sig=00000000075666667677QP7757676PP665F97APQY56FE75P7c76EE766bbTSUF776db77777666c7666 [test hl fill subbmp dest clip] extend=test hl fill subbmp dest op3=al_set_clipping_rectangle(220, 140, 300, 200) hash=52d7f9fd [test circle] op0=al_clear_to_color(#884444) op1=al_draw_circle(200, 150, 100, #66aa0080, 10) op2=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_ONE) op3=al_draw_circle(350, 250, 200, #00aaaa80, 50) op4=al_draw_filled_circle(250, 175, 75, #aa660080) hash=484ad11f [test small arc crash] op0=al_build_transform(t, 100, 100, scale, scale, 0.0) scale=0.005 op1=al_use_transform(t) op2=al_draw_ellipse(0, 0, 32, 16, red, 2) op3=al_draw_rounded_rectangle(50.5, 0.5, 100.5, 50.5, 5, 5, green, 3) op4=al_draw_filled_rounded_rectangle(0, 100, 50, 150, 5, 5, blue) op5=al_draw_arc(100, 100, 50, 0, 1.7, yellow, 4) hash=f2391dc5 [test filled notex blend] op0= op1=al_draw_bitmap(bkg, 0, 0, 0) op2=al_build_transform(t, 320, 240, 1, 1, 1.0) op3=al_use_transform(t) op4=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE) op5=al_draw_prim(vtx_notex, 0, 0, 0, 6, ALLEGRO_PRIM_TRIANGLE_FAN) op6=al_draw_prim(vtx_notex, 0, 0, 7, 13, ALLEGRO_PRIM_TRIANGLE_LIST) op7=al_draw_prim(vtx_notex, 0, 0, 14, 20, ALLEGRO_PRIM_TRIANGLE_STRIP) hash=1312b9c9 sig=766666666766P66766656657K776767676667666975I5666LK556766KPJ6766657NJ7576776666766 [test filled notex opaque] extend=test filled notex blend op4=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO) hash=2ac96499 sig=766666666766I66766656657E776767676667666775B5666FE556766EID6766657GC7576776666766 [test filled textured blend] op0= op1=al_draw_bitmap(bkg, 0, 0, 0) op2=al_build_transform(t, 320, 240, 1, 1, 1.0) op3=al_use_transform(t) op4=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE) op5=al_draw_prim(vtx_tex, 0, tex, 0, 6, ALLEGRO_PRIM_TRIANGLE_FAN) op6=al_draw_prim(vtx_tex, 0, tex, 7, 13, ALLEGRO_PRIM_TRIANGLE_LIST) op7=al_draw_prim(vtx_tex, 0, tex, 14, 20, ALLEGRO_PRIM_TRIANGLE_STRIP) tex=texture hash=04d0ae2f sig=766666666766B66766656657977676767666766687585666NP556766RXS6766657fR7576776666766 [test filled textured blend clip] extend=test filled textured blend op0=al_set_clipping_rectangle(150, 80, 340, 280) hash=4b485162 sig=000000000006B66700006657900006767600006687500006NP550000RXS6700000000000000000000 [test filled textured opaque] extend=test filled textured blend op4=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO) hash=67cc8955 sig=766666666766466766656657377676767666766677515666IK556766LTN6766657cK7576776666766 [test filled textured opaque clip] extend=test filled textured opaque op0=al_set_clipping_rectangle(150, 80, 340, 280) hash=42db2b52 sig=000000000006466700006657300006767600006677500006IK550000LTN6700000000000000000000 [test filled subtexture blend] # Note: sub-bitmap textures may not repeat/tile. op0=tex = al_create_sub_bitmap(obp, 70, 60, 322, 303) op1=al_draw_bitmap(bkg, 0, 0, 0) op2=al_build_transform(t, 320, 240, 1, 1, 1.0) op3=al_use_transform(t) op4=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE) op5=al_draw_prim(vtx_tex2, 0, tex, 0, 6, ALLEGRO_PRIM_TRIANGLE_FAN) op6=al_draw_prim(vtx_tex2, 0, tex, 7, 13, ALLEGRO_PRIM_TRIANGLE_LIST) op7=al_draw_prim(vtx_tex2, 0, tex, 14, 20, ALLEGRO_PRIM_TRIANGLE_STRIP) hash=891747fe sig=766666666766J66766656657D776767676667666A75G5666ML556766NNK6766657MM7576776666766 [test filled subtexture opaque] extend=test filled subtexture blend op4=al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO) hash=325bf4a2 sig=766666666766C66766656657777676767666766687595666GF556766GHE6766657GE7576776666766 [test filled textured solid non-white tint] op0= op1=al_draw_bitmap(bkg, 0, 0, 0) op2=al_build_transform(t, 320, 240, 1, 1, 1.0) op3=al_use_transform(t) op4=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op5=al_draw_prim(vtx_tex3, 0, texture, 0, 6, ALLEGRO_PRIM_TRIANGLE_FAN) hash=e16da3fc sig=7666666667666667666566576776767676667666675656669A556766ACA6766657FA7576776666766 [test filled textured subbmp dest] op0=al_clear_to_color(gray) op1=sub = al_create_sub_bitmap(target, 30, 150, 400, 300) op2=al_set_target_bitmap(sub) op3=al_clear_to_color(orange) op4= op5=al_build_transform(Tsub, 300, 10, 5, 4, 1.0) op6=al_use_transform(Tsub) op7=al_draw_prim(vtx_tex, 0, texture, 0, 6, ALLEGRO_PRIM_TRIANGLE_FAN) hash=19fb34dc sig=WWWWWWWWWWWWWWWWWWWWWWWWWWWZZZZgZWWWZZY7bZWWWZgEM5ZWWWgUaHAeWWWP8gUf7WWWCUEgNgWWW [test filled textured subbmp dest clip] extend=test filled textured subbmp dest op4=al_set_clipping_rectangle(50, 50, 300, 200) hash=49c3d736 [test div-by-zero] # This test used to cause a division-by-zero. op0=al_build_transform(t, 320, 240, 1, 1, theta) op1=al_use_transform(t) op2=al_draw_prim(vtx_divbyzero, 0, texture, 0, 4, ALLEGRO_PRIM_TRIANGLE_FAN) theta=4.84207964 hash=a95ea313 sig=0000000000000Ca000000EgW00000bBgSK0000TWPYa0000NMgEX00000gbX000000MM0000000000000 [test pieslice] # 5.1 additions scheduled to be backported to 5.0.6 op0=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op1=al_draw_pieslice(160, 240, 100, 1.0, 6.0, blue, 10) op2=al_draw_pieslice(160, 240, 100, 1.0, 6.0, yellow, 1) op3=al_draw_filled_pieslice(480, 240, 200, 1.0, 1.5, #aa333388) op4=al_draw_filled_pieslice(480, 240, 200, 2.0, 1.5, #33aa3399) op5=al_draw_filled_pieslice(480, 240, 200, 3.0, 1.5, #3333aa88) hash=64ef5e16 sig=00000000000000C6000OO0CCC005002ICC00C00IIII0030O1DDI300NN0DICC000000ICC0000000CC0 [test elliptical arc] # 5.1 addition scheduled to be backported to 5.0.6 op0=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op1=al_draw_elliptical_arc(160, 240, 50, 100, -1.5, 4.5, #ff5555aa, 50) op2=al_draw_elliptical_arc(160, 240, 50, 100, 2.0, 4.5, #55ff55aa, 40) op3=al_draw_elliptical_arc(160, 240, 50, 100, 2.0, 4.5, yellow, 0) op4=al_draw_elliptical_arc(440, 240, 100, 50, -1.5, 4.5, #ff5555aa, 10) op5=al_draw_elliptical_arc(440, 240, 100, 50, 2.0, 4.5, #55ff55aa, 20) op6=al_draw_elliptical_arc(440, 240, 100, 50, 2.0, 4.5, yellow, 1) hash=6a88fcfc [vtx_ll] v0 = 200.000000, 0.000000, 0.000000; 128.000000, 0.000000; #408000 v1 = 177.091202, 92.944641, 0.000000; 113.338371, 59.484570; #800040 v2 = 113.612938, 164.596771, 0.000000; 72.712280, 105.341934; #004080 v3 = 24.107338, 198.541779, 0.000000; 15.428697, 127.066742; #408000 v4 = -70.920990, 187.003250, 0.000000; -45.389435, 119.682083; #800040 v5 =-149.702148, 132.624527, 0.000000; -95.809372, 84.879700; #004080 v6 =-194.188370, 47.863136, 0.000000; -124.280556, 30.632408; #408000 v7 =-194.188354, -47.863167, 0.000000; -124.280548, -30.632427; #800040 v8 =-149.702133, -132.624557, 0.000000; -95.809364, -84.879715; #004080 v9 = -70.920914, -187.003265, 0.000000; -45.389385, -119.682091; #408000 v10= 24.107349, -198.541779, 0.000000; 15.428703, -127.066742; #800040 v11= 113.612984, -164.596741, 0.000000; 72.712311, -105.341911; #004080 v12= 177.091202, -92.944641, 0.000000; 113.338371, -59.484570; #408000 [vtx_ll_white] v0 = 200.000000, 0.000000, 0.000000; 128.000000, 0.000000; #ffffff v1 = 177.091202, 92.944641, 0.000000; 113.338371, 59.484570; #ffffff v2 = 113.612938, 164.596771, 0.000000; 72.712280, 105.341934; #ffffff v3 = 24.107338, 198.541779, 0.000000; 15.428697, 127.066742; #ffffff v4 = -70.920990, 187.003250, 0.000000; -45.389435, 119.682083; #ffffff v5 =-149.702148, 132.624527, 0.000000; -95.809372, 84.879700; #ffffff v6 =-194.188370, 47.863136, 0.000000; -124.280556, 30.632408; #ffffff v7 =-194.188354, -47.863167, 0.000000; -124.280548, -30.632427; #ffffff v8 =-149.702133, -132.624557, 0.000000; -95.809364, -84.879715; #ffffff v9 = -70.920914, -187.003265, 0.000000; -45.389385, -119.682091; #ffffff v10= 24.107349, -198.541779, 0.000000; 15.428703, -127.066742; #ffffff v11= 113.612984, -164.596741, 0.000000; 72.712311, -105.341911; #ffffff v12= 177.091202, -92.944641, 0.000000; 113.338371, -59.484570; #ffffff [vtx_notex] v0 = 0.000000, 0.000000, 0.000000; 0.000000, 0.000000; #408000 v1 = 190.211304, 61.803402, 0.000000; 0.000000, 0.000000; #804040 v2 = 121.352547, 88.167786, 0.000000; 0.000000, 0.000000; #000080 v3 = 117.557053, 161.803406, 0.000000; 0.000000, 0.000000; #408000 v4 = 46.352547, 142.658478, 0.000000; 0.000000, 0.000000; #804040 v5 = -0.000009, 200.000000, 0.000000; 0.000000, 0.000000; #000080 v6 = -46.352554, 142.658478, 0.000000; 0.000000, 0.000000; #408000 v7 = -117.557037, 161.803406, 0.000000; 0.000000, 0.000000; #804040 v8 = -121.352547, 88.167778, 0.000000; 0.000000, 0.000000; #000080 v9 = -190.211304, 61.803406, 0.000000; 0.000000, 0.000000; #408000 v10= -150.000000, -0.000013, 0.000000; 0.000000, 0.000000; #804040 v11= -190.211304, -61.803394, 0.000000; 0.000000, 0.000000; #000080 v12= -121.352539, -88.167801, 0.000000; 0.000000, 0.000000; #408000 v13= -117.557083, -161.803360, 0.000000; 0.000000, 0.000000; #804040 v14= -46.352562, -142.658478, 0.000000; 0.000000, 0.000000; #000080 v15= 0.000002, -200.000000, 0.000000; 0.000000, 0.000000; #408000 v16= 46.352570, -142.658478, 0.000000; 0.000000, 0.000000; #804040 v17= 117.557098, -161.803360, 0.000000; 0.000000, 0.000000; #000080 v18= 121.352539, -88.167793, 0.000000; 0.000000, 0.000000; #408000 v19= 190.211304, -61.803391, 0.000000; 0.000000, 0.000000; #804040 v20= 150.000000, 0.000026, 0.000000; 0.000000, 0.000000; #000080 [vtx_tex] v0 = 0.000000, 0.000000, 0.000000; 0.000000, 0.000000; #ffffff v1 = 190.211304, 61.803402, 0.000000; 121.735237, 39.554176; #ffffff v2 = 121.352547, 88.167786, 0.000000; 77.665627, 56.427383; #ffffff v3 = 117.557053, 161.803406, 0.000000; 75.236511, 103.554176; #ffffff v4 = 46.352547, 142.658478, 0.000000; 29.665630, 91.301422; #ffffff v5 = -0.000009, 200.000000, 0.000000; -0.000006, 128.000000; #ffffff v6 = -46.352554, 142.658478, 0.000000; -29.665634, 91.301422; #ffffff v7 = -117.557037, 161.803406, 0.000000; -75.236504, 103.554176; #ffffff v8 = -121.352547, 88.167778, 0.000000; -77.665627, 56.427380; #ffffff v9 = -190.211304, 61.803406, 0.000000; -121.735237, 39.554180; #ffffff v10= -150.000000, -0.000013, 0.000000; -96.000000, -0.000008; #804040 v11= -190.211304, -61.803394, 0.000000; -121.735237, -39.554173; #000080 v12= -121.352539, -88.167801, 0.000000; -77.665627, -56.427391; #408000 v13= -117.557083, -161.803360, 0.000000; -75.236534, -103.554153; #804040 v14= -46.352562, -142.658478, 0.000000; -29.665640, -91.301422; #000080 v15= 0.000002, -200.000000, 0.000000; 0.000002, -128.000000; #408000 v16= 46.352570, -142.658478, 0.000000; 29.665644, -91.301422; #804040 v17= 117.557098, -161.803360, 0.000000; 75.236542, -103.554153; #000080 v18= 121.352539, -88.167793, 0.000000; 77.665627, -56.427387; #408000 v19= 190.211304, -61.803391, 0.000000; 121.735237, -39.554169; #804040 v20= 150.000000, 0.000026, 0.000000; 96.000000, 0.000017; #000080 [vtx_tex2] v0 = 0.000000, 0.000000, 0.000000; 161.000000, 151.500000; #ffffff v1 = 190.211304, 61.803402, 0.000000; 314.120087, 198.316071; #ffffff v2 = 121.352547, 88.167786, 0.000000; 258.688812, 218.287094; #ffffff v3 = 117.557053, 161.803406, 0.000000; 255.633423, 274.066071; #ffffff v4 = 46.352547, 142.658478, 0.000000; 198.313797, 259.563782; #ffffff v5 = -0.000009, 200.000000, 0.000000; 161.000000, 303.000000; #ffffff v6 = -46.352554, 142.658478, 0.000000; 123.686195, 259.563782; #ffffff v7 = -117.557037, 161.803406, 0.000000; 66.366585, 274.066071; #ffffff v8 = -121.352547, 88.167778, 0.000000; 63.311199, 218.287094; #ffffff v9 = -190.211304, 61.803406, 0.000000; 7.879900, 198.316086; #ffffff v10= -150.000000, -0.000013, 0.000000; 40.250000, 151.499985; #804040 v11= -190.211304, -61.803394, 0.000000; 7.879900, 104.683929; #000080 v12= -121.352539, -88.167801, 0.000000; 63.311207, 84.712891; #408000 v13= -117.557083, -161.803360, 0.000000; 66.366547, 28.933954; #804040 v14= -46.352562, -142.658478, 0.000000; 123.686188, 43.436203; #000080 v15= 0.000002, -200.000000, 0.000000; 161.000000, 0.000000; #408000 v16= 46.352570, -142.658478, 0.000000; 198.313812, 43.436203; #804040 v17= 117.557098, -161.803360, 0.000000; 255.633469, 28.933954; #000080 v18= 121.352539, -88.167793, 0.000000; 258.688782, 84.712898; #408000 v19= 190.211304, -61.803391, 0.000000; 314.120087, 104.683929; #804040 v20= 150.000000, 0.000026, 0.000000; 281.750000, 151.500015; #000080 [vtx_tex3] # All vertices have same non-white colour. v0 = 0.000000, 0.000000, 0.000000; 0.000000, 0.000000; #ff883366 v1 = 190.211304, 61.803402, 0.000000; 121.735237, 39.554176; #ff883366 v2 = 121.352547, 88.167786, 0.000000; 77.665627, 56.427383; #ff883366 v3 = 117.557053, 161.803406, 0.000000; 75.236511, 103.554176; #ff883366 v4 = 46.352547, 142.658478, 0.000000; 29.665630, 91.301422; #ff883366 v5 = -0.000009, 200.000000, 0.000000; -0.000006, 128.000000; #ff883366 v6 = -46.352554, 142.658478, 0.000000; -29.665634, 91.301422; #ff883366 [vtx_divbyzero] v0= 200.000000, 0.000000, 0.000000; 128.00, 0.0; #ffffff v1= 0.000000, 200.000000, 0.000000; 0.0, 128.0; #ffffff v2= -200.000000, 0.000000, 0.000000; -128.0, 0.0; #ffffff v3= 0.000000, -200.000000, 0.000000; 0.0, -128.0; #ffffff allegro5-5.2.10.1/tests/test_prim2.ini000066400000000000000000000110731473414355200174150ustar00rootroot00000000000000# Test primitives which are only in the 5.1 branch. [test projection] # Projection doesn't work on memory bitmaps hw_only = true op0=al_orthographic_transform(trans, -1, -1, -1, 1, 1, 1) op1=al_use_projection_transform(trans) op2=al_draw_filled_circle(0, 0, 1, #aa6600) hash=cb2630a9 sig=0DMMMMMC0CMMMMMMM9MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM9MMMMMMM60AMMMMM80 [test projection flipped] # Projection doesn't work on memory bitmaps hw_only = true op0=al_orthographic_transform(trans, -1, 1, -1, 1, -1, 1) op1=al_use_projection_transform(trans) op2=al_draw_filled_circle(0, 0, 1, #aa6600) hash=cb2630a9 sig=0DMMMMMC0CMMMMMMM9MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM9MMMMMMM60AMMMMM80 [triangle base] op0=al_clear_to_color(white) op1=al_draw_polyline(verts, join, cap, color, thickness, miter_limit) verts=vtx_triangle join=ALLEGRO_LINE_JOIN_NONE cap=ALLEGRO_LINE_CAP_NONE color=#8080aa thickness=1.0 miter_limit=1.0 [squiggle base] extend=triangle base verts=vtx_squiggle thickness=25 [test polyline collinear 50] extend=triangle base verts=vtx_collinear thickness=50 hash=553ab2e5 [test polyline triangle 50] extend=triangle base thickness=50 hash=019534c0 [test polyline squiggle 0] extend=squiggle base thickness=0 hash=1b5e258d [test polyline squiggle 1] extend=squiggle base thickness=1 hash=08066329 [test polyline join bevel] extend=squiggle base join=ALLEGRO_LINE_JOIN_BEVEL hash=1452f13d [test polyline join round] extend=squiggle base join=ALLEGRO_LINE_JOIN_ROUND hash=e3be6520 [test polyline join miter1] extend=squiggle base join=ALLEGRO_LINE_JOIN_MITER miter_limit=1.0 hash=0cc7a65d [test polyline join miter2] extend=squiggle base join=ALLEGRO_LINE_JOIN_MITER miter_limit=2.0 hash=973b5a4d [test polyline cap square] extend=squiggle base cap=ALLEGRO_LINE_CAP_SQUARE hash=8df5cafc [test polyline cap round] extend=squiggle base cap=ALLEGRO_LINE_CAP_ROUND hash=a308506c [test polyline cap triangle] extend=squiggle base cap=ALLEGRO_LINE_CAP_TRIANGLE hash=680ab634 [test polyline cap closed] extend=squiggle base cap=ALLEGRO_LINE_CAP_CLOSED hash=6f62fb5c # The backbuffer may not have an alpha channel so we draw to an # intermediate bitmap. [test polygon] op0=b = al_create_bitmap(640, 480) op1=al_set_target_bitmap(b) op2=al_clear_to_color(white) op3=al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA) op4=al_draw_polygon(vtx_concave, join, #4444aa80, 25, 1) op5=al_set_target_bitmap(target) op6=al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ZERO, ALLEGRO_ONE) op7=al_clear_to_color(brown) op8=al_draw_bitmap(b, 0, 0, 0) join=ALLEGRO_LINE_JOIN_ROUND hash=2c6d9cdc [test filled polygon] extend=test polygon op4=al_draw_filled_polygon(vtx_concave, #4444aa80) hash=de3f4621 [test filled polygon with holes] extend=test polygon op4=al_draw_filled_polygon_with_holes(decep.vtx, decep.counts, #4444aa80) hash=23b1a895 [vtx_collinear] v0 = 100, 100 v1 = 300, 100 v2 = 200, 100 [vtx_triangle] v0 = 96.00, 195.00 v1 = 251.00, 297.00 v2 = 150.00, 206.00 [vtx_squiggle] v0 = 41.00, 219.00 v1 = 193.00, 316.00 v2 = 137.00, 178.00 v3 = 287.00, 172.00 v4 = 242.00, 270.00 v5 = 387.00, 273.00 v6 = 382.00, 174.00 v7 = 313.00, 77.00 v8 = 468.00, 63.00 v9 = 496.00, 130.00 v10 = 416.00, 151.00 v11 = 501.00, 249.00 [vtx_concave] v0 = 80.00, 296.00 v1 = 330.00, 297.00 v2 = 268.00, 251.00 v3 = 331.00, 242.00 v4 = 292.00, 192.00 v5 = 290.00, 231.00 v6 = 235.00, 223.00 v7 = 250.00, 172.00 v8 = 272.00, 215.00 v9 = 278.00, 165.00 v10 = 367.00, 180.00 v11 = 361.00, 115.00 v12 = 300.00, 71.00 v13 = 333.00, 130.00 v14 = 292.00, 122.00 v15 = 262.00, 76.00 v16 = 245.00, 118.00 v17 = 247.00, 140.00 v18 = 202.00, 146.00 v19 = 185.00, 102.00 v20 = 128.00, 93.00 v21 = 122.00, 138.00 v22 = 179.00, 161.00 v23 = 100.00, 170.00 v24 = 88.00, 236.00 v25 = 127.00, 186.00 v26 = 195.00, 242.00 v27 = 163.00, 271.00 v28 = 165.00, 191.00 [decep.vtx] v0 = 314.00, 438.00 v1 = 459.00, 207.00 v2 = 485.00, 44.00 v3 = 431.00, 111.00 v4 = 373.00, 130.00 v5 = 368.00, 167.00 v6 = 427.00, 153.00 v7 = 426.00, 159.00 v8 = 366.00, 177.00 v9 = 360.00, 204.00 v10= 420.00, 188.00 v11= 419.00, 196.00 v12= 350.00, 217.00 v13= 314.00, 257.00 v14= 280.00, 218.00 v15= 206.00, 197.00 v16= 205.00, 188.00 v17= 270.00, 208.00 v18= 263.00, 177.00 v19= 205.00, 161.00 v20= 201.00, 151.00 v21= 263.00, 171.00 v22= 251.00, 131.00 v23= 196.00, 110.00 v24= 140.00, 41.00 v25= 168.00, 211.00 v26= 225.00, 234.00 v27= 266.00, 245.00 v28= 280.00, 275.00 v29= 242.00, 255.00 v30= 364.00, 245.00 v31= 402.00, 234.00 v32= 388.00, 255.00 v33= 349.00, 275.00 [decep.counts] p0=26 p1=4 p2=4 allegro5-5.2.10.1/tools/000077500000000000000000000000001473414355200146205ustar00rootroot00000000000000allegro5-5.2.10.1/tools/macosx/000077500000000000000000000000001473414355200161125ustar00rootroot00000000000000allegro5-5.2.10.1/tools/macosx/fixbundle.c000066400000000000000000000511631473414355200202440ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * MacOS X application bundle fixer utility. Creates an application * bundle out of an executable and some optional icon image files. * * By Angelo Mottola. * * See readme.txt for copyright information. */ #define ALLEGRO_USE_CONSOLE #include #include #include #include #include #include #undef TRUE #undef FALSE #ifndef SCAN_DEPEND #include #endif #undef TRUE #undef FALSE #define TRUE -1 #define FALSE 0 /* 16x16 */ #define ICON_SMALL 0 /* 32x32 */ #define ICON_LARGE 1 /* 48x48 */ #define ICON_HUGE 2 /* 128x128 */ #define ICON_THUMBNAIL 3 #define F_SMALL_DEFINED 0x1 #define F_LARGE_DEFINED 0x2 #define F_HUGE_DEFINED 0x4 #define F_THUMBNAIL_DEFINED 0x8 #define F_ICONS_DEFINED 0xf #define F_MOVE 0x10 #define F_GOT_VERSION 0x20 #define F_GOT_LONG_VERSION 0x40 #define F_EMBED_FRAMEWORK 0x80 #define MAX_STRING_SIZE 1024 #define ONE_SIXTH (1.0 / 6.0) typedef struct ICON_DATA { BITMAP *original, *workspace, *scaled; int size; OSType data, mask8, mask1; int defined; } ICON_DATA; static ICON_DATA icon_data[4] = { { NULL, NULL, NULL, 16, kSmall32BitData, kSmall8BitMask, kSmall1BitMask, F_SMALL_DEFINED }, { NULL, NULL, NULL, 32, kLarge32BitData, kLarge8BitMask, kLarge1BitMask, F_LARGE_DEFINED }, { NULL, NULL, NULL, 48, kHuge32BitData, kHuge8BitMask, kHuge1BitMask, F_HUGE_DEFINED }, { NULL, NULL, NULL, 128, kThumbnail32BitData, kThumbnail8BitMask, 0, F_THUMBNAIL_DEFINED } }; static int flags = 0; static float cubic_bspline(float x) { float a, b, c, d; if (x <= -2.0) a = 0.0; else a = (x + 2.0) * (x + 2.0) * (x + 2.0); if (x <= -1.0) b = 0.0; else b = ((x + 1.0) * (x + 1.0) * (x + 1.0)) * -4.0; if (x <= 0) c = 0.0; else c = (x * x * x) * 6.0; if (x <= 1.0) d = 0.0; else d = ((x - 1.0) * (x - 1.0) * (x - 1.0)) * -4.0; return (a + b + c + d) * ONE_SIXTH; } static int scale_icon(ICON_DATA *icon) { BITMAP *shape; int size, x_ofs = 2, y_ofs = 2; int x, y, m, n; int i_x, i_y; float k, f_x, f_y, a, b, r1, r2; float red, green, blue, alpha; unsigned char *p; unsigned int color; if (icon->original->w > icon->original->h) { size = 4 + icon->original->w; y_ofs = 2 + ((icon->original->w - icon->original->h) / 2); } else { size = 4 + icon->original->h; x_ofs = 2 + ((icon->original->h - icon->original->w) / 2); } k = (float)(size - 4) / (float)icon->size; icon->workspace = create_bitmap_ex(32, size, size); if (!icon->workspace) return -1; icon->scaled = create_bitmap_ex(32, icon->size, icon->size); if (!icon->scaled) return -1; shape = create_bitmap_ex(32, icon->original->w, icon->original->h); if (!shape) return -1; blit(icon->original, shape, 0, 0, 0, 0, icon->original->w, icon->original->h); clear_to_color(icon->workspace, makeacol32(0, 0, 0, 255)); shape->vtable->mask_color = makeacol32(255, 0, 255, 0); masked_blit(shape, icon->workspace, 0, 0, x_ofs, y_ofs, shape->w, shape->h); destroy_bitmap(shape); for (y = 0; y < icon->size; y++) { f_y = (float)y * k; i_y = (int)floor(f_y); a = f_y - floor(f_y); for (x = 0; x < icon->size; x++) { f_x = (float)x * k; i_x = (int)floor(f_x); b = f_x - floor(f_x); red = green = blue = alpha = 0.0; for (m = -1; m < 3; m++) { r1 = cubic_bspline((float)m - a); for (n = -1; n < 3; n++) { r2 = cubic_bspline(b - (float)n); color = ((unsigned int *)(icon->workspace->line[i_y + m + 2]))[i_x + n + 2]; red += ((float)getr32(color) * r1 * r2); green += ((float)getg32(color) * r1 * r2); blue += ((float)getb32(color) * r1 * r2); alpha += ((float)geta32(color) * r1 * r2); } } color = makeacol32((int)floor(red), (int)floor(green), (int)floor(blue), 255 - (int)floor(alpha)); ((unsigned int *)(icon->scaled->line[y]))[x] = color; } } return 0; } static int load_resource(char *datafile, char *name, ICON_DATA *icon) { DATAFILE *data; BITMAP *temp, *bitmap = NULL; RLE_SPRITE *rle_sprite; PALETTE palette; int size, type, i; int result = 0; if (datafile[0] != '\0') { data = load_datafile_object(datafile, name); if (!data) { fprintf(stderr, "Error loading object '%s' from %s\n", name, datafile); return -1; } switch (data->type) { case DAT_BITMAP: temp = (BITMAP *)data->dat; bitmap = create_bitmap_ex(temp->vtable->color_depth, temp->w, temp->h); blit(temp, bitmap, 0, 0, 0, 0, temp->w, temp->h); break; case DAT_RLE_SPRITE: rle_sprite = (RLE_SPRITE *)data->dat; bitmap = create_bitmap_ex(rle_sprite->color_depth, rle_sprite->w, rle_sprite->h); clear_to_color(bitmap, bitmap->vtable->mask_color); draw_rle_sprite(bitmap, rle_sprite, 0, 0); break; case DAT_PALETTE: select_palette((RGB *)data->dat); unload_datafile_object(data); return 0; default: fprintf(stderr, "'%s' is not a BITMAP, RLE_SPRITE or PALETTE object in datafile '%s'\n", name, datafile); unload_datafile_object(data); return -1; } unload_datafile_object(data); } else { bitmap = load_bitmap(name, palette); select_palette(palette); if (!bitmap) { fprintf(stderr, "Unable to load '%s'\n", name); return -1; } } if (!icon) { size = MAX(bitmap->w, bitmap->h); if (size <= 16) type = ICON_SMALL; else if (size <= 32) type = ICON_LARGE; else if (size <= 48) type = ICON_HUGE; else type = ICON_THUMBNAIL; icon = &icon_data[type]; if (flags & icon->defined) { for (i = 0; i < 3; i++) { type = (type + 1) % 4; icon = &icon_data[type]; if (!(flags & icon->defined)) break; } if (flags & icon->defined) { fprintf(stderr, "Too many icon resources!"); result = -1; goto exit_error; } } } else { if (icon->scaled) { fprintf(stderr, "Multiple icon resources of the same size"); result = -1; goto exit_error; } } icon->original = create_bitmap_ex(bitmap->vtable->color_depth, bitmap->w, bitmap->h); blit(bitmap, icon->original, 0, 0, 0, 0, bitmap->w, bitmap->h); result = scale_icon(icon); flags |= icon->defined; exit_error: destroy_bitmap(bitmap); return result; } static void usage(void) { fprintf(stderr, "\nMacOS X application bundle fixer utility for Allegro " ALLEGRO_VERSION_STR "\n" "By Angelo Mottola, " ALLEGRO_DATE_STR "\n\n" "Usage: fixbundle exename [-m] [-o bundlename] [-v version] [-V long_version]\n" "\t\t[-e] [[-d datafile] [[palette] [-{16,32,48,128}] icon] ...]\n" "\twhere icon is either a datafile bitmap or a RLE sprite object, either\n" "\tan image file.\n" "Options:\n" "\t-m\t\tMoves executable inside bundle instead of copying it\n" "\t-o bundlename\tSpecifies a bundle name (default: exename.app)\n" "\t-v version\tSets application version string (default: 1.0)\n" "\t-V long_version\tSets long application version string\n" "\t-e\t\tEmbeds the Allegro framework into the application bundle\n" "\t-d datafile\tUses datafile as source for objects and palettes\n" "\t-{16,32,48,128}\tForces next icon image into the 16x16, 32x32, 48x48 or\n" "\t\t\t128x128 icon resource slot\n" "\n"); exit(EXIT_FAILURE); } static int copy_file(const char *filename, const char *dest_path) { char *buffer = NULL; char dest_file[1024]; PACKFILE *f; size_t size; if (!exists(filename)) return -1; buffer = malloc(size = file_size_ex(filename)); if (!buffer) return -1; append_filename(dest_file, dest_path, get_filename(filename), 1024); f = pack_fopen(filename, F_READ); if (!f) { free(buffer); return -1; } pack_fread(buffer, size, f); pack_fclose(f); f = pack_fopen(dest_file, F_WRITE); if (!f) { free(buffer); return -1; } pack_fwrite(buffer, size, f); pack_fclose(f); free(buffer); return 0; } /* main: * Guess what this function does. */ int main(int argc, char *argv[]) { PACKFILE *f; CFURLRef cf_url_ref; FSRef fs_ref; FSSpec fs_spec; IconFamilyHandle icon_family; Handle raw_data; char datafile[MAX_STRING_SIZE]; char bundle[MAX_STRING_SIZE]; char bundle_dir[MAX_STRING_SIZE]; char bundle_contents_dir[MAX_STRING_SIZE]; char bundle_contents_resources_dir[MAX_STRING_SIZE]; char bundle_contents_macos_dir[MAX_STRING_SIZE]; char bundle_contents_frameworks_dir[MAX_STRING_SIZE]; char *bundle_exe = NULL; char bundle_plist[MAX_STRING_SIZE]; char bundle_pkginfo[MAX_STRING_SIZE]; char bundle_icns[MAX_STRING_SIZE]; char bundle_version[MAX_STRING_SIZE]; char bundle_long_version[MAX_STRING_SIZE]; char *buffer = NULL; int arg, type = 0, result = 0; int i, size, x, y, mask_bit, mask_byte; unsigned char *data; install_allegro(SYSTEM_NONE, &errno, &atexit); set_color_depth(32); set_color_conversion(COLORCONV_TOTAL | COLORCONV_KEEP_TRANS); if (argc < 2) usage(); datafile[0] = '\0'; bundle[0] = '\0'; select_palette(black_palette); /* Parse command line and load any given resource */ for (arg = 2; arg < argc; arg++) { if (!strcmp(argv[arg], "-m")) flags |= F_MOVE; else if (!strcmp(argv[arg], "-e")) flags |= F_EMBED_FRAMEWORK; else if (!strcmp(argv[arg], "-o")) { if ((argc < arg + 2) || (bundle[0] != '\0')) usage(); strcpy(bundle, argv[++arg]); } else if (!strcmp(argv[arg], "-v")) { if (argc < arg + 2) usage(); flags |= F_GOT_VERSION; strcpy(bundle_version, argv[++arg]); } else if (!strcmp(argv[arg], "-V")) { if (argc < arg + 2) usage(); flags |= F_GOT_LONG_VERSION; strcpy(bundle_long_version, argv[++arg]); } else if (!strcmp(argv[arg], "-d")) { if (argc < arg + 2) usage(); strcpy(datafile, argv[++arg]); } else if ((!strcmp(argv[arg], "-16")) || (!strcmp(argv[arg], "-32")) || (!strcmp(argv[arg], "-48")) || (!strcmp(argv[arg], "-128"))) { if (argc < arg + 2) usage(); switch (atoi(&argv[arg][1])) { case 16: type = 0; break; case 32: type = 1; break; case 48: type = 2; break; case 128: type = 3; break; } if (load_resource(datafile, argv[++arg], &icon_data[type])) { result = -1; goto exit_error; } } else { if (load_resource(datafile, argv[arg], NULL)) { result = -1; goto exit_error; } } } buffer = malloc(4096); if (!buffer) { result = -1; goto exit_error_bundle; } bundle_exe = argv[1]; if (!exists(bundle_exe)) { fprintf(stderr, "Cannot locate executable file '%s'\n", bundle_exe); result = -1; goto exit_error; } if (bundle[0] == '\0') strcpy(bundle, bundle_exe); replace_extension(bundle_dir, bundle, "app", MAX_STRING_SIZE); strcpy(bundle_contents_dir, bundle_dir); strcat(bundle_contents_dir, "/Contents"); strcpy(bundle_contents_resources_dir, bundle_contents_dir); strcat(bundle_contents_resources_dir, "/Resources"); strcpy(bundle_contents_macos_dir, bundle_contents_dir); strcat(bundle_contents_macos_dir, "/MacOS"); strcpy(bundle_contents_frameworks_dir, bundle_contents_dir); strcat(bundle_contents_frameworks_dir, "/Frameworks"); bundle_icns[0] = '\0'; bundle_plist[0] = '\0'; bundle_pkginfo[0] = '\0'; /* Create bundle structure */ if ((mkdir(bundle_dir, 0777) && (errno != EEXIST)) || (mkdir(bundle_contents_dir, 0777) && (errno != EEXIST)) || (mkdir(bundle_contents_resources_dir, 0777) && (errno != EEXIST)) || (mkdir(bundle_contents_macos_dir, 0777) && (errno != EEXIST))) { fprintf(stderr, "Cannot create %s\n", bundle_dir); result = -1; goto exit_error_bundle; } /* Copy/move executable into the bundle */ if (copy_file(bundle_exe, bundle_contents_macos_dir)) { fprintf(stderr, "Cannot create %s\n", bundle_contents_macos_dir); result = -1; goto exit_error_bundle; } strcat(bundle_contents_macos_dir, "/"); strcat(bundle_contents_macos_dir, get_filename(bundle_exe)); chmod(bundle_contents_macos_dir, 0755); if (flags & F_MOVE) unlink(bundle_exe); /* Embed Allegro framework if requested */ if (flags & F_EMBED_FRAMEWORK) { if (!file_exists("/Library/Frameworks/Allegro.framework", FA_RDONLY | FA_DIREC, NULL)) { fprintf(stderr, "Cannot find Allegro framework\n"); result = -1; goto exit_error_bundle; } if (!exists("/Library/Frameworks/Allegro.framework/Resources/Embeddable")) { fprintf(stderr, "Cannot embed system wide Allegro framework; install embeddable version first!\n"); result = -1; goto exit_error_bundle; } sprintf(buffer, "/Developer/Tools/pbxcp -exclude .DS_Store -exclude CVS -resolve-src-symlinks /Library/Frameworks/Allegro.framework %s", bundle_contents_frameworks_dir); if ((mkdir(bundle_contents_frameworks_dir, 0777) && (errno != EEXIST)) || (system(buffer))) { fprintf(stderr, "Cannot create %s\n", bundle_contents_frameworks_dir); result = -1; goto exit_error_bundle; } } /* Setup the .icns resource */ if (flags & F_ICONS_DEFINED) { strcat(bundle_contents_resources_dir, "/"); strcat(bundle_contents_resources_dir, get_filename(bundle)); replace_extension(bundle_icns, bundle_contents_resources_dir, "icns", MAX_STRING_SIZE); icon_family = (IconFamilyHandle)NewHandle(0); for (i = 0; i < 4; i++) { if (flags & icon_data[i].defined) { /* Set 32bit RGBA data */ raw_data = NewHandle(icon_data[i].size * icon_data[i].size * 4); data = *(unsigned char **)raw_data; for (y = 0; y < icon_data[i].size; y++) { for (x = 0; x < icon_data[i].size; x++) { *data++ = geta32(((unsigned int *)(icon_data[i].scaled->line[y]))[x]); *data++ = getr32(((unsigned int *)(icon_data[i].scaled->line[y]))[x]); *data++ = getg32(((unsigned int *)(icon_data[i].scaled->line[y]))[x]); *data++ = getb32(((unsigned int *)(icon_data[i].scaled->line[y]))[x]); } } if (SetIconFamilyData(icon_family, icon_data[i].data, raw_data) != noErr) { DisposeHandle(raw_data); fprintf(stderr, "Error setting %dx%d icon resource RGBA data\n", icon_data[i].size, icon_data[i].size); result = -1; goto exit_error_bundle; } DisposeHandle(raw_data); /* Set 8bit mask */ raw_data = NewHandle(icon_data[i].size * icon_data[i].size); data = *(unsigned char **)raw_data; for (y = 0; y < icon_data[i].size; y++) { for (x = 0; x < icon_data[i].size; x++) { *data++ = geta32(((unsigned int *)(icon_data[i].scaled->line[y]))[x]); } } if (SetIconFamilyData(icon_family, icon_data[i].mask8, raw_data) != noErr) { DisposeHandle(raw_data); fprintf(stderr, "Error setting %dx%d icon resource 8bit mask\n", icon_data[i].size, icon_data[i].size); result = -1; goto exit_error_bundle; } DisposeHandle(raw_data); /* Set 1bit mask */ if (icon_data[i].mask1) { size = ((icon_data[i].size * icon_data[i].size) + 7) / 8; raw_data = NewHandle(size * 2); data = *(unsigned char **)raw_data; mask_byte = 0; mask_bit = 7; for (y = 0; y < icon_data[i].size; y++) { for (x = 0; x < icon_data[i].size; x++) { if (geta32(((unsigned int *)(icon_data[i].scaled->line[y]))[x]) >= 0xfd) mask_byte |= (1 << mask_bit); mask_bit--; if (mask_bit < 0) { *data++ = mask_byte; mask_byte = 0; mask_bit = 7; } } } memcpy(*raw_data + size, *raw_data, size); if (SetIconFamilyData(icon_family, icon_data[i].mask1, raw_data) != noErr) { DisposeHandle(raw_data); fprintf(stderr, "Error setting %dx%d icon resource 1bit mask\n", icon_data[i].size, icon_data[i].size); result = -1; goto exit_error_bundle; } DisposeHandle(raw_data); } } } f = pack_fopen(bundle_icns, F_WRITE); if (!f) { fprintf(stderr, "Cannot create %s\n", bundle_icns); result = -1; goto exit_error_bundle; } pack_fclose(f); cf_url_ref = CFURLCreateWithBytes(kCFAllocatorDefault, (unsigned char *)bundle_icns, strlen(bundle_icns), 0, NULL); if (!cf_url_ref) { fprintf(stderr, "Cannot create %s\n", bundle_icns); result = -1; goto exit_error_bundle; } CFURLGetFSRef(cf_url_ref, &fs_ref); CFRelease(cf_url_ref); if ((FSGetCatalogInfo(&fs_ref, kFSCatInfoNone, NULL, NULL, &fs_spec, NULL)) || (WriteIconFile(icon_family, &fs_spec) != noErr)) { fprintf(stderr, "Cannot create %s\n", bundle_icns); result = -1; goto exit_error_bundle; } DisposeHandle((Handle)icon_family); } /* Setup Info.plist */ sprintf(bundle_plist, "%s/Info.plist", bundle_contents_dir); f = pack_fopen(bundle_plist, F_WRITE); if (!f) { fprintf(stderr, "Cannot create %s\n", bundle_plist); result = -1; goto exit_error_bundle; } sprintf(buffer, "\n" "\n" "\n" "\n" "\tCFBundleExecutable\n" "\t%s\n" "\tCFBundleInfoDictionaryVersion\n" "\t6.0\n" "\tCFBundlePackageType\n" "\tAPPL\n" "\tCFBundleSignature\n" "\t%s\n" "\tCFBundleVersion\n" "\t%s\n" "\tCFBundleDocumentTypes\n" "\t\n" "\t\t\n" "\t\t\tCFBundleTypeExtensions\n" "\t\t\t\n" "\t\t\t\t*\n" "\t\t\t\n" "\t\t\tCFBundleTypeName\n" "\t\t\tNSStringPboardType\n" "\t\t\tCFBundleTypeOSTypes\n" "\t\t\t\n" "\t\t\t\t****\n" "\t\t\t\n" "\t\t\tCFBundleTypeRole\n" "\t\t\tViewer\n" "\t\t\n" "\t\n", get_filename(bundle_exe), "????", (flags & F_GOT_VERSION) ? bundle_version : "1.0"); pack_fputs(buffer, f); if (flags & F_GOT_LONG_VERSION) { sprintf(buffer, "\tCFBundleGetInfoString\n" "\t%s\n", bundle_long_version); pack_fputs(buffer, f); } if (flags & F_ICONS_DEFINED) { sprintf(buffer, "\tCFBundleIconFile\n" "\t%s\n", get_filename(bundle_icns)); pack_fputs(buffer, f); } pack_fputs("\n\n", f); pack_fclose(f); /* Setup PkgInfo */ sprintf(bundle_pkginfo, "%s/PkgInfo", bundle_contents_dir); f = pack_fopen(bundle_pkginfo, F_WRITE); if (!f) { fprintf(stderr, "Cannot create %s\n", bundle_pkginfo); result = -1; goto exit_error_bundle; } pack_fputs("APPL????", f); pack_fclose(f); exit_error: if (buffer) free(buffer); for (i = 0; i < 4; i++) { if (icon_data[i].original) destroy_bitmap(icon_data[i].original); if (icon_data[i].workspace) destroy_bitmap(icon_data[i].workspace); if (icon_data[i].scaled) destroy_bitmap(icon_data[i].scaled); } return result; exit_error_bundle: sprintf(buffer, "%s/%s", bundle_contents_macos_dir, get_filename(bundle_exe)); unlink(buffer); unlink(bundle_plist); unlink(bundle_pkginfo); unlink(bundle_icns); rmdir(bundle_dir); rmdir(bundle_contents_dir); rmdir(bundle_contents_resources_dir); rmdir(bundle_contents_macos_dir); goto exit_error; } allegro5-5.2.10.1/tools/win/000077500000000000000000000000001473414355200154155ustar00rootroot00000000000000allegro5-5.2.10.1/tools/win/wfixicon.c000066400000000000000000000217531473414355200174170ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Allegro bitmap -> Windows icon converter. * * By Elias Pschernig. * * See readme.txt for copyright information. */ #define ALLEGRO_USE_CONSOLE #include #include #include #include #define ICON_MAX 16 /* save_ico: * Saves bitmaps as an .ico, using as palette for 8-bit bitmaps. * Other color depths are saved as 24-bit. */ int save_ico(const char *filename, BITMAP *bmp[], int num, PALETTE pal[]) { PACKFILE *f; int depth, bpp, bw, bitsw; int size, offset, n, i; int c, x, y, b, m, v; errno = 0; f = pack_fopen(filename, F_WRITE); if (!f) return errno; offset = 6 + num * 16; /* ICONDIR + ICONDIRENTRYs */ /* ICONDIR */ pack_iputw(0, f); /* reserved */ pack_iputw(1, f); /* resource type: ICON */ pack_iputw(num, f); /* number of icons */ for(n = 0; n < num; n++) { depth = bitmap_color_depth(bmp[n]); bpp = (depth == 8) ? 8 : 24; bw = (((bmp[n]->w * bpp / 8) + 3) / 4) * 4; bitsw = ((((bmp[n]->w + 7) / 8) + 3) / 4) * 4; size = bmp[n]->h * (bw + bitsw) + 40; if (bpp == 8) size += 256 * 4; /* ICONDIRENTRY */ pack_putc(bmp[n]->w, f); /* width */ pack_putc(bmp[n]->h, f); /* height */ pack_putc(0, f); /* color count */ pack_putc(0, f); /* reserved */ pack_iputw(1, f); /* color planes */ pack_iputw(bpp, f); /* bits per pixel */ pack_iputl(size, f); /* size in bytes of image data */ pack_iputl(offset, f); /* file offset to image data */ offset += size; } for(n = 0; n < num; n++) { depth = bitmap_color_depth(bmp[n]); bpp = (depth == 8) ? 8 : 24; bw = (((bmp[n]->w * bpp / 8) + 3) / 4) * 4; bitsw = ((((bmp[n]->w + 7) / 8) + 3) / 4) * 4; size = bmp[n]->h * (bw + bitsw) + 40; if (bpp == 8) size += 256 * 4; /* BITMAPINFOHEADER */ pack_iputl(40, f); /* size */ pack_iputl(bmp[n]->w, f); /* width */ pack_iputl(bmp[n]->h * 2, f); /* height x 2 */ pack_iputw(1, f); /* planes */ pack_iputw(bpp, f); /* bitcount */ pack_iputl(0, f); /* unused for ico */ pack_iputl(size, f); /* size */ pack_iputl(0, f); /* unused for ico */ pack_iputl(0, f); /* unused for ico */ pack_iputl(0, f); /* unused for ico */ pack_iputl(0, f); /* unused for ico */ /* PALETTE */ if (bpp == 8) { pack_iputl(0, f); /* color 0 is black, so the XOR mask works */ for (i = 1; i<256; i++) { if (pal[n]) { pack_putc(_rgb_scale_6[pal[n][i].b], f); pack_putc(_rgb_scale_6[pal[n][i].g], f); pack_putc(_rgb_scale_6[pal[n][i].r], f); pack_putc(0, f); } else { pack_iputl(0, f); } } } /* XOR MASK */ for (y = bmp[n]->h - 1; y >= 0; y--) { for (x = 0; x < bmp[n]->w; x++) { if (bpp == 8) { pack_putc(getpixel(bmp[n], x, y), f); } else { c = getpixel(bmp[n], x, y); pack_putc(getb_depth(depth, c), f); pack_putc(getg_depth(depth, c), f); pack_putc(getr_depth(depth, c), f); } } /* every scanline must be 32-bit aligned */ while (x&3) { pack_putc(0, f); x++; } } /* AND MASK */ for (y = bmp[n]->h - 1; y >= 0; y--) { for (x = 0; x < (bmp[n]->w + 7)/8; x++) { m = 0; v = 128; for (b = 0; b < 8; b++) { c = getpixel(bmp[n], x * 8 + b, y); if (c == bitmap_mask_color(bmp[n])) m += v; v /= 2; } pack_putc(m, f); } /* every scanline must be 32-bit aligned */ while (x&3) { pack_putc(0, f); x++; } } } pack_fclose(f); return errno; } void usage(void) { printf("\nWindows icon converter for Allegro " ALLEGRO_VERSION_STR "\n"); printf("By Elias Pschernig, " ALLEGRO_DATE_STR "\n\n"); printf("Usage: wfixicon icon [-r[o]] bitmap [bitmap...]\n"); printf(" or\n"); printf(" wfixicon icon [-r[o]] -d datafile object [palette] [object...]\n"); printf(" where each 'object' is a bitmap or a RLE sprite.\n"); printf("Options:\n"); printf(" -r output .rc file for the icon\n"); printf(" -ro call the resource compiler on the .rc file\n"); exit(1); } int main(int argc, char *argv[]) { char dat_name[128], rc_name[128], res_name[128], str[256]; int icon_num = 0, pal_start = 0; int create_rc = FALSE, call_windres = FALSE; int i, j, arg; BITMAP *bmp[ICON_MAX]; PALETTE pal[ICON_MAX]; RLE_SPRITE *sprite; DATAFILE *dat; PACKFILE *f; if (install_allegro(SYSTEM_NONE, &errno, atexit) != 0) exit(EXIT_FAILURE); set_color_conversion(COLORCONV_NONE); if (argc < 3) usage(); dat_name[0] = '\0'; for (arg = 2; arg < argc; arg++) { if (argv[arg][0] == '-') { switch(argv[arg][1]) { case 'd': /* datafile argument */ if (argc < arg+2) usage(); strcpy(dat_name, argv[++arg]); pal_start = icon_num; break; case 'r': create_rc = TRUE; if (argv[arg][2] == 'o') { call_windres = TRUE; } break; default: usage(); } } /* end of '-' handling */ else { if (dat_name[0]) { dat = load_datafile_object(dat_name, argv[arg]); if (!dat) { printf("Error reading %s from %s.\n", argv[arg], dat_name); exit(EXIT_FAILURE); } switch (dat->type) { case DAT_BITMAP: bmp[icon_num] = (BITMAP *)dat->dat; icon_num++; break; case DAT_RLE_SPRITE: sprite = (RLE_SPRITE *)dat->dat; bmp[icon_num] = create_bitmap_ex(sprite->color_depth, sprite->w, sprite->h); clear_to_color(bmp[icon_num], bitmap_mask_color(bmp[icon_num])); draw_rle_sprite(bmp[icon_num], sprite, 0, 0); icon_num++; break; case DAT_PALETTE: if (pal_start == icon_num) usage(); for (j = pal_start; j < icon_num; j++) for (i = 0; i < PAL_SIZE; i++) pal[j][i] = ((RGB *)dat->dat)[i]; pal_start = icon_num; break; default: usage(); } } else { bmp[icon_num] = load_bitmap(argv[arg], pal[icon_num]); if (!bmp[icon_num]) { printf("Error reading %s.\n", argv[arg]); exit(EXIT_FAILURE); } icon_num++; } if (icon_num == ICON_MAX) break; } /* end of normal argument handling */ } if (icon_num == 0) usage(); /* do the hard work */ if (save_ico(argv[1], bmp, icon_num, pal) != 0) { printf("Error writing %s.\n", argv[1]); exit(EXIT_FAILURE); } /* output a .rc file along with the ico, to be processed by the resource compiler */ if (create_rc) { replace_extension(rc_name, argv[1], "rc", sizeof(rc_name)); f = pack_fopen(rc_name, F_WRITE); sprintf(str, "allegro_icon ICON %s\n", argv[1]); pack_fwrite(str, strlen(str), f); pack_fclose(f); if (call_windres) { replace_extension(res_name, argv[1], "res", sizeof(res_name)); #if defined ALLEGRO_MINGW32 sprintf(str, "windres -O coff -o %s -i %s", res_name, rc_name); #elif defined ALLEGRO_MSVC sprintf(str, "rc -fo %s %s", res_name, rc_name); #elif defined ALLEGRO_BCC32 sprintf(str, "brc32 -r -fo %s %s", res_name, rc_name); #endif system(str); delete_file(argv[1]); delete_file(rc_name); } } return 0; } allegro5-5.2.10.1/tools/win/wfixicon.txt000066400000000000000000000051001473414355200200000ustar00rootroot00000000000000 ____ _ _ _ _ ___ __ _ |_ | \/ | | | | |\ | | | _/\_ | |__ |_| | \| by Elias Pschernig The wfixicon utility converts Allegro images to Windows icons, that is it lets you convert one or several images in any format supported by Allegro into icons suitable to be included in your Windows executable. It has two main execution modes: you can either directly pass it image files from your hard drive or bitmaps and RLE sprites from an Allegro datafile. The only difference between the two modes is for 8-bit images: in the former case, wfixicon will automatically extract the palette from the image file, whereas in the latter case you will have to explicitly provide a palette object from the datafile. The general syntax for the first mode is as follows: 'wfixicon icon [options] bitmap [bitmap...]' where 'icon' is the icon file to be generated (usually with the standard .ico extension) and each 'bitmap' is a source bitmaps to be processed. The general syntax for the second mode is as follows: 'wfixicon icon [options] -d datafile object [palette] [object...]' where 'icon' is the icon file to be generated (see above), 'datafile' is the source from which all objects are taken, and each 'object' is a bitmap or RLE sprite (DAT_BITMAP or DAT_RLE) within the datafile, specified by name. If you have used any 8-bit images, you must also specify a palette. For each palette object you include on the command line, any images between it and the last palette will be given that palette. For example: 'wfixicon i.ico -d d.dat icon icon2 pal1 tool tool2 pal2' will give the icons called 'icon' and 'icon2' the palette 'pal1', and the icons 'tool' and 'tool2' will be given 'pal2'. The wfixicon utility accepts the following options: '-r' Outputs a resource source file (.rc) suited to the icon, in addition to the icon itself. When compiled and linked to an Allegro Windows executable, this file attachs the icon to the executable and makes it the default icon, displayed in the window caption and the task list. '-ro' Same as '-r' but additionally call the resource compiler on the .rc file, making it produce an object file ready to be linked to an Allegro Windows executable, with the same effects as described above. An example of use is provided in the Allegro distribution: the demo program gets a nice little icon (or an ugly one, it's up to you...) extracted from its datafile (with the Borland C++ compiler you need to type 'make fixdemo' from the main directory once you have properly installed the library). allegro5-5.2.10.1/tools/x11/000077500000000000000000000000001473414355200152315ustar00rootroot00000000000000allegro5-5.2.10.1/tools/x11/xf2pcx.c000066400000000000000000000217371473414355200166210ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Utility to convert X11 fonts to a PCX file, ready for use in the * grabber. * * By Michael Bukin, 1998. * * Minor changes in 2002 by Peter Wang. * * Minor changes in 2003 by Elias Pschernig. * * See readme.txt for copyright information. */ #include #include #include #include #ifndef SCAN_DEPEND #include #include #endif /* usage: * Show usage information. */ static void usage(char *argv0) { printf("Usage: %s [OPTIONS]\n\n", argv0); printf(" -f FONTNAME Font name pattern ('*' by default).\n" " -o FILENAME Output file name ('font.pcx' by default).\n" " -r NUM-NUM Character range, default = 0x20-0xff.\n" " -c COLOR Character color (default 000000000 -- black).\n" " -b COLOR Background color (default 255255255 -- white).\n" " -g COLOR Grid color (default 255000255 -- magenta).\n" " Colors are specified as RRRGGGBBB values,\n" " with each RRR, GGG and BBB in the range [0, 255].\n" " -h This help.\n" "\n" "Find the font you want to convert using xlsfonts or xfontsel.\n\n" "Example 1:\n" "bash> xlsfonts -fn '*' | less\n" "bash> %s -f '-adobe-courier-medium-r-normal--34-*'\n" "bash> grabber\n\n" "In grabber, create a new font 'Object|New|Font'. Use 'Object|Grab'\n" "on this object and choose the pcx file with the font (font.pcx).\n\n" "Example 2:\n" "./xf2pcx -f '-*-clearlyu-*-*-*-*-17-*-*-*-p--iso10646-1' -r 0x2800-0x28ff -o braille.pcx\n\n" "Writes the Braille alphabet into braille.pcx.\n", argv0); } int main(int argc, char *argv[]) { /* default values for -f, -i, -r, -c, -b, -g */ char *fontname = "*"; char *filename = "font.pcx"; int start_char = 32, end_char = 255; int ccolor = 000000000; int bcolor = 255255255; int gcolor = 255000255; /* X11 variables */ Display *display; int screen_number; int default_depth; Window window; Font font; GC gc, gc2; Pixmap pixmap; XImage *image; XCharStruct overall; /* misc variables */ int bitmap_width, bitmap_height; int max_ascent, max_descent; int max_width, max_height; int i, opt, x, y, cx, cy, sx, sy, lines; unsigned long black, white; BITMAP *bitmap; RGB palette[256]; /* show usage if no options */ if (argc == 1) { usage(argv[0]); exit(EXIT_SUCCESS); } /* only to access bitmap operations */ install_allegro(SYSTEM_NONE, &errno, atexit); /* parse options */ opterr = 0; while ((opt = getopt(argc, argv, "f:o:z:c:b:g:r:h")) != EOF) { switch (opt) { case 'f': fontname = optarg; break; case 'o': filename = optarg; break; case 'c': ccolor = atol(optarg); break; case 'b': bcolor = atol(optarg); break; case 'g': gcolor = atol(optarg); break; case 'r': { char *str; start_char = strtol(optarg, &str, 0); end_char = strtol(str + 1, NULL, 0); break; } case 'h': usage(argv[0]); exit(EXIT_SUCCESS); default: fprintf(stderr, "%s: unrecognized option -- '%c'\n", argv[0], optopt); fprintf(stderr, "%s: try '%s -h' for more information\n", argv[0], argv[0]); exit(EXIT_FAILURE); } } /* open display */ display = XOpenDisplay(0); if (display == 0) { fprintf(stderr, "%s: XOpenDisplay failed\n", argv[0]); exit(EXIT_FAILURE); } /* default screen number and window */ screen_number = XDefaultScreen(display); default_depth = XDefaultDepth(display, screen_number); window = XDefaultRootWindow(display); /* load font */ font = XLoadFont(display, fontname); /* create gcs */ { unsigned long val_mask; XGCValues val_bits; val_mask = GCForeground | GCBackground | GCFont | GCFunction; val_bits.function = GXcopy; val_bits.foreground = white = WhitePixel(display, screen_number); val_bits.background = black = BlackPixel(display, screen_number); val_bits.font = font; gc = XCreateGC(display, window, val_mask, &val_bits); val_mask = GCForeground; val_bits.foreground = black; gc2 = XCreateGC(display, window, val_mask, &val_bits); } /* query font ascent and descent */ { XFontStruct *xfs; int min, max; xfs = XQueryFont(display, font); max_ascent = xfs->ascent; max_descent = xfs->descent; if (xfs->min_byte1 == 0 && xfs->max_byte1 == 0) { min = xfs->min_char_or_byte2; max = xfs->max_char_or_byte2; } else { min = (xfs->min_byte1 << 8) + xfs->min_char_or_byte2; max = (xfs->max_byte1 << 8) + xfs->max_char_or_byte2; } if (start_char < min || end_char > max) fprintf(stderr, "You specified characters %04x-%04x, but this font " "only has the range %04x-%04x\n", start_char, end_char, min, max); XFreeFontInfo(NULL, xfs, 0); } /* calculate bitmap width and maximum ascent and descent of characters * (can exceed the font ascent/descent queried above!) */ max_width = 0; lines = 1 + (end_char - start_char) / 16; for (cy = 0; cy < lines; cy++) { for (cx = 0; cx < 16 && start_char + cy * 16 + cx <= end_char; cx++) { int dir, ascent, descent; int width; XChar2b string[2] = { {0, 0}, {0, 0} }; /* query character size */ string[0].byte1 = (start_char + cy * 16 + cx) >> 8; string[0].byte2 = (start_char + cy * 16 + cx) & 255; XQueryTextExtents16(display, font, string, 1, &dir, &ascent, &descent, &overall); width = overall.width; if (width < 1) width = 1; if (width > max_width) max_width = width; if (max_ascent < overall.ascent) max_ascent = overall.ascent; if (max_descent < overall.descent) max_descent = overall.descent; } } max_height = max_ascent + max_descent; bitmap_width = (max_width + 1) * 16 + 1; bitmap_height = (max_height + 1) * lines + 1; /* create bitmap */ bitmap = create_bitmap(bitmap_width, bitmap_height); if (bitmap == 0) { fprintf(stderr, "%s: can not create bitmap\n", argv[0]); exit(EXIT_FAILURE); } /* fill with filler color */ clear_to_color(bitmap, 255); /* process all characters */ sy = 1; for (cy = 0; cy < lines; cy++) { sx = 1; for (cx = 0; cx < 16 && start_char + cy * 16 + cx <= end_char; cx++) { int dir, ascent, descent; XChar2b string[2] = { {0, 0}, {0, 0} }; /* query character size */ string[0].byte1 = (start_char + cy * 16 + cx) >> 8; string[0].byte2 = (start_char + cy * 16 + cx) & 255; XQueryTextExtents16(display, font, string, 1, &dir, &ascent, &descent, &overall); if (overall.width < 1) overall.width = 1; /* create pixmap and draw character there */ pixmap = XCreatePixmap(display, window, overall.width, max_height, default_depth); /* some fonts draw outside their ascent/descent, so we need to clear * the pixmap before drawing the glyph */ XFillRectangle(display, pixmap, gc2, 0, 0, overall.width, max_height); XDrawImageString16(display, pixmap, gc, 0, max_ascent, string, 1); /* create image with pixmap contents */ image = XGetImage(display, pixmap, 0, 0, overall.width, max_height, AllPlanes, ZPixmap); if (image == 0) { fprintf(stderr, "%s: can not get image\n", argv[0]); exit(EXIT_FAILURE); } /* copy image to bitmap */ for (y = 0; y < max_height; y++) for (x = 0; x < overall.width; x++) { if (XGetPixel(image, x, y) == white) putpixel(bitmap, sx + x, sy + y, 1); else putpixel(bitmap, sx + x, sy + y, 0); } XDestroyImage(image); XFreePixmap(display, pixmap); sx += max_width + 1; } sy += max_height + 1; } /* initialize palette */ for (i = 0; i < 256; i++) palette[i].r = palette[i].g = palette[i].b = 0; #define CLAMP(v) (((v / 4) > 63) ? 63 : (v / 4)) palette[0].r = CLAMP(bcolor / 1000000); palette[0].g = CLAMP((bcolor % 1000000) / 1000); palette[0].b = CLAMP(bcolor % 1000); palette[1].r = CLAMP(ccolor / 1000000); palette[1].g = CLAMP((ccolor % 1000000) / 1000); palette[1].b = CLAMP(ccolor % 1000); palette[255].r = CLAMP(gcolor / 1000000); palette[255].g = CLAMP((gcolor % 1000000) / 1000); palette[255].b = CLAMP(gcolor % 1000); #undef CLAMP save_pcx(filename, bitmap, palette); /* clean up */ destroy_bitmap(bitmap); XFreeGC(display, gc); XFreeGC(display, gc2); XUnloadFont(display, font); XCloseDisplay(display); exit(EXIT_SUCCESS); } allegro5-5.2.10.1/tools/x11/xfixicon.sh000066400000000000000000000023721473414355200174200ustar00rootroot00000000000000#! /bin/sh # Generate X11 icon # Usage: xfixicon iconfile if test -z "$1"; then echo "Usage:" echo " xfixicon iconfile [-o outputfile]" echo "this will generate a C file that can be linked with your application" echo "to set the X11 icon automatically." echo "" echo "Options:" echo " -o Set the name of the output file. Default name is allegro_icon.c" exit fi outfile="allegro_icon.c" while !(test -z "$1"); do if (test "$1" = "-o"); then outfile=$2 shift else file=$1 fi shift done if !(test -e "$file"); then echo "File not found: $file" exit 1 fi if !(convert -transparent "magenta" "$file" "/tmp/allegico_xpm.xpm"); then echo "Conversion failed" exit 1 fi echo "#include " > $outfile cat /tmp/allegico_xpm.xpm | sed -e 's,static char,static const char,' >> $outfile echo "#if defined ALLEGRO_WITH_XWINDOWS && defined ALLEGRO_USE_CONSTRUCTOR" >> $outfile echo "extern void *allegro_icon;" >> $outfile echo "CONSTRUCTOR_FUNCTION(static void _set_allegro_icon(void));" >> $outfile echo "static void _set_allegro_icon(void)" >> $outfile echo "{" >> $outfile echo " allegro_icon = allegico_xpm;" >> $outfile echo "}" >> $outfile echo "#endif" >> $outfile rm /tmp/allegico_xpm.xpm allegro5-5.2.10.1/tools/x11/xkeymap.c000066400000000000000000000203101473414355200170470ustar00rootroot00000000000000/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Utility to create mapping from X keycodes to Allegro scancodes. * * By Michael Bukin, modified by Elias Pschernig. * * See readme.txt for copyright information. */ #include #include #include #include #define FILENAME_LENGTH 1024 char unicode_description[256] = ""; static DIALOG main_dialog[]; static DIALOG keymap_dialog[]; static int black = 0; static int white = 1; static int red = 2; static int yellow = 3; static volatile int waiting_for_key = 0; static volatile int new_keycode = 0; static int keycode_to_scancode[256]; static void get_raw_keycode(int pressed, int keycode) { if (pressed && waiting_for_key) { new_keycode = keycode; waiting_for_key = 0; } } static const char *keycode_getter(int index, int *list_size) { if (index >= 0) { return scancode_to_name(index + 1); } else { *list_size = KEY_MAX - 1; return NULL; } } static DIALOG keymap_dialog[] = { /* 0 */{d_clear_proc, 0, 0, 250, 230, 0, 0, 0, 0, 0, 0, 0, NULL, NULL}, /* 1 */{d_ctext_proc, 125, 10, 0, 16, 0, 255, 0, 0, 0, 0, "Select Keycode:", NULL, NULL}, /* 2 */{d_list_proc, 0, 32, 230, 92, 0, 255, 0, D_EXIT, 0, 0, (void *)keycode_getter, NULL, NULL}, /* 3 */{d_ctext_proc, 125, 142, 0, 16, 0, 255, 0, 0, 0, 0, unicode_description, NULL, NULL}, /* 4 */{d_button_proc, 10, 164, 230, 16, 0, 255, 0, D_EXIT, 0, 0, "Define &X Key !", NULL, NULL}, /* 5 */{d_button_proc, 10, 186, 110, 16, 0, 255, 27, D_EXIT, 0, 0, "&Cancel", NULL, NULL}, /* 6 */{d_button_proc, 130, 186, 110, 16 , 0, 255, 0, D_EXIT, 0, 0, "&Done", NULL, NULL}, /* 7 */{d_ctext_proc, 125, 208, 0, 16, 0, 255, 0, 0, 0, 0, "", NULL, NULL}, {d_yield_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL}, {NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL} }; /* handle the setup command */ static void setup_all_keys(void) { int focus = 2; int i; /* Prepare dialog. */ set_dialog_color(keymap_dialog, black, white); centre_dialog(keymap_dialog); /* Parse input. */ while (1) { focus = do_dialog(keymap_dialog, focus); switch (focus) { case 2: case 4: textprintf_centre_ex (screen, font, keymap_dialog[7].x, keymap_dialog[7].y, red, -1, "Press a key to map to the current scancode"); textprintf_centre_ex (screen, font, keymap_dialog[7].x, keymap_dialog[7].y + 8, red, -1, "(or a mouse button to leave it unchanged)"); /* Wait for new key press. */ new_keycode = -1; waiting_for_key = 1; do { poll_keyboard(); poll_mouse(); if (mouse_b) waiting_for_key = 0; } while (waiting_for_key); /* Save keycode to scancode mapping. */ if ((new_keycode >= 0) && (new_keycode < 256)) { keycode_to_scancode[new_keycode] = keymap_dialog[2].d1 + 1; } clear_keybuf(); break; case 5: return; case 6: for (i = 0; i < 256; i++) { if (keycode_to_scancode[i] >= 0) _xwin.keycode_to_scancode[i] = keycode_to_scancode[i]; } return; } } } static void test_key_map(void) { int i, k, u; static int key_was_pressed[KEY_MAX + 1] = {0}; static int key_is_pressed[KEY_MAX + 1] = {0}; static char *welcome[] = { "Key that is pressed now is marked with red", "Key that was pressed is marked with yellow", "Press mouse button or Escape to exit test", 0 }; /* Clear screen and output prompt. */ clear_to_color(screen, white); for (i = 0; welcome[i] != 0; i++) textout_ex(screen, font, welcome[i], 8, i * 8 + 8, black, -1); clear_to_color(screen, white); for (i = 0; i < KEY_MAX; i++) textprintf_ex(screen, font, 32 + (i % 4) * 160, 32 + (i / 4) * 14, black, -1, "%s", scancode_to_name (i)); do { poll_keyboard(); poll_mouse(); } while ((key[KEY_ESC]) || (mouse_b)); do { while (keypressed()) { u = ureadkey (&k); textprintf_centre_ex (screen, font, SCREEN_W / 2, 8, red, white, "> %c <", u); } poll_keyboard(); poll_mouse(); for (i = 0; i < KEY_MAX; i++) { if (key[i]) key_was_pressed[i] = key_is_pressed[i] = 1; else key_is_pressed[i] = 0; } for (i = 0; i < KEY_MAX; i++) { int x = 16 + (i % 4) * 160; int y = 32 + (i / 4) * 14; if (key_is_pressed[i]) rectfill(screen, x, y, x + 7, y + 7, red); else if (key_was_pressed[i]) rectfill(screen, x, y, x + 7, y + 7, yellow); else rectfill(screen, x, y, x + 7, y + 7, white); } rest(1); } while ((!key[KEY_ESC]) && (!mouse_b)); do { poll_keyboard(); poll_mouse(); } while ((key[KEY_ESC]) || (mouse_b)); clear_keybuf(); } /* handle the save command */ static void save_key_map(void) { int i; char *section, *option_format, option[80], tmp1[80], tmp2[80]; set_config_file("xkeymap.cfg"); section = uconvert_ascii("xkeymap", tmp1); option_format = uconvert_ascii("keycode%d", tmp2); for (i = 0; i < 256; i++) { if (keycode_to_scancode[i] > 0) { uszprintf(option, sizeof(option), option_format, i); set_config_int(section, option, keycode_to_scancode[i]); } } } /* reads a specific keymapping table from the config file */ void load_table(unsigned short *table, char *section) { char name[80]; int i; for (i=0; i