From 3e043d7885587181a08f6d2ebcbd04851aacb208 Mon Sep 17 00:00:00 2001
From: Tuomas Kulve <tuomas@kulve.fi>
Date: Mon, 27 Apr 2009 08:38:09 +0300
Subject: [PATCH] Initial Linux/X11 port.

---
 Common/Include/EGL/eglplatform.h   |   24 +++++
 Common/Include/Makefile.am         |    1 +
 Common/Include/esUtil.h            |   23 +++++-
 Common/Makefile.am                 |    1 +
 Common/Source/Linux/esUtil_TGA.c   |   23 +++++
 Common/Source/Linux/esUtil_linux.c |  176 ++++++++++++++++++++++++++++++++++++
 Common/Source/Makefile.am          |    7 ++
 Common/Source/esUtil.c             |  153 +++++++++++++++++++++++++++++--
 Makefile.am                        |    6 ++
 autogen.sh                         |    7 ++
 configure.ac                       |   19 ++++
 libes.pc.in                        |   10 ++
 12 files changed, 438 insertions(+), 12 deletions(-)
 create mode 100644 Common/Include/Makefile.am
 create mode 100644 Common/Makefile.am
 create mode 100644 Common/Source/Linux/esUtil_TGA.c
 create mode 100644 Common/Source/Linux/esUtil_linux.c
 create mode 100644 Common/Source/Makefile.am
 create mode 100644 Makefile.am
 create mode 100755 autogen.sh
 create mode 100644 configure.ac
 create mode 100644 libes.pc.in

diff --git a/Common/Include/EGL/eglplatform.h b/Common/Include/EGL/eglplatform.h
index 96a3da5..0b7f827 100644
--- a/Common/Include/EGL/eglplatform.h
+++ b/Common/Include/EGL/eglplatform.h
@@ -40,6 +40,28 @@
  * types, renamed in EGL 1.3 so all types in the API start with "EGL".
  */
 
+#if defined(__linux__)
+#if defined(EGLAPI)
+#undef EGLAPI
+#define EGLAPI
+#endif
+#if defined(EGLAPIENTRY)
+#undef EGLAPIENTRY
+#define EGLAPIENTRY
+#endif
+#       include <sys/types.h>
+#       if defined(SUPPORT_X11)
+#               include <X11/Xlib.h>
+                typedef Display*        EGLNativeDisplayType;
+                typedef Window          EGLNativeWindowType;
+                typedef Pixmap          EGLNativePixmapType;
+#       else
+                typedef int             EGLNativeDisplayType;
+                typedef void*   EGLNativeWindowType;
+                typedef void*   EGLNativePixmapType;
+#       endif
+#else
+
 #define NativeDisplayType HDC
 #define NativeWindowType  HWND
 #define NativePixmapType  HBITMAP
@@ -57,4 +79,6 @@ typedef NativeDisplayType EGLNativeDisplayType;
 typedef NativePixmapType EGLNativePixmapType;
 typedef NativeWindowType EGLNativeWindowType;
 
+#endif /* _linux__ */
+
 #endif /* __eglplatform_h */
diff --git a/Common/Include/Makefile.am b/Common/Include/Makefile.am
new file mode 100644
index 0000000..a5d9c80
--- /dev/null
+++ b/Common/Include/Makefile.am
@@ -0,0 +1 @@
+include_HEADERS = esUtil.h  esUtil_win.h
diff --git a/Common/Include/esUtil.h b/Common/Include/esUtil.h
index f1ab1bf..6b71238 100644
--- a/Common/Include/esUtil.h
+++ b/Common/Include/esUtil.h
@@ -23,6 +23,15 @@
 #include <GLES2/gl2.h>
 #include <EGL/egl.h>
 
+
+/* Example codes in Chapters use TRUE instead of GL_TRUE */
+#ifndef TRUE
+#define TRUE GL_TRUE
+#endif
+#ifndef FALSE
+#define FALSE GL_FALSE
+#endif
+
 #ifdef __cplusplus
 
 extern "C" {
@@ -32,9 +41,16 @@ extern "C" {
 ///
 //  Macros
 //
+#ifdef __linux__
+#define ESUTIL_API
+#define ESCALLBACK
+#include <stdlib.h>               /* malloc */
+#include <string.h>               /* memset */
+#include <stdarg.h>               /* v*printf */
+#else
 #define ESUTIL_API  __cdecl
 #define ESCALLBACK  __cdecl
-
+#endif
 
 /// esCreateWindow flag - RGB color buffer
 #define ES_WINDOW_RGB           0
@@ -71,6 +87,9 @@ typedef struct
    /// Window handle
    EGLNativeWindowType  hWnd;
 
+   // Native display
+   EGLNativeDisplayType  hDpy;
+
    /// EGL display
    EGLDisplay  eglDisplay;
       
@@ -271,4 +290,4 @@ void ESUTIL_API esMatrixLoadIdentity(ESMatrix *result);
 }
 #endif
 
-#endif // ESUTIL_H
\ No newline at end of file
+#endif // ESUTIL_H
diff --git a/Common/Makefile.am b/Common/Makefile.am
new file mode 100644
index 0000000..30b7568
--- /dev/null
+++ b/Common/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = Source Include
diff --git a/Common/Source/Linux/esUtil_TGA.c b/Common/Source/Linux/esUtil_TGA.c
new file mode 100644
index 0000000..e85707b
--- /dev/null
+++ b/Common/Source/Linux/esUtil_TGA.c
@@ -0,0 +1,23 @@
+//
+// Book:      OpenGL(R) ES 2.0 Programming Guide
+// Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// Modified from win version: Tuomas Kulve
+// ISBN-10:   0321502795
+// ISBN-13:   9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs:      http://safari.informit.com/9780321563835
+//            http://www.opengles-book.com
+//
+
+// esUtil_TGA.c
+//
+//    This file contains the Linux implementation of a TGA image loader
+
+
+///
+//  WinTGALoad()
+//
+int WinTGALoad( const char *fileName, char **buffer, int *width, int *height )
+{
+   return 0;
+}
diff --git a/Common/Source/Linux/esUtil_linux.c b/Common/Source/Linux/esUtil_linux.c
new file mode 100644
index 0000000..485fab2
--- /dev/null
+++ b/Common/Source/Linux/esUtil_linux.c
@@ -0,0 +1,176 @@
+//
+// Book:      OpenGL(R) ES 2.0 Programming Guide
+// Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// Modified from win version: Tuomas Kulve
+// ISBN-10:   0321502795
+// ISBN-13:   9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs:      http://safari.informit.com/9780321563835
+//            http://www.opengles-book.com
+//
+
+// esUtil_linux.c
+//
+//    This file contains the Linux implementation of the windowing functions. 
+
+
+///
+// Includes
+//
+#include <assert.h>            /* assert */
+#include <stdio.h>             /* *printf */
+#include <stdlib.h>            /* malloc */
+
+#include <EGL/egl.h>           /* EGL */
+#include <GLES2/gl2.h>         /* GL ES 2 */
+
+#include <X11/Xlib.h>          /* X11 */
+#include <X11/Xutil.h>
+
+#include "esUtil.h"
+#include "esUtil_win.h"
+
+//////////////////////////////////////////////////////////////////
+//
+//  Private Functions
+//
+//
+
+
+//////////////////////////////////////////////////////////////////
+//
+//  Public Functions
+//
+//
+
+///
+//  WinCreate()
+//
+//      Create X11 window
+//
+GLboolean WinCreate ( ESContext *esContext, const char *title )
+{
+  Display                *x11display;
+  Window                 x11window;
+  XSizeHints             sh;
+  int                    depth;
+  Atom                   wmDelete;  
+  long                   x11screen;
+  XVisualInfo*           x11visual  = NULL;
+  Colormap               x11colormap;
+  Window                 x11root;
+
+
+  x11display = XOpenDisplay(NULL);
+  if(!x11display) {
+	fprintf(stderr, "Failed to open DISPLAY\n");
+	return GL_FALSE;
+  }
+
+  x11display = x11display;
+
+  x11screen = XDefaultScreen(x11display);
+
+  depth = DefaultDepth(x11display, x11screen);
+
+  x11visual = malloc(sizeof(XVisualInfo));
+  assert(x11visual != NULL);
+  memset(x11visual, 0, sizeof(XVisualInfo));
+
+  XMatchVisualInfo(x11display, x11screen, depth, TrueColor, x11visual);
+
+  if (!x11visual) {
+	fprintf(stderr, "Failed to get visual\n");
+	return GL_FALSE;
+  }
+
+  x11colormap = XCreateColormap(x11display, 
+								RootWindow(x11display, x11screen),
+								x11visual->visual,
+								AllocNone);
+
+  x11root = DefaultRootWindow(x11display);
+  x11window = XCreateSimpleWindow(x11display,
+								  x11root,
+								  0, 0, esContext->width, esContext->height,
+								  0, 0,
+								  BlackPixel(x11display,
+											 x11screen));
+
+  XSelectInput(x11display, x11window, StructureNotifyMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask);
+  sh.x = 0;
+  sh.y = 0;
+  XSetStandardProperties(x11display, x11window,
+						 title, title, None, 0, 0, &sh);
+
+  XMapWindow(x11display, x11window);
+  wmDelete = XInternAtom(x11display, "WM_DELETE_WINDOW", True);
+  XSetWMProtocols(x11display, x11window, &wmDelete, 1);
+
+  XSetWMColormapWindows(x11display, x11window, &x11window, 1);
+
+  XFlush(x11display);
+
+
+  esContext->eglDisplay = (EGLDisplay)x11display;
+  esContext->hWnd = (EGLNativeWindowType)x11window;
+  esContext->hDpy = (EGLNativeDisplayType)x11display;
+
+  return GL_TRUE;
+}
+
+///
+//  winLoop()
+//
+//      Start main windows loop
+//
+void WinLoop ( ESContext *esContext )
+{
+  Display                *x11display;
+  KeyCode                quit_code;
+  XEvent                 xev;
+
+#if NOT_PORTED_YET
+  MSG msg = { 0 };
+  int done = 0;
+  DWORD lastTime = GetTickCount();
+#endif
+
+  x11display = (Display*)esContext->hDpy;
+  quit_code = XKeysymToKeycode(x11display, XK_q);
+
+  while(1) {
+	XNextEvent(x11display, &xev);
+	switch(xev.type) {
+	case KeyPress:
+	  {
+		XKeyEvent *kev = &xev.xkey;
+
+		/* Test for "quit" key */
+		if (kev->keycode == quit_code) {
+		  return;
+		}
+		break;
+	case Expose:
+	  {
+		XExposeEvent *eev = &xev.xexpose;
+
+		if (eev->count == 0) {
+                  if ( esContext->drawFunc != NULL ) {
+	              esContext->drawFunc (esContext);
+	          }
+		}
+	  }
+	  break;
+	  }
+	}
+  }
+
+#if NOT_PORTED_YET
+	// Call update function if registered
+	if ( esContext->updateFunc != NULL ) {
+	  esContext->updateFunc ( esContext, deltaTime );
+	}
+#endif	
+
+}
diff --git a/Common/Source/Makefile.am b/Common/Source/Makefile.am
new file mode 100644
index 0000000..0cefb49
--- /dev/null
+++ b/Common/Source/Makefile.am
@@ -0,0 +1,7 @@
+lib_LTLIBRARIES = libes.la
+
+libes_la_LIBADD = -lEGL -lGLESv2
+libes_la_SOURCES = esShader.c esShapes.c esTransform.c esUtil.c \
+					Linux/esUtil_linux.c Linux/esUtil_TGA.c
+libes_la_LDFLAGS = -L../../Lib
+libes_la_CFLAGS = -I../Include
diff --git a/Common/Source/esUtil.c b/Common/Source/esUtil.c
index fe774ae..0f3de0f 100644
--- a/Common/Source/esUtil.c
+++ b/Common/Source/esUtil.c
@@ -24,9 +24,113 @@
 #include <EGL/egl.h>
 #include "esUtil.h"
 #include "esUtil_win.h"
+#define DEBUG 1
+static void egl_print_config(EGLDisplay display, EGLConfig config);
+EGLBoolean CreateEGLContext ( EGLNativeWindowType hWnd, EGLDisplay* eglDisplay,
+                              EGLContext* eglContext, EGLSurface* eglSurface,
+                              EGLint attribList[]);
 
-
-
+/*
+* Print out one config
+ */
+void
+egl_print_config(EGLDisplay display, EGLConfig config)
+{
+  EGLint id;
+  EGLint r;
+  EGLint g;
+  EGLint b;
+  EGLint buf_type;
+  EGLint fb_level;
+  EGLint pbuffer_max_x = -1, pbuffer_max_y = -1, pbuffer_max_px = -1;
+  EGLint native_renderable = -1;
+
+  EGLint renderable_type = 0;
+  char renderable_type_str[256] = {0};
+  int renderable_type_i;
+
+  EGLint surface_type = 0;
+  char surface_type_str[256] = {0};
+  int surface_type_i;
+
+  eglGetConfigAttrib(display, config, EGL_CONFIG_ID, &id);
+  eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
+  eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
+  eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
+  eglGetConfigAttrib(display, config, EGL_COLOR_BUFFER_TYPE, &buf_type);
+  eglGetConfigAttrib(display, config, EGL_LEVEL, &fb_level);
+  eglGetConfigAttrib(display, config, EGL_MAX_PBUFFER_WIDTH,
+                                         &pbuffer_max_x);
+  eglGetConfigAttrib(display, config, EGL_MAX_PBUFFER_HEIGHT,
+                                         &pbuffer_max_y);
+  eglGetConfigAttrib(display, config, EGL_MAX_PBUFFER_PIXELS,
+                                         &pbuffer_max_px);
+  eglGetConfigAttrib(display, config, EGL_NATIVE_RENDERABLE,
+                                         &native_renderable);
+
+  /* Get renderable types */
+  renderable_type_i = 0;
+  eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE,
+                                         &renderable_type);
+
+  if (renderable_type & EGL_OPENGL_ES_BIT) {
+        renderable_type_i += snprintf(&renderable_type_str[renderable_type_i],
+                                                                  256 - renderable_type_i,
+                                                                  "EGL_OPENGL");
+  }
+
+  if (renderable_type & EGL_OPENGL_ES2_BIT) {
+        renderable_type_i += snprintf(&renderable_type_str[renderable_type_i],
+                                                                  256 - renderable_type_i,
+                                                                  "%sEGL_OPENGL_ES2",
+                                                                  renderable_type_i > 0 ? " | " : "");
+  }
+
+  if (renderable_type & EGL_OPENVG_BIT) {
+        renderable_type_i += snprintf(&renderable_type_str[renderable_type_i],
+                                                                  256 - renderable_type_i,
+                                                                  "%sEGL_OPENVG",
+                                                                  renderable_type_i > 0 ? " | " : "");
+  }
+
+  /* Get surface types */
+  surface_type_i = 0;
+  eglGetConfigAttrib(display, config, EGL_SURFACE_TYPE,
+                                         &surface_type);
+
+  if (surface_type & EGL_WINDOW_BIT) {
+        surface_type_i += snprintf(&surface_type_str[surface_type_i],
+                                                           256 - surface_type_i,
+                                                           "EGL_WINDOW");
+  }
+
+  if (surface_type & EGL_PIXMAP_BIT) {
+        surface_type_i += snprintf(&surface_type_str[surface_type_i],
+                                                           256 - surface_type_i,
+                                                           "%sEGL_PIXMAP",
+                                                           surface_type_i > 0 ? " | " : "");
+  }
+
+  if (surface_type & EGL_PBUFFER_BIT) {
+        surface_type_i += snprintf(&surface_type_str[surface_type_i],
+                                                           256 - surface_type_i,
+                                                           "%sEGL_PBUFFER",
+                                                           surface_type_i > 0 ? " | " : "");
+  }
+
+  esLogMessage("Configuration (ID %d):\n", id);
+
+  esLogMessage("\tR/G/B            : %d/%d/%d\n", r, g, b);
+  esLogMessage("\tColor buffer type: %s\n",
+           buf_type == EGL_RGB_BUFFER ? "RGB" : "Luminance");
+  esLogMessage("\tFramebuffer level: %d\n", fb_level);
+  esLogMessage("\tMax pbuffer      : %dx%d\n", pbuffer_max_x, pbuffer_max_y);
+  esLogMessage("\tMax pbuffer (px) : %d\n", pbuffer_max_px);
+  esLogMessage("\tNative renderable: %s\n", native_renderable ? "True" : "False");
+  esLogMessage("\tRenderable type  : %s\n", renderable_type_str);
+  esLogMessage("\tSurface type     : %s\n", surface_type_str);
+  esLogMessage("\n");
+}
 
 ///
 // CreateEGLContext()
@@ -43,11 +147,18 @@ EGLBoolean CreateEGLContext ( EGLNativeWindowType hWnd, EGLDisplay* eglDisplay,
    EGLDisplay display;
    EGLContext context;
    EGLSurface surface;
-   EGLConfig config;
+   EGLConfig config[20];
    EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
+#ifdef DEBUG
+   int i;
+#endif
 
    // Get Display
+#ifdef __linux__
+   display = eglGetDisplay((EGLNativeDisplayType)*eglDisplay);
+#else
    display = eglGetDisplay(GetDC(hWnd));
+#endif
    if ( display == EGL_NO_DISPLAY )
    {
       return EGL_FALSE;
@@ -60,28 +171,48 @@ EGLBoolean CreateEGLContext ( EGLNativeWindowType hWnd, EGLDisplay* eglDisplay,
    }
 
    // Get configs
-   if ( !eglGetConfigs(display, NULL, 0, &numConfigs) )
+   if ( !eglGetConfigs(display, config, 20, &numConfigs) )
    {
       return EGL_FALSE;
    }
+#ifdef DEBUG
+   for(i = 0; i < numConfigs; ++i) {
+     esLogMessage("config %d:\n", i);
+     egl_print_config(display, config[i]);
+   }
+#endif
 
    // Choose config
-   if ( !eglChooseConfig(display, attribList, &config, 1, &numConfigs) )
+   if ( !eglChooseConfig(display, attribList, config, 20, &numConfigs) )
    {
       return EGL_FALSE;
    }
-
+#ifdef DEBUG
+   for(i = 0; i < numConfigs; ++i) {
+     esLogMessage("config %d:\n", i);
+     egl_print_config(display, config[i]);
+   }
+#endif
    // Create a surface
-   surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)hWnd, NULL);
+   /* FIXME: use proper config instead of hard coded "5" */
+   if (numConfigs < 5) {
+      esLogMessage("%s: Using hard coded config number 5, but there are only %d configs\n",
+                   __FUNCTION__, numConfigs);
+      return EGL_FALSE;
+   }
+   surface = eglCreateWindowSurface(display, config[5], (EGLNativeWindowType)hWnd, NULL);
    if ( surface == EGL_NO_SURFACE )
    {
+      esLogMessage("%s: eglCreateWindowSurface failed: 0x%x\n", __FUNCTION__, eglGetError());
       return EGL_FALSE;
    }
 
    // Create a GL context
-   context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs );
+   /* FIXME: use proper config instead of hard coded "5" */
+   context = eglCreateContext(display, config[5], EGL_NO_CONTEXT, contextAttribs );
    if ( context == EGL_NO_CONTEXT )
    {
+      esLogMessage("%s: eglCreateContext failed: 0x%x\n", __FUNCTION__, eglGetError());
       return EGL_FALSE;
    }   
    
@@ -136,6 +267,7 @@ GLboolean ESUTIL_API esCreateWindow ( ESContext *esContext, const char* title, G
        EGL_RED_SIZE,       5,
        EGL_GREEN_SIZE,     6,
        EGL_BLUE_SIZE,      5,
+       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
        EGL_ALPHA_SIZE,     (flags & ES_WINDOW_ALPHA) ? 8 : EGL_DONT_CARE,
        EGL_DEPTH_SIZE,     (flags & ES_WINDOW_DEPTH) ? 8 : EGL_DONT_CARE,
        EGL_STENCIL_SIZE,   (flags & ES_WINDOW_STENCIL) ? 8 : EGL_DONT_CARE,
@@ -163,6 +295,7 @@ GLboolean ESUTIL_API esCreateWindow ( ESContext *esContext, const char* title, G
                             &esContext->eglSurface,
                             attribList) )
    {
+      esLogMessage("%s: CreateEGLContext failed\n", __FUNCTION__);
       return GL_FALSE;
    }
    
@@ -220,7 +353,7 @@ void ESUTIL_API esLogMessage ( const char *formatStr, ... )
     char buf[BUFSIZ];
 
     va_start ( params, formatStr );
-    vsprintf_s ( buf, sizeof(buf),  formatStr, params );
+    vsnprintf ( buf, sizeof(buf),  formatStr, params );
     
     printf ( "%s", buf );
     
@@ -243,4 +376,4 @@ char* ESUTIL_API esLoadTGA ( char *fileName, int *width, int *height )
    }
 
    return NULL;
-}
\ No newline at end of file
+}
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..e1508d2
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,6 @@
+EXTRA_DIST = autogen.sh libes.pc.in
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libes.pc
+
+SUBDIRS = Common
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..945eb94
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# hack
+touch NEWS README AUTHORS ChangeLog
+
+autoreconf -f -i
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..dd8f75d
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,19 @@
+AC_PREREQ(2.52)
+AC_INIT(libes, 0.1, tuomas@kulve.fi)
+AC_CONFIG_SRCDIR(Common/Source/esUtil.c)
+AM_CONFIG_HEADER(config.h)
+
+AM_INIT_AUTOMAKE
+
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+CFLAGS="$CFLAGS -Wall -g -Wmissing-prototypes -Wmissing-declarations -std=gnu99"
+
+AC_OUTPUT(
+libes.pc
+Makefile
+Common/Makefile
+Common/Source/Makefile
+Common/Include/Makefile
+)
diff --git a/libes.pc.in b/libes.pc.in
new file mode 100644
index 0000000..31d4b2e
--- /dev/null
+++ b/libes.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libes
+Description: libes from OpenGL(R) ES 2.0 Programming Guide
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Libs: -les -lEGL -lGLESv2 -lX11 -L${libdir}
-- 
1.5.6.5

