├── .gitignore ├── Makefile.am ├── autogen.sh ├── configure.ac ├── esTransform.c ├── esUtil.h └── kmscube.c /.gitignore: -------------------------------------------------------------------------------- 1 | aclocal.m4 2 | autom4te.cache 3 | Makefile.in 4 | Makefile 5 | .deps 6 | .libs 7 | *.o 8 | *.lo 9 | *.la 10 | libtool 11 | *.pc 12 | config.log 13 | config.status 14 | config.guess 15 | config.h 16 | config.h.in 17 | config.sub 18 | config 19 | configure 20 | install-sh 21 | ltmain.sh 22 | missing 23 | stamp-h1 24 | depcomp 25 | .cproject 26 | .project 27 | .settings 28 | kmscube 29 | tags 30 | TAGS 31 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2012 Rob Clark 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a 5 | # copy of this software and associated documentation files (the "Software"), 6 | # to deal in the Software without restriction, including without limitation 7 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | # and/or sell copies of the Software, and to permit persons to whom the 9 | # Software is furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice (including the next 12 | # paragraph) shall be included in all copies or substantial portions of the 13 | # Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | 24 | bin_PROGRAMS = kmscube 25 | 26 | kmscube_LDFLAGS = \ 27 | -no-undefined 28 | 29 | kmscube_LDADD = \ 30 | $(DRM_LIBS) \ 31 | $(GBM_LIBS) \ 32 | $(EGL_LIBS) \ 33 | $(GL_LIBS) 34 | 35 | kmscube_CFLAGS = \ 36 | -O0 -g -lm \ 37 | $(DRM_CFLAGS) \ 38 | $(GBM_CFLAGS) \ 39 | $(EGL_CFLAGS) \ 40 | $(GL_CFLAGS) 41 | 42 | kmscube_SOURCES = \ 43 | kmscube.c \ 44 | esTransform.c 45 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | srcdir=`dirname $0` 4 | test -z "$srcdir" && srcdir=. 5 | 6 | ORIGDIR=`pwd` 7 | cd $srcdir 8 | 9 | mkdir -p m4 10 | autoreconf -v --install || exit 1 11 | cd $ORIGDIR || exit $? 12 | 13 | $srcdir/configure --enable-maintainer-mode "$@" 14 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2012 Rob Clark 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a 5 | # copy of this software and associated documentation files (the "Software"), 6 | # to deal in the Software without restriction, including without limitation 7 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | # and/or sell copies of the Software, and to permit persons to whom the 9 | # Software is furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice (including the next 12 | # paragraph) shall be included in all copies or substantial portions of the 13 | # Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | 24 | # Initialize Autoconf 25 | AC_PREREQ([2.60]) 26 | AC_INIT([kmscube], [0.0.1], [https://github.com/robclark/kmscube/], [kmscube]) 27 | AC_CONFIG_SRCDIR([Makefile.am]) 28 | AC_CONFIG_HEADERS([config.h]) 29 | AC_CONFIG_AUX_DIR([build-aux]) 30 | AC_CONFIG_MACRO_DIR([m4]) 31 | 32 | # Initialize Automake 33 | AM_INIT_AUTOMAKE([foreign dist-bzip2]) 34 | AM_MAINTAINER_MODE 35 | 36 | # Enable quiet compiles on automake 1.11. 37 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 38 | 39 | # Initialize libtool 40 | AC_PROG_LIBTOOL 41 | 42 | # Obtain compiler/linker options for depedencies 43 | PKG_CHECK_MODULES(DRM, libdrm) 44 | PKG_CHECK_MODULES(GBM, gbm) 45 | PKG_CHECK_MODULES(EGL, egl) 46 | PKG_CHECK_MODULES(GLES2, glesv2) 47 | PKG_CHECK_MODULES(GL, gl) 48 | 49 | dnl =========================================================================== 50 | dnl check compiler flags 51 | AC_DEFUN([LIBDRM_CC_TRY_FLAG], [ 52 | AC_MSG_CHECKING([whether $CC supports $1]) 53 | 54 | libdrm_save_CFLAGS="$CFLAGS" 55 | CFLAGS="$CFLAGS $1" 56 | 57 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[]])], 58 | [libdrm_cc_flag=yes], 59 | [libdrm_cc_flag=no]) 60 | CFLAGS="$libdrm_save_CFLAGS" 61 | 62 | if test "x$libdrm_cc_flag" = "xyes"; then 63 | ifelse([$2], , :, [$2]) 64 | else 65 | ifelse([$3], , :, [$3]) 66 | fi 67 | AC_MSG_RESULT([$libdrm_cc_flag]) 68 | ]) 69 | 70 | MAYBE_WARN="-Wall -Wextra -Wno-packed-bitfield-compat \ 71 | -Wsign-compare -Werror-implicit-function-declaration \ 72 | -Wpointer-arith -Wwrite-strings -Wstrict-prototypes \ 73 | -Wnested-externs \ 74 | -Wpacked -Wswitch-enum -Wmissing-format-attribute \ 75 | -Wstrict-aliasing=2 -Winit-self -Wunsafe-loop-optimizations \ 76 | -Wdeclaration-after-statement -Wold-style-definition \ 77 | -Wno-missing-field-initializers -Wno-unused-parameter \ 78 | -Wno-attributes -Wno-long-long -Winline" 79 | 80 | AC_MSG_CHECKING([which warning flags were supported]) 81 | for W in $MAYBE_WARN; do 82 | LIBDRM_CC_TRY_FLAG([$W], [WARN_CFLAGS="$WARN_CFLAGS $W"]) 83 | done 84 | 85 | AC_SUBST(WARN_CFLAGS) 86 | 87 | AC_CONFIG_FILES([Makefile]) 88 | AC_OUTPUT 89 | -------------------------------------------------------------------------------- /esTransform.c: -------------------------------------------------------------------------------- 1 | // 2 | // Book: OpenGL(R) ES 2.0 Programming Guide 3 | // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner 4 | // ISBN-10: 0321502795 5 | // ISBN-13: 9780321502797 6 | // Publisher: Addison-Wesley Professional 7 | // URLs: http://safari.informit.com/9780321563835 8 | // http://www.opengles-book.com 9 | // 10 | 11 | /* 12 | * (c) 2009 Aaftab Munshi, Dan Ginsburg, Dave Shreiner 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a 15 | * copy of this software and associated documentation files (the "Software"), 16 | * to deal in the Software without restriction, including without limitation 17 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 | * and/or sell copies of the Software, and to permit persons to whom the 19 | * Software is furnished to do so, subject to the following conditions: 20 | * 21 | * The above copyright notice and this permission notice shall be included 22 | * in all copies or substantial portions of the Software. 23 | * 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 29 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 30 | * DEALINGS IN THE SOFTWARE. 31 | */ 32 | 33 | // ESUtil.c 34 | // 35 | // A utility library for OpenGL ES. This library provides a 36 | // basic common framework for the example applications in the 37 | // OpenGL ES 2.0 Programming Guide. 38 | // 39 | 40 | /// 41 | // Includes 42 | // 43 | #include "esUtil.h" 44 | #include 45 | #include 46 | 47 | #define PI 3.1415926535897932384626433832795f 48 | 49 | void ESUTIL_API 50 | esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz) 51 | { 52 | result->m[0][0] *= sx; 53 | result->m[0][1] *= sx; 54 | result->m[0][2] *= sx; 55 | result->m[0][3] *= sx; 56 | 57 | result->m[1][0] *= sy; 58 | result->m[1][1] *= sy; 59 | result->m[1][2] *= sy; 60 | result->m[1][3] *= sy; 61 | 62 | result->m[2][0] *= sz; 63 | result->m[2][1] *= sz; 64 | result->m[2][2] *= sz; 65 | result->m[2][3] *= sz; 66 | } 67 | 68 | void ESUTIL_API 69 | esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz) 70 | { 71 | result->m[3][0] += (result->m[0][0] * tx + result->m[1][0] * ty + result->m[2][0] * tz); 72 | result->m[3][1] += (result->m[0][1] * tx + result->m[1][1] * ty + result->m[2][1] * tz); 73 | result->m[3][2] += (result->m[0][2] * tx + result->m[1][2] * ty + result->m[2][2] * tz); 74 | result->m[3][3] += (result->m[0][3] * tx + result->m[1][3] * ty + result->m[2][3] * tz); 75 | } 76 | 77 | void ESUTIL_API 78 | esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z) 79 | { 80 | GLfloat sinAngle, cosAngle; 81 | GLfloat mag = sqrtf(x * x + y * y + z * z); 82 | 83 | sinAngle = sinf ( angle * PI / 180.0f ); 84 | cosAngle = cosf ( angle * PI / 180.0f ); 85 | if ( mag > 0.0f ) 86 | { 87 | GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs; 88 | GLfloat oneMinusCos; 89 | ESMatrix rotMat; 90 | 91 | x /= mag; 92 | y /= mag; 93 | z /= mag; 94 | 95 | xx = x * x; 96 | yy = y * y; 97 | zz = z * z; 98 | xy = x * y; 99 | yz = y * z; 100 | zx = z * x; 101 | xs = x * sinAngle; 102 | ys = y * sinAngle; 103 | zs = z * sinAngle; 104 | oneMinusCos = 1.0f - cosAngle; 105 | 106 | rotMat.m[0][0] = (oneMinusCos * xx) + cosAngle; 107 | rotMat.m[0][1] = (oneMinusCos * xy) - zs; 108 | rotMat.m[0][2] = (oneMinusCos * zx) + ys; 109 | rotMat.m[0][3] = 0.0F; 110 | 111 | rotMat.m[1][0] = (oneMinusCos * xy) + zs; 112 | rotMat.m[1][1] = (oneMinusCos * yy) + cosAngle; 113 | rotMat.m[1][2] = (oneMinusCos * yz) - xs; 114 | rotMat.m[1][3] = 0.0F; 115 | 116 | rotMat.m[2][0] = (oneMinusCos * zx) - ys; 117 | rotMat.m[2][1] = (oneMinusCos * yz) + xs; 118 | rotMat.m[2][2] = (oneMinusCos * zz) + cosAngle; 119 | rotMat.m[2][3] = 0.0F; 120 | 121 | rotMat.m[3][0] = 0.0F; 122 | rotMat.m[3][1] = 0.0F; 123 | rotMat.m[3][2] = 0.0F; 124 | rotMat.m[3][3] = 1.0F; 125 | 126 | esMatrixMultiply( result, &rotMat, result ); 127 | } 128 | } 129 | 130 | void ESUTIL_API 131 | esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ) 132 | { 133 | float deltaX = right - left; 134 | float deltaY = top - bottom; 135 | float deltaZ = farZ - nearZ; 136 | ESMatrix frust; 137 | 138 | if ( (nearZ <= 0.0f) || (farZ <= 0.0f) || 139 | (deltaX <= 0.0f) || (deltaY <= 0.0f) || (deltaZ <= 0.0f) ) 140 | return; 141 | 142 | frust.m[0][0] = 2.0f * nearZ / deltaX; 143 | frust.m[0][1] = frust.m[0][2] = frust.m[0][3] = 0.0f; 144 | 145 | frust.m[1][1] = 2.0f * nearZ / deltaY; 146 | frust.m[1][0] = frust.m[1][2] = frust.m[1][3] = 0.0f; 147 | 148 | frust.m[2][0] = (right + left) / deltaX; 149 | frust.m[2][1] = (top + bottom) / deltaY; 150 | frust.m[2][2] = -(nearZ + farZ) / deltaZ; 151 | frust.m[2][3] = -1.0f; 152 | 153 | frust.m[3][2] = -2.0f * nearZ * farZ / deltaZ; 154 | frust.m[3][0] = frust.m[3][1] = frust.m[3][3] = 0.0f; 155 | 156 | esMatrixMultiply(result, &frust, result); 157 | } 158 | 159 | 160 | void ESUTIL_API 161 | esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ) 162 | { 163 | GLfloat frustumW, frustumH; 164 | 165 | frustumH = tanf( fovy / 360.0f * PI ) * nearZ; 166 | frustumW = frustumH * aspect; 167 | 168 | esFrustum( result, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ ); 169 | } 170 | 171 | void ESUTIL_API 172 | esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ) 173 | { 174 | float deltaX = right - left; 175 | float deltaY = top - bottom; 176 | float deltaZ = farZ - nearZ; 177 | ESMatrix ortho; 178 | 179 | if ( (deltaX == 0.0f) || (deltaY == 0.0f) || (deltaZ == 0.0f) ) 180 | return; 181 | 182 | esMatrixLoadIdentity(&ortho); 183 | ortho.m[0][0] = 2.0f / deltaX; 184 | ortho.m[3][0] = -(right + left) / deltaX; 185 | ortho.m[1][1] = 2.0f / deltaY; 186 | ortho.m[3][1] = -(top + bottom) / deltaY; 187 | ortho.m[2][2] = -2.0f / deltaZ; 188 | ortho.m[3][2] = -(nearZ + farZ) / deltaZ; 189 | 190 | esMatrixMultiply(result, &ortho, result); 191 | } 192 | 193 | 194 | void ESUTIL_API 195 | esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB) 196 | { 197 | ESMatrix tmp; 198 | int i; 199 | 200 | for (i=0; i<4; i++) 201 | { 202 | tmp.m[i][0] = (srcA->m[i][0] * srcB->m[0][0]) + 203 | (srcA->m[i][1] * srcB->m[1][0]) + 204 | (srcA->m[i][2] * srcB->m[2][0]) + 205 | (srcA->m[i][3] * srcB->m[3][0]) ; 206 | 207 | tmp.m[i][1] = (srcA->m[i][0] * srcB->m[0][1]) + 208 | (srcA->m[i][1] * srcB->m[1][1]) + 209 | (srcA->m[i][2] * srcB->m[2][1]) + 210 | (srcA->m[i][3] * srcB->m[3][1]) ; 211 | 212 | tmp.m[i][2] = (srcA->m[i][0] * srcB->m[0][2]) + 213 | (srcA->m[i][1] * srcB->m[1][2]) + 214 | (srcA->m[i][2] * srcB->m[2][2]) + 215 | (srcA->m[i][3] * srcB->m[3][2]) ; 216 | 217 | tmp.m[i][3] = (srcA->m[i][0] * srcB->m[0][3]) + 218 | (srcA->m[i][1] * srcB->m[1][3]) + 219 | (srcA->m[i][2] * srcB->m[2][3]) + 220 | (srcA->m[i][3] * srcB->m[3][3]) ; 221 | } 222 | memcpy(result, &tmp, sizeof(ESMatrix)); 223 | } 224 | 225 | 226 | void ESUTIL_API 227 | esMatrixLoadIdentity(ESMatrix *result) 228 | { 229 | memset(result, 0x0, sizeof(ESMatrix)); 230 | result->m[0][0] = 1.0f; 231 | result->m[1][1] = 1.0f; 232 | result->m[2][2] = 1.0f; 233 | result->m[3][3] = 1.0f; 234 | } 235 | 236 | -------------------------------------------------------------------------------- /esUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // Book: OpenGL(R) ES 2.0 Programming Guide 3 | // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner 4 | // ISBN-10: 0321502795 5 | // ISBN-13: 9780321502797 6 | // Publisher: Addison-Wesley Professional 7 | // URLs: http://safari.informit.com/9780321563835 8 | // http://www.opengles-book.com 9 | // 10 | 11 | /* 12 | * (c) 2009 Aaftab Munshi, Dan Ginsburg, Dave Shreiner 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a 15 | * copy of this software and associated documentation files (the "Software"), 16 | * to deal in the Software without restriction, including without limitation 17 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 | * and/or sell copies of the Software, and to permit persons to whom the 19 | * Software is furnished to do so, subject to the following conditions: 20 | * 21 | * The above copyright notice and this permission notice shall be included 22 | * in all copies or substantial portions of the Software. 23 | * 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 29 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 30 | * DEALINGS IN THE SOFTWARE. 31 | */ 32 | 33 | // 34 | /// \file ESUtil.h 35 | /// \brief A utility library for OpenGL ES. This library provides a 36 | /// basic common framework for the example applications in the 37 | /// OpenGL ES 2.0 Programming Guide. 38 | // 39 | #ifndef ESUTIL_H 40 | #define ESUTIL_H 41 | 42 | /// 43 | // Includes 44 | // 45 | #include 46 | #include 47 | 48 | #ifdef __cplusplus 49 | 50 | extern "C" { 51 | #endif 52 | 53 | 54 | /// 55 | // Macros 56 | // 57 | #define ESUTIL_API 58 | #define ESCALLBACK 59 | 60 | 61 | /// esCreateWindow flag - RGB color buffer 62 | #define ES_WINDOW_RGB 0 63 | /// esCreateWindow flag - ALPHA color buffer 64 | #define ES_WINDOW_ALPHA 1 65 | /// esCreateWindow flag - depth buffer 66 | #define ES_WINDOW_DEPTH 2 67 | /// esCreateWindow flag - stencil buffer 68 | #define ES_WINDOW_STENCIL 4 69 | /// esCreateWindow flat - multi-sample buffer 70 | #define ES_WINDOW_MULTISAMPLE 8 71 | 72 | 73 | /// 74 | // Types 75 | // 76 | 77 | #ifndef FALSE 78 | #define FALSE 0 79 | #endif 80 | #ifndef TRUE 81 | #define TRUE 1 82 | #endif 83 | 84 | typedef struct 85 | { 86 | GLfloat m[4][4]; 87 | } ESMatrix; 88 | 89 | typedef struct _escontext 90 | { 91 | /// Put your user data here... 92 | void* userData; 93 | 94 | /// Window width 95 | GLint width; 96 | 97 | /// Window height 98 | GLint height; 99 | 100 | /// Window handle 101 | EGLNativeWindowType hWnd; 102 | 103 | /// EGL display 104 | EGLDisplay eglDisplay; 105 | 106 | /// EGL context 107 | EGLContext eglContext; 108 | 109 | /// EGL surface 110 | EGLSurface eglSurface; 111 | 112 | /// Callbacks 113 | void (ESCALLBACK *drawFunc) ( struct _escontext * ); 114 | void (ESCALLBACK *keyFunc) ( struct _escontext *, unsigned char, int, int ); 115 | void (ESCALLBACK *updateFunc) ( struct _escontext *, float deltaTime ); 116 | } ESContext; 117 | 118 | 119 | /// 120 | // Public Functions 121 | // 122 | 123 | // 124 | /// 125 | /// \brief Initialize ES framework context. This must be called before calling any other functions. 126 | /// \param esContext Application context 127 | // 128 | void ESUTIL_API esInitContext ( ESContext *esContext ); 129 | 130 | // 131 | /// \brief Create a window with the specified parameters 132 | /// \param esContext Application context 133 | /// \param title Name for title bar of window 134 | /// \param width Width in pixels of window to create 135 | /// \param height Height in pixels of window to create 136 | /// \param flags Bitfield for the window creation flags 137 | /// ES_WINDOW_RGB - specifies that the color buffer should have R,G,B channels 138 | /// ES_WINDOW_ALPHA - specifies that the color buffer should have alpha 139 | /// ES_WINDOW_DEPTH - specifies that a depth buffer should be created 140 | /// ES_WINDOW_STENCIL - specifies that a stencil buffer should be created 141 | /// ES_WINDOW_MULTISAMPLE - specifies that a multi-sample buffer should be created 142 | /// \return GL_TRUE if window creation is succesful, GL_FALSE otherwise 143 | GLboolean ESUTIL_API esCreateWindow ( ESContext *esContext, const char *title, GLint width, GLint height, GLuint flags ); 144 | 145 | // 146 | /// \brief Start the main loop for the OpenGL ES application 147 | /// \param esContext Application context 148 | // 149 | void ESUTIL_API esMainLoop ( ESContext *esContext ); 150 | 151 | // 152 | /// \brief Register a draw callback function to be used to render each frame 153 | /// \param esContext Application context 154 | /// \param drawFunc Draw callback function that will be used to render the scene 155 | // 156 | void ESUTIL_API esRegisterDrawFunc ( ESContext *esContext, void (ESCALLBACK *drawFunc) ( ESContext* ) ); 157 | 158 | // 159 | /// \brief Register an update callback function to be used to update on each time step 160 | /// \param esContext Application context 161 | /// \param updateFunc Update callback function that will be used to render the scene 162 | // 163 | void ESUTIL_API esRegisterUpdateFunc ( ESContext *esContext, void (ESCALLBACK *updateFunc) ( ESContext*, float ) ); 164 | 165 | // 166 | /// \brief Register an keyboard input processing callback function 167 | /// \param esContext Application context 168 | /// \param keyFunc Key callback function for application processing of keyboard input 169 | // 170 | void ESUTIL_API esRegisterKeyFunc ( ESContext *esContext, 171 | void (ESCALLBACK *drawFunc) ( ESContext*, unsigned char, int, int ) ); 172 | // 173 | /// \brief Log a message to the debug output for the platform 174 | /// \param formatStr Format string for error log. 175 | // 176 | void ESUTIL_API esLogMessage ( const char *formatStr, ... ); 177 | 178 | // 179 | /// 180 | /// \brief Load a shader, check for compile errors, print error messages to output log 181 | /// \param type Type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER) 182 | /// \param shaderSrc Shader source string 183 | /// \return A new shader object on success, 0 on failure 184 | // 185 | GLuint ESUTIL_API esLoadShader ( GLenum type, const char *shaderSrc ); 186 | 187 | // 188 | /// 189 | /// \brief Load a vertex and fragment shader, create a program object, link program. 190 | /// Errors output to log. 191 | /// \param vertShaderSrc Vertex shader source code 192 | /// \param fragShaderSrc Fragment shader source code 193 | /// \return A new program object linked with the vertex/fragment shader pair, 0 on failure 194 | // 195 | GLuint ESUTIL_API esLoadProgram ( const char *vertShaderSrc, const char *fragShaderSrc ); 196 | 197 | 198 | // 199 | /// \brief Generates geometry for a sphere. Allocates memory for the vertex data and stores 200 | /// the results in the arrays. Generate index list for a TRIANGLE_STRIP 201 | /// \param numSlices The number of slices in the sphere 202 | /// \param vertices If not NULL, will contain array of float3 positions 203 | /// \param normals If not NULL, will contain array of float3 normals 204 | /// \param texCoords If not NULL, will contain array of float2 texCoords 205 | /// \param indices If not NULL, will contain the array of indices for the triangle strip 206 | /// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array 207 | /// if it is not NULL ) as a GL_TRIANGLE_STRIP 208 | // 209 | int ESUTIL_API esGenSphere ( int numSlices, float radius, GLfloat **vertices, GLfloat **normals, 210 | GLfloat **texCoords, GLuint **indices ); 211 | 212 | // 213 | /// \brief Generates geometry for a cube. Allocates memory for the vertex data and stores 214 | /// the results in the arrays. Generate index list for a TRIANGLES 215 | /// \param scale The size of the cube, use 1.0 for a unit cube. 216 | /// \param vertices If not NULL, will contain array of float3 positions 217 | /// \param normals If not NULL, will contain array of float3 normals 218 | /// \param texCoords If not NULL, will contain array of float2 texCoords 219 | /// \param indices If not NULL, will contain the array of indices for the triangle strip 220 | /// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array 221 | /// if it is not NULL ) as a GL_TRIANGLES 222 | // 223 | int ESUTIL_API esGenCube ( float scale, GLfloat **vertices, GLfloat **normals, 224 | GLfloat **texCoords, GLuint **indices ); 225 | 226 | // 227 | /// \brief Loads a 24-bit TGA image from a file 228 | /// \param fileName Name of the file on disk 229 | /// \param width Width of loaded image in pixels 230 | /// \param height Height of loaded image in pixels 231 | /// \return Pointer to loaded image. NULL on failure. 232 | // 233 | char* ESUTIL_API esLoadTGA ( char *fileName, int *width, int *height ); 234 | 235 | 236 | // 237 | /// \brief multiply matrix specified by result with a scaling matrix and return new matrix in result 238 | /// \param result Specifies the input matrix. Scaled matrix is returned in result. 239 | /// \param sx, sy, sz Scale factors along the x, y and z axes respectively 240 | // 241 | void ESUTIL_API esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz); 242 | 243 | // 244 | /// \brief multiply matrix specified by result with a translation matrix and return new matrix in result 245 | /// \param result Specifies the input matrix. Translated matrix is returned in result. 246 | /// \param tx, ty, tz Scale factors along the x, y and z axes respectively 247 | // 248 | void ESUTIL_API esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz); 249 | 250 | // 251 | /// \brief multiply matrix specified by result with a rotation matrix and return new matrix in result 252 | /// \param result Specifies the input matrix. Rotated matrix is returned in result. 253 | /// \param angle Specifies the angle of rotation, in degrees. 254 | /// \param x, y, z Specify the x, y and z coordinates of a vector, respectively 255 | // 256 | void ESUTIL_API esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); 257 | 258 | // 259 | // \brief multiply matrix specified by result with a perspective matrix and return new matrix in result 260 | /// \param result Specifies the input matrix. new matrix is returned in result. 261 | /// \param left, right Coordinates for the left and right vertical clipping planes 262 | /// \param bottom, top Coordinates for the bottom and top horizontal clipping planes 263 | /// \param nearZ, farZ Distances to the near and far depth clipping planes. Both distances must be positive. 264 | // 265 | void ESUTIL_API esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ); 266 | 267 | // 268 | /// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result 269 | /// \param result Specifies the input matrix. new matrix is returned in result. 270 | /// \param fovy Field of view y angle in degrees 271 | /// \param aspect Aspect ratio of screen 272 | /// \param nearZ Near plane distance 273 | /// \param farZ Far plane distance 274 | // 275 | void ESUTIL_API esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ); 276 | 277 | // 278 | /// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result 279 | /// \param result Specifies the input matrix. new matrix is returned in result. 280 | /// \param left, right Coordinates for the left and right vertical clipping planes 281 | /// \param bottom, top Coordinates for the bottom and top horizontal clipping planes 282 | /// \param nearZ, farZ Distances to the near and far depth clipping planes. These values are negative if plane is behind the viewer 283 | // 284 | void ESUTIL_API esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ); 285 | 286 | // 287 | /// \brief perform the following operation - result matrix = srcA matrix * srcB matrix 288 | /// \param result Returns multiplied matrix 289 | /// \param srcA, srcB Input matrices to be multiplied 290 | // 291 | void ESUTIL_API esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB); 292 | 293 | // 294 | //// \brief return an indentity matrix 295 | //// \param result returns identity matrix 296 | // 297 | void ESUTIL_API esMatrixLoadIdentity(ESMatrix *result); 298 | 299 | #ifdef __cplusplus 300 | } 301 | #endif 302 | 303 | #endif // ESUTIL_H 304 | -------------------------------------------------------------------------------- /kmscube.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Arvin Schnell 3 | * Copyright (c) 2012 Rob Clark 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a 6 | * copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sub license, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice (including the 13 | * next paragraph) shall be included in all copies or substantial portions 14 | * of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | * DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /* Based on a egl cube test app originally written by Arvin Schnell */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #include "esUtil.h" 42 | 43 | 44 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 45 | 46 | 47 | static struct { 48 | EGLDisplay display; 49 | EGLConfig config; 50 | EGLContext context; 51 | EGLSurface surface; 52 | GLuint program; 53 | GLint modelviewmatrix, modelviewprojectionmatrix, normalmatrix; 54 | GLuint vbo; 55 | GLuint positionsoffset, colorsoffset, normalsoffset; 56 | } gl; 57 | 58 | static struct { 59 | struct gbm_device *dev; 60 | struct gbm_surface *surface; 61 | } gbm; 62 | 63 | static struct { 64 | int fd; 65 | drmModeModeInfo *mode; 66 | uint32_t crtc_id; 67 | uint32_t connector_id; 68 | } drm; 69 | 70 | struct drm_fb { 71 | struct gbm_bo *bo; 72 | uint32_t fb_id; 73 | }; 74 | 75 | static int init_drm(void) 76 | { 77 | static const char *modules[] = { 78 | "i915", 79 | "radeon", 80 | "nouveau", 81 | "vmwgfx", 82 | "omapdrm", 83 | "exynos", 84 | "msm" 85 | }; 86 | drmModeRes *resources; 87 | drmModeConnector *connector = NULL; 88 | drmModeEncoder *encoder = NULL; 89 | int i, area; 90 | 91 | for (i = 0; i < ARRAY_SIZE(modules); i++) { 92 | fprintf(stderr,"trying to load module %s...", modules[i]); 93 | drm.fd = drmOpen(modules[i], NULL); 94 | if (drm.fd < 0) { 95 | fprintf(stderr,"failed.\n"); 96 | } else { 97 | fprintf(stderr,"success.\n"); 98 | break; 99 | } 100 | } 101 | 102 | if (drm.fd < 0) { 103 | fprintf(stderr,"could not open drm device\n"); 104 | return -1; 105 | } 106 | 107 | resources = drmModeGetResources(drm.fd); 108 | if (!resources) { 109 | fprintf(stderr,"drmModeGetResources failed: %s\n", strerror(errno)); 110 | return -1; 111 | } 112 | 113 | /* find a connected connector: */ 114 | for (i = 0; i < resources->count_connectors; i++) { 115 | connector = drmModeGetConnector(drm.fd, resources->connectors[i]); 116 | if (connector->connection == DRM_MODE_CONNECTED) { 117 | /* it's connected, let's use this! */ 118 | break; 119 | } 120 | drmModeFreeConnector(connector); 121 | connector = NULL; 122 | } 123 | 124 | if (!connector) { 125 | /* we could be fancy and listen for hotplug events and wait for 126 | * a connector.. 127 | */ 128 | fprintf(stderr,"no connected connector!\n"); 129 | return -1; 130 | } 131 | 132 | /* find highest resolution mode: */ 133 | for (i = 0, area = 0; i < connector->count_modes; i++) { 134 | drmModeModeInfo *current_mode = &connector->modes[i]; 135 | int current_area = current_mode->hdisplay * current_mode->vdisplay; 136 | if (current_area > area) { 137 | drm.mode = current_mode; 138 | area = current_area; 139 | } 140 | } 141 | 142 | if (!drm.mode) { 143 | fprintf(stderr,"could not find mode!\n"); 144 | return -1; 145 | } 146 | 147 | /* find encoder: */ 148 | for (i = 0; i < resources->count_encoders; i++) { 149 | encoder = drmModeGetEncoder(drm.fd, resources->encoders[i]); 150 | if (encoder->encoder_id == connector->encoder_id) 151 | break; 152 | drmModeFreeEncoder(encoder); 153 | encoder = NULL; 154 | } 155 | 156 | if (!encoder) { 157 | fprintf(stderr,"no encoder!\n"); 158 | return -1; 159 | } 160 | 161 | drm.crtc_id = encoder->crtc_id; 162 | drm.connector_id = connector->connector_id; 163 | 164 | return 0; 165 | } 166 | 167 | static int init_gbm(void) 168 | { 169 | gbm.dev = gbm_create_device(drm.fd); 170 | 171 | gbm.surface = gbm_surface_create(gbm.dev, 172 | drm.mode->hdisplay, drm.mode->vdisplay, 173 | // GBM_FORMAT_XRGB8888, 174 | GBM_FORMAT_ARGB2101010, 175 | GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); 176 | if (!gbm.surface) { 177 | fprintf(stderr,"failed to create gbm surface\n"); 178 | return -1; 179 | } 180 | 181 | return 0; 182 | } 183 | 184 | static int init_gl(void) 185 | { 186 | EGLint major, minor, n; 187 | GLuint vertex_shader, fragment_shader; 188 | GLint ret; 189 | 190 | static const GLfloat vVertices[] = { 191 | // front 192 | -1.0f, -1.0f, +1.0f, // point blue 193 | +1.0f, -1.0f, +1.0f, // point magenta 194 | -1.0f, +1.0f, +1.0f, // point cyan 195 | +1.0f, +1.0f, +1.0f, // point white 196 | // back 197 | +1.0f, -1.0f, -1.0f, // point red 198 | -1.0f, -1.0f, -1.0f, // point black 199 | +1.0f, +1.0f, -1.0f, // point yellow 200 | -1.0f, +1.0f, -1.0f, // point green 201 | // right 202 | +1.0f, -1.0f, +1.0f, // point magenta 203 | +1.0f, -1.0f, -1.0f, // point red 204 | +1.0f, +1.0f, +1.0f, // point white 205 | +1.0f, +1.0f, -1.0f, // point yellow 206 | // left 207 | -1.0f, -1.0f, -1.0f, // point black 208 | -1.0f, -1.0f, +1.0f, // point blue 209 | -1.0f, +1.0f, -1.0f, // point green 210 | -1.0f, +1.0f, +1.0f, // point cyan 211 | // top 212 | -1.0f, +1.0f, +1.0f, // point cyan 213 | +1.0f, +1.0f, +1.0f, // point white 214 | -1.0f, +1.0f, -1.0f, // point green 215 | +1.0f, +1.0f, -1.0f, // point yellow 216 | // bottom 217 | -1.0f, -1.0f, -1.0f, // point black 218 | +1.0f, -1.0f, -1.0f, // point red 219 | -1.0f, -1.0f, +1.0f, // point blue 220 | +1.0f, -1.0f, +1.0f // point magenta 221 | }; 222 | 223 | static const GLfloat vColors[] = { 224 | // front 225 | 0.0f, 0.0f, 1.0f, // blue 226 | 1.0f, 0.0f, 1.0f, // magenta 227 | 0.0f, 1.0f, 1.0f, // cyan 228 | 1.0f, 1.0f, 1.0f, // white 229 | // back 230 | 1.0f, 0.0f, 0.0f, // red 231 | 0.0f, 0.0f, 0.0f, // black 232 | 1.0f, 1.0f, 0.0f, // yellow 233 | 0.0f, 1.0f, 0.0f, // green 234 | // right 235 | 1.0f, 0.0f, 1.0f, // magenta 236 | 1.0f, 0.0f, 0.0f, // red 237 | 1.0f, 1.0f, 1.0f, // white 238 | 1.0f, 1.0f, 0.0f, // yellow 239 | // left 240 | 0.0f, 0.0f, 0.0f, // black 241 | 0.0f, 0.0f, 1.0f, // blue 242 | 0.0f, 1.0f, 0.0f, // green 243 | 0.0f, 1.0f, 1.0f, // cyan 244 | // top 245 | 0.0f, 1.0f, 1.0f, // cyan 246 | 1.0f, 1.0f, 1.0f, // white 247 | 0.0f, 1.0f, 0.0f, // green 248 | 1.0f, 1.0f, 0.0f, // yellow 249 | // bottom 250 | 0.0f, 0.0f, 0.0f, // black 251 | 1.0f, 0.0f, 0.0f, // red 252 | 0.0f, 0.0f, 1.0f, // blue 253 | 1.0f, 0.0f, 1.0f // magenta 254 | }; 255 | 256 | static const GLfloat vNormals[] = { 257 | // front 258 | +0.0f, +0.0f, +1.0f, // forward 259 | +0.0f, +0.0f, +1.0f, // forward 260 | +0.0f, +0.0f, +1.0f, // forward 261 | +0.0f, +0.0f, +1.0f, // forward 262 | // back 263 | +0.0f, +0.0f, -1.0f, // backbard 264 | +0.0f, +0.0f, -1.0f, // backbard 265 | +0.0f, +0.0f, -1.0f, // backbard 266 | +0.0f, +0.0f, -1.0f, // backbard 267 | // right 268 | +1.0f, +0.0f, +0.0f, // right 269 | +1.0f, +0.0f, +0.0f, // right 270 | +1.0f, +0.0f, +0.0f, // right 271 | +1.0f, +0.0f, +0.0f, // right 272 | // left 273 | -1.0f, +0.0f, +0.0f, // left 274 | -1.0f, +0.0f, +0.0f, // left 275 | -1.0f, +0.0f, +0.0f, // left 276 | -1.0f, +0.0f, +0.0f, // left 277 | // top 278 | +0.0f, +1.0f, +0.0f, // up 279 | +0.0f, +1.0f, +0.0f, // up 280 | +0.0f, +1.0f, +0.0f, // up 281 | +0.0f, +1.0f, +0.0f, // up 282 | // bottom 283 | +0.0f, -1.0f, +0.0f, // down 284 | +0.0f, -1.0f, +0.0f, // down 285 | +0.0f, -1.0f, +0.0f, // down 286 | +0.0f, -1.0f, +0.0f // down 287 | }; 288 | 289 | static const EGLint context_attribs[] = { 290 | EGL_CONTEXT_CLIENT_VERSION, 2, 291 | EGL_NONE 292 | }; 293 | 294 | static const EGLint config_attribs[] = { 295 | EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 296 | EGL_RED_SIZE, 1, 297 | EGL_GREEN_SIZE, 1, 298 | EGL_BLUE_SIZE, 1, 299 | EGL_ALPHA_SIZE, 1, 300 | EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, 301 | EGL_NONE 302 | }; 303 | 304 | static const char *vertex_shader_source = 305 | "uniform mat4 modelviewMatrix; \n" 306 | "uniform mat4 modelviewprojectionMatrix;\n" 307 | "uniform mat3 normalMatrix; \n" 308 | " \n" 309 | "attribute vec4 in_position; \n" 310 | "attribute vec3 in_normal; \n" 311 | "attribute vec4 in_color; \n" 312 | "\n" 313 | "vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n" 314 | " \n" 315 | "varying vec4 vVaryingColor; \n" 316 | " \n" 317 | "void main() \n" 318 | "{ \n" 319 | " gl_Position = modelviewprojectionMatrix * in_position;\n" 320 | " vec3 vEyeNormal = normalMatrix * in_normal;\n" 321 | " vec4 vPosition4 = modelviewMatrix * in_position;\n" 322 | " vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n" 323 | " vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n" 324 | " float diff = max(0.0, dot(vEyeNormal, vLightDir));\n" 325 | " vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n" 326 | "} \n"; 327 | 328 | static const char *fragment_shader_source = 329 | "precision mediump float; \n" 330 | " \n" 331 | "varying vec4 vVaryingColor; \n" 332 | " \n" 333 | "void main() \n" 334 | "{ \n" 335 | " gl_FragColor = vVaryingColor; \n" 336 | "} \n"; 337 | 338 | gl.display = eglGetDisplay(gbm.dev); 339 | 340 | if (!eglInitialize(gl.display, &major, &minor)) { 341 | fprintf(stderr,"failed to initialize\n"); 342 | return -1; 343 | } 344 | 345 | fprintf(stderr,"Using display %p with EGL version %d.%d\n", 346 | gl.display, major, minor); 347 | 348 | fprintf(stderr,"EGL Version \"%s\"\n", eglQueryString(gl.display, EGL_VERSION)); 349 | fprintf(stderr,"EGL Vendor \"%s\"\n", eglQueryString(gl.display, EGL_VENDOR)); 350 | fprintf(stderr,"EGL Extensions \"%s\"\n", eglQueryString(gl.display, EGL_EXTENSIONS)); 351 | 352 | if (!eglBindAPI(EGL_OPENGL_ES_API)) { 353 | fprintf(stderr,"failed to bind api EGL_OPENGL_ES_API\n"); 354 | return -1; 355 | } 356 | 357 | if (!eglChooseConfig(gl.display, config_attribs, &gl.config, 1, &n) || n != 1) { 358 | fprintf(stderr,"failed to choose config: %d\n", n); 359 | return -1; 360 | } 361 | 362 | gl.context = eglCreateContext(gl.display, gl.config, 363 | EGL_NO_CONTEXT, context_attribs); 364 | if (gl.context == NULL) { 365 | fprintf(stderr,"failed to create context\n"); 366 | return -1; 367 | } 368 | 369 | gl.surface = eglCreateWindowSurface(gl.display, gl.config, gbm.surface, NULL); 370 | if (gl.surface == EGL_NO_SURFACE) { 371 | fprintf(stderr,"failed to create egl surface\n"); 372 | return -1; 373 | } 374 | 375 | /* connect the context to the surface */ 376 | eglMakeCurrent(gl.display, gl.surface, gl.surface, gl.context); 377 | 378 | 379 | vertex_shader = glCreateShader(GL_VERTEX_SHADER); 380 | 381 | glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL); 382 | glCompileShader(vertex_shader); 383 | 384 | glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &ret); 385 | if (!ret) { 386 | char *log; 387 | 388 | fprintf(stderr,"vertex shader compilation failed!:\n"); 389 | glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &ret); 390 | if (ret > 1) { 391 | log = malloc(ret); 392 | glGetShaderInfoLog(vertex_shader, ret, NULL, log); 393 | fprintf(stderr,"%s", log); 394 | } 395 | 396 | return -1; 397 | } 398 | 399 | fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); 400 | 401 | glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL); 402 | glCompileShader(fragment_shader); 403 | 404 | glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &ret); 405 | if (!ret) { 406 | char *log; 407 | 408 | fprintf(stderr,"fragment shader compilation failed!:\n"); 409 | glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &ret); 410 | 411 | if (ret > 1) { 412 | log = malloc(ret); 413 | glGetShaderInfoLog(fragment_shader, ret, NULL, log); 414 | fprintf(stderr,"%s", log); 415 | } 416 | 417 | return -1; 418 | } 419 | 420 | gl.program = glCreateProgram(); 421 | 422 | glAttachShader(gl.program, vertex_shader); 423 | glAttachShader(gl.program, fragment_shader); 424 | 425 | glBindAttribLocation(gl.program, 0, "in_position"); 426 | glBindAttribLocation(gl.program, 1, "in_normal"); 427 | glBindAttribLocation(gl.program, 2, "in_color"); 428 | 429 | glLinkProgram(gl.program); 430 | 431 | glGetProgramiv(gl.program, GL_LINK_STATUS, &ret); 432 | if (!ret) { 433 | char *log; 434 | 435 | fprintf(stderr,"program linking failed!:\n"); 436 | glGetProgramiv(gl.program, GL_INFO_LOG_LENGTH, &ret); 437 | 438 | if (ret > 1) { 439 | log = malloc(ret); 440 | glGetProgramInfoLog(gl.program, ret, NULL, log); 441 | fprintf(stderr,"%s", log); 442 | } 443 | 444 | return -1; 445 | } 446 | 447 | glUseProgram(gl.program); 448 | 449 | gl.modelviewmatrix = glGetUniformLocation(gl.program, "modelviewMatrix"); 450 | gl.modelviewprojectionmatrix = glGetUniformLocation(gl.program, "modelviewprojectionMatrix"); 451 | gl.normalmatrix = glGetUniformLocation(gl.program, "normalMatrix"); 452 | 453 | glViewport(0, 0, drm.mode->hdisplay, drm.mode->vdisplay); 454 | glEnable(GL_CULL_FACE); 455 | 456 | gl.positionsoffset = 0; 457 | gl.colorsoffset = sizeof(vVertices); 458 | gl.normalsoffset = sizeof(vVertices) + sizeof(vColors); 459 | glGenBuffers(1, &gl.vbo); 460 | glBindBuffer(GL_ARRAY_BUFFER, gl.vbo); 461 | glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW); 462 | glBufferSubData(GL_ARRAY_BUFFER, gl.positionsoffset, sizeof(vVertices), &vVertices[0]); 463 | glBufferSubData(GL_ARRAY_BUFFER, gl.colorsoffset, sizeof(vColors), &vColors[0]); 464 | glBufferSubData(GL_ARRAY_BUFFER, gl.normalsoffset, sizeof(vNormals), &vNormals[0]); 465 | 466 | 467 | void (*glVertexAttribOffset)(GLuint,GLint,GLenum,GLboolean,GLsizei,uintptr_t) = 468 | (void*)glVertexAttribPointer; 469 | 470 | glVertexAttribOffset(0, 3, GL_FLOAT, GL_FALSE, 0, gl.positionsoffset); 471 | glEnableVertexAttribArray(0); 472 | glVertexAttribOffset(1, 3, GL_FLOAT, GL_FALSE, 0, gl.normalsoffset); 473 | glEnableVertexAttribArray(1); 474 | glVertexAttribOffset(2, 3, GL_FLOAT, GL_FALSE, 0, gl.colorsoffset); 475 | glEnableVertexAttribArray(2); 476 | 477 | return 0; 478 | } 479 | 480 | static void draw(uint32_t i) 481 | { 482 | ESMatrix modelview; 483 | 484 | /* clear the color buffer */ 485 | glClearColor(0.5, 0.5, 0.5, 1.0); 486 | glClear(GL_COLOR_BUFFER_BIT); 487 | 488 | esMatrixLoadIdentity(&modelview); 489 | esTranslate(&modelview, 0.0f, 0.0f, -8.0f); 490 | esRotate(&modelview, 45.0f + (0.25f * i), 1.0f, 0.0f, 0.0f); 491 | esRotate(&modelview, 45.0f - (0.5f * i), 0.0f, 1.0f, 0.0f); 492 | esRotate(&modelview, 10.0f + (0.15f * i), 0.0f, 0.0f, 1.0f); 493 | 494 | GLfloat aspect = (GLfloat)(drm.mode->vdisplay) / (GLfloat)(drm.mode->hdisplay); 495 | 496 | ESMatrix projection; 497 | esMatrixLoadIdentity(&projection); 498 | esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f); 499 | 500 | ESMatrix modelviewprojection; 501 | esMatrixLoadIdentity(&modelviewprojection); 502 | esMatrixMultiply(&modelviewprojection, &modelview, &projection); 503 | 504 | float normal[9]; 505 | normal[0] = modelview.m[0][0]; 506 | normal[1] = modelview.m[0][1]; 507 | normal[2] = modelview.m[0][2]; 508 | normal[3] = modelview.m[1][0]; 509 | normal[4] = modelview.m[1][1]; 510 | normal[5] = modelview.m[1][2]; 511 | normal[6] = modelview.m[2][0]; 512 | normal[7] = modelview.m[2][1]; 513 | normal[8] = modelview.m[2][2]; 514 | 515 | glUniformMatrix4fv(gl.modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]); 516 | glUniformMatrix4fv(gl.modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]); 517 | glUniformMatrix3fv(gl.normalmatrix, 1, GL_FALSE, normal); 518 | 519 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 520 | glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); 521 | glDrawArrays(GL_TRIANGLE_STRIP, 8, 4); 522 | glDrawArrays(GL_TRIANGLE_STRIP, 12, 4); 523 | glDrawArrays(GL_TRIANGLE_STRIP, 16, 4); 524 | glDrawArrays(GL_TRIANGLE_STRIP, 20, 4); 525 | } 526 | 527 | static void 528 | drm_fb_destroy_callback(struct gbm_bo *bo, void *data) 529 | { 530 | struct drm_fb *fb = data; 531 | struct gbm_device *gbm = gbm_bo_get_device(bo); 532 | 533 | if (fb->fb_id) 534 | drmModeRmFB(drm.fd, fb->fb_id); 535 | 536 | free(fb); 537 | } 538 | 539 | static struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo) 540 | { 541 | struct drm_fb *fb = gbm_bo_get_user_data(bo); 542 | uint32_t width, height, stride, handle; 543 | int ret; 544 | 545 | if (fb) 546 | return fb; 547 | 548 | fb = calloc(1, sizeof *fb); 549 | fb->bo = bo; 550 | 551 | width = gbm_bo_get_width(bo); 552 | height = gbm_bo_get_height(bo); 553 | stride = gbm_bo_get_stride(bo); 554 | handle = gbm_bo_get_handle(bo).u32; 555 | 556 | ret = drmModeAddFB(drm.fd, width, height, 24, 32, stride, handle, &fb->fb_id); 557 | if (ret) { 558 | fprintf(stderr,"failed to create fb: %s\n", strerror(errno)); 559 | free(fb); 560 | return NULL; 561 | } 562 | 563 | gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback); 564 | 565 | return fb; 566 | } 567 | 568 | static void page_flip_handler(int fd, unsigned int frame, 569 | unsigned int sec, unsigned int usec, void *data) 570 | { 571 | int *waiting_for_flip = data; 572 | *waiting_for_flip = 0; 573 | } 574 | 575 | int main(int argc, char *argv[]) 576 | { 577 | fd_set fds; 578 | drmEventContext evctx = { 579 | .version = DRM_EVENT_CONTEXT_VERSION, 580 | .page_flip_handler = page_flip_handler, 581 | }; 582 | struct gbm_bo *bo; 583 | struct drm_fb *fb; 584 | uint32_t i = 0; 585 | int ret; 586 | 587 | if( getenv("DISPLAY") ) { 588 | fprintf(stderr, 589 | "X11 display variable set. Likely %s was started from within a X11 session. " 590 | "This is not good, because we're treading on the toes of the X11 server here, " 591 | "which may lead to it crashing.\n", 592 | argv[0] ); 593 | return 1; 594 | } 595 | 596 | int const fd_tty = open("/dev/tty", O_RDWR); 597 | if( -1 == fd_tty ) { 598 | fprintf(stderr, "failed to open TTY\n"); 599 | return 1; 600 | } 601 | ioctl(fd_tty, KDSETMODE, KD_GRAPHICS); 602 | 603 | ret = init_drm(); 604 | if (ret) { 605 | fprintf(stderr,"failed to initialize DRM\n"); 606 | return ret; 607 | } 608 | 609 | ret = init_gbm(); 610 | if (ret) { 611 | fprintf(stderr,"failed to initialize GBM\n"); 612 | return ret; 613 | } 614 | 615 | ret = init_gl(); 616 | if (ret) { 617 | fprintf(stderr,"failed to initialize EGL\n"); 618 | return ret; 619 | } 620 | 621 | /* clear the color buffer */ 622 | glClearColor(0.5, 0.5, 0.5, 1.0); 623 | glClear(GL_COLOR_BUFFER_BIT); 624 | eglSwapBuffers(gl.display, gl.surface); 625 | bo = gbm_surface_lock_front_buffer(gbm.surface); 626 | fb = drm_fb_get_from_bo(bo); 627 | 628 | /* set mode: */ 629 | ret = drmModeSetCrtc(drm.fd, drm.crtc_id, fb->fb_id, 0, 0, 630 | &drm.connector_id, 1, drm.mode); 631 | if (ret) { 632 | fprintf(stderr,"failed to set mode: %s\n", strerror(errno)); 633 | return ret; 634 | } 635 | 636 | int quit = 0; 637 | while (!quit) { 638 | struct gbm_bo *next_bo; 639 | int waiting_for_flip = 1; 640 | 641 | draw(i++); 642 | 643 | eglSwapBuffers(gl.display, gl.surface); 644 | next_bo = gbm_surface_lock_front_buffer(gbm.surface); 645 | fb = drm_fb_get_from_bo(next_bo); 646 | 647 | /* 648 | * Here you could also update drm plane layers if you want 649 | * hw composition 650 | */ 651 | 652 | ret = drmModePageFlip(drm.fd, drm.crtc_id, fb->fb_id, 653 | DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip); 654 | if (ret) { 655 | fprintf(stderr,"failed to queue page flip: %s\n", strerror(errno)); 656 | return -1; 657 | } 658 | 659 | while (waiting_for_flip) { 660 | FD_ZERO(&fds); 661 | FD_SET(0, &fds); 662 | FD_SET(drm.fd, &fds); 663 | 664 | ret = select(drm.fd + 1, &fds, NULL, NULL, NULL); 665 | if (ret < 0) { 666 | fprintf(stderr,"select err: %s\n", strerror(errno)); 667 | return ret; 668 | } else if (ret == 0) { 669 | fprintf(stderr,"select timeout!\n"); 670 | return -1; 671 | } else if (FD_ISSET(0, &fds)) { 672 | fprintf(stderr,"user interrupted!\n"); 673 | quit = 1; 674 | break; 675 | } 676 | drmHandleEvent(drm.fd, &evctx); 677 | } 678 | 679 | /* release last buffer to render on again: */ 680 | gbm_surface_release_buffer(gbm.surface, bo); 681 | bo = next_bo; 682 | } 683 | quit_main_loop: 684 | 685 | ioctl(fd_tty, KDSETMODE, KD_TEXT); 686 | close(fd_tty); 687 | 688 | return ret; 689 | } 690 | --------------------------------------------------------------------------------