diff --git a/Makefile.am b/Makefile.am index c1021cfe..b970a331 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,7 +22,7 @@ MAINTAINERCLEANFILES = \ $(srcdir)/ChangeLog \ `find "$(srcdir)" -type f -name Makefile.in -print` -SUBDIRS = src demo +SUBDIRS = src demo-gl2 demo-gl3 pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = glyphy.pc diff --git a/configure.ac b/configure.ac index e90b7a3d..a80ad9db 100644 --- a/configure.ac +++ b/configure.ac @@ -96,8 +96,10 @@ AC_CONFIG_FILES([ glyphy.pc Makefile src/Makefile -demo/Makefile -demo/android/Makefile +demo-gl2/Makefile +demo-gl2/android/Makefile +demo-gl3/Makefile +demo-gl3/android/Makefile ]) AC_OUTPUT diff --git a/demo/Makefile.am b/demo-gl2/Makefile.am similarity index 100% rename from demo/Makefile.am rename to demo-gl2/Makefile.am diff --git a/demo/android/AndroidManifest.xml b/demo-gl2/android/AndroidManifest.xml similarity index 100% rename from demo/android/AndroidManifest.xml rename to demo-gl2/android/AndroidManifest.xml diff --git a/demo/android/Makefile.am b/demo-gl2/android/Makefile.am similarity index 100% rename from demo/android/Makefile.am rename to demo-gl2/android/Makefile.am diff --git a/demo/android/README b/demo-gl2/android/README similarity index 100% rename from demo/android/README rename to demo-gl2/android/README diff --git a/demo/android/build.xml b/demo-gl2/android/build.xml similarity index 100% rename from demo/android/build.xml rename to demo-gl2/android/build.xml diff --git a/demo/android/jni/Android.mk b/demo-gl2/android/jni/Android.mk similarity index 100% rename from demo/android/jni/Android.mk rename to demo-gl2/android/jni/Android.mk diff --git a/demo/android/jni/Application.mk b/demo-gl2/android/jni/Application.mk similarity index 100% rename from demo/android/jni/Application.mk rename to demo-gl2/android/jni/Application.mk diff --git a/demo/android/project.properties b/demo-gl2/android/project.properties similarity index 100% rename from demo/android/project.properties rename to demo-gl2/android/project.properties diff --git a/demo/android/res/values/strings.xml b/demo-gl2/android/res/values/strings.xml similarity index 100% rename from demo/android/res/values/strings.xml rename to demo-gl2/android/res/values/strings.xml diff --git a/demo/default-font.ttf b/demo-gl2/default-font.ttf similarity index 100% rename from demo/default-font.ttf rename to demo-gl2/default-font.ttf diff --git a/demo/default-text.txt b/demo-gl2/default-text.txt similarity index 100% rename from demo/default-text.txt rename to demo-gl2/default-text.txt diff --git a/demo/demo-atlas.cc b/demo-gl2/demo-atlas.cc similarity index 100% rename from demo/demo-atlas.cc rename to demo-gl2/demo-atlas.cc diff --git a/demo/demo-atlas.glsl b/demo-gl2/demo-atlas.glsl similarity index 100% rename from demo/demo-atlas.glsl rename to demo-gl2/demo-atlas.glsl diff --git a/demo/demo-atlas.h b/demo-gl2/demo-atlas.h similarity index 100% rename from demo/demo-atlas.h rename to demo-gl2/demo-atlas.h diff --git a/demo/demo-buffer.cc b/demo-gl2/demo-buffer.cc similarity index 100% rename from demo/demo-buffer.cc rename to demo-gl2/demo-buffer.cc diff --git a/demo/demo-buffer.h b/demo-gl2/demo-buffer.h similarity index 100% rename from demo/demo-buffer.h rename to demo-gl2/demo-buffer.h diff --git a/demo/demo-common.h b/demo-gl2/demo-common.h similarity index 99% rename from demo/demo-common.h rename to demo-gl2/demo-common.h index 9ff2dbc3..f25ec036 100644 --- a/demo/demo-common.h +++ b/demo-gl2/demo-common.h @@ -30,6 +30,8 @@ #include #include +#define GL_SILENCE_DEPRECATION 1 + /* Tailor config for various platforms. */ #ifdef EMSCRIPTEN diff --git a/demo/demo-font.cc b/demo-gl2/demo-font.cc similarity index 100% rename from demo/demo-font.cc rename to demo-gl2/demo-font.cc diff --git a/demo/demo-font.h b/demo-gl2/demo-font.h similarity index 100% rename from demo/demo-font.h rename to demo-gl2/demo-font.h diff --git a/demo/demo-fshader.glsl b/demo-gl2/demo-fshader.glsl similarity index 100% rename from demo/demo-fshader.glsl rename to demo-gl2/demo-fshader.glsl diff --git a/demo/demo-glstate.cc b/demo-gl2/demo-glstate.cc similarity index 100% rename from demo/demo-glstate.cc rename to demo-gl2/demo-glstate.cc diff --git a/demo/demo-glstate.h b/demo-gl2/demo-glstate.h similarity index 100% rename from demo/demo-glstate.h rename to demo-gl2/demo-glstate.h diff --git a/demo/demo-shader.cc b/demo-gl2/demo-shader.cc similarity index 100% rename from demo/demo-shader.cc rename to demo-gl2/demo-shader.cc diff --git a/demo/demo-shader.h b/demo-gl2/demo-shader.h similarity index 100% rename from demo/demo-shader.h rename to demo-gl2/demo-shader.h diff --git a/demo/demo-view.cc b/demo-gl2/demo-view.cc similarity index 100% rename from demo/demo-view.cc rename to demo-gl2/demo-view.cc diff --git a/demo/demo-view.h b/demo-gl2/demo-view.h similarity index 100% rename from demo/demo-view.h rename to demo-gl2/demo-view.h diff --git a/demo/demo-vshader.glsl b/demo-gl2/demo-vshader.glsl similarity index 100% rename from demo/demo-vshader.glsl rename to demo-gl2/demo-vshader.glsl diff --git a/demo/glyphy-demo.cc b/demo-gl2/glyphy-demo.cc similarity index 98% rename from demo/glyphy-demo.cc rename to demo-gl2/glyphy-demo.cc index b4668a6e..71f59fa6 100644 --- a/demo/glyphy-demo.cc +++ b/demo-gl2/glyphy-demo.cc @@ -228,6 +228,7 @@ main (int argc, char** argv) glutInitWindowSize (WINDOW_W, WINDOW_H); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); int window = glutCreateWindow ("GLyphy Demo"); + printf("\nInitialized with Open GL version %s\n\n", glGetString(GL_VERSION)); glutReshapeFunc (reshape_func); glutDisplayFunc (display_func); glutKeyboardFunc (keyboard_func); diff --git a/demo/glyphy-validate.cc b/demo-gl2/glyphy-validate.cc similarity index 100% rename from demo/glyphy-validate.cc rename to demo-gl2/glyphy-validate.cc diff --git a/demo/matrix4x4.c b/demo-gl2/matrix4x4.c similarity index 100% rename from demo/matrix4x4.c rename to demo-gl2/matrix4x4.c diff --git a/demo/matrix4x4.h b/demo-gl2/matrix4x4.h similarity index 100% rename from demo/matrix4x4.h rename to demo-gl2/matrix4x4.h diff --git a/demo/trackball.c b/demo-gl2/trackball.c similarity index 100% rename from demo/trackball.c rename to demo-gl2/trackball.c diff --git a/demo/trackball.h b/demo-gl2/trackball.h similarity index 100% rename from demo/trackball.h rename to demo-gl2/trackball.h diff --git a/demo-gl3/Makefile.am b/demo-gl3/Makefile.am new file mode 100644 index 00000000..229123d2 --- /dev/null +++ b/demo-gl3/Makefile.am @@ -0,0 +1,105 @@ +NULL = +SUBDIRS = +EXTRA_DIST = +CLEANFILES = +DISTCLEANFILES = +MAINTAINERCLEANFILES = +BUILT_SOURCES = +noinst_PROGRAMS = + +BUILT_SOURCES += default-text.h default-font.h +EXTRA_DIST += default-text.txt default-font.ttf +default-text.h: default-text.txt $(top_srcdir)/src/stringize + $(AM_V_GEN) $(top_srcdir)/src/stringize "static const char default_text[]" $< > $@ +default-font.h: default-font.ttf + $(AM_V_GEN) { \ + echo "static const unsigned char default_font[] = {"; \ + hexdump -v -e '"x" 1/1 "%02X" " "' < $< | fmt | sed 's/ *x/\\x/g;s/^/"/;s/$$/"/'; \ + echo '};'; \ + } > $@ + +if HAVE_FREETYPE2 +if HAVE_GL +if HAVE_GLUT + +if ANDROID +SUBDIRS += android +else +noinst_PROGRAMS += glyphy-demo +glyphy_demo_CPPFLAGS = \ + -I $(top_srcdir)/src \ + $(FREETYPE2_CFLAGS) \ + $(GL_CFLAGS) \ + $(GLEW_CFLAGS) \ + $(GLUT_CFLAGS) \ + $(NULL) +glyphy_demo_LDADD = \ + $(top_builddir)/src/libglyphy.la \ + -lm \ + $(FREETYPE2_LIBS) \ + $(GL_LIBS) \ + $(GLEW_LIBS) \ + $(GLUT_LIBS) \ + $(NULL) +glyphy_demo_SOURCES = \ + default-font.h \ + default-text.h \ + demo-atlas.h \ + demo-atlas.cc \ + demo-buffer.h \ + demo-buffer.cc \ + demo-common.h \ + demo-font.h \ + demo-font.cc \ + demo-glstate.h \ + demo-glstate.cc \ + demo-shader.h \ + demo-shader.cc \ + demo-view.h \ + demo-view.cc \ + glyphy-demo.cc \ + matrix4x4.h \ + matrix4x4.c \ + trackball.h \ + trackball.c \ + $(SHADERHEADERS) \ + $(NULL) +endif +SHADERS = \ + demo-atlas.glsl \ + demo-fshader.glsl \ + demo-vshader.glsl \ + $(NULL) +SHADERHEADERS = $(patsubst %.glsl,%-glsl.h, $(SHADERS)) +BUILT_SOURCES += $(SHADERHEADERS) +EXTRA_DIST += $(SHADERS) + +%-glsl.h: %.glsl $(top_srcdir)/src/stringize + $(AM_V_GEN) $(top_srcdir)/src/stringize "static const char *`echo "$<" | \ + sed 's@.*/@@;s/[-.]/_/g'`" < "$<" > "$@.tmp" && \ + mv "$@.tmp" "$@" || ($(RM) "$@.tmp"; false) + +endif +endif +endif + + +if HAVE_FREETYPE2 + +noinst_PROGRAMS += glyphy-validate +glyphy_validate_CPPFLAGS = \ + -I $(top_srcdir)/src \ + $(FREETYPE2_CFLAGS) \ + $(NULL) +glyphy_validate_LDADD = \ + $(top_builddir)/src/libglyphy.la \ + $(FREETYPE2_LIBS) \ + $(NULL) +glyphy_validate_SOURCES = \ + glyphy-validate.cc \ + $(NULL) + +endif + + +-include $(top_srcdir)/git.mk diff --git a/demo-gl3/android/AndroidManifest.xml b/demo-gl3/android/AndroidManifest.xml new file mode 100644 index 00000000..62934bbe --- /dev/null +++ b/demo-gl3/android/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo-gl3/android/Makefile.am b/demo-gl3/android/Makefile.am new file mode 100644 index 00000000..f584851f --- /dev/null +++ b/demo-gl3/android/Makefile.am @@ -0,0 +1,15 @@ +if ANDROID + +all: + NDK_PROJECT_PATH=$(srcdir) ndk-build NDK_DEBUG=1 + ant -buildfile $(srcdir)/build.xml debug + +clean-local: + NDK_PROJECT_PATH=$(srcdir) ndk-build clean + ant -buildfile $(srcdir)/build.xml clean + +endif + +GITIGNOREFILES = bin libs obj + +-include $(top_srcdir)/git.mk diff --git a/demo-gl3/android/README b/demo-gl3/android/README new file mode 100644 index 00000000..a8b1fbc9 --- /dev/null +++ b/demo-gl3/android/README @@ -0,0 +1,57 @@ +To build GLyphy Demo app on Android, follow these steps: + +- Download and install Android SDK and NDK, for Android API version 18 or later. + +- Install a "standalone" toolchain with the NDK, and set PLATFORM_PREFIX env + var to point to it. You can do this by running, eg: + + ndk/build/tools/make-standalone-toolchain.sh \ + --platform=android-18 \ + --install-dir=/prefix + + Adjust platform and install-dir. + +- Make sure the cross-compile tools from PLATFORM_PREFIX are in the path. + Ie. that you can run arm-linux-androideabi-gcc. + +- Configure and install FreeType. Within the FreeType tarball run: + + ./configure --host=arm-linux-androideabi --prefix=$PLATFORM_PREFIX --without-png + make install + +- Configure and install freeglut-gles2. We want the pre-3.0 version of freeglut + which has native Android support. Get from SVN and run: + + cmake -D CMAKE_TOOLCHAIN_FILE=android_toolchain.cmake \ + -D CMAKE_INSTALL_PREFIX=$PLATFORM_PREFIX \ + -D CMAKE_BUILD_TYPE=Debug \ + -D FREEGLUT_GLES2=ON \ + -D FREEGLUT_BUILD_DEMOS=NO \ + .. + make install + +- Configure GLyphy: + + ./configure \ + --host=arm-linux-androideabi \ + --prefix=$PLATFORM_PREFIX \ + --enable-static \ + PKG_CONFIG_LIBDIR=$PLATFORM_PREFIX/lib/pkgconfig + +- Make and install the GLyphy library (but not the demos): + + make -C src install + +- Add a local.properties file to demo/android, with: + + sdk.dir=/path/to/sdk + + By default GLyphy Demo app builds against android-18 target. If you want + to override that, you can add a target=android-XX line to the above file. + +- Finally, make the demo app: + + make -C demo + +- If all goes well, you should now have demo/android/bin/GLyphyDemo-debug.apk + diff --git a/demo-gl3/android/build.xml b/demo-gl3/android/build.xml new file mode 100644 index 00000000..b5142b7d --- /dev/null +++ b/demo-gl3/android/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo-gl3/android/jni/Android.mk b/demo-gl3/android/jni/Android.mk new file mode 100644 index 00000000..7f5ab98e --- /dev/null +++ b/demo-gl3/android/jni/Android.mk @@ -0,0 +1,50 @@ +# Copyright (C) 2010 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := freetype +LOCAL_SRC_FILES := $(PLATFORM_PREFIX)/lib/libfreetype.a +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := glyphy +LOCAL_SRC_FILES := $(PLATFORM_PREFIX)/lib/libglyphy.a +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := glut +LOCAL_SRC_FILES := $(PLATFORM_PREFIX)/lib/libfreeglut-gles2.a +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := glyphy-demo +LOCAL_CPP_EXTENSION := .cc +LOCAL_SRC_FILES := \ + ../../matrix4x4.c \ + ../../trackball.c \ + ../../demo-atlas.cc \ + ../../demo-buffer.cc \ + ../../demo-font.cc \ + ../../demo-glstate.cc \ + ../../demo-shader.cc \ + ../../demo-view.cc \ + ../../glyphy-demo.cc \ + $(NULL) +LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv2 -lz +LOCAL_WHOLE_STATIC_LIBRARIES := gnustl_static freetype glyphy glut +include $(BUILD_SHARED_LIBRARY) + +$(call import-module,android/native_app_glue) diff --git a/demo-gl3/android/jni/Application.mk b/demo-gl3/android/jni/Application.mk new file mode 100644 index 00000000..af5560ec --- /dev/null +++ b/demo-gl3/android/jni/Application.mk @@ -0,0 +1,11 @@ +PLATFORM_PREFIX := /home/behdad/.local/arm-linux-androideabi + +APP_STL := gnustl_static + +APP_CPPFLAGS := \ + -I$(PLATFORM_PREFIX)/include/ \ + -I$(PLATFORM_PREFIX)/include/freetype2 \ + -I$(PLATFORM_PREFIX)/include/glyphy \ + -DDEFAULT_FONT='"/system/fonts/Roboto-Regular.ttf"' \ + -DFREEGLUT_GLES2 \ + $(NULL) diff --git a/demo-gl3/android/project.properties b/demo-gl3/android/project.properties new file mode 100644 index 00000000..ce39f2d0 --- /dev/null +++ b/demo-gl3/android/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-18 diff --git a/demo-gl3/android/res/values/strings.xml b/demo-gl3/android/res/values/strings.xml new file mode 100644 index 00000000..c5c76902 --- /dev/null +++ b/demo-gl3/android/res/values/strings.xml @@ -0,0 +1,4 @@ + + + GLyphy Demo + diff --git a/demo-gl3/default-font.ttf b/demo-gl3/default-font.ttf new file mode 100644 index 00000000..3bdd3956 Binary files /dev/null and b/demo-gl3/default-font.ttf differ diff --git a/demo-gl3/default-text.txt b/demo-gl3/default-text.txt new file mode 100644 index 00000000..fdb77198 --- /dev/null +++ b/demo-gl3/default-text.txt @@ -0,0 +1,69 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam tincidunt nibh quis semper malesuada. Mauris sit amet metus sed tellus gravida +maximus sit amet a enim. Morbi et lorem congue, aliquam lorem vitae, condimentum erat. Mauris aliquet, sapien consequat blandit mattis, velit ante +molestie mi, ac condimentum justo leo sed odio. Curabitur at suscipit quam. Ut ac convallis ante, at sollicitudin sapien. Nulla pellentesque felis +id mi blandit dictum. Phasellus ultrices, odio non volutpat tincidunt, neque quam tristique lacus, nec gravida nulla ante id risus. Nulla sit amet +bibendum lectus, sed bibendum lectus. Vivamus ultrices metus sit amet sapien posuere volutpat. Suspendisse luctus non mauris nec iaculis. Duis +mattis enim libero, ac malesuada tortor gravida tempor. Cras sagittis felis at sollicitudin fermentum. Duis et ipsum bibendum, viverra felis quis, +consectetur lacus. Donec vulputate risus imperdiet, tincidunt purus nec, vestibulum lorem. Morbi iaculis tincidunt rutrum. Duis sit amet nulla +ut lectus efficitur suscipit. Curabitur urna turpis, congue lacinia varius vitae, interdum vel dolor. Vestibulum sit amet suscipit arcu, sit amet +tincidunt ipsum. Maecenas feugiat ante vel fermentum viverra. Sed aliquam sem ac quam bibendum, sit amet fringilla augue pharetra. Morbi scelerisque +tempus purus, interdum tempor est pulvinar bibendum. Duis tincidunt dictum ante vel sodales. Fusce quis cursus metus. Pellentesque mi mauris, +tincidunt ut orci ut, interdum dapibus dolor. Aliquam blandit, nisl et rhoncus laoreet, tellus nulla blandit tellus, sit amet cursus magna enim nec +ante. Integer venenatis a est sed hendrerit. Proin id porttitor turpis, aliquam tempus ex. Morbi tristique, felis ut aliquet luctus, orci tortor +sodales sem, vel imperdiet justo tortor sit amet arcu. Quisque ipsum sem, lacinia in fermentum eu, maximus in lectus. Pellentesque quis scelerisque +neque, eget ultricies ligula. Etiam accumsan orci mi, ut blandit nibh viverra quis. Pellentesque tincidunt auctor dictum. Integer tincidunt neque +at enim ultrices, in accumsan augue elementum. Sed placerat eros leo, ac venenatis metus dignissim vel. Suspendisse mauris sem, pulvinar id purus +non, hendrerit pretium sem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla accumsan massa id nulla +viverra semper. Aliquam sit amet neque vitae diam rhoncus feugiat. Etiam tellus purus, rhoncus id enim a, fermentum volutpat neque. Vestibulum +tortor augue, dapibus at varius sed, varius at nisl. Ut pharetra elementum varius. Nulla molestie, urna sit amet euismod venenatis, nunc magna +bibendum augue, vitae elementum augue elit eget urna. Morbi a leo at sapien tempor varius sit amet venenatis metus. Sed ac pellentesque turpis, +quis malesuada ligula. Cras quis ex mattis, ultricies nibh ac, vestibulum velit. Sed sed sagittis libero, at consectetur massa. Cras quis risus +nunc. Curabitur vitae odio laoreet, sodales sem eu, fermentum risus. Quisque laoreet felis eu mattis laoreet. Phasellus auctor velit ut varius +accumsan. Sed molestie bibendum mi varius auctor. Vestibulum iaculis, lacus ut mattis convallis, turpis purus cursus nibh, nec ullamcorper dolor nibh +eget nunc. Nam lacinia justo ac vestibulum lacinia. Nulla vestibulum eu urna a sodales. Aliquam blandit congue lacus vitae ornare. Nulla bibendum +vehicula tortor eu vestibulum. Mauris nec pretium est. Pellentesque faucibus quam et est sollicitudin, quis condimentum justo placerat. Etiam urna +elit, porttitor sodales dui congue, maximus sodales dolor. Proin lacinia diam quis libero molestie viverra. Pellentesque tortor mauris, sodales +vel luctus non, euismod eu risus. Nulla sed condimentum ex. Morbi ac mi quis felis laoreet mattis. Fusce nec quam orci. Morbi pretium quis risus +a tincidunt. Phasellus accumsan suscipit nisi sed viverra. Vestibulum eu vulputate lorem. Nullam fermentum turpis eget nulla rutrum egestas. Sed +tortor nisi, consectetur a semper ut, lacinia in lectus. Phasellus finibus at diam nec interdum. Nunc mollis congue enim, et tempor neque dapibus +quis. Nunc a egestas quam, vitae tempor mi. Sed at lobortis neque. Pellentesque habitant morbi tristique senectus et netus et malesuada fames +ac turpis egestas. Etiam blandit mi sit amet ipsum accumsan, eget euismod nulla facilisis. Morbi imperdiet ex massa, in porttitor nibh posuere +ut. Curabitur bibendum lorem id ultricies placerat. Aenean tincidunt malesuada mauris, sit amet rhoncus odio ornare ac. Morbi venenatis turpis +non nulla tincidunt, bibendum tincidunt quam ultricies. Donec dictum, lorem eget commodo malesuada, risus nisi ornare augue, feugiat accumsan +dui massa eu ipsum. Mauris aliquam sapien id felis faucibus ornare. Nullam eleifend felis vel metus rutrum mollis. Quisque posuere eros vitae +imperdiet dapibus. Suspendisse quis est laoreet, faucibus lectus at, mattis est. Vestibulum nec neque ut ante auctor luctus. Nunc posuere vulputate +egestas. Quisque sit amet sodales erat, ac suscipit lorem. Ut auctor dapibus efficitur. Phasellus tincidunt cursus neque in ultrices. Sed pretium +viverra felis vitae aliquet. Vivamus at quam libero. Phasellus mattis orci ut egestas finibus. Suspendisse mattis maximus consequat. Ut id aliquam +lectus. Maecenas ut libero in nulla tempus accumsan at at tellus. Quisque a nibh quis ligula pharetra vehicula id et ante. Pellentesque et nisl in +lectus commodo sollicitudin non quis lectus. Vestibulum varius leo at diam fringilla, nec vulputate diam pellentesque. Curabitur id nisl in nibh +sollicitudin vestibulum non sit amet odio. Nunc pulvinar lectus ac est sagittis mollis. Nunc vel consectetur nulla, sit amet eleifend elit. Etiam +volutpat, ligula id cursus posuere, est lacus sagittis purus, scelerisque tempus sem lectus tempor nisi. Curabitur scelerisque leo et neque +ultricies semper. Sed in efficitur urna. Aliquam tempus cursus tortor. Sed feugiat mi elit, id ullamcorper nulla ullamcorper vitae. Suspendisse +rutrum ornare orci, eget facilisis nisi ornare et. Aenean sed leo vitae lorem congue lobortis. Nunc vel dui condimentum, sagittis sapien ac, +ultricies odio. Suspendisse elementum iaculis commodo. Phasellus pellentesque purus nec nisl pretium eleifend. Suspendisse a imperdiet urna. Fusce +eleifend et nunc at elementum. Morbi imperdiet varius mattis. Cras pharetra urna nulla, gravida sodales orci blandit et. Nulla dignissim eleifend +tempus. Vivamus placerat tristique purus et facilisis. In eget maximus urna. Mauris ut commodo elit. Aliquam erat volutpat. Donec efficitur augue +vitae nisi suscipit, vel aliquet sem posuere. Ut placerat ullamcorper lorem, eget consequat nunc ultricies nec. Nulla scelerisque ex non velit +efficitur imperdiet. Aliquam faucibus augue vel rhoncus feugiat. Aenean hendrerit nunc sem, ac hendrerit tortor fringilla sed. Morbi lorem massa, +dictum at maximus vitae, dictum et mi. Nullam ante elit, ultrices tincidunt tempor quis, aliquam ut lacus. Donec ut aliquet purus. Sed dolor mi, +rhoncus auctor tristique ac, lobortis non urna. Sed tempor leo ut finibus mattis. Aenean fermentum augue eget nisi aliquet feugiat. Donec convallis +laoreet nulla id malesuada. Vestibulum in congue enim, non sagittis massa. Ut et euismod nibh, eu euismod leo. Class aptent taciti sociosqu ad litora +torquent per conubia nostra, per inceptos himenaeos. Cras sodales purus nec ligula egestas cursus. Sed gravida, elit non eleifend semper, ex erat +ultricies augue, nec suscipit velit metus in augue. Nulla dapibus, ante a aliquam cursus, mi purus lobortis purus, sit amet feugiat neque sapien +at mauris. Vivamus mattis sagittis purus, quis viverra dolor mollis nec. Pellentesque habitant morbi tristique senectus et netus et malesuada fames +ac turpis egestas. Fusce in semper justo, eget mattis magna. Donec libero augue, aliquam eget mi at, laoreet sodales metus. Etiam gravida, libero +eu pellentesque imperdiet, nulla dolor scelerisque tortor, vitae placerat est risus non metus. Etiam vel laoreet est. Ut posuere turpis facilisis, +faucibus magna nec, ornare augue. Pellentesque auctor feugiat ornare. Etiam vulputate vitae odio et lacinia. Aenean semper purus vitae erat tincidunt +volutpat. Sed et laoreet nulla, eu condimentum arcu. Maecenas magna arcu, condimentum ut elementum vitae, laoreet sed justo. Maecenas bibendum +lacus vel blandit tincidunt. Praesent mattis, eros eget auctor malesuada, felis ligula egestas eros, at lacinia dolor lacus sed arcu. Praesent +lectus lacus, rhoncus ultricies facilisis vel, tristique pellentesque eros. Donec et justo placerat, finibus lectus id, mattis augue. Nam +consequat, felis a commodo varius, odio erat viverra urna, mollis sodales nibh lectus non turpis. Maecenas quis egestas risus, eget lobortis +dui. Sed pellentesque vitae neque non condimentum. Proin eu maximus magna, ac posuere libero. Maecenas porta interdum metus eu hendrerit. Integer +ut blandit risus. Maecenas facilisis consectetur dolor a mattis. Morbi elementum tincidunt turpis, vel tempus est mattis vel. Morbi et ultrices +velit, at dapibus neque. Vestibulum dictum in mi et rhoncus. In congue, elit vel ultricies maximus, arcu augue venenatis neque, sed imperdiet purus +leo et risus. Quisque tincidunt sapien felis, vitae elementum erat aliquet in. Curabitur mauris nibh, dictum sollicitudin dolor ut, accumsan luctus +nulla. Aenean quis diam quam. Etiam viverra odio at felis tincidunt laoreet. Proin euismod non lectus sit amet lacinia. Proin aliquet mauris et dui +consectetur sagittis. Ut tempus fringilla odio, vitae scelerisque neque efficitur ut. Quisque a nulla pulvinar, varius dolor sed, eleifend magna. +Vivamus eu neque pulvinar, accumsan odio venenatis, mollis leo. Morbi aliquet ac dolor sed lobortis. Maecenas urna sapien, volutpat non sagittis in, +tempor eget enim. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed mollis porta lectus, id lobortis metus elementum vitae. Nullam +non nulla sed risus rhoncus tempor. Nullam id quam hendrerit, dictum purus ut, maximus ipsum. Cras auct diff --git a/demo-gl3/demo-atlas.cc b/demo-gl3/demo-atlas.cc new file mode 100644 index 00000000..d84da068 --- /dev/null +++ b/demo-gl3/demo-atlas.cc @@ -0,0 +1,144 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "demo-atlas.h" + + +struct demo_atlas_t { + unsigned int refcount; + + GLuint tex_unit; + GLuint tex_name; + GLuint tex_w; + GLuint tex_h; + GLuint item_w; + GLuint item_h_q; /* height quantum */ + GLuint cursor_x; + GLuint cursor_y; +}; + + +demo_atlas_t * +demo_atlas_create (unsigned int w, + unsigned int h, + unsigned int item_w, + unsigned int item_h_quantum) +{ + TRACE(); + + demo_atlas_t *at = (demo_atlas_t *) calloc (1, sizeof (demo_atlas_t)); + at->refcount = 1; + + glGetIntegerv (GL_ACTIVE_TEXTURE, (GLint *) &at->tex_unit); + glGenTextures (1, &at->tex_name); + at->tex_w = w; + at->tex_h = h; + at->item_w = item_w; + at->item_h_q = item_h_quantum; + at->cursor_x = 0; + at->cursor_y = 0; + + demo_atlas_bind_texture (at); + + glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + gl(TexImage2D) (GL_TEXTURE_2D, 0, GL_RGBA, at->tex_w, at->tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + return at; +} + +demo_atlas_t * +demo_atlas_reference (demo_atlas_t *at) +{ + if (at) at->refcount++; + return at; +} + +void +demo_atlas_destroy (demo_atlas_t *at) +{ + if (!at || --at->refcount) + return; + + glDeleteTextures (1, &at->tex_name); + free (at); +} + +void +demo_atlas_bind_texture (demo_atlas_t *at) +{ + glActiveTexture (at->tex_unit); + glBindTexture (GL_TEXTURE_2D, at->tex_name); +} + +void +demo_atlas_set_uniforms (demo_atlas_t *at) +{ + GLuint program; + glGetIntegerv (GL_CURRENT_PROGRAM, (GLint *) &program); + + glUniform4i (glGetUniformLocation (program, "u_atlas_info"), + at->tex_w, at->tex_h, at->item_w, at->item_h_q); + glUniform1i (glGetUniformLocation (program, "u_atlas_tex"), at->tex_unit - GL_TEXTURE0); +} + +void +demo_atlas_alloc (demo_atlas_t *at, + glyphy_rgba_t *data, + unsigned int len, + unsigned int *px, + unsigned int *py) +{ + GLuint w, h, x, y; + + w = at->item_w; + h = (len + w - 1) / w; + + if (at->cursor_y + h > at->tex_h) { + /* Go to next column */ + at->cursor_x += at->item_w; + at->cursor_y = 0; + } + + if (at->cursor_x + w <= at->tex_w && + at->cursor_y + h <= at->tex_h) + { + x = at->cursor_x; + y = at->cursor_y; + at->cursor_y += (h + at->item_h_q - 1) & ~(at->item_h_q - 1); + } else + die ("Ran out of atlas memory"); + + demo_atlas_bind_texture (at); + if (w * h == len) + gl(TexSubImage2D) (GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data); + else { + gl(TexSubImage2D) (GL_TEXTURE_2D, 0, x, y, w, h - 1, GL_RGBA, GL_UNSIGNED_BYTE, data); + /* Upload the last row separately */ + gl(TexSubImage2D) (GL_TEXTURE_2D, 0, x, y + h - 1, len - (w * (h - 1)), 1, GL_RGBA, GL_UNSIGNED_BYTE, + data + w * (h - 1)); + } + + *px = x / at->item_w; + *py = y / at->item_h_q; +} diff --git a/demo-gl3/demo-atlas.glsl b/demo-gl3/demo-atlas.glsl new file mode 100644 index 00000000..f08ad180 --- /dev/null +++ b/demo-gl3/demo-atlas.glsl @@ -0,0 +1,16 @@ +uniform sampler2D u_atlas_tex; +uniform ivec4 u_atlas_info; + +#define GLYPHY_TEXTURE1D_EXTRA_DECLS , sampler2D _tex, ivec4 _atlas_info, ivec2 _atlas_pos +#define GLYPHY_TEXTURE1D_EXTRA_ARGS , _tex, _atlas_info, _atlas_pos +#define GLYPHY_DEMO_EXTRA_ARGS , u_atlas_tex, u_atlas_info, gi.atlas_pos + +vec4 +glyphy_texture1D_func (int offset GLYPHY_TEXTURE1D_EXTRA_DECLS) +{ + ivec2 item_geom = _atlas_info.zw; + vec2 pos = (vec2 (_atlas_pos.xy * item_geom + + ivec2 (mod (float (offset), float (item_geom.x)), offset / item_geom.x)) + + + vec2 (.5, .5)) / vec2(_atlas_info.xy); + return texture (_tex, pos); +} diff --git a/demo-gl3/demo-atlas.h b/demo-gl3/demo-atlas.h new file mode 100644 index 00000000..729403f4 --- /dev/null +++ b/demo-gl3/demo-atlas.h @@ -0,0 +1,54 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod, Maysum Panju + */ + +#ifndef DEMO_ATLAS_H +#define DEMO_ATLAS_H + +#include "demo-common.h" + + +typedef struct demo_atlas_t demo_atlas_t; + +demo_atlas_t * +demo_atlas_create (unsigned int w, + unsigned int h, + unsigned int item_w, + unsigned int item_h_quantum); + +demo_atlas_t * +demo_atlas_reference (demo_atlas_t *at); + +void +demo_atlas_destroy (demo_atlas_t *at); + + +void +demo_atlas_alloc (demo_atlas_t *at, + glyphy_rgba_t *data, + unsigned int len, + unsigned int *px, + unsigned int *py); + +void +demo_atlas_bind_texture (demo_atlas_t *at); + +void +demo_atlas_set_uniforms (demo_atlas_t *at); + + +#endif /* DEMO_ATLAS_H */ diff --git a/demo-gl3/demo-buffer.cc b/demo-gl3/demo-buffer.cc new file mode 100644 index 00000000..eaa98b54 --- /dev/null +++ b/demo-gl3/demo-buffer.cc @@ -0,0 +1,183 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "demo-buffer.h" + +struct demo_buffer_t { + unsigned int refcount; + + glyphy_point_t cursor; + std::vector *vertices; + glyphy_extents_t ink_extents; + glyphy_extents_t logical_extents; + bool dirty; + GLuint buf_name; +}; + +demo_buffer_t * +demo_buffer_create (void) +{ + demo_buffer_t *buffer = (demo_buffer_t *) calloc (1, sizeof (demo_buffer_t)); + buffer->refcount = 1; + + buffer->vertices = new std::vector; + glGenBuffers (1, &buffer->buf_name); + + demo_buffer_clear (buffer); + + return buffer; +} + +demo_buffer_t * +demo_buffer_reference (demo_buffer_t *buffer) +{ + if (buffer) buffer->refcount++; + return buffer; +} + +void +demo_buffer_destroy (demo_buffer_t *buffer) +{ + if (!buffer || --buffer->refcount) + return; + + glDeleteBuffers (1, &buffer->buf_name); + delete buffer->vertices; + free (buffer); +} + + +void +demo_buffer_clear (demo_buffer_t *buffer) +{ + buffer->vertices->clear (); + glyphy_extents_clear (&buffer->ink_extents); + glyphy_extents_clear (&buffer->logical_extents); + buffer->dirty = true; +} + +void +demo_buffer_extents (demo_buffer_t *buffer, + glyphy_extents_t *ink_extents, + glyphy_extents_t *logical_extents) +{ + if (ink_extents) + *ink_extents = buffer->ink_extents; + if (logical_extents) + *logical_extents = buffer->logical_extents; +} + +void +demo_buffer_move_to (demo_buffer_t *buffer, + const glyphy_point_t *p) +{ + buffer->cursor = *p; +} + +void +demo_buffer_current_point (demo_buffer_t *buffer, + glyphy_point_t *p) +{ + *p = buffer->cursor; +} + +void +demo_buffer_add_text (demo_buffer_t *buffer, + const char *utf8, + demo_font_t *font, + double font_size) +{ + FT_Face face = demo_font_get_face (font); + glyphy_point_t top_left = buffer->cursor; + buffer->cursor.y += font_size /* * font->ascent */; + unsigned int unicode; + for (const unsigned char *p = (const unsigned char *) utf8; *p; p++) { + if (*p < 128) { + unicode = *p; + } else { + unsigned int j; + if (*p < 0xE0) { + unicode = *p & ~0xE0; + j = 1; + } else if (*p < 0xF0) { + unicode = *p & ~0xF0; + j = 2; + } else { + unicode = *p & ~0xF8; + j = 3; + continue; + } + p++; + for (; j && *p; j--, p++) + unicode = (unicode << 6) | (*p & ~0xC0); + p--; + } + + if (unicode == '\n') { + buffer->cursor.y += font_size; + buffer->cursor.x = top_left.x; + continue; + } + + unsigned int glyph_index = FT_Get_Char_Index (face, unicode); + glyph_info_t gi; + demo_font_lookup_glyph (font, glyph_index, &gi); + + /* Update ink extents */ + glyphy_extents_t ink_extents; + demo_shader_add_glyph_vertices (buffer->cursor, font_size, &gi, buffer->vertices, &ink_extents); + glyphy_extents_extend (&buffer->ink_extents, &ink_extents); + + /* Update logical extents */ + glyphy_point_t corner; + corner.x = buffer->cursor.x; + corner.y = buffer->cursor.y - font_size; + glyphy_extents_add (&buffer->logical_extents, &corner); + corner.x = buffer->cursor.x + font_size * gi.advance; + corner.y = buffer->cursor.y; + glyphy_extents_add (&buffer->logical_extents, &corner); + + buffer->cursor.x += font_size * gi.advance; + } + + buffer->dirty = true; +} + +void +demo_buffer_draw (demo_buffer_t *buffer) +{ + GLint program; + glGetIntegerv (GL_CURRENT_PROGRAM, &program); + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + glBindBuffer (GL_ARRAY_BUFFER, buffer->buf_name); + if (buffer->dirty) { + glBufferData (GL_ARRAY_BUFFER, sizeof (glyph_vertex_t) * buffer->vertices->size (), (const char *) &(*buffer->vertices)[0], GL_STATIC_DRAW); + buffer->dirty = false; + } + glEnableVertexAttribArray (0); + glVertexAttribPointer (0, 4, GL_FLOAT, GL_FALSE, sizeof (glyph_vertex_t), 0); + glDrawArrays (GL_TRIANGLES, 0, buffer->vertices->size ()); + glDisableVertexAttribArray (0); + glDeleteVertexArrays(1, &vao); +} diff --git a/demo-gl3/demo-buffer.h b/demo-gl3/demo-buffer.h new file mode 100644 index 00000000..2948a7ff --- /dev/null +++ b/demo-gl3/demo-buffer.h @@ -0,0 +1,64 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef DEMO_BUFFER_H +#define DEMO_BUFFER_H + +#include "demo-common.h" +#include "demo-font.h" +#include "demo-shader.h" + +typedef struct demo_buffer_t demo_buffer_t; + +demo_buffer_t * +demo_buffer_create (void); + +demo_buffer_t * +demo_buffer_reference (demo_buffer_t *buffer); + +void +demo_buffer_destroy (demo_buffer_t *buffer); + + +void +demo_buffer_clear (demo_buffer_t *buffer); + +void +demo_buffer_extents (demo_buffer_t *buffer, + glyphy_extents_t *ink_extents, + glyphy_extents_t *logical_extents); + +void +demo_buffer_move_to (demo_buffer_t *buffer, + const glyphy_point_t *p); + +void +demo_buffer_current_point (demo_buffer_t *buffer, + glyphy_point_t *p); + +void +demo_buffer_add_text (demo_buffer_t *buffer, + const char *utf8, + demo_font_t *font, + double font_size); + +void +demo_buffer_draw (demo_buffer_t *buffer); + + +#endif /* DEMO_BUFFER_H */ diff --git a/demo-gl3/demo-common.h b/demo-gl3/demo-common.h new file mode 100644 index 00000000..e0b97959 --- /dev/null +++ b/demo-gl3/demo-common.h @@ -0,0 +1,204 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod, Maysum Panju + */ + +#ifndef DEMO_COMMON_H +#define DEMO_COMMON_H + +#include + +#include +#include +#include +#include +#include + +#include +#include + +/* Tailor config for various platforms. */ + +// first include GL3 header +#if defined(__APPLE__) + #define GL_SILENCE_DEPRECATION + #include + #include +#else + #include +#endif + +// next include GLUT header + +#ifdef HAVE_GLUT + #if defined(__APPLE__) + #define __gl_h_ + #include + #undef __gl_h_ + #else + #include + #endif +#endif + +// include glew if we have it +// otherwise emulate needed functionality +#ifdef HAVE_GLEW +# include +#else +# define GLEW_OK 0 + static inline int glewInit (void) { return GLEW_OK; } + static inline int glewIsSupported (const char *s) + { return 0 == strcmp ("GL_VERSION_2_0", s); } +#endif + + +#if 0 + +#ifdef EMSCRIPTEN +/* https://github.com/kripken/emscripten/issues/340 */ +# undef HAVE_GLEW + /* WebGL shaders are ES2 */ +# define GL_ES_VERSION_2_0 1 +#endif + +#if defined(__ANDROID__) +# define HAVE_GLES2 1 +# define HAVE_GLUT 1 +#endif + +#ifdef _WIN32 +# define HAVE_GL 1 +# define HAVE_GLEW 1 +# define HAVE_GLUT 1 +# define HAVE_FREETYPE2 1 +#endif + +/* Get Glew out of the way. */ +#ifdef HAVE_GLEW +# include +#else +# define GLEW_OK 0 + static inline int glewInit (void) { return GLEW_OK; } + static inline int glewIsSupported (const char *s) + { return 0 == strcmp ("GL_VERSION_2_0", s); } +#endif /* HAVE_GLEW */ + +/* WTF this block?! */ +#if defined(HAVE_GLES2) +# include +#elif defined(HAVE_GL) +# ifndef HAVE_GLEW +# define GL_GLEXT_PROTOTYPES 1 +# if defined(__APPLE__) +# include +# else +# include +# endif +# endif +# if defined(__APPLE__) +# include +# else +# ifdef HAVE_GLEW +# ifdef _WIN32 +# include +# else +# include +# endif +# endif +# endif +#endif /* HAVE_GL */ + +/* Finally, Glut. */ +#ifdef HAVE_GLUT +# if defined(__APPLE__) +# include +# else +# include +# endif +#endif +#endif + + + + +/* Logging. */ +#ifdef __ANDROID__ +# include +# define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "glyphy-demo", __VA_ARGS__)) +# define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "glyphy-demo", __VA_ARGS__)) +# define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "glyphy-demo", __VA_ARGS__)) +#else /* !__ANDROID__ */ +# define LOGI(...) ((void) fprintf (stdout, __VA_ARGS__)) +# define LOGW(...) ((void) fprintf (stderr, __VA_ARGS__)) +# define LOGE(...) ((void) fprintf (stderr, __VA_ARGS__), abort ()) +#endif + + + +#define STRINGIZE1(Src) #Src +#define STRINGIZE(Src) STRINGIZE1(Src) + +#define ARRAY_LEN(Array) (sizeof (Array) / sizeof (*Array)) + + +#define MIN_FONT_SIZE 10 +#define TOLERANCE (1./2048) + + +#define gl(name) \ + for (GLint __ee, __ii = 0; \ + __ii < 1; \ + (__ii++, \ + (__ee = glGetError()) && \ + (fprintf (stderr, "gl" #name " failed with error %04X on line %d\n", __ee, __LINE__), abort (), 0))) \ + gl##name + + +static inline void +die (const char *msg) +{ + fprintf (stderr, "%s\n", msg); + exit (1); +} + +template +T clamp (T v, T m, T M) +{ + return v < m ? m : v > M ? M : v; +} + + +#if defined(_MSC_VER) +#define DEMO_FUNC __FUNCSIG__ +#else +#define DEMO_FUNC __func__ +#endif + +struct auto_trace_t +{ + auto_trace_t (const char *func_) : func (func_) + { printf ("Enter: %s\n", func); } + + ~auto_trace_t (void) + { printf ("Leave: %s\n", func); } + + private: + const char * const func; +}; + +#define TRACE() auto_trace_t trace(DEMO_FUNC) + +#endif /* DEMO_COMMON_H */ diff --git a/demo-gl3/demo-font.cc b/demo-gl3/demo-font.cc new file mode 100644 index 00000000..53e53e55 --- /dev/null +++ b/demo-gl3/demo-font.cc @@ -0,0 +1,255 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "demo-font.h" + +#include + +#include +#include + +typedef std::map glyph_cache_t; + +struct demo_font_t { + unsigned int refcount; + + FT_Face face; + glyph_cache_t *glyph_cache; + demo_atlas_t *atlas; + glyphy_arc_accumulator_t *acc; + + /* stats */ + unsigned int num_glyphs; + double sum_error; + unsigned int sum_endpoints; + double sum_fetch; + unsigned int sum_bytes; +}; + +demo_font_t * +demo_font_create (FT_Face face, + demo_atlas_t *atlas) +{ + demo_font_t *font = (demo_font_t *) calloc (1, sizeof (demo_font_t)); + font->refcount = 1; + + font->face = face; + font->glyph_cache = new glyph_cache_t (); + font->atlas = demo_atlas_reference (atlas); + font->acc = glyphy_arc_accumulator_create (); + + font->num_glyphs = 0; + font->sum_error = 0; + font->sum_endpoints = 0; + font->sum_fetch = 0; + font->sum_bytes = 0; + + return font; +} + +demo_font_t * +demo_font_reference (demo_font_t *font) +{ + if (font) font->refcount++; + return font; +} + +void +demo_font_destroy (demo_font_t *font) +{ + if (!font || --font->refcount) + return; + + glyphy_arc_accumulator_destroy (font->acc); + demo_atlas_destroy (font->atlas); + delete font->glyph_cache; + free (font); +} + + +FT_Face +demo_font_get_face (demo_font_t *font) +{ + return font->face; +} + +demo_atlas_t * +demo_font_get_atlas (demo_font_t *font) +{ + return font->atlas; +} + + +static glyphy_bool_t +accumulate_endpoint (glyphy_arc_endpoint_t *endpoint, + std::vector *endpoints) +{ + endpoints->push_back (*endpoint); + return true; +} + +static void +encode_ft_glyph (demo_font_t *font, + unsigned int glyph_index, + double tolerance_per_em, + glyphy_rgba_t *buffer, + unsigned int buffer_len, + unsigned int *output_len, + unsigned int *nominal_width, + unsigned int *nominal_height, + glyphy_extents_t *extents, + double *advance) +{ +/* Used for testing only */ +#define SCALE (1. * (1 << 0)) + + FT_Face face = font->face; + if (FT_Err_Ok != FT_Load_Glyph (face, + glyph_index, + FT_LOAD_NO_BITMAP | + FT_LOAD_NO_HINTING | + FT_LOAD_NO_AUTOHINT | + FT_LOAD_NO_SCALE | + FT_LOAD_LINEAR_DESIGN | + FT_LOAD_IGNORE_TRANSFORM)) + die ("Failed loading FreeType glyph"); + + if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) + die ("FreeType loaded glyph format is not outline"); + + unsigned int upem = face->units_per_EM; + double tolerance = upem * tolerance_per_em; /* in font design units */ + double faraway = double (upem) / (MIN_FONT_SIZE * M_SQRT2); + std::vector endpoints; + + glyphy_arc_accumulator_reset (font->acc); + glyphy_arc_accumulator_set_tolerance (font->acc, tolerance); + glyphy_arc_accumulator_set_callback (font->acc, + (glyphy_arc_endpoint_accumulator_callback_t) accumulate_endpoint, + &endpoints); + + if (FT_Err_Ok != glyphy_freetype(outline_decompose) (&face->glyph->outline, font->acc)) + die ("Failed converting glyph outline to arcs"); + + assert (glyphy_arc_accumulator_get_error (font->acc) <= tolerance); + + if (endpoints.size ()) + { +#if 0 + /* Technically speaking, we want the following code, + * however, crappy fonts have crappy flags. So we just + * fixup unconditionally... */ + if (face->glyph->outline.flags & FT_OUTLINE_EVEN_ODD_FILL) + glyphy_outline_winding_from_even_odd (&endpoints[0], endpoints.size (), false); + else if (face->glyph->outline.flags & FT_OUTLINE_REVERSE_FILL) + glyphy_outline_reverse (&endpoints[0], endpoints.size ()); +#else + glyphy_outline_winding_from_even_odd (&endpoints[0], endpoints.size (), false); +#endif + } + + if (SCALE != 1.) + for (unsigned int i = 0; i < endpoints.size (); i++) + { + endpoints[i].p.x /= SCALE; + endpoints[i].p.y /= SCALE; + } + + double avg_fetch_achieved; + if (!glyphy_arc_list_encode_blob (endpoints.size () ? &endpoints[0] : NULL, endpoints.size (), + buffer, + buffer_len, + faraway / SCALE, + 4, /* UNUSED */ + &avg_fetch_achieved, + output_len, + nominal_width, + nominal_height, + extents)) + die ("Failed encoding arcs"); + + glyphy_extents_scale (extents, 1. / upem, 1. / upem); + glyphy_extents_scale (extents, SCALE, SCALE); + + *advance = face->glyph->metrics.horiAdvance / (double) upem; + + if (0) + LOGI ("gid%3u: endpoints%3d; err%3g%%; tex fetch%4.1f; mem%4.1fkb\n", + glyph_index, + (unsigned int) glyphy_arc_accumulator_get_num_endpoints (font->acc), + round (100 * glyphy_arc_accumulator_get_error (font->acc) / tolerance), + avg_fetch_achieved, + (*output_len * sizeof (glyphy_rgba_t)) / 1024.); + + font->num_glyphs++; + font->sum_error += glyphy_arc_accumulator_get_error (font->acc) / tolerance; + font->sum_endpoints += glyphy_arc_accumulator_get_num_endpoints (font->acc); + font->sum_fetch += avg_fetch_achieved; + font->sum_bytes += (*output_len * sizeof (glyphy_rgba_t)); +} + +static void +_demo_font_upload_glyph (demo_font_t *font, + unsigned int glyph_index, + glyph_info_t *glyph_info) +{ + glyphy_rgba_t buffer[4096 * 16]; + unsigned int output_len; + + encode_ft_glyph (font, + glyph_index, + TOLERANCE, + buffer, ARRAY_LEN (buffer), + &output_len, + &glyph_info->nominal_w, + &glyph_info->nominal_h, + &glyph_info->extents, + &glyph_info->advance); + + glyph_info->is_empty = glyphy_extents_is_empty (&glyph_info->extents); + if (!glyph_info->is_empty) + demo_atlas_alloc (font->atlas, buffer, output_len, + &glyph_info->atlas_x, &glyph_info->atlas_y); +} + +void +demo_font_lookup_glyph (demo_font_t *font, + unsigned int glyph_index, + glyph_info_t *glyph_info) +{ + if (font->glyph_cache->find (glyph_index) == font->glyph_cache->end ()) { + _demo_font_upload_glyph (font, glyph_index, glyph_info); + (*font->glyph_cache)[glyph_index] = *glyph_info; + } else + *glyph_info = (*font->glyph_cache)[glyph_index]; +} + +void +demo_font_print_stats (demo_font_t *font) +{ + LOGI ("%3d glyphs; avg num endpoints%6.2f; avg error%5.1f%%; avg tex fetch%5.2f; avg %5.2fkb per glyph\n", + font->num_glyphs, + (double) font->sum_endpoints / font->num_glyphs, + 100. * font->sum_error / font->num_glyphs, + font->sum_fetch / font->num_glyphs, + font->sum_bytes / 1024. / font->num_glyphs); +} diff --git a/demo-gl3/demo-font.h b/demo-gl3/demo-font.h new file mode 100644 index 00000000..9756d668 --- /dev/null +++ b/demo-gl3/demo-font.h @@ -0,0 +1,74 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef DEMO_FONT_H +#define DEMO_FONT_H + +#include "demo-common.h" +#include "demo-atlas.h" + +#include +#include FT_FREETYPE_H + +#ifdef _WIN32 +#define DEFAULT_FONT "Calibri" +#undef near +#undef far +#endif + +typedef struct { + glyphy_extents_t extents; + double advance; + glyphy_bool_t is_empty; /* has no outline; eg. space; don't draw it */ + unsigned int nominal_w; + unsigned int nominal_h; + unsigned int atlas_x; + unsigned int atlas_y; +} glyph_info_t; + + +typedef struct demo_font_t demo_font_t; + +demo_font_t * +demo_font_create (FT_Face face, + demo_atlas_t *atlas); + +demo_font_t * +demo_font_reference (demo_font_t *font); + +void +demo_font_destroy (demo_font_t *font); + + +FT_Face +demo_font_get_face (demo_font_t *font); + +demo_atlas_t * +demo_font_get_atlas (demo_font_t *font); + + +void +demo_font_lookup_glyph (demo_font_t *font, + unsigned int glyph_index, + glyph_info_t *glyph_info); + +void +demo_font_print_stats (demo_font_t *font); + + +#endif /* DEMO_FONT_H */ diff --git a/demo-gl3/demo-fshader.glsl b/demo-gl3/demo-fshader.glsl new file mode 100644 index 00000000..8eb4b9a1 --- /dev/null +++ b/demo-gl3/demo-fshader.glsl @@ -0,0 +1,86 @@ +uniform float u_contrast; +uniform float u_gamma_adjust; +uniform float u_outline_thickness; +uniform bool u_outline; +uniform float u_boldness; +uniform bool u_debug; + +in vec4 v_glyph; +out vec4 FragColor; + + +#define SQRT2_2 0.70710678118654757 /* 1 / sqrt(2.) */ +#define SQRT2 1.4142135623730951 + +struct glyph_info_t { + ivec2 nominal_size; + ivec2 atlas_pos; +}; + +glyph_info_t +glyph_info_decode (vec4 v) +{ + glyph_info_t gi; + gi.nominal_size = (ivec2 (mod (v.zw, 256.)) + 2) / 4; + gi.atlas_pos = ivec2 (v_glyph.zw) / 256; + return gi; +} + + +float +antialias (float d) +{ + return smoothstep (-.75, +.75, d); +} + +void +main() +{ + vec2 p = v_glyph.xy; + glyph_info_t gi = glyph_info_decode (v_glyph); + + /* isotropic antialiasing */ + vec2 dpdx = dFdx (p); + vec2 dpdy = dFdy (p); + float m = length (vec2 (length (dpdx), length (dpdy))) * SQRT2_2; + + vec4 color = vec4 (0,0,0,1); + + float gsdist = glyphy_sdf (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS); + float sdist = gsdist / m * u_contrast; + + if (!u_debug) { + sdist -= u_boldness * 10.; + if (u_outline) + sdist = abs (sdist) - u_outline_thickness * .5; + if (sdist > 1.) + discard; + float alpha = antialias (-sdist); + if (u_gamma_adjust != 1.) + alpha = pow (alpha, 1./u_gamma_adjust); + color = vec4 (color.rgb,color.a * alpha); + } else { + color = vec4 (0,0,0,0); + + // Color the inside of the glyph a light red + color += vec4 (.5,0,0,.5) * smoothstep (1., -1., sdist); + + float udist = abs (sdist); + float gudist = abs (gsdist); + // Color the outline red + color += vec4 (1,0,0,1) * smoothstep (2., 1., udist); + // Color the distance field in green + if (!glyphy_isinf (udist)) + color += vec4(0,.4,0,.4 - (abs(gsdist) / max(float(gi.nominal_size.x), float(gi.nominal_size.y))) * 4.); + + float pdist = glyphy_point_dist (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS); + // Color points green + color = mix (vec4 (0,1,0,.5), color, smoothstep (.05, .06, pdist)); + + glyphy_arc_list_t arc_list = glyphy_arc_list (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS); + // Color the number of endpoints per cell blue + color += vec4 (0,0,1,.1) * float(arc_list.num_endpoints) * 32./255.; + } + + FragColor = color; +} diff --git a/demo-gl3/demo-glstate.cc b/demo-gl3/demo-glstate.cc new file mode 100644 index 00000000..0f6f394b --- /dev/null +++ b/demo-gl3/demo-glstate.cc @@ -0,0 +1,155 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod, Maysum Panju, Wojciech Baranowski + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "demo-glstate.h" + +struct demo_glstate_t { + unsigned int refcount; + + GLuint program; + demo_atlas_t *atlas; + + /* Uniforms */ + double u_debug; + double u_contrast; + double u_gamma_adjust; + double u_outline; + double u_outline_thickness; + double u_boldness; +}; + +demo_glstate_t * +demo_glstate_create (void) +{ + TRACE(); + + demo_glstate_t *st = (demo_glstate_t *) calloc (1, sizeof (demo_glstate_t)); + st->refcount = 1; + + st->program = demo_shader_create_program (); + st->atlas = demo_atlas_create (2048, 1024, 64, 8); + + st->u_debug = false; + st->u_contrast = 1.0; + st->u_gamma_adjust = 1.0; + st->u_outline = false; + st->u_outline_thickness = 1.0; + st->u_boldness = 0.; + + return st; +} + +demo_glstate_t * +demo_glstate_reference (demo_glstate_t *st) +{ + if (st) st->refcount++; + return st; +} + +void +demo_glstate_destroy (demo_glstate_t *st) +{ + if (!st || --st->refcount) + return; + + demo_atlas_destroy (st->atlas); + glDeleteProgram (st->program); + + free (st); +} + + +static void +set_uniform (GLuint program, const char *name, double *p, double value) +{ + *p = value; + glUniform1f (glGetUniformLocation (program, name), value); + LOGI ("Setting %s to %g\n", name + 2, value); +} + +#define SET_UNIFORM(name, value) set_uniform (st->program, #name, &st->name, value) + +void +demo_glstate_setup (demo_glstate_t *st) +{ + glUseProgram (st->program); + + demo_atlas_set_uniforms (st->atlas); + + SET_UNIFORM (u_debug, st->u_debug); + SET_UNIFORM (u_contrast, st->u_contrast); + SET_UNIFORM (u_gamma_adjust, st->u_gamma_adjust); + SET_UNIFORM (u_outline, st->u_outline); + SET_UNIFORM (u_outline_thickness, st->u_outline_thickness); + SET_UNIFORM (u_boldness, st->u_boldness); + + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + +demo_atlas_t * +demo_glstate_get_atlas (demo_glstate_t *st) +{ + return st->atlas; +} + +void +demo_glstate_scale_gamma_adjust (demo_glstate_t *st, double factor) +{ + SET_UNIFORM (u_gamma_adjust, clamp (st->u_gamma_adjust * factor, .1, 10.)); +} + +void +demo_glstate_scale_contrast (demo_glstate_t *st, double factor) +{ + SET_UNIFORM (u_contrast, clamp (st->u_contrast * factor, .1, 10.)); +} + +void +demo_glstate_toggle_debug (demo_glstate_t *st) +{ + SET_UNIFORM (u_debug, 1 - st->u_debug); +} + +void +demo_glstate_set_matrix (demo_glstate_t *st, float mat[16]) +{ + glUniformMatrix4fv (glGetUniformLocation (st->program, "u_matViewProjection"), 1, GL_FALSE, mat); +} + +void +demo_glstate_toggle_outline (demo_glstate_t *st) +{ + SET_UNIFORM (u_outline, 1 - st->u_outline); +} + +void +demo_glstate_scale_outline_thickness (demo_glstate_t *st, double factor) +{ + SET_UNIFORM (u_outline_thickness, clamp (st->u_outline_thickness * factor, .5, 3.)); +} + +void +demo_glstate_adjust_boldness (demo_glstate_t *st, double adjustment) +{ + SET_UNIFORM (u_boldness, clamp (st->u_boldness + adjustment, -.2, .7)); +} diff --git a/demo-gl3/demo-glstate.h b/demo-gl3/demo-glstate.h new file mode 100644 index 00000000..23899cda --- /dev/null +++ b/demo-gl3/demo-glstate.h @@ -0,0 +1,68 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef DEMO_GLSTATE_H +#define DEMO_GLSTATE_H + +#include "demo-common.h" +#include "demo-buffer.h" + +#include "demo-atlas.h" +#include "demo-shader.h" + +typedef struct demo_glstate_t demo_glstate_t; + +demo_glstate_t * +demo_glstate_create (void); + +demo_glstate_t * +demo_glstate_reference (demo_glstate_t *st); + +void +demo_glstate_destroy (demo_glstate_t *st); + + +void +demo_glstate_setup (demo_glstate_t *st); + +demo_atlas_t * +demo_glstate_get_atlas (demo_glstate_t *st); + +void +demo_glstate_scale_gamma_adjust (demo_glstate_t *st, double factor); + +void +demo_glstate_scale_contrast (demo_glstate_t *st, double factor); + +void +demo_glstate_toggle_debug (demo_glstate_t *st); + +void +demo_glstate_set_matrix (demo_glstate_t *st, float mat[16]); + +void +demo_glstate_toggle_outline (demo_glstate_t *st); + +void +demo_glstate_scale_outline_thickness (demo_glstate_t *st, double factor); + +void +demo_glstate_adjust_boldness (demo_glstate_t *st, double adjustment); + + +#endif /* DEMO_GLSTATE_H */ diff --git a/demo-gl3/demo-shader.cc b/demo-gl3/demo-shader.cc new file mode 100644 index 00000000..fec50b47 --- /dev/null +++ b/demo-gl3/demo-shader.cc @@ -0,0 +1,213 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "demo-shader.h" + +#include "demo-atlas-glsl.h" +#include "demo-vshader-glsl.h" +#include "demo-fshader-glsl.h" + + +static unsigned int +glyph_encode (unsigned int atlas_x , /* 7 bits */ + unsigned int atlas_y, /* 7 bits */ + unsigned int corner_x, /* 1 bit */ + unsigned int corner_y, /* 1 bit */ + unsigned int nominal_w, /* 6 bits */ + unsigned int nominal_h /* 6 bits */) +{ + assert (0 == (atlas_x & ~0x7F)); + assert (0 == (atlas_y & ~0x7F)); + assert (0 == (corner_x & ~1)); + assert (0 == (corner_y & ~1)); + assert (0 == (nominal_w & ~0x3F)); + assert (0 == (nominal_h & ~0x3F)); + + unsigned int x = (((atlas_x << 6) | nominal_w) << 1) | corner_x; + unsigned int y = (((atlas_y << 6) | nominal_h) << 1) | corner_y; + + return (x << 16) | y; +} + +static void +glyph_vertex_encode (double x, double y, + unsigned int corner_x, unsigned int corner_y, + const glyph_info_t *gi, + glyph_vertex_t *v) +{ + unsigned int encoded = glyph_encode (gi->atlas_x, gi->atlas_y, + corner_x, corner_y, + gi->nominal_w, gi->nominal_h); + v->x = x; + v->y = y; + v->g16hi = encoded >> 16; + v->g16lo = encoded & 0xFFFF; +} + +void +demo_shader_add_glyph_vertices (const glyphy_point_t &p, + double font_size, + glyph_info_t *gi, + std::vector *vertices, + glyphy_extents_t *extents) +{ + if (gi->is_empty) + return; + + glyph_vertex_t v[4]; + +#define ENCODE_CORNER(_cx, _cy) \ + do { \ + double _vx = p.x + font_size * ((1-_cx) * gi->extents.min_x + _cx * gi->extents.max_x); \ + double _vy = p.y - font_size * ((1-_cy) * gi->extents.min_y + _cy * gi->extents.max_y); \ + glyph_vertex_encode (_vx, _vy, _cx, _cy, gi, &v[_cx * 2 + _cy]); \ + } while (0) + ENCODE_CORNER (0, 0); + ENCODE_CORNER (0, 1); + ENCODE_CORNER (1, 0); + ENCODE_CORNER (1, 1); +#undef ENCODE_CORNER + + vertices->push_back (v[0]); + vertices->push_back (v[1]); + vertices->push_back (v[2]); + + vertices->push_back (v[1]); + vertices->push_back (v[2]); + vertices->push_back (v[3]); + + if (extents) { + glyphy_extents_clear (extents); + for (unsigned int i = 0; i < 4; i++) { + glyphy_point_t p = {v[i].x, v[i].y}; + glyphy_extents_add (extents, &p); + } + } +} + + + + +static GLuint +compile_shader (GLenum type, + GLsizei count, + const GLchar** sources) +{ + TRACE(); + + GLuint shader; + GLint compiled; + + if (!(shader = glCreateShader (type))) + return shader; + + glShaderSource (shader, count, sources, 0); + glCompileShader (shader); + + glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint info_len = 0; + LOGW ("%s shader failed to compile\n", + type == GL_VERTEX_SHADER ? "Vertex" : "Fragment"); + glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &info_len); + + if (info_len > 0) { + char *info_log = (char*) malloc (info_len); + glGetShaderInfoLog (shader, info_len, NULL, info_log); + + LOGW ("%s\n", info_log); + free (info_log); + } + + abort (); + } + + return shader; +} + +static GLuint +link_program (GLuint vshader, + GLuint fshader) +{ + TRACE(); + + GLuint program; + GLint linked; + + program = glCreateProgram (); + glAttachShader (program, vshader); + glAttachShader (program, fshader); + glLinkProgram (program); + glDeleteShader (vshader); + glDeleteShader (fshader); + + glGetProgramiv (program, GL_LINK_STATUS, &linked); + if (!linked) { + GLint info_len = 0; + LOGW ("Program failed to link\n"); + glGetProgramiv (program, GL_INFO_LOG_LENGTH, &info_len); + + if (info_len > 0) { + char *info_log = (char*) malloc (info_len); + glGetProgramInfoLog (program, info_len, NULL, info_log); + + LOGW ("%s\n", info_log); + free (info_log); + } + + abort (); + } + + return program; +} + +#ifdef GL_ES_VERSION_2_0 +# define GLSL_HEADER_STRING \ + "#version 320 es\n" \ + "#extension GL_OES_standard_derivatives : enable\n" \ + "precision highp float;\n" \ + "precision highp int;\n" +#else +# define GLSL_HEADER_STRING \ + "#version 330 core\n" +#endif + +GLuint +demo_shader_create_program (void) +{ + TRACE(); + + GLuint vshader, fshader, program; + const GLchar *vshader_sources[] = {GLSL_HEADER_STRING, + demo_vshader_glsl}; + vshader = compile_shader (GL_VERTEX_SHADER, ARRAY_LEN (vshader_sources), vshader_sources); + const GLchar *fshader_sources[] = {GLSL_HEADER_STRING, + demo_atlas_glsl, + glyphy_common_shader_source (), + "#define GLYPHY_SDF_PSEUDO_DISTANCE 1\n", + glyphy_sdf_shader_source (), + demo_fshader_glsl}; + fshader = compile_shader (GL_FRAGMENT_SHADER, ARRAY_LEN (fshader_sources), fshader_sources); + + program = link_program (vshader, fshader); + return program; +} diff --git a/demo-gl3/demo-shader.h b/demo-gl3/demo-shader.h new file mode 100644 index 00000000..dfa54809 --- /dev/null +++ b/demo-gl3/demo-shader.h @@ -0,0 +1,47 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef DEMO_SHADERS_H +#define DEMO_SHADERS_H + +#include "demo-common.h" +#include "demo-font.h" + + +struct glyph_vertex_t { + /* Position */ + GLfloat x; + GLfloat y; + /* Glyph info */ + GLfloat g16hi; + GLfloat g16lo; +}; + +void +demo_shader_add_glyph_vertices (const glyphy_point_t &p, + double font_size, + glyph_info_t *gi, + std::vector *vertices, + glyphy_extents_t *extents); + + +GLuint +demo_shader_create_program (void); + + +#endif /* DEMO_SHADERS_H */ diff --git a/demo-gl3/demo-view.cc b/demo-gl3/demo-view.cc new file mode 100644 index 00000000..edaaf43b --- /dev/null +++ b/demo-gl3/demo-view.cc @@ -0,0 +1,657 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod, Maysum Panju, Wojciech Baranowski + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "demo-view.h" + +extern "C" { +#include "trackball.h" +#include "matrix4x4.h" +} + +#ifndef _WIN32 +#include +#endif + +struct demo_view_t { + unsigned int refcount; + + demo_glstate_t *st; + + /* Output */ + GLint vsync; + glyphy_bool_t srgb; + glyphy_bool_t fullscreen; + + /* Mouse handling */ + int buttons; + int modifiers; + bool dragged; + bool click_handled; + double beginx, beginy; + double lastx, lasty, lastt; + double dx,dy, dt; + + /* Transformation */ + float quat[4]; + double scale; + glyphy_point_t translate; + double perspective; + + /* Animation */ + float rot_axis[3]; + float rot_speed; + bool animate; + int num_frames; + long fps_start_time; + long last_frame_time; + bool has_fps_timer; + + /* Window geometry just before going fullscreen */ + int x; + int y; + int width; + int height; +}; + +demo_view_t *static_vu; + +demo_view_t * +demo_view_create (demo_glstate_t *st) +{ + TRACE(); + + demo_view_t *vu = (demo_view_t *) calloc (1, sizeof (demo_view_t)); + vu->refcount = 1; + + vu->st = st; + demo_view_reset (vu); + + assert (!static_vu); + static_vu = vu; + + return vu; +} + +demo_view_t * +demo_view_reference (demo_view_t *vu) +{ + if (vu) vu->refcount++; + return vu; +} + +void +demo_view_destroy (demo_view_t *vu) +{ + if (!vu || --vu->refcount) + return; + + assert (static_vu == vu); + static_vu = NULL; + + free (vu); +} + + +#define ANIMATION_SPEED 1. /* Default speed, in radians second. */ +void +demo_view_reset (demo_view_t *vu) +{ + vu->perspective = 4; + vu->scale = 1; + vu->translate.x = vu->translate.y = 0; + trackball (vu->quat , 0.0, 0.0, 0.0, 0.0); + vset (vu->rot_axis, 0., 0., 1.); + vu->rot_speed = ANIMATION_SPEED / 1000.; +} + + +static void +demo_view_scale_gamma_adjust (demo_view_t *vu, double factor) +{ + demo_glstate_scale_gamma_adjust (vu->st, factor); +} + +static void +demo_view_scale_contrast (demo_view_t *vu, double factor) +{ + demo_glstate_scale_contrast (vu->st, factor); +} + +static void +demo_view_scale_perspective (demo_view_t *vu, double factor) +{ + vu->perspective = clamp (vu->perspective * factor, .01, 100.); +} + +static void +demo_view_toggle_outline (demo_view_t *vu) +{ + demo_glstate_toggle_outline (vu->st); +} + +static void +demo_view_scale_outline_thickness (demo_view_t *vu, double factor) +{ + demo_glstate_scale_outline_thickness (vu->st, factor); +} + + +static void +demo_view_adjust_boldness (demo_view_t *vu, double factor) +{ + demo_glstate_adjust_boldness (vu->st, factor); +} + + +static void +demo_view_scale (demo_view_t *vu, double factor) +{ + vu->scale *= factor; +} + +static void +demo_view_translate (demo_view_t *vu, double dx, double dy) +{ + vu->translate.x += dx / vu->scale; + vu->translate.y += dy / vu->scale; +} + +static void +demo_view_apply_transform (demo_view_t *vu, float *mat) +{ + int viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + GLint width = viewport[2]; + GLint height = viewport[3]; + + // View transform + m4Scale (mat, vu->scale, vu->scale, 1); + m4Translate (mat, vu->translate.x, vu->translate.y, 0); + + // Perspective + { + double d = std::max (width, height); + double near = d / vu->perspective; + double far = near + d; + double factor = near / (2 * near + d); + m4Frustum (mat, -width * factor, width * factor, -height * factor, height * factor, near, far); + m4Translate (mat, 0, 0, -(near + d * .5)); + } + + // Rotate + float m[4][4]; + build_rotmatrix (m, vu->quat); + m4MultMatrix(mat, &m[0][0]); + + // Fix 'up' + m4Scale (mat, 1, -1, 1); +} + + +/* return current time in milli-seconds */ +static long +current_time (void) +{ + return glutGet (GLUT_ELAPSED_TIME); +} + +static void +next_frame (demo_view_t *vu) +{ + glutPostRedisplay (); +} + +static void +timed_step (int ms) +{ + demo_view_t *vu = static_vu; + if (vu->animate) { + glutTimerFunc (ms, timed_step, ms); + next_frame (vu); + } +} + +static void +idle_step (void) +{ + demo_view_t *vu = static_vu; + if (vu->animate) { + next_frame (vu); + } + else + glutIdleFunc (NULL); +} + +static void +print_fps (int ms) +{ + demo_view_t *vu = static_vu; + if (vu->animate) { + glutTimerFunc (ms, print_fps, ms); + long t = current_time (); + LOGI ("%gfps\n", vu->num_frames * 1000. / (t - vu->fps_start_time)); + vu->num_frames = 0; + vu->fps_start_time = t; + } else + vu->has_fps_timer = false; +} + +static void +start_animation (demo_view_t *vu) +{ + vu->num_frames = 0; + vu->last_frame_time = vu->fps_start_time = current_time (); + //glutTimerFunc (1000/60, timed_step, 1000/60); + glutIdleFunc (idle_step); + if (!vu->has_fps_timer) { + vu->has_fps_timer = true; + glutTimerFunc (5000, print_fps, 5000); + } +} + +static void +demo_view_toggle_animation (demo_view_t *vu) +{ + vu->animate = !vu->animate; + if (vu->animate) + start_animation (vu); +} + + +static void +demo_view_toggle_vsync (demo_view_t *vu) +{ + vu->vsync = !vu->vsync; + LOGI ("Setting vsync %s.\n", vu->vsync ? "on" : "off"); +#if defined(__APPLE__) + CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &vu->vsync); +#elif defined(__WGLEW__) + if (wglewIsSupported ("WGL_EXT_swap_control")) + wglSwapIntervalEXT (vu->vsync); + else + LOGW ("WGL_EXT_swal_control not supported; failed to set vsync\n"); +#elif defined(__GLXEW_H__) + if (glxewIsSupported ("GLX_SGI_swap_control")) + glXSwapIntervalSGI (vu->vsync); + else + LOGW ("GLX_SGI_swap_control not supported; failed to set vsync\n"); +#else + LOGW ("No vsync extension found; failed to set vsync\n"); +#endif +} + +static void +demo_view_toggle_srgb (demo_view_t *vu) +{ + vu->srgb = !vu->srgb; + LOGI ("Setting sRGB framebuffer %s.\n", vu->srgb ? "on" : "off"); +#if defined(GL_FRAMEBUFFER_SRGB) && defined(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT) + GLboolean available = false; + if ((glewIsSupported ("GL_ARB_framebuffer_sRGB") || glewIsSupported ("GL_EXT_framebuffer_sRGB")) && + (glGetBooleanv (GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &available), available)) { + if (vu->srgb) + glEnable (GL_FRAMEBUFFER_SRGB); + else + glDisable (GL_FRAMEBUFFER_SRGB); + } else +#endif + LOGW ("No sRGB framebuffer extension found; failed to set sRGB framebuffer\n"); +} + +static void +demo_view_toggle_fullscreen (demo_view_t *vu) +{ + vu->fullscreen = !vu->fullscreen; + if (vu->fullscreen) { + vu->x = glutGet (GLUT_WINDOW_X); + vu->y = glutGet (GLUT_WINDOW_Y); + vu->width = glutGet (GLUT_WINDOW_WIDTH); + vu->height = glutGet (GLUT_WINDOW_HEIGHT); + glutFullScreen (); + } else { + glutReshapeWindow (vu->width, vu->height); + glutPositionWindow (vu->x, vu->y); + } +} + +static void +demo_view_toggle_debug (demo_view_t *vu) +{ + demo_glstate_toggle_debug (vu->st); +} + + +void +demo_view_reshape_func (demo_view_t *vu, int width, int height) +{ + glViewport (0, 0, width, height); + glutPostRedisplay (); +} + +#define STEP 1.05 +void +demo_view_keyboard_func (demo_view_t *vu, unsigned char key, int x, int y) +{ + switch (key) + { + case '\033': + case 'q': + exit (0); + break; + + case ' ': + demo_view_toggle_animation (vu); + break; + case 'v': + demo_view_toggle_vsync (vu); + break; + + case 'f': + demo_view_toggle_fullscreen (vu); + break; + + case 'd': + demo_view_toggle_debug (vu); + break; + + case 'o': + demo_view_toggle_outline (vu); + break; + case 'p': + demo_view_scale_outline_thickness (vu, STEP); + break; + case 'i': + demo_view_scale_outline_thickness (vu, 1. / STEP); + break; + + case '0': + demo_view_adjust_boldness (vu, +.01); + break; + case '9': + demo_view_adjust_boldness (vu, -.01); + break; + + + case 'a': + demo_view_scale_contrast (vu, STEP); + break; + case 'z': + demo_view_scale_contrast (vu, 1. / STEP); + break; + case 'g': + demo_view_scale_gamma_adjust (vu, STEP); + break; + case 'b': + demo_view_scale_gamma_adjust (vu, 1. / STEP); + break; + case 'c': + demo_view_toggle_srgb (vu); + break; + + case '=': + demo_view_scale (vu, STEP); + break; + case '-': + demo_view_scale (vu, 1. / STEP); + break; + + case 'k': + demo_view_translate (vu, 0, -.1); + break; + case 'j': + demo_view_translate (vu, 0, +.1); + break; + case 'h': + demo_view_translate (vu, +.1, 0); + break; + case 'l': + demo_view_translate (vu, -.1, 0); + break; + + case 'r': + demo_view_reset (vu); + break; + + default: + return; + } + glutPostRedisplay (); +} + +void +demo_view_special_func (demo_view_t *vu, int key, int x, int y) +{ + switch (key) + { + case GLUT_KEY_UP: + demo_view_translate (vu, 0, -.1); + break; + case GLUT_KEY_DOWN: + demo_view_translate (vu, 0, +.1); + break; + case GLUT_KEY_LEFT: + demo_view_translate (vu, +.1, 0); + break; + case GLUT_KEY_RIGHT: + demo_view_translate (vu, -.1, 0); + break; + + default: + return; + } + glutPostRedisplay (); +} + +void +demo_view_mouse_func (demo_view_t *vu, int button, int state, int x, int y) +{ + if (state == GLUT_DOWN) { + vu->buttons |= (1 << button); + vu->click_handled = false; + } else + vu->buttons &= !(1 << button); + vu->modifiers = glutGetModifiers (); + + switch (button) + { + case GLUT_RIGHT_BUTTON: + switch (state) { + case GLUT_DOWN: + if (vu->animate) { + demo_view_toggle_animation (vu); + vu->click_handled = true; + } + break; + case GLUT_UP: + if (!vu->animate) + { + if (!vu->dragged && !vu->click_handled) + demo_view_toggle_animation (vu); + else if (vu->dt) { + double speed = hypot (vu->dx, vu->dy) / vu->dt; + if (speed > 0.1) + demo_view_toggle_animation (vu); + } + vu->dx = vu->dy = vu->dt = 0; + } + break; + } + break; + +#if !defined(GLUT_WHEEL_UP) +#define GLUT_WHEEL_UP 3 +#define GLUT_WHEEL_DOWN 4 +#endif + + case GLUT_WHEEL_UP: + demo_view_scale (vu, STEP); + break; + + case GLUT_WHEEL_DOWN: + demo_view_scale (vu, 1. / STEP); + break; + } + + vu->beginx = vu->lastx = x; + vu->beginy = vu->lasty = y; + vu->dragged = false; + + glutPostRedisplay (); +} + +void +demo_view_motion_func (demo_view_t *vu, int x, int y) +{ + vu->dragged = true; + + int viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + GLuint width = viewport[2]; + GLuint height = viewport[3]; + + if (vu->buttons & (1 << GLUT_LEFT_BUTTON)) + { + if (vu->modifiers & GLUT_ACTIVE_SHIFT) { + /* adjust contrast/gamma */ + demo_view_scale_gamma_adjust (vu, 1 - ((y - vu->lasty) / height)); + demo_view_scale_contrast (vu, 1 + ((x - vu->lastx) / width)); + } else { + /* translate */ + demo_view_translate (vu, + +2 * (x - vu->lastx) / width, + -2 * (y - vu->lasty) / height); + } + } + + if (vu->buttons & (1 << GLUT_RIGHT_BUTTON)) + { + if (vu->modifiers & GLUT_ACTIVE_SHIFT) { + /* adjust perspective */ + demo_view_scale_perspective (vu, 1 - ((y - vu->lasty) / height) * 5); + } else { + /* rotate */ + float dquat[4]; + trackball (dquat, + (2.0*vu->lastx - width) / width, + ( height - 2.0*vu->lasty) / height, + ( 2.0*x - width) / width, + ( height - 2.0*y) / height ); + + vu->dx = x - vu->lastx; + vu->dy = y - vu->lasty; + vu->dt = current_time () - vu->lastt; + + add_quats (dquat, vu->quat, vu->quat); + + if (vu->dt) { + vcopy (dquat, vu->rot_axis); + vnormal (vu->rot_axis); + vu->rot_speed = 2 * acos (dquat[3]) / vu->dt; + } + } + } + + if (vu->buttons & (1 << GLUT_MIDDLE_BUTTON)) + { + /* scale */ + double factor = 1 - ((y - vu->lasty) / height) * 5; + demo_view_scale (vu, factor); + /* adjust translate so we scale centered at the drag-begin mouse position */ + demo_view_translate (vu, + +(2. * vu->beginx / width - 1) * (1 - factor), + -(2. * vu->beginy / height - 1) * (1 - factor)); + } + + vu->lastx = x; + vu->lasty = y; + vu->lastt = current_time (); + + glutPostRedisplay (); +} + +void +demo_view_print_help (demo_view_t *vu) +{ + LOGI ("Welcome to GLyphy demo\n"); +} + + +static void +advance_frame (demo_view_t *vu, long dtime) +{ + if (vu->animate) { + float dquat[4]; + axis_to_quat (vu->rot_axis, vu->rot_speed * dtime, dquat); + add_quats (dquat, vu->quat, vu->quat); + vu->num_frames++; + } +} + +void +demo_view_display (demo_view_t *vu, demo_buffer_t *buffer) +{ + long new_time = current_time (); + advance_frame (vu, new_time - vu->last_frame_time); + vu->last_frame_time = new_time; + + int viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + GLint width = viewport[2]; + GLint height = viewport[3]; + + + float mat[16]; + + m4LoadIdentity (mat); + + demo_view_apply_transform (vu, mat); + + // Buffer best-fit + glyphy_extents_t extents; + demo_buffer_extents (buffer, NULL, &extents); + double content_scale = .9 * std::min (width / (extents.max_x - extents.min_x), + height / (extents.max_y - extents.min_y)); + m4Scale (mat, content_scale, content_scale, 1); + // Center buffer + m4Translate (mat, + -(extents.max_x + extents.min_x) / 2., + -(extents.max_y + extents.min_y) / 2., 0); + + demo_glstate_set_matrix (vu->st, mat); + + glClearColor (1, 1, 1, 1); + glClear (GL_COLOR_BUFFER_BIT); + + demo_buffer_draw (buffer); + + glutSwapBuffers (); +} + +void +demo_view_setup (demo_view_t *vu) +{ + if (!vu->vsync) + demo_view_toggle_vsync (vu); + if (!vu->srgb) + demo_view_toggle_srgb (vu); + demo_glstate_setup (vu->st); +} diff --git a/demo-gl3/demo-view.h b/demo-gl3/demo-view.h new file mode 100644 index 00000000..9619361d --- /dev/null +++ b/demo-gl3/demo-view.h @@ -0,0 +1,66 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef DEMO_VIEW_H +#define DEMO_VIEW_H + +#include "demo-common.h" +#include "demo-buffer.h" +#include "demo-glstate.h" + +typedef struct demo_view_t demo_view_t; + +demo_view_t * +demo_view_create (demo_glstate_t *st); + +demo_view_t * +demo_view_reference (demo_view_t *vu); + +void +demo_view_destroy (demo_view_t *vu); + + +void +demo_view_reset (demo_view_t *vu); + +void +demo_view_reshape_func (demo_view_t *vu, int width, int height); + +void +demo_view_keyboard_func (demo_view_t *vu, unsigned char key, int x, int y); + +void +demo_view_special_func (demo_view_t *view, int key, int x, int y); + +void +demo_view_mouse_func (demo_view_t *vu, int button, int state, int x, int y); + +void +demo_view_motion_func (demo_view_t *vu, int x, int y); + +void +demo_view_print_help (demo_view_t *vu); + +void +demo_view_display (demo_view_t *vu, demo_buffer_t *buffer); + +void +demo_view_setup (demo_view_t *vu); + + +#endif /* DEMO_VIEW_H */ diff --git a/demo-gl3/demo-vshader.glsl b/demo-gl3/demo-vshader.glsl new file mode 100644 index 00000000..6bc3e6d6 --- /dev/null +++ b/demo-gl3/demo-vshader.glsl @@ -0,0 +1,22 @@ +uniform mat4 u_matViewProjection; + +layout (location = 0) in vec4 a_glyph_vertex; + +out vec4 v_glyph; + +vec4 +glyph_vertex_transcode (vec2 v) +{ + ivec2 g = ivec2 (v); + ivec2 corner = ivec2 (mod (v, 2.)); + g /= 2; + ivec2 nominal_size = ivec2 (mod (vec2(g), 64.)); + return vec4 (corner * nominal_size, g * 4); +} + +void +main() +{ + gl_Position = u_matViewProjection * vec4 (a_glyph_vertex.xy, 0, 1); + v_glyph = glyph_vertex_transcode (a_glyph_vertex.zw); +} diff --git a/demo-gl3/glyphy-demo.cc b/demo-gl3/glyphy-demo.cc new file mode 100644 index 00000000..15e0bc00 --- /dev/null +++ b/demo-gl3/glyphy-demo.cc @@ -0,0 +1,291 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod, Maysum Panju, Wojciech Baranowski + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef _WIN32 +#include +#include +#endif +#include +#include +#include +#include + + +#include "demo-buffer.h" +#include "demo-font.h" +#include "demo-view.h" + +static demo_glstate_t *st; +static demo_view_t *vu; +static demo_buffer_t *buffer; + +#define WINDOW_W 700 +#define WINDOW_H 700 + +#ifdef _WIN32 + +static int isroot(const char *path) +{ + return ((strlen(path) == 1 && path[0] == '/') || + (strlen(path) == 3 && isalpha(path[0]) && path[1] == ':' && (path[2] == '/' || path[2] == '\\'))); +} + +static char *basename(char *path) +{ + if (path == NULL || *path == '\0') + return "."; + + while ((path[strlen(path)-1] == '/' || + path[strlen(path)-1] == '\\') && + !isroot(path)) + path[strlen(path)-1] = '\0'; + + if (isroot(path)) + return path; + + char *slash = strrchr(path, '/'); + char *backslash = strrchr(path, '\\'); + + if (slash != NULL && (backslash == NULL || backslash < slash)) + return slash + 1; + else if (backslash != NULL && (slash == NULL || slash < backslash)) + return backslash + 1; + else + return path; +} + +static int opterr = 1; +static int optind = 1; +static int optopt; +static char *optarg; + +static int getopt(int argc, char *argv[], char *opts) +{ + static int sp = 1; + int c; + char *cp; + + if (sp == 1) { + if (optind >= argc || + argv[optind][0] != '-' || argv[optind][1] == '\0') + return EOF; + else if (!strcmp(argv[optind], "--")) { + optind++; + return EOF; + } + } + optopt = c = argv[optind][sp]; + if (c == ':' || !(cp = strchr(opts, c))) { + fprintf(stderr, ": illegal option -- %c\n", c); + if (argv[optind][++sp] == '\0') { + optind++; + sp = 1; + } + return '?'; + } + if (*++cp == ':') { + if (argv[optind][sp+1] != '\0') + optarg = &argv[optind++][sp+1]; + else if(++optind >= argc) { + fprintf(stderr, ": option requires an argument -- %c\n", c); + sp = 1; + return '?'; + } else + optarg = argv[optind++]; + sp = 1; + } else { + if (argv[optind][++sp] == '\0') { + sp = 1; + optind++; + } + optarg = NULL; + } + + return c; +} + +#endif + +static void +reshape_func (int width, int height) +{ + demo_view_reshape_func (vu, width, height); +} + +static void +keyboard_func (unsigned char key, int x, int y) +{ + demo_view_keyboard_func (vu, key, x, y); +} + +static void +special_func (int key, int x, int y) +{ + demo_view_special_func (vu, key, x, y); +} + +static void +mouse_func (int button, int state, int x, int y) +{ + demo_view_mouse_func (vu, button, state, x, y); +} + +static void +motion_func (int x, int y) +{ + demo_view_motion_func (vu, x, y); +} + +static void +display_func (void) +{ + demo_view_display (vu, buffer); +} + +static void +show_usage(const char *path) +{ + + char *name, *p = strdup(path); + + name = basename(p); + + printf("Usage:\n" + " %s [fontfile [text]]\n" + "or:\n" + " %s [-h] [-f fontfile] [-t text]\n" + "\n" + " -h show this help message and exit;\n" + " -t text the text string to be rendered; \n" + " -f fontfile the font file (e.g. /Library/Fonts/Microsoft/Verdana.ttf)\n" + "\n", name, name); + + free(p); +} + +int +main (int argc, char** argv) +{ + /* Process received parameters */ +# include "default-text.h" + const char *text = NULL; + const char *font_path = NULL; + char arg; + while ((arg = getopt(argc, argv, "t:f:h")) != -1) { + switch (arg) { + case 't': + text = optarg; + break; + case 'f': + font_path = optarg; + break; + case 'h': + show_usage(argv[0]); + return 0; + default: + return 1; + } + } + if (!font_path) + { + if (optind < argc) + font_path = argv[optind++]; + } + if (!text) + { + if (optind < argc) + text = argv[optind++]; + else + text = default_text; + } + if (!text || optind < argc) + { + show_usage(argv[0]); + return 1; + } + + /* Setup glut */ + glutInit (&argc, argv); + glutInitWindowSize (WINDOW_W, WINDOW_H); + glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_3_2_CORE_PROFILE); + int window = glutCreateWindow ("GLyphy Demo"); + printf("\nInitialized with Open GL version %s\n\n", glGetString(GL_VERSION)); + glutReshapeFunc (reshape_func); + glutDisplayFunc (display_func); + glutKeyboardFunc (keyboard_func); + glutSpecialFunc (special_func); + glutMouseFunc (mouse_func); + glutMotionFunc (motion_func); + + /* Setup glew */ + if (GLEW_OK != glewInit ()) + die ("Failed to initialize GL; something really broken"); + if (!glewIsSupported ("GL_VERSION_2_0")) + die ("OpenGL 2.0 not supported"); + + st = demo_glstate_create (); + vu = demo_view_create (st); + demo_view_print_help (vu); + + FT_Library ft_library; + FT_Init_FreeType (&ft_library); + FT_Face ft_face = NULL; + if (font_path) + { + FT_New_Face (ft_library, font_path, 0/*face_index*/, &ft_face); + } + else + { +#ifdef _WIN32 + FT_New_Face(ft_library, "C:\\Windows\\Fonts\\calibri.ttf", 0/*face_index*/, &ft_face); +#else + #include "default-font.h" + FT_New_Memory_Face (ft_library, (const FT_Byte *) default_font, sizeof (default_font), 0/*face_index*/, &ft_face); +#endif + } + if (!ft_face) + die ("Failed to open font file"); + demo_font_t *font = demo_font_create (ft_face, demo_glstate_get_atlas (st)); + + buffer = demo_buffer_create (); + glyphy_point_t top_left = {0, 0}; + demo_buffer_move_to (buffer, &top_left); + demo_buffer_add_text (buffer, text, font, 1); + + demo_font_print_stats (font); + + demo_view_setup (vu); + glutMainLoop (); + + demo_buffer_destroy (buffer); + demo_font_destroy (font); + + FT_Done_Face (ft_face); + FT_Done_FreeType (ft_library); + + demo_view_destroy (vu); + demo_glstate_destroy (st); + + glutDestroyWindow (window); + + return 0; +} diff --git a/demo-gl3/glyphy-validate.cc b/demo-gl3/glyphy-validate.cc new file mode 100644 index 00000000..b89bed61 --- /dev/null +++ b/demo-gl3/glyphy-validate.cc @@ -0,0 +1,153 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Google Author(s): Behdad Esfahbod, Maysum Panju, Wojciech Baranowski + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#define TOLERANCE (1./2048) + +#include + +#include + +using namespace std; + +static inline void +die (const char *msg) +{ + fprintf (stderr, "%s\n", msg); + exit (1); +} + +static glyphy_bool_t +accumulate_endpoint (glyphy_arc_endpoint_t *endpoint, + vector *endpoints) +{ + endpoints->push_back (*endpoint); + return true; +} + +int +main (int argc, char** argv) +{ + bool verbose = false; + + if (argc > 1 && 0 == strcmp (argv[1], "--verbose")) { + verbose = true; + argc--; + argv++; + } + + if (argc == 1) { + fprintf (stderr, "Usage: %s FONT_FILE...\n", argv[0]); + exit (1); + } + + FT_Library ft_library; + FT_Init_FreeType (&ft_library); + + glyphy_arc_accumulator_t *acc = glyphy_arc_accumulator_create (); + + for (unsigned int arg = 1; (int) arg < argc; arg++) + { + const char *font_path = argv[arg]; + + unsigned int num_faces = 1; + for (unsigned int face_index = 0; face_index < num_faces; face_index++) + { + FT_Face ft_face = NULL; + FT_New_Face (ft_library, font_path, face_index, &ft_face); + if (!ft_face) + die ("Failed to open font file"); + /* FreeType's absurd. You have to open a ft_face to get the number of + * faces in the font file. */ + num_faces = ft_face->num_faces; + printf ("Opened %s face index %d. Has %d glyphs\n", + font_path, face_index, (int) ft_face->num_glyphs); + + for (unsigned int glyph_index = 0; glyph_index < ft_face->num_glyphs; glyph_index++) + { + char glyph_name[30]; + if (FT_Get_Glyph_Name (ft_face, glyph_index, glyph_name, sizeof (glyph_name))) + sprintf (glyph_name, "gid%u", glyph_index); + + printf ("Processing glyph %d (%s)\n", glyph_index, glyph_name); + + if (FT_Err_Ok != FT_Load_Glyph (ft_face, + glyph_index, + FT_LOAD_NO_BITMAP | + FT_LOAD_NO_HINTING | + FT_LOAD_NO_AUTOHINT | + FT_LOAD_NO_SCALE | + FT_LOAD_LINEAR_DESIGN | + FT_LOAD_IGNORE_TRANSFORM)) + die ("Failed loading FreeType glyph"); + + if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) + die ("FreeType loaded glyph format is not outline"); + + unsigned int upem = ft_face->units_per_EM; + double tolerance = upem * TOLERANCE; /* in font design units */ + vector endpoints; + + glyphy_arc_accumulator_reset (acc); + glyphy_arc_accumulator_set_tolerance (acc, tolerance); + glyphy_arc_accumulator_set_callback (acc, + (glyphy_arc_endpoint_accumulator_callback_t) accumulate_endpoint, + &endpoints); + + if (FT_Err_Ok != glyphy_freetype(outline_decompose) (&ft_face->glyph->outline, acc)) + die ("Failed converting glyph outline to arcs"); + + if (verbose) { + printf ("Arc list has %d endpoints\n", (int) endpoints.size ()); + for (unsigned int i = 0; i < endpoints.size (); i++) + printf ("Endpoint %d: p=(%g,%g),d=%g\n", i, endpoints[i].p.x, endpoints[i].p.y, endpoints[i].d); + } + + assert (glyphy_arc_accumulator_get_error (acc) <= tolerance); + +#if 0 + if (ft_face->glyph->outline.flags & FT_OUTLINE_EVEN_ODD_FILL) + glyphy_outline_winding_from_even_odd (&endpoints[0], endpoints.size (), false); +#endif + if (ft_face->glyph->outline.flags & FT_OUTLINE_REVERSE_FILL) + glyphy_outline_reverse (&endpoints[0], endpoints.size ()); + + if (glyphy_outline_winding_from_even_odd (&endpoints[0], endpoints.size (), false)) + { + fprintf (stderr, "ERROR: %s:%d: Glyph %d (%s) has contours with wrong direction\n", + font_path, face_index, glyph_index, glyph_name); + } + } + + FT_Done_Face (ft_face); + } + } + + glyphy_arc_accumulator_destroy (acc); + + FT_Done_FreeType (ft_library); + + return 0; +} diff --git a/demo-gl3/matrix4x4.c b/demo-gl3/matrix4x4.c new file mode 100644 index 00000000..bf679f72 --- /dev/null +++ b/demo-gl3/matrix4x4.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2009, Mozilla Corp + * Copyright (c) 2012, Google, Inc. + * 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 the 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 ''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 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. + */ + +/* + * Based on sample code from the OpenGL(R) ES 2.0 Programming Guide, which carriers + * the following header: + * + * Book: OpenGL(R) ES 2.0 Programming Guide + * Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner + * ISBN-10: 0321502795 + * ISBN-13: 9780321502797 + * Publisher: Addison-Wesley Professional + * URLs: http://safari.informit.com/9780321563835 + * http://www.opengles-book.com + */ + +/* + * Ported from JavaScript to C by Behdad Esfahbod, 2012. + * Added MultMatrix. Converting from fixed-function OpenGL matrix + * operations to these functions should be as simple as renaming the + * 'gl' prefix to 'm4' and adding the matrix argument to the call. + * + * The C version lives at http://code.google.com/p/matrix4x4-c/ + */ + +#include "matrix4x4.h" +#include + +/* + * A simple 4x4 matrix utility implementation + */ + + +float * +m4LoadIdentity (float *mat) { + unsigned int i; + for (i = 0; i < 16; i++) + mat[i] = 0; + mat[0*4+0] = 1.0; + mat[1*4+1] = 1.0; + mat[2*4+2] = 1.0; + mat[3*4+3] = 1.0; + return mat; +} + +/* Copies other matrix into mat */ +float * +m4Copy (float *mat, const float *other) { + unsigned int i; + for (i = 0; i < 16; i++) { + mat[i] = other[i]; + } + return mat; +} + +float * +m4Multiply (float *mat, const float *right) { + float tmp[16]; + unsigned int i; + + for (i = 0; i < 4; i++) { + tmp[i*4+0] = + (mat[i*4+0] * right[0*4+0]) + + (mat[i*4+1] * right[1*4+0]) + + (mat[i*4+2] * right[2*4+0]) + + (mat[i*4+3] * right[3*4+0]) ; + + tmp[i*4+1] = + (mat[i*4+0] * right[0*4+1]) + + (mat[i*4+1] * right[1*4+1]) + + (mat[i*4+2] * right[2*4+1]) + + (mat[i*4+3] * right[3*4+1]) ; + + tmp[i*4+2] = + (mat[i*4+0] * right[0*4+2]) + + (mat[i*4+1] * right[1*4+2]) + + (mat[i*4+2] * right[2*4+2]) + + (mat[i*4+3] * right[3*4+2]) ; + + tmp[i*4+3] = + (mat[i*4+0] * right[0*4+3]) + + (mat[i*4+1] * right[1*4+3]) + + (mat[i*4+2] * right[2*4+3]) + + (mat[i*4+3] * right[3*4+3]) ; + } + + return m4Copy (mat, tmp); +} + +float +m4Get (float *mat, unsigned int row, unsigned int col) { + return mat[4*row+col]; +} + +float * +m4MultMatrix (float *mat, const float *left) { + float tmp[16]; + return m4Copy (mat, m4Multiply (m4Copy (tmp, left), mat)); +} + +float * +m4Scale (float *mat, float sx, float sy, float sz) { + mat[0*4+0] *= sx; + mat[0*4+1] *= sx; + mat[0*4+2] *= sx; + mat[0*4+3] *= sx; + + mat[1*4+0] *= sy; + mat[1*4+1] *= sy; + mat[1*4+2] *= sy; + mat[1*4+3] *= sy; + + mat[2*4+0] *= sz; + mat[2*4+1] *= sz; + mat[2*4+2] *= sz; + mat[2*4+3] *= sz; + + return mat; +} + +float * +m4Translate (float *mat, float tx, float ty, float tz) { + mat[3*4+0] += mat[0*4+0] * tx + mat[1*4+0] * ty + mat[2*4+0] * tz; + mat[3*4+1] += mat[0*4+1] * tx + mat[1*4+1] * ty + mat[2*4+1] * tz; + mat[3*4+2] += mat[0*4+2] * tx + mat[1*4+2] * ty + mat[2*4+2] * tz; + mat[3*4+3] += mat[0*4+3] * tx + mat[1*4+3] * ty + mat[2*4+3] * tz; + + return mat; +} + +float * +m4Rotate (float *mat, float angle, float x, float y, float z) { + float mag = sqrt(x*x + y*y + z*z); + float sinAngle = sin(angle * M_PI / 180.0); + float cosAngle = cos(angle * M_PI / 180.0); + + float xx, yy, zz, xy, yz, zx, xs, ys, zs; + float oneMinusCos; + + float rotMat[16]; + + if (mag <= 0) + return mat; + + m4LoadIdentity (rotMat); + + x /= mag; + y /= mag; + z /= mag; + + xx = x * x; + yy = y * y; + zz = z * z; + xy = x * y; + yz = y * z; + zx = z * x; + xs = x * sinAngle; + ys = y * sinAngle; + zs = z * sinAngle; + oneMinusCos = 1.0 - cosAngle; + + rotMat[0*4+0] = (oneMinusCos * xx) + cosAngle; + rotMat[0*4+1] = (oneMinusCos * xy) - zs; + rotMat[0*4+2] = (oneMinusCos * zx) + ys; + rotMat[0*4+3] = 0.0; + + rotMat[1*4+0] = (oneMinusCos * xy) + zs; + rotMat[1*4+1] = (oneMinusCos * yy) + cosAngle; + rotMat[1*4+2] = (oneMinusCos * yz) - xs; + rotMat[1*4+3] = 0.0; + + rotMat[2*4+0] = (oneMinusCos * zx) - ys; + rotMat[2*4+1] = (oneMinusCos * yz) + xs; + rotMat[2*4+2] = (oneMinusCos * zz) + cosAngle; + rotMat[2*4+3] = 0.0; + + rotMat[3*4+0] = 0.0; + rotMat[3*4+1] = 0.0; + rotMat[3*4+2] = 0.0; + rotMat[3*4+3] = 1.0; + + return m4Copy (mat, m4Multiply (rotMat, mat)); +} + +float * +m4Frustum (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ) { + float deltaX = right - left; + float deltaY = top - bottom; + float deltaZ = farZ - nearZ; + + float frust[16]; + + if ( (nearZ <= 0.0) || (farZ <= 0.0) || + (deltaX <= 0.0) || (deltaY <= 0.0) || (deltaZ <= 0.0) ) + return mat; + + m4LoadIdentity (frust); + + frust[0*4+0] = 2.0 * nearZ / deltaX; + frust[0*4+1] = frust[0*4+2] = frust[0*4+3] = 0.0; + + frust[1*4+1] = 2.0 * nearZ / deltaY; + frust[1*4+0] = frust[1*4+2] = frust[1*4+3] = 0.0; + + frust[2*4+0] = (right + left) / deltaX; + frust[2*4+1] = (top + bottom) / deltaY; + frust[2*4+2] = -(nearZ + farZ) / deltaZ; + frust[2*4+3] = -1.0; + + frust[3*4+2] = -2.0 * nearZ * farZ / deltaZ; + frust[3*4+0] = frust[3*4+1] = frust[3*4+3] = 0.0; + + return m4Copy (mat, m4Multiply (frust, mat)); +} + +float * +m4Perspective (float *mat, float fovy, float aspect, float nearZ, float farZ) { + float frustumH = tan(fovy / 360.0 * M_PI) * nearZ; + float frustumW = frustumH * aspect; + + return m4Frustum(mat, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ); +} + +float * +m4Ortho (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ) { + float deltaX = right - left; + float deltaY = top - bottom; + float deltaZ = farZ - nearZ; + + float ortho[16]; + + if ( (deltaX == 0.0) || (deltaY == 0.0) || (deltaZ == 0.0) ) + return mat; + + m4LoadIdentity (ortho); + + ortho[0*4+0] = 2.0 / deltaX; + ortho[3*4+0] = -(right + left) / deltaX; + ortho[1*4+1] = 2.0 / deltaY; + ortho[3*4+1] = -(top + bottom) / deltaY; + ortho[2*4+2] = -2.0 / deltaZ; + ortho[3*4+2] = -(nearZ + farZ) / deltaZ; + + return m4Copy (mat, m4Multiply (ortho, mat)); +} + +/* In-place inversion */ +float * +m4Invert (float *mat) { + float tmp_0 = m4Get(mat,2,2) * m4Get(mat,3,3); + float tmp_1 = m4Get(mat,3,2) * m4Get(mat,2,3); + float tmp_2 = m4Get(mat,1,2) * m4Get(mat,3,3); + float tmp_3 = m4Get(mat,3,2) * m4Get(mat,1,3); + float tmp_4 = m4Get(mat,1,2) * m4Get(mat,2,3); + float tmp_5 = m4Get(mat,2,2) * m4Get(mat,1,3); + float tmp_6 = m4Get(mat,0,2) * m4Get(mat,3,3); + float tmp_7 = m4Get(mat,3,2) * m4Get(mat,0,3); + float tmp_8 = m4Get(mat,0,2) * m4Get(mat,2,3); + float tmp_9 = m4Get(mat,2,2) * m4Get(mat,0,3); + float tmp_10 = m4Get(mat,0,2) * m4Get(mat,1,3); + float tmp_11 = m4Get(mat,1,2) * m4Get(mat,0,3); + float tmp_12 = m4Get(mat,2,0) * m4Get(mat,3,1); + float tmp_13 = m4Get(mat,3,0) * m4Get(mat,2,1); + float tmp_14 = m4Get(mat,1,0) * m4Get(mat,3,1); + float tmp_15 = m4Get(mat,3,0) * m4Get(mat,1,1); + float tmp_16 = m4Get(mat,1,0) * m4Get(mat,2,1); + float tmp_17 = m4Get(mat,2,0) * m4Get(mat,1,1); + float tmp_18 = m4Get(mat,0,0) * m4Get(mat,3,1); + float tmp_19 = m4Get(mat,3,0) * m4Get(mat,0,1); + float tmp_20 = m4Get(mat,0,0) * m4Get(mat,2,1); + float tmp_21 = m4Get(mat,2,0) * m4Get(mat,0,1); + float tmp_22 = m4Get(mat,0,0) * m4Get(mat,1,1); + float tmp_23 = m4Get(mat,1,0) * m4Get(mat,0,1); + + float t0 = ((tmp_0 * m4Get(mat,1,1) + tmp_3 * m4Get(mat,2,1) + tmp_4 * m4Get(mat,3,1)) - + (tmp_1 * m4Get(mat,1,1) + tmp_2 * m4Get(mat,2,1) + tmp_5 * m4Get(mat,3,1))); + float t1 = ((tmp_1 * m4Get(mat,0,1) + tmp_6 * m4Get(mat,2,1) + tmp_9 * m4Get(mat,3,1)) - + (tmp_0 * m4Get(mat,0,1) + tmp_7 * m4Get(mat,2,1) + tmp_8 * m4Get(mat,3,1))); + float t2 = ((tmp_2 * m4Get(mat,0,1) + tmp_7 * m4Get(mat,1,1) + tmp_10 * m4Get(mat,3,1)) - + (tmp_3 * m4Get(mat,0,1) + tmp_6 * m4Get(mat,1,1) + tmp_11 * m4Get(mat,3,1))); + float t3 = ((tmp_5 * m4Get(mat,0,1) + tmp_8 * m4Get(mat,1,1) + tmp_11 * m4Get(mat,2,1)) - + (tmp_4 * m4Get(mat,0,1) + tmp_9 * m4Get(mat,1,1) + tmp_10 * m4Get(mat,2,1))); + + float d = 1.0 / (m4Get(mat,0,0) * t0 + m4Get(mat,1,0) * t1 + m4Get(mat,2,0) * t2 + m4Get(mat,3,0) * t3); + + float out_00 = d * t0; + float out_01 = d * t1; + float out_02 = d * t2; + float out_03 = d * t3; + + float out_10 = d * ((tmp_1 * m4Get(mat,1,0) + tmp_2 * m4Get(mat,2,0) + tmp_5 * m4Get(mat,3,0)) - + (tmp_0 * m4Get(mat,1,0) + tmp_3 * m4Get(mat,2,0) + tmp_4 * m4Get(mat,3,0))); + float out_11 = d * ((tmp_0 * m4Get(mat,0,0) + tmp_7 * m4Get(mat,2,0) + tmp_8 * m4Get(mat,3,0)) - + (tmp_1 * m4Get(mat,0,0) + tmp_6 * m4Get(mat,2,0) + tmp_9 * m4Get(mat,3,0))); + float out_12 = d * ((tmp_3 * m4Get(mat,0,0) + tmp_6 * m4Get(mat,1,0) + tmp_11 * m4Get(mat,3,0)) - + (tmp_2 * m4Get(mat,0,0) + tmp_7 * m4Get(mat,1,0) + tmp_10 * m4Get(mat,3,0))); + float out_13 = d * ((tmp_4 * m4Get(mat,0,0) + tmp_9 * m4Get(mat,1,0) + tmp_10 * m4Get(mat,2,0)) - + (tmp_5 * m4Get(mat,0,0) + tmp_8 * m4Get(mat,1,0) + tmp_11 * m4Get(mat,2,0))); + + float out_20 = d * ((tmp_12 * m4Get(mat,1,3) + tmp_15 * m4Get(mat,2,3) + tmp_16 * m4Get(mat,3,3)) - + (tmp_13 * m4Get(mat,1,3) + tmp_14 * m4Get(mat,2,3) + tmp_17 * m4Get(mat,3,3))); + float out_21 = d * ((tmp_13 * m4Get(mat,0,3) + tmp_18 * m4Get(mat,2,3) + tmp_21 * m4Get(mat,3,3)) - + (tmp_12 * m4Get(mat,0,3) + tmp_19 * m4Get(mat,2,3) + tmp_20 * m4Get(mat,3,3))); + float out_22 = d * ((tmp_14 * m4Get(mat,0,3) + tmp_19 * m4Get(mat,1,3) + tmp_22 * m4Get(mat,3,3)) - + (tmp_15 * m4Get(mat,0,3) + tmp_18 * m4Get(mat,1,3) + tmp_23 * m4Get(mat,3,3))); + float out_23 = d * ((tmp_17 * m4Get(mat,0,3) + tmp_20 * m4Get(mat,1,3) + tmp_23 * m4Get(mat,2,3)) - + (tmp_16 * m4Get(mat,0,3) + tmp_21 * m4Get(mat,1,3) + tmp_22 * m4Get(mat,2,3))); + + float out_30 = d * ((tmp_14 * m4Get(mat,2,2) + tmp_17 * m4Get(mat,3,2) + tmp_13 * m4Get(mat,1,2)) - + (tmp_16 * m4Get(mat,3,2) + tmp_12 * m4Get(mat,1,2) + tmp_15 * m4Get(mat,2,2))); + float out_31 = d * ((tmp_20 * m4Get(mat,3,2) + tmp_12 * m4Get(mat,0,2) + tmp_19 * m4Get(mat,2,2)) - + (tmp_18 * m4Get(mat,2,2) + tmp_21 * m4Get(mat,3,2) + tmp_13 * m4Get(mat,0,2))); + float out_32 = d * ((tmp_18 * m4Get(mat,1,2) + tmp_23 * m4Get(mat,3,2) + tmp_15 * m4Get(mat,0,2)) - + (tmp_22 * m4Get(mat,3,2) + tmp_14 * m4Get(mat,0,2) + tmp_19 * m4Get(mat,1,2))); + float out_33 = d * ((tmp_22 * m4Get(mat,2,2) + tmp_16 * m4Get(mat,0,2) + tmp_21 * m4Get(mat,1,2)) - + (tmp_20 * m4Get(mat,1,2) + tmp_23 * m4Get(mat,2,2) + tmp_17 * m4Get(mat,0,2))); + + mat[0*4+0] = out_00; + mat[0*4+1] = out_01; + mat[0*4+2] = out_02; + mat[0*4+3] = out_03; + mat[1*4+0] = out_10; + mat[1*4+1] = out_11; + mat[1*4+2] = out_12; + mat[1*4+3] = out_13; + mat[2*4+0] = out_20; + mat[2*4+1] = out_21; + mat[2*4+2] = out_22; + mat[2*4+3] = out_23; + mat[3*4+0] = out_30; + mat[3*4+1] = out_31; + mat[3*4+2] = out_32; + mat[3*4+3] = out_33; + return mat; +} + +/* Puts the inverse of other matrix into mat */ +float * +m4Inverse (float *mat, const float *other) { + m4Copy (mat, other); + m4Invert (mat); + return mat; +} + +/* In-place transpose */ +float * +m4Transpose (float *mat) { + float tmp = mat[0*4+1]; + mat[0*4+1] = mat[1*4+0]; + mat[1*4+0] = tmp; + + tmp = mat[0*4+2]; + mat[0*4+2] = mat[2*4+0]; + mat[2*4+0] = tmp; + + tmp = mat[0*4+3]; + mat[0*4+3] = mat[3*4+0]; + mat[3*4+0] = tmp; + + tmp = mat[1*4+2]; + mat[1*4+2] = mat[2*4+1]; + mat[2*4+1] = tmp; + + tmp = mat[1*4+3]; + mat[1*4+3] = mat[3*4+1]; + mat[3*4+1] = tmp; + + tmp = mat[2*4+3]; + mat[2*4+3] = mat[3*4+2]; + mat[3*4+2] = tmp; + + return mat; +} diff --git a/demo-gl3/matrix4x4.h b/demo-gl3/matrix4x4.h new file mode 100644 index 00000000..bc2a1c19 --- /dev/null +++ b/demo-gl3/matrix4x4.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2009, Mozilla Corp + * Copyright (c) 2012, Google, Inc. + * 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 the 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 ''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 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. + */ + +/* + * Based on sample code from the OpenGL(R) ES 2.0 Programming Guide, which carriers + * the following header: + * + * Book: OpenGL(R) ES 2.0 Programming Guide + * Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner + * ISBN-10: 0321502795 + * ISBN-13: 9780321502797 + * Publisher: Addison-Wesley Professional + * URLs: http://safari.informit.com/9780321563835 + * http://www.opengles-book.com + */ + +/* + * Ported from JavaScript to C by Behdad Esfahbod, 2012. + * Added MultMatrix. Converting from fixed-function OpenGL matrix + * operations to these functions should be as simple as renaming the + * 'gl' prefix to 'm4' and adding the matrix argument to the call. + * + * The C version lives at http://code.google.com/p/matrix4x4-c/ + */ + +/* + * A simple 4x4 matrix utility implementation + */ + +#ifndef MATRIX4x4_H +#define MATRIX4x4_H + +/* Copies other matrix into mat */ +float * +m4Copy (float *mat, const float *other); + +float * +m4Multiply (float *mat, const float *right); + +float * +m4MultMatrix (float *mat, const float *left); + +float +m4Get (float *mat, unsigned int row, unsigned int col); + +float * +m4Scale (float *mat, float sx, float sy, float sz); + +float * +m4Translate (float *mat, float tx, float ty, float tz); + +float * +m4Rotate (float *mat, float angle, float x, float y, float z); + +float * +m4Frustum (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ); + +float * +m4Perspective (float *mat, float fovy, float aspect, float nearZ, float farZ); + +float * +m4Ortho (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ); + +/* In-place inversion */ +float * +m4Invert (float *mat); + +/* Puts the inverse of other matrix into mat */ +float * +m4Inverse (float *mat, const float *other); + +/* In-place transpose */ +float * +m4Transpose (float *mat); + +float * +m4LoadIdentity (float *mat); + +#endif diff --git a/demo-gl3/trackball.c b/demo-gl3/trackball.c new file mode 100644 index 00000000..bea4baee --- /dev/null +++ b/demo-gl3/trackball.c @@ -0,0 +1,337 @@ +#include +/* + * (c) Copyright 1993, 1994, Silicon Graphics, Inc. + * ALL RIGHTS RESERVED + * Permission to use, copy, modify, and distribute this software for + * any purpose and without fee is hereby granted, provided that the above + * copyright notice appear in all copies and that both the copyright notice + * and this permission notice appear in supporting documentation, and that + * the name of Silicon Graphics, Inc. not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" + * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, + * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY + * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, + * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF + * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN + * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE + * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer Software + * clause at DFARS 252.227-7013 and/or in similar or successor + * clauses in the FAR or the DOD or NASA FAR Supplement. + * Unpublished-- rights reserved under the copyright laws of the + * United States. Contractor/manufacturer is Silicon Graphics, + * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ +/* + * Trackball code: + * + * Implementation of a virtual trackball. + * Implemented by Gavin Bell, lots of ideas from Thant Tessman and + * the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129. + * + * Vector manip code: + * + * Original code from: + * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli + * + * Much mucking with by: + * Gavin Bell + */ +#if defined(_WIN32) +#pragma warning (disable:4244) /* disable bogus conversion warnings */ +#endif +#include +#include "trackball.h" + +/* + * This size should really be based on the distance from the center of + * rotation to the point on the object underneath the mouse. That + * point would then track the mouse as closely as possible. This is a + * simple example, though, so that is left as an Exercise for the + * Programmer. + */ +#define TRACKBALLSIZE (0.5f) + +/* + * Local function prototypes (not defined in trackball.h) + */ +static float tb_project_to_sphere(float, float, float); +static void normalize_quat(float [4]); + +void +vzero(float *v) +{ + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; +} + +void +vset(float *v, float x, float y, float z) +{ + v[0] = x; + v[1] = y; + v[2] = z; +} + +void +vsub(const float *src1, const float *src2, float *dst) +{ + dst[0] = src1[0] - src2[0]; + dst[1] = src1[1] - src2[1]; + dst[2] = src1[2] - src2[2]; +} + +void +vcopy(const float *v1, float *v2) +{ + register int i; + for (i = 0 ; i < 3 ; i++) + v2[i] = v1[i]; +} + +void +vcross(const float *v1, const float *v2, float *cross) +{ + float temp[3]; + + temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); + temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); + temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); + vcopy(temp, cross); +} + +float +vlength(const float *v) +{ + return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); +} + +void +vscale(float *v, float div) +{ + v[0] *= div; + v[1] *= div; + v[2] *= div; +} + +void +vnormal(float *v) +{ + vscale(v,1.0/vlength(v)); +} + +float +vdot(const float *v1, const float *v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void +vadd(const float *src1, const float *src2, float *dst) +{ + dst[0] = src1[0] + src2[0]; + dst[1] = src1[1] + src2[1]; + dst[2] = src1[2] + src2[2]; +} + +/* + * Ok, simulate a track-ball. Project the points onto the virtual + * trackball, then figure out the axis of rotation, which is the cross + * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) + * Note: This is a deformed trackball-- is a trackball in the center, + * but is deformed into a hyperbolic sheet of rotation away from the + * center. This particular function was chosen after trying out + * several variations. + * + * It is assumed that the arguments to this routine are in the range + * (-1.0 ... 1.0) + */ +void +trackball(float q[4], float p1x, float p1y, float p2x, float p2y) +{ + float a[3]; /* Axis of rotation */ + float phi; /* how much to rotate about axis */ + float p1[3], p2[3], d[3]; + float t; + + if (p1x == p2x && p1y == p2y) { + /* Zero rotation */ + vzero(q); + q[3] = 1.0; + return; + } + + /* + * First, figure out z-coordinates for projection of P1 and P2 to + * deformed sphere + */ + vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y)); + vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y)); + + /* + * Now, we want the cross product of P1 and P2 + */ + vcross(p2,p1,a); + + /* + * Figure out how much to rotate around that axis. + */ + vsub(p1,p2,d); + t = vlength(d) / (2.0*TRACKBALLSIZE); + + /* + * Avoid problems with out-of-control values... + */ + if (t > 1.0) t = 1.0; + if (t < -1.0) t = -1.0; + phi = 2.0 * asin(t); + + axis_to_quat(a,phi,q); +} + +/* + * Given an axis and angle, compute quaternion. + */ +void +axis_to_quat(float a[3], float phi, float q[4]) +{ + vcopy(a,q); + vnormal(q); + vscale(q,sin(phi/2.0)); + q[3] = cos(phi/2.0); +} + +/* + * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet + * if we are away from the center of the sphere. + */ +static float +tb_project_to_sphere(float r, float x, float y) +{ + float d, t, z; + + d = sqrt(x*x + y*y); + if (d < r * 0.70710678118654752440) { /* Inside sphere */ + z = sqrt(r*r - d*d); + } else { /* On hyperbola */ + t = r / 1.41421356237309504880; + z = t*t / d; + } + return z; +} + +/* + * Given two rotations, e1 and e2, expressed as quaternion rotations, + * figure out the equivalent single rotation and stuff it into dest. + * + * This routine also normalizes the result every RENORMCOUNT times it is + * called, to keep error from creeping in. + * + * NOTE: This routine is written so that q1 or q2 may be the same + * as dest (or each other). + */ + +#define RENORMCOUNT 97 + +void +add_quats(float q1[4], float q2[4], float dest[4]) +{ + static int count=0; + float t1[4], t2[4], t3[4]; + float tf[4]; + +#if 0 +printf("q1 = %f %f %f %f\n", q1[0], q1[1], q1[2], q1[3]); +printf("q2 = %f %f %f %f\n", q2[0], q2[1], q2[2], q2[3]); +#endif + + vcopy(q1,t1); + vscale(t1,q2[3]); + + vcopy(q2,t2); + vscale(t2,q1[3]); + + vcross(q2,q1,t3); + vadd(t1,t2,tf); + vadd(t3,tf,tf); + tf[3] = q1[3] * q2[3] - vdot(q1,q2); + +#if 0 +printf("tf = %f %f %f %f\n", tf[0], tf[1], tf[2], tf[3]); +#endif + + dest[0] = tf[0]; + dest[1] = tf[1]; + dest[2] = tf[2]; + dest[3] = tf[3]; + + if (++count > RENORMCOUNT) { + count = 0; + normalize_quat(dest); + } +} + +/* + * Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0 + * If they don't add up to 1.0, dividing by their magnitued will + * renormalize them. + * + * Note: See the following for more information on quaternions: + * + * - Shoemake, K., Animating rotation with quaternion curves, Computer + * Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985. + * - Pletinckx, D., Quaternion calculus as a basic tool in computer + * graphics, The Visual Computer 5, 2-13, 1989. + */ +static void +normalize_quat(float q[4]) +{ + int i; + float mag; + + mag = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]); + for (i = 0; i < 4; i++) q[i] /= mag; +} + +/* + * Build a rotation matrix, given a quaternion rotation. + * + */ +void +build_rotmatrix(float m[4][4], float q[4]) +{ + m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]); + m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]); + m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]); + m[0][3] = 0.0; + + m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]); + m[1][1]= 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]); + m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]); + m[1][3] = 0.0; + + m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]); + m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]); + m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]); + m[2][3] = 0.0; + + m[3][0] = 0.0; + m[3][1] = 0.0; + m[3][2] = 0.0; + m[3][3] = 1.0; +} + diff --git a/demo-gl3/trackball.h b/demo-gl3/trackball.h new file mode 100644 index 00000000..990c5286 --- /dev/null +++ b/demo-gl3/trackball.h @@ -0,0 +1,109 @@ +/* + * (c) Copyright 1993, 1994, Silicon Graphics, Inc. + * ALL RIGHTS RESERVED + * Permission to use, copy, modify, and distribute this software for + * any purpose and without fee is hereby granted, provided that the above + * copyright notice appear in all copies and that both the copyright notice + * and this permission notice appear in supporting documentation, and that + * the name of Silicon Graphics, Inc. not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" + * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, + * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY + * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, + * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF + * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN + * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE + * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer Software + * clause at DFARS 252.227-7013 and/or in similar or successor + * clauses in the FAR or the DOD or NASA FAR Supplement. + * Unpublished-- rights reserved under the copyright laws of the + * United States. Contractor/manufacturer is Silicon Graphics, + * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ +/* + * trackball.h + * A virtual trackball implementation + * Written by Gavin Bell for Silicon Graphics, November 1988. + */ + +void +vzero(float *v); + +void +vset(float *v, float x, float y, float z); + +void +vsub(const float *src1, const float *src2, float *dst); + +void +vcopy(const float *v1, float *v2); + +void +vcross(const float *v1, const float *v2, float *cross); + +float +vlength(const float *v); + +void +vscale(float *v, float div); + +void +vnormal(float *v); + +float +vdot(const float *v1, const float *v2); + +void +vadd(const float *src1, const float *src2, float *dst); + + +/* + * Pass the x and y coordinates of the last and current positions of + * the mouse, scaled so they are from (-1.0 ... 1.0). + * + * The resulting rotation is returned as a quaternion rotation in the + * first paramater. + */ +void +trackball(float q[4], float p1x, float p1y, float p2x, float p2y); + +/* + * Given two quaternions, add them together to get a third quaternion. + * Adding quaternions to get a compound rotation is analagous to adding + * translations to get a compound translation. When incrementally + * adding rotations, the first argument here should be the new + * rotation, the second and third the total rotation (which will be + * over-written with the resulting new total rotation). + */ +void +add_quats(float *q1, float *q2, float *dest); + +/* + * A useful function, builds a rotation matrix in Matrix based on + * given quaternion. + */ +void +build_rotmatrix(float m[4][4], float q[4]); + +/* + * This function computes a quaternion based on an axis (defined by + * the given vector) and an angle about which to rotate. The angle is + * expressed in radians. The result is put into the third argument. + */ +void +axis_to_quat(float a[3], float phi, float q[4]); + diff --git a/demo/default-text.h b/demo/default-text.h deleted file mode 100644 index b28e1286..00000000 --- a/demo/default-text.h +++ /dev/null @@ -1,71 +0,0 @@ -static const char default_text[] = -"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam tincidunt nibh quis semper malesuada. Mauris sit amet metus sed tellus gravida\n" -"maximus sit amet a enim. Morbi et lorem congue, aliquam lorem vitae, condimentum erat. Mauris aliquet, sapien consequat blandit mattis, velit ante\n" -"molestie mi, ac condimentum justo leo sed odio. Curabitur at suscipit quam. Ut ac convallis ante, at sollicitudin sapien. Nulla pellentesque felis\n" -"id mi blandit dictum. Phasellus ultrices, odio non volutpat tincidunt, neque quam tristique lacus, nec gravida nulla ante id risus. Nulla sit amet\n" -"bibendum lectus, sed bibendum lectus. Vivamus ultrices metus sit amet sapien posuere volutpat. Suspendisse luctus non mauris nec iaculis. Duis\n" -"mattis enim libero, ac malesuada tortor gravida tempor. Cras sagittis felis at sollicitudin fermentum. Duis et ipsum bibendum, viverra felis quis,\n" -"consectetur lacus. Donec vulputate risus imperdiet, tincidunt purus nec, vestibulum lorem. Morbi iaculis tincidunt rutrum. Duis sit amet nulla\n" -"ut lectus efficitur suscipit. Curabitur urna turpis, congue lacinia varius vitae, interdum vel dolor. Vestibulum sit amet suscipit arcu, sit amet\n" -"tincidunt ipsum. Maecenas feugiat ante vel fermentum viverra. Sed aliquam sem ac quam bibendum, sit amet fringilla augue pharetra. Morbi scelerisque\n" -"tempus purus, interdum tempor est pulvinar bibendum. Duis tincidunt dictum ante vel sodales. Fusce quis cursus metus. Pellentesque mi mauris,\n" -"tincidunt ut orci ut, interdum dapibus dolor. Aliquam blandit, nisl et rhoncus laoreet, tellus nulla blandit tellus, sit amet cursus magna enim nec\n" -"ante. Integer venenatis a est sed hendrerit. Proin id porttitor turpis, aliquam tempus ex. Morbi tristique, felis ut aliquet luctus, orci tortor\n" -"sodales sem, vel imperdiet justo tortor sit amet arcu. Quisque ipsum sem, lacinia in fermentum eu, maximus in lectus. Pellentesque quis scelerisque\n" -"neque, eget ultricies ligula. Etiam accumsan orci mi, ut blandit nibh viverra quis. Pellentesque tincidunt auctor dictum. Integer tincidunt neque\n" -"at enim ultrices, in accumsan augue elementum. Sed placerat eros leo, ac venenatis metus dignissim vel. Suspendisse mauris sem, pulvinar id purus\n" -"non, hendrerit pretium sem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla accumsan massa id nulla\n" -"viverra semper. Aliquam sit amet neque vitae diam rhoncus feugiat. Etiam tellus purus, rhoncus id enim a, fermentum volutpat neque. Vestibulum\n" -"tortor augue, dapibus at varius sed, varius at nisl. Ut pharetra elementum varius. Nulla molestie, urna sit amet euismod venenatis, nunc magna\n" -"bibendum augue, vitae elementum augue elit eget urna. Morbi a leo at sapien tempor varius sit amet venenatis metus. Sed ac pellentesque turpis,\n" -"quis malesuada ligula. Cras quis ex mattis, ultricies nibh ac, vestibulum velit. Sed sed sagittis libero, at consectetur massa. Cras quis risus\n" -"nunc. Curabitur vitae odio laoreet, sodales sem eu, fermentum risus. Quisque laoreet felis eu mattis laoreet. Phasellus auctor velit ut varius\n" -"accumsan. Sed molestie bibendum mi varius auctor. Vestibulum iaculis, lacus ut mattis convallis, turpis purus cursus nibh, nec ullamcorper dolor nibh\n" -"eget nunc. Nam lacinia justo ac vestibulum lacinia. Nulla vestibulum eu urna a sodales. Aliquam blandit congue lacus vitae ornare. Nulla bibendum\n" -"vehicula tortor eu vestibulum. Mauris nec pretium est. Pellentesque faucibus quam et est sollicitudin, quis condimentum justo placerat. Etiam urna\n" -"elit, porttitor sodales dui congue, maximus sodales dolor. Proin lacinia diam quis libero molestie viverra. Pellentesque tortor mauris, sodales\n" -"vel luctus non, euismod eu risus. Nulla sed condimentum ex. Morbi ac mi quis felis laoreet mattis. Fusce nec quam orci. Morbi pretium quis risus\n" -"a tincidunt. Phasellus accumsan suscipit nisi sed viverra. Vestibulum eu vulputate lorem. Nullam fermentum turpis eget nulla rutrum egestas. Sed\n" -"tortor nisi, consectetur a semper ut, lacinia in lectus. Phasellus finibus at diam nec interdum. Nunc mollis congue enim, et tempor neque dapibus\n" -"quis. Nunc a egestas quam, vitae tempor mi. Sed at lobortis neque. Pellentesque habitant morbi tristique senectus et netus et malesuada fames\n" -"ac turpis egestas. Etiam blandit mi sit amet ipsum accumsan, eget euismod nulla facilisis. Morbi imperdiet ex massa, in porttitor nibh posuere\n" -"ut. Curabitur bibendum lorem id ultricies placerat. Aenean tincidunt malesuada mauris, sit amet rhoncus odio ornare ac. Morbi venenatis turpis\n" -"non nulla tincidunt, bibendum tincidunt quam ultricies. Donec dictum, lorem eget commodo malesuada, risus nisi ornare augue, feugiat accumsan\n" -"dui massa eu ipsum. Mauris aliquam sapien id felis faucibus ornare. Nullam eleifend felis vel metus rutrum mollis. Quisque posuere eros vitae\n" -"imperdiet dapibus. Suspendisse quis est laoreet, faucibus lectus at, mattis est. Vestibulum nec neque ut ante auctor luctus. Nunc posuere vulputate\n" -"egestas. Quisque sit amet sodales erat, ac suscipit lorem. Ut auctor dapibus efficitur. Phasellus tincidunt cursus neque in ultrices. Sed pretium\n" -"viverra felis vitae aliquet. Vivamus at quam libero. Phasellus mattis orci ut egestas finibus. Suspendisse mattis maximus consequat. Ut id aliquam\n" -"lectus. Maecenas ut libero in nulla tempus accumsan at at tellus. Quisque a nibh quis ligula pharetra vehicula id et ante. Pellentesque et nisl in\n" -"lectus commodo sollicitudin non quis lectus. Vestibulum varius leo at diam fringilla, nec vulputate diam pellentesque. Curabitur id nisl in nibh\n" -"sollicitudin vestibulum non sit amet odio. Nunc pulvinar lectus ac est sagittis mollis. Nunc vel consectetur nulla, sit amet eleifend elit. Etiam\n" -"volutpat, ligula id cursus posuere, est lacus sagittis purus, scelerisque tempus sem lectus tempor nisi. Curabitur scelerisque leo et neque\n" -"ultricies semper. Sed in efficitur urna. Aliquam tempus cursus tortor. Sed feugiat mi elit, id ullamcorper nulla ullamcorper vitae. Suspendisse\n" -"rutrum ornare orci, eget facilisis nisi ornare et. Aenean sed leo vitae lorem congue lobortis. Nunc vel dui condimentum, sagittis sapien ac,\n" -"ultricies odio. Suspendisse elementum iaculis commodo. Phasellus pellentesque purus nec nisl pretium eleifend. Suspendisse a imperdiet urna. Fusce\n" -"eleifend et nunc at elementum. Morbi imperdiet varius mattis. Cras pharetra urna nulla, gravida sodales orci blandit et. Nulla dignissim eleifend\n" -"tempus. Vivamus placerat tristique purus et facilisis. In eget maximus urna. Mauris ut commodo elit. Aliquam erat volutpat. Donec efficitur augue\n" -"vitae nisi suscipit, vel aliquet sem posuere. Ut placerat ullamcorper lorem, eget consequat nunc ultricies nec. Nulla scelerisque ex non velit\n" -"efficitur imperdiet. Aliquam faucibus augue vel rhoncus feugiat. Aenean hendrerit nunc sem, ac hendrerit tortor fringilla sed. Morbi lorem massa,\n" -"dictum at maximus vitae, dictum et mi. Nullam ante elit, ultrices tincidunt tempor quis, aliquam ut lacus. Donec ut aliquet purus. Sed dolor mi,\n" -"rhoncus auctor tristique ac, lobortis non urna. Sed tempor leo ut finibus mattis. Aenean fermentum augue eget nisi aliquet feugiat. Donec convallis\n" -"laoreet nulla id malesuada. Vestibulum in congue enim, non sagittis massa. Ut et euismod nibh, eu euismod leo. Class aptent taciti sociosqu ad litora\n" -"torquent per conubia nostra, per inceptos himenaeos. Cras sodales purus nec ligula egestas cursus. Sed gravida, elit non eleifend semper, ex erat\n" -"ultricies augue, nec suscipit velit metus in augue. Nulla dapibus, ante a aliquam cursus, mi purus lobortis purus, sit amet feugiat neque sapien\n" -"at mauris. Vivamus mattis sagittis purus, quis viverra dolor mollis nec. Pellentesque habitant morbi tristique senectus et netus et malesuada fames\n" -"ac turpis egestas. Fusce in semper justo, eget mattis magna. Donec libero augue, aliquam eget mi at, laoreet sodales metus. Etiam gravida, libero\n" -"eu pellentesque imperdiet, nulla dolor scelerisque tortor, vitae placerat est risus non metus. Etiam vel laoreet est. Ut posuere turpis facilisis,\n" -"faucibus magna nec, ornare augue. Pellentesque auctor feugiat ornare. Etiam vulputate vitae odio et lacinia. Aenean semper purus vitae erat tincidunt\n" -"volutpat. Sed et laoreet nulla, eu condimentum arcu. Maecenas magna arcu, condimentum ut elementum vitae, laoreet sed justo. Maecenas bibendum\n" -"lacus vel blandit tincidunt. Praesent mattis, eros eget auctor malesuada, felis ligula egestas eros, at lacinia dolor lacus sed arcu. Praesent\n" -"lectus lacus, rhoncus ultricies facilisis vel, tristique pellentesque eros. Donec et justo placerat, finibus lectus id, mattis augue. Nam\n" -"consequat, felis a commodo varius, odio erat viverra urna, mollis sodales nibh lectus non turpis. Maecenas quis egestas risus, eget lobortis\n" -"dui. Sed pellentesque vitae neque non condimentum. Proin eu maximus magna, ac posuere libero. Maecenas porta interdum metus eu hendrerit. Integer\n" -"ut blandit risus. Maecenas facilisis consectetur dolor a mattis. Morbi elementum tincidunt turpis, vel tempus est mattis vel. Morbi et ultrices\n" -"velit, at dapibus neque. Vestibulum dictum in mi et rhoncus. In congue, elit vel ultricies maximus, arcu augue venenatis neque, sed imperdiet purus\n" -"leo et risus. Quisque tincidunt sapien felis, vitae elementum erat aliquet in. Curabitur mauris nibh, dictum sollicitudin dolor ut, accumsan luctus\n" -"nulla. Aenean quis diam quam. Etiam viverra odio at felis tincidunt laoreet. Proin euismod non lectus sit amet lacinia. Proin aliquet mauris et dui\n" -"consectetur sagittis. Ut tempus fringilla odio, vitae scelerisque neque efficitur ut. Quisque a nulla pulvinar, varius dolor sed, eleifend magna.\n" -"Vivamus eu neque pulvinar, accumsan odio venenatis, mollis leo. Morbi aliquet ac dolor sed lobortis. Maecenas urna sapien, volutpat non sagittis in,\n" -"tempor eget enim. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed mollis porta lectus, id lobortis metus elementum vitae. Nullam\n" -"non nulla sed risus rhoncus tempor. Nullam id quam hendrerit, dictum purus ut, maximus ipsum. Cras auct\n" -;