Add base Android and EGL code

git-svn-id: https://svn.code.sf.net/p/freeglut/code/trunk@1101 7f0cb862-5218-0410-a997-914c9d46530a
This commit is contained in:
beuc 2012-03-11 08:55:24 +00:00
parent cf7613066d
commit c8a8d03fc5
21 changed files with 2340 additions and 0 deletions

20
.gitattributes vendored
View File

@ -47,6 +47,8 @@ freeglut/freeglut/VisualStudio/2010/smooth_opengl3/smooth_opengl3.vcxproj -text
freeglut/freeglut/VisualStudio/2010/smooth_opengl3/smooth_opengl3.vcxproj.filters -text freeglut/freeglut/VisualStudio/2010/smooth_opengl3/smooth_opengl3.vcxproj.filters -text
freeglut/freeglut/VisualStudio/2010/subwin/subwin.vcxproj -text freeglut/freeglut/VisualStudio/2010/subwin/subwin.vcxproj -text
freeglut/freeglut/VisualStudio/2010/subwin/subwin.vcxproj.filters -text freeglut/freeglut/VisualStudio/2010/subwin/subwin.vcxproj.filters -text
freeglut/freeglut/android/Android.mk -text
freeglut/freeglut/android/README -text
freeglut/freeglut/autogen.sh svn_keywords=Author+Date+Id+Revision freeglut/freeglut/autogen.sh svn_keywords=Author+Date+Id+Revision
freeglut/freeglut/config.h.in svn_keywords=Author+Date+Id+Revision freeglut/freeglut/config.h.in svn_keywords=Author+Date+Id+Revision
freeglut/freeglut/configure.ac svn_keywords=Author+Date+Id+Revision freeglut/freeglut/configure.ac svn_keywords=Author+Date+Id+Revision
@ -156,6 +158,24 @@ freeglut/freeglut/src/Common/freeglutdll.def svn_keywords=Author+Date+Id+Revisio
freeglut/freeglut/src/Common/xparsegeometry_repl.c -text freeglut/freeglut/src/Common/xparsegeometry_repl.c -text
freeglut/freeglut/src/Common/xparsegeometry_repl.h -text freeglut/freeglut/src/Common/xparsegeometry_repl.h -text
freeglut/freeglut/src/Makefile.am svn_keywords=Author+Date+Id+Revision freeglut/freeglut/src/Makefile.am svn_keywords=Author+Date+Id+Revision
freeglut/freeglut/src/android/freeglut_gamemode_android.c -text
freeglut/freeglut/src/android/freeglut_input_devices_android.c -text
freeglut/freeglut/src/android/freeglut_internal_android.h -text
freeglut/freeglut/src/android/freeglut_joystick_android.c -text
freeglut/freeglut/src/android/freeglut_main_android.c -text
freeglut/freeglut/src/android/freeglut_runtime_android.c -text
freeglut/freeglut/src/android/freeglut_spaceball_android.c -text
freeglut/freeglut/src/android/freeglut_state_android.c -text
freeglut/freeglut/src/android/freeglut_window_android.c -text
freeglut/freeglut/src/android/native_app_glue/README -text
freeglut/freeglut/src/android/native_app_glue/android_native_app_glue.c -text
freeglut/freeglut/src/android/native_app_glue/android_native_app_glue.h -text
freeglut/freeglut/src/android/opengles_stubs.c -text
freeglut/freeglut/src/egl/freeglut_display_egl.c -text
freeglut/freeglut/src/egl/freeglut_init_egl.c -text
freeglut/freeglut/src/egl/freeglut_internal_egl.h -text
freeglut/freeglut/src/egl/freeglut_structure_egl.c -text
freeglut/freeglut/src/egl/freeglut_window_egl.c -text
freeglut/freeglut/src/mswin/freeglut_cursor_mswin.c svn_keywords=Author+Date+Id+Revision freeglut/freeglut/src/mswin/freeglut_cursor_mswin.c svn_keywords=Author+Date+Id+Revision
freeglut/freeglut/src/mswin/freeglut_display_mswin.c svn_keywords=Author+Date+Id+Revision freeglut/freeglut/src/mswin/freeglut_display_mswin.c svn_keywords=Author+Date+Id+Revision
freeglut/freeglut/src/mswin/freeglut_ext_mswin.c svn_keywords=Author+Date+Id+Revision freeglut/freeglut/src/mswin/freeglut_ext_mswin.c svn_keywords=Author+Date+Id+Revision

View File

@ -0,0 +1,9 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := freeglut
LOCAL_SRC_FILES := lib/libglut.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)

View File

@ -0,0 +1,2 @@
- Android.mk : used to create a module compatible with the NDK build
system. See ../README.android for details.

View File

@ -0,0 +1,57 @@
/*
* freeglut_gamemode_x11.c
*
* The game mode handling code.
*
* Copyright (C) 2012 Sylvain Beucler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <GL/freeglut.h>
#include "../Common/freeglut_internal.h"
/*
* Changes the current display mode to match user's settings
*/
GLboolean fgPlatformChangeDisplayMode( GLboolean haveToTest )
{
fprintf(stderr, "fgPlatformChangeDisplayMode: STUB\n");
return GL_FALSE;
}
void fgPlatformEnterGameMode( void )
{
fprintf(stderr, "fgPlatformEnterGameMode: STUB\n");
}
void fgPlatformRememberState( void )
{
fprintf(stderr, "fgPlatformRememberState: STUB\n");
}
void fgPlatformRestoreState( void )
{
fprintf(stderr, "fgPlatformRestoreState: STUB\n");
}
void fgPlatformLeaveGameMode( void )
{
fprintf(stderr, "fgPlatformLeaveGameMode: STUB\n");
}

View File

@ -0,0 +1,69 @@
/*
* freeglut_input_devices_android.c
*
* Handles miscellaneous input devices via direct serial-port access.
*
* Written by Joe Krahn <krahn@niehs.nih.gov> 2005
* Copyright (c) 2005 Stephen J. Baker. All Rights Reserved.
* Copied for Platform code by Evan Felix <karcaw at gmail.com>
* Copyright 2012 (C) Sylvain Beucler
* Creation date: Thur Feb 2 2012
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA OR STEPHEN J. BAKER BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <GL/freeglut.h>
#include "../Common/freeglut_internal.h"
typedef struct _serialport SERIALPORT;
/*
* Try initializing the input device(s)
*/
void fgPlatformRegisterDialDevice ( const char *dial_device )
{
fprintf(stderr, "fgPlatformRegisterDialDevice: STUB\n");
}
SERIALPORT *serial_open ( const char *device )
{
fprintf(stderr, "serial_open: STUB\n");
return NULL;
}
void serial_close(SERIALPORT *port)
{
fprintf(stderr, "serial_close: STUB\n");
}
int serial_getchar(SERIALPORT *port)
{
fprintf(stderr, "serial_getchar: STUB\n");
return EOF;
}
int serial_putchar(SERIALPORT *port, unsigned char ch)
{
fprintf(stderr, "serial_putchar: STUB\n");
return 0;
}
void serial_flush ( SERIALPORT *port )
{
fprintf(stderr, "serial_flush: STUB\n");
}

View File

@ -0,0 +1,86 @@
/*
* freeglut_internal_android.h
*
* The freeglut library private include file.
*
* Copyright (C) 2012 Sylvain Beucler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef FREEGLUT_INTERNAL_ANDROID_H
#define FREEGLUT_INTERNAL_ANDROID_H
/* -- PLATFORM-SPECIFIC INCLUDES ------------------------------------------- */
/* Android OpenGL ES is accessed through EGL */
#include "../egl/freeglut_internal_egl.h"
/**
* Virtual PAD (spots on touchscreen that simulate keys)
*/
struct vpad_state {
bool on;
bool left;
bool right;
bool up;
bool down;
};
struct touchscreen {
struct vpad_state vpad;
bool in_mmotion;
};
/* -- JOYSTICK-SPECIFIC STRUCTURES AND TYPES ------------------------------- */
/*
* Initial defines from "js.h" starting around line 33 with the existing "freeglut_joystick.c"
* interspersed
*/
/*
* We'll put these values in and that should
* allow the code to at least compile when there is
* no support. The JS open routine should error out
* and shut off all the code downstream anyway and if
* the application doesn't use a joystick we'll be fine.
*/
struct JS_DATA_TYPE
{
int buttons;
int x;
int y;
};
# define JS_RETURN (sizeof(struct JS_DATA_TYPE))
/* XXX It might be better to poll the operating system for the numbers of buttons and
* XXX axes and then dynamically allocate the arrays.
*/
# define _JS_MAX_AXES 16
typedef struct tagSFG_PlatformJoystick SFG_PlatformJoystick;
struct tagSFG_PlatformJoystick
{
struct JS_DATA_TYPE js;
char fname [ 128 ];
int fd;
};
#endif /* FREEGLUT_INTERNAL_ANDROID_H */

View File

@ -0,0 +1,50 @@
/*
* freeglut_joystick_android.c
*
* Joystick handling code
*
* Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
* Written by Steve Baker, <sjbaker1@airmail.net>
* Copied for Platform code by Evan Felix <karcaw at gmail.com>
* Copyright (C) 2012 Sylvain Beucler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <GL/freeglut.h>
#include "../Common/freeglut_internal.h"
void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
{
fprintf(stderr, "fgPlatformJoystickRawRead: STUB\n");
}
void fgPlatformJoystickOpen( SFG_Joystick* joy )
{
fprintf(stderr, "fgPlatformJoystickOpen: STUB\n");
}
void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
{
fprintf(stderr, "fgJoystick: STUB\n");
}
void fgPlatformJoystickClose ( int ident )
{
fprintf(stderr, "fgPlatformJoystickClose: STUB\n");
}

View File

@ -0,0 +1,403 @@
/*
* freeglut_main_android.c
*
* The Android-specific windows message processing methods.
*
* Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
* Written by Pawel W. Olszta, <olszta@sourceforge.net>
* Copied for Platform code by Evan Felix <karcaw at gmail.com>
* Copyright (C) 2012 Sylvain Beucler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <GL/freeglut.h>
#include "Common/freeglut_internal.h"
#include <android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "FreeGLUT", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "FreeGLUT", __VA_ARGS__))
#include <android/native_app_glue/android_native_app_glue.h>
#include <android/keycodes.h>
static struct touchscreen touchscreen;
static unsigned char key_a2fg[256];
/* Cf. http://developer.android.com/reference/android/view/KeyEvent.html */
/* These codes are missing in <android/keycodes.h> */
/* Don't convert to enum, since it may conflict with future version of
that <android/keycodes.h> */
#define AKEYCODE_FORWARD_DEL 112
#define AKEYCODE_CTRL_LEFT 113
#define AKEYCODE_CTRL_RIGHT 114
#define AKEYCODE_MOVE_HOME 122
#define AKEYCODE_MOVE_END 123
#define AKEYCODE_INSERT 124
#define AKEYCODE_ESCAPE 127
#define AKEYCODE_F1 131
#define AKEYCODE_F2 132
#define AKEYCODE_F3 133
#define AKEYCODE_F4 134
#define AKEYCODE_F5 135
#define AKEYCODE_F6 136
#define AKEYCODE_F7 137
#define AKEYCODE_F8 138
#define AKEYCODE_F9 139
#define AKEYCODE_F10 140
#define AKEYCODE_F11 141
#define AKEYCODE_F12 142
#define EVENT_HANDLED 1
#define EVENT_NOT_HANDLED 0
/**
* Initialize Android keycode to GLUT keycode mapping
*/
static void key_init() {
memset(key_a2fg, 0, sizeof(key_a2fg));
key_a2fg[AKEYCODE_F1] = GLUT_KEY_F1;
key_a2fg[AKEYCODE_F2] = GLUT_KEY_F2;
key_a2fg[AKEYCODE_F3] = GLUT_KEY_F3;
key_a2fg[AKEYCODE_F4] = GLUT_KEY_F4;
key_a2fg[AKEYCODE_F5] = GLUT_KEY_F5;
key_a2fg[AKEYCODE_F6] = GLUT_KEY_F6;
key_a2fg[AKEYCODE_F7] = GLUT_KEY_F7;
key_a2fg[AKEYCODE_F8] = GLUT_KEY_F8;
key_a2fg[AKEYCODE_F9] = GLUT_KEY_F9;
key_a2fg[AKEYCODE_F10] = GLUT_KEY_F10;
key_a2fg[AKEYCODE_F11] = GLUT_KEY_F11;
key_a2fg[AKEYCODE_F12] = GLUT_KEY_F12;
key_a2fg[AKEYCODE_PAGE_UP] = GLUT_KEY_PAGE_UP;
key_a2fg[AKEYCODE_PAGE_DOWN] = GLUT_KEY_PAGE_DOWN;
key_a2fg[AKEYCODE_MOVE_HOME] = GLUT_KEY_HOME;
key_a2fg[AKEYCODE_MOVE_END] = GLUT_KEY_END;
key_a2fg[AKEYCODE_INSERT] = GLUT_KEY_INSERT;
key_a2fg[AKEYCODE_DPAD_UP] = GLUT_KEY_UP;
key_a2fg[AKEYCODE_DPAD_DOWN] = GLUT_KEY_DOWN;
key_a2fg[AKEYCODE_DPAD_LEFT] = GLUT_KEY_LEFT;
key_a2fg[AKEYCODE_DPAD_RIGHT] = GLUT_KEY_RIGHT;
key_a2fg[AKEYCODE_ALT_LEFT] = GLUT_KEY_ALT_L;
key_a2fg[AKEYCODE_ALT_RIGHT] = GLUT_KEY_ALT_R;
key_a2fg[AKEYCODE_SHIFT_LEFT] = GLUT_KEY_SHIFT_L;
key_a2fg[AKEYCODE_SHIFT_RIGHT] = GLUT_KEY_SHIFT_R;
key_a2fg[AKEYCODE_CTRL_LEFT] = GLUT_KEY_CTRL_L;
key_a2fg[AKEYCODE_CTRL_RIGHT] = GLUT_KEY_CTRL_R;
}
/**
* Convert an Android key event to ASCII.
*/
static unsigned char key_ascii(struct android_app* app, AInputEvent* event) {
int32_t code = AKeyEvent_getKeyCode(event);
/* Handle a few special cases: */
switch (code) {
case AKEYCODE_DEL:
return 8;
case AKEYCODE_FORWARD_DEL:
return 127;
case AKEYCODE_ESCAPE:
return 27;
}
/* Get usable JNI context */
JNIEnv* env = app->activity->env;
JavaVM* vm = app->activity->vm;
(*vm)->AttachCurrentThread(vm, &env, NULL);
jclass KeyEventClass = (*env)->FindClass(env, "android/view/KeyEvent");
jmethodID KeyEventConstructor = (*env)->GetMethodID(env, KeyEventClass, "<init>", "(II)V");
jobject keyEvent = (*env)->NewObject(env, KeyEventClass, KeyEventConstructor,
AKeyEvent_getAction(event), AKeyEvent_getKeyCode(event));
jmethodID KeyEvent_getUnicodeChar = (*env)->GetMethodID(env, KeyEventClass, "getUnicodeChar", "(I)I");
int ascii = (*env)->CallIntMethod(env, keyEvent, KeyEvent_getUnicodeChar, AKeyEvent_getMetaState(event));
/* LOGI("getUnicodeChar(%d) = %d ('%c')", AKeyEvent_getKeyCode(event), ascii, ascii); */
return ascii;
}
/*
* Handle a window configuration change. When no reshape
* callback is hooked, the viewport size is updated to
* match the new window size.
*/
void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
{
fprintf(stderr, "fgPlatformReshapeWindow: STUB\n");
}
/*
* A static helper function to execute display callback for a window
*/
void fgPlatformDisplayWindow ( SFG_Window *window )
{
fghRedrawWindow ( window ) ;
}
unsigned long fgPlatformSystemTime ( void )
{
struct timeval now;
gettimeofday( &now, NULL );
return now.tv_usec/1000 + now.tv_sec*1000;
}
/*
* Does the magic required to relinquish the CPU until something interesting
* happens.
*/
void fgPlatformSleepForEvents( long msec )
{
/* fprintf(stderr, "fgPlatformSleepForEvents: STUB\n"); */
}
/**
* Process the next input event.
*/
int32_t handle_input(struct android_app* app, AInputEvent* event) {
SFG_Window* window = fgStructure.CurrentWindow;
/* FIXME: in Android, when key is repeated, down and up events
happen most often at the exact same time. This makes it
impossible to animate based on key press time. */
/* e.g. down/up/wait/down/up rather than down/wait/down/wait/up */
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
/* LOGI("action: %d", AKeyEvent_getAction(event)); */
/* LOGI("keycode: %d", code); */
int32_t code = AKeyEvent_getKeyCode(event);
if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) {
int32_t keypress = 0;
unsigned char ascii = 0;
if ((keypress = key_a2fg[code]) && FETCH_WCB(*window, Special)) {
INVOKE_WCB(*window, Special, (keypress, window->State.MouseX, window->State.MouseY));
return EVENT_HANDLED;
} else if ((ascii = key_ascii(app, event)) && FETCH_WCB(*window, Keyboard)) {
INVOKE_WCB(*window, Keyboard, (ascii, window->State.MouseX, window->State.MouseY));
return EVENT_HANDLED;
}
}
else if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_UP) {
int32_t keypress = 0;
unsigned char ascii = 0;
if ((keypress = key_a2fg[code]) && FETCH_WCB(*window, Special)) {
INVOKE_WCB(*window, SpecialUp, (keypress, window->State.MouseX, window->State.MouseY));
return EVENT_HANDLED;
} else if ((ascii = key_ascii(app, event)) && FETCH_WCB(*window, Keyboard)) {
INVOKE_WCB(*window, KeyboardUp, (ascii, window->State.MouseX, window->State.MouseY));
return EVENT_HANDLED;
}
}
}
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
int32_t action = AMotionEvent_getAction(event);
float x = AMotionEvent_getX(event, 0);
float y = AMotionEvent_getY(event, 0);
LOGI("motion %.01f,%.01f action=%d", x, y, AMotionEvent_getAction(event));
/* Virtual arrows PAD */
// Don't interfere with existing mouse move event
if (!touchscreen.in_mmotion) {
struct vpad_state prev_vpad = touchscreen.vpad;
touchscreen.vpad.left = touchscreen.vpad.right
= touchscreen.vpad.up = touchscreen.vpad.down = false;
int32_t width = ANativeWindow_getWidth(window->Window.Handle);
int32_t height = ANativeWindow_getHeight(window->Window.Handle);
if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE) {
if ((x > 0 && x < 100) && (y > (height - 100) && y < height))
touchscreen.vpad.left = true;
if ((x > 200 && x < 300) && (y > (height - 100) && y < height))
touchscreen.vpad.right = true;
if ((x > 100 && x < 200) && (y > (height - 100) && y < height))
touchscreen.vpad.down = true;
if ((x > 100 && x < 200) && (y > (height - 200) && y < (height - 100)))
touchscreen.vpad.up = true;
}
if (action == AMOTION_EVENT_ACTION_DOWN &&
(touchscreen.vpad.left || touchscreen.vpad.right || touchscreen.vpad.down || touchscreen.vpad.up))
touchscreen.vpad.on = true;
if (action == AMOTION_EVENT_ACTION_UP)
touchscreen.vpad.on = false;
if (prev_vpad.left != touchscreen.vpad.left
|| prev_vpad.right != touchscreen.vpad.right
|| prev_vpad.up != touchscreen.vpad.up
|| prev_vpad.down != touchscreen.vpad.down
|| prev_vpad.on != touchscreen.vpad.on) {
if (FETCH_WCB(*window, Special)) {
if (prev_vpad.left == false && touchscreen.vpad.left == true)
INVOKE_WCB(*window, Special, (GLUT_KEY_LEFT, x, y));
else if (prev_vpad.right == false && touchscreen.vpad.right == true)
INVOKE_WCB(*window, Special, (GLUT_KEY_RIGHT, x, y));
else if (prev_vpad.up == false && touchscreen.vpad.up == true)
INVOKE_WCB(*window, Special, (GLUT_KEY_UP, x, y));
else if (prev_vpad.down == false && touchscreen.vpad.down == true)
INVOKE_WCB(*window, Special, (GLUT_KEY_DOWN, x, y));
}
if (FETCH_WCB(*window, SpecialUp)) {
if (prev_vpad.left == true && touchscreen.vpad.left == false)
INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_LEFT, x, y));
if (prev_vpad.right == true && touchscreen.vpad.right == false)
INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_RIGHT, x, y));
if (prev_vpad.up == true && touchscreen.vpad.up == false)
INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_UP, x, y));
if (prev_vpad.down == true && touchscreen.vpad.down == false)
INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_DOWN, x, y));
}
return EVENT_HANDLED;
}
}
/* Normal mouse events */
if (!touchscreen.vpad.on) {
window->State.MouseX = x;
window->State.MouseY = y;
LOGI("Changed mouse position: %d,%d", x, y);
if (action == AMOTION_EVENT_ACTION_DOWN && FETCH_WCB(*window, Mouse)) {
touchscreen.in_mmotion = true;
INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, GLUT_DOWN, x, y));
} else if (action == AMOTION_EVENT_ACTION_UP && FETCH_WCB(*window, Mouse)) {
touchscreen.in_mmotion = false;
INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, GLUT_UP, x, y));
} else if (action == AMOTION_EVENT_ACTION_MOVE && FETCH_WCB(*window, Motion)) {
INVOKE_WCB(*window, Motion, (x, y));
}
}
return EVENT_HANDLED;
}
/* Let Android handle other events (e.g. Back and Menu buttons) */
return EVENT_NOT_HANDLED;
}
/**
* Process the next main command.
*/
void handle_cmd(struct android_app* app, int32_t cmd) {
switch (cmd) {
case APP_CMD_SAVE_STATE:
/* The system has asked us to save our current state. Do so. */
LOGI("handle_cmd: APP_CMD_SAVE_STATE");
break;
case APP_CMD_INIT_WINDOW:
/* The window is being shown, get it ready. */
LOGI("handle_cmd: APP_CMD_INIT_WINDOW");
fgDisplay.pDisplay.single_window->Window.Handle = app->window;
/* glPlatformOpenWindow was waiting for Handle to be defined and
will now return from fgPlatformProcessSingleEvent() */
break;
case APP_CMD_TERM_WINDOW:
/* The window is being hidden or closed, clean it up. */
LOGI("handle_cmd: APP_CMD_TERM_WINDOW");
fgDestroyWindow(fgDisplay.pDisplay.single_window);
break;
case APP_CMD_DESTROY:
/* Not reached because GLUT exit()s when last window is closed */
LOGI("handle_cmd: APP_CMD_DESTROY");
break;
case APP_CMD_GAINED_FOCUS:
LOGI("handle_cmd: APP_CMD_GAINED_FOCUS");
break;
case APP_CMD_LOST_FOCUS:
LOGI("handle_cmd: APP_CMD_LOST_FOCUS");
break;
case APP_CMD_CONFIG_CHANGED:
/* Handle rotation / orientation change */
LOGI("handle_cmd: APP_CMD_CONFIG_CHANGED");
break;
case APP_CMD_WINDOW_RESIZED:
LOGI("handle_cmd: APP_CMD_WINDOW_RESIZED");
if (fgDisplay.pDisplay.single_window->Window.pContext.eglSurface != EGL_NO_SURFACE)
/* Make ProcessSingleEvent detect the new size, only available
after the next SwapBuffer */
glutPostRedisplay();
break;
default:
LOGI("handle_cmd: unhandled cmd=%d", cmd);
}
}
void fgPlatformProcessSingleEvent ( void )
{
static int32_t last_width = -1;
static int32_t last_height = -1;
/* When the screen is resized, the window handle still points to the
old window until the next SwapBuffer, while it's crucial to set
the size (onShape) correctly before the next onDisplay callback.
Plus we don't know if the next SwapBuffer already occurred at the
time we process the event (e.g. during onDisplay). */
/* So we do the check each time rather than on event. */
/* Interestingly, on a Samsung Galaxy S/PowerVR SGX540 GPU/Android
2.3, that next SwapBuffer is fake (but still necessary to get the
new size). */
SFG_Window* window = fgDisplay.pDisplay.single_window;
if (window != NULL && window->Window.Handle != NULL) {
int32_t width = ANativeWindow_getWidth(window->Window.Handle);
int32_t height = ANativeWindow_getHeight(window->Window.Handle);
if (width != last_width || height != last_height) {
last_width = width;
last_height = height;
LOGI("width=%d, height=%d", width, height);
if( FETCH_WCB( *window, Reshape ) )
INVOKE_WCB( *window, Reshape, ( width, height ) );
else
glViewport( 0, 0, width, height );
glutPostRedisplay();
}
}
/* Read pending event. */
int ident;
int events;
struct android_poll_source* source;
/* This is called "ProcessSingleEvent" but this means we'd only
process ~60 (screen Hz) mouse events per second, plus other ports
are processing all events already. So let's process all pending
events. */
/* if ((ident=ALooper_pollOnce(0, NULL, &events, (void**)&source)) >= 0) { */
while ((ident=ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0) {
/* Process this event. */
if (source != NULL) {
source->process(source->app, source);
}
}
}
void fgPlatformMainLoopPreliminaryWork ( void )
{
printf("fgPlatformMainLoopPreliminaryWork\n");
key_init();
/* Make sure glue isn't stripped. */
/* JNI entry points need to be bundled even when linking statically */
app_dummy();
}
void fgPlatformDeinitialiseInputDevices ( void )
{
fprintf(stderr, "fgPlatformDeinitialiseInputDevices: STUB\n");
}

View File

@ -0,0 +1,160 @@
/*
* freeglut_runtime_android.c
*
* Android runtime
*
* Copyright (C) 2012 Sylvain Beucler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Parts taken from Android NDK's 'native-activity' sample : */
/*
* 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.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <jni.h>
#include <android/log.h>
#include <android/asset_manager.h>
#include <android/native_window.h>
#include "android/native_app_glue/android_native_app_glue.h"
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "FreeGLUT", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "FreeGLUT", __VA_ARGS__))
/* Cf. freeglut_main_android.c */
extern int32_t handle_input(struct android_app* app, AInputEvent* event);
extern void handle_cmd(struct android_app* app, int32_t cmd);
extern int main(int argc, char* argv[]);
/** NativeActivity Callbacks **/
/* Caution: they are called in the native_activity thread, not the
FreeGLUT thread. Use android_app_write_cmd. */
/* Could be used instead of onNativeWindowRedrawNeeded */
/* Deals with status bar presence */
static void onContentRectChanged(ANativeActivity* activity, const ARect* rect) {
LOGI("onContentRectChanged: l=%d,t=%d,r=%d,b=%d", rect->left, rect->top, rect->right, rect->bottom);
}
/* Bug: not called during a resize in android-9, only once on startup :/ */
static void onNativeWindowResized(ANativeActivity* activity, ANativeWindow* window) {
LOGI("onNativeWindowResized: %p\n", (void*)activity);
}
/* Called after a resize, compensate broken onNativeWindowResized */
static void onNativeWindowRedrawNeeded(ANativeActivity* activity, ANativeWindow* window) {
LOGI("onNativeWindowRedrawNeeded: %p\n", (void*)activity);
struct android_app* app = (struct android_app*)activity->instance;
//if (fgDisplay.pDisplay.single_window->Window.pContext.eglSurface != EGL_NO_SURFACE)
android_app_write_cmd(app, APP_CMD_WINDOW_RESIZED);
}
/**
* Extract all .apk assets to the application directory so they can be
* accessed using accessed.
* TODO: parse directories recursively
*/
static void extract_assets(struct android_app* app) {
/* Get usable JNI context */
JNIEnv* env = app->activity->env;
JavaVM* vm = app->activity->vm;
(*vm)->AttachCurrentThread(vm, &env, NULL);
{
/* Get a handle on our calling NativeActivity class */
jclass activityClass = (*env)->GetObjectClass(env, app->activity->clazz);
/* Get path to cache dir (/data/data/org.myapp/cache) */
jmethodID getCacheDir = (*env)->GetMethodID(env, activityClass, "getCacheDir", "()Ljava/io/File;");
jobject file = (*env)->CallObjectMethod(env, app->activity->clazz, getCacheDir);
jclass fileClass = (*env)->FindClass(env, "java/io/File");
jmethodID getAbsolutePath = (*env)->GetMethodID(env, fileClass, "getAbsolutePath", "()Ljava/lang/String;");
jstring jpath = (jstring)(*env)->CallObjectMethod(env, file, getAbsolutePath);
const char* app_dir = (*env)->GetStringUTFChars(env, jpath, NULL);
/* chdir in the application cache directory */
LOGI("app_dir: %s", app_dir);
chdir(app_dir);
(*env)->ReleaseStringUTFChars(env, jpath, app_dir);
/* Pre-extract assets, to avoid Android-specific file opening */
{
AAssetManager* mgr = app->activity->assetManager;
AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
const char* filename = (const char*)NULL;
while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {
AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);
char buf[BUFSIZ];
int nb_read = 0;
FILE* out = fopen(filename, "w");
while ((nb_read = AAsset_read(asset, buf, BUFSIZ)) > 0)
fwrite(buf, nb_read, 1, out);
fclose(out);
AAsset_close(asset);
}
AAssetDir_close(assetDir);
}
}
}
/**
* This is the main entry point of a native application that is using
* android_native_app_glue. It runs in its own thread, with its own
* event loop for receiving input events and doing other things.
*/
void android_main(struct android_app* app) {
LOGI("android_main");
// Register window resize callback
app->activity->callbacks->onNativeWindowResized = onNativeWindowResized;
app->activity->callbacks->onContentRectChanged = onContentRectChanged;
app->activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded;
app->onAppCmd = handle_cmd;
app->onInputEvent = handle_input;
extract_assets(app);
/* Call user's main */
{
char progname[5] = "self";
char* argv[] = {progname, NULL};
main(1, argv);
}
LOGI("android_main: end");
exit(0);
}

View File

@ -0,0 +1,58 @@
/*
* freeglut_spaceball_android.c
*
* Spaceball support for Windows
*
* Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.
* Written by Evan Felix <karcaw at gmail.com>
* Creation date: Sat Feb 4, 2012
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* This code is a very complicated way of doing nothing.
* But is needed for Android platform builds.
*/
#include <GL/freeglut.h>
#include "../Common/freeglut_internal.h"
void fgPlatformInitializeSpaceball(void)
{
return;
}
void fgPlatformSpaceballClose(void)
{
return;
}
int fgPlatformHasSpaceball(void)
{
return 0;
}
int fgPlatformSpaceballNumButtons(void)
{
return 0;
}
void fgPlatformSpaceballSetWindow(SFG_Window *window)
{
return;
}

View File

@ -0,0 +1,113 @@
/*
* freeglut_state_android.c
*
* Android-specific freeglut state query methods.
*
* Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.
* Written by John F. Fay, <fayjf@sourceforge.net>
* Copyright (C) 2012 Sylvain Beucler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <GL/freeglut.h>
#include "../Common/freeglut_internal.h"
#include <android/native_window.h>
int fgPlatformGlutGet ( GLenum eWhat )
{
fprintf(stderr, "fgPlatformGlutGet: STUB\n");
switch (eWhat) {
case GLUT_WINDOW_WIDTH:
case GLUT_WINDOW_HEIGHT:
{
if ( fgStructure.CurrentWindow == NULL )
return 0;
int32_t width = ANativeWindow_getWidth(fgStructure.CurrentWindow->Window.Handle);
int32_t height = ANativeWindow_getHeight(fgStructure.CurrentWindow->Window.Handle);
switch ( eWhat )
{
case GLUT_WINDOW_WIDTH:
return width;
case GLUT_WINDOW_HEIGHT:
return height;
}
}
}
return -1;
}
int fgPlatformGlutDeviceGet ( GLenum eWhat )
{
fprintf(stderr, "fgPlatformGlutDeviceGet: STUB\n");
return -1;
}
int fgPlatformGlutLayerGet( GLenum eWhat )
{
/*
* This is easy as layers are not implemented ;-)
*
* XXX Can we merge the UNIX/X11 and WIN32 sections? Or
* XXX is overlay support planned?
*/
switch( eWhat )
{
case GLUT_OVERLAY_POSSIBLE:
return 0;
case GLUT_LAYER_IN_USE:
return GLUT_NORMAL;
case GLUT_HAS_OVERLAY:
return 0;
case GLUT_TRANSPARENT_INDEX:
/*
* Return just anything, which is always defined as zero
*
* XXX HUH?
*/
return 0;
case GLUT_NORMAL_DAMAGED:
/* XXX Actually I do not know. Maybe. */
return 0;
case GLUT_OVERLAY_DAMAGED:
return -1;
default:
fgWarning( "glutLayerGet(): missing enum handle %d", eWhat );
break;
}
/* And fail. That's good. Programs do love failing. */
return -1;
}
int *fgPlatformGlutGetModeValues(GLenum eWhat, int *size)
{
fprintf(stderr, "fgPlatformGlutGetModeValues: STUB\n");
return NULL;
}

View File

@ -0,0 +1,165 @@
/*
* freeglut_window_android.c
*
* Window management methods for Android
*
* Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
* Written by Pawel W. Olszta, <olszta@sourceforge.net>
* Copied for Platform code by Evan Felix <karcaw at gmail.com>
* Copyright (C) 2012 Sylvain Beucler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define FREEGLUT_BUILDING_LIB
#include <GL/freeglut.h>
#include "../Common/freeglut_internal.h"
extern EGLSurface fghEGLPlatformOpenWindow( EGLNativeWindowType handle );
/*
* Opens a window. Requires a SFG_Window object created and attached
* to the freeglut structure. OpenGL context is created here.
*/
void fgPlatformOpenWindow( SFG_Window* window, const char* title,
GLboolean positionUse, int x, int y,
GLboolean sizeUse, int w, int h,
GLboolean gameMode, GLboolean isSubWindow )
{
printf("fgPlatformOpenWindow %p ID=%d\n", (void*)window, window->ID);
/* TODO: only one full-screen window possible? */
static int nb_windows = 0;
if (nb_windows == 0) {
nb_windows++;
fgDisplay.pDisplay.single_window = window;
printf("=> %p ID=%d\n", (void*)fgDisplay.pDisplay.single_window, fgDisplay.pDisplay.single_window->ID);
} else {
return;
}
/* Wait until window is available and OpenGL context is created */
/* Normally events are processed through glutMainLoop(), but the
user didn't call it yet, and the Android may not have initialized
the View yet. So we need to wait for that to happen. */
/* We can't return from this function before the OpenGL context is
properly made current with a valid surface. So we wait for the
surface. */
while (fgDisplay.pDisplay.single_window->Window.Handle == NULL) {
/* APP_CMD_INIT_WINDOW will do the job */
fgPlatformProcessSingleEvent();
}
EGLDisplay display = fgDisplay.pDisplay.eglDisplay;
EGLint format = fgDisplay.pDisplay.eglContextFormat;
ANativeWindow_setBuffersGeometry(window->Window.Handle, 0, 0, format);
window->Window.pContext.eglSurface = fghEGLPlatformOpenWindow(window->Window.Handle);
window->State.Visible = GL_TRUE;
}
void fgPlatformSetWindow ( SFG_Window *window )
{
/* TODO: only a single window possible? */
}
/*
* This function makes the current window visible
*/
void fgPlatformGlutShowWindow( void )
{
fprintf(stderr, "fgPlatformGlutShowWindow: STUB\n");
}
/*
* This function hides the current window
*/
void fgPlatformGlutHideWindow( void )
{
fprintf(stderr, "fgPlatformGlutHideWindow: STUB\n");
}
/*
* Iconify the current window (top-level windows only)
*/
void fgPlatformGlutIconifyWindow( void )
{
fprintf(stderr, "fgPlatformGlutIconifyWindow: STUB\n");
}
/*
* Set the current window's title
*/
void fgPlatformGlutSetWindowTitle( const char* title )
{
fprintf(stderr, "fgPlatformGlutSetWindowTitle: STUB\n");
}
/*
* Set the current window's iconified title
*/
void fgPlatformGlutSetIconTitle( const char* title )
{
fprintf(stderr, "fgPlatformGlutSetIconTitle: STUB\n");}
/*
* Change the current window's position
*/
void fgPlatformGlutPositionWindow( int x, int y )
{
fprintf(stderr, "fgPlatformGlutPositionWindow: STUB\n");
}
/*
* Lowers the current window (by Z order change)
*/
void fgPlatformGlutPushWindow( void )
{
fprintf(stderr, "fgPlatformGlutPushWindow: STUB\n");
}
/*
* Raises the current window (by Z order change)
*/
void fgPlatformGlutPopWindow( void )
{
fprintf(stderr, "fgPlatformGlutPopWindow: STUB\n");
}
/*
* Resize the current window so that it fits the whole screen
*/
void fgPlatformGlutFullScreen( SFG_Window *win )
{
fprintf(stderr, "fgPlatformGlutFullScreen: STUB\n");
}
/*
* If we are fullscreen, resize the current window back to its original size
*/
void fgPlatformGlutLeaveFullScreen( SFG_Window *win )
{
fprintf(stderr, "fgPlatformGlutLeaveFullScreen: STUB\n");
}
/*
* Toggle the window's full screen state.
*/
void fgPlatformGlutFullScreenToggle( SFG_Window *win )
{
fprintf(stderr, "fgPlatformGlutFullScreenToggle: STUB\n");
}

View File

@ -0,0 +1,7 @@
This code is copied from the Android NDK r7, from
source/android/native_app_glue/ .
A few GCC warnings were suppressed.
'android_app_write_cmd' was made non-static so that resize events can
be injected from FreeGLUT.

View File

@ -0,0 +1,436 @@
/*
* 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.
*
*/
#include <jni.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>
#include "android_native_app_glue.h"
#include <android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
static void free_saved_state(struct android_app* android_app) {
pthread_mutex_lock(&android_app->mutex);
if (android_app->savedState != NULL) {
free(android_app->savedState);
android_app->savedState = NULL;
android_app->savedStateSize = 0;
}
pthread_mutex_unlock(&android_app->mutex);
}
int8_t android_app_read_cmd(struct android_app* android_app) {
int8_t cmd;
if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {
switch (cmd) {
case APP_CMD_SAVE_STATE:
free_saved_state(android_app);
break;
}
return cmd;
} else {
LOGI("No data on command pipe!");
}
return -1;
}
static void print_cur_config(struct android_app* android_app) {
char lang[2], country[2];
AConfiguration_getLanguage(android_app->config, lang);
AConfiguration_getCountry(android_app->config, country);
LOGI("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
"keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
"modetype=%d modenight=%d",
AConfiguration_getMcc(android_app->config),
AConfiguration_getMnc(android_app->config),
lang[0], lang[1], country[0], country[1],
AConfiguration_getOrientation(android_app->config),
AConfiguration_getTouchscreen(android_app->config),
AConfiguration_getDensity(android_app->config),
AConfiguration_getKeyboard(android_app->config),
AConfiguration_getNavigation(android_app->config),
AConfiguration_getKeysHidden(android_app->config),
AConfiguration_getNavHidden(android_app->config),
AConfiguration_getSdkVersion(android_app->config),
AConfiguration_getScreenSize(android_app->config),
AConfiguration_getScreenLong(android_app->config),
AConfiguration_getUiModeType(android_app->config),
AConfiguration_getUiModeNight(android_app->config));
}
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {
switch (cmd) {
case APP_CMD_INPUT_CHANGED:
LOGI("APP_CMD_INPUT_CHANGED\n");
pthread_mutex_lock(&android_app->mutex);
if (android_app->inputQueue != NULL) {
AInputQueue_detachLooper(android_app->inputQueue);
}
android_app->inputQueue = android_app->pendingInputQueue;
if (android_app->inputQueue != NULL) {
LOGI("Attaching input queue to looper");
AInputQueue_attachLooper(android_app->inputQueue,
android_app->looper, LOOPER_ID_INPUT, NULL,
&android_app->inputPollSource);
}
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
break;
case APP_CMD_INIT_WINDOW:
LOGI("APP_CMD_INIT_WINDOW\n");
pthread_mutex_lock(&android_app->mutex);
android_app->window = android_app->pendingWindow;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
break;
case APP_CMD_TERM_WINDOW:
LOGI("APP_CMD_TERM_WINDOW\n");
pthread_cond_broadcast(&android_app->cond);
break;
case APP_CMD_RESUME:
case APP_CMD_START:
case APP_CMD_PAUSE:
case APP_CMD_STOP:
LOGI("activityState=%d\n", cmd);
pthread_mutex_lock(&android_app->mutex);
android_app->activityState = cmd;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
break;
case APP_CMD_CONFIG_CHANGED:
LOGI("APP_CMD_CONFIG_CHANGED\n");
AConfiguration_fromAssetManager(android_app->config,
android_app->activity->assetManager);
print_cur_config(android_app);
break;
case APP_CMD_DESTROY:
LOGI("APP_CMD_DESTROY\n");
android_app->destroyRequested = 1;
break;
}
}
void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) {
switch (cmd) {
case APP_CMD_TERM_WINDOW:
LOGI("APP_CMD_TERM_WINDOW\n");
pthread_mutex_lock(&android_app->mutex);
android_app->window = NULL;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
break;
case APP_CMD_SAVE_STATE:
LOGI("APP_CMD_SAVE_STATE\n");
pthread_mutex_lock(&android_app->mutex);
android_app->stateSaved = 1;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
break;
case APP_CMD_RESUME:
free_saved_state(android_app);
break;
}
}
void app_dummy() {
}
static void android_app_destroy(struct android_app* android_app) {
LOGI("android_app_destroy!");
free_saved_state(android_app);
pthread_mutex_lock(&android_app->mutex);
if (android_app->inputQueue != NULL) {
AInputQueue_detachLooper(android_app->inputQueue);
}
AConfiguration_delete(android_app->config);
android_app->destroyed = 1;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
/* // Can't touch android_app object after this. */
}
static void process_input(struct android_app* app, struct android_poll_source* source) {
AInputEvent* event = NULL;
if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
LOGI("New input event: type=%d\n", AInputEvent_getType(event));
if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
return;
}
{
int32_t handled = 0;
if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
AInputQueue_finishEvent(app->inputQueue, event, handled);
}
} else {
LOGI("Failure reading next input event: %s\n", strerror(errno));
}
}
static void process_cmd(struct android_app* app, struct android_poll_source* source) {
int8_t cmd = android_app_read_cmd(app);
android_app_pre_exec_cmd(app, cmd);
if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
android_app_post_exec_cmd(app, cmd);
}
static void* android_app_entry(void* param) {
struct android_app* android_app = (struct android_app*)param;
ALooper* looper;
android_app->config = AConfiguration_new();
AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
print_cur_config(android_app);
android_app->cmdPollSource.id = LOOPER_ID_MAIN;
android_app->cmdPollSource.app = android_app;
android_app->cmdPollSource.process = process_cmd;
android_app->inputPollSource.id = LOOPER_ID_INPUT;
android_app->inputPollSource.app = android_app;
android_app->inputPollSource.process = process_input;
looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
&android_app->cmdPollSource);
android_app->looper = looper;
pthread_mutex_lock(&android_app->mutex);
android_app->running = 1;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
android_main(android_app);
android_app_destroy(android_app);
return NULL;
}
/* // -------------------------------------------------------------------- */
/* // Native activity interaction (called from main thread) */
/* // -------------------------------------------------------------------- */
static struct android_app* android_app_create(ANativeActivity* activity,
void* savedState, size_t savedStateSize) {
struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
int msgpipe[2];
pthread_attr_t attr;
memset(android_app, 0, sizeof(struct android_app));
android_app->activity = activity;
pthread_mutex_init(&android_app->mutex, NULL);
pthread_cond_init(&android_app->cond, NULL);
if (savedState != NULL) {
android_app->savedState = malloc(savedStateSize);
android_app->savedStateSize = savedStateSize;
memcpy(android_app->savedState, savedState, savedStateSize);
}
if (pipe(msgpipe)) {
LOGI("could not create pipe: %s", strerror(errno));
}
android_app->msgread = msgpipe[0];
android_app->msgwrite = msgpipe[1];
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
/* // Wait for thread to start. */
pthread_mutex_lock(&android_app->mutex);
while (!android_app->running) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
pthread_mutex_unlock(&android_app->mutex);
return android_app;
}
/* static */void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
LOGI("Failure writing android_app cmd: %s\n", strerror(errno));
}
}
static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
pthread_mutex_lock(&android_app->mutex);
android_app->pendingInputQueue = inputQueue;
android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
while (android_app->inputQueue != android_app->pendingInputQueue) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
pthread_mutex_unlock(&android_app->mutex);
}
static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
pthread_mutex_lock(&android_app->mutex);
if (android_app->pendingWindow != NULL) {
android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
}
android_app->pendingWindow = window;
if (window != NULL) {
android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
}
while (android_app->window != android_app->pendingWindow) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
pthread_mutex_unlock(&android_app->mutex);
}
static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
pthread_mutex_lock(&android_app->mutex);
android_app_write_cmd(android_app, cmd);
while (android_app->activityState != cmd) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
pthread_mutex_unlock(&android_app->mutex);
}
static void android_app_free(struct android_app* android_app) {
pthread_mutex_lock(&android_app->mutex);
android_app_write_cmd(android_app, APP_CMD_DESTROY);
while (!android_app->destroyed) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
pthread_mutex_unlock(&android_app->mutex);
close(android_app->msgread);
close(android_app->msgwrite);
pthread_cond_destroy(&android_app->cond);
pthread_mutex_destroy(&android_app->mutex);
free(android_app);
}
static void onDestroy(ANativeActivity* activity) {
LOGI("Destroy: %p\n", (void*)activity);
android_app_free((struct android_app*)activity->instance);
}
static void onStart(ANativeActivity* activity) {
LOGI("Start: %p\n", (void*)activity);
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
}
static void onResume(ANativeActivity* activity) {
LOGI("Resume: %p\n", (void*)activity);
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
}
static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
struct android_app* android_app = (struct android_app*)activity->instance;
void* savedState = NULL;
LOGI("SaveInstanceState: %p\n", (void*)activity);
pthread_mutex_lock(&android_app->mutex);
android_app->stateSaved = 0;
android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
while (!android_app->stateSaved) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
if (android_app->savedState != NULL) {
savedState = android_app->savedState;
*outLen = android_app->savedStateSize;
android_app->savedState = NULL;
android_app->savedStateSize = 0;
}
pthread_mutex_unlock(&android_app->mutex);
return savedState;
}
static void onPause(ANativeActivity* activity) {
LOGI("Pause: %p\n", (void*)activity);
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
}
static void onStop(ANativeActivity* activity) {
LOGI("Stop: %p\n", (void*)activity);
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
}
static void onConfigurationChanged(ANativeActivity* activity) {
struct android_app* android_app = (struct android_app*)activity->instance;
LOGI("ConfigurationChanged: %p\n", (void*)activity);
android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
}
static void onLowMemory(ANativeActivity* activity) {
struct android_app* android_app = (struct android_app*)activity->instance;
LOGI("LowMemory: %p\n", (void*)activity);
android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
}
static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
LOGI("WindowFocusChanged: %p -- %d\n", (void*)activity, focused);
android_app_write_cmd((struct android_app*)activity->instance,
focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
}
static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
LOGI("NativeWindowCreated: %p -- %p\n", (void*)activity, (void*)window);
android_app_set_window((struct android_app*)activity->instance, window);
}
static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
LOGI("NativeWindowDestroyed: %p -- %p\n", (void*)activity, (void*)window);
android_app_set_window((struct android_app*)activity->instance, NULL);
}
static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
LOGI("InputQueueCreated: %p -- %p\n", (void*)activity, (void*)queue);
android_app_set_input((struct android_app*)activity->instance, queue);
}
static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
LOGI("InputQueueDestroyed: %p -- %p\n", (void*)activity, (void*)queue);
android_app_set_input((struct android_app*)activity->instance, NULL);
}
void ANativeActivity_onCreate(ANativeActivity* activity,
void* savedState, size_t savedStateSize) {
LOGI("Creating: %p\n", (void*)activity);
activity->callbacks->onDestroy = onDestroy;
activity->callbacks->onStart = onStart;
activity->callbacks->onResume = onResume;
activity->callbacks->onSaveInstanceState = onSaveInstanceState;
activity->callbacks->onPause = onPause;
activity->callbacks->onStop = onStop;
activity->callbacks->onConfigurationChanged = onConfigurationChanged;
activity->callbacks->onLowMemory = onLowMemory;
activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
activity->callbacks->onInputQueueCreated = onInputQueueCreated;
activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
activity->instance = android_app_create(activity, savedState, savedStateSize);
}

View File

@ -0,0 +1,349 @@
/*
* 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.
*
*/
#ifndef _ANDROID_NATIVE_APP_GLUE_H
#define _ANDROID_NATIVE_APP_GLUE_H
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <android/configuration.h>
#include <android/looper.h>
#include <android/native_activity.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* The native activity interface provided by <android/native_activity.h>
* is based on a set of application-provided callbacks that will be called
* by the Activity's main thread when certain events occur.
*
* This means that each one of this callbacks _should_ _not_ block, or they
* risk having the system force-close the application. This programming
* model is direct, lightweight, but constraining.
*
* The 'threaded_native_app' static library is used to provide a different
* execution model where the application can implement its own main event
* loop in a different thread instead. Here's how it works:
*
* 1/ The application must provide a function named "android_main()" that
* will be called when the activity is created, in a new thread that is
* distinct from the activity's main thread.
*
* 2/ android_main() receives a pointer to a valid "android_app" structure
* that contains references to other important objects, e.g. the
* ANativeActivity obejct instance the application is running in.
*
* 3/ the "android_app" object holds an ALooper instance that already
* listens to two important things:
*
* - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX
* declarations below.
*
* - input events coming from the AInputQueue attached to the activity.
*
* Each of these correspond to an ALooper identifier returned by
* ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT,
* respectively.
*
* Your application can use the same ALooper to listen to additional
* file-descriptors. They can either be callback based, or with return
* identifiers starting with LOOPER_ID_USER.
*
* 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event,
* the returned data will point to an android_poll_source structure. You
* can call the process() function on it, and fill in android_app->onAppCmd
* and android_app->onInputEvent to be called for your own processing
* of the event.
*
* Alternatively, you can call the low-level functions to read and process
* the data directly... look at the process_cmd() and process_input()
* implementations in the glue to see how to do this.
*
* See the sample named "native-activity" that comes with the NDK with a
* full usage example. Also look at the JavaDoc of NativeActivity.
*/
struct android_app;
/**
* Data associated with an ALooper fd that will be returned as the "outData"
* when that source has data ready.
*/
struct android_poll_source {
/* // The identifier of this source. May be LOOPER_ID_MAIN or */
/* // LOOPER_ID_INPUT. */
int32_t id;
/* // The android_app this ident is associated with. */
struct android_app* app;
/* // Function to call to perform the standard processing of data from */
/* // this source. */
void (*process)(struct android_app* app, struct android_poll_source* source);
};
/**
* This is the interface for the standard glue code of a threaded
* application. In this model, the application's code is running
* in its own thread separate from the main thread of the process.
* It is not required that this thread be associated with the Java
* VM, although it will need to be in order to make JNI calls any
* Java objects.
*/
struct android_app {
/* // The application can place a pointer to its own state object */
/* // here if it likes. */
void* userData;
/* // Fill this in with the function to process main app commands (APP_CMD_*) */
void (*onAppCmd)(struct android_app* app, int32_t cmd);
/* // Fill this in with the function to process input events. At this point */
/* // the event has already been pre-dispatched, and it will be finished upon */
/* // return. Return 1 if you have handled the event, 0 for any default */
/* // dispatching. */
int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
/* // The ANativeActivity object instance that this app is running in. */
ANativeActivity* activity;
/* // The current configuration the app is running in. */
AConfiguration* config;
/* // This is the last instance's saved state, as provided at creation time. */
/* // It is NULL if there was no state. You can use this as you need; the */
/* // memory will remain around until you call android_app_exec_cmd() for */
/* // APP_CMD_RESUME, at which point it will be freed and savedState set to NULL. */
/* // These variables should only be changed when processing a APP_CMD_SAVE_STATE, */
/* // at which point they will be initialized to NULL and you can malloc your */
/* // state and place the information here. In that case the memory will be */
/* // freed for you later. */
void* savedState;
size_t savedStateSize;
/* // The ALooper associated with the app's thread. */
ALooper* looper;
/* // When non-NULL, this is the input queue from which the app will */
/* // receive user input events. */
AInputQueue* inputQueue;
/* // When non-NULL, this is the window surface that the app can draw in. */
ANativeWindow* window;
/* // Current content rectangle of the window; this is the area where the */
/* // window's content should be placed to be seen by the user. */
ARect contentRect;
/* // Current state of the app's activity. May be either APP_CMD_START, */
/* // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. */
int activityState;
/* // This is non-zero when the application's NativeActivity is being */
/* // destroyed and waiting for the app thread to complete. */
int destroyRequested;
/* // ------------------------------------------------- */
/* // Below are "private" implementation of the glue code. */
pthread_mutex_t mutex;
pthread_cond_t cond;
int msgread;
int msgwrite;
pthread_t thread;
struct android_poll_source cmdPollSource;
struct android_poll_source inputPollSource;
int running;
int stateSaved;
int destroyed;
int redrawNeeded;
AInputQueue* pendingInputQueue;
ANativeWindow* pendingWindow;
ARect pendingContentRect;
};
enum {
/**
* Looper data ID of commands coming from the app's main thread, which
* is returned as an identifier from ALooper_pollOnce(). The data for this
* identifier is a pointer to an android_poll_source structure.
* These can be retrieved and processed with android_app_read_cmd()
* and android_app_exec_cmd().
*/
LOOPER_ID_MAIN = 1,
/**
* Looper data ID of events coming from the AInputQueue of the
* application's window, which is returned as an identifier from
* ALooper_pollOnce(). The data for this identifier is a pointer to an
* android_poll_source structure. These can be read via the inputQueue
* object of android_app.
*/
LOOPER_ID_INPUT = 2,
/**
* Start of user-defined ALooper identifiers.
*/
LOOPER_ID_USER = 3
};
enum {
/**
* Command from main thread: the AInputQueue has changed. Upon processing
* this command, android_app->inputQueue will be updated to the new queue
* (or NULL).
*/
APP_CMD_INPUT_CHANGED,
/**
* Command from main thread: a new ANativeWindow is ready for use. Upon
* receiving this command, android_app->window will contain the new window
* surface.
*/
APP_CMD_INIT_WINDOW,
/**
* Command from main thread: the existing ANativeWindow needs to be
* terminated. Upon receiving this command, android_app->window still
* contains the existing window; after calling android_app_exec_cmd
* it will be set to NULL.
*/
APP_CMD_TERM_WINDOW,
/**
* Command from main thread: the current ANativeWindow has been resized.
* Please redraw with its new size.
*/
APP_CMD_WINDOW_RESIZED,
/**
* Command from main thread: the system needs that the current ANativeWindow
* be redrawn. You should redraw the window before handing this to
* android_app_exec_cmd() in order to avoid transient drawing glitches.
*/
APP_CMD_WINDOW_REDRAW_NEEDED,
/**
* Command from main thread: the content area of the window has changed,
* such as from the soft input window being shown or hidden. You can
* find the new content rect in android_app::contentRect.
*/
APP_CMD_CONTENT_RECT_CHANGED,
/**
* Command from main thread: the app's activity window has gained
* input focus.
*/
APP_CMD_GAINED_FOCUS,
/**
* Command from main thread: the app's activity window has lost
* input focus.
*/
APP_CMD_LOST_FOCUS,
/**
* Command from main thread: the current device configuration has changed.
*/
APP_CMD_CONFIG_CHANGED,
/**
* Command from main thread: the system is running low on memory.
* Try to reduce your memory use.
*/
APP_CMD_LOW_MEMORY,
/**
* Command from main thread: the app's activity has been started.
*/
APP_CMD_START,
/**
* Command from main thread: the app's activity has been resumed.
*/
APP_CMD_RESUME,
/**
* Command from main thread: the app should generate a new saved state
* for itself, to restore from later if needed. If you have saved state,
* allocate it with malloc and place it in android_app.savedState with
* the size in android_app.savedStateSize. The will be freed for you
* later.
*/
APP_CMD_SAVE_STATE,
/**
* Command from main thread: the app's activity has been paused.
*/
APP_CMD_PAUSE,
/**
* Command from main thread: the app's activity has been stopped.
*/
APP_CMD_STOP,
/**
* Command from main thread: the app's activity is being destroyed,
* and waiting for the app thread to clean up and exit before proceeding.
*/
APP_CMD_DESTROY
};
/**
* Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next
* app command message.
*/
int8_t android_app_read_cmd(struct android_app* android_app);
/**
* Call with the command returned by android_app_read_cmd() to do the
* initial pre-processing of the given command. You can perform your own
* actions for the command after calling this function.
*/
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd);
/**
* Call with the command returned by android_app_read_cmd() to do the
* final post-processing of the given command. You must have done your own
* actions for the command before calling this function.
*/
void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd);
/**
* Dummy function you can call to ensure glue code isn't stripped.
*/
void app_dummy();
/**
* This is the function that application code must implement, representing
* the main entry to the app.
*/
extern void android_main(struct android_app* app);
#ifdef __cplusplus
}
#endif
#endif /* _ANDROID_NATIVE_APP_GLUE_H */

View File

@ -0,0 +1,9 @@
#include <GL/freeglut.h>
#include "../Common/freeglut_internal.h"
void fgDeactivateMenu( SFG_Window *window ) {
fprintf(stderr, "fgDeactivateMenu: STUB\n");
}
void fgDisplayMenu( void ) {
fprintf(stderr, "fgDisplayMenu: STUB\n");
}

View File

@ -0,0 +1,36 @@
/*
* freeglut_display_android.c
*
* Display message posting, context buffer swapping.
*
* Copyright (C) 2012 Sylvain Beucler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <GL/freeglut.h>
#include "../Common/freeglut_internal.h"
#include <android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "FreeGLUT", __VA_ARGS__))
void fgPlatformGlutSwapBuffers( SFG_PlatformDisplay *pDisplayPtr, SFG_Window* CurrentWindow )
{
/* LOGI("Swap!"); */
eglSwapBuffers( pDisplayPtr->eglDisplay, CurrentWindow->Window.pContext.eglSurface );
}

View File

@ -0,0 +1,80 @@
/*
* freeglut_init_android.c
*
* Various freeglut initialization functions.
*
* Copyright (C) 2012 Sylvain Beucler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define FREEGLUT_BUILDING_LIB
#include <GL/freeglut.h>
#include "../Common/freeglut_internal.h"
#include <android/native_app_glue/android_native_app_glue.h>
/*
* A call to this function should initialize all the display stuff...
*/
void fgPlatformInitialize( const char* displayName )
{
fprintf(stderr, "fgPlatformInitialize\n");
fgState.Initialised = GL_TRUE;
/* CreateDisplay */
/* Using EGL_DEFAULT_DISPLAY, or a specific native display */
EGLNativeDisplayType nativeDisplay = EGL_DEFAULT_DISPLAY;
fgDisplay.pDisplay.eglDisplay = eglGetDisplay(nativeDisplay);
FREEGLUT_INTERNAL_ERROR_EXIT(fgDisplay.pDisplay.eglDisplay != EGL_NO_DISPLAY,
"No display available", "fgPlatformInitialize");
if (!eglInitialize(fgDisplay.pDisplay.eglDisplay, NULL, NULL))
fgError("eglInitialize: error %x\n", eglGetError());
/* CreateContext */
fghCreateContext();
// fgDisplay.ScreenWidth = ...;
// fgDisplay.ScreenHeight = ...;
// fgDisplay.ScreenWidthMM = ...;
// fgDisplay.ScreenHeightMM = ...;
}
void fgPlatformCloseDisplay ( void )
{
eglMakeCurrent(fgDisplay.pDisplay.eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (fgDisplay.pDisplay.eglContext != EGL_NO_CONTEXT) {
eglDestroyContext(fgDisplay.pDisplay.eglDisplay, fgDisplay.pDisplay.eglContext);
fgDisplay.pDisplay.eglContext = EGL_NO_CONTEXT;
}
if (fgDisplay.pDisplay.eglDisplay != EGL_NO_DISPLAY) {
eglTerminate(fgDisplay.pDisplay.eglDisplay);
fgDisplay.pDisplay.eglDisplay = EGL_NO_DISPLAY;
}
}
/**
* Destroy a menu context
*/
void fgPlatformDestroyContext ( SFG_PlatformDisplay pDisplay, SFG_WindowContextType MContext )
{
if (MContext != EGL_NO_CONTEXT)
eglDestroyContext(pDisplay.eglDisplay, MContext);
}

View File

@ -0,0 +1,68 @@
/*
* freeglut_internal_android.h
*
* The freeglut library private include file.
*
* Copyright (C) 2012 Sylvain Beucler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef FREEGLUT_INTERNAL_EGL_H
#define FREEGLUT_INTERNAL_EGL_H
#include <EGL/egl.h>
/* -- GLOBAL TYPE DEFINITIONS ---------------------------------------------- */
/* The structure used by display initialization in freeglut_init.c */
typedef struct tagSFG_PlatformDisplay SFG_PlatformDisplay;
struct tagSFG_Window;
struct tagSFG_PlatformDisplay
{
/* Used to initialize and deinitialize EGL */
EGLDisplay eglDisplay;
EGLContext eglContext;
EGLConfig eglContextConfig;
EGLint eglContextFormat;
struct tagSFG_Window* single_window;
};
/*
* Make "freeglut" window handle and context types so that we don't need so
* much conditionally-compiled code later in the library.
*/
typedef EGLNativeWindowType SFG_WindowHandleType ;
typedef EGLContext SFG_WindowContextType ;
typedef struct tagSFG_PlatformContext SFG_PlatformContext;
/* SFG_PlatformContext is used for SFG_Window.Window */
struct tagSFG_PlatformContext
{
EGLSurface eglSurface;
};
/* Window's state description. This structure should be kept portable. */
typedef struct tagSFG_PlatformWindowState SFG_PlatformWindowState;
struct tagSFG_PlatformWindowState
{
int OldWidth; /* Window width from before a resize */
int OldHeight; /* " height " " " " */
};
#endif

View File

@ -0,0 +1,34 @@
/*
* freeglut_structure_egl.c
*
* Windows and menus need tree structure
*
* Copyright (C) 2012 Sylvain Beucler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <GL/freeglut.h>
#include "../Common/freeglut_internal.h"
extern SFG_Structure fgStructure;
void fgPlatformCreateWindow ( SFG_Window *window )
{
window->Window.pContext.eglSurface = EGL_NO_SURFACE;
}

View File

@ -0,0 +1,129 @@
/*
* freeglut_display_android.c
*
* Window management methods for EGL
*
* Copyright (C) 2012 Sylvain Beucler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <GL/freeglut.h>
#include "../Common/freeglut_internal.h"
/**
* Initialize an EGL context for the current display.
*/
void fghCreateContext( ) {
/*
* Here specify the attributes of the desired configuration.
* Below, we select an EGLConfig with at least 8 bits per color
* component compatible with on-screen windows
*/
/* Ensure OpenGLES 2.0 context */
printf("DisplayMode: %d (DEPTH %d)\n", fgState.DisplayMode, (fgState.DisplayMode & GLUT_DEPTH));
const EGLint attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_BLUE_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_RED_SIZE, 1,
EGL_ALPHA_SIZE, (fgState.DisplayMode & GLUT_ALPHA) ? 1 : 0,
EGL_DEPTH_SIZE, (fgState.DisplayMode & GLUT_DEPTH) ? 1 : 0,
EGL_STENCIL_SIZE, (fgState.DisplayMode & GLUT_STENCIL) ? 1 : 0,
EGL_SAMPLE_BUFFERS, (fgState.DisplayMode & GLUT_MULTISAMPLE) ? 1 : 0,
EGL_SAMPLES, (fgState.DisplayMode & GLUT_MULTISAMPLE) ? fgState.SampleNumber : 0,
EGL_NONE
};
EGLint format;
EGLint numConfigs;
EGLConfig config;
EGLContext context;
EGLDisplay eglDisplay = fgDisplay.pDisplay.eglDisplay;
/* TODO : apply DisplayMode */
/* (GLUT_DEPTH already applied in attribs[] above) */
/* Here, the application chooses the configuration it desires. In this
* sample, we have a very simplified selection process, where we pick
* the first EGLConfig that matches our criteria */
eglChooseConfig(eglDisplay, attribs, &config, 1, &numConfigs);
/* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
* guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
* As soon as we picked a EGLConfig, we can safely reconfigure the
* ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
eglGetConfigAttrib(eglDisplay, config, EGL_NATIVE_VISUAL_ID, &format);
/* Default, but doesn't hurt */
eglBindAPI(EGL_OPENGL_ES_API);
/* Ensure OpenGLES 2.0 context */
static const EGLint ctx_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
context = eglCreateContext(eglDisplay, config, EGL_NO_CONTEXT, ctx_attribs);
if (context == EGL_NO_CONTEXT) {
fgWarning("Cannot initialize EGL context, err=%x\n", eglGetError());
fghContextCreationError();
}
EGLint ver = -1;
eglQueryContext(fgDisplay.pDisplay.eglDisplay, context, EGL_CONTEXT_CLIENT_VERSION, &ver);
if (ver != 2)
fgError("Wrong GLES major version: %d\n", ver);
fgDisplay.pDisplay.eglContext = context;
fgDisplay.pDisplay.eglContextConfig = config;
fgDisplay.pDisplay.eglContextFormat = format;
}
/*
* Really opens a window when handle is available
*/
EGLSurface fghEGLPlatformOpenWindow( EGLNativeWindowType handle )
{
EGLDisplay display = fgDisplay.pDisplay.eglDisplay;
EGLContext context = fgDisplay.pDisplay.eglContext;
EGLConfig config = fgDisplay.pDisplay.eglContextConfig;
EGLSurface surface = eglCreateWindowSurface(display, config, handle, NULL);
if (surface == EGL_NO_SURFACE)
fgError("Cannot create EGL window surface, err=%x\n", eglGetError());
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
fgError("eglMakeCurrent: err=%x\n", eglGetError());
//EGLint w, h;
//eglQuerySurface(display, surface, EGL_WIDTH, &w);
//eglQuerySurface(display, surface, EGL_HEIGHT, &h);
return surface;
}
/*
* Closes a window, destroying the frame and OpenGL context
*/
void fgPlatformCloseWindow( SFG_Window* window )
{
if (window->Window.pContext.eglSurface != EGL_NO_SURFACE) {
eglDestroySurface(fgDisplay.pDisplay.eglDisplay, window->Window.pContext.eglSurface);
window->Window.pContext.eglSurface = EGL_NO_SURFACE;
}
}