// -*- C++ -*- /* * Simple MultimEdia LiTerator(SMELT) * by Chris Xiong 2015 * SMELT system implementation * * WARNING: This library is in development and interfaces would be very * unstable. * */ #include "smelt_internal.hpp" static const char* SYS_SDL_SRCFN="smelt/sdl/sys_sdl.cpp"; int refcnt=0; SMELT_IMPL *pSM=0; SMELT* smGetInterface(int apilevel) { if(apilevel==SMELT_APILEVEL) return(SMELT*)SMELT_IMPL::getInterface(); else return 0; } SMELT_IMPL* SMELT_IMPL::getInterface() { if(!pSM)pSM=new SMELT_IMPL(); ++refcnt;return pSM; } void SMELT_IMPL::smRelease() { --refcnt; if(!refcnt) { if(pSM->hwnd)pSM->smFinale(); delete pSM;pSM=0; } } bool SMELT_IMPL::smInit() { smLog("%s:" SLINE ": Initalizing SMELT...\n",SYS_SDL_SRCFN); smLog("%s:" SLINE ": SMELT api version %d\n",SYS_SDL_SRCFN,SMELT_APILEVEL); time_t t=time(NULL); smLog("%s:" SLINE ": Date %s",SYS_SDL_SRCFN,asctime(localtime(&t))); #ifdef WIN32 OSVERSIONINFO os_ver; MEMORYSTATUS mem_st; os_ver.dwOSVersionInfoSize=sizeof(os_ver); GetVersionEx(&os_ver); smLog("%s:" SLINE ": OS: Windows %ld.%ld.%ld\n", SYS_SDL_SRCFN,os_ver.dwMajorVersion,os_ver.dwMinorVersion,os_ver.dwBuildNumber); int CPUInfo[4]={-1}; __cpuid(CPUInfo,0x80000000); unsigned int nExIds=CPUInfo[0]; char *cpuName,*loced;cpuName=calloc(0x40,sizeof(char));loced=cpuName; for(unsigned int i=0x80000000;i<=nExIds;++i) { __cpuid(CPUInfo, i); if(i==0x80000002) memcpy(cpuName,CPUInfo,sizeof(CPUInfo)); else if(i==0x80000003) memcpy(cpuName+16,CPUInfo,sizeof(CPUInfo)); else if(i==0x80000004) memcpy(cpuName+32, CPUInfo, sizeof(CPUInfo)); } while(*cpuName=' ')++cpuName; smLog("%s:" SLINE ": CPU: %s\n", SYS_SDL_SRCFN,cpuName); free(loced); GlobalMemoryStatus(&mem_st); smLog("%s:" SLINE ": Memory: %ldK total, %ldK free\n", SYS_SDL_SRCFN,mem_st.dwTotalPhys/1024L,mem_st.dwAvailPhys/1024L); #else system("uname -svm > /tmp/os.out"); char osv[100];FILE* a=fopen("/tmp/os.out","r");fgets(osv,100,a);fclose(a); osv[strlen(osv)-1]='\0'; smLog("%s:" SLINE ": OS: %s\n",SYS_SDL_SRCFN,osv); system("rm /tmp/os.out"); system("cat /proc/cpuinfo | grep name -m 1 > /tmp/cpu.out"); a=fopen("/tmp/cpu.out","r");fgets(osv,100,a);fclose(a); osv[strlen(osv)-1]='\0';char *ptr=osv;while(*ptr!=':')++ptr;ptr+=2; smLog("%s:" SLINE ": CPU: %s\n",SYS_SDL_SRCFN,osv); system("rm /tmp/cpu.out"); a=fopen("/proc/meminfo","r"); unsigned totalm,freem; fscanf(a,"MemTotal: %u kB\n",&totalm); fscanf(a,"MemFree: %u kB\n",&freem); smLog("%s:" SLINE ": RAM: %ukB installed, %ukB free\n",SYS_SDL_SRCFN,totalm,freem); fclose(a); #endif if(SDL_Init(SDL_INIT_VIDEO)==-1) { smLog("%s:" SLINE ": SDL_Init() failed with error %s\n",SYS_SDL_SRCFN,SDL_GetError()); return false; } if(SDL_GL_LoadLibrary(NULL)==-1) { smLog("%s:" SLINE ": SDL_GL_LoadLibrary() failed with error %s\n",SYS_SDL_SRCFN,SDL_GetError()); return false; } SDL_DisplayMode vidinfo; if(SDL_GetDesktopDisplayMode(0,&vidinfo)) { smLog("%s:" SLINE ": SDL_GetDesktopDisplayMode() failed with error %s\n",SYS_SDL_SRCFN,SDL_GetError()); SDL_Quit(); return false; } dispw=vidinfo.w;disph=vidinfo.h; smLog("%s:" SLINE ": Screen: %d x %d\n",SYS_SDL_SRCFN,dispw,disph); Uint32 flags=SDL_WINDOW_OPENGL; if(!windowed)flags|=SDL_WINDOW_FULLSCREEN; SDL_Window *screen=SDL_CreateWindow(winTitle,SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,scrw,scrh,flags); hwnd=(void*)screen; glContext=SDL_GL_CreateContext(screen); SDL_GL_SetAttribute(SDL_GL_RED_SIZE,8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE,8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,16); SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL,1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); SDL_GL_SetSwapInterval(vsync?1:0); if(!hwnd) { smLog("%s:" SLINE ": SDL_CreateWindow() failed with error %s\n",SYS_SDL_SRCFN,SDL_GetError()); SDL_Quit(); return false; } if(!windowed) { mouseOver=true; if(!pSM->Active)pSM->focusChange(true); } SDL_ShowCursor(hideMouse?SDL_DISABLE:SDL_ENABLE); SDL_EnableScreenSaver(); initInput(); if(!initOGL()){smFinale();return false;} if(!initOAL()){smFinale();return false;} t0=SDL_GetTicks();dt=fcnt=0;fps=.0; updateFPSDelay=.0; return true; } void SMELT_IMPL::smFinale() { smLog("%s:" SLINE ": Cleaning up...\n",SYS_SDL_SRCFN); clearQueue();finiOAL();finiOGL(); SDL_GL_UnloadLibrary();SDL_Quit();hwnd=0; } void SMELT_IMPL::smMainLoop() { if(!hwnd)return smLog("%s:" SLINE ": Error: SMELT is not initialized.\n",SYS_SDL_SRCFN); if(!pUpdateFunc&&!updateHandler) return smLog("%s:" SLINE ": UpdateFunc is not defined.\n",SYS_SDL_SRCFN); Active=true; for(;;) { SDL_Event e; bool loopcont=true; while(SDL_PollEvent(&e)&&loopcont)loopcont=procSDLEvent(e); if(!loopcont)break; if(Active||noSuspend) { Uint32 sdlticks; do{sdlticks=SDL_GetTicks();dt=sdlticks-t0;}while(dt<1); if(dt>=fixDelta) { timeDelta=dt/1000.; if(timeDelta>0.2)timeDelta=fixDelta?fixDelta/1000.:.01; ++fcnt;updateFPSDelay+=timeDelta;t0=sdlticks;timeS+=timeDelta; if(updateFPSDelay>1){fps=fcnt/updateFPSDelay;updateFPSDelay=.0;fcnt=0;} if(pUpdateFunc){if(pUpdateFunc())break;} if(updateHandler){if(updateHandler->handlerFunc())break;} for(int i=1;i<=255;++i)keylst[i]=((keyz[i]&4)!=0); clearQueue(); } else if(fixDelta&&dt+3Active)pSM->focusChange(true);} } } void SMELT_IMPL::smLogFile(const char* path) { strcpy(logFile,path); FILE *tf=fopen(logFile,"w"); if(!tf)*logFile=0;else fclose(tf); } void SMELT_IMPL::smLog(const char* format,...) { va_list ap; va_start(ap,format);vfprintf(stderr,format,ap);va_end(ap); FILE *logf=fopen(logFile,"a");if(!logf)return; va_start(ap,format);vfprintf(logf,format,ap);va_end(ap); fclose(logf); } void SMELT_IMPL::smScreenShot(const char* path) { if(pOpenGLDevice) { #if SDL_BYTEORDER==SDL_BIG_ENDIAN const Uint32 rmask=0xFF0000; const Uint32 gmask=0x00FF00; const Uint32 bmask=0x0000FF; #else const Uint32 rmask=0x0000FF; const Uint32 gmask=0x00FF00; const Uint32 bmask=0xFF0000; #endif pOpenGLDevice->glFinish(); SDL_Surface *screen=SDL_GetWindowSurface((SDL_Window*)hwnd); SDL_Surface *surface=SDL_CreateRGBSurface(SDL_SWSURFACE,screen->w,screen->h,24,rmask,gmask,bmask,0); pOpenGLDevice->glReadPixels(0,0,screen->w,screen->h,GL_RGB,GL_UNSIGNED_BYTE,surface->pixels); flipSDLSurface(surface->pitch,surface->h,surface->pixels); SDL_SaveBMP(surface,path); SDL_FreeSurface(surface); } } void SMELT_IMPL::smSetFPS(int fps) { vsync=(fps==FPS_VSYNC); if(pOpenGLDevice)SDL_GL_SetSwapInterval(vsync?1:0); if(fps>0)fixDelta=1000./fps;else fixDelta=0; } float SMELT_IMPL::smGetFPS(){return fps;} float SMELT_IMPL::smGetDelta(){return timeDelta;} float SMELT_IMPL::smGetTime(){return timeS;} SMELT_IMPL::SMELT_IMPL() { hwnd=NULL;Active=false;memset(curError,0,sizeof(curError)); pUpdateFunc=pUnFocFunc=pFocFunc=pQuitFunc=NULL; updateHandler=unFocHandler=focHandler=quitHandler=NULL; Icon=NULL;strcpy(winTitle,"untitled");scrw=dispw=800;scrh=disph=600; windowed=vsync=false;memset(logFile,0,sizeof(logFile)); limfps=0;hideMouse=true;noSuspend=false; pOpenGLDevice=NULL;targets=NULL;curTarget=NULL; textures=NULL;vertexArray=NULL;vertexBuf=NULL;indexBuf=NULL;primTex=0; pOpenALDevice=NULL;mute=false;inpQueue=NULL;posz=0;posx=posy=.0; mouseOver=true;captured=false;keymods=KMOD_NONE;zbufenabled=false; timeDelta=updateFPSDelay=fps=.0;fcnt=dt=fixDelta=0; } void SMELT_IMPL::focusChange(bool actif) { Active=actif; if(actif){pFocFunc?pFocFunc():0;focHandler?focHandler->handlerFunc():0;} else {pUnFocFunc?pUnFocFunc():0;unFocHandler?unFocHandler->handlerFunc():0;}; } bool SMELT_IMPL::procSDLEvent(const SDL_Event &e) { switch(e.type) { case SDL_WINDOWEVENT: switch(e.window.event) { case SDL_WINDOWEVENT_EXPOSED: //redraw, omitted. break; case SDL_WINDOWEVENT_FOCUS_GAINED: pSM->focusChange(true); break; case SDL_WINDOWEVENT_FOCUS_LOST: pSM->focusChange(false); break; case SDL_WINDOWEVENT_ENTER: mouseOver=true; break; case SDL_WINDOWEVENT_LEAVE: mouseOver=false; break; } break; case SDL_QUIT: { bool accepted=true; if(pSM->pQuitFunc&&pSM->pQuitFunc())accepted=false; if(pSM->quitHandler&&quitHandler->handlerFunc())accepted=false; if(accepted)return false; } break; case SDL_KEYDOWN: keymods=(SDL_Keymod)e.key.keysym.mod; if((keymods&KMOD_ALT)&&((e.key.keysym.sym==SDLK_RETURN)||(e.key.keysym.sym==SDLK_KP_ENTER))) {smVidMode(scrw,scrh,!windowed);break;} pSM->buildEvent(INPUT_KEYDOWN,e.key.keysym.scancode,0,0,-1,-1); break; case SDL_KEYUP: keymods=(SDL_Keymod)e.key.keysym.mod; pSM->buildEvent(INPUT_KEYUP,e.key.keysym.scancode,0,0,-1,-1); break; case SDL_MOUSEBUTTONDOWN: if(e.button.button==SDL_BUTTON_LEFT) pSM->buildEvent(INPUT_MBUTTONDOWN,SMK_LBUTTON,0,0,e.button.x,e.button.y); if(e.button.button==SDL_BUTTON_RIGHT) pSM->buildEvent(INPUT_MBUTTONDOWN,SMK_RBUTTON,0,0,e.button.x,e.button.y); if(e.button.button==SDL_BUTTON_MIDDLE) pSM->buildEvent(INPUT_MBUTTONDOWN,SMK_MBUTTON,0,0,e.button.x,e.button.y); break; case SDL_MOUSEBUTTONUP: if(e.button.button==SDL_BUTTON_LEFT) pSM->buildEvent(INPUT_MBUTTONUP,SMK_LBUTTON,0,0,e.button.x,e.button.y); if(e.button.button==SDL_BUTTON_RIGHT) pSM->buildEvent(INPUT_MBUTTONUP,SMK_RBUTTON,0,0,e.button.x,e.button.y); if(e.button.button==SDL_BUTTON_MIDDLE) pSM->buildEvent(INPUT_MBUTTONUP,SMK_MBUTTON,0,0,e.button.x,e.button.y); break; case SDL_MOUSEWHEEL: if(e.wheel.y>0)pSM->buildEvent(INPUT_MOUSEWHEEL,1,0,0,e.button.x,e.button.y); if(e.wheel.y<0)pSM->buildEvent(INPUT_MOUSEWHEEL,-1,0,0,e.button.x,e.button.y); break; case SDL_MOUSEMOTION: pSM->buildEvent(INPUT_MOUSEMOVE,0,0,0,e.motion.x,e.motion.y); break; } return true; } void SMELT_IMPL::flipSDLSurface(int p,int h,void* px) { void* temp_row; int height_div_2; temp_row=(void*)malloc(p); //assert(temp_row); height_div_2=(int)(h*.5); for(int i=0;i