📄 glcanvasmodule.cpp
字号:
/**
* ====================================================================
* glcanvasmodule.cpp
*
* Copyright (c) 2006 - 2007 Nokia Corporation
*
* 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 "glcanvas.h"
/* EGL 1.1 enumeration */
#ifndef EGL_VERSION_1_1
#define EGL_CONTEXT_LOST 0x300E
#define EGL_BIND_TO_TEXTURE_RGB 0x3039
#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
#define EGL_MIN_SWAP_INTERVAL 0x303B
#define EGL_MAX_SWAP_INTERVAL 0x303C
#define EGL_BACK_BUFFER 0x3084
#endif
/**
* Implementation of GLCanvas
*
* A big part of the implementation has been copied from
* the original Canvas object implementation in
* appui/appuifw/appuifwmodule.cpp
*
*/
CGLCanvas::CGLCanvas(PyObject *aDrawCallback, PyObject *aEventCallback, PyObject *aResizeCallback) {
iDrawCallback = aDrawCallback;
iEventCallback = aEventCallback;
iResizeCallback = aResizeCallback;
iOpenGLInitialized = 0;
}
void CGLCanvas::ConstructL(const TRect& aRect, const CCoeControl* aParent) {
CreateWindowL(aParent);
SetRect(aRect);
ActivateL();
#ifdef DEBUG_GLCANVAS
DEBUGMSG2("aRect Size: %d x %d", aRect.Size().iWidth, aRect.Size().iHeight);
DEBUGMSG2("aRect PosX: %d PosY: %d", aRect.iTl.iX, aRect.iTl.iY);
#endif
}
CGLCanvas::~CGLCanvas() {
#ifdef DEBUG_GLCANVAS
DEBUGMSG("CGLCanvas destructor");
#endif
eglMakeCurrent( iEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
eglDestroySurface( iEglDisplay, iEglSurface );
eglDestroyContext( iEglDisplay, iEglContext );
// Release resources associated
// with EGL and OpenGL ES
eglTerminate( iEglDisplay );
}
TKeyResponse CGLCanvas::OfferKeyEventL(const TKeyEvent& aKeyEvent,
TEventCode aType) {
PyObject *arg=NULL, *ret=NULL;
CCoeControl::OfferKeyEventL(aKeyEvent,aType);
if (!iEventCallback)
return EKeyWasNotConsumed;
PyEval_RestoreThread(PYTHON_TLS->thread_state);
arg=Py_BuildValue("({s:i,s:i,s:i,s:i})",
"type",aType,
"keycode",aKeyEvent.iCode,
"scancode", aKeyEvent.iScanCode,
"modifiers", aKeyEvent.iModifiers);
if (!arg)
goto error;
ret=PyEval_CallObject(iEventCallback,arg);
Py_DECREF(arg);
if (!ret)
goto error;
Py_DECREF(ret);
PyEval_SaveThread();
return EKeyWasNotConsumed;
error:
PyErr_Print();
PyEval_SaveThread();
return EKeyWasNotConsumed;
}
/**
* Creates a new EGL rendering context on screen. Sets a Python exception if
* the operation fails.
*
* @param attrib_list An array of desired attributes.
* @return 1 on success, 0 on failure.
*/
int CGLCanvas::CreateContext(EGLint *attrib_list) {
#ifdef DEBUG_GLCANVAS
DEBUGMSG("CGLCanvas::CreateContext\n");
#endif
assert(attrib_list != NULL);
// Initialize frame counter
iFrame = 0;
// Describes the format, type and
// size of the color buffers and
// ancillary buffers for EGLSurface
EGLConfig Config;
// Get the display for drawing graphics
iEglDisplay = eglGetDisplay( EGL_DEFAULT_DISPLAY );
if ( iEglDisplay == NULL )
{
PyErr_Format(PyExc_RuntimeError, "eglGetDisplay failed [Errno %d]", eglGetError());
return NULL;
}
// Initialize display
if ( eglInitialize( iEglDisplay, NULL, NULL ) == EGL_FALSE )
{
PyErr_Format(PyExc_RuntimeError, "eglInitialize [Errno %d, disp: %x]", eglGetError(), iEglDisplay);
return NULL;
}
// Pointer for EGLConfigs
EGLConfig *configList = NULL;
EGLint numOfConfigs = 0;
EGLint configSize = 0;
// Get the number of possible EGLConfigs
if ( eglGetConfigs( iEglDisplay, configList, configSize, &numOfConfigs )
== EGL_FALSE )
{
PyErr_Format(PyExc_ValueError, "eglGetConfigs failed [Errno %d]", eglGetError());
return NULL;
}
configSize = numOfConfigs;
// Allocate memory for the configList
configList = (EGLConfig*) glcanvas_alloc( sizeof(EGLConfig)*configSize );
if ( configList == NULL )
{
PyErr_SetString(PyExc_ValueError, "Config alloc failed");
return NULL;
}
/* Define properties for the wanted EGLSurface.
To get the best possible performance, choose
an EGLConfig with a buffersize matching
the current window's display mode*/
// Choose an EGLConfig that best matches to the properties in attrib_list
if ( eglChooseConfig( iEglDisplay, attrib_list, configList, configSize,
&numOfConfigs ) == EGL_FALSE )
{
glcanvas_free(configList);
PyErr_Format(PyExc_TypeError, "No matching configuration found. [Errno %d]", eglGetError());
return NULL;
}
// Choose the best EGLConfig. EGLConfigs
// returned by eglChooseConfig are sorted so
// that the best matching EGLConfig is first in
// the list.
Config = configList[0];
// Free configList, not used anymore.
glcanvas_free( configList );
// Create a window where the graphics are blitted
iEglSurface = eglCreateWindowSurface( iEglDisplay, Config, &Window(), NULL );
if ( iEglSurface == NULL )
{
PyErr_Format(PyExc_RuntimeError, "eglCreateWindowSurface failed [Errno %d]", eglGetError());
return NULL;
}
// Create a rendering context
iEglContext = eglCreateContext( iEglDisplay, Config, EGL_NO_CONTEXT, NULL );
if ( iEglContext == NULL )
{
PyErr_Format(PyExc_RuntimeError, "eglCreateContext failed [Errno %d]", eglGetError());
return NULL;
}
/* Make the context current. Binds context to the current rendering thread
and surface.*/
if ( eglMakeCurrent( iEglDisplay, iEglSurface, iEglSurface, iEglContext )
== EGL_FALSE )
{
PyErr_Format(PyExc_RuntimeError, "eglMakeCurrent failed [Errno %d]", eglGetError());
return NULL;
}
iOpenGLInitialized = 1;
return 1;
}
void CGLCanvas::makeCurrent() {
/* Make the context current. Binds context to the current rendering thread
and surface.*/
if ( eglMakeCurrent( iEglDisplay, iEglSurface, iEglSurface, iEglContext )
== EGL_FALSE )
{
PyErr_SetString(PyExc_RuntimeError, "eglMakeCurrent failed");
return;
}
return;
}
PyObject *CGLCanvas::GetRedrawCallBack() {
return iDrawCallback;
}
PyObject *CGLCanvas::GetEventCallBack() {
return iEventCallback;
}
PyObject *CGLCanvas::GetResizeCallBack() {
return iResizeCallback;
}
void CGLCanvas::SetRedrawCallBack(PyObject *cb) {
if(PyCallable_Check(cb) ) {
Py_XINCREF(cb);
} else if(cb == Py_None) {
cb = NULL;
} else {
PyErr_SetString(PyExc_TypeError, "Callable of None expected");
return;
}
if(iDrawCallback) {
Py_XDECREF(iDrawCallback);
}
iDrawCallback = cb;
return;
}
void CGLCanvas::SetEventCallBack(PyObject *cb) {
if(PyCallable_Check(cb) ) {
Py_XINCREF(cb);
} else if(cb == Py_None) {
cb = NULL;
} else {
PyErr_SetString(PyExc_TypeError, "Callable of None expected");
return;
}
if(iEventCallback) {
Py_XDECREF(iEventCallback);
}
iEventCallback = cb;
return;
}
void CGLCanvas::SetResizeCallBack(PyObject *cb) {
if(PyCallable_Check(cb) ) {
Py_XINCREF(cb);
} else if(cb == Py_None) {
cb = NULL;
} else {
PyErr_SetString(PyExc_TypeError, "Callable of None expected");
return;
}
if(iResizeCallback) {
Py_XDECREF(iResizeCallback);
}
iResizeCallback = cb;
return;
}
/**
* Returns the buffer size for current display mode
*
* @return Buffer size in bits
*/
int CGLCanvas::GetBufferSize() {
TDisplayMode DMode = Window().DisplayMode();
int BufferSize = 0;
#ifdef DEBUG_GLCANVAS
DEBUGMSG1("DMode = %x", DMode);
#endif
switch ( DMode ) {
case(EColor4K):
BufferSize = 12;
break;
case(EColor64K):
BufferSize = 16;
break;
case(EColor16M):
BufferSize = 24;
break;
#if SERIES60_VERSION >= 28
case(EColor16MA):
BufferSize = 32;
break;
#endif
case(EColor16MU):
BufferSize = 32;
break;
default:
return -1;
}
return BufferSize;
}
/* FIXME This method is declared const so it should not alter the
state of the object, but arbitrary code execution is allowed in the
Python callback. This could lead to trouble if the GLCanvas is
altered there. Maybe we should switch to double buffering completely or
invoke the callback via a callgate? */
void CGLCanvas::Draw(const TRect& /*aRect*/) const {
#ifdef DEBUG_GLCANVAS
DEBUGMSG("GLCanvas::Draw");
DEBUGMSG1("Frame: %d", iFrame);
#endif
// This fails on the emulator
#ifndef __WINS__
redraw();
#endif
}
void CGLCanvas::redraw() const {
if( !iOpenGLInitialized ) {
return;
}
if (iDrawCallback) {
int in_interpreter=(_PyThreadState_Current == PYTHON_TLS->thread_state);
if (!in_interpreter)
PyEval_RestoreThread(PYTHON_TLS->thread_state);
PyObject *frame = Py_BuildValue("(i)", iFrame);
app_callback_handler(iDrawCallback,frame);
if (!in_interpreter)
PyEval_SaveThread();
}
eglSwapBuffers( this->iEglDisplay, this->iEglSurface );
// This keeps the backlight turned on when the rendering is continuous
if ( !(iFrame%50) ) {
User::ResetInactivityTime();
User::After(0);
#ifdef DEBUG_GLCANVAS
DEBUGMSG("User::ResetinactivityTime()");
DEBUGMSG("User::After(0)");
#endif
}
}
void CGLCanvas::SizeChanged() {
#ifdef DEBUG_GLCANVAS
DEBUGMSG("GLCanvas::SizeChanged()\n");
TSize size = Size();
TPoint position = Position();
DEBUGMSG2("New size: %d x %d", size.iWidth, size.iHeight);
DEBUGMSG2("New posX: %d posY: %d", position.iX, position.iY);
#endif
if( !iOpenGLInitialized ) {
return;
}
if (iResizeCallback) {
int in_interpreter=(_PyThreadState_Current == PYTHON_TLS->thread_state);
if (!in_interpreter)
PyEval_RestoreThread(PYTHON_TLS->thread_state);
app_callback_handler(iResizeCallback,NULL);
if (!in_interpreter)
PyEval_SaveThread();
}
}
#define ADD_EGL_ATTRIB_VALUE(ptr,param,value) do { *ptr=param; ptr++; *ptr=value; ptr++; } while(0)
#define TERMINATE_EGL_ATTRIB_LIST(ptr) do { *ptr=EGL_NONE; } while(0)
EGLint *CGLCanvas::GenerateEglAttributes(PyObject *options) {
PyObject *optlist = NULL;
int optsize = 0;
EGLint *attrib_list = NULL;
EGLint *attrib_list_item = NULL;
int i = 0;
#ifdef DEBUG_GLCANVAS
DEBUGMSG("GLCanvas_egl_attrs()\n");
#endif
if(!PyDict_Check(options) ) {
PyErr_SetString(PyExc_TypeError, "Expecting a dict");
return NULL;
}
// See if the user wants to specify a custom buffer size
if(PyDict_GetItem(options, PyInt_FromLong(EGL_BUFFER_SIZE)) == NULL ) {
PyDict_SetItem(options,Py_BuildValue("i", EGL_BUFFER_SIZE), Py_BuildValue("i", GetBufferSize()) );
}
// See if the user wants to specify a custom buffer size
if(PyDict_GetItem(options, PyInt_FromLong(EGL_DEPTH_SIZE)) == NULL ) {
PyDict_SetItem(options, Py_BuildValue("i", EGL_DEPTH_SIZE), Py_BuildValue("i", GLCANVAS_DEFAULT_DEPTH_SIZE));
}
// Build an array from the dictionary items
optlist = PyDict_Items(options);
optsize = PyList_Size(optlist);
attrib_list = (EGLint*)glcanvas_alloc( (sizeof(EGLint) * ((optsize)*2)) + 1 );
if(attrib_list == NULL) {
return (EGLint*)PyErr_NoMemory();
}
// Take a copy of the array pointer, we'll be incrementing this while adding new values.
attrib_list_item = attrib_list;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -