StJNIEnv::StJNIEnv(JavaVM* theJavaVM) : myJavaVM(theJavaVM), myJniEnv(NULL), myToDetach(false) { if(myJavaVM == NULL) { return; } void* aJniEnv = NULL; switch(myJavaVM->GetEnv(&aJniEnv, JNI_VERSION_1_6)) { case JNI_EDETACHED: { if(myJavaVM->AttachCurrentThread(&myJniEnv, NULL) < 0) { myJniEnv = NULL; ST_ERROR_LOG("Failed to attach working thread to Java VM"); return; } myToDetach = true; break; } case JNI_OK: { myJniEnv = (JNIEnv* )aJniEnv; myToDetach = false; break; } case JNI_EVERSION: { ST_ERROR_LOG("Failed to attach working thread to Java VM - JNI version is not supported"); break; } default: { ST_ERROR_LOG("Failed to attach working thread to Java VM"); break; } } }
bool StAndroidGlue::writeCommand(const int8_t theCmd) { if(::write(myMsgWrite, &theCmd, sizeof(theCmd)) != sizeof(theCmd)) { ST_ERROR_LOG("Failure writing StAndroidGlue cmd: " + strerror(errno)); return false; } return true; }
bool StGLFontEntry::createTexture(StGLContext& theCtx) { const GLint aMaxSize = theCtx.getMaxTextureSize(); GLint aGlyphsNb = 0; if(myFont->hasCJK() || myFont->hasKorean()) { // italic does not make sense for Chinese // limit overall number of glyphs in the single texture to 4k // (single font file might contain about 20k-50k glyphs) aGlyphsNb = stMin(4000, 2 * myFont->getGlyphsNumber() - GLint(myLastTileId) + 1); } else { // western might contain reg/bold/italic/bolditalic styles // limit overall number of glyphs in the single texture to 1k // (single font file might contain about 6k glyphs for different languages) aGlyphsNb = stMin(1000, 4 * myFont->getGlyphsNumber() - GLint(myLastTileId) + 1); } const GLsizei aTextureSizeX = getPowerOfTwo(aGlyphsNb * myTileSizeX, aMaxSize); const size_t aTilesPerRow = aTextureSizeX / myTileSizeX; GLsizei aTextureSizeY = stMin(getEvenNumber(GLint((aGlyphsNb / aTilesPerRow) + 1) * myTileSizeY), aMaxSize); if(!theCtx.arbNPTW) { aTextureSizeY = getPowerOfTwo(aTextureSizeY, aMaxSize); } stMemZero(&myLastTilePx, sizeof(myLastTilePx)); myLastTilePx.bottom() = myTileSizeY; myTextures.add(new StGLTexture(theCtx.arbTexRG ? GL_R8 : GL_ALPHA)); myFbos.add(new StGLFrameBuffer()); StHandle<StGLTexture>& aTexture = myTextures[myTextures.size() - 1]; StHandle<StGLFrameBuffer>& aFbo = myFbos [myTextures.size() - 1]; if(!aTexture->initTrash(theCtx, aTextureSizeX, aTextureSizeY)) { return false; } aTexture->bind(theCtx); theCtx.core11fwd->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); theCtx.core11fwd->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); aTexture->unbind(theCtx); // destruction of temporary FBO produces broken texture on Catalyst drivers for unknown reason //StGLFrameBuffer::clearTexture(theCtx, aTexture); #if !defined(GL_ES_VERSION_2_0) if(theCtx.arbTexClear) { theCtx.core11fwd->glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); theCtx.core11fwd->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); theCtx.core11fwd->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); const stUByte_t THE_BLACK = 0; theCtx.extAll->glClearTexImage(aTexture->getTextureId(), 0, theCtx.arbTexRG ? GL_RED : GL_ALPHA, GL_UNSIGNED_BYTE, &THE_BLACK); } else if(aFbo->init(theCtx, aTexture, false)) { aFbo->clearTexture(theCtx); } else { ST_ERROR_LOG("Fail to bind " + (theCtx.arbTexRG ? "GL_R8" : "GL_ALPHA8") + " texture to FBO!"); } #else (void )aFbo; #endif return true; }
void StAndroidGlue::postExit() { if(myThJniEnv == NULL) { return; } jclass aJClassAct = myThJniEnv->GetObjectClass(myActivity->clazz); if(aJClassAct == NULL) { ST_ERROR_LOG("StAndroidGlue::postExit() - class is unavailable!"); return; } jmethodID aJMetId = myThJniEnv->GetMethodID(aJClassAct, "postExit", "()V"); if(aJMetId == NULL) { ST_ERROR_LOG("StAndroidGlue::postExit() - method is unavailable!"); return; } myThJniEnv->CallVoidMethod(myActivity->clazz, aJMetId); }
void StAndroidGlue::postMessage(const char* theInfo) { if(myThJniEnv == NULL) { return; } jclass aJClassAct = myThJniEnv->GetObjectClass(myActivity->clazz); if(aJClassAct == NULL) { ST_ERROR_LOG("StAndroidGlue::postMessage() - class is unavailable!"); return; } jmethodID aJMetId = myThJniEnv->GetMethodID(aJClassAct, "postMessage", "(Ljava/lang/String;)V"); if(aJMetId == NULL) { ST_ERROR_LOG("StAndroidGlue::postMessage() - method is unavailable!"); return; } jstring aJStr = myThJniEnv->NewStringUTF(theInfo); myThJniEnv->CallVoidMethod(myActivity->clazz, aJMetId, aJStr); myThJniEnv->DeleteLocalRef (aJStr); }
/** * Copy OCCT resource file. */ ST_LOCAL bool copyResource(const StHandle<StResourceManager>& theResMgr, const StString& theResFolder, const StString& theDestFolder, const StString& theFileName) { StString aFileResPath = theResFolder + SYS_FS_SPLITTER + theFileName; StHandle<StResource> aRes = theResMgr->getResource(aFileResPath); if( aRes.isNull() || !aRes->read()) { ST_ERROR_LOG(StString("Can not read resource file ") + aFileResPath); return false; } StRawFile aFileOut; StString aFileOutPath = theDestFolder + SYS_FS_SPLITTER + theFileName; if(!aFileOut.openFile(StRawFile::WRITE, aFileOutPath)) { ST_ERROR_LOG(StString("Can not create resource file ") + aFileOutPath); return false; } if(!aFileOut.write((const char* )aRes->getData(), aRes->getSize()) != aRes->getSize()) { ST_ERROR_LOG(StString("Can not write resource file ") + aFileOutPath); return false; } return true; }
StWinGlrc::~StWinGlrc() { if(myRC != EGL_NO_CONTEXT) { if(eglMakeCurrent(myDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE) { ST_DEBUG_LOG("EGL, FAILED to release OpenGL context"); } eglDestroyContext(myDisplay, myRC); myRC = EGL_NO_CONTEXT; } if(myDisplay != EGL_NO_DISPLAY) { if(eglTerminate(myDisplay) != EGL_TRUE) { ST_ERROR_LOG("EGL, eglTerminate FAILED"); } myDisplay = EGL_NO_DISPLAY; } }
StWinGlrc::~StWinGlrc() { if(myRC == NULL) { return; } if(wglMakeCurrent(NULL, NULL) == FALSE) { // this is not a problem in most cases; // also this happens when wglMakeCurrent(NULL, NULL) called twice //ST_DEBUG_LOG("WinAPI, FAILED to release DC and RC contexts"); } //ST_ASSERT_SLIP(wglDeleteContext(myRC) != FALSE, "WinAPI, FAILED to delete RC", return); if(wglDeleteContext(myRC) == FALSE) { ST_ERROR_LOG("WinAPI, FAILED to delete RC"); } }
int StAndroidGlue::openFileDescriptor(const StString& thePath) { if(myJavaVM == NULL) { return -1; } StJNIEnv aJniEnv(myJavaVM); if(aJniEnv.isNull()) { return -1; } jclass aJClass_Activity = aJniEnv->GetObjectClass(myActivity->clazz); jmethodID aJMet_openFileDescriptor = aJniEnv->GetMethodID(aJClass_Activity, "openFileDescriptor", "(Ljava/lang/String;)I"); if(aJMet_openFileDescriptor == NULL) { ST_ERROR_LOG("StAndroidGlue::openFileDescriptor() - method is unavailable!"); return -1; } jstring aJStr = aJniEnv->NewStringUTF(thePath.toCString()); int aFileDesc = aJniEnv->CallIntMethod(myActivity->clazz, aJMet_openFileDescriptor, aJStr); aJniEnv->DeleteLocalRef(aJStr); return aFileDesc; }
// function create GUI window bool StWindowImpl::create() { myKeysState.reset(); // replace default XError handler to ignore some errors XSetErrorHandler(stXErrorHandler); myInitState = STWIN_INITNOTSTART; // X-server implementation // create window on unix systems throw X-server int dummy; // open a connection to the X server StXDisplayH stXDisplay = new StXDisplay(); if(!stXDisplay->isOpened()) { stXDisplay.nullify(); stError("X, could not open display"); myInitState = STWIN_ERROR_X_OPENDISPLAY; return false; } myMaster.stXDisplay = stXDisplay; Display* hDisplay = stXDisplay->hDisplay; #if defined(ST_HAVE_EGL) myMaster.hRC = new StWinGlrc(eglGetDisplay(hDisplay), attribs.IsGlDebug, attribs.GlDepthSize); if(!myMaster.hRC->isValid()) { myMaster.close(); mySlave.close(); myInitState = STWIN_ERROR_X_GLRC_CREATE; return false; } XVisualInfo aVisInfo; aVisInfo.visualid = 0; if (eglGetConfigAttrib(myMaster.hRC->getDisplay(), myMaster.hRC->getConfig(), EGL_NATIVE_VISUAL_ID, (EGLint* )&aVisInfo.visualid) != EGL_TRUE) { myMaster.close(); mySlave.close(); myInitState = STWIN_ERROR_X_GLRC_CREATE; return false; } int aNbVisuals = 0; stXDisplay->hVisInfo = XGetVisualInfo(hDisplay, VisualIDMask, &aVisInfo, &aNbVisuals); #else // GLX // make sure OpenGL's GLX extension supported if(!glXQueryExtension(hDisplay, &dummy, &dummy)) { myMaster.close(); stError("X, server has no OpenGL GLX extension"); myInitState = STWIN_ERROR_X_NOGLX; return false; } int anAttribsBuff[] = { GLX_STEREO, attribs.IsGlStereo ? True : False, GLX_X_RENDERABLE, True, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 0, GLX_DEPTH_SIZE, attribs.GlDepthSize, GLX_STENCIL_SIZE, 0, GLX_DOUBLEBUFFER, True, //GLX_SAMPLE_BUFFERS, 1, //GLX_SAMPLES, 4, None }; // FBConfigs were added in GLX version 1.3 int aGlxMajor = 0; int aGlxMinor = 0; const bool hasFBCfg = glXQueryVersion(hDisplay, &aGlxMajor, &aGlxMinor) && ((aGlxMajor == 1 && aGlxMinor >= 3) || (aGlxMajor > 1)); int aFBCount = 0; GLXFBConfig* aFBCfgList = NULL; if(hasFBCfg) { aFBCfgList = glXChooseFBConfig(hDisplay, DefaultScreen(hDisplay), anAttribsBuff, &aFBCount); } if(aFBCfgList == NULL && hasFBCfg && attribs.IsGlStereo) { ST_ERROR_LOG("X, no Quad Buffered visual"); anAttribsBuff[1] = False; aFBCfgList = glXChooseFBConfig(hDisplay, DefaultScreen(hDisplay), anAttribsBuff, &aFBCount); } if(aFBCfgList != NULL && aFBCount >= 1) { stXDisplay->FBCfg = aFBCfgList[0]; stXDisplay->hVisInfo = glXGetVisualFromFBConfig(hDisplay, stXDisplay->FBCfg); } else { // try to use glXChooseVisual... pointless? int aDblBuff[] = { GLX_RGBA, GLX_DEPTH_SIZE, attribs.GlDepthSize, GLX_DOUBLEBUFFER, None }; if(attribs.IsGlStereo) { // find an appropriate visual int aQuadBuff[] = { GLX_RGBA, GLX_DEPTH_SIZE, attribs.GlDepthSize, GLX_DOUBLEBUFFER, GLX_STEREO, None }; stXDisplay->hVisInfo = glXChooseVisual(hDisplay, DefaultScreen(hDisplay), aQuadBuff); if(stXDisplay->hVisInfo == NULL) { ST_ERROR_LOG("X, no Quad Buffered visual"); stXDisplay->hVisInfo = glXChooseVisual(hDisplay, DefaultScreen(hDisplay), aDblBuff); if(stXDisplay->hVisInfo == NULL) { myMaster.close(); stError("X, no RGB visual with depth buffer"); myInitState = STWIN_ERROR_X_NORGB; return false; } } } else { // find an appropriate visual // find an OpenGL-capable RGB visual with depth buffer stXDisplay->hVisInfo = glXChooseVisual(hDisplay, DefaultScreen(hDisplay), aDblBuff); if(stXDisplay->hVisInfo == NULL) { myMaster.close(); stError("X, no RGB visual with depth buffer"); myInitState = STWIN_ERROR_X_NORGB; return false; } } } XFree(aFBCfgList); #endif if(attribs.Slave != StWinSlave_slaveOff) { // just copy handle mySlave.stXDisplay = stXDisplay; } // create an X window with the selected visual XSetWindowAttributes aWinAttribsX = createDefaultAttribs(stXDisplay); updateChildRect(); Window aParentWin = (Window )myParentWin; if(aParentWin == 0 && !attribs.IsNoDecor) { aWinAttribsX.override_redirect = False; myMaster.hWindow = XCreateWindow(hDisplay, stXDisplay->getRootWindow(), myRectNorm.left(), myRectNorm.top(), myRectNorm.width(), myRectNorm.height(), 0, stXDisplay->getDepth(), InputOutput, stXDisplay->getVisual(), CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttribsX); if(myMaster.hWindow == 0) { myMaster.close(); stError("X, XCreateWindow failed for Master"); myInitState = STWIN_ERROR_X_CREATEWIN; return false; } aParentWin = myMaster.hWindow; XSetStandardProperties(hDisplay, myMaster.hWindow, myWindowTitle.toCString(), myWindowTitle.toCString(), None, NULL, 0, NULL); // setup WM_CLASS in sync with .desktop StartupWMClass entity // to ensure Window Manager would show an propriate icon for application XClassHint* aClassHint = XAllocClassHint(); if(aClassHint != NULL) { StString aName = StProcess::getProcessName(); StString aClass("sView"); // const_cast should be harmless here and it seems to be just broken signature of XClassHint structure aClassHint->res_name = const_cast<char* >(aName.toCString()); aClassHint->res_class = const_cast<char* >(aClass.toCString()); XSetClassHint(hDisplay, myMaster.hWindow, aClassHint); XFree(aClassHint); } } aWinAttribsX.override_redirect = True; // GL window always undecorated myMaster.hWindowGl = XCreateWindow(hDisplay, (aParentWin != 0) ? aParentWin : stXDisplay->getRootWindow(), 0, 0, myRectNorm.width(), myRectNorm.height(), 0, stXDisplay->getDepth(), InputOutput, stXDisplay->getVisual(), CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttribsX); if(myMaster.hWindowGl == 0) { myMaster.close(); stError("X, XCreateWindow failed for Master"); myInitState = STWIN_ERROR_X_CREATEWIN; return false; } XSetStandardProperties(hDisplay, myMaster.hWindowGl, "master window", "master window", None, NULL, 0, NULL); if(attribs.Slave != StWinSlave_slaveOff) { aWinAttribsX.event_mask = NoEventMask; // we do not parse any events to slave window! aWinAttribsX.override_redirect = True; // slave window always undecorated mySlave.hWindowGl = XCreateWindow(hDisplay, stXDisplay->getRootWindow(), getSlaveLeft(), getSlaveTop(), getSlaveWidth(), getSlaveHeight(), 0, stXDisplay->getDepth(), InputOutput, stXDisplay->getVisual(), CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttribsX); if(mySlave.hWindowGl == 0) { myMaster.close(); mySlave.close(); stError("X, XCreateWindow failed for Slave"); myInitState = STWIN_ERROR_X_CREATEWIN; return false; } XSetStandardProperties(hDisplay, mySlave.hWindowGl, "slave window", "slave window", None, NULL, 0, NULL); } int isGlCtx = myMaster.glCreateContext(attribs.Slave != StWinSlave_slaveOff ? &mySlave : NULL, myRectNorm, attribs.GlDepthSize, attribs.IsGlStereo, attribs.IsGlDebug); if(isGlCtx != STWIN_INIT_SUCCESS) { myMaster.close(); mySlave.close(); myInitState = isGlCtx; return false; } myGlContext = new StGLContext(myResMgr); if(!myGlContext->stglInit()) { myMaster.close(); mySlave.close(); stError("Critical error - broken GL context!\nInvalid OpenGL driver?"); myInitState = STWIN_ERROR_X_GLRC_CREATE; return false; } // handle close window event if(myMaster.hWindow != 0) { XSetWMProtocols(hDisplay, myMaster.hWindow, &(stXDisplay->wndDestroyAtom), 1); } // Announce XDND support myMaster.setupXDND(); // Initialize XRandr events reception if(XRRQueryExtension(hDisplay, &myMaster.xrandrEventBase, &dummy)) { XRRSelectInput(hDisplay, stXDisplay->getRootWindow(), RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask | RROutputPropertyNotifyMask); myMaster.isRecXRandrEvents = true; } else { myMaster.isRecXRandrEvents = false; } // request the X window to be displayed on the screen if(attribs.Slave != StWinSlave_slaveOff) { // request the X window to be displayed on the screen if(!attribs.IsSlaveHidden && (!isSlaveIndependent() || myMonitors.size() > 1)) { XMapWindow(hDisplay, mySlave.hWindowGl); //XIfEvent(hDisplay, &myXEvent, stXWaitMapped, (char* )mySlave.hWindowGl); } // always hise mouse cursor on slave window mySlave.setupNoCursor(); } if(!attribs.IsHidden) { if(myMaster.hWindow != 0) { XMapWindow(hDisplay, myMaster.hWindow); //XIfEvent(hDisplay, &myXEvent, stXWaitMapped, (char* )myMaster.hWindow); } XMapWindow(hDisplay, myMaster.hWindowGl); //XIfEvent(hDisplay, &myXEvent, stXWaitMapped, (char* )myMaster.hWindowGl); } // setup default icon if((Window )myParentWin == 0) { XpmCreatePixmapFromData(hDisplay, myMaster.hWindow, (char** )sview_xpm, &myMaster.iconImage, &myMaster.iconShape, NULL); XWMHints anIconHints; anIconHints.flags = IconPixmapHint | IconMaskHint; anIconHints.icon_pixmap = myMaster.iconImage; anIconHints.icon_mask = myMaster.iconShape; XSetWMHints(hDisplay, myMaster.hWindow, &anIconHints); } // we need this call to go around bugs if(!attribs.IsFullScreen && myMaster.hWindow != 0) { XMoveResizeWindow(hDisplay, myMaster.hWindow, myRectNorm.left(), myRectNorm.top(), myRectNorm.width(), myRectNorm.height()); } // flushes the output buffer, most client apps needn't use this cause buffer is automatically flushed as needed by calls to XNextEvent()... XFlush(hDisplay); myMonitors.registerUpdater(true); myIsUpdated = true; myInitState = STWIN_INIT_SUCCESS; return true; }
bool StAVImage::load(const StString& theFilePath, ImageType theImageType, uint8_t* theDataPtr, int theDataSize) { // reset current data StImage::nullify(); setState(); close(); myMetadata.clear(); switch(theImageType) { case ST_TYPE_PNG: case ST_TYPE_PNS: { myCodec = avcodec_find_decoder_by_name("png"); break; } case ST_TYPE_JPEG: case ST_TYPE_MPO: case ST_TYPE_JPS: { myCodec = avcodec_find_decoder_by_name("mjpeg"); break; } case ST_TYPE_EXR: { myCodec = avcodec_find_decoder_by_name("exr"); break; } case ST_TYPE_WEBP: case ST_TYPE_WEBPLL: { myCodec = avcodec_find_decoder_by_name("webp"); break; } default: { break; } } if(theImageType == ST_TYPE_NONE || (theDataPtr == NULL && !StFileNode::isFileExists(theFilePath))) { // open image file and detect its type, its could be non local file! #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 2, 0)) int avErrCode = avformat_open_input(&myFormatCtx, theFilePath.toCString(), myImageFormat, NULL); #else int avErrCode = av_open_input_file (&myFormatCtx, theFilePath.toCString(), myImageFormat, 0, NULL); #endif if(avErrCode != 0 || myFormatCtx->nb_streams < 1 || myFormatCtx->streams[0]->codec->codec_id == 0) { if(myFormatCtx != NULL) { #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 17, 0)) avformat_close_input(&myFormatCtx); #else av_close_input_file(myFormatCtx); myFormatCtx = NULL; #endif } #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 2, 0)) avErrCode = avformat_open_input(&myFormatCtx, theFilePath.toCString(), NULL, NULL); #else avErrCode = av_open_input_file(&myFormatCtx, theFilePath.toCString(), NULL, 0, NULL); #endif } if(avErrCode != 0 || myFormatCtx->nb_streams < 1) { setState(StString("AVFormat library, couldn't open image file. Error: ") + stAV::getAVErrorDescription(avErrCode)); close(); return false; } // find the decoder for the video stream myCodecCtx = myFormatCtx->streams[0]->codec; if(theImageType == ST_TYPE_NONE) { myCodec = avcodec_find_decoder(myCodecCtx->codec_id); } } if(myCodec == NULL) { setState("AVCodec library, video codec not found"); close(); return false; } else if(myFormatCtx == NULL) { // use given image type to load decoder #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) myCodecCtx = avcodec_alloc_context3(myCodec); #else myCodecCtx = avcodec_alloc_context(); #endif } // stupid check if(myCodecCtx == NULL) { setState("AVCodec library, codec context is NULL"); close(); return false; } // open VIDEO codec #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) if(avcodec_open2(myCodecCtx, myCodec, NULL) < 0) { #else if(avcodec_open(myCodecCtx, myCodec) < 0) { #endif setState("AVCodec library, could not open video codec"); close(); return false; } // read one packet or file StRawFile aRawFile(theFilePath); StAVPacket anAvPkt; if(theDataPtr != NULL && theDataSize != 0) { anAvPkt.getAVpkt()->data = theDataPtr; anAvPkt.getAVpkt()->size = theDataSize; } else { if(myFormatCtx != NULL) { if(av_read_frame(myFormatCtx, anAvPkt.getAVpkt()) < 0) { setState("AVFormat library, could not read first packet"); close(); return false; } } else { if(!aRawFile.readFile()) { setState("StAVImage, could not read the file"); close(); return false; } anAvPkt.getAVpkt()->data = (uint8_t* )aRawFile.getBuffer(); anAvPkt.getAVpkt()->size = (int )aRawFile.getSize(); } } anAvPkt.setKeyFrame(); // decode one frame int isFrameFinished = 0; #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 23, 0)) avcodec_decode_video2(myCodecCtx, myFrame.Frame, &isFrameFinished, anAvPkt.getAVpkt()); #else avcodec_decode_video(myCodecCtx, myFrame.Frame, &isFrameFinished, theDataPtr, theDataSize); #endif if(isFrameFinished == 0) { // thats not an image!!! try to decode more packets??? setState("AVCodec library, input file is not an Image!"); close(); return false; } // check frame size if(myCodecCtx->width <= 0 || myCodecCtx->height <= 0) { setState("AVCodec library, codec returns wrong frame size"); close(); return false; } // read aspect ratio if(myCodecCtx->sample_aspect_ratio.num == 0 || myCodecCtx->sample_aspect_ratio.den == 0) { setPixelRatio(1.0f); } else { const GLfloat aRatio = GLfloat(myCodecCtx->sample_aspect_ratio.num) / GLfloat(myCodecCtx->sample_aspect_ratio.den); if(aRatio > 70.0f) { ST_DEBUG_LOG("AVCodec library, igning wrong PAR " + myCodecCtx->sample_aspect_ratio.num + ":" + myCodecCtx->sample_aspect_ratio.den); setPixelRatio(1.0f); } else { setPixelRatio(aRatio); } } #ifdef ST_AV_NEWSTEREO // currently it is unlikelly... but maybe in future? AVFrameSideData* aSideData = av_frame_get_side_data(myFrame.Frame, AV_FRAME_DATA_STEREO3D); if(aSideData != NULL) { AVStereo3D* aStereo = (AVStereo3D* )aSideData->data; mySrcFormat = stAV::stereo3dAvToSt(aStereo->type); if(aStereo->flags & AV_STEREO3D_FLAG_INVERT) { mySrcFormat = st::formatReversed(mySrcFormat); } } else { mySrcFormat = StFormat_AUTO; } #endif // it is unlikely that there would be any metadata from format... // but lets try if(myFormatCtx != NULL) { for(stAV::meta::Tag* aTag = stAV::meta::findTag(myFormatCtx->metadata, "", NULL, stAV::meta::SEARCH_IGNORE_SUFFIX); aTag != NULL; aTag = stAV::meta::findTag(myFormatCtx->metadata, "", aTag, stAV::meta::SEARCH_IGNORE_SUFFIX)) { myMetadata.add(StDictEntry(aTag->key, aTag->value)); } for(stAV::meta::Tag* aTag = stAV::meta::findTag(myFormatCtx->streams[0]->metadata, "", NULL, stAV::meta::SEARCH_IGNORE_SUFFIX); aTag != NULL; aTag = stAV::meta::findTag(myFormatCtx->streams[0]->metadata, "", aTag, stAV::meta::SEARCH_IGNORE_SUFFIX)) { myMetadata.add(StDictEntry(aTag->key, aTag->value)); } } // collect metadata from the frame stAV::meta::Dict* aFrameMetadata = stAV::meta::getFrameMetadata(myFrame.Frame); for(stAV::meta::Tag* aTag = stAV::meta::findTag(aFrameMetadata, "", NULL, stAV::meta::SEARCH_IGNORE_SUFFIX); aTag != NULL; aTag = stAV::meta::findTag(aFrameMetadata, "", aTag, stAV::meta::SEARCH_IGNORE_SUFFIX)) { myMetadata.add(StDictEntry(aTag->key, aTag->value)); } stAV::dimYUV aDimsYUV; if(myCodecCtx->pix_fmt == stAV::PIX_FMT::RGB24) { setColorModel(StImage::ImgColor_RGB); changePlane(0).initWrapper(StImagePlane::ImgRGB, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::BGR24) { setColorModel(StImage::ImgColor_RGB); changePlane(0).initWrapper(StImagePlane::ImgBGR, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::RGBA32) { setColorModel(StImage::ImgColor_RGBA); changePlane(0).initWrapper(StImagePlane::ImgRGBA, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::BGRA32) { setColorModel(StImage::ImgColor_RGBA); changePlane(0).initWrapper(StImagePlane::ImgBGRA, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::GRAY8) { setColorModel(StImage::ImgColor_GRAY); changePlane(0).initWrapper(StImagePlane::ImgGray, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::GRAY16) { setColorModel(StImage::ImgColor_GRAY); changePlane(0).initWrapper(StImagePlane::ImgGray16, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::RGB48) { setColorModel(StImage::ImgColor_RGB); changePlane(0).initWrapper(StImagePlane::ImgRGB48, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::RGBA64) { setColorModel(StImage::ImgColor_RGBA); changePlane(0).initWrapper(StImagePlane::ImgRGBA64, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(stAV::isFormatYUVPlanar(myCodecCtx, aDimsYUV)) { #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 29, 0)) if(myCodecCtx->color_range == AVCOL_RANGE_JPEG) { aDimsYUV.isFullScale = true; } #endif setColorModel(StImage::ImgColor_YUV); setColorScale(aDimsYUV.isFullScale ? StImage::ImgScale_Full : StImage::ImgScale_Mpeg); StImagePlane::ImgFormat aPlaneFrmt = StImagePlane::ImgGray; if(aDimsYUV.bitsPerComp == 9) { aPlaneFrmt = StImagePlane::ImgGray16; setColorScale(aDimsYUV.isFullScale ? StImage::ImgScale_Jpeg9 : StImage::ImgScale_Mpeg9); } else if(aDimsYUV.bitsPerComp == 10) { aPlaneFrmt = StImagePlane::ImgGray16; setColorScale(aDimsYUV.isFullScale ? StImage::ImgScale_Jpeg10 : StImage::ImgScale_Mpeg10); } else if(aDimsYUV.bitsPerComp == 16) { aPlaneFrmt = StImagePlane::ImgGray16; } changePlane(0).initWrapper(aPlaneFrmt, myFrame.getPlane(0), size_t(aDimsYUV.widthY), size_t(aDimsYUV.heightY), myFrame.getLineSize(0)); changePlane(1).initWrapper(aPlaneFrmt, myFrame.getPlane(1), size_t(aDimsYUV.widthU), size_t(aDimsYUV.heightU), myFrame.getLineSize(1)); changePlane(2).initWrapper(aPlaneFrmt, myFrame.getPlane(2), size_t(aDimsYUV.widthV), size_t(aDimsYUV.heightV), myFrame.getLineSize(2)); } else { ///ST_DEBUG_LOG("StAVImage, perform conversion from Pixel format '" + avcodec_get_pix_fmt_name(myCodecCtx->pix_fmt) + "' to RGB"); // initialize software scaler/converter SwsContext* pToRgbCtx = sws_getContext(myCodecCtx->width, myCodecCtx->height, myCodecCtx->pix_fmt, // source myCodecCtx->width, myCodecCtx->height, stAV::PIX_FMT::RGB24, // destination SWS_BICUBIC, NULL, NULL, NULL); if(pToRgbCtx == NULL) { setState("SWScale library, failed to create SWScaler context"); close(); return false; } // initialize additional buffer for converted RGB data setColorModel(StImage::ImgColor_RGB); changePlane(0).initTrash(StImagePlane::ImgRGB, myCodecCtx->width, myCodecCtx->height); uint8_t* rgbData[4]; stMemZero(rgbData, sizeof(rgbData)); int rgbLinesize[4]; stMemZero(rgbLinesize, sizeof(rgbLinesize)); rgbData[0] = changePlane(0).changeData(); rgbLinesize[0] = (int )changePlane(0).getSizeRowBytes(); sws_scale(pToRgbCtx, myFrame.Frame->data, myFrame.Frame->linesize, 0, myCodecCtx->height, rgbData, rgbLinesize); // reset original data closeAvCtx(); sws_freeContext(pToRgbCtx); } // set debug information StString aDummy, aFileName; StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName); setState(StString("AVCodec library, loaded image '") + aFileName + "' " + getDescription()); // we should not close the file because decoded image data is in codec context cache return true; } bool StAVImage::save(const StString& theFilePath, ImageType theImageType, StFormat theSrcFormat) { close(); setState(); if(isNull()) { return false; } PixelFormat aPFormatAV = (PixelFormat )getAVPixelFormat(*this); StImage anImage; switch(theImageType) { case ST_TYPE_PNG: case ST_TYPE_PNS: { myCodec = avcodec_find_encoder_by_name("png"); if(myCodec == NULL) { setState("AVCodec library, video codec 'png' not found"); close(); return false; } if(aPFormatAV == stAV::PIX_FMT::RGB24 || aPFormatAV == stAV::PIX_FMT::RGBA32 || aPFormatAV == stAV::PIX_FMT::GRAY8) { anImage.initWrapper(*this); } else { // convert to compatible pixel format anImage.changePlane().initTrash(StImagePlane::ImgRGB, getSizeX(), getSizeY(), getAligned(getSizeX() * 3)); PixelFormat aPFrmtTarget = stAV::PIX_FMT::RGB24; if(!convert(*this, aPFormatAV, anImage, aPFrmtTarget)) { setState("SWScale library, failed to create SWScaler context"); close(); return false; } aPFormatAV = aPFrmtTarget; } #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) myCodecCtx = avcodec_alloc_context3(myCodec); #else myCodecCtx = avcodec_alloc_context(); #endif // setup encoder myCodecCtx->pix_fmt = aPFormatAV; myCodecCtx->width = (int )anImage.getSizeX(); myCodecCtx->height = (int )anImage.getSizeY(); myCodecCtx->compression_level = 9; // 0..9 break; } case ST_TYPE_JPEG: case ST_TYPE_MPO: case ST_TYPE_JPS: { myCodec = avcodec_find_encoder_by_name("mjpeg"); if(myCodec == NULL) { setState("AVCodec library, video codec 'mjpeg' not found"); close(); return false; } if(aPFormatAV == stAV::PIX_FMT::YUVJ420P || aPFormatAV == stAV::PIX_FMT::YUVJ422P //|| aPFormatAV == stAV::PIX_FMT::YUVJ444P not supported by FFmpeg... yet? //|| aPFormatAV == stAV::PIX_FMT::YUVJ440P ) { anImage.initWrapper(*this); } else { // convert to compatible pixel format PixelFormat aPFrmtTarget = aPFormatAV == stAV::PIX_FMT::YUV420P ? stAV::PIX_FMT::YUVJ420P : stAV::PIX_FMT::YUVJ422P; anImage.setColorModel(StImage::ImgColor_YUV); anImage.setColorScale(StImage::ImgScale_Mpeg); anImage.changePlane(0).initTrash(StImagePlane::ImgGray, getSizeX(), getSizeY(), getAligned(getSizeX())); stMemSet(anImage.changePlane(0).changeData(), '\0', anImage.getPlane(0).getSizeBytes()); anImage.changePlane(1).initTrash(StImagePlane::ImgGray, getSizeX(), getSizeY(), getAligned(getSizeX())); stMemSet(anImage.changePlane(1).changeData(), '\0', anImage.getPlane(1).getSizeBytes()); anImage.changePlane(2).initTrash(StImagePlane::ImgGray, getSizeX(), getSizeY(), getAligned(getSizeX())); stMemSet(anImage.changePlane(2).changeData(), '\0', anImage.getPlane(2).getSizeBytes()); if(!convert(*this, aPFormatAV, anImage, aPFrmtTarget)) { setState("SWScale library, failed to create SWScaler context"); close(); return false; } aPFormatAV = aPFrmtTarget; } #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) myCodecCtx = avcodec_alloc_context3(myCodec); #else myCodecCtx = avcodec_alloc_context(); #endif myCodecCtx->pix_fmt = aPFormatAV; myCodecCtx->width = (int )anImage.getSizeX(); myCodecCtx->height = (int )anImage.getSizeY(); myCodecCtx->time_base.num = 1; myCodecCtx->time_base.den = 1; myCodecCtx->qmin = myCodecCtx->qmax = 5; // quality factor - lesser is better break; } case ST_TYPE_NONE: default: close(); return false; } // open VIDEO codec #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) if(avcodec_open2(myCodecCtx, myCodec, NULL) < 0) { #else if(avcodec_open(myCodecCtx, myCodec) < 0) { #endif setState("AVCodec library, could not open video codec"); close(); return false; } // wrap own data into AVFrame myFrame.Frame->format = myCodecCtx->pix_fmt; myFrame.Frame->width = myCodecCtx->width; myFrame.Frame->height = myCodecCtx->height; fillPointersAV(anImage, myFrame.Frame->data, myFrame.Frame->linesize); #ifdef ST_AV_NEWSTEREO bool isReversed = false; AVStereo3DType anAvStereoType = stAV::stereo3dStToAv(theSrcFormat, isReversed); if(anAvStereoType != (AVStereo3DType )-1) { AVStereo3D* aStereo = av_stereo3d_create_side_data(myFrame.Frame); if(aStereo != NULL) { aStereo->type = anAvStereoType; if(isReversed) { aStereo->flags |= AV_STEREO3D_FLAG_INVERT; } } } #endif StJpegParser aRawFile(theFilePath); if(!aRawFile.openFile(StRawFile::WRITE)) { setState("Can not open the file for writing"); close(); return false; } // allocate the buffer, large enough (stupid formula copied from ffmpeg.c) int aBuffSize = int(getSizeX() * getSizeY() * 10); aRawFile.initBuffer(aBuffSize); // encode the image StAVPacket aPacket; aPacket.getAVpkt()->data = (uint8_t* )aRawFile.changeBuffer(); aPacket.getAVpkt()->size = aBuffSize; #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 2, 100)) int isGotPacket = 0; int anEncSize = avcodec_encode_video2(myCodecCtx, aPacket.getAVpkt(), myFrame.Frame, &isGotPacket); if(anEncSize == 0 && isGotPacket != 0) { anEncSize = aPacket.getSize(); } #else int anEncSize = avcodec_encode_video(myCodecCtx, aPacket.changeData(), aPacket.getSize(), myFrame.Frame); #endif if(anEncSize <= 0) { setState("AVCodec library, fail to encode the image"); close(); return false; } aRawFile.setDataSize((size_t )anEncSize); // save metadata when possible if(theImageType == ST_TYPE_JPEG || theImageType == ST_TYPE_JPS) { if(aRawFile.parse()) { if(theSrcFormat != StFormat_AUTO) { aRawFile.setupJps(theSrcFormat); } } else { ST_ERROR_LOG("AVCodec library, created JPEG can not be parsed!"); } } // store current content aRawFile.writeFile(); // and finally close the file handle aRawFile.closeFile(); close(); // set debug information StString aDummy, aFileName; StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName); setState(StString("AVCodec library, saved image '") + aFileName + "' " + getDescription()); return true; }
void StAndroidGlue::processCommand() { int8_t aCmd = -1; if(::read(myMsgRead, &aCmd, sizeof(aCmd)) == sizeof(aCmd)) { switch(aCmd) { case CommandId_SaveState: freeSavedState(); break; } } else { ST_ERROR_LOG("No data on command pipe!"); return; } // preprocessing switch(aCmd) { case CommandId_InputChanged: { pthread_mutex_lock(&myMutex); if(myInputQueue != NULL) { AInputQueue_detachLooper(myInputQueue); } myInputQueue = myInputQueuePending; if(myInputQueue != NULL) { AInputQueue_attachLooper(myInputQueue, myLooper, LooperId_INPUT, NULL, &myInputPollSource); } pthread_cond_broadcast(&myCond); pthread_mutex_unlock(&myMutex); break; } case CommandId_WindowChanged: case CommandId_WindowInit: { pthread_mutex_lock(&myMutex); myWindow = myWindowPending; pthread_cond_broadcast(&myCond); pthread_mutex_unlock(&myMutex); break; } case CommandId_WindowTerm: { pthread_cond_broadcast(&myCond); break; } case CommandId_Resume: case CommandId_Start: case CommandId_Pause: case CommandId_Stop: { pthread_mutex_lock(&myMutex); myActivityState = aCmd; pthread_cond_broadcast(&myCond); pthread_mutex_unlock(&myMutex); break; } case CommandId_ConfigChanged: { AConfiguration_fromAssetManager(myConfig, myActivity->assetManager); updateMonitors(); printConfig(); break; } case CommandId_Destroy: { myToDestroy = true; break; } } signals.onAppCmd(aCmd); // post-processing switch(aCmd) { case CommandId_WindowTerm: { pthread_mutex_lock(&myMutex); myWindow = NULL; pthread_cond_broadcast(&myCond); pthread_mutex_unlock(&myMutex); break; } case CommandId_WindowChanged: { pthread_mutex_lock(&myMutex); myWindowPending = NULL; pthread_cond_broadcast(&myCond); pthread_mutex_unlock(&myMutex); break; } case CommandId_SaveState: { pthread_mutex_lock(&myMutex); myIsStateSaved = true; pthread_cond_broadcast(&myCond); pthread_mutex_unlock(&myMutex); break; } case CommandId_Resume: { freeSavedState(); break; } } }
void StWindowImpl::setFullScreen(bool theFullscreen) { if(attribs.IsFullScreen != theFullscreen) { attribs.IsFullScreen = theFullscreen; if(attribs.IsFullScreen) { myFullScreenWinNb.increment(); } else { myFullScreenWinNb.decrement(); } } if(attribs.IsHidden) { // TODO (Kirill Gavrilov#9) parse correctly // do nothing, just set the flag return; } else if(myMaster.stXDisplay.isNull()) { return; } Display* hDisplay = myMaster.stXDisplay->hDisplay; if(attribs.IsFullScreen) { const StMonitor& stMon = (myMonMasterFull == -1) ? myMonitors[myRectNorm.center()] : myMonitors[myMonMasterFull]; myRectFull = stMon.getVRect(); XUnmapWindow(hDisplay, myMaster.hWindowGl); // workaround for strange bugs StRectI_t aRect = myRectFull; // use tiled Master+Slave layout within single window if possible if(attribs.Slave != StWinSlave_slaveOff && isSlaveIndependent() && myMonitors.size() > 1) { StRectI_t aRectSlave; aRectSlave.left() = getSlaveLeft(); aRectSlave.top() = getSlaveTop(); aRectSlave.right() = aRectSlave.left() + myRectFull.width(); aRectSlave.bottom() = aRectSlave.top() + myRectFull.height(); myTiledCfg = TiledCfg_Separate; if(myRectFull.top() == aRectSlave.top()) { if(myRectFull.right() == aRectSlave.left()) { myTiledCfg = TiledCfg_MasterSlaveX; } else if(myRectFull.left() == aRectSlave.right()) { myTiledCfg = TiledCfg_SlaveMasterX; } } else if(myRectFull.left() == aRectSlave.left()) { if(myRectFull.bottom() == aRectSlave.top()) { myTiledCfg = TiledCfg_MasterSlaveY; } else if(myRectFull.top() == aRectSlave.bottom()) { myTiledCfg = TiledCfg_SlaveMasterY; } } } if(myTiledCfg != TiledCfg_Separate) { XUnmapWindow(hDisplay, mySlave.hWindowGl); getTiledWinRect(aRect); } else if(attribs.Split == StWinSlave_splitHorizontal) { myTiledCfg = TiledCfg_MasterSlaveX; myRectFull.right() -= myRectFull.width() / 2; } else if(attribs.Split == StWinSlave_splitVertical) { myTiledCfg = TiledCfg_MasterSlaveY; myRectFull.bottom() -= myRectFull.height() / 2; } if((Window )myParentWin != 0 || myMaster.hWindow != 0) { XReparentWindow(hDisplay, myMaster.hWindowGl, myMaster.stXDisplay->getRootWindow(), 0, 0); XMoveResizeWindow(hDisplay, myMaster.hWindowGl, aRect.left(), aRect.top(), aRect.width(), aRect.height()); XFlush(hDisplay); XMapWindow(hDisplay, myMaster.hWindowGl); //XIfEvent(hDisplay, &myXEvent, stXWaitMapped, (char* )myMaster.hWindowGl); } else { XMoveResizeWindow(hDisplay, myMaster.hWindowGl, aRect.left(), aRect.top(), aRect.width(), aRect.height()); XFlush(hDisplay); XMapWindow(hDisplay, myMaster.hWindowGl); //XIfEvent(hDisplay, &myXEvent, stXWaitMapped, (char* )myMaster.hWindowGl); } if(attribs.Slave != StWinSlave_slaveOff && myTiledCfg == TiledCfg_Separate && (!isSlaveIndependent() || myMonitors.size() > 1)) { XMoveResizeWindow(hDisplay, mySlave.hWindowGl, getSlaveLeft(), getSlaveTop(), getSlaveWidth(), getSlaveHeight()); } } else { Window aParent = ((Window )myParentWin != 0) ? (Window )myParentWin : myMaster.hWindow; if(aParent != 0) { // workaround bugs in some OpenGL drivers (Catalyst etc.) - entirely re-create window but not GL context XSetWindowAttributes aWinAttribsX = createDefaultAttribs(myMaster.stXDisplay); aWinAttribsX.override_redirect = True; // GL window always undecorated Window aWin = XCreateWindow(hDisplay, aParent, 0, 0, myRectNorm.width(), myRectNorm.height(), 0, myMaster.stXDisplay->getDepth(), InputOutput, myMaster.stXDisplay->getVisual(), CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttribsX); #if defined(ST_HAVE_EGL) EGLSurface anEglSurf = eglCreateWindowSurface(myMaster.hRC->getDisplay(), myMaster.hRC->getConfig(), aWin, NULL); if(anEglSurf == EGL_NO_SURFACE || !myMaster.hRC->makeCurrent(anEglSurf)) { if(anEglSurf == EGL_NO_SURFACE) { eglDestroySurface(myMaster.hRC->getDisplay(), anEglSurf); } #else if(!myMaster.hRC->makeCurrent(aWin)) { #endif ST_ERROR_LOG("X, FAILED to bind rendering context to NEW master window"); XDestroyWindow(hDisplay, aWin); XReparentWindow(hDisplay, myMaster.hWindowGl, aParent, 0, 0); } else { XUnmapWindow (hDisplay, myMaster.hWindowGl); XDestroyWindow(hDisplay, myMaster.hWindowGl); myMaster.hWindowGl = aWin; #if defined(ST_HAVE_EGL) eglDestroySurface(myMaster.hRC->getDisplay(), myMaster.eglSurface); myMaster.eglSurface = anEglSurf; #endif XSetStandardProperties(hDisplay, myMaster.hWindowGl, "master window", "master window", None, NULL, 0, NULL); myMaster.setupXDND(); if(attribs.ToHideCursor) { myMaster.setupNoCursor(); } XMapWindow(hDisplay, myMaster.hWindowGl); } myIsUpdated = true; } else { XUnmapWindow(hDisplay, myMaster.hWindowGl); // workaround for strange bugs XResizeWindow(hDisplay, myMaster.hWindowGl, 256, 256); if(attribs.Slave != StWinSlave_slaveOff && (!isSlaveIndependent() || myMonitors.size() > 1)) { XUnmapWindow (hDisplay, mySlave.hWindowGl); XResizeWindow(hDisplay, mySlave.hWindowGl, 256, 256); } XFlush(hDisplay); XMapWindow(hDisplay, myMaster.hWindowGl); //XIfEvent(hDisplay, &myXEvent, stXWaitMapped, (char* )myMaster.hWindowGl); if(attribs.Slave != StWinSlave_slaveOff && (!isSlaveIndependent() || myMonitors.size() > 1)) { XMapWindow(hDisplay, mySlave.hWindowGl); //XIfEvent(hDisplay, &myXEvent, stXWaitMapped, (char* )mySlave.hWindowGl); } XFlush(hDisplay); XMoveResizeWindow(hDisplay, myMaster.hWindowGl, myRectNorm.left(), myRectNorm.top(), myRectNorm.width(), myRectNorm.height()); } } XSetInputFocus(hDisplay, myMaster.hWindowGl, RevertToParent, CurrentTime); const StRectI_t& aRect = attribs.IsFullScreen ? myRectFull : myRectNorm; myStEvent.Type = stEvent_Size; myStEvent.Size.Time = getEventTime(); myStEvent.Size.SizeX = aRect.width(); myStEvent.Size.SizeY = aRect.height(); signals.onResize->emit(myStEvent.Size); // flushes the output buffer, most client apps needn't use this cause buffer is automatically flushed as needed by calls to XNextEvent()... XFlush(hDisplay); } void StWindowImpl::parseXDNDClientMsg() { const StXDisplayH& aDisplay = myMaster.stXDisplay; // myMaster.hWindow or myMaster.hWindowGl Window aWinReciever = ((XClientMessageEvent* )&myXEvent)->window; if(myXEvent.xclient.message_type == aDisplay->xDNDEnter) { myMaster.xDNDVersion = (myXEvent.xclient.data.l[1] >> 24); bool isMoreThan3 = myXEvent.xclient.data.l[1] & 1; Window aSrcWin = myXEvent.xclient.data.l[0]; /*ST_DEBUG_LOG( "Xdnd: Source window = 0x" + (int )myXEvent.xclient.data.l[0] + "\n" + "Supports > 3 types = " + (more_than_3) + "\n" + "Protocol version = " + myMaster.xDNDVersion + "\n" + "Type 1 = " + myMaster.getAtomName(myXEvent.xclient.data.l[2]) + "\n" + "Type 2 = " + myMaster.getAtomName(myXEvent.xclient.data.l[3]) + "\n" + "Type 3 = " + myMaster.getAtomName(myXEvent.xclient.data.l[4]) + "\n" );*/ if(isMoreThan3) { Property aProperty = aDisplay->readProperty(aSrcWin, aDisplay->xDNDTypeList); Atom* anAtomList = (Atom* )aProperty.data; for(int anIter = 0; anIter < aProperty.nitems; ++anIter) { if(anAtomList[anIter] == aDisplay->xDNDUriList) { myMaster.xDNDRequestType = aDisplay->xDNDUriList; break; } else if(anAtomList[anIter] == aDisplay->xDNDPlainText) { myMaster.xDNDRequestType = aDisplay->xDNDPlainText; break; } } XFree(aProperty.data); } else if((Atom )myXEvent.xclient.data.l[2] == aDisplay->xDNDPlainText || (Atom )myXEvent.xclient.data.l[3] == aDisplay->xDNDPlainText || (Atom )myXEvent.xclient.data.l[4] == aDisplay->xDNDPlainText) { myMaster.xDNDRequestType = aDisplay->xDNDPlainText; } else { myMaster.xDNDRequestType = XA_STRING; } } else if(myXEvent.xclient.message_type == aDisplay->xDNDPosition) {
StWinGlrc::StWinGlrc(EGLDisplay theDisplay, const bool theDebugCtx, int8_t theGlDepthSize) : myDisplay(theDisplay), myConfig(NULL), myRC(EGL_NO_CONTEXT) { if(theDisplay == EGL_NO_DISPLAY) { return; } EGLint aVerMajor = 0; EGLint aVerMinor = 0; if(eglInitialize(myDisplay, &aVerMajor, &aVerMinor) != EGL_TRUE) { ST_ERROR_LOG("EGL, FAILED to initialize Display"); return; } ST_DEBUG_LOG("EGL info\n" + " Version: " + aVerMajor + "." + aVerMinor + " (" + eglQueryString(myDisplay, EGL_VERSION) + ")\n" + " Vendor: " + eglQueryString(myDisplay, EGL_VENDOR) + "\n" + " Client APIs: " + eglQueryString(myDisplay, EGL_CLIENT_APIS) + "\n" + " Extensions: " + eglQueryString(myDisplay, EGL_EXTENSIONS)); const EGLint aConfigAttribs[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 0, EGL_DEPTH_SIZE, theGlDepthSize, #if defined(GL_ES_VERSION_2_0) EGL_CONFORMANT, EGL_OPENGL_ES2_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, #else EGL_CONFORMANT, EGL_OPENGL_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, #endif EGL_NONE }; EGLint aNbConfigs = 0; if(eglChooseConfig(myDisplay, aConfigAttribs, &myConfig, 1, &aNbConfigs) != EGL_TRUE) { ST_ERROR_LOG("EGL, eglChooseConfig FAILED"); return; } /*EGLenum aEglApi = eglQueryAPI(); switch(aEglApi) { case EGL_OPENGL_ES_API: ST_DEBUG_LOG("EGL API: OpenGL ES\n"); break; case EGL_OPENGL_API: ST_DEBUG_LOG("EGL API: OpenGL\n"); break; case EGL_OPENVG_API: ST_DEBUG_LOG("EGL API: OpenNVG\n"); break; case EGL_NONE: ST_DEBUG_LOG("EGL API: NONE\n"); break; }*/ #if defined(GL_ES_VERSION_2_0) if(eglBindAPI(EGL_OPENGL_ES_API) != EGL_TRUE) { ST_ERROR_LOG("EGL, EGL_OPENGL_ES_API is unavailable!"); return; } #else if(eglBindAPI(EGL_OPENGL_API) != EGL_TRUE) { ST_ERROR_LOG("EGL, EGL_OPENGL_API is unavailable!"); return; } #endif #define ST_EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 #define ST_EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB #define ST_EGL_CONTEXT_FLAGS_KHR 0x30FC #define ST_EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD #define ST_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD // for EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR #define ST_EGL_NO_RESET_NOTIFICATION_KHR 0x31BE #define ST_EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF // for EGL_CONTEXT_FLAGS_KHR #define ST_EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 #define ST_EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 #define ST_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 // for EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR #define ST_EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 #define ST_EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 const char* anEglExts = eglQueryString(myDisplay, EGL_EXTENSIONS); if(StGLContext::stglCheckExtension(anEglExts, "EGL_KHR_create_context")) { const EGLint anEglCtxAttribs[] = { ST_EGL_CONTEXT_FLAGS_KHR, theDebugCtx ? ST_EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0, #if defined(GL_ES_VERSION_2_0) EGL_CONTEXT_CLIENT_VERSION, 2, #endif //EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, ST_EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, EGL_NONE }; myRC = eglCreateContext(myDisplay, myConfig, EGL_NO_CONTEXT, anEglCtxAttribs); } if(myRC == EGL_NO_CONTEXT) { #if defined(GL_ES_VERSION_2_0) EGLint anEglCtxAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; #else EGLint* anEglCtxAttribs = NULL; #endif myRC = eglCreateContext(myDisplay, myConfig, EGL_NO_CONTEXT, anEglCtxAttribs); /*#if defined(GL_ES_VERSION_2_0) if(myRC == EGL_NO_CONTEXT) { myRC = eglCreateContext(myDisplay, myConfig, EGL_NO_CONTEXT, NULL); if(myRC != EGL_NO_CONTEXT) { ST_ERROR_LOG("EGL, eglCreateContext FAILED when ES 2.0 is requested!"); } } #endif*/ } if(myRC == EGL_NO_CONTEXT) { ST_ERROR_LOG("EGL, eglCreateContext FAILED"); } }
void StAndroidGlue::threadEntry() { if(myJavaVM->AttachCurrentThread(&myThJniEnv, NULL) < 0) { ST_ERROR_LOG("Failed to attach working thread to Java VM"); return; } THE_ANDROID_GLUE = this; StMessageBox::setCallback(msgBoxCallback); myConfig = AConfiguration_new(); AConfiguration_fromAssetManager(myConfig, myActivity->assetManager); updateMonitors(); printConfig(); ALooper* aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); ALooper_addFd(aLooper, myMsgRead, LooperId_MAIN, ALOOPER_EVENT_INPUT, NULL, &myCmdPollSource); myLooper = aLooper; pthread_mutex_lock(&myMutex); myIsRunning = true; pthread_cond_broadcast(&myCond); pthread_mutex_unlock(&myMutex); // try to load stereo APIs /**jclass aJClass_Real3D = myThJniEnv->FindClass("com/lge/real3d/Real3D"); if(aJClass_Real3D != NULL) { jmethodID aJMet_isStereoDisplayAvailable = myThJniEnv->GetStaticMethodID(aJClass_Real3D, "isStereoDisplayAvailable", "(Landroid/content/Contex;)Z"); postMessage("com.lge.real3d.Real3D !!!"); } jclass aJClass_HTC = myThJniEnv->FindClass("com/htc/view/DisplaySetting"); if(aJClass_HTC != NULL) { jmethodID aJMet_isStereoDisplayAvailable = myThJniEnv->GetStaticMethodID(aJClass_HTC, "setStereoscopic3DFormat", "(Landroid/view/Surface;I)Z"); postMessage("com.htc.view.DisplaySetting !!!"); } jclass aJClass_Sharp = myThJniEnv->FindClass("jp/co/sharp/android/stereo3dlcd/SurfaceController"); if(aJClass_Sharp != NULL) { jmethodID aJMet_setStereoView = myThJniEnv->GetMethodID(aJClass_Sharp, "setStereoView", "(Z)V"); postMessage("jp.co.sharp.android.stereo3dlcd !!!"); }*/ createApplication(); if(!myApp.isNull()) { if(!myApp->open()) { stError("Error: application can not be executed!"); } myApp->exec(); } else { stError("Error: no application to execute!"); } myApp.nullify(); // application is done but we are waiting for destroying event... bool isFirstWait = true; for(; !myToDestroy; ) { if(isFirstWait) { postExit(); isFirstWait = false; } StAndroidPollSource* aSource = NULL; int aNbEvents = 0; ALooper_pollAll(-1, NULL, &aNbEvents, (void** )&aSource); if(aSource != NULL) { aSource->process(this, aSource); } } freeSavedState(); pthread_mutex_lock(&myMutex); if(myInputQueue != NULL) { AInputQueue_detachLooper(myInputQueue); } AConfiguration_delete(myConfig); pthread_cond_broadcast(&myCond); pthread_mutex_unlock(&myMutex); myThJniEnv = NULL; StMessageBox::setCallback(NULL); THE_ANDROID_GLUE = NULL; myJavaVM->DetachCurrentThread(); }
int StWinHandles::glCreateContext(StWinHandles* theSlave, const StRectI_t& theRect, const int theDepthSize, const bool theIsQuadStereo, const bool theDebugCtx) { (void )theRect; #ifdef _WIN32 ThreadGL = StThread::getCurrentThreadId(); ST_DEBUG_LOG("WinAPI, glCreateContext, ThreadGL= " + ThreadGL + ", ThreadWnd= " + ThreadWnd); hDC = GetDC(hWindowGl); ST_GL_ERROR_CHECK(hDC != NULL, STWIN_ERROR_WIN32_GLDC, "WinAPI, Can't create Master GL Device Context"); if(theSlave != NULL) { theSlave->ThreadGL = ThreadGL; theSlave->hDC = GetDC(theSlave->hWindowGl); ST_GL_ERROR_CHECK(theSlave->hDC != NULL, STWIN_ERROR_WIN32_GLDC, "WinAPI, Can't create Slave GL Device Context"); } HGLRC aRendCtx = NULL; { PIXELFORMATDESCRIPTOR aPixFrmtDesc = THE_PIXELFRMT_DOUBLE; aPixFrmtDesc.cDepthBits = (BYTE )theDepthSize; if(theIsQuadStereo) { aPixFrmtDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_GDI | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_STEREO; } HMODULE aModule = GetModuleHandleW(NULL); hWinTmp = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE, ClassTmp.toCString(), L"TmpWnd", WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED, // always create temporary window on main screen // to workaround sporadic bugs (access violation) in AMD Catalyst drivers 2, 2, 4, 4, //theRect.left() + 2, theRect.top() + 2, 4, 4, NULL, NULL, aModule, NULL); ST_GL_ERROR_CHECK(hWinTmp != NULL, STWIN_ERROR_WIN32_GLDC, "WinAPI, Temporary window creation error"); HDC aDevCtxTmp = GetDC(hWinTmp); int aPixFrmtIdTmp = ChoosePixelFormat(aDevCtxTmp, &aPixFrmtDesc); ST_GL_ERROR_CHECK(aPixFrmtIdTmp != 0, STWIN_ERROR_WIN32_PIXELFORMATF, "WinAPI, Can't find a suitable PixelFormat for Tmp"); ST_GL_ERROR_CHECK(SetPixelFormat(aDevCtxTmp, aPixFrmtIdTmp, &aPixFrmtDesc), STWIN_ERROR_WIN32_PIXELFORMATS, "WinAPI, Can't set the PixelFormat for Master"); StWinGlrcH aRendCtxTmp = new StWinGlrc(aDevCtxTmp, NULL); ST_GL_ERROR_CHECK(aRendCtxTmp->isValid(), STWIN_ERROR_WIN32_GLRC_CREATE, "WinAPI, Can't create GL Rendering Context"); ST_GL_ERROR_CHECK(aRendCtxTmp->makeCurrent(aDevCtxTmp), STWIN_ERROR_WIN32_GLRC_ACTIVATE, "WinAPI, Can't activate Tmp GL Rendering Context"); StGLContext aCtx(false); ST_GL_ERROR_CHECK(aCtx.stglInit(), STWIN_ERROR_WIN32_GLRC_ACTIVATE, "WinAPI, Broken Tmp GL Rendering Context"); int aPixFrmtId = 0; if(aCtx.extAll->wglChoosePixelFormatARB != NULL) { const int aPixAttribs[] = { WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, WGL_SUPPORT_OPENGL_ARB, GL_TRUE, WGL_DOUBLE_BUFFER_ARB, GL_TRUE, WGL_STEREO_ARB, theIsQuadStereo ? GL_TRUE : GL_FALSE, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, //WGL_SAMPLE_BUFFERS_ARB, 1, //WGL_SAMPLES_ARB, 8, // WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 WGL_COLOR_BITS_ARB, 24, WGL_DEPTH_BITS_ARB, theDepthSize, WGL_STENCIL_BITS_ARB, 0, 0, 0, }; unsigned int aFrmtsNb = 0; aCtx.extAll->wglChoosePixelFormatARB(hDC, aPixAttribs, NULL, 1, &aPixFrmtId, &aFrmtsNb); if(theSlave != NULL) { int aPixFrmtIdSlave = 0; aCtx.extAll->wglChoosePixelFormatARB(theSlave->hDC, aPixAttribs, NULL, 1, &aPixFrmtIdSlave, &aFrmtsNb); if(aPixFrmtIdSlave != aPixFrmtId) { ST_ERROR_LOG("Slave window returns another pixel format! Try to ignore..."); } } } else { aPixFrmtId = ChoosePixelFormat(hDC, &aPixFrmtDesc); if(theSlave != NULL && ChoosePixelFormat(theSlave->hDC, &aPixFrmtDesc) != aPixFrmtId) { ST_ERROR_LOG("Slave window returns another pixel format! Try to ignore..."); } } ST_GL_ERROR_CHECK(aPixFrmtId != 0, STWIN_ERROR_WIN32_PIXELFORMATF, "WinAPI, Can't find a suitable PixelFormat for Master"); DescribePixelFormat(hDC, aPixFrmtId, sizeof(PIXELFORMATDESCRIPTOR), &aPixFrmtDesc); if(theIsQuadStereo) { if((aPixFrmtDesc.dwFlags & PFD_STEREO) == 0) { ST_ERROR_LOG("WinAPI, Quad Buffered stereo is not supported"); } } ST_GL_ERROR_CHECK(SetPixelFormat(hDC, aPixFrmtId, &aPixFrmtDesc), STWIN_ERROR_WIN32_PIXELFORMATS, "WinAPI, Can't set the PixelFormat for Master"); ST_GL_ERROR_CHECK(theSlave == NULL || SetPixelFormat(theSlave->hDC, aPixFrmtId, &aPixFrmtDesc), STWIN_ERROR_WIN32_PIXELFORMATS, "WinAPI, Can't set the PixelFormat for Slave"); if(aCtx.extAll->wglCreateContextAttribsARB != NULL) { // Beware! NVIDIA drivers reject context creation when WGL_CONTEXT_PROFILE_MASK_ARB are specified // but not WGL_CONTEXT_MAJOR_VERSION_ARB/WGL_CONTEXT_MINOR_VERSION_ARB int aCtxAttribs[] = { //WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //WGL_CONTEXT_MINOR_VERSION_ARB, 2, //WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, //WGL_CONTEXT_CORE_PROFILE_BIT_ARB, WGL_CONTEXT_FLAGS_ARB, theDebugCtx ? WGL_CONTEXT_DEBUG_BIT_ARB : 0, 0, 0 }; aRendCtx = aCtx.extAll->wglCreateContextAttribsARB(hDC, NULL, aCtxAttribs); } aRendCtxTmp.nullify(); destroyWindow(hWinTmp); } hRC = new StWinGlrc(hDC, aRendCtx); ST_GL_ERROR_CHECK(hRC->isValid(), STWIN_ERROR_WIN32_GLRC_CREATE, "WinAPI, Can't create GL Rendering Context"); if(theSlave != NULL) { theSlave->hRC = hRC; } ST_GL_ERROR_CHECK(hRC->makeCurrent(hDC), STWIN_ERROR_WIN32_GLRC_ACTIVATE, "WinAPI, Can't activate Master GL Rendering Context"); return STWIN_INIT_SUCCESS; #elif defined(__linux__) // create an OpenGL rendering context #if defined(ST_HAVE_EGL) || defined(__ANDROID__) // GL context is created beforehand for EGL ST_GL_ERROR_CHECK(!hRC.isNull() && hRC->isValid(), STWIN_ERROR_X_GLRC_CREATE, "EGL, could not create rendering context for Master"); #if defined(__ANDROID__) EGLint aFormat = 0; eglGetConfigAttrib(hRC->getDisplay(), hRC->getConfig(), EGL_NATIVE_VISUAL_ID, &aFormat); ANativeWindow_setBuffersGeometry(hWindowGl, 0, 0, aFormat); #endif eglSurface = eglCreateWindowSurface(hRC->getDisplay(), hRC->getConfig(), hWindowGl, NULL); if(theSlave != NULL) { theSlave->hRC = hRC; theSlave->eglSurface = eglCreateWindowSurface(hRC->getDisplay(), hRC->getConfig(), theSlave->hWindowGl, NULL); // bind the rendering context to the window ST_GL_ERROR_CHECK(hRC->makeCurrent(theSlave->eglSurface), STWIN_ERROR_X_GLRC_CREATE, "EGL, Can't activate Slave GL Rendering Context"); } // bind the rendering context to the window ST_GL_ERROR_CHECK(hRC->makeCurrent(eglSurface), STWIN_ERROR_X_GLRC_CREATE, "EGL, Can't activate Master GL Rendering Context"); return STWIN_INIT_SUCCESS; #else // GLX hRC = new StWinGlrc(stXDisplay, theDebugCtx); ST_GL_ERROR_CHECK(hRC->isValid(), STWIN_ERROR_X_GLRC_CREATE, "GLX, could not create rendering context for Master"); if(theSlave != NULL) { theSlave->hRC = hRC; // bind the rendering context to the window ST_GL_ERROR_CHECK(hRC->makeCurrent(theSlave->hWindowGl), STWIN_ERROR_X_GLRC_CREATE, "GLX, Can't activate Slave GL Rendering Context"); } // bind the rendering context to the window ST_GL_ERROR_CHECK(hRC->makeCurrent(hWindowGl), STWIN_ERROR_X_GLRC_CREATE, "GLX, Can't activate Master GL Rendering Context"); return STWIN_INIT_SUCCESS; #endif // GLX or EGL #endif }
StWinHandles::StWinHandles() #ifdef _WIN32 : ThreadWnd(0), EventMsgThread(true), hWindow(NULL), hWindowGl(NULL), hWinTmp(NULL), myMKeyStop(GlobalAddAtom(MAKEINTATOM(VK_MEDIA_STOP))), myMKeyPlay(GlobalAddAtom(MAKEINTATOM(VK_MEDIA_PLAY_PAUSE))), myMKeyPrev(GlobalAddAtom(MAKEINTATOM(VK_MEDIA_PREV_TRACK))), myMKeyNext(GlobalAddAtom(MAKEINTATOM(VK_MEDIA_NEXT_TRACK))), ThreadGL(0), hDC(NULL) { // #elif defined(__linux__) : hWindow(0), hWindowGl(0), stXDisplay(), iconImage(0), iconShape(0), xDNDRequestType(None), xDNDSrcWindow(0), xDNDVersion(0), xrandrEventBase(0), isRecXRandrEvents(false) { // #endif } StWinHandles::~StWinHandles() { close(); } void StWinHandles::glSwap() { #ifdef _WIN32 if(hDC != NULL) { SwapBuffers(hDC); } #elif defined(__linux__) if(!stXDisplay.isNull() && hRC->makeCurrent(hWindowGl)) { // if GL rendering context is bound to another drawable - we got BadMatch error glXSwapBuffers(stXDisplay->hDisplay, hWindowGl); } #endif } bool StWinHandles::glMakeCurrent() { #ifdef _WIN32 if(hDC != NULL && !hRC.isNull()) { return hRC->isCurrent(hDC) || hRC->makeCurrent(hDC); } #elif defined(__linux__) if(!stXDisplay.isNull() && !hRC.isNull()) { return hRC->makeCurrent(hWindowGl); } #endif return false; } /** * Auxiliary macros. */ #define ST_GL_ERROR_CHECK(theTrueCondition, theErrCode, theErrDesc) \ if(!(theTrueCondition)) { \ stError(theErrDesc); \ return theErrCode; \ } int StWinHandles::glCreateContext(StWinHandles* theSlave, const StRectI_t& theRect, const int theDepthSize, const bool theIsQuadStereo, const bool theDebugCtx) { #ifdef _WIN32 ThreadGL = StThread::getCurrentThreadId(); ST_DEBUG_LOG("WinAPI, glCreateContext, ThreadGL= " + ThreadGL + ", ThreadWnd= " + ThreadWnd); hDC = GetDC(hWindowGl); ST_GL_ERROR_CHECK(hDC != NULL, STWIN_ERROR_WIN32_GLDC, "WinAPI, Can't create Master GL Device Context"); if(theSlave != NULL) { theSlave->ThreadGL = ThreadGL; theSlave->hDC = GetDC(theSlave->hWindowGl); ST_GL_ERROR_CHECK(theSlave->hDC != NULL, STWIN_ERROR_WIN32_GLDC, "WinAPI, Can't create Slave GL Device Context"); } PIXELFORMATDESCRIPTOR aPixFrmtDesc = THE_PIXELFRMT_DOUBLE; aPixFrmtDesc.cDepthBits = (BYTE )theDepthSize; if(theIsQuadStereo) { aPixFrmtDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_GDI | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_STEREO; } int aPixFrmtId = ChoosePixelFormat(hDC, &aPixFrmtDesc); ST_GL_ERROR_CHECK(aPixFrmtId != 0, STWIN_ERROR_WIN32_PIXELFORMATF, "WinAPI, Can't find a suitable PixelFormat for Master"); if(theSlave != NULL && ChoosePixelFormat(theSlave->hDC, &aPixFrmtDesc) != aPixFrmtId) { ST_ERROR_LOG("Slave window returns another pixel format! Try to ignore..."); } if(theIsQuadStereo) { DescribePixelFormat(hDC, aPixFrmtId, sizeof(PIXELFORMATDESCRIPTOR), &aPixFrmtDesc); if((aPixFrmtDesc.dwFlags & PFD_STEREO) == 0) { ST_ERROR_LOG("WinAPI, Quad Buffered stereo not supported"); } else { //bool isVistaPlus = StSys::isVistaPlus(); //bool isWin8Plus = StSys::isWin8Plus(); ///myNeedsFullscr } } HMODULE aModule = GetModuleHandleW(NULL); hWinTmp = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE, ClassTmp.toCString(), L"TmpWnd", WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED, theRect.left() + 2, theRect.top() + 2, 4, 4, NULL, NULL, aModule, NULL); ST_GL_ERROR_CHECK(hWinTmp != NULL, STWIN_ERROR_WIN32_GLDC, "WinAPI, Temporary window creation error"); HDC aDevCtxTmp = GetDC(hWinTmp); ST_GL_ERROR_CHECK(aPixFrmtId != 0, STWIN_ERROR_WIN32_PIXELFORMATF, "WinAPI, Can't find a suitable PixelFormat for Tmp"); ST_GL_ERROR_CHECK(SetPixelFormat(aDevCtxTmp, aPixFrmtId, &aPixFrmtDesc), STWIN_ERROR_WIN32_PIXELFORMATS, "WinAPI, Can't set the PixelFormat for Master"); StWinGlrcH aRendCtxTmp = new StWinGlrc(aDevCtxTmp, NULL); ST_GL_ERROR_CHECK(aRendCtxTmp->isValid(), STWIN_ERROR_WIN32_GLRC_CREATE, "WinAPI, Can't create GL Rendering Context"); ST_GL_ERROR_CHECK(aRendCtxTmp->makeCurrent(aDevCtxTmp), STWIN_ERROR_WIN32_GLRC_ACTIVATE, "WinAPI, Can't activate Tmp GL Rendering Context"); StGLContext aCtx; ST_GL_ERROR_CHECK(aCtx.stglInit(), STWIN_ERROR_WIN32_GLRC_ACTIVATE, "WinAPI, Broken Tmp GL Rendering Context"); if(aCtx.extAll->wglChoosePixelFormatARB != NULL) { const int aPixAttribs[] = { WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, WGL_SUPPORT_OPENGL_ARB, GL_TRUE, WGL_DOUBLE_BUFFER_ARB, GL_TRUE, WGL_STEREO_ARB, theIsQuadStereo ? GL_TRUE : GL_FALSE, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, //WGL_SAMPLE_BUFFERS_ARB, 1, //WGL_SAMPLES_ARB, 8, // WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 WGL_COLOR_BITS_ARB, 24, WGL_DEPTH_BITS_ARB, theDepthSize, WGL_STENCIL_BITS_ARB, 0, 0, 0, }; unsigned int aFrmtsNb = 0; aCtx.extAll->wglChoosePixelFormatARB(hDC, aPixAttribs, NULL, 1, &aPixFrmtId, &aFrmtsNb); } ST_GL_ERROR_CHECK(SetPixelFormat(hDC, aPixFrmtId, &aPixFrmtDesc), STWIN_ERROR_WIN32_PIXELFORMATS, "WinAPI, Can't set the PixelFormat for Master"); ST_GL_ERROR_CHECK(theSlave == NULL || SetPixelFormat(theSlave->hDC, aPixFrmtId, &aPixFrmtDesc), STWIN_ERROR_WIN32_PIXELFORMATS, "WinAPI, Can't set the PixelFormat for Slave"); HGLRC aRendCtx = NULL; if(aCtx.extAll->wglCreateContextAttribsARB != NULL) { // Beware! NVIDIA drivers reject context creation when WGL_CONTEXT_PROFILE_MASK_ARB are specified // but not WGL_CONTEXT_MAJOR_VERSION_ARB/WGL_CONTEXT_MINOR_VERSION_ARB int aCtxAttribs[] = { //WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //WGL_CONTEXT_MINOR_VERSION_ARB, 2, //WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, //WGL_CONTEXT_CORE_PROFILE_BIT_ARB, WGL_CONTEXT_FLAGS_ARB, theDebugCtx ? WGL_CONTEXT_DEBUG_BIT_ARB : 0, 0, 0 }; aRendCtx = aCtx.extAll->wglCreateContextAttribsARB(hDC, NULL, aCtxAttribs); } aRendCtxTmp.nullify(); destroyWindow(hWinTmp); hRC = new StWinGlrc(hDC, aRendCtx); ST_GL_ERROR_CHECK(hRC->isValid(), STWIN_ERROR_WIN32_GLRC_CREATE, "WinAPI, Can't create GL Rendering Context"); if(theSlave != NULL) { theSlave->hRC = hRC; } ST_GL_ERROR_CHECK(hRC->makeCurrent(hDC), STWIN_ERROR_WIN32_GLRC_ACTIVATE, "WinAPI, Can't activate Master GL Rendering Context"); return STWIN_INIT_SUCCESS; #elif defined(__linux__) // create an OpenGL rendering context hRC = new StWinGlrc(stXDisplay, theDebugCtx); ST_GL_ERROR_CHECK(hRC->isValid(), STWIN_ERROR_X_GLRC_CREATE, "GLX, could not create rendering context for Master"); if(theSlave != NULL) { theSlave->hRC = hRC; // bind the rendering context to the window ST_GL_ERROR_CHECK(hRC->makeCurrent(theSlave->hWindowGl), STWIN_ERROR_X_GLRC_CREATE, "GLX, Can't activate Slave GL Rendering Context"); } // bind the rendering context to the window ST_GL_ERROR_CHECK(hRC->makeCurrent(hWindowGl), STWIN_ERROR_X_GLRC_CREATE, "GLX, Can't activate Master GL Rendering Context"); return STWIN_INIT_SUCCESS; #endif }
StAndroidGlue::StAndroidGlue(ANativeActivity* theActivity, void* theSavedState, size_t theSavedStateSize) : myActivity(theActivity), myConfig(NULL), myLooper(NULL), myInputQueue(NULL), myInputQueuePending(NULL), myWindow(NULL), myWindowPending(NULL), myIsChangingSurface(false), myWindowFlags(0), myActivityState(0), myMemoryClassMiB(0), mySavedState(NULL), mySavedStateSize(0), myJavaVM(NULL), myThJniEnv(NULL), myMsgRead(0), myMsgWrite(0), myToEnableStereoHW(false), myHasOrientSensor(false), myIsPoorOrient(false), myToTrackOrient(false), myIsRunning(false), myIsStateSaved(false), myToDestroy(false) { theActivity->instance = this; theActivity->env->GetJavaVM(&myJavaVM); // allow FFmpeg to use JNI calls stAV::setJavaVM(myJavaVM); JNIEnv* aJniEnv = myActivity->env; jclass aJClass_Activity = aJniEnv->GetObjectClass(myActivity->clazz); jmethodID aJMet_getSystemService = aJniEnv->GetMethodID(aJClass_Activity, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"); jstring aJStr_activity = aJniEnv->NewStringUTF("activity"); jobject aJActivityMgr = aJniEnv->CallObjectMethod(myActivity->clazz, aJMet_getSystemService, aJStr_activity); aJniEnv->DeleteLocalRef(aJStr_activity); if(aJActivityMgr != NULL) { // getLargeMemoryClass() jclass aJClass_ActivityManager = aJniEnv->GetObjectClass(aJActivityMgr); jmethodID aJMet_getMemoryClass = aJniEnv->GetMethodID(aJClass_ActivityManager, "getMemoryClass", "()I"); myMemoryClassMiB = aJniEnv->CallIntMethod(aJActivityMgr, aJMet_getMemoryClass); } jmethodID aJMet_getStAppClass = aJniEnv->GetMethodID(aJClass_Activity, "getStAppClass", "()Ljava/lang/String;"); myStAppClass = stStringFromJava(aJniEnv, (jstring )aJniEnv->CallObjectMethod(myActivity->clazz, aJMet_getStAppClass)); jmethodID aJMet_getStereoApiInfo = aJniEnv->GetMethodID(aJClass_Activity, "getStereoApiInfo", "()Ljava/lang/String;"); myStereoApiId = stStringFromJava(aJniEnv, (jstring )aJniEnv->CallObjectMethod(myActivity->clazz, aJMet_getStereoApiInfo)); // workaround NativeActivity design issues - notify Java StActivity class about C++ pointer to StAndroidGlue instance jmethodID aJMet_setCppInstance = aJniEnv->GetMethodID(aJClass_Activity, "setCppInstance", "(J)V"); aJniEnv->CallVoidMethod(myActivity->clazz, aJMet_setCppInstance, (jlong )this); readOpenPath(); myCmdPollSource.id = LooperId_MAIN; myCmdPollSource.app = this; myCmdPollSource.process = StAndroidGlue::processCommandWrapper; myInputPollSource.id = LooperId_INPUT; myInputPollSource.app = this; myInputPollSource.process = StAndroidGlue::processInputWrapper; theActivity->callbacks->onDestroy = StAndroidGlue::onDestroy; theActivity->callbacks->onStart = StAndroidGlue::onStart; theActivity->callbacks->onResume = StAndroidGlue::onResume; theActivity->callbacks->onSaveInstanceState = StAndroidGlue::onSaveInstanceState; theActivity->callbacks->onPause = StAndroidGlue::onPause; theActivity->callbacks->onStop = StAndroidGlue::onStop; theActivity->callbacks->onConfigurationChanged = StAndroidGlue::onConfigurationChanged; theActivity->callbacks->onLowMemory = StAndroidGlue::onLowMemory; theActivity->callbacks->onWindowFocusChanged = StAndroidGlue::onWindowFocusChanged; theActivity->callbacks->onNativeWindowCreated = StAndroidGlue::onNativeWindowCreated; theActivity->callbacks->onNativeWindowDestroyed = StAndroidGlue::onNativeWindowDestroyed; theActivity->callbacks->onInputQueueCreated = StAndroidGlue::onInputQueueCreated; theActivity->callbacks->onInputQueueDestroyed = StAndroidGlue::onInputQueueDestroyed; pthread_mutex_init(&myMutex, NULL); pthread_cond_init (&myCond, NULL); if(theSavedState != NULL) { mySavedState = ::malloc(theSavedStateSize); mySavedStateSize = theSavedStateSize; memcpy(mySavedState, theSavedState, theSavedStateSize); } int aMsgPipe[2]; if(::pipe(aMsgPipe)) { ST_ERROR_LOG("could not create pipe: " + strerror(errno)); return; } myMsgRead = aMsgPipe[0]; myMsgWrite = aMsgPipe[1]; }